mirror of
https://github.com/oven-sh/bun
synced 2026-02-12 20:09:04 +00:00
Return expected data when using Promises with crypto.generateKeyPair (#13600)
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
This commit is contained in:
79
src/js/internal/promisify.ts
Normal file
79
src/js/internal/promisify.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
const kCustomPromisifiedSymbol = Symbol.for("nodejs.util.promisify.custom");
|
||||
const kCustomPromisifyArgsSymbol = Symbol("customPromisifyArgs");
|
||||
|
||||
function defineCustomPromisify(target, callback) {
|
||||
Object.defineProperty(target, kCustomPromisifiedSymbol, {
|
||||
value: callback,
|
||||
__proto__: null,
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
return callback;
|
||||
}
|
||||
|
||||
function defineCustomPromisifyArgs(target, args) {
|
||||
Object.defineProperty(target, kCustomPromisifyArgsSymbol, {
|
||||
__proto__: null,
|
||||
value: args,
|
||||
enumerable: false,
|
||||
});
|
||||
return args;
|
||||
}
|
||||
|
||||
var promisify = function promisify(original) {
|
||||
if (typeof original !== "function") throw new TypeError('The "original" argument must be of type Function');
|
||||
const custom = original[kCustomPromisifiedSymbol];
|
||||
if (custom) {
|
||||
if (typeof custom !== "function") {
|
||||
throw new TypeError('The "util.promisify.custom" argument must be of type Function');
|
||||
}
|
||||
// ensure that we don't create another promisified function wrapper
|
||||
return defineCustomPromisify(custom, custom);
|
||||
}
|
||||
|
||||
const callbackArgs = original[kCustomPromisifyArgsSymbol];
|
||||
|
||||
function fn(...originalArgs) {
|
||||
const { promise, resolve, reject } = Promise.withResolvers();
|
||||
try {
|
||||
original.$apply(this, [
|
||||
...originalArgs,
|
||||
function (err, ...values) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
if (callbackArgs !== undefined && values.length > 0) {
|
||||
if (!Array.isArray(callbackArgs)) {
|
||||
throw new TypeError('The "customPromisifyArgs" argument must be of type Array');
|
||||
}
|
||||
if (callbackArgs.length !== values.length) {
|
||||
throw new Error("Mismatched length in promisify callback args");
|
||||
}
|
||||
const result = {};
|
||||
for (let i = 0; i < callbackArgs.length; i++) {
|
||||
result[callbackArgs[i]] = values[i];
|
||||
}
|
||||
resolve(result);
|
||||
} else {
|
||||
resolve(values[0]);
|
||||
}
|
||||
},
|
||||
]);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
Object.setPrototypeOf(fn, Object.getPrototypeOf(original));
|
||||
defineCustomPromisify(fn, fn);
|
||||
return Object.defineProperties(fn, Object.getOwnPropertyDescriptors(original));
|
||||
};
|
||||
promisify.custom = kCustomPromisifiedSymbol;
|
||||
|
||||
export default {
|
||||
defineCustomPromisify,
|
||||
defineCustomPromisifyArgs,
|
||||
promisify,
|
||||
};
|
||||
@@ -11935,14 +11935,17 @@ function _generateKeyPairSync(algorithm, options) {
|
||||
}
|
||||
crypto_exports.generateKeyPairSync = _generateKeyPairSync;
|
||||
|
||||
crypto_exports.generateKeyPair = function (algorithm, options, callback) {
|
||||
function _generateKeyPair(algorithm, options, callback) {
|
||||
try {
|
||||
const result = _generateKeyPairSync(algorithm, options);
|
||||
typeof callback === "function" && callback(null, result.publicKey, result.privateKey);
|
||||
} catch (err) {
|
||||
typeof callback === "function" && callback(err);
|
||||
}
|
||||
};
|
||||
}
|
||||
const { defineCustomPromisifyArgs } = require("internal/promisify");
|
||||
defineCustomPromisifyArgs(_generateKeyPair, ["publicKey", "privateKey"]);
|
||||
crypto_exports.generateKeyPair = _generateKeyPair;
|
||||
|
||||
crypto_exports.createSecretKey = function (key, encoding) {
|
||||
if (key instanceof KeyObject || key instanceof CryptoKey) {
|
||||
|
||||
@@ -1,4 +1,32 @@
|
||||
// Hardcoded module "node:timers"
|
||||
const { defineCustomPromisify } = require("internal/promisify");
|
||||
|
||||
// Lazily load node:timers/promises promisified functions onto the global timers.
|
||||
{
|
||||
const { setTimeout: timeout, setImmediate: immediate, setInterval: interval } = globalThis;
|
||||
|
||||
if (timeout && $isCallable(timeout)) {
|
||||
defineCustomPromisify(timeout, function setTimeout(arg1) {
|
||||
const fn = defineCustomPromisify(timeout, require("node:timers/promises").setTimeout);
|
||||
return fn.$apply(this, arguments);
|
||||
});
|
||||
}
|
||||
|
||||
if (immediate && $isCallable(immediate)) {
|
||||
defineCustomPromisify(immediate, function setImmediate(arg1) {
|
||||
const fn = defineCustomPromisify(immediate, require("node:timers/promises").setImmediate);
|
||||
return fn.$apply(this, arguments);
|
||||
});
|
||||
}
|
||||
|
||||
if (interval && $isCallable(interval)) {
|
||||
defineCustomPromisify(interval, function setInterval(arg1) {
|
||||
const fn = defineCustomPromisify(interval, require("node:timers/promises").setInterval);
|
||||
return fn.$apply(this, arguments);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
setTimeout,
|
||||
clearTimeout,
|
||||
|
||||
@@ -3,6 +3,7 @@ const types = require("node:util/types");
|
||||
/** @type {import('node-inspect-extracted')} */
|
||||
const utl = require("internal/util/inspect");
|
||||
const { ERR_INVALID_ARG_TYPE, ERR_OUT_OF_RANGE } = require("internal/errors");
|
||||
const { promisify } = require("internal/promisify");
|
||||
|
||||
const internalErrorName = $newZigFunction("node_util_binding.zig", "internalErrorName", 1);
|
||||
|
||||
@@ -158,80 +159,7 @@ var _extend = function (origin, add) {
|
||||
}
|
||||
return origin;
|
||||
};
|
||||
var kCustomPromisifiedSymbol = Symbol.for("nodejs.util.promisify.custom");
|
||||
function defineCustomPromisify(target, callback) {
|
||||
Object.defineProperty(target, kCustomPromisifiedSymbol, {
|
||||
value: callback,
|
||||
__proto__: null,
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
return callback;
|
||||
}
|
||||
|
||||
// Lazily load node:timers/promises promisifed functions onto the global timers.
|
||||
// This is not a complete solution, as one could load these without loading the "util" module
|
||||
// But it is better than nothing.
|
||||
{
|
||||
const { setTimeout: timeout, setImmediate: immediate, setInterval: interval } = globalThis;
|
||||
|
||||
if (timeout && $isCallable(timeout)) {
|
||||
defineCustomPromisify(timeout, function setTimeout(arg1) {
|
||||
const fn = defineCustomPromisify(timeout, require("node:timers/promises").setTimeout);
|
||||
return fn.$apply(this, arguments);
|
||||
});
|
||||
}
|
||||
|
||||
if (immediate && $isCallable(immediate)) {
|
||||
defineCustomPromisify(immediate, function setImmediate(arg1) {
|
||||
const fn = defineCustomPromisify(immediate, require("node:timers/promises").setImmediate);
|
||||
return fn.$apply(this, arguments);
|
||||
});
|
||||
}
|
||||
|
||||
if (interval && $isCallable(interval)) {
|
||||
defineCustomPromisify(interval, function setInterval(arg1) {
|
||||
const fn = defineCustomPromisify(interval, require("node:timers/promises").setInterval);
|
||||
return fn.$apply(this, arguments);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var promisify = function promisify(original) {
|
||||
if (typeof original !== "function") throw new TypeError('The "original" argument must be of type Function');
|
||||
const custom = original[kCustomPromisifiedSymbol];
|
||||
if (custom) {
|
||||
if (typeof custom !== "function") {
|
||||
throw new TypeError('The "util.promisify.custom" argument must be of type Function');
|
||||
}
|
||||
// ensure that we don't create another promisified function wrapper
|
||||
return defineCustomPromisify(custom, custom);
|
||||
}
|
||||
|
||||
function fn(...originalArgs) {
|
||||
const { promise, resolve, reject } = Promise.withResolvers();
|
||||
try {
|
||||
original.$apply(this, [
|
||||
...originalArgs,
|
||||
function (err, ...values) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
resolve(values[0]);
|
||||
},
|
||||
]);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
Object.setPrototypeOf(fn, Object.getPrototypeOf(original));
|
||||
defineCustomPromisify(fn, fn);
|
||||
return Object.defineProperties(fn, getOwnPropertyDescriptors(original));
|
||||
};
|
||||
promisify.custom = kCustomPromisifiedSymbol;
|
||||
function callbackifyOnRejected(reason, cb) {
|
||||
if (!reason) {
|
||||
var newReason = new Error("Promise was rejected with a falsy value");
|
||||
|
||||
27
test/regression/issue/09469.test.ts
Normal file
27
test/regression/issue/09469.test.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
const crypto = require("crypto");
|
||||
const util = require("util");
|
||||
|
||||
if (!crypto.generateKeyPair) {
|
||||
test.skip("missing crypto.generateKeyPair");
|
||||
}
|
||||
|
||||
test("09469", async () => {
|
||||
const generateKeyPairAsync = util.promisify(crypto.generateKeyPair);
|
||||
const ret = await generateKeyPairAsync("rsa", {
|
||||
publicExponent: 3,
|
||||
modulusLength: 512,
|
||||
publicKeyEncoding: {
|
||||
type: "pkcs1",
|
||||
format: "pem",
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
type: "pkcs8",
|
||||
format: "pem",
|
||||
},
|
||||
});
|
||||
|
||||
expect(Object.keys(ret)).toHaveLength(2);
|
||||
const { publicKey, privateKey } = ret;
|
||||
expect(typeof publicKey).toBe("string");
|
||||
expect(typeof privateKey).toBe("string");
|
||||
});
|
||||
Reference in New Issue
Block a user