diff options
author | GitHub Nightly Merge Action <actions@github.com> | 2022-10-14 03:20:54 +0300 |
---|---|---|
committer | GitHub Nightly Merge Action <actions@github.com> | 2022-10-14 03:20:54 +0300 |
commit | c1a2c0ef7ada78b1999c50951851f5871fa06ee5 (patch) | |
tree | 95a5886443eb72dcb3e9ac5e761b1c728eb750bc | |
parent | a9d0856b3d7c1788bac39ab291ff1e4c87f80061 (diff) | |
parent | 2e408096e182c767066850aa11b0f5c58d09a77c (diff) |
Merge branch 'maintenance' into devel
-rw-r--r-- | .github/workflows/build.yml | 1 | ||||
-rw-r--r-- | .github/workflows/nightly_merge.yml | 18 | ||||
-rw-r--r-- | .pre-commit-config.yaml | 1 | ||||
-rw-r--r-- | src/octoprint/plugins/backup/__init__.py | 26 | ||||
-rw-r--r-- | src/octoprint/server/__init__.py | 1 | ||||
-rw-r--r-- | src/octoprint/server/util/flask.py | 4 | ||||
-rw-r--r-- | src/octoprint/static/js/app/client/base.js | 7 | ||||
-rw-r--r-- | tests/cypress/package-lock.json | 15 | ||||
-rw-r--r-- | tests/static/js/test-client-base.html | 18 | ||||
-rw-r--r-- | tests/static/js/test-client-base.js | 110 |
10 files changed, 178 insertions, 23 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9ef20ac0f..c6f89e6d6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -77,6 +77,7 @@ jobs: - name: ๐ Run helpers.js test suite run: | node-qunit-puppeteer tests/static/js/test-helpers.html + node-qunit-puppeteer tests/static/js/test-client-base.html test-install: name: ๐งช Installation tests diff --git a/.github/workflows/nightly_merge.yml b/.github/workflows/nightly_merge.yml index 089f44c8c..56821fbc0 100644 --- a/.github/workflows/nightly_merge.yml +++ b/.github/workflows/nightly_merge.yml @@ -23,6 +23,24 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: ๐ Merge staging/bugfix into maintenance + uses: robotology/gh-action-nightly-merge@v1.3.3 + with: + stable_branch: "staging/bugfix" + development_branch: "maintenance" + allow_ff: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: ๐ Merge staging/maintenance into maintenance + uses: robotology/gh-action-nightly-merge@v1.3.3 + with: + stable_branch: "staging/bugfix" + development_branch: "maintenance" + allow_ff: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: ๐ Merge maintenance into devel uses: robotology/gh-action-nightly-merge@v1.3.3 with: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 42120070c..c04d91f59 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -54,6 +54,7 @@ repos: - id: flake8 additional_dependencies: - flake8-bugbear==22.3.20 + - importlib-metadata<5.0 exclude: ^(docs/) - repo: https://github.com/pre-commit/mirrors-prettier rev: v2.5.1 diff --git a/src/octoprint/plugins/backup/__init__.py b/src/octoprint/plugins/backup/__init__.py index 19e1e69b3..643f9aa11 100644 --- a/src/octoprint/plugins/backup/__init__.py +++ b/src/octoprint/plugins/backup/__init__.py @@ -390,9 +390,7 @@ class BackupPlugin( "as_attachment": True, "path_validation": path_validation_factory( lambda path: not is_hidden_path(path) - and self._match_backup_filename( - os.path.basename(path), self._settings - ), + and self._valid_backup(path), status_code=404, ), "access_validation": access_validation_factory( @@ -739,9 +737,7 @@ class BackupPlugin( for entry in os.scandir(self.get_plugin_data_folder()): if is_hidden_path(entry.path): continue - if not entry.is_file(): - continue - if not entry.name.endswith(".zip"): + if not self._valid_backup(entry.path): continue backups.append( @@ -1374,13 +1370,6 @@ class BackupPlugin( ) @classmethod - def _match_backup_filename(cls, path, settings): - import re - - backup_prefix = cls._get_backup_prefix(settings) - return re.match(re.escape(backup_prefix) + r"-backup-\d{8}-\d{6}.zip", path) - - @classmethod def _get_backup_prefix(cls, settings): if settings.global_get(["appearance", "name"]) == "": backup_prefix = "octoprint" @@ -1397,6 +1386,17 @@ class BackupPlugin( not in valid_boolean_trues ) + @classmethod + def _valid_backup(cls, path): + if not path.endswith(".zip") or not zipfile.is_zipfile(path): + return False + + try: + with zipfile.ZipFile(path) as z: + return "metadata.json" in z.namelist() + except Exception: + return False + def _send_client_message(self, message, payload=None): if payload is None: payload = {} diff --git a/src/octoprint/server/__init__.py b/src/octoprint/server/__init__.py index 9ae57cf8d..08dd56999 100644 --- a/src/octoprint/server/__init__.py +++ b/src/octoprint/server/__init__.py @@ -1476,6 +1476,7 @@ class Server: app, key_func=get_remote_address, enabled=s.getBoolean(["devel", "enableRateLimiter"]), + storage_uri="memory://", ) def _setup_i18n(self, app): diff --git a/src/octoprint/server/util/flask.py b/src/octoprint/server/util/flask.py index b14d84777..ec0d0b7e5 100644 --- a/src/octoprint/server/util/flask.py +++ b/src/octoprint/server/util/flask.py @@ -588,7 +588,9 @@ class OctoPrintFlaskResponse(flask.Response): kwargs["samesite"] = samesite # set secure if necessary - kwargs["secure"] = settings().getBoolean(["server", "cookies", "secure"]) + kwargs["secure"] = flask.request.environ.get( + "wsgi.url_scheme" + ) == "https" or settings().getBoolean(["server", "cookies", "secure"]) # tie account properties to remember me cookie (e.g. current password hash) if key == current_app.config.get("REMEMBER_COOKIE_NAME", REMEMBER_COOKIE_NAME): diff --git a/src/octoprint/static/js/app/client/base.js b/src/octoprint/static/js/app/client/base.js index 79870fd86..9bc72ce2f 100644 --- a/src/octoprint/static/js/app/client/base.js +++ b/src/octoprint/static/js/app/client/base.js @@ -107,13 +107,14 @@ return url; }; - OctoPrintClient.prototype.getParsedBaseUrl = function () { + OctoPrintClient.prototype.getParsedBaseUrl = function (location) { if (!this.options.baseurl) return ""; try { var url = new URL(this.options.baseurl); } catch (e) { - var parsed = new URL(window.location); + location = location || window.location; + var parsed = new URL(location); var path = this.options.baseurl; if (!path || path[0] !== "/") { path = "/" + (path ? path : ""); @@ -135,7 +136,7 @@ if (path.endsWith("/")) { path = path.substring(0, path.length - 1); } - return "_P" + port + "_R" + path.replace(/\//, "|"); + return "_P" + port + "_R" + path.replace(/\//g, "|"); } else { return "_P" + port; } diff --git a/tests/cypress/package-lock.json b/tests/cypress/package-lock.json index 35f278b3c..5c20777e8 100644 --- a/tests/cypress/package-lock.json +++ b/tests/cypress/package-lock.json @@ -1571,9 +1571,12 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/ms": { "version": "2.1.2", @@ -3279,9 +3282,9 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" }, "ms": { "version": "2.1.2", diff --git a/tests/static/js/test-client-base.html b/tests/static/js/test-client-base.html new file mode 100644 index 000000000..fa69c3fea --- /dev/null +++ b/tests/static/js/test-client-base.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8" /> + <title>src/octoprint/static/js/app/client/base.js Tests</title> + <link rel="stylesheet" href="lib/qunit-1.18.0.css" /> + </head> + <body> + <div id="qunit"></div> + <div id="qunit-fixture"></div> + <script src="lib/qunit-1.18.0.js"></script> + <script src="lib/qunit-parameterize.js"></script> + <script src="../../../src/octoprint/static/js/lib/lodash.min.js"></script> + <script src="../../../src/octoprint/static/js/lib/sprintf.min.js"></script> + <script src="../../../src/octoprint/static/js/app/client/base.js"></script> + <script src="test-client-base.js"></script> + </body> +</html> diff --git a/tests/static/js/test-client-base.js b/tests/static/js/test-client-base.js new file mode 100644 index 000000000..6d39fa39f --- /dev/null +++ b/tests/static/js/test-client-base.js @@ -0,0 +1,110 @@ +_.mixin({sprintf: sprintf, vsprintf: vsprintf}); + +QUnit.module("getParsedBaseUrl"); +QUnit.cases( + (function () { + return [ + { + title: "fully qualified baseurl", + baseurl: "https://example.com", + location: undefined, + expected: "https://example.com/" + }, + { + title: "fully qualified baseurl with http", + baseurl: "http://example.com", + location: undefined, + expected: "http://example.com/" + }, + { + title: "fully qualified baseurl with custom port", + baseurl: "https://example.com:5000", + location: undefined, + expected: "https://example.com:5000/" + }, + { + title: "website root", + baseurl: "/", + location: "https://example.com", + expected: "https://example.com/" + }, + { + title: "website root with custom port", + baseurl: "/", + location: "https://example.com:5000", + expected: "https://example.com:5000/" + }, + { + title: "single level prefix", + baseurl: "/octoprint/", + location: "https://example.com", + expected: "https://example.com/octoprint/" + }, + { + title: "multi level prefix", + baseurl: "/path/to/octoprint/", + location: "https://example.com", + expected: "https://example.com/path/to/octoprint/" + }, + { + title: "multi level prefix with http and custom port", + baseurl: "/path/to/octoprint/", + location: "http://example.com:5000", + expected: "http://example.com:5000/path/to/octoprint/" + }, + { + title: "multi level prefix with https, custom port, no trailing slash", + baseurl: "/path/to/octoprint", + location: "https://example.com:5001", + expected: "https://example.com:5001/path/to/octoprint" + } + ]; + })() +).test("getParsedBaseUrl", function (params, assert) { + OctoPrint.options.baseurl = params.baseurl; + assert.equal( + OctoPrint.getParsedBaseUrl(params.location).toString(), + params.expected, + "Expected: " + String(params.expected) + ); +}); + +QUnit.module("getCookieSuffix"); +QUnit.cases( + (function () { + return [ + { + title: "http with default port", + baseurl: "http://example.com", + expected: "_P80" + }, + { + title: "https with default port", + baseurl: "https://example.com", + expected: "_P443" + }, + { + title: "custom port", + baseurl: "http://example.com:5000", + expected: "_P5000" + }, + { + title: "single level prefix", + baseurl: "https://example.com/octoprint/", + expected: "_P443_R|octoprint" + }, + { + title: "multi level prefix", + baseurl: "https://example.com/path/to/octoprint", + expected: "_P443_R|path|to|octoprint" + } + ]; + })() +).test("getCookieSuffix", function (params, assert) { + OctoPrint.options.baseurl = params.baseurl; + assert.equal( + OctoPrint.getCookieSuffix(), + params.expected, + "Expected: " + String(params.expected) + ); +}); |