Skip to content

feat(NODE-7379): Refactor Crypto to Web Crypto API#4862

Merged
dariakp merged 8 commits intomongodb:mainfrom
PavelSafronov:NODE-7379
Mar 16, 2026
Merged

feat(NODE-7379): Refactor Crypto to Web Crypto API#4862
dariakp merged 8 commits intomongodb:mainfrom
PavelSafronov:NODE-7379

Conversation

@PavelSafronov
Copy link
Contributor

@PavelSafronov PavelSafronov commented Feb 4, 2026

Description

Summary of Changes

Use standard Web Crypto API globalThis.crypto instead of Node.js crypto.

What is the motivation for this change?

This helps us reduce our runtime dependencies, as part of https://jira.mongodb.org/browse/NODE-6601

Release Highlight

Replaced Node‑specific API crypto with standards‑based equivalent

The driver now uses the standard Web Crypto API globalThis.crypto instead of the Node‑specific crypto API.

This reduces the number of patches needed to run the driver outside Node.js.

Double check the following

  • Lint is passing (npm run check:lint)
  • Self-review completed using the steps outlined here
  • PR title follows the correct format: type(NODE-xxxx)[!]: description
    • Example: feat(NODE-1234)!: rewriting everything in coffeescript
  • Changes are covered by tests
  • New TODOs have a related JIRA ticket

@PavelSafronov PavelSafronov changed the title WIP feat(NODE-7379): Refactor Crypto to Web Crypto API feat(NODE-7379): Refactor Crypto to Web Crypto API Feb 6, 2026
@PavelSafronov PavelSafronov marked this pull request as ready for review February 6, 2026 16:37
@PavelSafronov PavelSafronov requested a review from a team as a code owner February 6, 2026 16:37
@tadjik1 tadjik1 self-assigned this Feb 17, 2026
@tadjik1 tadjik1 added the Primary Review In Review with primary reviewer, not yet ready for team's eyes label Feb 17, 2026
@codeowners-service-app
Copy link

Assigned dariakp for team dbx-node-devs because tadjik1 is out of office.

Copilot AI review requested due to automatic review settings March 13, 2026 14:54
Copy link
Contributor

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 refactors the MongoDB Node.js driver to use the Web Crypto API (crypto.subtle and crypto.getRandomValues) instead of Node.js's crypto module for most cryptographic operations. This is part of an effort to make the driver runtime-agnostic so it can eventually run in non-Node environments. The only remaining dependency on Node.js crypto is for SCRAM-SHA-1's MD5 digest, which is loaded dynamically via require('crypto').

Changes:

  • Replace crypto.randomBytes with crypto.getRandomValues in uuidV4() and randomBytes(), and replace crypto.createHash/crypto.createHmac/crypto.pbkdf2Sync with their Web Crypto API equivalents (crypto.subtle.digest, crypto.subtle.sign, crypto.subtle.deriveBits).
  • Isolate the remaining Node.js crypto dependency to SCRAM-SHA-1's passwordDigest function via dynamic require('crypto'), and add an eslint restriction on importing crypto.
  • Add documentation in README about running in custom runtimes and current limitations.

Reviewed changes

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

File Description
src/utils.ts Replace crypto.randomBytes with crypto.getRandomValues for uuidV4 and randomBytes
src/cmap/auth/scram.ts Migrate SCRAM auth crypto functions (H, HMAC, HI) to Web Crypto API; isolate MD5 dependency via dynamic require; remove timingSafeEqual
README.md Add documentation section about running in custom/non-Node runtimes
.eslintrc.json Add crypto to restricted imports for test files
Comments suppressed due to low confidence (1)

src/cmap/auth/scram.ts:355

  • Removing crypto.timingSafeEqual weakens security. The manual XOR loop is not guaranteed to be constant-time in JavaScript — JIT compilers may optimize it in ways that leak timing information, making it potentially vulnerable to timing side-channel attacks on SCRAM authentication. Consider keeping crypto.timingSafeEqual as the preferred path (via a dynamic require('crypto') similar to passwordDigest), with the manual loop as a fallback for non-Node runtimes.
  let result = 0;
  for (let i = 0; i < lhs.length; i++) {
    result |= lhs[i] ^ rhs[i];
  }

  return result === 0;

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

tadjik1
tadjik1 previously approved these changes Mar 13, 2026
Copy link
Member

@tadjik1 tadjik1 left a comment

Choose a reason for hiding this comment

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

@PavelSafronov would you mind fixing the documentation typos and clarification that Copilot found? Everything else looks good, thank you! 👍

@dariakp dariakp added Team Review Needs review from team and removed Primary Review In Review with primary reviewer, not yet ready for team's eyes labels Mar 13, 2026
tadjik1
tadjik1 previously approved these changes Mar 16, 2026
addaleax
addaleax previously approved these changes Mar 16, 2026
Co-authored-by: Anna Henningsen <github@addaleax.net>
@tadjik1 tadjik1 dismissed stale reviews from addaleax and themself via d0a94da March 16, 2026 15:14
@dariakp dariakp merged commit ac98f4a into mongodb:main Mar 16, 2026
28 of 30 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Team Review Needs review from team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants