@hsuite/smart-engines-sdk 3.5.0 → 3.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/index.d.ts +59 -2
- package/dist/index.js +231 -125
- package/dist/index.js.map +1 -1
- package/dist/ipfs-access-key/index.js.map +1 -1
- package/dist/k8s-secret-reader/index.js.map +1 -1
- package/dist/nestjs/index.d.ts +53 -1
- package/dist/nestjs/index.js +232 -87
- package/dist/nestjs/index.js.map +1 -1
- package/dist/pqc-verify/index.js.map +1 -1
- package/dist/pqc-verify-envelope/index.d.ts +1 -1
- package/dist/pqc-verify-envelope/index.js +2 -37
- package/dist/pqc-verify-envelope/index.js.map +1 -1
- package/package.json +16 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ipfs-access-key/retrieve-access-key.ts"],"names":["sha384","ml_kem768","ml_kem1024","hkdf"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Customer-side helper for retrieving an IPFS pinned-content\n * access-key envelope and decapsulating the wrapped CEK — Arc 10.\n *\n * Spec: `docs/superpowers/specs/2026-05-29-kyber-mlkem-production-readiness.md`\n * §4 row 9.\n *\n * # Layering\n *\n * Validators expose the envelope read path via `IpfsAccessKeyService.getEnvelope`\n * (libs/ipfs-core). Customers don't import that module — they import this\n * SDK helper. The SDK does NOT impose a fetch mechanism (HTTP vs direct\n * Mongo vs custom RPC); the caller passes an `envelopeProvider` callback\n * that returns the raw envelope JSON.\n *\n * # No key material on the wire\n *\n * The caller's Kyber secret key stays in their process. Decap runs locally.\n * The `envelopeProvider` only ever fetches a public artifact (the hybrid\n * envelope contains zero plaintext bytes — the wrapped CEK is encrypted to\n * the caller's pk).\n */\nimport { ml_kem768, ml_kem1024 } from '@noble/post-quantum/ml-kem';\nimport { hkdf } from '@noble/hashes/hkdf';\nimport { sha384 } from '@noble/hashes/sha2';\n\n/**\n * Minimal shape of the access-key envelope as it appears on the wire.\n * Mirrors `KyberAesEnvelopeV1` from\n * `libs/security-core/src/encryption-pqc/envelope.types.ts` but inlined\n * here so the SDK has zero workspace dependencies.\n */\nexport type IpfsAccessKeyEnvelope = {\n version: 'kyber-aes-v1';\n kemAlgorithm: 'ml-kem-768' | 'ml-kem-1024';\n kemCiphertext: string;\n recipientPkFingerprint: string;\n aesAlgorithm: 'aes-256-gcm';\n aesIv: string;\n aesCiphertext: string;\n aesAuthTag: string;\n kdfAlgorithm: 'hkdf-sha384';\n kdfSalt: string;\n kdfLabel: string;\n encryptedAt: number;\n};\n\n/**\n * Per-surface HKDF label prefix for IPFS access-key envelopes. Must match\n * the producer-side constant `IPFS_ACCESS_KEY_KDF_LABEL_PREFIX` in\n * `libs/ipfs-core/src/access-key-envelope/access-key-envelope.types.ts`.\n *\n * The full per-CID label is `${PREFIX}${cid}` — see\n * `buildIpfsAccessKeyKdfLabel`.\n */\nexport const IPFS_ACCESS_KEY_KDF_LABEL_PREFIX = 'ipfs-pinned-access-key-v1::';\n\n/** Build the per-CID HKDF label expected by `retrieveAndDecryptAccessKey`. */\nexport function buildIpfsAccessKeyKdfLabel(cid: string): string {\n return `${IPFS_ACCESS_KEY_KDF_LABEL_PREFIX}${cid}`;\n}\n\n/**\n * Compute the recipient-pk fingerprint exactly as the validator does:\n * `hex(sha384(pk)[0..16])`. The fingerprint identifies WHICH envelope row\n * to fetch when a CID has multiple recipients.\n */\nexport function fingerprintRecipientPk(recipientPk: Uint8Array): string {\n const hash = sha384(recipientPk).subarray(0, 16);\n return bytesToHex(hash);\n}\n\n/**\n * Fetch + decap the IPFS access-key envelope for `cid`.\n *\n * @param params.cid the IPFS CID whose CEK we want to unwrap.\n * @param params.recipientSk caller's Kyber secret key (must correspond\n * to the pk used by the producer).\n * @param params.recipientPk caller's Kyber public key — used to compute\n * the fingerprint passed to `envelopeProvider`. (We can't derive the pk\n * from the sk without re-running keygen on the seed, which the SDK does\n * not store, so the caller passes the pk explicitly.)\n * @param params.envelopeProvider caller-supplied fetch — given the CID +\n * their fingerprint, returns the raw envelope JSON or `null` if no row\n * exists. Caller chooses the fetch mechanism (HTTP API to the validator,\n * direct Mongo read, custom RPC, etc.).\n *\n * @returns the original CEK bytes, or `null` if no envelope row exists\n * for `(cid, fingerprint)` — back-compat path: content pinned before\n * Arc 10 has no envelope, caller falls back to \"no access control\".\n *\n * @throws if envelope's `kdfLabel` does not match the per-CID label\n * (substitution attack detected). AES-GCM auth-tag failure propagates\n * from the noble decryption path.\n */\nexport async function retrieveAndDecryptAccessKey(params: {\n cid: string;\n recipientSk: Uint8Array;\n recipientPk: Uint8Array;\n envelopeProvider: (\n cid: string,\n recipientPkFingerprint: string,\n ) => Promise<IpfsAccessKeyEnvelope | null>;\n}): Promise<Uint8Array | null> {\n const fp = fingerprintRecipientPk(params.recipientPk);\n const envelope = await params.envelopeProvider(params.cid, fp);\n if (!envelope) return null;\n\n const expectedLabel = buildIpfsAccessKeyKdfLabel(params.cid);\n if (envelope.kdfLabel !== expectedLabel) {\n throw new Error(\n `ipfs-access-key envelope label mismatch: expected='${expectedLabel}', ` +\n `actual='${envelope.kdfLabel}'`,\n );\n }\n\n // KEM decapsulation.\n const kem = envelope.kemAlgorithm === 'ml-kem-768' ? ml_kem768 : ml_kem1024;\n const kemCt = base64ToBytes(envelope.kemCiphertext);\n const sharedSecret = kem.decapsulate(kemCt, params.recipientSk);\n\n // HKDF-SHA384 → 32-byte AES-256 key.\n const kdfSalt = base64ToBytes(envelope.kdfSalt);\n const labelBytes = new TextEncoder().encode(envelope.kdfLabel);\n const derivedKey = hkdf(sha384, sharedSecret, kdfSalt, labelBytes, 32);\n\n // AES-256-GCM decrypt via WebCrypto (universal — works in Node, browser,\n // Deno, edge runtimes; the SDK avoids hard-coding Node's `crypto`).\n const aesIv = base64ToBytes(envelope.aesIv);\n const aesCt = base64ToBytes(envelope.aesCiphertext);\n const aesTag = base64ToBytes(envelope.aesAuthTag);\n\n // WebCrypto AES-GCM expects ct || tag concatenated. Backed by a fresh\n // ArrayBuffer (not SharedArrayBuffer) so the TypeScript lib's strict\n // BufferSource shape accepts it across all target runtimes.\n const ctWithTag = new Uint8Array(new ArrayBuffer(aesCt.length + aesTag.length));\n ctWithTag.set(aesCt, 0);\n ctWithTag.set(aesTag, aesCt.length);\n\n const derivedKeyBuf = new Uint8Array(new ArrayBuffer(derivedKey.length));\n derivedKeyBuf.set(derivedKey, 0);\n\n const aesIvBuf = new Uint8Array(new ArrayBuffer(aesIv.length));\n aesIvBuf.set(aesIv, 0);\n\n const subtle = getWebCrypto().subtle;\n const cryptoKey = await subtle.importKey(\n 'raw',\n derivedKeyBuf,\n { name: 'AES-GCM' },\n false,\n ['decrypt'],\n );\n const plaintext = await subtle.decrypt(\n { name: 'AES-GCM', iv: aesIvBuf, tagLength: 128 },\n cryptoKey,\n ctWithTag,\n );\n return new Uint8Array(plaintext);\n}\n\n// ── helpers (vendored to avoid Node-only deps) ────────────────────────\n\nfunction bytesToHex(bytes: Uint8Array): string {\n let out = '';\n for (const b of bytes) out += b.toString(16).padStart(2, '0');\n return out;\n}\n\nfunction base64ToBytes(b64: string): Uint8Array {\n // Universal base64 decode: works in Node (Buffer) and browsers (atob).\n if (typeof Buffer !== 'undefined') {\n return new Uint8Array(Buffer.from(b64, 'base64'));\n }\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i += 1) out[i] = bin.charCodeAt(i);\n return out;\n}\n\n/**\n * Minimal structural slice of the WebCrypto interface we depend on. Avoids\n * a hard dep on the lib.DOM `Crypto` global type — the SDK ships to Node,\n * browsers, Deno, and edge runtimes and we don't want to pull lib.DOM into\n * the build typecheck.\n */\ntype WebCryptoSlice = {\n subtle: {\n importKey(\n format: 'raw',\n keyData: ArrayBuffer | ArrayBufferView,\n algorithm: { name: 'AES-GCM' },\n extractable: boolean,\n keyUsages: ReadonlyArray<'decrypt'>,\n ): Promise<unknown>;\n decrypt(\n algorithm: { name: 'AES-GCM'; iv: ArrayBuffer | ArrayBufferView; tagLength: number },\n key: unknown,\n data: ArrayBuffer | ArrayBufferView,\n ): Promise<ArrayBuffer>;\n };\n};\n\nfunction getWebCrypto(): WebCryptoSlice {\n const g = globalThis as unknown as { crypto?: WebCryptoSlice };\n if (g.crypto?.subtle) return g.crypto;\n // Node 18+ exposes globalThis.crypto; older runtimes fall through here.\n throw new Error(\n 'retrieveAndDecryptAccessKey: WebCrypto (globalThis.crypto.subtle) is ' +\n 'not available in this runtime. Use Node 18+ or a browser/edge env.',\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/ipfs-access-key/retrieve-access-key.ts"],"names":["sha384","ml_kem768","ml_kem1024","hkdf"],"mappings":";;;;;;;AAiDO,IAAM,gCAAA,GAAmC;AAGzC,SAAS,2BAA2B,GAAA,EAAqB;AAC9D,EAAA,OAAO,CAAA,EAAG,gCAAgC,CAAA,EAAG,GAAG,CAAA,CAAA;AAClD;AAOO,SAAS,uBAAuB,WAAA,EAAiC;AACtE,EAAA,MAAM,OAAOA,WAAA,CAAO,WAAW,CAAA,CAAE,QAAA,CAAS,GAAG,EAAE,CAAA;AAC/C,EAAA,OAAO,WAAW,IAAI,CAAA;AACxB;AAyBA,eAAsB,4BAA4B,MAAA,EAQnB;AAC7B,EAAA,MAAM,EAAA,GAAK,sBAAA,CAAuB,MAAA,CAAO,WAAW,CAAA;AACpD,EAAA,MAAM,WAAW,MAAM,MAAA,CAAO,gBAAA,CAAiB,MAAA,CAAO,KAAK,EAAE,CAAA;AAC7D,EAAA,IAAI,CAAC,UAAU,OAAO,IAAA;AAEtB,EAAA,MAAM,aAAA,GAAgB,0BAAA,CAA2B,MAAA,CAAO,GAAG,CAAA;AAC3D,EAAA,IAAI,QAAA,CAAS,aAAa,aAAA,EAAe;AACvC,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,mDAAA,EAAsD,aAAa,CAAA,WAAA,EACtD,QAAA,CAAS,QAAQ,CAAA,CAAA;AAAA,KAChC;AAAA,EACF;AAGA,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,YAAA,KAAiB,YAAA,GAAeC,eAAA,GAAYC,gBAAA;AACjE,EAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,QAAA,CAAS,aAAa,CAAA;AAClD,EAAA,MAAM,YAAA,GAAe,GAAA,CAAI,WAAA,CAAY,KAAA,EAAO,OAAO,WAAW,CAAA;AAG9D,EAAA,MAAM,OAAA,GAAU,aAAA,CAAc,QAAA,CAAS,OAAO,CAAA;AAC9C,EAAA,MAAM,aAAa,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,SAAS,QAAQ,CAAA;AAC7D,EAAA,MAAM,aAAaC,SAAA,CAAKH,WAAA,EAAQ,YAAA,EAAc,OAAA,EAAS,YAAY,EAAE,CAAA;AAIrE,EAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,QAAA,CAAS,KAAK,CAAA;AAC1C,EAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,QAAA,CAAS,aAAa,CAAA;AAClD,EAAA,MAAM,MAAA,GAAS,aAAA,CAAc,QAAA,CAAS,UAAU,CAAA;AAKhD,EAAA,MAAM,SAAA,GAAY,IAAI,UAAA,CAAW,IAAI,YAAY,KAAA,CAAM,MAAA,GAAS,MAAA,CAAO,MAAM,CAAC,CAAA;AAC9E,EAAA,SAAA,CAAU,GAAA,CAAI,OAAO,CAAC,CAAA;AACtB,EAAA,SAAA,CAAU,GAAA,CAAI,MAAA,EAAQ,KAAA,CAAM,MAAM,CAAA;AAElC,EAAA,MAAM,gBAAgB,IAAI,UAAA,CAAW,IAAI,WAAA,CAAY,UAAA,CAAW,MAAM,CAAC,CAAA;AACvE,EAAA,aAAA,CAAc,GAAA,CAAI,YAAY,CAAC,CAAA;AAE/B,EAAA,MAAM,WAAW,IAAI,UAAA,CAAW,IAAI,WAAA,CAAY,KAAA,CAAM,MAAM,CAAC,CAAA;AAC7D,EAAA,QAAA,CAAS,GAAA,CAAI,OAAO,CAAC,CAAA;AAErB,EAAA,MAAM,MAAA,GAAS,cAAa,CAAE,MAAA;AAC9B,EAAA,MAAM,SAAA,GAAY,MAAM,MAAA,CAAO,SAAA;AAAA,IAC7B,KAAA;AAAA,IACA,aAAA;AAAA,IACA,EAAE,MAAM,SAAA,EAAU;AAAA,IAClB,KAAA;AAAA,IACA,CAAC,SAAS;AAAA,GACZ;AACA,EAAA,MAAM,SAAA,GAAY,MAAM,MAAA,CAAO,OAAA;AAAA,IAC7B,EAAE,IAAA,EAAM,SAAA,EAAW,EAAA,EAAI,QAAA,EAAU,WAAW,GAAA,EAAI;AAAA,IAChD,SAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,OAAO,IAAI,WAAW,SAAS,CAAA;AACjC;AAIA,SAAS,WAAW,KAAA,EAA2B;AAC7C,EAAA,IAAI,GAAA,GAAM,EAAA;AACV,EAAA,KAAA,MAAW,CAAA,IAAK,OAAO,GAAA,IAAO,CAAA,CAAE,SAAS,EAAE,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAA;AAC5D,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,cAAc,GAAA,EAAyB;AAE9C,EAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,IAAA,OAAO,IAAI,UAAA,CAAW,MAAA,CAAO,IAAA,CAAK,GAAA,EAAK,QAAQ,CAAC,CAAA;AAAA,EAClD;AACA,EAAA,MAAM,GAAA,GAAM,KAAK,GAAG,CAAA;AACpB,EAAA,MAAM,GAAA,GAAM,IAAI,UAAA,CAAW,GAAA,CAAI,MAAM,CAAA;AACrC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,MAAA,EAAQ,CAAA,IAAK,CAAA,EAAG,GAAA,CAAI,CAAC,CAAA,GAAI,GAAA,CAAI,UAAA,CAAW,CAAC,CAAA;AACjE,EAAA,OAAO,GAAA;AACT;AAyBA,SAAS,YAAA,GAA+B;AACtC,EAAA,MAAM,CAAA,GAAI,UAAA;AACV,EAAA,IAAI,CAAA,CAAE,MAAA,EAAQ,MAAA,EAAQ,OAAO,CAAA,CAAE,MAAA;AAE/B,EAAA,MAAM,IAAI,KAAA;AAAA,IACR;AAAA,GAEF;AACF","file":"index.js","sourcesContent":["/**\n * Customer-side helper for retrieving an IPFS pinned-content access-key\n * envelope and decapsulating the wrapped CEK.\n *\n * # Layering\n *\n * Validators expose the envelope read path; customers don't import that\n * module — they import this SDK helper. The SDK does NOT impose a fetch\n * mechanism (HTTP vs direct Mongo vs custom RPC); the caller passes an\n * `envelopeProvider` callback that returns the raw envelope JSON.\n *\n * # No key material on the wire\n *\n * The caller's Kyber secret key stays in their process. Decap runs locally.\n * The `envelopeProvider` only ever fetches a public artifact (the hybrid\n * envelope contains zero plaintext bytes — the wrapped CEK is encrypted to\n * the caller's pk).\n */\nimport { ml_kem768, ml_kem1024 } from '@noble/post-quantum/ml-kem';\nimport { hkdf } from '@noble/hashes/hkdf';\nimport { sha384 } from '@noble/hashes/sha2';\n\n/**\n * Minimal shape of the access-key envelope as it appears on the wire.\n * Mirrors the platform's `KyberAesEnvelopeV1` but inlined here so the SDK has\n * zero workspace dependencies.\n */\nexport type IpfsAccessKeyEnvelope = {\n version: 'kyber-aes-v1';\n kemAlgorithm: 'ml-kem-768' | 'ml-kem-1024';\n kemCiphertext: string;\n recipientPkFingerprint: string;\n aesAlgorithm: 'aes-256-gcm';\n aesIv: string;\n aesCiphertext: string;\n aesAuthTag: string;\n kdfAlgorithm: 'hkdf-sha384';\n kdfSalt: string;\n kdfLabel: string;\n encryptedAt: number;\n};\n\n/**\n * Per-surface HKDF label prefix for IPFS access-key envelopes. Must match\n * the producer-side constant.\n *\n * The full per-CID label is `${PREFIX}${cid}` — see\n * {@link buildIpfsAccessKeyKdfLabel}.\n */\nexport const IPFS_ACCESS_KEY_KDF_LABEL_PREFIX = 'ipfs-pinned-access-key-v1::';\n\n/** Build the per-CID HKDF label expected by `retrieveAndDecryptAccessKey`. */\nexport function buildIpfsAccessKeyKdfLabel(cid: string): string {\n return `${IPFS_ACCESS_KEY_KDF_LABEL_PREFIX}${cid}`;\n}\n\n/**\n * Compute the recipient-pk fingerprint exactly as the validator does:\n * `hex(sha384(pk)[0..16])`. The fingerprint identifies WHICH envelope row\n * to fetch when a CID has multiple recipients.\n */\nexport function fingerprintRecipientPk(recipientPk: Uint8Array): string {\n const hash = sha384(recipientPk).subarray(0, 16);\n return bytesToHex(hash);\n}\n\n/**\n * Fetch + decap the IPFS access-key envelope for `cid`.\n *\n * @param params.cid the IPFS CID whose CEK we want to unwrap.\n * @param params.recipientSk caller's Kyber secret key (must correspond\n * to the pk used by the producer).\n * @param params.recipientPk caller's Kyber public key — used to compute\n * the fingerprint passed to `envelopeProvider`. (We can't derive the pk\n * from the sk without re-running keygen on the seed, which the SDK does\n * not store, so the caller passes the pk explicitly.)\n * @param params.envelopeProvider caller-supplied fetch — given the CID +\n * their fingerprint, returns the raw envelope JSON or `null` if no row\n * exists. Caller chooses the fetch mechanism (HTTP API to the validator,\n * direct Mongo read, custom RPC, etc.).\n *\n * @returns the original CEK bytes, or `null` if no envelope row exists\n * for `(cid, fingerprint)` — e.g. content with no access control, in which\n * case the caller falls back to \"no access control\".\n *\n * @throws if envelope's `kdfLabel` does not match the per-CID label\n * (substitution attack detected). AES-GCM auth-tag failure propagates\n * from the noble decryption path.\n */\nexport async function retrieveAndDecryptAccessKey(params: {\n cid: string;\n recipientSk: Uint8Array;\n recipientPk: Uint8Array;\n envelopeProvider: (\n cid: string,\n recipientPkFingerprint: string,\n ) => Promise<IpfsAccessKeyEnvelope | null>;\n}): Promise<Uint8Array | null> {\n const fp = fingerprintRecipientPk(params.recipientPk);\n const envelope = await params.envelopeProvider(params.cid, fp);\n if (!envelope) return null;\n\n const expectedLabel = buildIpfsAccessKeyKdfLabel(params.cid);\n if (envelope.kdfLabel !== expectedLabel) {\n throw new Error(\n `ipfs-access-key envelope label mismatch: expected='${expectedLabel}', ` +\n `actual='${envelope.kdfLabel}'`,\n );\n }\n\n // KEM decapsulation.\n const kem = envelope.kemAlgorithm === 'ml-kem-768' ? ml_kem768 : ml_kem1024;\n const kemCt = base64ToBytes(envelope.kemCiphertext);\n const sharedSecret = kem.decapsulate(kemCt, params.recipientSk);\n\n // HKDF-SHA384 → 32-byte AES-256 key.\n const kdfSalt = base64ToBytes(envelope.kdfSalt);\n const labelBytes = new TextEncoder().encode(envelope.kdfLabel);\n const derivedKey = hkdf(sha384, sharedSecret, kdfSalt, labelBytes, 32);\n\n // AES-256-GCM decrypt via WebCrypto (universal — works in Node, browser,\n // Deno, edge runtimes; the SDK avoids hard-coding Node's `crypto`).\n const aesIv = base64ToBytes(envelope.aesIv);\n const aesCt = base64ToBytes(envelope.aesCiphertext);\n const aesTag = base64ToBytes(envelope.aesAuthTag);\n\n // WebCrypto AES-GCM expects ct || tag concatenated. Backed by a fresh\n // ArrayBuffer (not SharedArrayBuffer) so the TypeScript lib's strict\n // BufferSource shape accepts it across all target runtimes.\n const ctWithTag = new Uint8Array(new ArrayBuffer(aesCt.length + aesTag.length));\n ctWithTag.set(aesCt, 0);\n ctWithTag.set(aesTag, aesCt.length);\n\n const derivedKeyBuf = new Uint8Array(new ArrayBuffer(derivedKey.length));\n derivedKeyBuf.set(derivedKey, 0);\n\n const aesIvBuf = new Uint8Array(new ArrayBuffer(aesIv.length));\n aesIvBuf.set(aesIv, 0);\n\n const subtle = getWebCrypto().subtle;\n const cryptoKey = await subtle.importKey(\n 'raw',\n derivedKeyBuf,\n { name: 'AES-GCM' },\n false,\n ['decrypt'],\n );\n const plaintext = await subtle.decrypt(\n { name: 'AES-GCM', iv: aesIvBuf, tagLength: 128 },\n cryptoKey,\n ctWithTag,\n );\n return new Uint8Array(plaintext);\n}\n\n// ── helpers (vendored to avoid Node-only deps) ────────────────────────\n\nfunction bytesToHex(bytes: Uint8Array): string {\n let out = '';\n for (const b of bytes) out += b.toString(16).padStart(2, '0');\n return out;\n}\n\nfunction base64ToBytes(b64: string): Uint8Array {\n // Universal base64 decode: works in Node (Buffer) and browsers (atob).\n if (typeof Buffer !== 'undefined') {\n return new Uint8Array(Buffer.from(b64, 'base64'));\n }\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i += 1) out[i] = bin.charCodeAt(i);\n return out;\n}\n\n/**\n * Minimal structural slice of the WebCrypto interface we depend on. Avoids\n * a hard dep on the lib.DOM `Crypto` global type — the SDK ships to Node,\n * browsers, Deno, and edge runtimes and we don't want to pull lib.DOM into\n * the build typecheck.\n */\ntype WebCryptoSlice = {\n subtle: {\n importKey(\n format: 'raw',\n keyData: ArrayBuffer | ArrayBufferView,\n algorithm: { name: 'AES-GCM' },\n extractable: boolean,\n keyUsages: ReadonlyArray<'decrypt'>,\n ): Promise<unknown>;\n decrypt(\n algorithm: { name: 'AES-GCM'; iv: ArrayBuffer | ArrayBufferView; tagLength: number },\n key: unknown,\n data: ArrayBuffer | ArrayBufferView,\n ): Promise<ArrayBuffer>;\n };\n};\n\nfunction getWebCrypto(): WebCryptoSlice {\n const g = globalThis as unknown as { crypto?: WebCryptoSlice };\n if (g.crypto?.subtle) return g.crypto;\n // Node 18+ exposes globalThis.crypto; older runtimes fall through here.\n throw new Error(\n 'retrieveAndDecryptAccessKey: WebCrypto (globalThis.crypto.subtle) is ' +\n 'not available in this runtime. Use Node 18+ or a browser/edge env.',\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/k8s-secret-reader/decrypt-k8s-secret-value.ts"],"names":["ml_kem768","ml_kem1024","hkdf","sha384","createDecipheriv"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Kyber Arc 9 — K8s Secret value decryption helper.\n *\n * Spec: `docs/superpowers/specs/2026-05-29-kyber-mlkem-production-readiness.md`\n * §4 row 8.\n *\n * # Contract\n *\n * Consumers of a Secret materialized by\n * `K8sSecretWriterService.writeOpaqueSecret` may receive EITHER:\n *\n * - **Envelope shape**: `base64(JSON.stringify(KyberAesEnvelopeV1))` —\n * the post-Arc-9 write path. Decrypts the inlined hybrid envelope\n * (KEM-decap → HKDF → AES-256-GCM) under the per-surface HKDF label\n * root + caller's `labelSuffix`. Mirror of\n * `libs/security-core/src/encryption-pqc/decrypt-hybrid.ts` —\n * intentionally inlined so the SDK has no security-core runtime\n * dependency (only the @noble/* primitives, which the SDK already\n * ships for the sibling `pqc-verify` + `pqc-verify-envelope` subpaths).\n * - **Legacy plaintext shape**: raw plaintext string written before Arc 9\n * wired the wrap. Returned bit-for-bit as UTF-8 bytes for back-compat\n * during the 12-month migration window per spec §7.\n *\n * The helper auto-detects the shape by base64-decoding then JSON-parsing\n * the value and checking `version === 'kyber-aes-v1'`. Any other shape →\n * legacy pass-through.\n *\n * # Label suffix discipline\n *\n * The writer's `options.labelSuffix` MUST match the reader's\n * `options.labelSuffix` — they compose the same final HKDF label\n * (`'k8s-secret-materialization-v1' + suffix`). Mismatch throws\n * `KyberLabelMismatchError` BEFORE KEM decap (substitution-attack defense).\n *\n * # Secret-key handling\n *\n * Callers MUST supply the cluster Kyber secret key. On smart-validator\n * this is `DkgKyberKeypairProvider.getClusterKyberKeypair(algo).secretKey`\n * — the SAME source the writer's `getClusterKyberPublicKey` consults.\n * Apps without TSS infrastructure can't decrypt envelopes — by design —\n * and either consume plaintext-only Secrets during back-compat OR receive\n * a delegated decryption endpoint from the validator (future arc).\n *\n * @example Validator-side consumer\n * ```ts\n * import { decryptK8sSecretValue } from '@hsuite/smart-engines-sdk/k8s-secret-reader';\n *\n * const pair = await clusterKyberProvider.getClusterKyberKeypair('ml-kem-768');\n * try {\n * const usernameBytes = await decryptK8sSecretValue(\n * // K8s `data` is base64 of the writer-emitted value — decode once first.\n * Buffer.from(secret.data['username'], 'base64').toString('utf-8'),\n * pair.secretKey,\n * 'ml-kem-768',\n * { labelSuffix: ':harbor-admin' },\n * );\n * const username = new TextDecoder().decode(usernameBytes);\n * } finally {\n * pair.secretKey.fill(0); // wipe after decap\n * }\n * ```\n */\nimport { createDecipheriv } from 'crypto';\nimport { ml_kem768, ml_kem1024 } from '@noble/post-quantum/ml-kem';\nimport { hkdf } from '@noble/hashes/hkdf';\nimport { sha384 } from '@noble/hashes/sha2';\n\n/**\n * Per-surface HKDF label root used by the K8s secret materialization\n * writer + reader pair. Re-exported so consumers can verify they're\n * composing the same label without having to import the provisioner-\n * internal constant.\n *\n * Final label composition: `${K8S_SECRET_MATERIALIZATION_LABEL_ROOT}${labelSuffix ?? ''}`.\n *\n * Examples:\n * - generic (no suffix): `'k8s-secret-materialization-v1'`\n * - harbor admin : `'k8s-secret-materialization-v1::harbor-admin'`\n * - smart-app env : `'k8s-secret-materialization-v1::smart-app-env'`\n */\nexport const K8S_SECRET_MATERIALIZATION_LABEL_ROOT =\n 'k8s-secret-materialization-v1';\n\n/**\n * ML-KEM parameter set literal (mirrors\n * `KyberKemAlgorithm` from `@hsuite/smart-engines-security-core`,\n * inlined to keep the SDK's runtime free of the security-core dep).\n */\nexport type KyberKemAlgorithm = 'ml-kem-768' | 'ml-kem-1024';\n\n/**\n * Options for {@link decryptK8sSecretValue}.\n *\n * @field labelSuffix - per-call-site discriminator the WRITER passed\n * (must match exactly; mismatch throws a label-mismatch error BEFORE\n * KEM decap). Default empty string (generic label root).\n */\nexport type DecryptK8sSecretValueOptions = {\n labelSuffix?: string;\n};\n\n/**\n * Internal — minimal KyberAesEnvelopeV1 shape sufficient for routing +\n * decap. Mirrors `libs/security-core/src/encryption-pqc/envelope.types.ts`\n * KyberAesEnvelopeV1. Inlined to keep the SDK security-core-free.\n */\ntype KyberAesEnvelopeV1Like = {\n version: 'kyber-aes-v1';\n kemAlgorithm: 'ml-kem-768' | 'ml-kem-1024';\n kemCiphertext: string;\n recipientPkFingerprint: string;\n aesAlgorithm: 'aes-256-gcm';\n aesIv: string;\n aesCiphertext: string;\n aesAuthTag: string;\n kdfAlgorithm: 'hkdf-sha384';\n kdfSalt: string;\n kdfLabel: string;\n encryptedAt: number;\n};\n\n/**\n * Thrown when the envelope's `kdfLabel` does not match the expected label\n * (writer/reader suffix mismatch or cross-surface substitution attempt).\n * Aborts BEFORE KEM decap (no timing leak on decap path).\n */\nexport class K8sSecretLabelMismatchError extends Error {\n constructor(\n public readonly expectedLabel: string,\n public readonly actualLabel: string,\n ) {\n super(\n `K8s Secret envelope kdfLabel mismatch: expected='${expectedLabel}', actual='${actualLabel}'`,\n );\n this.name = 'K8sSecretLabelMismatchError';\n }\n}\n\n/**\n * Decrypt a K8s Secret value written by `K8sSecretWriterService.writeOpaqueSecret`.\n *\n * @param writerEmittedValue - the value AS WRITTEN by the writer (the\n * string the writer placed in `stringData[key]`). When reading from a\n * live K8s Secret object via the API the `data` map is base64-encoded\n * by K8s — caller must base64-decode ONCE before calling this helper.\n * When reading from a file-system mount of the Secret (the typical\n * consumer path), the file content IS the writer-emitted value\n * directly.\n * @param clusterKyberSk - cluster Kyber secret key matching the\n * `kemAlgorithm` the writer used. Caller is responsible for memory\n * hygiene (wipe after decap).\n * @param algo - ML-KEM parameter set the writer used. Default\n * `'ml-kem-768'` (matches the writer's default for generic K8s secrets);\n * harbor admin sites use `'ml-kem-1024'`.\n * @param options - see {@link DecryptK8sSecretValueOptions}.\n * @returns plaintext bytes. UTF-8 strings can be reconstructed via\n * `new TextDecoder().decode(bytes)`.\n *\n * @throws {K8sSecretLabelMismatchError} if the envelope's `kdfLabel`\n * doesn't match the composed expected label.\n * @throws on AES-GCM auth failure (wrong sk, tampered envelope).\n */\nexport async function decryptK8sSecretValue(\n writerEmittedValue: string,\n clusterKyberSk: Uint8Array,\n algo: KyberKemAlgorithm = 'ml-kem-768',\n options?: DecryptK8sSecretValueOptions,\n): Promise<Uint8Array> {\n const suffix = options?.labelSuffix ?? '';\n const expectedLabel = `${K8S_SECRET_MATERIALIZATION_LABEL_ROOT}${suffix}`;\n\n // Step 1 — base64-decode the writer-emitted value. The writer's wrap\n // path emits `base64(JSON.stringify(envelope))`; the legacy plaintext\n // path emits the raw plaintext string. Either way base64-decoding\n // SHOULD succeed (raw plaintext as base64 may produce garbage bytes,\n // which won't JSON-parse below → legacy fall-through).\n let decodedText: string;\n try {\n decodedText = Buffer.from(writerEmittedValue, 'base64').toString('utf-8');\n } catch {\n return new Uint8Array(Buffer.from(writerEmittedValue, 'utf-8'));\n }\n\n // Step 2 — try JSON-parse for envelope detection. Pre-Arc-9 plaintext\n // values are arbitrary user strings; the vast majority WILL NOT parse\n // as JSON, so this is a cheap discriminator.\n let parsed: unknown;\n try {\n parsed = JSON.parse(decodedText);\n } catch {\n // Not JSON → legacy plaintext during compat window. Return the\n // ORIGINAL bytes the writer stored (the writer didn't base64-wrap\n // legacy values either — they went through as-is in `stringData`).\n return new Uint8Array(Buffer.from(writerEmittedValue, 'utf-8'));\n }\n\n // Step 3 — version discriminator. Envelope-shaped JSON with the\n // canonical version literal → decap via the inlined hybrid path.\n if (isKyberAesV1Envelope(parsed)) {\n return decryptHybridInline(parsed, clusterKyberSk, expectedLabel, algo);\n }\n\n // Step 4 — JSON-shaped but NOT our envelope (some pre-Arc-9 caller\n // stored a JSON blob in a Secret value). Return the decoded UTF-8 bytes\n // verbatim so the consumer sees the original JSON string.\n return new Uint8Array(Buffer.from(decodedText, 'utf-8'));\n}\n\n/**\n * Inlined hybrid-decrypt — bit-for-bit equivalent of\n * `libs/security-core/src/encryption-pqc/decrypt-hybrid.ts`. The SDK\n * cannot import security-core (would force every downstream npm consumer\n * to pull the workspace package), so the primitive is duplicated under\n * the same noble dependency set.\n *\n * Steps:\n * 1. Label gate — pre-decap check. Fail-loud BEFORE KEM work.\n * 2. KEM decap with `clusterKyberSk`. The envelope's `kemAlgorithm`\n * MUST match the caller's `algo` argument (otherwise decap silently\n * yields garbage → AES-GCM auth fails in step 4). Cross-checked here.\n * 3. HKDF-SHA384(sharedSecret, salt, label) → 32-byte AES-256 key.\n * 4. AES-256-GCM decrypt with the envelope's IV + auth tag.\n */\nasync function decryptHybridInline(\n env: KyberAesEnvelopeV1Like,\n clusterKyberSk: Uint8Array,\n expectedLabel: string,\n algo: KyberKemAlgorithm,\n): Promise<Uint8Array> {\n if (env.kdfLabel !== expectedLabel) {\n throw new K8sSecretLabelMismatchError(expectedLabel, env.kdfLabel);\n }\n if (env.kemAlgorithm !== algo) {\n throw new Error(\n `K8s Secret envelope kemAlgorithm mismatch: caller='${algo}', envelope='${env.kemAlgorithm}'. ` +\n `Pass the matching algorithm argument to decryptK8sSecretValue.`,\n );\n }\n const kem = env.kemAlgorithm === 'ml-kem-768' ? ml_kem768 : ml_kem1024;\n const kemCt = Buffer.from(env.kemCiphertext, 'base64');\n const sharedSecret = kem.decapsulate(kemCt, clusterKyberSk);\n const kdfSalt = Buffer.from(env.kdfSalt, 'base64');\n const labelBytes = new TextEncoder().encode(env.kdfLabel);\n const derivedKey = hkdf(sha384, sharedSecret, kdfSalt, labelBytes, 32);\n const aesIv = Buffer.from(env.aesIv, 'base64');\n const aesCt = Buffer.from(env.aesCiphertext, 'base64');\n const aesTag = Buffer.from(env.aesAuthTag, 'base64');\n const decipher = createDecipheriv('aes-256-gcm', derivedKey, aesIv);\n decipher.setAuthTag(aesTag);\n const ptHead = decipher.update(aesCt);\n const ptTail = decipher.final();\n return new Uint8Array(Buffer.concat([ptHead, ptTail]));\n}\n\n/**\n * Discriminator — returns `true` iff the parsed value is a Kyber-AES-v1\n * envelope shape. Checks the `version` literal + minimum field presence\n * to defend against partial/corrupted JSON that happens to be a valid\n * object but lacks the envelope fields.\n *\n * Schema-level validation (kemAlgorithm enum, field types, base64\n * correctness) is handled by the noble libs at decap time — this is\n * purely the routing decision.\n */\nfunction isKyberAesV1Envelope(v: unknown): v is KyberAesEnvelopeV1Like {\n if (typeof v !== 'object' || v === null) return false;\n const env = v as Record<string, unknown>;\n return (\n env['version'] === 'kyber-aes-v1' &&\n typeof env['kemAlgorithm'] === 'string' &&\n typeof env['kemCiphertext'] === 'string' &&\n typeof env['aesCiphertext'] === 'string' &&\n typeof env['aesAuthTag'] === 'string' &&\n typeof env['aesIv'] === 'string' &&\n typeof env['kdfSalt'] === 'string' &&\n typeof env['kdfLabel'] === 'string'\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/k8s-secret-reader/decrypt-k8s-secret-value.ts"],"names":["ml_kem768","ml_kem1024","hkdf","sha384","createDecipheriv"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * K8s Secret value decryption helper.\n *\n * # Contract\n *\n * Consumers of a Secret materialized by the platform's K8s secret writer may\n * receive EITHER:\n *\n * - **Envelope shape**: `base64(JSON.stringify(KyberAesEnvelopeV1))` — the\n * wrapped write path. Decrypts the inlined hybrid envelope\n * (KEM-decap → HKDF → AES-256-GCM) under the per-surface HKDF label\n * root + caller's `labelSuffix`. Mirror of the platform's hybrid-decrypt\n * primitive — intentionally inlined so the SDK has no platform-internal\n * runtime dependency (only the @noble/* primitives, which the SDK already\n * ships for the sibling `pqc-verify` + `pqc-verify-envelope` subpaths).\n * - **Plaintext shape**: a raw plaintext string. Returned bit-for-bit as\n * UTF-8 bytes — covers secrets that were never wrapped.\n *\n * The helper auto-detects the shape by base64-decoding then JSON-parsing\n * the value and checking `version === 'kyber-aes-v1'`. Any other shape is\n * passed through as plaintext bytes.\n *\n * # Label suffix discipline\n *\n * The writer's `options.labelSuffix` MUST match the reader's\n * `options.labelSuffix` — they compose the same final HKDF label\n * (`'k8s-secret-materialization-v1' + suffix`). Mismatch throws\n * `KyberLabelMismatchError` BEFORE KEM decap (substitution-attack defense).\n *\n * # Secret-key handling\n *\n * Callers MUST supply the cluster Kyber secret key. On smart-validator\n * this is `DkgKyberKeypairProvider.getClusterKyberKeypair(algo).secretKey`\n * — the SAME source the writer's `getClusterKyberPublicKey` consults.\n * Apps without TSS infrastructure can't decrypt envelopes — by design —\n * and consume plaintext-shaped Secrets only.\n *\n * @example Validator-side consumer\n * ```ts\n * import { decryptK8sSecretValue } from '@hsuite/smart-engines-sdk/k8s-secret-reader';\n *\n * const pair = await clusterKyberProvider.getClusterKyberKeypair('ml-kem-768');\n * try {\n * const usernameBytes = await decryptK8sSecretValue(\n * // K8s `data` is base64 of the writer-emitted value — decode once first.\n * Buffer.from(secret.data['username'], 'base64').toString('utf-8'),\n * pair.secretKey,\n * 'ml-kem-768',\n * { labelSuffix: ':harbor-admin' },\n * );\n * const username = new TextDecoder().decode(usernameBytes);\n * } finally {\n * pair.secretKey.fill(0); // wipe after decap\n * }\n * ```\n */\nimport { createDecipheriv } from 'crypto';\nimport { ml_kem768, ml_kem1024 } from '@noble/post-quantum/ml-kem';\nimport { hkdf } from '@noble/hashes/hkdf';\nimport { sha384 } from '@noble/hashes/sha2';\n\n/**\n * Per-surface HKDF label root used by the K8s secret materialization\n * writer + reader pair. Re-exported so consumers can verify they're\n * composing the same label without having to import the provisioner-\n * internal constant.\n *\n * Final label composition: `${K8S_SECRET_MATERIALIZATION_LABEL_ROOT}${labelSuffix ?? ''}`.\n *\n * Examples:\n * - generic (no suffix): `'k8s-secret-materialization-v1'`\n * - harbor admin : `'k8s-secret-materialization-v1::harbor-admin'`\n * - smart-app env : `'k8s-secret-materialization-v1::smart-app-env'`\n */\nexport const K8S_SECRET_MATERIALIZATION_LABEL_ROOT =\n 'k8s-secret-materialization-v1';\n\n/**\n * ML-KEM parameter set literal. Inlined to keep the SDK's runtime free of any\n * platform-internal dependency.\n */\nexport type KyberKemAlgorithm = 'ml-kem-768' | 'ml-kem-1024';\n\n/**\n * Options for {@link decryptK8sSecretValue}.\n *\n * @field labelSuffix - per-call-site discriminator the WRITER passed\n * (must match exactly; mismatch throws a label-mismatch error BEFORE\n * KEM decap). Default empty string (generic label root).\n */\nexport type DecryptK8sSecretValueOptions = {\n labelSuffix?: string;\n};\n\n/**\n * Internal — minimal KyberAesEnvelopeV1 shape sufficient for routing and\n * decap. Mirrors the platform's KyberAesEnvelopeV1; inlined to keep the SDK\n * free of any platform-internal dependency.\n */\ntype KyberAesEnvelopeV1Like = {\n version: 'kyber-aes-v1';\n kemAlgorithm: 'ml-kem-768' | 'ml-kem-1024';\n kemCiphertext: string;\n recipientPkFingerprint: string;\n aesAlgorithm: 'aes-256-gcm';\n aesIv: string;\n aesCiphertext: string;\n aesAuthTag: string;\n kdfAlgorithm: 'hkdf-sha384';\n kdfSalt: string;\n kdfLabel: string;\n encryptedAt: number;\n};\n\n/**\n * Thrown when the envelope's `kdfLabel` does not match the expected label\n * (writer/reader suffix mismatch or cross-surface substitution attempt).\n * Aborts BEFORE KEM decap (no timing leak on decap path).\n */\nexport class K8sSecretLabelMismatchError extends Error {\n constructor(\n public readonly expectedLabel: string,\n public readonly actualLabel: string,\n ) {\n super(\n `K8s Secret envelope kdfLabel mismatch: expected='${expectedLabel}', actual='${actualLabel}'`,\n );\n this.name = 'K8sSecretLabelMismatchError';\n }\n}\n\n/**\n * Decrypt a K8s Secret value written by `K8sSecretWriterService.writeOpaqueSecret`.\n *\n * @param writerEmittedValue - the value AS WRITTEN by the writer (the\n * string the writer placed in `stringData[key]`). When reading from a\n * live K8s Secret object via the API the `data` map is base64-encoded\n * by K8s — caller must base64-decode ONCE before calling this helper.\n * When reading from a file-system mount of the Secret (the typical\n * consumer path), the file content IS the writer-emitted value\n * directly.\n * @param clusterKyberSk - cluster Kyber secret key matching the\n * `kemAlgorithm` the writer used. Caller is responsible for memory\n * hygiene (wipe after decap).\n * @param algo - ML-KEM parameter set the writer used. Default\n * `'ml-kem-768'` (matches the writer's default for generic K8s secrets);\n * harbor admin sites use `'ml-kem-1024'`.\n * @param options - see {@link DecryptK8sSecretValueOptions}.\n * @returns plaintext bytes. UTF-8 strings can be reconstructed via\n * `new TextDecoder().decode(bytes)`.\n *\n * @throws {K8sSecretLabelMismatchError} if the envelope's `kdfLabel`\n * doesn't match the composed expected label.\n * @throws on AES-GCM auth failure (wrong sk, tampered envelope).\n */\nexport async function decryptK8sSecretValue(\n writerEmittedValue: string,\n clusterKyberSk: Uint8Array,\n algo: KyberKemAlgorithm = 'ml-kem-768',\n options?: DecryptK8sSecretValueOptions,\n): Promise<Uint8Array> {\n const suffix = options?.labelSuffix ?? '';\n const expectedLabel = `${K8S_SECRET_MATERIALIZATION_LABEL_ROOT}${suffix}`;\n\n // Step 1 — base64-decode the writer-emitted value. The wrap path emits\n // `base64(JSON.stringify(envelope))`; a plaintext value is the raw string.\n // Either way base64-decoding SHOULD succeed (raw plaintext decoded as\n // base64 may produce garbage bytes, which won't JSON-parse below →\n // plaintext fall-through).\n let decodedText: string;\n try {\n decodedText = Buffer.from(writerEmittedValue, 'base64').toString('utf-8');\n } catch {\n return new Uint8Array(Buffer.from(writerEmittedValue, 'utf-8'));\n }\n\n // Step 2 — try JSON-parse for envelope detection. Plaintext values are\n // arbitrary user strings; the vast majority WILL NOT parse as JSON, so\n // this is a cheap discriminator.\n let parsed: unknown;\n try {\n parsed = JSON.parse(decodedText);\n } catch {\n // Not JSON → plaintext value. Return the ORIGINAL bytes the writer\n // stored (plaintext values are written as-is in `stringData`, not\n // base64-wrapped).\n return new Uint8Array(Buffer.from(writerEmittedValue, 'utf-8'));\n }\n\n // Step 3 — version discriminator. Envelope-shaped JSON with the\n // canonical version literal → decap via the inlined hybrid path.\n if (isKyberAesV1Envelope(parsed)) {\n return decryptHybridInline(parsed, clusterKyberSk, expectedLabel, algo);\n }\n\n // Step 4 — JSON-shaped but NOT an envelope (a caller stored a JSON blob\n // in a Secret value). Return the decoded UTF-8 bytes verbatim so the\n // consumer sees the original JSON string.\n return new Uint8Array(Buffer.from(decodedText, 'utf-8'));\n}\n\n/**\n * Inlined hybrid-decrypt — bit-for-bit equivalent of the platform's\n * hybrid-decrypt primitive. The SDK cannot import the platform-internal\n * security package (would force every downstream npm consumer to pull the\n * workspace package), so the primitive is duplicated under the same noble\n * dependency set.\n *\n * Steps:\n * 1. Label gate — pre-decap check. Fail-loud BEFORE KEM work.\n * 2. KEM decap with `clusterKyberSk`. The envelope's `kemAlgorithm`\n * MUST match the caller's `algo` argument (otherwise decap silently\n * yields garbage → AES-GCM auth fails in step 4). Cross-checked here.\n * 3. HKDF-SHA384(sharedSecret, salt, label) → 32-byte AES-256 key.\n * 4. AES-256-GCM decrypt with the envelope's IV + auth tag.\n */\nasync function decryptHybridInline(\n env: KyberAesEnvelopeV1Like,\n clusterKyberSk: Uint8Array,\n expectedLabel: string,\n algo: KyberKemAlgorithm,\n): Promise<Uint8Array> {\n if (env.kdfLabel !== expectedLabel) {\n throw new K8sSecretLabelMismatchError(expectedLabel, env.kdfLabel);\n }\n if (env.kemAlgorithm !== algo) {\n throw new Error(\n `K8s Secret envelope kemAlgorithm mismatch: caller='${algo}', envelope='${env.kemAlgorithm}'. ` +\n `Pass the matching algorithm argument to decryptK8sSecretValue.`,\n );\n }\n const kem = env.kemAlgorithm === 'ml-kem-768' ? ml_kem768 : ml_kem1024;\n const kemCt = Buffer.from(env.kemCiphertext, 'base64');\n const sharedSecret = kem.decapsulate(kemCt, clusterKyberSk);\n const kdfSalt = Buffer.from(env.kdfSalt, 'base64');\n const labelBytes = new TextEncoder().encode(env.kdfLabel);\n const derivedKey = hkdf(sha384, sharedSecret, kdfSalt, labelBytes, 32);\n const aesIv = Buffer.from(env.aesIv, 'base64');\n const aesCt = Buffer.from(env.aesCiphertext, 'base64');\n const aesTag = Buffer.from(env.aesAuthTag, 'base64');\n const decipher = createDecipheriv('aes-256-gcm', derivedKey, aesIv);\n decipher.setAuthTag(aesTag);\n const ptHead = decipher.update(aesCt);\n const ptTail = decipher.final();\n return new Uint8Array(Buffer.concat([ptHead, ptTail]));\n}\n\n/**\n * Discriminator — returns `true` iff the parsed value is a Kyber-AES-v1\n * envelope shape. Checks the `version` literal + minimum field presence\n * to defend against partial/corrupted JSON that happens to be a valid\n * object but lacks the envelope fields.\n *\n * Schema-level validation (kemAlgorithm enum, field types, base64\n * correctness) is handled by the noble libs at decap time — this is\n * purely the routing decision.\n */\nfunction isKyberAesV1Envelope(v: unknown): v is KyberAesEnvelopeV1Like {\n if (typeof v !== 'object' || v === null) return false;\n const env = v as Record<string, unknown>;\n return (\n env['version'] === 'kyber-aes-v1' &&\n typeof env['kemAlgorithm'] === 'string' &&\n typeof env['kemCiphertext'] === 'string' &&\n typeof env['aesCiphertext'] === 'string' &&\n typeof env['aesAuthTag'] === 'string' &&\n typeof env['aesIv'] === 'string' &&\n typeof env['kdfSalt'] === 'string' &&\n typeof env['kdfLabel'] === 'string'\n );\n}\n"]}
|
package/dist/nestjs/index.d.ts
CHANGED
|
@@ -1677,6 +1677,13 @@ export type SubscriptionStatusResponse = {
|
|
|
1677
1677
|
lockedUntil?: string;
|
|
1678
1678
|
};
|
|
1679
1679
|
subscriptionNftSerial?: number;
|
|
1680
|
+
chainNfts?: {
|
|
1681
|
+
xrpl?: {
|
|
1682
|
+
nftId?: string;
|
|
1683
|
+
issuerAddress?: string;
|
|
1684
|
+
offerTxId?: string;
|
|
1685
|
+
};
|
|
1686
|
+
} & Record<string, unknown>;
|
|
1680
1687
|
expiresAt?: string;
|
|
1681
1688
|
remainingBalance?: string;
|
|
1682
1689
|
createdAt?: string;
|
|
@@ -1863,6 +1870,48 @@ declare class SubscriptionClient {
|
|
|
1863
1870
|
getBilling(appId: string, options?: GetBillingOptions): Promise<SubscriptionBillingResponse>;
|
|
1864
1871
|
mintCustomer(request: MintCustomerSubscriptionRequest): Promise<MintCustomerSubscriptionResponse>;
|
|
1865
1872
|
}
|
|
1873
|
+
export type FaucetChallenge = {
|
|
1874
|
+
challengeId: string;
|
|
1875
|
+
message: string;
|
|
1876
|
+
expiresInSeconds: number;
|
|
1877
|
+
};
|
|
1878
|
+
export type FaucetDispenseRequest = {
|
|
1879
|
+
chain: string;
|
|
1880
|
+
recipientAddress: string;
|
|
1881
|
+
challengeId: string;
|
|
1882
|
+
signature: string;
|
|
1883
|
+
publicKey?: string;
|
|
1884
|
+
};
|
|
1885
|
+
export type FaucetDispensed = {
|
|
1886
|
+
status: "dispensed";
|
|
1887
|
+
amount: string;
|
|
1888
|
+
txHash: string;
|
|
1889
|
+
remainingDailyAllowance: string;
|
|
1890
|
+
};
|
|
1891
|
+
export type FaucetTrustlineRequired = {
|
|
1892
|
+
status: "trustline_required";
|
|
1893
|
+
trustLine: {
|
|
1894
|
+
currency: string;
|
|
1895
|
+
issuer: string;
|
|
1896
|
+
limit: string;
|
|
1897
|
+
};
|
|
1898
|
+
};
|
|
1899
|
+
export type FaucetRateLimited = {
|
|
1900
|
+
status: "rate_limited";
|
|
1901
|
+
retryAfterSeconds: number;
|
|
1902
|
+
};
|
|
1903
|
+
export type FaucetDispenseResult = FaucetDispensed | FaucetTrustlineRequired | FaucetRateLimited;
|
|
1904
|
+
export type FaucetStatusResponse = {
|
|
1905
|
+
dispensedToday: string;
|
|
1906
|
+
[key: string]: unknown;
|
|
1907
|
+
};
|
|
1908
|
+
declare class FaucetClient {
|
|
1909
|
+
private readonly http;
|
|
1910
|
+
constructor(http: HttpClient);
|
|
1911
|
+
requestChallenge(chain: string, recipientAddress: string): Promise<FaucetChallenge>;
|
|
1912
|
+
dispense(req: FaucetDispenseRequest): Promise<FaucetDispenseResult>;
|
|
1913
|
+
getStatus(chain: string, recipientAddress: string): Promise<FaucetStatusResponse>;
|
|
1914
|
+
}
|
|
1866
1915
|
export type EntityType = "account" | "token" | "topic";
|
|
1867
1916
|
export type EntityCreationOptions = {
|
|
1868
1917
|
entityType: EntityType;
|
|
@@ -3542,6 +3591,7 @@ export type BaasDeployRequest = {
|
|
|
3542
3591
|
tag: string;
|
|
3543
3592
|
port?: number;
|
|
3544
3593
|
replicas?: number;
|
|
3594
|
+
degree?: number;
|
|
3545
3595
|
env?: Record<string, string>;
|
|
3546
3596
|
resources?: {
|
|
3547
3597
|
cpu?: string;
|
|
@@ -3977,6 +4027,7 @@ declare class SmartEngineClient {
|
|
|
3977
4027
|
private readonly txHttp;
|
|
3978
4028
|
private lastHttpError?;
|
|
3979
4029
|
readonly subscription: SubscriptionClient;
|
|
4030
|
+
readonly faucet: FaucetClient;
|
|
3980
4031
|
readonly tss: TSSClient;
|
|
3981
4032
|
readonly ipfs: IPFSClient;
|
|
3982
4033
|
readonly transactions: TransactionsClient;
|
|
@@ -4634,7 +4685,6 @@ declare class StorageClient {
|
|
|
4634
4685
|
delete(cid: string): Promise<{
|
|
4635
4686
|
success: boolean;
|
|
4636
4687
|
}>;
|
|
4637
|
-
getFile(cid: string): Promise<BaasFileInfo>;
|
|
4638
4688
|
listFiles(pagination?: {
|
|
4639
4689
|
limit?: number;
|
|
4640
4690
|
offset?: number;
|
|
@@ -12235,6 +12285,7 @@ declare class BaasClient {
|
|
|
12235
12285
|
private readonly allowInsecure;
|
|
12236
12286
|
private readonly http;
|
|
12237
12287
|
private lastHttpError?;
|
|
12288
|
+
private authContext?;
|
|
12238
12289
|
readonly db: DatabaseClient;
|
|
12239
12290
|
readonly storage: StorageClient;
|
|
12240
12291
|
readonly functions: FunctionsClient;
|
|
@@ -12256,6 +12307,7 @@ declare class BaasClient {
|
|
|
12256
12307
|
};
|
|
12257
12308
|
private requireAppId;
|
|
12258
12309
|
authenticate(options: AuthenticateOptions): Promise<BaasAuthResult>;
|
|
12310
|
+
private reauthenticate;
|
|
12259
12311
|
validateSession(): Promise<BaasSessionInfo>;
|
|
12260
12312
|
logout(): Promise<void>;
|
|
12261
12313
|
private requireAuth;
|