Skip to content

chore: fall back when id_generator return wrong uuidv4#320

Draft
duyhungtnn wants to merge 11 commits intomainfrom
chore/fall-back-when-wrong-uuidv4
Draft

chore: fall back when id_generator return wrong uuidv4#320
duyhungtnn wants to merge 11 commits intomainfrom
chore/fall-back-when-wrong-uuidv4

Conversation

@duyhungtnn
Copy link
Copy Markdown
Collaborator

@duyhungtnn duyhungtnn commented Apr 21, 2026

#319

Issue: crypto.randomUUID may return non-v4 UUIDs in certain environments

crypto.randomUUID is a high-level API that returns a formatted UUID string, but its output is not guaranteed to always be a v4 UUID in every environment:

  • Insecure contexts (HTTP): per MDN, randomUUID is restricted to secure contexts and will throw or be undefined, while getRandomValues continues to work.
  • Enterprise environments: there is Edge Enterprise version that the corporate IT policies can override or hook browser APIs, potentially changing the UUID version or format returned by randomUUID.
  • Browser extensions: extensions can monkey-patch crypto.randomUUID on the page context, producing non-standard output.
  • Incorrect polyfills: a third-party polyfill may implement randomUUID incorrectly and return a non-v4 UUID.
  • Older / non-standard runtimes: embedded WebViews or older browser versions may not implement randomUUID at all (it was added in Chrome 92 / Safari 15.4).

Why do we still trust crypto.getRandomValues?

  • We apply the RFC 4122 v4 bit layout to the output of getRandomValues ourselves, so the output format is always under our control.
  • Per MDN, getRandomValues is the only crypto API guaranteed to work in insecure contexts.
  • Both APIs can be polyfilled, but if getRandomValues is broken, many other web APIs will likely be broken too — making it a more reliable signal of a non-compliant environment.

What changed:
The SDK validates the output of crypto.randomUUID at module load time. If the value is not a valid v4 UUID (or if the call fails), we fall back to our internal UUID v4 generator built on getRandomValues.

Validate and prefer native crypto.randomUUID but fallback to a compliant UUIDv4 generator using crypto.getRandomValues. Adds UUID v4 regex, a createUuidV4 helper, and logic to call randomUUID only if it returns a valid v4 string. Adds tests covering the native-valid and native-invalid cases, and updates test setup to provide webcrypto.getRandomValues on global.self.crypto.
Introduce a module-level useNativeRandomUUID IIFE that checks once whether globalThis.crypto.randomUUID is available and returns a valid UUIDv4, and simplify BrowserIdGenerator.newId to use this cached boolean instead of validating every call. Update tests to reset modules and dynamically import the generator so the IIFE runs per test, add explicit UUIDv4 regex specs, and add tests covering: valid native randomUUID, invalid-version randomUUID fallback, absent randomUUID behavior, that validity is only checked once at module init, and that the getRandomValues fallback is used on every newId() when randomUUID is unavailable.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens the browser-side ID generator against environments where crypto.randomUUID() can return non–RFC 4122 v4 UUIDs (notably Edge Enterprise under certain IT policies) by validating randomUUID output once at module load and falling back to a local v4 generator using crypto.getRandomValues().

Changes:

  • Add UUID v4 validation and a getRandomValues-based UUID v4 fallback in BrowserIdGenerator.
  • Update browser test setup to provide crypto.getRandomValues in the happy-dom environment.
  • Add unit tests covering native-vs-fallback selection behavior for the browser ID generator.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
src/internal/IdGenerator.browser.ts Validates crypto.randomUUID() output and falls back to a local RFC 4122 v4 generator via getRandomValues.
test/setup.browser.ts Polyfills the browser test environment with crypto.randomUUID and crypto.getRandomValues.
test/internal/IdGenerator.browser.spec.ts Adds tests for v4 validation and fallback behavior (module-init probe + per-call behavior).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/internal/IdGenerator.browser.ts Outdated
Comment thread src/internal/IdGenerator.browser.ts Outdated
Comment thread test/internal/IdGenerator.browser.spec.ts
Comment thread test/internal/IdGenerator.browser.spec.ts Outdated
Comment thread test/internal/IdGenerator.browser.spec.ts
Wrap crypto.randomUUID() usage in a try/catch so environments that throw (e.g. insecure contexts or policy-restricted runtimes) are treated as lacking native randomUUID. Clarify comments about getRandomValues being available as a fallback, polyfill behavior, and reliability signals. Adjust the test to directly assert crypto.randomUUID() matches the UUID v4 regex (removing the conditional), surfacing unsupported environments in CI. Minor comment cleanups included.
Export the UUID_V4_REGEX constant from src/internal/IdGenerator.browser.ts and update the browser test to import it instead of redefining the regex. This removes duplication and centralizes the UUID v4 pattern for reuse in tests.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a defensive fallback for browser UUID generation to handle environments (notably Edge Enterprise 105 under certain policies) where crypto.randomUUID() can return a non-v4 UUID, ensuring IDs remain RFC 4122 v4 compliant.

Changes:

  • Implement UUID v4 validation and a getRandomValues-based UUID v4 generator fallback in the browser ID generator.
  • Update browser test setup to provide crypto.getRandomValues in the browser test environment.
  • Add unit tests covering valid native UUIDs, invalid UUIDs (e.g. v3), and missing/invalid randomUUID scenarios.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/internal/IdGenerator.browser.ts Validates native randomUUID() once at module init; falls back to an RFC 4122 v4 generator using getRandomValues.
test/setup.browser.ts Extends browser test crypto shim to include getRandomValues.
test/internal/IdGenerator.browser.spec.ts Adds coverage for UUID v4 regex validation and native-vs-fallback behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/internal/IdGenerator.browser.ts Outdated
Comment thread src/internal/IdGenerator.browser.ts Outdated
Add spies and expectations in test/internal/IdGenerator.browser.spec.ts to verify that crypto.getRandomValues is invoked when generating IDs. Ensures BrowserIdGenerator falls back to getRandomValues in cases where randomUUID is stubbed, undefined, or not a function.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens the browser-side ID generation to ensure UUIDs sent to the backend are RFC 4122 v4, even when crypto.randomUUID() is missing, throws, or returns a non-v4 UUID in certain environments (e.g., Edge Enterprise / patched APIs).

Changes:

  • Add UUID v4 validation and a getRandomValues-based UUID v4 generator fallback in BrowserIdGenerator.
  • Update browser test setup to expose crypto.getRandomValues in the test environment.
  • Add browser-focused tests covering v4 validation and fallback behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/internal/IdGenerator.browser.ts Adds v4 regex validation, getRandomValues UUIDv4 generator, and native/fallback selection logic.
test/setup.browser.ts Extends test crypto shim to include getRandomValues for fallback-path tests.
test/internal/IdGenerator.browser.spec.ts Adds test coverage for v4 regex and fallback behavior under various randomUUID failure modes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/internal/IdGenerator.browser.ts
Comment thread src/internal/IdGenerator.browser.ts
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens the browser ID generator by verifying that crypto.randomUUID() yields an RFC4122 UUID v4 at module initialization time and falling back to a getRandomValues-based v4 generator when it doesn’t.

Changes:

  • Add UUID_V4_REGEX and use it to validate crypto.randomUUID() output during module init in BrowserIdGenerator.
  • Implement an internal getRandomValues-based UUID v4 generator for the browser fallback path.
  • Add browser-focused tests for the validation + fallback behavior and update the browser test setup to provide crypto.getRandomValues.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
src/internal/IdGenerator.browser.ts Adds module-init validation of native randomUUID and a getRandomValues fallback UUID v4 generator.
src/utils/regex.ts Introduces a shared UUID v4 validation regex constant.
test/setup.browser.ts Extends the browser test crypto shim to include getRandomValues.
test/internal/IdGenerator.browser.spec.ts Adds test coverage for UUID v4 regex behavior and native-vs-fallback selection logic.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/internal/IdGenerator.browser.ts Outdated
Small comment update in BrowserIdGenerator: removed the phrase "throws or" so the comment only references randomUUID returning a malformed UUID at runtime. This is a documentation-only tweak to clarify expected runtime failure mode; no functional change.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens the browser ID generation path to ensure generated event IDs are valid RFC 4122 UUID v4 values, even when crypto.randomUUID() is unavailable or returns a non-v4 UUID.

Changes:

  • Add a UUID v4 validator (UUID_V4_REGEX) and use it at module load to decide whether to trust crypto.randomUUID().
  • Implement a UUID v4 generator based on crypto.getRandomValues() as a fallback.
  • Extend browser test setup to provide crypto.getRandomValues and add browser-focused tests covering the new fallback behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
test/setup.browser.ts Adds crypto.getRandomValues to the happy-dom test crypto shim.
test/internal/IdGenerator.browser.spec.ts New tests verifying v4 validation, fallback selection, and call-count behavior.
src/utils/regex.ts Introduces UUID_V4_REGEX used to validate UUID v4 format.
src/internal/IdGenerator.browser.ts Adds v4 validation + getRandomValues-based fallback UUID generator.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

// Both APIs can be polyfilled, but if `getRandomValues` is broken, many other
// web APIs will likely be broken too — making it a more reliable signal of a
// non-compliant environment.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Thanks, but I don’t think we will handle this case. When this happens, all UUID libraries available on npm are also broken.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants