@nice-code/util 0.8.0 → 0.9.0
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/build/index.d.ts +765 -0
- package/build/index.js +966 -1080
- package/build/index.js.map +1 -0
- package/package.json +6 -18
- package/build/types/core/core_valibot_schemas.d.ts +0 -13
- package/build/types/core/createDataStringConverter_stringToObject.d.ts +0 -12
- package/build/types/crypto/aes_gcm/createAesGcmKeyFromX25519Keys.d.ts +0 -6
- package/build/types/crypto/aes_gcm/decryptBytesWithAesGcmKey.d.ts +0 -9
- package/build/types/crypto/aes_gcm/decryptTextDataWithAesGcmKey.d.ts +0 -5
- package/build/types/crypto/aes_gcm/encryptBytesWithAesGcmKey.d.ts +0 -10
- package/build/types/crypto/aes_gcm/encryptTextDataWithAesGcmKey.d.ts +0 -5
- package/build/types/crypto/client_key_link/ClientCryptoKeyLink.d.ts +0 -181
- package/build/types/crypto/client_key_link/buildVerifyKeyBoundInfoString.d.ts +0 -20
- package/build/types/crypto/crypto.converters.d.ts +0 -53
- package/build/types/crypto/crypto.schema.d.ts +0 -92
- package/build/types/crypto/ed25519/generateEd25519KeyPair.d.ts +0 -1
- package/build/types/crypto/ed25519/importEd25519Key.d.ts +0 -35
- package/build/types/crypto/ed25519/serializeEd25519Key_Jwk.d.ts +0 -2
- package/build/types/crypto/ed25519/serializeEd25519Key_Raw.d.ts +0 -2
- package/build/types/crypto/ed25519/signCombinedTextDataWithKeyEd25519.d.ts +0 -2
- package/build/types/crypto/ed25519/signTextDataWithKeyEd25519.d.ts +0 -1
- package/build/types/crypto/ed25519/verifyWithKeyEd25519.d.ts +0 -5
- package/build/types/crypto/index.d.ts +0 -21
- package/build/types/crypto/x25519/createSharedBitsFromX25519.d.ts +0 -4
- package/build/types/crypto/x25519/generateX25519KeyPair.d.ts +0 -1
- package/build/types/crypto/x25519/importX25519Key.d.ts +0 -35
- package/build/types/crypto/x25519/serializeX25519Key_Jwk.d.ts +0 -2
- package/build/types/crypto/x25519/serializeX25519Key_Raw.d.ts +0 -2
- package/build/types/data_type/index.d.ts +0 -1
- package/build/types/data_type/string/nullEmpty.d.ts +0 -3
- package/build/types/index.d.ts +0 -10
- package/build/types/storage_adapter/StorageAdapter.d.ts +0 -23
- package/build/types/storage_adapter/specific/browser/browser_storage.d.ts +0 -26
- package/build/types/storage_adapter/specific/cloudflare/durable_object/durable_object_storage.d.ts +0 -14
- package/build/types/storage_adapter/specific/cloudflare/durable_object/durable_object_storage.types.d.ts +0 -18
- package/build/types/storage_adapter/specific/cloudflare/kv/kv_storage.d.ts +0 -18
- package/build/types/storage_adapter/specific/cloudflare/kv/kv_storage.types.d.ts +0 -22
- package/build/types/storage_adapter/specific/memory/memory_storage.d.ts +0 -28
- package/build/types/storage_adapter/storage_adapter.types.d.ts +0 -21
- package/build/types/storage_adapter/typed_storage/createTypedStorage.d.ts +0 -16
- package/build/types/typescript/special_typescript_types.d.ts +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["fromBase64","fromJwk","fromSerializedObject","fromFormattedString","extractableOrNonExtractable"],"sources":["../src/data_type/string/nullEmpty.ts","../src/crypto/x25519/createSharedBitsFromX25519.ts","../src/crypto/aes_gcm/createAesGcmKeyFromX25519Keys.ts","../src/crypto/aes_gcm/decryptBytesWithAesGcmKey.ts","../src/crypto/aes_gcm/decryptTextDataWithAesGcmKey.ts","../src/crypto/aes_gcm/encryptBytesWithAesGcmKey.ts","../src/crypto/aes_gcm/encryptTextDataWithAesGcmKey.ts","../src/crypto/ed25519/signTextDataWithKeyEd25519.ts","../src/crypto/ed25519/signCombinedTextDataWithKeyEd25519.ts","../src/crypto/client_key_link/buildVerifyKeyBoundInfoString.ts","../src/storage_adapter/typed_storage/createTypedStorage.ts","../src/crypto/ed25519/generateEd25519KeyPair.ts","../src/core/createDataStringConverter_stringToObject.ts","../src/core/core_valibot_schemas.ts","../src/crypto/crypto.schema.ts","../src/crypto/crypto.converters.ts","../src/crypto/ed25519/importEd25519Key.ts","../src/crypto/ed25519/serializeEd25519Key_Jwk.ts","../src/crypto/ed25519/serializeEd25519Key_Raw.ts","../src/crypto/ed25519/verifyWithKeyEd25519.ts","../src/crypto/x25519/generateX25519KeyPair.ts","../src/crypto/x25519/importX25519Key.ts","../src/crypto/x25519/serializeX25519Key_Jwk.ts","../src/crypto/x25519/serializeX25519Key_Raw.ts","../src/crypto/client_key_link/ClientCryptoKeyLink.ts","../src/storage_adapter/storage_adapter.types.ts","../src/storage_adapter/StorageAdapter.ts","../src/storage_adapter/specific/browser/browser_storage.ts","../src/storage_adapter/specific/cloudflare/durable_object/durable_object_storage.ts","../src/storage_adapter/specific/cloudflare/kv/kv_storage.ts","../src/storage_adapter/specific/memory/memory_storage.ts"],"sourcesContent":["export const notNullEmpty = (str: string | null | undefined): str is string => {\n return str != null && str.length > 0;\n};\n\nexport const nullEmpty = (str: string | null | undefined): str is null | undefined | \"\" => {\n return !notNullEmpty(str);\n};\n\nexport const firstNotNullEmpty = (\n ...strItems: (string | null | undefined)[]\n): string | undefined => {\n for (const item of strItems) {\n if (notNullEmpty(item)) {\n return item;\n }\n }\n\n return undefined;\n};\n","export const createSharedBitsFromX25519 = async ({\n privateKey,\n publicKey,\n}: {\n privateKey: CryptoKey;\n publicKey: CryptoKey;\n}): Promise<Uint8Array> => {\n return new Uint8Array(\n await crypto.subtle.deriveBits({ name: \"X25519\", public: publicKey }, privateKey, 256),\n );\n};\n","import { notNullEmpty } from \"../../data_type/string/nullEmpty\";\nimport { createSharedBitsFromX25519 } from \"../x25519/createSharedBitsFromX25519\";\n\nconst DEFAULT_INFO_STRING = \"METEOR_BRIDGE_DEFAULT_INFO_STRING\";\n\nexport const createAesGcmKeyFromX25519Keys = async ({\n externalX25519PublicKey,\n internalX25519PrivateKey,\n infoString,\n saltString,\n}: {\n internalX25519PrivateKey: CryptoKey;\n externalX25519PublicKey: CryptoKey;\n saltString?: string;\n infoString?: string;\n}): Promise<CryptoKey> => {\n const sharedBits = await createSharedBitsFromX25519({\n privateKey: internalX25519PrivateKey,\n publicKey: externalX25519PublicKey,\n });\n\n // Initial Key Material\n const ikm = await crypto.subtle.importKey(\"raw\", new Uint8Array(sharedBits), \"HKDF\", false, [\n \"deriveKey\",\n ]);\n\n const salt = notNullEmpty(saltString) ? new TextEncoder().encode(saltString) : new Uint8Array();\n const info = new TextEncoder().encode(\n notNullEmpty(infoString) ? infoString : DEFAULT_INFO_STRING,\n );\n\n // Run HKDF to get your final usable key (e.g., AES-GCM)\n return await crypto.subtle.deriveKey(\n {\n name: \"HKDF\",\n hash: \"SHA-256\",\n salt, // Salt\n info, // Context string\n },\n ikm,\n { name: \"AES-GCM\", length: 256 },\n false, // The final AES key shouldn't be exportable\n [\"encrypt\", \"decrypt\"],\n );\n};\n","import type { TEncryptedAesGcmBytes } from \"../crypto.schema\";\r\n\r\n/**\r\n * Decrypts a raw-bytes AES-GCM payload (binary nonce + ciphertext) back to bytes. The counterpart of\r\n * {@link decryptTextDataWithAesGcmKey}. AES-GCM verifies integrity, so a tampered ciphertext throws.\r\n */\r\nexport const decryptBytesWithAesGcmKey = async ({\r\n aesGcmKey,\r\n dataToDecrypt,\r\n}: {\r\n aesGcmKey: CryptoKey;\r\n dataToDecrypt: TEncryptedAesGcmBytes;\r\n}): Promise<Uint8Array> => {\r\n const decryptedData = await crypto.subtle.decrypt(\r\n // Re-view nonce + ciphertext over plain ArrayBuffers so WebCrypto's `BufferSource` is satisfied\r\n // regardless of the source's backing buffer (msgpack output may be pooled / SharedArrayBuffer-typed).\r\n { name: \"AES-GCM\", iv: new Uint8Array(dataToDecrypt.nonce) },\r\n aesGcmKey,\r\n new Uint8Array(dataToDecrypt.ciphertext),\r\n );\r\n\r\n return new Uint8Array(decryptedData);\r\n};\r\n","import { base64 } from \"@scure/base\";\nimport type { TEncryptedAesGcmPayload } from \"../crypto.schema\";\n\nexport const decryptTextDataWithAesGcmKey = async ({\n aesGcmKey,\n dataToDecrypt,\n}: {\n aesGcmKey: CryptoKey;\n dataToDecrypt: TEncryptedAesGcmPayload;\n}): Promise<string> => {\n const decryptedData = await crypto.subtle.decrypt(\n {\n name: \"AES-GCM\",\n iv: new Uint8Array(base64.decode(dataToDecrypt.nonce)),\n },\n aesGcmKey,\n new Uint8Array(base64.decode(dataToDecrypt.ciphertext)),\n );\n\n return new TextDecoder().decode(decryptedData);\n};\n","import type { TEncryptedAesGcmBytes } from \"../crypto.schema\";\r\n\r\n/**\r\n * Encrypts raw bytes with an AES-GCM key, returning the binary nonce + ciphertext. The bytes\r\n * counterpart of {@link encryptTextDataWithAesGcmKey} — use it for binary channels (msgpack frames)\r\n * to avoid base64 inflation. A fresh 12-byte nonce is generated per call (never reuse a nonce).\r\n */\r\nexport const encryptBytesWithAesGcmKey = async ({\r\n aesGcmKey,\r\n dataToEncrypt,\r\n}: {\r\n aesGcmKey: CryptoKey;\r\n dataToEncrypt: Uint8Array;\r\n}): Promise<TEncryptedAesGcmBytes> => {\r\n const nonce = crypto.getRandomValues(new Uint8Array(12));\r\n\r\n const encryptedData = await crypto.subtle.encrypt(\r\n { name: \"AES-GCM\", iv: nonce },\r\n aesGcmKey,\r\n // Re-view over a plain ArrayBuffer so WebCrypto's `BufferSource` is satisfied regardless of the\r\n // source's backing buffer (msgpack output may be pooled / SharedArrayBuffer-typed).\r\n new Uint8Array(dataToEncrypt),\r\n );\r\n\r\n return { nonce, ciphertext: new Uint8Array(encryptedData) };\r\n};\r\n","import { base64 } from \"@scure/base\";\nimport type { TEncryptedAesGcmPayload } from \"../crypto.schema\";\n\nexport const encryptTextDataWithAesGcmKey = async ({\n aesGcmKey,\n dataToEncrypt,\n}: {\n aesGcmKey: CryptoKey;\n dataToEncrypt: string;\n}): Promise<TEncryptedAesGcmPayload> => {\n const nonce = crypto.getRandomValues(new Uint8Array(12));\n\n const encryptedData = await crypto.subtle.encrypt(\n {\n name: \"AES-GCM\",\n iv: nonce,\n },\n aesGcmKey,\n new TextEncoder().encode(dataToEncrypt),\n );\n\n return {\n nonce: base64.encode(nonce),\n ciphertext: base64.encode(new Uint8Array(encryptedData)),\n };\n};\n","export const signTextDataWithKeyEd25519 = async (\n data: string,\n cryptoKey: CryptoKey,\n): Promise<Uint8Array> => {\n const dataBuffer = new TextEncoder().encode(data);\n const signature = await crypto.subtle.sign(\n {\n name: \"ED25519\",\n },\n cryptoKey,\n dataBuffer,\n );\n\n return new Uint8Array(signature);\n};\n","import { signTextDataWithKeyEd25519 } from \"./signTextDataWithKeyEd25519\";\n\nexport const DEFAULT_COMBINED_TEXT_DATA_SEPARATOR = \"::\";\n\nexport const signCombinedTextDataWithKeyEd25519 = async (\n data: string[],\n cryptoKey: CryptoKey,\n separator = DEFAULT_COMBINED_TEXT_DATA_SEPARATOR,\n): Promise<Uint8Array> => {\n return await signTextDataWithKeyEd25519(data.join(separator), cryptoKey);\n};\n","import type { TSerializedCryptoKeyData_Ed25519_Raw } from \"../crypto.schema\";\nimport { DEFAULT_COMBINED_TEXT_DATA_SEPARATOR } from \"../ed25519/signCombinedTextDataWithKeyEd25519\";\n\ninterface IBuildVerifyKeyBoundInfoString_Input {\n infoString?: string;\n verifyPublicKeys: [TSerializedCryptoKeyData_Ed25519_Raw, TSerializedCryptoKeyData_Ed25519_Raw];\n}\n\n/**\n * The canonical HKDF `info` for a client-to-client shared key that binds both sides' verify\n * public keys into the derivation.\n *\n * When the two keys are relayed through an intermediary, a tampered key produces mismatched AES\n * keys on the two sides — the very first decryption fails, so key substitution is detected without\n * any extra signature ceremony.\n *\n * The keys are sorted lexicographically so the result is independent of which side is \"local\" —\n * both ends of a link compute the identical string without coordinating an order. Used internally\n * by ClientCryptoKeyLink (`bindVerifyKeysIntoDerivation`); exported for code that derives the same\n * key outside the link.\n */\nexport const buildVerifyKeyBoundInfoString = ({\n infoString,\n verifyPublicKeys,\n}: IBuildVerifyKeyBoundInfoString_Input): string => {\n const sortedKeys = [...verifyPublicKeys].sort();\n\n return [...(infoString != null ? [infoString] : []), ...sortedKeys].join(\n DEFAULT_COMBINED_TEXT_DATA_SEPARATOR,\n );\n};\n","import type { StringKeys } from \"../../typescript/special_typescript_types\";\nimport type { StorageAdapter } from \"../StorageAdapter\";\n\nexport interface ITypedStorage<T extends Record<string, any>> {\n getJson<K extends StringKeys<T>>(key: K): Promise<T[K] | undefined>;\n getJsonOrDef<K extends StringKeys<T>>(key: K, defVal: T[K]): Promise<T[K]>;\n setJson<K extends StringKeys<T>>(key: K, val: T[K]): Promise<void>;\n removeItem<K extends StringKeys<T>>(key: K): Promise<void>;\n updateJson<K extends StringKeys<T>>(\n key: K,\n updater: (currentVal: T[K] | undefined) => T[K],\n ): Promise<void>;\n updateJsonWithDef<K extends StringKeys<T>>(\n key: K,\n defaultVal: T[K],\n updater: (currentVal: T[K]) => T[K],\n ): Promise<void>;\n clearAll(): Promise<void>;\n}\n\ninterface ITypedStorage_Create_Input {\n storageAdapter: StorageAdapter;\n}\n\nexport function createTypedStorage<T extends Record<string, any>>({\n storageAdapter,\n}: ITypedStorage_Create_Input): ITypedStorage<T> {\n const getJson = async <K extends StringKeys<T>>(key: K): Promise<T[K] | undefined> => {\n return storageAdapter.getJson<T[K]>(key);\n };\n\n const getJsonOrDef = async <K extends StringKeys<T>>(key: K, defVal: T[K]): Promise<T[K]> => {\n return (await storageAdapter.getJson<T[K]>(key)) ?? defVal;\n };\n\n const setJson = async <K extends StringKeys<T>>(key: K, val: T[K]): Promise<void> => {\n return storageAdapter.setJson(key, val);\n };\n\n const removeItem = async <K extends StringKeys<T>>(key: K): Promise<void> => {\n await storageAdapter.removeItem(key);\n };\n\n const updateJson = async <K extends StringKeys<T>>(\n key: K,\n updater: (currentVal: T[K] | undefined) => T[K],\n ): Promise<void> => {\n await storageAdapter.updateJson(key, updater);\n };\n\n const updateJsonWithDef = async <K extends StringKeys<T>>(\n key: K,\n defaultVal: T[K],\n updater: (currentVal: T[K]) => T[K],\n ): Promise<void> => {\n await storageAdapter.updateJsonOrDef(key, defaultVal, updater);\n };\n\n return {\n getJson,\n getJsonOrDef,\n setJson,\n removeItem,\n updateJson,\n updateJsonWithDef,\n clearAll: async () => {\n await storageAdapter.clearAll();\n },\n };\n}\n","export const generateEd25519KeyPair = async (): Promise<CryptoKeyPair> => {\n const keyPair = (await crypto.subtle.generateKey({ name: \"Ed25519\" }, true, [\n \"sign\",\n \"verify\",\n ])) as CryptoKeyPair;\n\n return keyPair;\n};\n","import type { ECryptoKeyFormat } from \"../crypto/crypto.schema\";\n\ninterface ICreateDataStringConverter_StringToObject {\n transformJsonForFormats?: ECryptoKeyFormat[];\n transformJson?: boolean;\n}\n\nexport const createDataStringConverter_stringToObject =\n <T extends string, F extends ECryptoKeyFormat, D = string>({\n transformJsonForFormats = [],\n transformJson = false,\n }: ICreateDataStringConverter_StringToObject = {}) =>\n (\n inputDataString: `${T}::${F}::${string}`,\n ): { formattedString: `${T}::${F}::${string}`; type: T; format: F; data: D } => {\n const [type, format, dataString] = inputDataString.split(\"::\") as [\n string,\n ECryptoKeyFormat,\n string,\n ];\n let parsedData: D = dataString as D;\n\n if (transformJson || transformJsonForFormats.includes(format)) {\n try {\n parsedData = JSON.parse(dataString) as D;\n } catch (error) {\n const err = new Error(\n `Failed to parse type and format data string. Given input: \"${inputDataString}\", expected JSON parsable \"data\" value in the format \"${type}::${format}::data\" ${error instanceof Error ? error.message : String(error)}`,\n );\n\n err.cause = error;\n throw err;\n }\n }\n\n return {\n formattedString: inputDataString,\n type: type as T,\n format: format as F,\n data: parsedData,\n };\n };\n","import * as v from \"valibot\";\n\n// export const vBase64HashSha256 = v.pipe(v.string(), v.base64());\nexport const vBase64 = v.pipe(v.string(), v.base64());\n\nexport const vCreateSchema_TypePrefixedDataString = <P extends string>(\n typeValues: P[],\n typeKind: string,\n) => {\n const _typeKind = typeKind ?? \"data_type\";\n\n return v.pipe(\n v.custom<`${P}::${string}`>(\n (input) => {\n return (\n typeof input === \"string\" && typeValues.some((prefix) => input.startsWith(`${prefix}::`))\n );\n },\n `Invalid format, expected '<${_typeKind}>::<value>' where \"${_typeKind}\" is one of [${typeValues.join(\", \")}] and \"value\" is a string of base64-encoded data of that type`,\n ),\n );\n};\n\nexport interface ICreateTypePrefixedDataStringResult<T extends string, F extends string> {\n type: T;\n format: F;\n typeKind: string;\n formatKind?: string;\n transformJson?: boolean;\n}\n\nexport const vCreateSchema_TypeAndFormatPrefixedDataString = <T extends string, F extends string>({\n type,\n format,\n typeKind,\n formatKind,\n // transformJson = false,\n}: ICreateTypePrefixedDataStringResult<T, F>) => {\n const _typeKind = typeKind ?? \"data_type\";\n const _formatKind = formatKind ?? \"data_format\";\n\n return v.pipe(\n v.custom<`${T}::${F}::${string}`>((input) => {\n if (typeof input !== \"string\") return false;\n\n const [typePart, formatPart, dataPart] = input.split(\"::\") as [string, string, string];\n\n return typePart === type && formatPart === format && typeof dataPart === \"string\";\n }, `Invalid format, expected '<${_typeKind}>::<${_formatKind}>::<value>' where \"${_typeKind}\" is \"${type}\", \"${_formatKind}\" is \"${format}\", and \"value\" is a string in the specified format`),\n );\n};\n\nexport const vCreateSchema_TypeAndId = <S extends string>(dataType: S | S[]) =>\n v.pipe(\n v.custom<`${S}::${string}`>((input) => {\n if (typeof input !== \"string\") {\n return false;\n }\n\n let checkDataTypes: string[];\n\n if (typeof dataType === \"string\") {\n checkDataTypes = [dataType];\n } else if (Array.isArray(dataType)) {\n checkDataTypes = dataType;\n } else {\n throw new Error(\n \"Create Schema for TypeAndId: dataType must be a string or an array of strings\",\n );\n }\n\n if (checkDataTypes.length > 0) {\n return true;\n }\n\n for (const dataTypeCheck in checkDataTypes) {\n if (input.startsWith(`${dataTypeCheck}::`)) return true;\n }\n\n return false;\n }, `Invalid Type and ID formatted string, expected '<data_type>::<id>'`),\n );\n\nexport type TTypeAndId<S extends string = string> = `${S}::${string}`;\n","import * as v from \"valibot\";\r\nimport {\r\n vBase64,\r\n vCreateSchema_TypeAndFormatPrefixedDataString,\r\n} from \"../core/core_valibot_schemas\";\r\n\r\nexport enum ECryptoKeyAlgo {\r\n ed25519 = \"ed25519\",\r\n x25519 = \"x25519\",\r\n}\r\n\r\nexport enum ECryptoKeyFormat {\r\n raw_base64 = \"raw_base64\",\r\n jwk = \"jwk\",\r\n}\r\n\r\nexport const vSerializedCryptoKeyDataEd25519_Raw = vCreateSchema_TypeAndFormatPrefixedDataString<\r\n ECryptoKeyAlgo.ed25519,\r\n ECryptoKeyFormat.raw_base64\r\n>({\r\n format: ECryptoKeyFormat.raw_base64,\r\n type: ECryptoKeyAlgo.ed25519,\r\n typeKind: \"algo\",\r\n});\r\n\r\nexport const vSerializedCryptoKeyDataEd25519_Jwk = vCreateSchema_TypeAndFormatPrefixedDataString<\r\n ECryptoKeyAlgo.ed25519,\r\n ECryptoKeyFormat.jwk\r\n>({\r\n format: ECryptoKeyFormat.jwk,\r\n type: ECryptoKeyAlgo.ed25519,\r\n typeKind: \"algo\",\r\n transformJson: true,\r\n});\r\n\r\nexport type TSerializedCryptoKeyData_Ed25519_Raw = v.InferInput<\r\n typeof vSerializedCryptoKeyDataEd25519_Raw\r\n>;\r\n\r\nexport type TSerializedCryptoKeyData_Ed25519_Raw_Transformed = {\r\n formattedString: `${ECryptoKeyAlgo.ed25519}::${ECryptoKeyFormat.raw_base64}::${string}`;\r\n type: ECryptoKeyAlgo.ed25519;\r\n format: ECryptoKeyFormat.raw_base64;\r\n data: string;\r\n};\r\n\r\nexport type TSerializedCryptoKeyData_Ed25519_Jwk = v.InferInput<\r\n typeof vSerializedCryptoKeyDataEd25519_Jwk\r\n>;\r\n\r\nexport type TSerializedCryptoKeyData_Ed25519_Jwk_Transformed = {\r\n formattedString: `${ECryptoKeyAlgo.ed25519}::${ECryptoKeyFormat.jwk}::${string}`;\r\n type: ECryptoKeyAlgo.ed25519;\r\n format: ECryptoKeyFormat.jwk;\r\n data: JsonWebKey;\r\n};\r\n\r\nexport const vSerializedCryptoKeyDataX25519_Raw = vCreateSchema_TypeAndFormatPrefixedDataString<\r\n ECryptoKeyAlgo.x25519,\r\n ECryptoKeyFormat.raw_base64\r\n>({\r\n format: ECryptoKeyFormat.raw_base64,\r\n type: ECryptoKeyAlgo.x25519,\r\n typeKind: \"algo\",\r\n});\r\n\r\nexport const vSerializedCryptoKeyDataX25519_Jwk = vCreateSchema_TypeAndFormatPrefixedDataString<\r\n ECryptoKeyAlgo.x25519,\r\n ECryptoKeyFormat.jwk\r\n>({\r\n format: ECryptoKeyFormat.jwk,\r\n type: ECryptoKeyAlgo.x25519,\r\n typeKind: \"algo\",\r\n transformJson: true,\r\n});\r\n\r\nexport const vCryptoKeyPairDataX25519 = v.object({\r\n publicKey: vSerializedCryptoKeyDataX25519_Raw,\r\n privateKey: vSerializedCryptoKeyDataX25519_Jwk,\r\n});\r\n\r\nexport type TSerializedCryptoKeyPairDataX25519 = v.InferInput<typeof vCryptoKeyPairDataX25519>;\r\n\r\nexport const vCryptoKeyPairDataEd25519 = v.object({\r\n publicKey: vSerializedCryptoKeyDataEd25519_Raw,\r\n privateKey: vSerializedCryptoKeyDataEd25519_Jwk,\r\n});\r\n\r\nexport type TSerializedCryptoKeyPairDataEd25519 = v.InferInput<typeof vCryptoKeyPairDataEd25519>;\r\n\r\nexport type TSerializedCryptoKeyData_X25519_Raw = v.InferInput<\r\n typeof vSerializedCryptoKeyDataX25519_Raw\r\n>;\r\n\r\nexport type TSerializedCryptoKeyData_X25519_Raw_Transformed = {\r\n formattedString: `${ECryptoKeyAlgo.x25519}::${ECryptoKeyFormat.raw_base64}::${string}`;\r\n type: ECryptoKeyAlgo.x25519;\r\n format: ECryptoKeyFormat.raw_base64;\r\n data: string;\r\n};\r\n\r\nexport type TSerializedCryptoKeyData_X25519_Jwk = v.InferInput<\r\n typeof vSerializedCryptoKeyDataX25519_Jwk\r\n>;\r\n\r\nexport type TSerializedCryptoKeyData_X25519_Jwk_Transformed = {\r\n formattedString: `${ECryptoKeyAlgo.x25519}::${ECryptoKeyFormat.jwk}::${string}`;\r\n type: ECryptoKeyAlgo.x25519;\r\n format: ECryptoKeyFormat.jwk;\r\n data: JsonWebKey;\r\n};\r\n\r\nexport const vVerifyChallengeWithSignature_Input = v.object({\r\n challenge: v.string(),\r\n signatureBase64: vBase64,\r\n});\r\n\r\nexport const vVerifyChallengeWithSignature_WithThrow_Input = v.intersect([\r\n vVerifyChallengeWithSignature_Input,\r\n v.object({\r\n throwOnInvalid: v.optional(v.boolean()),\r\n }),\r\n]);\r\n\r\nexport type TVerifyChallengeWithSignature_Input = v.InferInput<\r\n typeof vVerifyChallengeWithSignature_Input\r\n>;\r\n\r\nexport type TVerifyChallengeWithSignature_WithThrow_Input = v.InferInput<\r\n typeof vVerifyChallengeWithSignature_WithThrow_Input\r\n>;\r\n\r\nexport const vEncryptedAesGcmPayload = v.object({\r\n nonce: vBase64,\r\n ciphertext: vBase64,\r\n});\r\n\r\nexport type TEncryptedAesGcmPayload = v.InferInput<typeof vEncryptedAesGcmPayload>;\r\nexport type TEncryptedAesGcmPayload_Transformed = v.InferOutput<typeof vEncryptedAesGcmPayload>;\r\n\r\n/**\r\n * Raw-bytes counterpart of {@link TEncryptedAesGcmPayload} — keeps `nonce`/`ciphertext` as binary\r\n * instead of base64 strings. For binary channels (e.g. msgpack WebSocket frames) this avoids the\r\n * ~33% base64 inflation the text payload incurs.\r\n */\r\nexport type TEncryptedAesGcmBytes = {\r\n nonce: Uint8Array;\r\n ciphertext: Uint8Array;\r\n};\r\n\r\ninterface ISerializedKeyData<T, P> {\r\n transformed: T;\r\n prefixed: P;\r\n}\r\n\r\nexport interface ISerializedKeyData_Ed25519_Raw\r\n extends ISerializedKeyData<\r\n TSerializedCryptoKeyData_Ed25519_Raw_Transformed,\r\n TSerializedCryptoKeyData_Ed25519_Raw\r\n > {}\r\n\r\nexport interface ISerializedKeyData_Ed25519_Jwk\r\n extends ISerializedKeyData<\r\n TSerializedCryptoKeyData_Ed25519_Jwk_Transformed,\r\n TSerializedCryptoKeyData_Ed25519_Jwk\r\n > {}\r\n\r\nexport interface ISerializedKeyData_X25519_Raw\r\n extends ISerializedKeyData<\r\n TSerializedCryptoKeyData_X25519_Raw_Transformed,\r\n TSerializedCryptoKeyData_X25519_Raw\r\n > {}\r\n\r\nexport interface ISerializedKeyData_X25519_Jwk\r\n extends ISerializedKeyData<\r\n TSerializedCryptoKeyData_X25519_Jwk_Transformed,\r\n TSerializedCryptoKeyData_X25519_Jwk\r\n > {}\r\n\r\nexport type TSerializedKeyData =\r\n | ISerializedKeyData_Ed25519_Raw\r\n | ISerializedKeyData_Ed25519_Jwk\r\n | ISerializedKeyData_X25519_Raw\r\n | ISerializedKeyData_X25519_Jwk;\r\n","import { createDataStringConverter_stringToObject } from \"../core/createDataStringConverter_stringToObject\";\nimport {\n type ECryptoKeyAlgo,\n ECryptoKeyFormat,\n type ISerializedKeyData_Ed25519_Jwk,\n type ISerializedKeyData_Ed25519_Raw,\n type ISerializedKeyData_X25519_Jwk,\n type ISerializedKeyData_X25519_Raw,\n type TSerializedCryptoKeyData_Ed25519_Jwk,\n type TSerializedCryptoKeyData_Ed25519_Jwk_Transformed,\n type TSerializedCryptoKeyData_Ed25519_Raw,\n type TSerializedCryptoKeyData_Ed25519_Raw_Transformed,\n type TSerializedCryptoKeyData_X25519_Jwk,\n type TSerializedCryptoKeyData_X25519_Jwk_Transformed,\n type TSerializedCryptoKeyData_X25519_Raw,\n type TSerializedCryptoKeyData_X25519_Raw_Transformed,\n} from \"./crypto.schema\";\n\n/**\n *\n * [CRYPTO ALGO] ED25519\n *\n */\n\nexport const convertEd25519RawDataStringToObject = createDataStringConverter_stringToObject<\n ECryptoKeyAlgo.ed25519,\n ECryptoKeyFormat.raw_base64\n>();\n\nexport const convertEd25519JwkDataStringToObject = createDataStringConverter_stringToObject<\n ECryptoKeyAlgo.ed25519,\n ECryptoKeyFormat.jwk,\n JsonWebKey\n>({ transformJson: true });\n\nexport const convertEd25519FormattedStringToObject = createDataStringConverter_stringToObject<\n ECryptoKeyAlgo.ed25519,\n ECryptoKeyFormat.raw_base64 | ECryptoKeyFormat.jwk\n>({\n transformJsonForFormats: [ECryptoKeyFormat.jwk],\n});\n\nexport const convertEd25519RawDataStringToSerializedKeyData = (\n input: TSerializedCryptoKeyData_Ed25519_Raw,\n): ISerializedKeyData_Ed25519_Raw => {\n const transformed = convertEd25519RawDataStringToObject(input);\n\n return {\n prefixed: input,\n transformed,\n };\n};\n\nexport const convertEd25519JwkDataStringToSerializedKeyData = (\n input: TSerializedCryptoKeyData_Ed25519_Jwk,\n): ISerializedKeyData_Ed25519_Jwk => {\n const transformed = convertEd25519JwkDataStringToObject(input);\n\n return {\n prefixed: input,\n transformed,\n };\n};\n\nexport const convertEd25519FormattedStringToSerializedKeyData = <\n I extends TSerializedCryptoKeyData_Ed25519_Raw | TSerializedCryptoKeyData_Ed25519_Jwk,\n O extends I extends TSerializedCryptoKeyData_Ed25519_Raw\n ? TSerializedCryptoKeyData_Ed25519_Raw_Transformed\n : TSerializedCryptoKeyData_Ed25519_Jwk_Transformed,\n>(\n input: I,\n): O => {\n return convertEd25519FormattedStringToObject(input) as O;\n};\n\n/**\n *\n * [CRYPTO ALGO] X25519\n *\n */\n\nexport const convertX25519RawDataStringToObject = createDataStringConverter_stringToObject<\n ECryptoKeyAlgo.x25519,\n ECryptoKeyFormat.raw_base64\n>();\n\nexport const convertX25519JwkDataStringToObject = createDataStringConverter_stringToObject<\n ECryptoKeyAlgo.x25519,\n ECryptoKeyFormat.jwk,\n JsonWebKey\n>({ transformJson: true });\n\nexport const convertX25519FormattedStringToObject = createDataStringConverter_stringToObject<\n ECryptoKeyAlgo.x25519,\n ECryptoKeyFormat.raw_base64 | ECryptoKeyFormat.jwk\n>({\n transformJsonForFormats: [ECryptoKeyFormat.jwk],\n});\n\nexport const convertX25519RawDataStringToSerializedKeyData = (\n input: TSerializedCryptoKeyData_X25519_Raw,\n): ISerializedKeyData_X25519_Raw => {\n const transformed = convertX25519RawDataStringToObject(input);\n\n return {\n prefixed: input,\n transformed,\n };\n};\n\nexport const convertX25519JwkDataStringToSerializedKeyData = (\n input: TSerializedCryptoKeyData_X25519_Jwk,\n): ISerializedKeyData_X25519_Jwk => {\n const transformed = convertX25519JwkDataStringToObject(input);\n\n return {\n prefixed: input,\n transformed,\n };\n};\n\nexport const convertX25519FormattedStringToSerializedKeyData = <\n I extends TSerializedCryptoKeyData_X25519_Raw | TSerializedCryptoKeyData_X25519_Jwk,\n O extends I extends TSerializedCryptoKeyData_X25519_Raw\n ? TSerializedCryptoKeyData_X25519_Raw_Transformed\n : TSerializedCryptoKeyData_X25519_Jwk_Transformed,\n>(\n input: I,\n): O => {\n return convertX25519FormattedStringToObject(input) as O;\n};\n","import { base64 } from \"@scure/base\";\nimport { convertEd25519FormattedStringToSerializedKeyData } from \"../crypto.converters\";\nimport {\n ECryptoKeyFormat,\n type TSerializedCryptoKeyData_Ed25519_Jwk,\n type TSerializedCryptoKeyData_Ed25519_Jwk_Transformed,\n type TSerializedCryptoKeyData_Ed25519_Raw,\n type TSerializedCryptoKeyData_Ed25519_Raw_Transformed,\n} from \"../crypto.schema\";\n\nconst fromBase64 = async (\n dataBase64: string,\n keyUsage: KeyUsage[],\n extractable: boolean,\n): Promise<CryptoKey> => {\n const keyBuffer = Uint8Array.from(base64.decode(dataBase64));\n\n return await crypto.subtle.importKey(\n \"raw\",\n keyBuffer,\n { name: \"Ed25519\" },\n extractable,\n keyUsage,\n );\n};\n\nconst fromJwk = async (\n jwk: JsonWebKey,\n keyUsage: KeyUsage[],\n extractable = true,\n): Promise<CryptoKey> => {\n return await crypto.subtle.importKey(\"jwk\", jwk, { name: \"Ed25519\" }, extractable, keyUsage);\n};\n\nconst fromSerializedObject = async <\n D extends\n | TSerializedCryptoKeyData_Ed25519_Raw_Transformed\n | TSerializedCryptoKeyData_Ed25519_Jwk_Transformed =\n | TSerializedCryptoKeyData_Ed25519_Raw_Transformed\n | TSerializedCryptoKeyData_Ed25519_Jwk_Transformed,\n>(\n serialized: D,\n keyUsage: KeyUsage[],\n extractable = true,\n): Promise<CryptoKey> => {\n if (serialized.format === ECryptoKeyFormat.jwk) {\n return await fromJwk(serialized.data, keyUsage, extractable);\n }\n\n return await fromBase64(serialized.data, keyUsage, extractable);\n};\n\nconst fromFormattedString = async <\n D extends TSerializedCryptoKeyData_Ed25519_Raw | TSerializedCryptoKeyData_Ed25519_Jwk =\n | TSerializedCryptoKeyData_Ed25519_Raw\n | TSerializedCryptoKeyData_Ed25519_Jwk,\n>(\n dataString: D,\n keyUsage: KeyUsage[],\n extractable = true,\n): Promise<CryptoKey> => {\n const transformed = convertEd25519FormattedStringToSerializedKeyData(dataString);\n return await fromSerializedObject(transformed, keyUsage, extractable);\n};\n\nconst extractableOrNonExtractable = <I>(\n keyUsage: KeyUsage[],\n func: (input: I, keyUsage: KeyUsage[], extractable: boolean) => Promise<CryptoKey>,\n) =>\n ({\n extractable: (input: I) => func(input, keyUsage, true),\n nonExtractable: (input: I) => func(input, keyUsage, false),\n }) as const;\n\nexport const importEd25519Key = {\n private: {\n fromFormattedString: extractableOrNonExtractable(\n [\"sign\"],\n fromFormattedString<TSerializedCryptoKeyData_Ed25519_Jwk>,\n ),\n fromSerializedObject: extractableOrNonExtractable(\n [\"sign\"],\n fromSerializedObject<TSerializedCryptoKeyData_Ed25519_Jwk_Transformed>,\n ),\n fromJwk: extractableOrNonExtractable([\"sign\"], fromJwk),\n },\n public: {\n fromBase64: extractableOrNonExtractable([\"verify\"], fromBase64),\n fromFormattedString: extractableOrNonExtractable(\n [\"verify\"],\n fromFormattedString<\n TSerializedCryptoKeyData_Ed25519_Raw | TSerializedCryptoKeyData_Ed25519_Jwk\n >,\n ),\n fromSerializedObject: extractableOrNonExtractable(\n [\"verify\"],\n fromSerializedObject<\n | TSerializedCryptoKeyData_Ed25519_Raw_Transformed\n | TSerializedCryptoKeyData_Ed25519_Jwk_Transformed\n >,\n ),\n fromJwk: extractableOrNonExtractable([\"verify\"], fromJwk),\n },\n};\n","import {\n ECryptoKeyAlgo,\n ECryptoKeyFormat,\n type ISerializedKeyData_Ed25519_Jwk,\n type TSerializedCryptoKeyData_Ed25519_Jwk_Transformed,\n} from \"../crypto.schema\";\n\nexport const serializeEd25519Key_Jwk = async (\n key: CryptoKey,\n): Promise<ISerializedKeyData_Ed25519_Jwk> => {\n const keyJwk = await crypto.subtle.exportKey(\"jwk\", key);\n\n const prefixed =\n `${ECryptoKeyAlgo.ed25519}::${ECryptoKeyFormat.jwk}::${JSON.stringify(keyJwk)}` as const;\n\n const transformed: TSerializedCryptoKeyData_Ed25519_Jwk_Transformed = {\n formattedString: prefixed,\n type: ECryptoKeyAlgo.ed25519,\n data: keyJwk,\n format: ECryptoKeyFormat.jwk,\n };\n\n return { transformed, prefixed };\n};\n","import { base64 } from \"@scure/base\";\nimport {\n ECryptoKeyAlgo,\n ECryptoKeyFormat,\n type ISerializedKeyData_Ed25519_Raw,\n type TSerializedCryptoKeyData_Ed25519_Raw_Transformed,\n} from \"../crypto.schema\";\n\nexport const serializeEd25519Key_Raw = async (\n publicKey: CryptoKey,\n): Promise<ISerializedKeyData_Ed25519_Raw> => {\n const publicKeyBuffer = await crypto.subtle.exportKey(\"raw\", publicKey);\n const publicKeyBase64 = base64.encode(new Uint8Array(publicKeyBuffer));\n\n const prefixed =\n `${ECryptoKeyAlgo.ed25519}::${ECryptoKeyFormat.raw_base64}::${publicKeyBase64}` as const;\n\n const transformed: TSerializedCryptoKeyData_Ed25519_Raw_Transformed = {\n formattedString: prefixed,\n type: ECryptoKeyAlgo.ed25519,\n data: publicKeyBase64,\n format: ECryptoKeyFormat.raw_base64,\n };\n\n return { transformed, prefixed };\n};\n","import { base64 } from \"@scure/base\";\n\nexport const verifyWithKeyEd25519 = async ({\n challenge,\n signatureBase64,\n publicKey,\n}: {\n challenge: string;\n signatureBase64: string;\n publicKey: CryptoKey;\n}): Promise<boolean> => {\n const signatureBuffer = Uint8Array.from(base64.decode(signatureBase64));\n const challengeBuffer = new TextEncoder().encode(challenge);\n\n return await crypto.subtle.verify(\n {\n name: \"ED25519\",\n },\n publicKey,\n signatureBuffer,\n challengeBuffer,\n );\n};\n","export const generateX25519KeyPair = async (): Promise<CryptoKeyPair> => {\n const keyPair = (await crypto.subtle.generateKey({ name: \"X25519\" }, true, [\n \"deriveKey\",\n \"deriveBits\",\n ])) as CryptoKeyPair;\n\n return keyPair;\n};\n","import { base64 } from \"@scure/base\";\nimport { convertX25519FormattedStringToSerializedKeyData } from \"../crypto.converters\";\nimport {\n ECryptoKeyFormat,\n type TSerializedCryptoKeyData_X25519_Jwk,\n type TSerializedCryptoKeyData_X25519_Jwk_Transformed,\n type TSerializedCryptoKeyData_X25519_Raw,\n type TSerializedCryptoKeyData_X25519_Raw_Transformed,\n} from \"../crypto.schema\";\n\nconst fromBase64 = async (\n dataBase64: string,\n keyUsage: KeyUsage[],\n extractable: boolean,\n): Promise<CryptoKey> => {\n const keyBuffer = Uint8Array.from(base64.decode(dataBase64));\n\n return await crypto.subtle.importKey(\"raw\", keyBuffer, { name: \"X25519\" }, extractable, keyUsage);\n};\n\nconst fromJwk = async (\n jwk: JsonWebKey,\n keyUsage: KeyUsage[],\n extractable = true,\n): Promise<CryptoKey> => {\n return await crypto.subtle.importKey(\"jwk\", jwk, { name: \"X25519\" }, extractable, keyUsage);\n};\n\nconst fromSerializedObject = async <\n D extends\n | TSerializedCryptoKeyData_X25519_Raw_Transformed\n | TSerializedCryptoKeyData_X25519_Jwk_Transformed =\n | TSerializedCryptoKeyData_X25519_Raw_Transformed\n | TSerializedCryptoKeyData_X25519_Jwk_Transformed,\n>(\n serialized: D,\n keyUsage: KeyUsage[],\n extractable = true,\n): Promise<CryptoKey> => {\n if (serialized.format === ECryptoKeyFormat.jwk) {\n return await fromJwk(serialized.data, keyUsage, extractable);\n }\n\n return await fromBase64(serialized.data, keyUsage, extractable);\n};\n\nconst fromFormattedString = async <\n D extends TSerializedCryptoKeyData_X25519_Raw | TSerializedCryptoKeyData_X25519_Jwk =\n | TSerializedCryptoKeyData_X25519_Raw\n | TSerializedCryptoKeyData_X25519_Jwk,\n>(\n dataString: D,\n keyUsage: KeyUsage[],\n extractable = true,\n): Promise<CryptoKey> => {\n const transformed = convertX25519FormattedStringToSerializedKeyData(dataString);\n return await fromSerializedObject(transformed, keyUsage, extractable);\n};\n\nconst extractableOrNonExtractable = <I>(\n keyUsage: KeyUsage[],\n func: (input: I, keyUsage: KeyUsage[], extractable: boolean) => Promise<CryptoKey>,\n) =>\n ({\n extractable: (input: I) => func(input, keyUsage, true),\n nonExtractable: (input: I) => func(input, keyUsage, false),\n }) as const;\n\nexport const importX25519Key = {\n private: {\n fromFormattedString: extractableOrNonExtractable(\n [\"deriveKey\", \"deriveBits\"],\n fromFormattedString<TSerializedCryptoKeyData_X25519_Jwk>,\n ),\n fromSerializedObject: extractableOrNonExtractable(\n [\"deriveKey\", \"deriveBits\"],\n fromSerializedObject<TSerializedCryptoKeyData_X25519_Jwk_Transformed>,\n ),\n fromJwk: extractableOrNonExtractable([\"deriveKey\", \"deriveBits\"], fromJwk),\n },\n public: {\n fromBase64: extractableOrNonExtractable([], fromBase64),\n fromFormattedString: extractableOrNonExtractable(\n [],\n fromFormattedString<\n TSerializedCryptoKeyData_X25519_Raw | TSerializedCryptoKeyData_X25519_Jwk\n >,\n ),\n fromSerializedObject: extractableOrNonExtractable(\n [],\n fromSerializedObject<\n | TSerializedCryptoKeyData_X25519_Raw_Transformed\n | TSerializedCryptoKeyData_X25519_Jwk_Transformed\n >,\n ),\n fromJwk: extractableOrNonExtractable([], fromJwk),\n },\n};\n","import {\n ECryptoKeyAlgo,\n ECryptoKeyFormat,\n type ISerializedKeyData_X25519_Jwk,\n type TSerializedCryptoKeyData_X25519_Jwk_Transformed,\n} from \"../crypto.schema\";\n\nexport const serializeX25519Key_Jwk = async (\n key: CryptoKey,\n): Promise<ISerializedKeyData_X25519_Jwk> => {\n const publicKeyJwk = await crypto.subtle.exportKey(\"jwk\", key);\n\n const prefixed =\n `${ECryptoKeyAlgo.x25519}::${ECryptoKeyFormat.jwk}::${JSON.stringify(publicKeyJwk)}` as const;\n\n const transformed: TSerializedCryptoKeyData_X25519_Jwk_Transformed = {\n formattedString: prefixed,\n type: ECryptoKeyAlgo.x25519,\n data: publicKeyJwk,\n format: ECryptoKeyFormat.jwk,\n };\n\n return { transformed, prefixed };\n};\n","import { base64 } from \"@scure/base\";\nimport {\n ECryptoKeyAlgo,\n ECryptoKeyFormat,\n type ISerializedKeyData_X25519_Raw,\n type TSerializedCryptoKeyData_X25519_Raw_Transformed,\n} from \"../crypto.schema\";\n\nexport const serializeX25519Key_Raw = async (\n key: CryptoKey,\n): Promise<ISerializedKeyData_X25519_Raw> => {\n const publicKeyBuffer = await crypto.subtle.exportKey(\"raw\", key);\n const publicKeyBase64 = base64.encode(new Uint8Array(publicKeyBuffer));\n\n const prefixed =\n `${ECryptoKeyAlgo.x25519}::${ECryptoKeyFormat.raw_base64}::${publicKeyBase64}` as const;\n\n const transformed: TSerializedCryptoKeyData_X25519_Raw_Transformed = {\n formattedString: prefixed,\n type: ECryptoKeyAlgo.x25519,\n data: publicKeyBase64,\n format: ECryptoKeyFormat.raw_base64,\n };\n\n return { transformed, prefixed };\n};\n","import { base64 } from \"@scure/base\";\r\nimport type { TTypeAndId } from \"../../core/core_valibot_schemas\";\r\nimport type { StorageAdapter } from \"../../storage_adapter/StorageAdapter\";\r\nimport {\r\n createTypedStorage,\r\n type ITypedStorage,\r\n} from \"../../storage_adapter/typed_storage/createTypedStorage\";\r\nimport { createAesGcmKeyFromX25519Keys } from \"../aes_gcm/createAesGcmKeyFromX25519Keys\";\r\nimport { decryptBytesWithAesGcmKey } from \"../aes_gcm/decryptBytesWithAesGcmKey\";\r\nimport { decryptTextDataWithAesGcmKey } from \"../aes_gcm/decryptTextDataWithAesGcmKey\";\r\nimport { encryptBytesWithAesGcmKey } from \"../aes_gcm/encryptBytesWithAesGcmKey\";\r\nimport { encryptTextDataWithAesGcmKey } from \"../aes_gcm/encryptTextDataWithAesGcmKey\";\r\nimport type {\r\n TEncryptedAesGcmBytes,\r\n TEncryptedAesGcmPayload,\r\n TSerializedCryptoKeyData_Ed25519_Raw,\r\n TSerializedCryptoKeyData_X25519_Raw,\r\n TSerializedCryptoKeyPairDataEd25519,\r\n TSerializedCryptoKeyPairDataX25519,\r\n} from \"../crypto.schema\";\r\nimport { generateEd25519KeyPair } from \"../ed25519/generateEd25519KeyPair\";\r\nimport { importEd25519Key } from \"../ed25519/importEd25519Key\";\r\nimport { serializeEd25519Key_Jwk } from \"../ed25519/serializeEd25519Key_Jwk\";\r\nimport { serializeEd25519Key_Raw } from \"../ed25519/serializeEd25519Key_Raw\";\r\nimport { signCombinedTextDataWithKeyEd25519 } from \"../ed25519/signCombinedTextDataWithKeyEd25519\";\r\nimport { signTextDataWithKeyEd25519 } from \"../ed25519/signTextDataWithKeyEd25519\";\r\nimport { verifyWithKeyEd25519 } from \"../ed25519/verifyWithKeyEd25519\";\r\nimport { generateX25519KeyPair } from \"../x25519/generateX25519KeyPair\";\r\nimport { importX25519Key } from \"../x25519/importX25519Key\";\r\nimport { serializeX25519Key_Jwk } from \"../x25519/serializeX25519Key_Jwk\";\r\nimport { serializeX25519Key_Raw } from \"../x25519/serializeX25519Key_Raw\";\r\nimport { buildVerifyKeyBoundInfoString } from \"./buildVerifyKeyBoundInfoString\";\r\n\r\ninterface IClientCryptoKeyLink_Constructor {\r\n storageAdapter?: StorageAdapter;\r\n}\r\n\r\ninterface ITypedStorage_ClientCryptoKeyLink {\r\n localExchangeKeyPair?: TSerializedCryptoKeyPairDataX25519;\r\n localVerifyKeyPair?: TSerializedCryptoKeyPairDataEd25519;\r\n linkedClientPublicKeys: {\r\n [key: TTypeAndId<string>]: {\r\n verifyPublicKey?: TSerializedCryptoKeyData_Ed25519_Raw;\r\n exchangePublicKey?: TSerializedCryptoKeyData_X25519_Raw;\r\n // HKDF inputs for the shared-key derivation. Persisted only via linkClientAndStore — these\r\n // are typically session secrets, so prefer the in-memory linkClient for ephemeral links.\r\n saltString?: string;\r\n infoString?: string;\r\n bindVerifyKeysIntoDerivation?: boolean;\r\n };\r\n };\r\n}\r\n\r\ninterface IExternalClientCryptoKeys {\r\n verify?: {\r\n publicKey: CryptoKey;\r\n publicKeySerialized: TSerializedCryptoKeyData_Ed25519_Raw;\r\n };\r\n exchange?: {\r\n publicKey: CryptoKey;\r\n // Serialized form retained so re-linking can detect a changed key and invalidate the cache.\r\n publicKeySerialized: TSerializedCryptoKeyData_X25519_Raw;\r\n saltString?: string;\r\n infoString?: string;\r\n bindVerifyKeysIntoDerivation?: boolean;\r\n sharedEncryptKey?: CryptoKey;\r\n };\r\n}\r\n\r\ninterface ILinkedClientPublicKeys {\r\n verifyPublicKey?: TSerializedCryptoKeyData_Ed25519_Raw;\r\n exchangePublicKey?: TSerializedCryptoKeyData_X25519_Raw;\r\n}\r\n\r\ninterface ILocalPublicKeys {\r\n verifyPublicKey: TSerializedCryptoKeyData_Ed25519_Raw;\r\n exchangePublicKey: TSerializedCryptoKeyData_X25519_Raw;\r\n}\r\n\r\ninterface ILinkClientKeys {\r\n linkedClientId: TTypeAndId;\r\n verifyPublicKey?: TSerializedCryptoKeyData_Ed25519_Raw;\r\n exchangePublicKey?: TSerializedCryptoKeyData_X25519_Raw;\r\n // HKDF salt/info bound into the shared AES-GCM key derivation with this client. Passing either\r\n // (or a new exchange public key) invalidates a previously cached shared key for the link.\r\n saltString?: string;\r\n infoString?: string;\r\n // When true, both sides' verify public keys (local + linked, sorted so both ends agree without\r\n // coordinating an order) are folded into the HKDF info alongside `infoString`. If either relayed\r\n // verify key was tampered with in transit, the two sides derive mismatched keys and the first\r\n // decryption fails — authenticating the keys without extra signatures. Requires the linked\r\n // client's verify key to be set. Both ends of the link must use the same setting.\r\n bindVerifyKeysIntoDerivation?: boolean;\r\n}\r\n\r\ninterface IEncryptDataForLinkedClient {\r\n linkedClientId: TTypeAndId;\r\n dataToEncrypt: string;\r\n}\r\n\r\ninterface IDecryptDataFromLinkedClient {\r\n linkedClientId: TTypeAndId;\r\n dataToDecrypt: TEncryptedAesGcmPayload;\r\n}\r\n\r\ninterface IDecryptAndVerifyDataFromLinkedClient extends IDecryptDataFromLinkedClient {\r\n signatureBase64: string;\r\n}\r\n\r\ninterface IVerifyChallengeFromLinkedClient {\r\n linkedClientId: TTypeAndId;\r\n challenge: string;\r\n signatureBase64: string;\r\n}\r\n\r\nexport class ClientCryptoKeyLink {\r\n private localExchangeKeyPair: CryptoKeyPair | undefined;\r\n private localVerifyKeyPair: CryptoKeyPair | undefined;\r\n private linkedClientKeys = new Map<TTypeAndId, IExternalClientCryptoKeys>();\r\n private storage: ITypedStorage<ITypedStorage_ClientCryptoKeyLink> | undefined;\r\n private initialized = false;\r\n private initializePromise: Promise<void> | undefined;\r\n private localExchangeKeyPairPromise: Promise<CryptoKeyPair> | undefined;\r\n private localVerifyKeyPairPromise: Promise<CryptoKeyPair> | undefined;\r\n\r\n constructor({ storageAdapter }: IClientCryptoKeyLink_Constructor = {}) {\r\n if (storageAdapter != null) {\r\n this.storage = createTypedStorage({ storageAdapter });\r\n }\r\n }\r\n\r\n /**\r\n * Loads the local key pairs and any linked client public keys from storage (when a storage\r\n * adapter was provided), generating and persisting fresh local key pairs if none exist yet.\r\n *\r\n * Must be called (and awaited) before any sign/verify/encrypt/decrypt operation.\r\n */\r\n async initialize(): Promise<void> {\r\n if (this.initialized) {\r\n return;\r\n }\r\n\r\n // Guard against concurrent initialize() calls (e.g. parallel callers on the frontend, where\r\n // there is no blockConcurrencyWhile) generating and persisting duplicate local key pairs.\r\n this.initializePromise ??= this.runInitialize();\r\n\r\n try {\r\n await this.initializePromise;\r\n } finally {\r\n this.initializePromise = undefined;\r\n }\r\n }\r\n\r\n private async runInitialize(): Promise<void> {\r\n await this.loadStoredLocalKeys();\r\n await this.loadLinkedClients();\r\n\r\n this.initialized = true;\r\n }\r\n\r\n /**\r\n * Loads the local key pairs from storage if they were previously persisted. Does NOT generate\r\n * fresh keys — local identity is created lazily on first use (see {@link ensureLocalExchangeKeyPair}\r\n * / {@link ensureLocalVerifyKeyPair}), so a verify-only or otherwise key-less consumer never\r\n * generates or stores keys it does not need.\r\n */\r\n private async loadStoredLocalKeys(): Promise<void> {\r\n const storedExchange = await this.storage?.getJson(\"localExchangeKeyPair\");\r\n if (storedExchange != null) {\r\n this.localExchangeKeyPair = {\r\n privateKey: await importX25519Key.private.fromFormattedString.extractable(\r\n storedExchange.privateKey,\r\n ),\r\n publicKey: await importX25519Key.public.fromFormattedString.extractable(\r\n storedExchange.publicKey,\r\n ),\r\n };\r\n }\r\n\r\n const storedVerify = await this.storage?.getJson(\"localVerifyKeyPair\");\r\n if (storedVerify != null) {\r\n this.localVerifyKeyPair = {\r\n privateKey: await importEd25519Key.private.fromFormattedString.extractable(\r\n storedVerify.privateKey,\r\n ),\r\n publicKey: await importEd25519Key.public.fromFormattedString.extractable(\r\n storedVerify.publicKey,\r\n ),\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Returns the local exchange (X25519) key pair, generating and persisting it on first use.\r\n * Concurrent callers share a single generation.\r\n */\r\n private async ensureLocalExchangeKeyPair(): Promise<CryptoKeyPair> {\r\n if (this.localExchangeKeyPair != null) {\r\n return this.localExchangeKeyPair;\r\n }\r\n\r\n this.localExchangeKeyPairPromise ??= (async () => {\r\n const keyPair = await generateX25519KeyPair();\r\n this.localExchangeKeyPair = keyPair;\r\n if (this.storage != null) {\r\n await this.storage.setJson(\r\n \"localExchangeKeyPair\",\r\n await this.serializeExchangeKeyPair(keyPair),\r\n );\r\n }\r\n return keyPair;\r\n })();\r\n\r\n try {\r\n return await this.localExchangeKeyPairPromise;\r\n } finally {\r\n this.localExchangeKeyPairPromise = undefined;\r\n }\r\n }\r\n\r\n /**\r\n * Returns the local verify (Ed25519) key pair, generating and persisting it on first use.\r\n * Concurrent callers share a single generation.\r\n */\r\n private async ensureLocalVerifyKeyPair(): Promise<CryptoKeyPair> {\r\n if (this.localVerifyKeyPair != null) {\r\n return this.localVerifyKeyPair;\r\n }\r\n\r\n this.localVerifyKeyPairPromise ??= (async () => {\r\n const keyPair = await generateEd25519KeyPair();\r\n this.localVerifyKeyPair = keyPair;\r\n if (this.storage != null) {\r\n await this.storage.setJson(\r\n \"localVerifyKeyPair\",\r\n await this.serializeVerifyKeyPair(keyPair),\r\n );\r\n }\r\n return keyPair;\r\n })();\r\n\r\n try {\r\n return await this.localVerifyKeyPairPromise;\r\n } finally {\r\n this.localVerifyKeyPairPromise = undefined;\r\n }\r\n }\r\n\r\n private async loadLinkedClients(): Promise<void> {\r\n const storedLinkedClients = await this.storage?.getJson(\"linkedClientPublicKeys\");\r\n\r\n if (storedLinkedClients == null) {\r\n return;\r\n }\r\n\r\n for (const [linkedClientId, publicKeys] of Object.entries(storedLinkedClients) as [\r\n TTypeAndId,\r\n ITypedStorage_ClientCryptoKeyLink[\"linkedClientPublicKeys\"][TTypeAndId],\r\n ][]) {\r\n await this.linkClient({\r\n linkedClientId,\r\n verifyPublicKey: publicKeys.verifyPublicKey,\r\n exchangePublicKey: publicKeys.exchangePublicKey,\r\n saltString: publicKeys.saltString,\r\n infoString: publicKeys.infoString,\r\n bindVerifyKeysIntoDerivation: publicKeys.bindVerifyKeysIntoDerivation,\r\n });\r\n }\r\n }\r\n\r\n private async serializeExchangeKeyPair(\r\n keyPair: CryptoKeyPair,\r\n ): Promise<TSerializedCryptoKeyPairDataX25519> {\r\n return {\r\n publicKey: (await serializeX25519Key_Raw(keyPair.publicKey)).prefixed,\r\n privateKey: (await serializeX25519Key_Jwk(keyPair.privateKey)).prefixed,\r\n };\r\n }\r\n\r\n private async serializeVerifyKeyPair(\r\n keyPair: CryptoKeyPair,\r\n ): Promise<TSerializedCryptoKeyPairDataEd25519> {\r\n return {\r\n publicKey: (await serializeEd25519Key_Raw(keyPair.publicKey)).prefixed,\r\n privateKey: (await serializeEd25519Key_Jwk(keyPair.privateKey)).prefixed,\r\n };\r\n }\r\n\r\n /**\r\n * The local public keys that should be shared with a linked client so that it can verify this\r\n * client's signatures and derive a shared encryption key. Generates the local identity on first\r\n * use.\r\n */\r\n async getLocalPublicKeys(): Promise<ILocalPublicKeys> {\r\n return {\r\n verifyPublicKey: await this.getLocalVerifyPublicKey(),\r\n exchangePublicKey: await this.getLocalExchangePublicKey(),\r\n };\r\n }\r\n\r\n /**\r\n * The local exchange (X25519) public key, generating the exchange key pair on first use. Does not\r\n * touch the verify key pair — useful for an exchange-only consumer (e.g. a bridge) that never\r\n * signs.\r\n */\r\n async getLocalExchangePublicKey(): Promise<TSerializedCryptoKeyData_X25519_Raw> {\r\n const exchangeKeyPair = await this.ensureLocalExchangeKeyPair();\r\n return (await serializeX25519Key_Raw(exchangeKeyPair.publicKey)).prefixed;\r\n }\r\n\r\n /**\r\n * The local verify (Ed25519) public key, generating the verify key pair on first use. Does not\r\n * touch the exchange key pair.\r\n */\r\n async getLocalVerifyPublicKey(): Promise<TSerializedCryptoKeyData_Ed25519_Raw> {\r\n const verifyKeyPair = await this.ensureLocalVerifyKeyPair();\r\n return (await serializeEd25519Key_Raw(verifyKeyPair.publicKey)).prefixed;\r\n }\r\n\r\n /**\r\n * Registers (or updates) the public keys of a linked client in memory only — nothing is written\r\n * to storage. Use this for ephemeral links (e.g. a per-session bridge or end-to-end peer keyed by\r\n * a session salt/info), so the derived shared key never outlives the process.\r\n *\r\n * Re-linking with a new exchange public key, salt, or info invalidates any previously cached\r\n * shared key for the link.\r\n */\r\n async linkClient({\r\n linkedClientId,\r\n verifyPublicKey,\r\n exchangePublicKey,\r\n saltString,\r\n infoString,\r\n bindVerifyKeysIntoDerivation,\r\n }: ILinkClientKeys): Promise<void> {\r\n const existing = this.linkedClientKeys.get(linkedClientId);\r\n\r\n const verify =\r\n verifyPublicKey != null\r\n ? {\r\n publicKey:\r\n await importEd25519Key.public.fromFormattedString.extractable(verifyPublicKey),\r\n publicKeySerialized: verifyPublicKey,\r\n }\r\n : existing?.verify;\r\n\r\n const verifyKeyChanged =\r\n verifyPublicKey != null && verifyPublicKey !== existing?.verify?.publicKeySerialized;\r\n\r\n let exchange = existing?.exchange;\r\n\r\n // `undefined` means \"leave as-is\"; only fields actually passed override the existing link.\r\n const exchangeParamsProvided =\r\n exchangePublicKey != null ||\r\n saltString !== undefined ||\r\n infoString !== undefined ||\r\n bindVerifyKeysIntoDerivation !== undefined;\r\n\r\n if (exchangeParamsProvided) {\r\n const nextPublicKeySerialized = exchangePublicKey ?? existing?.exchange?.publicKeySerialized;\r\n\r\n if (nextPublicKeySerialized == null) {\r\n throw new Error(\r\n `ClientCryptoKeyLink: Cannot set salt/info for ${linkedClientId} without an exchange public key`,\r\n );\r\n }\r\n\r\n const nextSalt = saltString !== undefined ? saltString : existing?.exchange?.saltString;\r\n const nextInfo = infoString !== undefined ? infoString : existing?.exchange?.infoString;\r\n const nextBind =\r\n bindVerifyKeysIntoDerivation !== undefined\r\n ? bindVerifyKeysIntoDerivation\r\n : existing?.exchange?.bindVerifyKeysIntoDerivation;\r\n\r\n const publicKey =\r\n exchangePublicKey != null\r\n ? await importX25519Key.public.fromFormattedString.extractable(exchangePublicKey)\r\n : // Safe: nextPublicKeySerialized fell back to the existing key, so it exists.\r\n existing!.exchange!.publicKey;\r\n\r\n const unchanged =\r\n nextPublicKeySerialized === existing?.exchange?.publicKeySerialized &&\r\n nextSalt === existing?.exchange?.saltString &&\r\n nextInfo === existing?.exchange?.infoString &&\r\n nextBind === existing?.exchange?.bindVerifyKeysIntoDerivation &&\r\n // With verify keys bound into the derivation, a new verify key changes the derived key.\r\n !(nextBind === true && verifyKeyChanged);\r\n\r\n exchange = {\r\n publicKey,\r\n publicKeySerialized: nextPublicKeySerialized,\r\n saltString: nextSalt,\r\n infoString: nextInfo,\r\n bindVerifyKeysIntoDerivation: nextBind,\r\n // Keep the cached shared key only when no derivation input changed.\r\n sharedEncryptKey: unchanged ? existing?.exchange?.sharedEncryptKey : undefined,\r\n };\r\n } else if (\r\n exchange?.bindVerifyKeysIntoDerivation === true &&\r\n verifyKeyChanged &&\r\n exchange.sharedEncryptKey != null\r\n ) {\r\n // Verify-only re-link, but the verify key participates in this link's derivation.\r\n exchange = { ...exchange, sharedEncryptKey: undefined };\r\n }\r\n\r\n this.linkedClientKeys.set(linkedClientId, { verify, exchange });\r\n }\r\n\r\n /**\r\n * Like {@link linkClient}, but also persists the linked client's public keys (and salt/info) to\r\n * storage so the link survives a reload.\r\n *\r\n * NOTE: salt/info are written in plaintext. When they are session secrets (e.g. a partner secret\r\n * or bridge salt), prefer {@link linkClient} and re-establish the link per session instead.\r\n */\r\n async linkClientAndStore(input: ILinkClientKeys): Promise<void> {\r\n await this.linkClient(input);\r\n\r\n if (this.storage == null) {\r\n return;\r\n }\r\n\r\n const {\r\n linkedClientId,\r\n verifyPublicKey,\r\n exchangePublicKey,\r\n saltString,\r\n infoString,\r\n bindVerifyKeysIntoDerivation,\r\n } = input;\r\n\r\n await this.storage.updateJsonWithDef(\"linkedClientPublicKeys\", {}, (current) => ({\r\n ...current,\r\n [linkedClientId]: {\r\n ...current[linkedClientId],\r\n ...(verifyPublicKey != null ? { verifyPublicKey } : {}),\r\n ...(exchangePublicKey != null ? { exchangePublicKey } : {}),\r\n ...(saltString !== undefined ? { saltString } : {}),\r\n ...(infoString !== undefined ? { infoString } : {}),\r\n ...(bindVerifyKeysIntoDerivation !== undefined ? { bindVerifyKeysIntoDerivation } : {}),\r\n },\r\n }));\r\n }\r\n\r\n /**\r\n * Whether a linked client is currently registered (in memory) under this id.\r\n */\r\n hasLinkedClient(linkedClientId: TTypeAndId): boolean {\r\n return this.linkedClientKeys.has(linkedClientId);\r\n }\r\n\r\n /**\r\n * The serialized public keys registered for a linked client, or undefined when the client is not\r\n * linked. Useful when a holder needs to relay a linked client's keys onward (e.g. a backend\r\n * relaying a wallet's verify key to a partner).\r\n */\r\n getLinkedClientPublicKeys(linkedClientId: TTypeAndId): ILinkedClientPublicKeys | undefined {\r\n const linkedClient = this.linkedClientKeys.get(linkedClientId);\r\n\r\n if (linkedClient == null) {\r\n return undefined;\r\n }\r\n\r\n return {\r\n verifyPublicKey: linkedClient.verify?.publicKeySerialized,\r\n exchangePublicKey: linkedClient.exchange?.publicKeySerialized,\r\n };\r\n }\r\n\r\n /**\r\n * Removes a single linked client from memory and, when storage is available, from persisted\r\n * state. Any cached shared key for the link is dropped with it.\r\n */\r\n async unlinkClient(linkedClientId: TTypeAndId): Promise<void> {\r\n this.linkedClientKeys.delete(linkedClientId);\r\n\r\n if (this.storage != null) {\r\n await this.storage.updateJson(\"linkedClientPublicKeys\", (current) => {\r\n if (current == null) {\r\n return {};\r\n }\r\n\r\n const { [linkedClientId]: _removed, ...rest } = current;\r\n return rest;\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Removes all linked clients from memory and persisted state, while keeping the local identity\r\n * key pairs intact.\r\n */\r\n async unlinkAllClients(): Promise<void> {\r\n this.linkedClientKeys.clear();\r\n\r\n if (this.storage != null) {\r\n await this.storage.setJson(\"linkedClientPublicKeys\", {});\r\n }\r\n }\r\n\r\n /**\r\n * Wipes everything this instance owns — local identity key pairs and all linked clients, in\r\n * memory and in storage. After a reset, {@link initialize} must be called again before use (it\r\n * will generate a fresh local identity).\r\n *\r\n * Only the keys owned by this util are removed, so a shared storage adapter's other data is left\r\n * untouched.\r\n */\r\n async reset(): Promise<void> {\r\n this.linkedClientKeys.clear();\r\n this.localExchangeKeyPair = undefined;\r\n this.localVerifyKeyPair = undefined;\r\n this.initialized = false;\r\n\r\n if (this.storage != null) {\r\n await this.storage.removeItem(\"linkedClientPublicKeys\");\r\n await this.storage.removeItem(\"localExchangeKeyPair\");\r\n await this.storage.removeItem(\"localVerifyKeyPair\");\r\n }\r\n }\r\n\r\n private getLinkedClient(linkedClientId: TTypeAndId): IExternalClientCryptoKeys {\r\n const linkedClient = this.linkedClientKeys.get(linkedClientId);\r\n\r\n if (linkedClient == null) {\r\n throw new Error(`ClientCryptoKeyLink: No linked client for ${linkedClientId}`);\r\n }\r\n\r\n return linkedClient;\r\n }\r\n\r\n private async getAesGcmKeyForLinkedClient(\r\n externalClientSourceId: TTypeAndId,\r\n ): Promise<CryptoKey> {\r\n const linkedClient = this.getLinkedClient(externalClientSourceId);\r\n\r\n if (linkedClient.exchange?.sharedEncryptKey != null) {\r\n return linkedClient.exchange.sharedEncryptKey;\r\n }\r\n\r\n if (linkedClient.exchange?.publicKey == null) {\r\n throw new Error(\r\n `ClientCryptoKeyLink: No public exchange key set for ${externalClientSourceId}`,\r\n );\r\n }\r\n\r\n const localExchangeKeyPair = await this.ensureLocalExchangeKeyPair();\r\n\r\n let infoString = linkedClient.exchange.infoString;\r\n\r\n if (linkedClient.exchange.bindVerifyKeysIntoDerivation === true) {\r\n const linkedVerifyPublicKey = linkedClient.verify?.publicKeySerialized;\r\n\r\n if (linkedVerifyPublicKey == null) {\r\n throw new Error(\r\n `ClientCryptoKeyLink: Link for ${externalClientSourceId} binds verify keys into the derivation, but no verify public key is set`,\r\n );\r\n }\r\n\r\n infoString = buildVerifyKeyBoundInfoString({\r\n infoString: linkedClient.exchange.infoString,\r\n verifyPublicKeys: [await this.getLocalVerifyPublicKey(), linkedVerifyPublicKey],\r\n });\r\n }\r\n\r\n const sharedEncryptKey = await createAesGcmKeyFromX25519Keys({\r\n internalX25519PrivateKey: localExchangeKeyPair.privateKey,\r\n externalX25519PublicKey: linkedClient.exchange.publicKey,\r\n saltString: linkedClient.exchange.saltString,\r\n infoString,\r\n });\r\n\r\n this.linkedClientKeys.set(externalClientSourceId, {\r\n ...linkedClient,\r\n exchange: {\r\n ...linkedClient.exchange,\r\n sharedEncryptKey,\r\n },\r\n });\r\n\r\n return sharedEncryptKey;\r\n }\r\n\r\n async encryptDataForLinkedClient({\r\n dataToEncrypt,\r\n linkedClientId,\r\n }: IEncryptDataForLinkedClient): Promise<TEncryptedAesGcmPayload> {\r\n const key = await this.getAesGcmKeyForLinkedClient(linkedClientId);\r\n\r\n return await encryptTextDataWithAesGcmKey({\r\n dataToEncrypt,\r\n aesGcmKey: key,\r\n });\r\n }\r\n\r\n async decryptDataFromLinkedClient({\r\n dataToDecrypt,\r\n linkedClientId,\r\n }: IDecryptDataFromLinkedClient): Promise<string> {\r\n const key = await this.getAesGcmKeyForLinkedClient(linkedClientId);\r\n\r\n return await decryptTextDataWithAesGcmKey({\r\n dataToDecrypt,\r\n aesGcmKey: key,\r\n });\r\n }\r\n\r\n /**\r\n * Bytes counterpart of {@link encryptDataForLinkedClient} — encrypts raw bytes with the shared\r\n * AES-GCM key, returning a binary nonce + ciphertext. Use it for binary channels (e.g. msgpack\r\n * WebSocket frames) to avoid base64 inflation.\r\n */\r\n async encryptBytesForLinkedClient({\r\n dataToEncrypt,\r\n linkedClientId,\r\n }: {\r\n dataToEncrypt: Uint8Array;\r\n linkedClientId: TTypeAndId;\r\n }): Promise<TEncryptedAesGcmBytes> {\r\n const key = await this.getAesGcmKeyForLinkedClient(linkedClientId);\r\n\r\n return await encryptBytesWithAesGcmKey({\r\n dataToEncrypt,\r\n aesGcmKey: key,\r\n });\r\n }\r\n\r\n /** Bytes counterpart of {@link decryptDataFromLinkedClient}. */\r\n async decryptBytesFromLinkedClient({\r\n dataToDecrypt,\r\n linkedClientId,\r\n }: {\r\n dataToDecrypt: TEncryptedAesGcmBytes;\r\n linkedClientId: TTypeAndId;\r\n }): Promise<Uint8Array> {\r\n const key = await this.getAesGcmKeyForLinkedClient(linkedClientId);\r\n\r\n return await decryptBytesWithAesGcmKey({\r\n dataToDecrypt,\r\n aesGcmKey: key,\r\n });\r\n }\r\n\r\n async signAndEncryptDataForLinkedClient({\r\n dataToEncrypt,\r\n linkedClientId,\r\n }: IEncryptDataForLinkedClient): Promise<{\r\n encryptedData: TEncryptedAesGcmPayload;\r\n signatureBase64: string;\r\n }> {\r\n const { signatureBase64 } = await this.signChallenge([dataToEncrypt]);\r\n const encryptedData = await this.encryptDataForLinkedClient({\r\n dataToEncrypt,\r\n linkedClientId,\r\n });\r\n\r\n return {\r\n encryptedData,\r\n signatureBase64,\r\n };\r\n }\r\n\r\n /**\r\n * Decrypts a payload from a linked client and verifies that the decrypted plaintext was signed\r\n * by that client. Counterpart to {@link signAndEncryptDataForLinkedClient}.\r\n *\r\n * Returns the decrypted `data` alongside `isValid` — the caller decides how to handle an invalid\r\n * signature. (A tampered ciphertext fails earlier at AES-GCM decryption.)\r\n */\r\n async decryptAndVerifyDataFromLinkedClient({\r\n dataToDecrypt,\r\n linkedClientId,\r\n signatureBase64,\r\n }: IDecryptAndVerifyDataFromLinkedClient): Promise<{ data: string; isValid: boolean }> {\r\n const data = await this.decryptDataFromLinkedClient({\r\n dataToDecrypt,\r\n linkedClientId,\r\n });\r\n\r\n const isValid = await this.verifyChallengeFromLinkedClient({\r\n linkedClientId,\r\n challenge: data,\r\n signatureBase64,\r\n });\r\n\r\n return { data, isValid };\r\n }\r\n\r\n async signChallenge(challenge: [string, ...string[]]): Promise<{\r\n signatureBase64: string;\r\n }> {\r\n if (challenge.length === 0) {\r\n throw new Error(\"Challenge must contain at least one string\");\r\n }\r\n\r\n const localVerifyKeyPair = await this.ensureLocalVerifyKeyPair();\r\n\r\n const signature =\r\n challenge.length > 1\r\n ? await signCombinedTextDataWithKeyEd25519(challenge, localVerifyKeyPair.privateKey)\r\n : await signTextDataWithKeyEd25519(challenge[0], localVerifyKeyPair.privateKey);\r\n\r\n return {\r\n signatureBase64: base64.encode(signature),\r\n };\r\n }\r\n\r\n /**\r\n * Verifies a signature over `challenge` against the linked client's verify (Ed25519) public key.\r\n */\r\n async verifyChallengeFromLinkedClient({\r\n linkedClientId,\r\n challenge,\r\n signatureBase64,\r\n }: IVerifyChallengeFromLinkedClient): Promise<boolean> {\r\n const linkedClient = this.getLinkedClient(linkedClientId);\r\n\r\n if (linkedClient.verify?.publicKey == null) {\r\n throw new Error(`ClientCryptoKeyLink: No verify public key set for ${linkedClientId}`);\r\n }\r\n\r\n return await verifyWithKeyEd25519({\r\n challenge,\r\n signatureBase64,\r\n publicKey: linkedClient.verify.publicKey,\r\n });\r\n }\r\n}\r\n","// import type { StringKeys } from \"../typescript/special_typescript_types\";\n\nexport enum EStorageAdapterType {\n string = \"string\",\n json = \"json\",\n}\n\nexport interface IStorageAdapterMethods_String {\n type: EStorageAdapterType.string;\n setItem: (key: string, value: string) => Promise<void>;\n getItem: (key: string) => Promise<string | null | undefined>;\n removeItem: (key: string) => Promise<void>;\n}\n\nexport interface IStorageAdapterMethods_Json {\n type: EStorageAdapterType.json;\n setItem: <T>(key: string, value: T) => Promise<void>;\n getItem: <T>(key: string) => Promise<T | null | undefined>;\n removeItem: (key: string) => Promise<void>;\n}\n\nexport type TStorageAdapterMethods = IStorageAdapterMethods_String | IStorageAdapterMethods_Json;\n\nexport interface IStorageKeyGetterAndSetter<T> {\n get: () => Promise<T | undefined>;\n set: (value: T) => Promise<void>;\n}\n\n// export interface IStorageAdapter {}\n","import {\n EStorageAdapterType,\n type IStorageKeyGetterAndSetter,\n type TStorageAdapterMethods,\n} from \"./storage_adapter.types\";\nimport { createTypedStorage, type ITypedStorage } from \"./typed_storage/createTypedStorage\";\n\nexport interface IStorageAdapterConstructor {\n methods: TStorageAdapterMethods;\n trackKeysForClearing?: boolean;\n keyPrefix?: string;\n}\n\ninterface IStorageAdapterTypedStorage {\n __usedKeys__: string[];\n}\n\nexport class StorageAdapter {\n private implementation: TStorageAdapterMethods;\n readonly keyPrefix: string;\n private readonly adapterStorage?: ITypedStorage<IStorageAdapterTypedStorage>;\n\n constructor({ methods, keyPrefix, trackKeysForClearing: trackKeys }: IStorageAdapterConstructor) {\n this.implementation = methods;\n this.keyPrefix = keyPrefix ?? \"\";\n const _trackKeys = trackKeys ?? true;\n // Only create keyStorage when tracking is enabled; the inner adapter has trackKeys:false so\n // its constructor skips this branch, breaking the infinite-recursion cycle.\n this.adapterStorage = _trackKeys\n ? createTypedStorage({\n storageAdapter: new StorageAdapter({ methods, keyPrefix, trackKeysForClearing: false }),\n })\n : undefined;\n }\n\n private getPrefixedKey(rawKey: string): string {\n return `${this.keyPrefix}${rawKey}`;\n }\n\n private async trackUsedKey(rawKey: string): Promise<void> {\n if (!this.adapterStorage) return;\n await this.adapterStorage.updateJsonWithDef(\"__usedKeys__\", [], (currentKeys) => {\n if (!currentKeys.includes(rawKey)) {\n return [...currentKeys, rawKey];\n }\n return currentKeys;\n });\n }\n\n private async untrackUsedKey(rawKey: string): Promise<void> {\n if (!this.adapterStorage) return;\n await this.adapterStorage.updateJsonWithDef(\"__usedKeys__\", [], (currentKeys) => {\n return currentKeys.filter((k) => k !== rawKey);\n });\n }\n\n async clearAll(): Promise<void> {\n if (!this.adapterStorage) return;\n const allKeys = (await this.adapterStorage.getJsonOrDef(\"__usedKeys__\", [])) ?? [];\n\n await Promise.all(\n allKeys.map(async (key) => {\n await this.removeItem(key);\n }),\n );\n\n await this.adapterStorage.setJson(\"__usedKeys__\", []);\n }\n\n async removeItem(rawKey: string): Promise<void> {\n await this.implementation.removeItem(this.getPrefixedKey(rawKey));\n await this.untrackUsedKey(rawKey);\n }\n\n async setJson(rawKey: string, value: any) {\n const key = this.getPrefixedKey(rawKey);\n\n if (this.implementation.type === EStorageAdapterType.string) {\n await this.implementation.setItem(key, JSON.stringify(value));\n } else {\n await this.implementation.setItem(key, value);\n }\n\n await this.trackUsedKey(rawKey);\n }\n\n async getJson<T>(rawKey: string): Promise<T | undefined> {\n const key = this.getPrefixedKey(rawKey);\n\n if (this.implementation.type === EStorageAdapterType.string) {\n const val = await this.implementation.getItem(key);\n\n if (val == null || val === \"undefined\" || val === \"null\") {\n return undefined;\n }\n\n return JSON.parse(val);\n } else {\n const val = await this.implementation.getItem<T>(key);\n\n if (val == null || val === \"undefined\" || val === \"null\") {\n return undefined;\n }\n\n return val;\n }\n }\n\n async getJsonOrDef<T>(rawKey: string, defVal: T): Promise<T> {\n if (this.implementation.type === EStorageAdapterType.string) {\n const val = await this.implementation.getItem(this.getPrefixedKey(rawKey));\n\n if (val == null || val === \"undefined\" || val === \"null\") {\n return defVal;\n }\n\n return JSON.parse(val);\n }\n\n const val = await this.implementation.getItem<T>(this.getPrefixedKey(rawKey));\n\n if (val == null || val === \"undefined\" || val === \"null\") {\n return defVal;\n }\n\n return val;\n }\n\n async updateJson<T>(rawKey: string, updater: (currentVal: T | undefined) => T): Promise<T> {\n const currentVal = await this.getJson<T>(rawKey);\n const newVal = updater(currentVal);\n await this.setJson(rawKey, newVal);\n return newVal;\n }\n\n async updateJsonOrDef<T>(rawKey: string, defVal: T, updater: (currentVal: T) => T): Promise<T> {\n const currentVal = await this.getJsonOrDef<T>(rawKey, defVal);\n const newVal = updater(currentVal);\n await this.setJson(rawKey, newVal);\n return newVal;\n }\n\n createJsonGetterSetter<T>(rawKey: string): IStorageKeyGetterAndSetter<T> {\n return {\n get: () => this.getJson(rawKey),\n set: (value: T) => this.setJson(rawKey, value),\n };\n }\n}\n","import { type IStorageAdapterConstructor, StorageAdapter } from \"../../StorageAdapter\";\nimport {\n EStorageAdapterType,\n type IStorageAdapterMethods_String,\n} from \"../../storage_adapter.types\";\nimport { createTypedStorage, type ITypedStorage } from \"../../typed_storage/createTypedStorage\";\n\n/**\n *\n * Web Storage [LOCAL STORAGE]\n *\n */\n\ntype TCreateWebLocalStorageOptions = Omit<IStorageAdapterConstructor, \"methods\"> & {\n localStorage: typeof localStorage;\n};\n\nexport function createWebLocalStorageMethods(\n _localStorage: typeof localStorage,\n): IStorageAdapterMethods_String {\n return {\n type: EStorageAdapterType.string,\n getItem: async (key) => _localStorage.getItem(key),\n setItem: async (key, value) => {\n _localStorage.setItem(key, value);\n },\n removeItem: async (key) => {\n _localStorage.removeItem(key);\n },\n };\n}\n\nexport const createWebLocalStorageAdapter = ({\n localStorage: _localStorage,\n ...options\n}: TCreateWebLocalStorageOptions): StorageAdapter => {\n return new StorageAdapter({\n methods: createWebLocalStorageMethods(_localStorage),\n ...options,\n });\n};\n\nexport function createTypedWebLocalStorage<T extends Record<string, any>>(\n options: TCreateWebLocalStorageOptions,\n): ITypedStorage<T> {\n return createTypedStorage<T>({\n storageAdapter: createWebLocalStorageAdapter(options),\n });\n}\n\n/**\n *\n * Web Storage [SESSION STORAGE]\n *\n */\n\ntype TCreateWebSessionStorageOptions = Omit<IStorageAdapterConstructor, \"methods\"> & {\n sessionStorage: typeof sessionStorage;\n};\n\nexport function createWebSessionStorageMethods(\n _sessionStorage: typeof sessionStorage,\n): IStorageAdapterMethods_String {\n return {\n type: EStorageAdapterType.string,\n getItem: async (key) => _sessionStorage.getItem(key),\n setItem: async (key, value) => {\n _sessionStorage.setItem(key, value);\n },\n removeItem: async (key) => {\n _sessionStorage.removeItem(key);\n },\n };\n}\n\nexport const createWebSessionStorageAdapter = ({\n sessionStorage: _sessionStorage,\n ...options\n}: TCreateWebSessionStorageOptions): StorageAdapter => {\n return new StorageAdapter({\n methods: createWebSessionStorageMethods(_sessionStorage),\n ...options,\n });\n};\n\nexport function createTypedWebSessionStorage<T extends Record<string, any>>(\n options: TCreateWebSessionStorageOptions,\n): ITypedStorage<T> {\n return createTypedStorage<T>({\n storageAdapter: createWebSessionStorageAdapter(options),\n });\n}\n","import { type IStorageAdapterConstructor, StorageAdapter } from \"../../../StorageAdapter\";\nimport {\n EStorageAdapterType,\n type IStorageAdapterMethods_Json,\n} from \"../../../storage_adapter.types\";\nimport { createTypedStorage, type ITypedStorage } from \"../../../typed_storage/createTypedStorage\";\nimport type { IDurableObjectStorage } from \"./durable_object_storage.types\";\n\nexport function createDurableObjectStorageMethods(\n durableObjectStorage: IDurableObjectStorage,\n): IStorageAdapterMethods_Json {\n return {\n type: EStorageAdapterType.json,\n getItem: (key) => durableObjectStorage.get(key),\n setItem: (key, value) => durableObjectStorage.put(key, value),\n removeItem: async (key) => {\n await durableObjectStorage.delete(key);\n },\n };\n}\n\nexport type TCreateDurableObjectStorageOptions = Omit<IStorageAdapterConstructor, \"methods\"> & {\n durableObjectStorage: IDurableObjectStorage;\n};\n\n/**\n * Wraps a Durable Object's storage in the generic StorageAdapter interface, e.g. for handing to a\n * ClientCryptoKeyLink so it can persist its keys inside the DO's own storage.\n */\nexport const createDurableObjectStorageAdapter = ({\n durableObjectStorage,\n ...options\n}: TCreateDurableObjectStorageOptions): StorageAdapter => {\n return new StorageAdapter({\n methods: createDurableObjectStorageMethods(durableObjectStorage),\n ...options,\n });\n};\n\nexport function createDurableObjectTypedStorage<T extends Record<string, any>>(\n options: TCreateDurableObjectStorageOptions,\n): ITypedStorage<T> {\n return createTypedStorage<T>({\n storageAdapter: createDurableObjectStorageAdapter(options),\n });\n}\n","import { type IStorageAdapterConstructor, StorageAdapter } from \"../../../StorageAdapter\";\nimport {\n EStorageAdapterType,\n type IStorageAdapterMethods_String,\n} from \"../../../storage_adapter.types\";\nimport { createTypedStorage, type ITypedStorage } from \"../../../typed_storage/createTypedStorage\";\nimport type { IKVNamespace, IKVNamespacePutOptions } from \"./kv_storage.types\";\n\nexport interface ICreateKVStorageMethodsOptions {\n /** The `KVNamespace` binding, e.g. accessed off `env.MY_KV` inside a worker. */\n kvNamespace: IKVNamespace;\n /** Default options applied to every `put`, e.g. `{ expirationTtl }` for TTL-based eviction. */\n defaultPutOptions?: IKVNamespacePutOptions;\n}\n\nexport function createKVStorageMethods({\n kvNamespace,\n defaultPutOptions,\n}: ICreateKVStorageMethodsOptions): IStorageAdapterMethods_String {\n return {\n type: EStorageAdapterType.string,\n getItem: (key) => kvNamespace.get(key),\n setItem: (key, value) => kvNamespace.put(key, value, defaultPutOptions),\n removeItem: (key) => kvNamespace.delete(key),\n };\n}\n\nexport type TCreateKVStorageOptions = Omit<IStorageAdapterConstructor, \"methods\"> &\n ICreateKVStorageMethodsOptions;\n\n/**\n * Wraps a Cloudflare KV namespace binding in the generic StorageAdapter interface, e.g. for handing\n * to a ClientCryptoKeyLink so it can persist its keys inside KV.\n */\nexport const createKVStorageAdapter = ({\n kvNamespace,\n defaultPutOptions,\n ...options\n}: TCreateKVStorageOptions): StorageAdapter => {\n return new StorageAdapter({\n methods: createKVStorageMethods({ kvNamespace, defaultPutOptions }),\n ...options,\n });\n};\n\nexport function createKVTypedStorage<T extends Record<string, any>>(\n options: TCreateKVStorageOptions,\n): ITypedStorage<T> {\n return createTypedStorage<T>({\n storageAdapter: createKVStorageAdapter(options),\n });\n}\n","import { type IStorageAdapterConstructor, StorageAdapter } from \"../../StorageAdapter\";\nimport {\n EStorageAdapterType,\n type IStorageAdapterMethods_Json,\n type IStorageAdapterMethods_String,\n} from \"../../storage_adapter.types\";\nimport { createTypedStorage, type ITypedStorage } from \"../../typed_storage/createTypedStorage\";\n\nexport type TMemoryStorage_string = Map<string, string>;\nexport type TMemoryStorage_json = Map<string, any>;\n\n/**\n *\n * Memory Storage [STRING]\n *\n */\n\ntype TCreateMemoryStorageOptions_string = Omit<IStorageAdapterConstructor, \"methods\"> & {\n memoryStorageMap?: TMemoryStorage_string;\n};\n\nexport function createMemoryStorageMethods_string(\n memoryStorageMap: TMemoryStorage_string = new Map(),\n): IStorageAdapterMethods_String {\n return {\n type: EStorageAdapterType.string,\n getItem: async (key) => memoryStorageMap.get(key) ?? null,\n setItem: async (key, value) => {\n memoryStorageMap.set(key, value);\n },\n removeItem: async (key) => {\n memoryStorageMap.delete(key);\n },\n };\n}\n\nexport const createMemoryStorageAdapter_string = (\n options?: TCreateMemoryStorageOptions_string,\n): StorageAdapter => {\n return new StorageAdapter({\n methods: createMemoryStorageMethods_string(options?.memoryStorageMap),\n ...options,\n });\n};\n\nexport function createTypedMemoryStorage_string<T extends Record<string, any>>(\n options?: TCreateMemoryStorageOptions_string,\n): ITypedStorage<T> {\n return createTypedStorage<T>({\n storageAdapter: createMemoryStorageAdapter_string(options),\n });\n}\n\n/**\n *\n * Memory Storage [JSON]\n *\n */\n\ntype TCreateMemoryStorageOptions_json = Omit<IStorageAdapterConstructor, \"methods\"> & {\n memoryStorageMap?: TMemoryStorage_json;\n};\n\nexport function createMemoryStorageMethods_json(\n memoryStorageMap: TMemoryStorage_json = new Map(),\n): IStorageAdapterMethods_Json {\n return {\n type: EStorageAdapterType.json,\n getItem: async (key) => memoryStorageMap.get(key),\n setItem: async (key, value) => {\n memoryStorageMap.set(key, value);\n },\n removeItem: async (key) => {\n memoryStorageMap.delete(key);\n },\n };\n}\n\nexport const createMemoryStorageAdapter_json = (\n options?: TCreateMemoryStorageOptions_json,\n): StorageAdapter => {\n return new StorageAdapter({\n methods: createMemoryStorageMethods_json(options?.memoryStorageMap),\n ...options,\n });\n};\n\nexport function createTypedMemoryStorage_json<T extends Record<string, any>>(\n options?: TCreateMemoryStorageOptions_json,\n): ITypedStorage<T> {\n return createTypedStorage<T>({\n storageAdapter: createMemoryStorageAdapter_json(options),\n });\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nice-code/util",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
8
8
|
"source": "./src/index.ts",
|
|
9
9
|
"import": "./build/index.js",
|
|
10
|
-
"types": "./build/
|
|
10
|
+
"types": "./build/index.d.ts"
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
@@ -24,29 +24,17 @@
|
|
|
24
24
|
"clean-build": "bunx rimraf build",
|
|
25
25
|
"vitest": "vitest --typecheck",
|
|
26
26
|
"vitest-agent": "vitest --typecheck --reporter=agent",
|
|
27
|
-
"build": "bun run clean-build && bun run build.ts && bun run build-types",
|
|
27
|
+
"build-bun": "bun run clean-build && bun run build.ts && bun run build-types",
|
|
28
|
+
"build": "bun run clean-build && tsdown",
|
|
28
29
|
"build-watch": "bun run clean-build && bun run build.ts --watch && bun run build-types --watch",
|
|
29
30
|
"build-types": "tsc --project tsconfig.build.json"
|
|
30
31
|
},
|
|
31
32
|
"dependencies": {
|
|
33
|
+
"valibot": "^1.3.1",
|
|
34
|
+
"@scure/base": "^2.2.0",
|
|
32
35
|
"nanoid": "^5.1.9"
|
|
33
36
|
},
|
|
34
37
|
"devDependencies": {
|
|
35
|
-
"@scure/base": "^2.2.0"
|
|
36
|
-
},
|
|
37
|
-
"peerDependencies": {
|
|
38
|
-
"@tanstack/react-query": "^5.100.3",
|
|
39
|
-
"react": ">=19",
|
|
40
|
-
"valibot": "^1.3.1",
|
|
41
|
-
"@scure/base": "^2.2.0",
|
|
42
38
|
"wrangler": "4.94.0"
|
|
43
|
-
},
|
|
44
|
-
"peerDependenciesMeta": {
|
|
45
|
-
"wrangler": {
|
|
46
|
-
"optional": true
|
|
47
|
-
},
|
|
48
|
-
"@scure/base": {
|
|
49
|
-
"optional": true
|
|
50
|
-
}
|
|
51
39
|
}
|
|
52
40
|
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import * as v from "valibot";
|
|
2
|
-
export declare const vBase64: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.Base64Action<string, undefined>]>;
|
|
3
|
-
export declare const vCreateSchema_TypePrefixedDataString: <P extends string>(typeValues: P[], typeKind: string) => v.SchemaWithPipe<readonly [v.CustomSchema<`${P}::${string}`, v.ErrorMessage<v.CustomIssue> | undefined>]>;
|
|
4
|
-
export interface ICreateTypePrefixedDataStringResult<T extends string, F extends string> {
|
|
5
|
-
type: T;
|
|
6
|
-
format: F;
|
|
7
|
-
typeKind: string;
|
|
8
|
-
formatKind?: string;
|
|
9
|
-
transformJson?: boolean;
|
|
10
|
-
}
|
|
11
|
-
export declare const vCreateSchema_TypeAndFormatPrefixedDataString: <T extends string, F extends string>({ type, format, typeKind, formatKind, }: ICreateTypePrefixedDataStringResult<T, F>) => v.SchemaWithPipe<readonly [v.CustomSchema<`${T}::${F}::${string}`, v.ErrorMessage<v.CustomIssue> | undefined>]>;
|
|
12
|
-
export declare const vCreateSchema_TypeAndId: <S extends string>(dataType: S | S[]) => v.SchemaWithPipe<readonly [v.CustomSchema<`${S}::${string}`, v.ErrorMessage<v.CustomIssue> | undefined>]>;
|
|
13
|
-
export type TTypeAndId<S extends string = string> = `${S}::${string}`;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { ECryptoKeyFormat } from "../crypto/crypto.schema";
|
|
2
|
-
interface ICreateDataStringConverter_StringToObject {
|
|
3
|
-
transformJsonForFormats?: ECryptoKeyFormat[];
|
|
4
|
-
transformJson?: boolean;
|
|
5
|
-
}
|
|
6
|
-
export declare const createDataStringConverter_stringToObject: <T extends string, F extends ECryptoKeyFormat, D = string>({ transformJsonForFormats, transformJson, }?: ICreateDataStringConverter_StringToObject) => (inputDataString: `${T}::${F}::${string}`) => {
|
|
7
|
-
formattedString: `${T}::${F}::${string}`;
|
|
8
|
-
type: T;
|
|
9
|
-
format: F;
|
|
10
|
-
data: D;
|
|
11
|
-
};
|
|
12
|
-
export {};
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export declare const createAesGcmKeyFromX25519Keys: ({ externalX25519PublicKey, internalX25519PrivateKey, infoString, saltString, }: {
|
|
2
|
-
internalX25519PrivateKey: CryptoKey;
|
|
3
|
-
externalX25519PublicKey: CryptoKey;
|
|
4
|
-
saltString?: string;
|
|
5
|
-
infoString?: string;
|
|
6
|
-
}) => Promise<CryptoKey>;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { TEncryptedAesGcmBytes } from "../crypto.schema";
|
|
2
|
-
/**
|
|
3
|
-
* Decrypts a raw-bytes AES-GCM payload (binary nonce + ciphertext) back to bytes. The counterpart of
|
|
4
|
-
* {@link decryptTextDataWithAesGcmKey}. AES-GCM verifies integrity, so a tampered ciphertext throws.
|
|
5
|
-
*/
|
|
6
|
-
export declare const decryptBytesWithAesGcmKey: ({ aesGcmKey, dataToDecrypt, }: {
|
|
7
|
-
aesGcmKey: CryptoKey;
|
|
8
|
-
dataToDecrypt: TEncryptedAesGcmBytes;
|
|
9
|
-
}) => Promise<Uint8Array>;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { TEncryptedAesGcmBytes } from "../crypto.schema";
|
|
2
|
-
/**
|
|
3
|
-
* Encrypts raw bytes with an AES-GCM key, returning the binary nonce + ciphertext. The bytes
|
|
4
|
-
* counterpart of {@link encryptTextDataWithAesGcmKey} — use it for binary channels (msgpack frames)
|
|
5
|
-
* to avoid base64 inflation. A fresh 12-byte nonce is generated per call (never reuse a nonce).
|
|
6
|
-
*/
|
|
7
|
-
export declare const encryptBytesWithAesGcmKey: ({ aesGcmKey, dataToEncrypt, }: {
|
|
8
|
-
aesGcmKey: CryptoKey;
|
|
9
|
-
dataToEncrypt: Uint8Array;
|
|
10
|
-
}) => Promise<TEncryptedAesGcmBytes>;
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import type { TTypeAndId } from "../../core/core_valibot_schemas";
|
|
2
|
-
import type { StorageAdapter } from "../../storage_adapter/StorageAdapter";
|
|
3
|
-
import type { TEncryptedAesGcmBytes, TEncryptedAesGcmPayload, TSerializedCryptoKeyData_Ed25519_Raw, TSerializedCryptoKeyData_X25519_Raw } from "../crypto.schema";
|
|
4
|
-
interface IClientCryptoKeyLink_Constructor {
|
|
5
|
-
storageAdapter?: StorageAdapter;
|
|
6
|
-
}
|
|
7
|
-
interface ILinkedClientPublicKeys {
|
|
8
|
-
verifyPublicKey?: TSerializedCryptoKeyData_Ed25519_Raw;
|
|
9
|
-
exchangePublicKey?: TSerializedCryptoKeyData_X25519_Raw;
|
|
10
|
-
}
|
|
11
|
-
interface ILocalPublicKeys {
|
|
12
|
-
verifyPublicKey: TSerializedCryptoKeyData_Ed25519_Raw;
|
|
13
|
-
exchangePublicKey: TSerializedCryptoKeyData_X25519_Raw;
|
|
14
|
-
}
|
|
15
|
-
interface ILinkClientKeys {
|
|
16
|
-
linkedClientId: TTypeAndId;
|
|
17
|
-
verifyPublicKey?: TSerializedCryptoKeyData_Ed25519_Raw;
|
|
18
|
-
exchangePublicKey?: TSerializedCryptoKeyData_X25519_Raw;
|
|
19
|
-
saltString?: string;
|
|
20
|
-
infoString?: string;
|
|
21
|
-
bindVerifyKeysIntoDerivation?: boolean;
|
|
22
|
-
}
|
|
23
|
-
interface IEncryptDataForLinkedClient {
|
|
24
|
-
linkedClientId: TTypeAndId;
|
|
25
|
-
dataToEncrypt: string;
|
|
26
|
-
}
|
|
27
|
-
interface IDecryptDataFromLinkedClient {
|
|
28
|
-
linkedClientId: TTypeAndId;
|
|
29
|
-
dataToDecrypt: TEncryptedAesGcmPayload;
|
|
30
|
-
}
|
|
31
|
-
interface IDecryptAndVerifyDataFromLinkedClient extends IDecryptDataFromLinkedClient {
|
|
32
|
-
signatureBase64: string;
|
|
33
|
-
}
|
|
34
|
-
interface IVerifyChallengeFromLinkedClient {
|
|
35
|
-
linkedClientId: TTypeAndId;
|
|
36
|
-
challenge: string;
|
|
37
|
-
signatureBase64: string;
|
|
38
|
-
}
|
|
39
|
-
export declare class ClientCryptoKeyLink {
|
|
40
|
-
private localExchangeKeyPair;
|
|
41
|
-
private localVerifyKeyPair;
|
|
42
|
-
private linkedClientKeys;
|
|
43
|
-
private storage;
|
|
44
|
-
private initialized;
|
|
45
|
-
private initializePromise;
|
|
46
|
-
private localExchangeKeyPairPromise;
|
|
47
|
-
private localVerifyKeyPairPromise;
|
|
48
|
-
constructor({ storageAdapter }?: IClientCryptoKeyLink_Constructor);
|
|
49
|
-
/**
|
|
50
|
-
* Loads the local key pairs and any linked client public keys from storage (when a storage
|
|
51
|
-
* adapter was provided), generating and persisting fresh local key pairs if none exist yet.
|
|
52
|
-
*
|
|
53
|
-
* Must be called (and awaited) before any sign/verify/encrypt/decrypt operation.
|
|
54
|
-
*/
|
|
55
|
-
initialize(): Promise<void>;
|
|
56
|
-
private runInitialize;
|
|
57
|
-
/**
|
|
58
|
-
* Loads the local key pairs from storage if they were previously persisted. Does NOT generate
|
|
59
|
-
* fresh keys — local identity is created lazily on first use (see {@link ensureLocalExchangeKeyPair}
|
|
60
|
-
* / {@link ensureLocalVerifyKeyPair}), so a verify-only or otherwise key-less consumer never
|
|
61
|
-
* generates or stores keys it does not need.
|
|
62
|
-
*/
|
|
63
|
-
private loadStoredLocalKeys;
|
|
64
|
-
/**
|
|
65
|
-
* Returns the local exchange (X25519) key pair, generating and persisting it on first use.
|
|
66
|
-
* Concurrent callers share a single generation.
|
|
67
|
-
*/
|
|
68
|
-
private ensureLocalExchangeKeyPair;
|
|
69
|
-
/**
|
|
70
|
-
* Returns the local verify (Ed25519) key pair, generating and persisting it on first use.
|
|
71
|
-
* Concurrent callers share a single generation.
|
|
72
|
-
*/
|
|
73
|
-
private ensureLocalVerifyKeyPair;
|
|
74
|
-
private loadLinkedClients;
|
|
75
|
-
private serializeExchangeKeyPair;
|
|
76
|
-
private serializeVerifyKeyPair;
|
|
77
|
-
/**
|
|
78
|
-
* The local public keys that should be shared with a linked client so that it can verify this
|
|
79
|
-
* client's signatures and derive a shared encryption key. Generates the local identity on first
|
|
80
|
-
* use.
|
|
81
|
-
*/
|
|
82
|
-
getLocalPublicKeys(): Promise<ILocalPublicKeys>;
|
|
83
|
-
/**
|
|
84
|
-
* The local exchange (X25519) public key, generating the exchange key pair on first use. Does not
|
|
85
|
-
* touch the verify key pair — useful for an exchange-only consumer (e.g. a bridge) that never
|
|
86
|
-
* signs.
|
|
87
|
-
*/
|
|
88
|
-
getLocalExchangePublicKey(): Promise<TSerializedCryptoKeyData_X25519_Raw>;
|
|
89
|
-
/**
|
|
90
|
-
* The local verify (Ed25519) public key, generating the verify key pair on first use. Does not
|
|
91
|
-
* touch the exchange key pair.
|
|
92
|
-
*/
|
|
93
|
-
getLocalVerifyPublicKey(): Promise<TSerializedCryptoKeyData_Ed25519_Raw>;
|
|
94
|
-
/**
|
|
95
|
-
* Registers (or updates) the public keys of a linked client in memory only — nothing is written
|
|
96
|
-
* to storage. Use this for ephemeral links (e.g. a per-session bridge or end-to-end peer keyed by
|
|
97
|
-
* a session salt/info), so the derived shared key never outlives the process.
|
|
98
|
-
*
|
|
99
|
-
* Re-linking with a new exchange public key, salt, or info invalidates any previously cached
|
|
100
|
-
* shared key for the link.
|
|
101
|
-
*/
|
|
102
|
-
linkClient({ linkedClientId, verifyPublicKey, exchangePublicKey, saltString, infoString, bindVerifyKeysIntoDerivation, }: ILinkClientKeys): Promise<void>;
|
|
103
|
-
/**
|
|
104
|
-
* Like {@link linkClient}, but also persists the linked client's public keys (and salt/info) to
|
|
105
|
-
* storage so the link survives a reload.
|
|
106
|
-
*
|
|
107
|
-
* NOTE: salt/info are written in plaintext. When they are session secrets (e.g. a partner secret
|
|
108
|
-
* or bridge salt), prefer {@link linkClient} and re-establish the link per session instead.
|
|
109
|
-
*/
|
|
110
|
-
linkClientAndStore(input: ILinkClientKeys): Promise<void>;
|
|
111
|
-
/**
|
|
112
|
-
* Whether a linked client is currently registered (in memory) under this id.
|
|
113
|
-
*/
|
|
114
|
-
hasLinkedClient(linkedClientId: TTypeAndId): boolean;
|
|
115
|
-
/**
|
|
116
|
-
* The serialized public keys registered for a linked client, or undefined when the client is not
|
|
117
|
-
* linked. Useful when a holder needs to relay a linked client's keys onward (e.g. a backend
|
|
118
|
-
* relaying a wallet's verify key to a partner).
|
|
119
|
-
*/
|
|
120
|
-
getLinkedClientPublicKeys(linkedClientId: TTypeAndId): ILinkedClientPublicKeys | undefined;
|
|
121
|
-
/**
|
|
122
|
-
* Removes a single linked client from memory and, when storage is available, from persisted
|
|
123
|
-
* state. Any cached shared key for the link is dropped with it.
|
|
124
|
-
*/
|
|
125
|
-
unlinkClient(linkedClientId: TTypeAndId): Promise<void>;
|
|
126
|
-
/**
|
|
127
|
-
* Removes all linked clients from memory and persisted state, while keeping the local identity
|
|
128
|
-
* key pairs intact.
|
|
129
|
-
*/
|
|
130
|
-
unlinkAllClients(): Promise<void>;
|
|
131
|
-
/**
|
|
132
|
-
* Wipes everything this instance owns — local identity key pairs and all linked clients, in
|
|
133
|
-
* memory and in storage. After a reset, {@link initialize} must be called again before use (it
|
|
134
|
-
* will generate a fresh local identity).
|
|
135
|
-
*
|
|
136
|
-
* Only the keys owned by this util are removed, so a shared storage adapter's other data is left
|
|
137
|
-
* untouched.
|
|
138
|
-
*/
|
|
139
|
-
reset(): Promise<void>;
|
|
140
|
-
private getLinkedClient;
|
|
141
|
-
private getAesGcmKeyForLinkedClient;
|
|
142
|
-
encryptDataForLinkedClient({ dataToEncrypt, linkedClientId, }: IEncryptDataForLinkedClient): Promise<TEncryptedAesGcmPayload>;
|
|
143
|
-
decryptDataFromLinkedClient({ dataToDecrypt, linkedClientId, }: IDecryptDataFromLinkedClient): Promise<string>;
|
|
144
|
-
/**
|
|
145
|
-
* Bytes counterpart of {@link encryptDataForLinkedClient} — encrypts raw bytes with the shared
|
|
146
|
-
* AES-GCM key, returning a binary nonce + ciphertext. Use it for binary channels (e.g. msgpack
|
|
147
|
-
* WebSocket frames) to avoid base64 inflation.
|
|
148
|
-
*/
|
|
149
|
-
encryptBytesForLinkedClient({ dataToEncrypt, linkedClientId, }: {
|
|
150
|
-
dataToEncrypt: Uint8Array;
|
|
151
|
-
linkedClientId: TTypeAndId;
|
|
152
|
-
}): Promise<TEncryptedAesGcmBytes>;
|
|
153
|
-
/** Bytes counterpart of {@link decryptDataFromLinkedClient}. */
|
|
154
|
-
decryptBytesFromLinkedClient({ dataToDecrypt, linkedClientId, }: {
|
|
155
|
-
dataToDecrypt: TEncryptedAesGcmBytes;
|
|
156
|
-
linkedClientId: TTypeAndId;
|
|
157
|
-
}): Promise<Uint8Array>;
|
|
158
|
-
signAndEncryptDataForLinkedClient({ dataToEncrypt, linkedClientId, }: IEncryptDataForLinkedClient): Promise<{
|
|
159
|
-
encryptedData: TEncryptedAesGcmPayload;
|
|
160
|
-
signatureBase64: string;
|
|
161
|
-
}>;
|
|
162
|
-
/**
|
|
163
|
-
* Decrypts a payload from a linked client and verifies that the decrypted plaintext was signed
|
|
164
|
-
* by that client. Counterpart to {@link signAndEncryptDataForLinkedClient}.
|
|
165
|
-
*
|
|
166
|
-
* Returns the decrypted `data` alongside `isValid` — the caller decides how to handle an invalid
|
|
167
|
-
* signature. (A tampered ciphertext fails earlier at AES-GCM decryption.)
|
|
168
|
-
*/
|
|
169
|
-
decryptAndVerifyDataFromLinkedClient({ dataToDecrypt, linkedClientId, signatureBase64, }: IDecryptAndVerifyDataFromLinkedClient): Promise<{
|
|
170
|
-
data: string;
|
|
171
|
-
isValid: boolean;
|
|
172
|
-
}>;
|
|
173
|
-
signChallenge(challenge: [string, ...string[]]): Promise<{
|
|
174
|
-
signatureBase64: string;
|
|
175
|
-
}>;
|
|
176
|
-
/**
|
|
177
|
-
* Verifies a signature over `challenge` against the linked client's verify (Ed25519) public key.
|
|
178
|
-
*/
|
|
179
|
-
verifyChallengeFromLinkedClient({ linkedClientId, challenge, signatureBase64, }: IVerifyChallengeFromLinkedClient): Promise<boolean>;
|
|
180
|
-
}
|
|
181
|
-
export {};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { TSerializedCryptoKeyData_Ed25519_Raw } from "../crypto.schema";
|
|
2
|
-
interface IBuildVerifyKeyBoundInfoString_Input {
|
|
3
|
-
infoString?: string;
|
|
4
|
-
verifyPublicKeys: [TSerializedCryptoKeyData_Ed25519_Raw, TSerializedCryptoKeyData_Ed25519_Raw];
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* The canonical HKDF `info` for a client-to-client shared key that binds both sides' verify
|
|
8
|
-
* public keys into the derivation.
|
|
9
|
-
*
|
|
10
|
-
* When the two keys are relayed through an intermediary, a tampered key produces mismatched AES
|
|
11
|
-
* keys on the two sides — the very first decryption fails, so key substitution is detected without
|
|
12
|
-
* any extra signature ceremony.
|
|
13
|
-
*
|
|
14
|
-
* The keys are sorted lexicographically so the result is independent of which side is "local" —
|
|
15
|
-
* both ends of a link compute the identical string without coordinating an order. Used internally
|
|
16
|
-
* by ClientCryptoKeyLink (`bindVerifyKeysIntoDerivation`); exported for code that derives the same
|
|
17
|
-
* key outside the link.
|
|
18
|
-
*/
|
|
19
|
-
export declare const buildVerifyKeyBoundInfoString: ({ infoString, verifyPublicKeys, }: IBuildVerifyKeyBoundInfoString_Input) => string;
|
|
20
|
-
export {};
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { type ECryptoKeyAlgo, ECryptoKeyFormat, type ISerializedKeyData_Ed25519_Jwk, type ISerializedKeyData_Ed25519_Raw, type ISerializedKeyData_X25519_Jwk, type ISerializedKeyData_X25519_Raw, type TSerializedCryptoKeyData_Ed25519_Jwk, type TSerializedCryptoKeyData_Ed25519_Jwk_Transformed, type TSerializedCryptoKeyData_Ed25519_Raw, type TSerializedCryptoKeyData_Ed25519_Raw_Transformed, type TSerializedCryptoKeyData_X25519_Jwk, type TSerializedCryptoKeyData_X25519_Jwk_Transformed, type TSerializedCryptoKeyData_X25519_Raw, type TSerializedCryptoKeyData_X25519_Raw_Transformed } from "./crypto.schema";
|
|
2
|
-
/**
|
|
3
|
-
*
|
|
4
|
-
* [CRYPTO ALGO] ED25519
|
|
5
|
-
*
|
|
6
|
-
*/
|
|
7
|
-
export declare const convertEd25519RawDataStringToObject: (inputDataString: `ed25519::raw_base64::${string}`) => {
|
|
8
|
-
formattedString: `ed25519::raw_base64::${string}`;
|
|
9
|
-
type: ECryptoKeyAlgo.ed25519;
|
|
10
|
-
format: ECryptoKeyFormat.raw_base64;
|
|
11
|
-
data: string;
|
|
12
|
-
};
|
|
13
|
-
export declare const convertEd25519JwkDataStringToObject: (inputDataString: `ed25519::jwk::${string}`) => {
|
|
14
|
-
formattedString: `ed25519::jwk::${string}`;
|
|
15
|
-
type: ECryptoKeyAlgo.ed25519;
|
|
16
|
-
format: ECryptoKeyFormat.jwk;
|
|
17
|
-
data: JsonWebKey;
|
|
18
|
-
};
|
|
19
|
-
export declare const convertEd25519FormattedStringToObject: (inputDataString: `ed25519::raw_base64::${string}` | `ed25519::jwk::${string}`) => {
|
|
20
|
-
formattedString: `ed25519::raw_base64::${string}` | `ed25519::jwk::${string}`;
|
|
21
|
-
type: ECryptoKeyAlgo.ed25519;
|
|
22
|
-
format: ECryptoKeyFormat;
|
|
23
|
-
data: string;
|
|
24
|
-
};
|
|
25
|
-
export declare const convertEd25519RawDataStringToSerializedKeyData: (input: TSerializedCryptoKeyData_Ed25519_Raw) => ISerializedKeyData_Ed25519_Raw;
|
|
26
|
-
export declare const convertEd25519JwkDataStringToSerializedKeyData: (input: TSerializedCryptoKeyData_Ed25519_Jwk) => ISerializedKeyData_Ed25519_Jwk;
|
|
27
|
-
export declare const convertEd25519FormattedStringToSerializedKeyData: <I extends TSerializedCryptoKeyData_Ed25519_Raw | TSerializedCryptoKeyData_Ed25519_Jwk, O extends I extends TSerializedCryptoKeyData_Ed25519_Raw ? TSerializedCryptoKeyData_Ed25519_Raw_Transformed : TSerializedCryptoKeyData_Ed25519_Jwk_Transformed>(input: I) => O;
|
|
28
|
-
/**
|
|
29
|
-
*
|
|
30
|
-
* [CRYPTO ALGO] X25519
|
|
31
|
-
*
|
|
32
|
-
*/
|
|
33
|
-
export declare const convertX25519RawDataStringToObject: (inputDataString: `x25519::raw_base64::${string}`) => {
|
|
34
|
-
formattedString: `x25519::raw_base64::${string}`;
|
|
35
|
-
type: ECryptoKeyAlgo.x25519;
|
|
36
|
-
format: ECryptoKeyFormat.raw_base64;
|
|
37
|
-
data: string;
|
|
38
|
-
};
|
|
39
|
-
export declare const convertX25519JwkDataStringToObject: (inputDataString: `x25519::jwk::${string}`) => {
|
|
40
|
-
formattedString: `x25519::jwk::${string}`;
|
|
41
|
-
type: ECryptoKeyAlgo.x25519;
|
|
42
|
-
format: ECryptoKeyFormat.jwk;
|
|
43
|
-
data: JsonWebKey;
|
|
44
|
-
};
|
|
45
|
-
export declare const convertX25519FormattedStringToObject: (inputDataString: `x25519::raw_base64::${string}` | `x25519::jwk::${string}`) => {
|
|
46
|
-
formattedString: `x25519::raw_base64::${string}` | `x25519::jwk::${string}`;
|
|
47
|
-
type: ECryptoKeyAlgo.x25519;
|
|
48
|
-
format: ECryptoKeyFormat;
|
|
49
|
-
data: string;
|
|
50
|
-
};
|
|
51
|
-
export declare const convertX25519RawDataStringToSerializedKeyData: (input: TSerializedCryptoKeyData_X25519_Raw) => ISerializedKeyData_X25519_Raw;
|
|
52
|
-
export declare const convertX25519JwkDataStringToSerializedKeyData: (input: TSerializedCryptoKeyData_X25519_Jwk) => ISerializedKeyData_X25519_Jwk;
|
|
53
|
-
export declare const convertX25519FormattedStringToSerializedKeyData: <I extends TSerializedCryptoKeyData_X25519_Raw | TSerializedCryptoKeyData_X25519_Jwk, O extends I extends TSerializedCryptoKeyData_X25519_Raw ? TSerializedCryptoKeyData_X25519_Raw_Transformed : TSerializedCryptoKeyData_X25519_Jwk_Transformed>(input: I) => O;
|