Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 61 additions & 13 deletions lib/internal/crypto/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -723,9 +723,19 @@ const validateByteSource = hideStackFrames((val, name) => {
val);
});

// CryptoJob constructors can synchronously throw while running their native
// AdditionalConfig hook. WebCrypto needs those operation-specific setup
// failures to reject with an OperationError.
/**
* @template T
* @typedef {{ run(): Promise<T> }} WebCryptoJob
*/

/**
* CryptoJob constructors can synchronously throw while running their native
* AdditionalConfig hook. WebCrypto needs those operation-specific setup
* failures to reject with an OperationError.
* @template T
* @param {() => WebCryptoJob<T>} getJob
* @returns {Promise<T>}
*/
function jobPromise(getJob) {
try {
return getJob().run();
Expand All @@ -736,10 +746,14 @@ function jobPromise(getJob) {
}
}

// Temporarily shadow inherited then accessors on WebCrypto result objects.
// Promise resolution reads "then" synchronously for thenable assimilation.
// Returning an own undefined data property keeps that lookup from reaching
// user-mutated prototypes.
/**
* Temporarily shadow inherited then accessors on WebCrypto result objects.
* Promise resolution reads "then" synchronously for thenable assimilation.
* Returning an own undefined data property keeps that lookup from reaching
* user-mutated prototypes.
* @param {unknown} value
* @returns {boolean}
*/
function prepareWebCryptoResult(value) {
if ((value === null || typeof value !== 'object') &&
typeof value !== 'function') {
Expand All @@ -751,12 +765,27 @@ function prepareWebCryptoResult(value) {
return true;
}

// Remove the temporary then property installed by prepareWebCryptoResult().
/**
* Remove the temporary then property installed by prepareWebCryptoResult().
* @param {{ then?: unknown }} value
* @returns {void}
*/
function cleanupWebCryptoResult(value) {
delete value.then;
}

// Resolve a WebCrypto promise while inherited then accessors are shadowed.
/**
* @template T
* @typedef {(value: T | PromiseLike<T>) => void} WebCryptoResolve
*/

/**
* Resolve a WebCrypto promise while inherited then accessors are shadowed.
* @template T
* @param {WebCryptoResolve<T>} resolve
* @param {T | PromiseLike<T>} value
* @returns {void}
*/
function resolveWebCryptoResult(resolve, value) {
const shouldCleanupResult = prepareWebCryptoResult(value);
try {
Expand All @@ -767,7 +796,17 @@ function resolveWebCryptoResult(resolve, value) {
}
}

// Run a WebCrypto promise reaction and settle the outer promise.
/**
* Run a WebCrypto promise reaction and settle the outer promise.
* @template T
* @template TResult
* @param {((value: T) => TResult | PromiseLike<TResult>) | undefined} handler
* @param {WebCryptoResolve<T | TResult>} resolve
* @param {(reason?: unknown) => void} reject
* @param {T} value
* @param {boolean} isRejected
* @returns {void}
*/
function settleJobPromise(handler, resolve, reject, value, isRejected) {
try {
if (typeof handler === 'function') {
Expand All @@ -782,9 +821,18 @@ function settleJobPromise(handler, resolve, reject, value, isRejected) {
}
}

// Promise.prototype.then gets promise.constructor to determine the result
// promise's species. These promises are internal WebCrypto intermediates, so
// make that lookup stay on the promise itself instead of user-mutated state.
/**
* Promise.prototype.then gets promise.constructor to determine the result
* promise's species. These promises are internal WebCrypto intermediates, so
* make that lookup stay on the promise itself instead of user-mutated state.
* @template T
* @template [TResult1=T]
* @template [TResult2=never]
* @param {Promise<T>} promise
* @param {((value: T) => TResult1 | PromiseLike<TResult1>) | null | undefined} [onFulfilled]
* @param {((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null | undefined} [onRejected]
* @returns {Promise<TResult1 | TResult2>}
*/
function jobPromiseThen(promise, onFulfilled, onRejected) {
const {
promise: resultPromise,
Expand Down
2 changes: 2 additions & 0 deletions typings/globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { BufferBinding } from './internalBinding/buffer';
import { CJSLexerBinding } from './internalBinding/cjs_lexer';
import { ConfigBinding } from './internalBinding/config';
import { ConstantsBinding } from './internalBinding/constants';
import { CryptoBinding } from './internalBinding/crypto';
import { DebugBinding } from './internalBinding/debug';
import { EncodingBinding } from './internalBinding/encoding_binding';
import { HttpParserBinding } from './internalBinding/http_parser';
Expand Down Expand Up @@ -42,6 +43,7 @@ interface InternalBindingMap {
cjs_lexer: CJSLexerBinding;
config: ConfigBinding;
constants: ConstantsBinding;
crypto: CryptoBinding;
debug: DebugBinding;
encoding_binding: EncodingBinding;
fs: FsBinding;
Expand Down
Loading
Loading