1// @effect-diagnostics nodeBuiltinImport:off
2/// <reference types="node" />
3
4import * as NodeCrypto from "node:crypto";
5
6function publicKeyFor(privateKey: Uint8Array) {
7 const ecdh = NodeCrypto.createECDH("prime256v1");
8 ecdh.setPrivateKey(privateKey);
9 return ecdh.getPublicKey();
10}
11
12/**
13 * Stands in for the T3NativeControls DPoP functions with Node's P-256.
14 * Return it from a mocked `expo` `requireNativeModule`.
15 */
16export function createNodeDpopKeysModule() {
17 return {
18 generateDpopKey: () => {
19 const ecdh = NodeCrypto.createECDH("prime256v1");
20 const publicKey = ecdh.generateKeys();
21 const privateKey = ecdh.getPrivateKey();
22 return Promise.resolve(
23 new Uint8Array(
24 Buffer.concat([Buffer.alloc(32 - privateKey.length), privateKey, publicKey]),
25 ),
26 );
27 },
28 dpopKeyMatches: (privateKey: Uint8Array, publicKey: Uint8Array) =>
29 Promise.resolve(publicKeyFor(privateKey).equals(publicKey)),
30 signDpop: (privateKey: Uint8Array, signingInput: Uint8Array) => {
31 const publicKey = publicKeyFor(privateKey);
32 const key = NodeCrypto.createPrivateKey({
33 format: "jwk",
34 key: {
35 kty: "EC",
36 crv: "P-256",
37 d: Buffer.from(privateKey).toString("base64url"),
38 x: publicKey.subarray(1, 33).toString("base64url"),
39 y: publicKey.subarray(33).toString("base64url"),
40 },
41 });
42 // ieee-p1363 is the raw r‖s pair the native functions return.
43 return Promise.resolve(
44 new Uint8Array(NodeCrypto.sign("sha256", signingInput, { key, dsaEncoding: "ieee-p1363" })),
45 );
46 },
47 };
48}