abi
abi2y ago

Abusing prototype CryptoKey in `node:crypto`

Is there any way that I can set the prototype of an object to specifically CryptoKey as defined by node:crypto? I am trying to get around some nasty instanceof check in a third-party library which is getting in the way.
import * as krypto from "node:crypto";
Object.setPrototypeOf(foo, krypto.webcrypto.CryptoKey.prototype);
import * as krypto from "node:crypto";
Object.setPrototypeOf(foo, krypto.webcrypto.CryptoKey.prototype);
The above gives me this error:
error: Uncaught TypeError: Cannot read properties of undefined (reading 'prototype')
error: Uncaught TypeError: Cannot read properties of undefined (reading 'prototype')
3 Replies
abi
abiOP2y ago
I also tried just ..., krypto.webcrypto.CryptoKey) but it's still undefined obviously and i'm not quite sure why I'm basically trying to get the type as found in [npm]/@types/node/18.11.18/crypto.d.ts:
interface Crypto {
// ...
CryptoKey: CryptoKeyConstructor;
}

// This constructor throws ILLEGAL_CONSTRUCTOR so it should not be newable.
interface CryptoKeyConstructor {
/** Illegal constructor */
(_: { readonly _: unique symbol }): never; // Allows instanceof to work but not be callable by the user.
readonly length: 0;
readonly name: 'CryptoKey';
readonly prototype: CryptoKey;
}
/**
* @since v15.0.0
*/
interface CryptoKey {

interface Crypto {
// ...
CryptoKey: CryptoKeyConstructor;
}

// This constructor throws ILLEGAL_CONSTRUCTOR so it should not be newable.
interface CryptoKeyConstructor {
/** Illegal constructor */
(_: { readonly _: unique symbol }): never; // Allows instanceof to work but not be callable by the user.
readonly length: 0;
readonly name: 'CryptoKey';
readonly prototype: CryptoKey;
}
/**
* @since v15.0.0
*/
interface CryptoKey {

Actually, looking back at how I even got here makes me question why I'm even doing it, because I'm calling krypto.webcrypto.subtle.importKey and then the return value of that should already be krypto.webcrypto.CryptoKey but this third-party library code does instanceof CryptoKey and says it's "a different" CryptoKey And so does krypto.KeyObject.from:
error: Uncaught TypeError: The "key" argument must be an instance of CryptoKey. Received an instance of CryptoKey
const keyObject = krypto.KeyObject.from(privateCryptoKey);
error: Uncaught TypeError: The "key" argument must be an instance of CryptoKey. Received an instance of CryptoKey
const keyObject = krypto.KeyObject.from(privateCryptoKey);
mmastrac
mmastrac2y ago
In this case, I suspect we're not actually exporting the CryptoKey prototype from the node:crypto polyfill which is probably a bug. We do export CryptoKey in the global namespace -- does this work?
Object.setPrototypeOf(foo, CryptoKey.prototype);
Object.setPrototypeOf(foo, CryptoKey.prototype);
abi
abiOP2y ago
oof, sorry, didn't see your message until now! the whole problem is no more tbh, not exactly sure why, but if it pops back up, i will make sure to give that a try. (but i'm like 90% sure i tried it before and it failed!)