Skip to content

Conversation

@dependabot
Copy link
Contributor

@dependabot dependabot bot commented on behalf of github Aug 27, 2025

Bumps the jest group with 4 updates in the / directory: jest, jest-cli, jest-each and jest-environment-jsdom.

Updates jest from 29.7.0 to 30.1.1

Release notes

Sourced from jest's releases.

30.1.1

Fixes

  • [jest-snapshot-utils] Fix deprecated goo.gl snapshot warning not handling Windows end-of-line sequences (#15800)

30.1.0

Features

  • [jest-leak-detector] Configurable GC aggressiveness regarding to V8 heap snapshot generation (#15793)
  • [jest-runtime] Reduce redundant ReferenceError messages
  • [jest-core] Include test modules that failed to load when --onlyFailures is active

Fixes

  • `[jest-snapshot-utils] Fix deprecated goo.gl snapshot guide link not getting replaced with fully canonical URL (#15787)
  • [jest-circus] Fix it.concurrent not working with describe.skip (#15765)
  • [jest-snapshot] Fix mangled inline snapshot updates when used with Prettier 3 and CRLF line endings
  • [jest-runtime] Importing from @jest/globals in more than one file no longer breaks relative paths (#15772)

Chore

  • [expect] Update docblock for toContain() to display info on substring check (#15789)

30.0.2

What's Changed

Fixes

  • [jest-matcher-utils] Make 'deepCyclicCopyObject' safer by setting descriptors to a null-prototype object (#15689)
  • [jest-util] Make garbage collection protection property writable (#15689)

Full Changelog: https://github.com/jestjs/jest/blob/main/CHANGELOG.md

Jest 30.0.1

What's Changed

Features

  • [jest-resolver] Implement the defaultAsyncResolver (#15679)

Fixes

  • [jest-resolver] Resolve builtin modules correctly (#15683)
  • [jest-environment-node, jest-util] Avoid setting globals cleanup protection symbol when feature is off (#15684)

Chore & Maintenance

  • [*] Remove and deprecate jest-repl package (#15673)
  • [jest-resolver] Replace custom isBuiltinModule with node's isBuiltin (#15685)

... (truncated)

Changelog

Sourced from jest's changelog.

30.1.1

Fixes

  • [jest-snapshot-utils] Fix deprecated goo.gl snapshot warning not handling Windows end-of-line sequences (#15800)

30.1.0

Features

  • [jest-leak-detector] Configurable GC aggressiveness regarding to V8 heap snapshot generation (#15793)
  • [jest-runtime] Reduce redundant ReferenceError messages
  • [jest-core] Include test modules that failed to load when --onlyFailures is active

Fixes

  • [jest-snapshot-utils] Fix deprecated goo.gl snapshot guide link not getting replaced with fully canonical URL (#15787)
  • [jest-circus] Fix it.concurrent not working with describe.skip (#15765)
  • [jest-snapshot] Fix mangled inline snapshot updates when used with Prettier 3 and CRLF line endings
  • [jest-runtime] Importing from @jest/globals in more than one file no longer breaks relative paths (#15772)

Chore

  • [expect] Update docblock for toContain() to display info on substring check (#15789)

30.0.5

Features

  • [jest-config] Allow testMatch to take a string value
  • [jest-worker] Let workerIdleMemoryLimit accept 0 to always restart worker child processes

Fixes

  • [expect] Fix bigint error (#15702)

30.0.4

Features

  • [expect] The Inverse type is now exported (#15714)
  • [expect] feat: support async functions in toBe (#15704)

Fixes

  • [jest] jest --onlyFailures --listTests now correctly lists only failed tests (#15700)
  • [jest-snapshot] Handle line endings in snapshots (#15708)

30.0.3

... (truncated)

Commits

Updates jest-cli from 29.7.0 to 30.1.1

Release notes

Sourced from jest-cli's releases.

30.1.1

Fixes

  • [jest-snapshot-utils] Fix deprecated goo.gl snapshot warning not handling Windows end-of-line sequences (#15800)

30.1.0

Features

  • [jest-leak-detector] Configurable GC aggressiveness regarding to V8 heap snapshot generation (#15793)
  • [jest-runtime] Reduce redundant ReferenceError messages
  • [jest-core] Include test modules that failed to load when --onlyFailures is active

Fixes

  • `[jest-snapshot-utils] Fix deprecated goo.gl snapshot guide link not getting replaced with fully canonical URL (#15787)
  • [jest-circus] Fix it.concurrent not working with describe.skip (#15765)
  • [jest-snapshot] Fix mangled inline snapshot updates when used with Prettier 3 and CRLF line endings
  • [jest-runtime] Importing from @jest/globals in more than one file no longer breaks relative paths (#15772)

Chore

  • [expect] Update docblock for toContain() to display info on substring check (#15789)

30.0.2

What's Changed

Fixes

  • [jest-matcher-utils] Make 'deepCyclicCopyObject' safer by setting descriptors to a null-prototype object (#15689)
  • [jest-util] Make garbage collection protection property writable (#15689)

Full Changelog: https://github.com/jestjs/jest/blob/main/CHANGELOG.md

Jest 30.0.1

What's Changed

Features

  • [jest-resolver] Implement the defaultAsyncResolver (#15679)

Fixes

  • [jest-resolver] Resolve builtin modules correctly (#15683)
  • [jest-environment-node, jest-util] Avoid setting globals cleanup protection symbol when feature is off (#15684)

Chore & Maintenance

  • [*] Remove and deprecate jest-repl package (#15673)
  • [jest-resolver] Replace custom isBuiltinModule with node's isBuiltin (#15685)

... (truncated)

Changelog

Sourced from jest-cli's changelog.

30.1.1

Fixes

  • [jest-snapshot-utils] Fix deprecated goo.gl snapshot warning not handling Windows end-of-line sequences (#15800)

30.1.0

Features

  • [jest-leak-detector] Configurable GC aggressiveness regarding to V8 heap snapshot generation (#15793)
  • [jest-runtime] Reduce redundant ReferenceError messages
  • [jest-core] Include test modules that failed to load when --onlyFailures is active

Fixes

  • [jest-snapshot-utils] Fix deprecated goo.gl snapshot guide link not getting replaced with fully canonical URL (#15787)
  • [jest-circus] Fix it.concurrent not working with describe.skip (#15765)
  • [jest-snapshot] Fix mangled inline snapshot updates when used with Prettier 3 and CRLF line endings
  • [jest-runtime] Importing from @jest/globals in more than one file no longer breaks relative paths (#15772)

Chore

  • [expect] Update docblock for toContain() to display info on substring check (#15789)

30.0.5

Features

  • [jest-config] Allow testMatch to take a string value
  • [jest-worker] Let workerIdleMemoryLimit accept 0 to always restart worker child processes

Fixes

  • [expect] Fix bigint error (#15702)

30.0.4

Features

  • [expect] The Inverse type is now exported (#15714)
  • [expect] feat: support async functions in toBe (#15704)

Fixes

  • [jest] jest --onlyFailures --listTests now correctly lists only failed tests (#15700)
  • [jest-snapshot] Handle line endings in snapshots (#15708)

30.0.3

... (truncated)

Commits

Updates jest-each from 30.0.5 to 30.1.0

Release notes

Sourced from jest-each's releases.

30.1.0

Features

  • [jest-leak-detector] Configurable GC aggressiveness regarding to V8 heap snapshot generation (#15793)
  • [jest-runtime] Reduce redundant ReferenceError messages
  • [jest-core] Include test modules that failed to load when --onlyFailures is active

Fixes

  • `[jest-snapshot-utils] Fix deprecated goo.gl snapshot guide link not getting replaced with fully canonical URL (#15787)
  • [jest-circus] Fix it.concurrent not working with describe.skip (#15765)
  • [jest-snapshot] Fix mangled inline snapshot updates when used with Prettier 3 and CRLF line endings
  • [jest-runtime] Importing from @jest/globals in more than one file no longer breaks relative paths (#15772)

Chore

  • [expect] Update docblock for toContain() to display info on substring check (#15789)
Changelog

Sourced from jest-each's changelog.

30.1.0

Features

  • [jest-leak-detector] Configurable GC aggressiveness regarding to V8 heap snapshot generation (#15793)
  • [jest-runtime] Reduce redundant ReferenceError messages
  • [jest-core] Include test modules that failed to load when --onlyFailures is active

Fixes

  • [jest-snapshot-utils] Fix deprecated goo.gl snapshot guide link not getting replaced with fully canonical URL (#15787)
  • [jest-circus] Fix it.concurrent not working with describe.skip (#15765)
  • [jest-snapshot] Fix mangled inline snapshot updates when used with Prettier 3 and CRLF line endings
  • [jest-runtime] Importing from @jest/globals in more than one file no longer breaks relative paths (#15772)

Chore

  • [expect] Update docblock for toContain() to display info on substring check (#15789)
Commits

Updates jest-environment-jsdom from 29.7.0 to 30.1.1

Release notes

Sourced from jest-environment-jsdom's releases.

30.1.1

Fixes

  • [jest-snapshot-utils] Fix deprecated goo.gl snapshot warning not handling Windows end-of-line sequences (#15800)

30.1.0

Features

  • [jest-leak-detector] Configurable GC aggressiveness regarding to V8 heap snapshot generation (#15793)
  • [jest-runtime] Reduce redundant ReferenceError messages
  • [jest-core] Include test modules that failed to load when --onlyFailures is active

Fixes

  • `[jest-snapshot-utils] Fix deprecated goo.gl snapshot guide link not getting replaced with fully canonical URL (#15787)
  • [jest-circus] Fix it.concurrent not working with describe.skip (#15765)
  • [jest-snapshot] Fix mangled inline snapshot updates when used with Prettier 3 and CRLF line endings
  • [jest-runtime] Importing from @jest/globals in more than one file no longer breaks relative paths (#15772)

Chore

  • [expect] Update docblock for toContain() to display info on substring check (#15789)

30.0.2

What's Changed

Fixes

  • [jest-matcher-utils] Make 'deepCyclicCopyObject' safer by setting descriptors to a null-prototype object (#15689)
  • [jest-util] Make garbage collection protection property writable (#15689)

Full Changelog: https://github.com/jestjs/jest/blob/main/CHANGELOG.md

Jest 30.0.1

What's Changed

Features

  • [jest-resolver] Implement the defaultAsyncResolver (#15679)

Fixes

  • [jest-resolver] Resolve builtin modules correctly (#15683)
  • [jest-environment-node, jest-util] Avoid setting globals cleanup protection symbol when feature is off (#15684)

Chore & Maintenance

  • [*] Remove and deprecate jest-repl package (#15673)
  • [jest-resolver] Replace custom isBuiltinModule with node's isBuiltin (#15685)

... (truncated)

Changelog

Sourced from jest-environment-jsdom's changelog.

30.1.1

Fixes

  • [jest-snapshot-utils] Fix deprecated goo.gl snapshot warning not handling Windows end-of-line sequences (#15800)

30.1.0

Features

  • [jest-leak-detector] Configurable GC aggressiveness regarding to V8 heap snapshot generation (#15793)
  • [jest-runtime] Reduce redundant ReferenceError messages
  • [jest-core] Include test modules that failed to load when --onlyFailures is active

Fixes

  • [jest-snapshot-utils] Fix deprecated goo.gl snapshot guide link not getting replaced with fully canonical URL (#15787)
  • [jest-circus] Fix it.concurrent not working with describe.skip (#15765)
  • [jest-snapshot] Fix mangled inline snapshot updates when used with Prettier 3 and CRLF line endings
  • [jest-runtime] Importing from @jest/globals in more than one file no longer breaks relative paths (#15772)

Chore

  • [expect] Update docblock for toContain() to display info on substring check (#15789)

30.0.5

Features

  • [jest-config] Allow testMatch to take a string value
  • [jest-worker] Let workerIdleMemoryLimit accept 0 to always restart worker child processes

Fixes

  • [expect] Fix bigint error (#15702)

30.0.4

Features

  • [expect] The Inverse type is now exported (#15714)
  • [expect] feat: support async functions in toBe (#15704)

Fixes

  • [jest] jest --onlyFailures --listTests now correctly lists only failed tests (#15700)
  • [jest-snapshot] Handle line endings in snapshots (#15708)

30.0.3

... (truncated)

Commits

You can trigger a rebase of this PR by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot merge will merge this PR after your CI passes on it
  • @dependabot squash and merge will squash and merge this PR after your CI passes on it
  • @dependabot cancel merge will cancel a previously requested merge and block automerging
  • @dependabot reopen will reopen this PR if it is closed
  • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore <dependency name> major version will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself)
  • @dependabot ignore <dependency name> minor version will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself)
  • @dependabot ignore <dependency name> will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself)
  • @dependabot unignore <dependency name> will remove all of the ignore conditions of the specified dependency
  • @dependabot unignore <dependency name> <ignore condition> will remove the ignore condition of the specified dependency and ignore conditions

Note
Automatic rebases have been disabled on this pull request as it has been open for over 30 days.

@dependabot dependabot bot added dependencies Pull requests that update a dependency file javascript Pull requests that update Javascript code labels Aug 27, 2025
@dependabot dependabot bot force-pushed the dependabot/npm_and_yarn/jest-1ecd9637f0 branch from 1b52632 to ca23232 Compare September 3, 2025 19:07
@dependabot dependabot bot force-pushed the dependabot/npm_and_yarn/jest-1ecd9637f0 branch from ca23232 to d1b2768 Compare September 10, 2025 00:02
@dependabot dependabot bot force-pushed the dependabot/npm_and_yarn/jest-1ecd9637f0 branch 2 times, most recently from ea3e481 to f2eaea0 Compare September 24, 2025 00:02
@dependabot dependabot bot force-pushed the dependabot/npm_and_yarn/jest-1ecd9637f0 branch from f2eaea0 to efb9b59 Compare October 1, 2025 00:02
@dependabot dependabot bot force-pushed the dependabot/npm_and_yarn/jest-1ecd9637f0 branch 2 times, most recently from 42794bb to 30c7dc2 Compare October 15, 2025 00:02
@dependabot dependabot bot force-pushed the dependabot/npm_and_yarn/jest-1ecd9637f0 branch from 30c7dc2 to 5ae0b86 Compare October 22, 2025 00:02
@dependabot dependabot bot force-pushed the dependabot/npm_and_yarn/jest-1ecd9637f0 branch from 5ae0b86 to 36a49ee Compare October 29, 2025 00:02
@dependabot dependabot bot force-pushed the dependabot/npm_and_yarn/jest-1ecd9637f0 branch from 36a49ee to 665242a Compare November 5, 2025 00:05
dependabot bot and others added 5 commits December 8, 2025 14:32
Bumps the jest group with 4 updates in the / directory: [jest](https://github.com/jestjs/jest/tree/HEAD/packages/jest), [jest-cli](https://github.com/jestjs/jest/tree/HEAD/packages/jest-cli), [jest-each](https://github.com/jestjs/jest/tree/HEAD/packages/jest-each) and [jest-environment-jsdom](https://github.com/jestjs/jest/tree/HEAD/packages/jest-environment-jsdom).

Updates `jest` from 29.7.0 to 30.1.1
- [Release notes](https://github.com/jestjs/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jestjs/jest/commits/v30.1.1/packages/jest)

Updates `jest-cli` from 29.7.0 to 30.1.1
- [Release notes](https://github.com/jestjs/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jestjs/jest/commits/v30.1.1/packages/jest-cli)

Updates `jest-each` from 30.0.5 to 30.1.0
- [Release notes](https://github.com/jestjs/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jestjs/jest/commits/v30.1.0/packages/jest-each)

Updates `jest-environment-jsdom` from 29.7.0 to 30.1.1
- [Release notes](https://github.com/jestjs/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jestjs/jest/commits/v30.1.1/packages/jest-environment-jsdom)

---
updated-dependencies:
- dependency-name: jest
  dependency-version: 30.1.1
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: jest
- dependency-name: jest-cli
  dependency-version: 30.1.1
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: jest
- dependency-name: jest-each
  dependency-version: 30.1.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: jest
- dependency-name: jest-environment-jsdom
  dependency-version: 30.1.1
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: jest
...

Signed-off-by: dependabot[bot] <[email protected]>
@nucleogenesis nucleogenesis force-pushed the dependabot/npm_and_yarn/jest-1ecd9637f0 branch from 1cf9ed1 to 27f80f3 Compare December 9, 2025 21:26
expect(
() => new Change({ key: '1', table: TABLE_NAMES.CONTENTNODE, type: CHANGE_TYPES.CREATED }),
).toThrow(new ReferenceError('source should be a string, but undefined was passed instead'));
).toThrow(new TypeError('source should be a string, but undefined was passed instead'));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is weird so I wonder if jest was a bit loosey-goosey with the type of error it got when checking things out here.

It was two years ago that the errors here were defined and the tests error types were flip-flopped but only now did they fail apparently.

@nucleogenesis
Copy link
Member

nucleogenesis commented Dec 11, 2025

I've gotten all but one test passing on this PR - seems like something has changed w/ regards to mocking and overriding window.location and it's bits and parts. So after trying everything I could think of and then watching Claude try everything I could think of and then some more things I didn't think of... it seems clear that the code just shouldn't rely on calling window.location.assign directly (or the test should test the behavior in a way that doesn't mock window.location.

In AccountsMain we used window.location.assign to change the URL so I started reworking it to use the Vue Router there - will need some non-me testing there once this is ready so I'll reach out for another reviewer when I have the tests passing to be sure that there wasn't some particular reason to avoid the router when this was written?

},
navigate(path) {
// Extracted for easier testing
window.location.assign(path);

Check failure

Code scanning / CodeQL

Client-side cross-site scripting High

Cross-site scripting vulnerability due to
user-provided value
.

Copilot Autofix

AI about 8 hours ago

General Fix:
The vulnerability must be fixed by ensuring the next parameter (from the query string) cannot facilitate cross-site scripting or open redirect attacks. Only allow navigation to safe, trusted URLs. The safest practice is to allow only relative internal paths or, even stricter, to whitelist possible destinations. Arbitrary full URLs or JavaScript schemes must never be allowed.

Detailed Fix:
Update the nextParam computed property (or submit method) to permit only valid, relative paths—beginning with / and not containing any protocol (to prohibit javascript:, //, or http(s)://). If next does not pass this validation, it should be ignored or fallback to a known safe page. We can use a simple regular expression or URL parsing to verify this. Changes should be made in AccountsMain.vue (lines 155-158 and/or in the logic around line 183 in submit).

Implementation Requirements:

  • Add a function to validate (sanitize) the next parameter: ensure it is a relative path within the application, e.g., /foo, /bar/baz?x=1, etc.
  • Use this function when retrieving nextParam so it cannot return an unsafe value.
  • This can be implemented in the computed block or as a method.
  • No external dependencies required—vanilla JS suffices.

Suggested changeset 1
contentcuration/contentcuration/frontend/accounts/pages/AccountsMain.vue

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/contentcuration/contentcuration/frontend/accounts/pages/AccountsMain.vue b/contentcuration/contentcuration/frontend/accounts/pages/AccountsMain.vue
--- a/contentcuration/contentcuration/frontend/accounts/pages/AccountsMain.vue
+++ b/contentcuration/contentcuration/frontend/accounts/pages/AccountsMain.vue
@@ -154,7 +154,8 @@
       }),
       nextParam() {
         const params = new URLSearchParams(window.location.search.substring(1));
-        return params.get('next');
+        const next = params.get('next');
+        return this.sanitizeNextPath(next);
       },
     },
     methods: {
@@ -196,6 +197,24 @@
         }
         return Promise.resolve();
       },
+
+      /**
+       * Only allow safe, local, relative paths for redirection.
+       * Disallows protocol-relative, external, or javascript: URLs.
+       */
+      sanitizeNextPath(next) {
+        if (
+          typeof next === 'string' &&
+          next.length > 0 &&
+          next.startsWith('/') &&
+          !next.startsWith('//') &&
+          !next.includes('://')
+        ) {
+          return next;
+        }
+        // Fallback: unsafe or missing next param
+        return null;
+      },
     },
     $trs: {
       kolibriStudio: 'Kolibri Studio',
EOF
@@ -154,7 +154,8 @@
}),
nextParam() {
const params = new URLSearchParams(window.location.search.substring(1));
return params.get('next');
const next = params.get('next');
return this.sanitizeNextPath(next);
},
},
methods: {
@@ -196,6 +197,24 @@
}
return Promise.resolve();
},

/**
* Only allow safe, local, relative paths for redirection.
* Disallows protocol-relative, external, or javascript: URLs.
*/
sanitizeNextPath(next) {
if (
typeof next === 'string' &&
next.length > 0 &&
next.startsWith('/') &&
!next.startsWith('//') &&
!next.includes('://')
) {
return next;
}
// Fallback: unsafe or missing next param
return null;
},
},
$trs: {
kolibriStudio: 'Kolibri Studio',
Copilot is powered by AI and may make mistakes. Always verify output.
},
navigate(path) {
// Extracted for easier testing
window.location.assign(path);

Check warning

Code scanning / CodeQL

Client-side URL redirect Medium

Untrusted URL redirection depends on a
user-provided value
.

Copilot Autofix

AI about 8 hours ago

To fix the open redirect issue, we must ensure that the next parameter extracted from the query string cannot be used to redirect users to arbitrary, potentially malicious, locations. The best approach is to only allow redirection to safe, internal paths. We can do this by only permitting relative paths that start with a single / and do not contain a protocol (://) or start with // (protocol-relative). We'll add a validation method that checks the supplied path, and only performs the redirect if it is deemed safe; otherwise, we fall back to a known-safe default (such as window.Urls.channels()). We will implement this validation inside the Vue component, ensuring minimal change to feature behavior.

The edits should be within contentcuration/contentcuration/frontend/accounts/pages/AccountsMain.vue, particularly in the method that handles the redirect (navigate), the computed property for nextParam, and the logic that determines the redirect target. We'll add a method isSafeRedirectPath for validation.


Suggested changeset 1
contentcuration/contentcuration/frontend/accounts/pages/AccountsMain.vue

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/contentcuration/contentcuration/frontend/accounts/pages/AccountsMain.vue b/contentcuration/contentcuration/frontend/accounts/pages/AccountsMain.vue
--- a/contentcuration/contentcuration/frontend/accounts/pages/AccountsMain.vue
+++ b/contentcuration/contentcuration/frontend/accounts/pages/AccountsMain.vue
@@ -154,7 +154,11 @@
       }),
       nextParam() {
         const params = new URLSearchParams(window.location.search.substring(1));
-        return params.get('next');
+        const param = params.get('next');
+        if (param && this.isSafeRedirectPath(param)) {
+          return param;
+        }
+        return null;
       },
     },
     methods: {
@@ -166,7 +170,7 @@
         this.$router.push({ query: { showPolicy: policies.PRIVACY } });
       },
       navigate(path) {
-        // Extracted for easier testing
+        // Only redirect to internal, validated paths
         window.location.assign(path);
       },
       submit() {
@@ -180,7 +184,7 @@
             .then(() => {
               this.loginFailedOffline = false;
               this.loginFailed = false;
-              const path = this.nextParam || window.Urls.channels();
+              const path = this.nextParam ? this.nextParam : window.Urls.channels();
               this.navigate(path);
             })
             .catch(err => {
@@ -197,6 +201,20 @@
         return Promise.resolve();
       },
     },
+    /**
+     * Accepts only safe internal paths:
+     * - Starts with a single "/" (not "//")
+     * - Does not contain ":" before a "?" or "#" (no protocol-relative or absolute URLs)
+     * - Optional: Could be tightened to match a whitelist
+     */
+    isSafeRedirectPath(path) {
+      // Must start with /, not with //
+      if (typeof path !== "string") return false;
+      if (!path.startsWith('/') || path.startsWith('//')) return false;
+      // Prevent "http:/", "http://", etc.
+      if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(path)) return false;
+      return true;
+    },
     $trs: {
       kolibriStudio: 'Kolibri Studio',
       passwordLabel: 'Password',
EOF
@@ -154,7 +154,11 @@
}),
nextParam() {
const params = new URLSearchParams(window.location.search.substring(1));
return params.get('next');
const param = params.get('next');
if (param && this.isSafeRedirectPath(param)) {
return param;
}
return null;
},
},
methods: {
@@ -166,7 +170,7 @@
this.$router.push({ query: { showPolicy: policies.PRIVACY } });
},
navigate(path) {
// Extracted for easier testing
// Only redirect to internal, validated paths
window.location.assign(path);
},
submit() {
@@ -180,7 +184,7 @@
.then(() => {
this.loginFailedOffline = false;
this.loginFailed = false;
const path = this.nextParam || window.Urls.channels();
const path = this.nextParam ? this.nextParam : window.Urls.channels();
this.navigate(path);
})
.catch(err => {
@@ -197,6 +201,20 @@
return Promise.resolve();
},
},
/**
* Accepts only safe internal paths:
* - Starts with a single "/" (not "//")
* - Does not contain ":" before a "?" or "#" (no protocol-relative or absolute URLs)
* - Optional: Could be tightened to match a whitelist
*/
isSafeRedirectPath(path) {
// Must start with /, not with //
if (typeof path !== "string") return false;
if (!path.startsWith('/') || path.startsWith('//')) return false;
// Prevent "http:/", "http://", etc.
if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(path)) return false;
return true;
},
$trs: {
kolibriStudio: 'Kolibri Studio',
passwordLabel: 'Password',
Copilot is powered by AI and may make mistakes. Always verify output.

// Create a spy for navigate before rendering
const navigateSpy = jest.fn();
const OriginalAccountsMain = AccountsMain;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the witchcraft that Claude came up with to accommodate the need to use the path in the next parameter to redirect.

I tried doing it w/ Vue Router and ran into redundant navigation errors. I tried mocking window.location all sorts of different ways but always ended up running into the issue of it being read-only.

I kind of hate everything about this because it feels like it should be done differently if this is how the tests have to be written, but my attempts to do it differently fizzled out in annoying ways where when I got it working in the browser, tests failed and vice versa until I asked Claude a second time to "figure it out please" and let them run with it.

It works and tests pass now anyway

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file javascript Pull requests that update Javascript code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants