@nice-code/util 0.7.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 +9 -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
package/build/index.js
CHANGED
|
@@ -1,1153 +1,1039 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { base64 } from "@scure/base";
|
|
2
|
+
import * as v from "valibot";
|
|
3
|
+
//#region src/data_type/string/nullEmpty.ts
|
|
4
|
+
const notNullEmpty = (str) => {
|
|
5
|
+
return str != null && str.length > 0;
|
|
4
6
|
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region src/crypto/x25519/createSharedBitsFromX25519.ts
|
|
9
|
+
const createSharedBitsFromX25519 = async ({ privateKey, publicKey }) => {
|
|
10
|
+
return new Uint8Array(await crypto.subtle.deriveBits({
|
|
11
|
+
name: "X25519",
|
|
12
|
+
public: publicKey
|
|
13
|
+
}, privateKey, 256));
|
|
12
14
|
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
hash: "SHA-256",
|
|
34
|
-
salt,
|
|
35
|
-
info
|
|
36
|
-
}, ikm, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]);
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/crypto/aes_gcm/createAesGcmKeyFromX25519Keys.ts
|
|
17
|
+
const DEFAULT_INFO_STRING = "METEOR_BRIDGE_DEFAULT_INFO_STRING";
|
|
18
|
+
const createAesGcmKeyFromX25519Keys = async ({ externalX25519PublicKey, internalX25519PrivateKey, infoString, saltString }) => {
|
|
19
|
+
const sharedBits = await createSharedBitsFromX25519({
|
|
20
|
+
privateKey: internalX25519PrivateKey,
|
|
21
|
+
publicKey: externalX25519PublicKey
|
|
22
|
+
});
|
|
23
|
+
const ikm = await crypto.subtle.importKey("raw", new Uint8Array(sharedBits), "HKDF", false, ["deriveKey"]);
|
|
24
|
+
const salt = notNullEmpty(saltString) ? new TextEncoder().encode(saltString) : new Uint8Array();
|
|
25
|
+
const info = new TextEncoder().encode(notNullEmpty(infoString) ? infoString : DEFAULT_INFO_STRING);
|
|
26
|
+
return await crypto.subtle.deriveKey({
|
|
27
|
+
name: "HKDF",
|
|
28
|
+
hash: "SHA-256",
|
|
29
|
+
salt,
|
|
30
|
+
info
|
|
31
|
+
}, ikm, {
|
|
32
|
+
name: "AES-GCM",
|
|
33
|
+
length: 256
|
|
34
|
+
}, false, ["encrypt", "decrypt"]);
|
|
37
35
|
};
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/crypto/aes_gcm/decryptBytesWithAesGcmKey.ts
|
|
38
|
+
/**
|
|
39
|
+
* Decrypts a raw-bytes AES-GCM payload (binary nonce + ciphertext) back to bytes. The counterpart of
|
|
40
|
+
* {@link decryptTextDataWithAesGcmKey}. AES-GCM verifies integrity, so a tampered ciphertext throws.
|
|
41
|
+
*/
|
|
42
|
+
const decryptBytesWithAesGcmKey = async ({ aesGcmKey, dataToDecrypt }) => {
|
|
43
|
+
const decryptedData = await crypto.subtle.decrypt({
|
|
44
|
+
name: "AES-GCM",
|
|
45
|
+
iv: new Uint8Array(dataToDecrypt.nonce)
|
|
46
|
+
}, aesGcmKey, new Uint8Array(dataToDecrypt.ciphertext));
|
|
47
|
+
return new Uint8Array(decryptedData);
|
|
45
48
|
};
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
iv: new Uint8Array(base64.decode(dataToDecrypt.nonce))
|
|
55
|
-
}, aesGcmKey, new Uint8Array(base64.decode(dataToDecrypt.ciphertext)));
|
|
56
|
-
return new TextDecoder().decode(decryptedData);
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/crypto/aes_gcm/decryptTextDataWithAesGcmKey.ts
|
|
51
|
+
const decryptTextDataWithAesGcmKey = async ({ aesGcmKey, dataToDecrypt }) => {
|
|
52
|
+
const decryptedData = await crypto.subtle.decrypt({
|
|
53
|
+
name: "AES-GCM",
|
|
54
|
+
iv: new Uint8Array(base64.decode(dataToDecrypt.nonce))
|
|
55
|
+
}, aesGcmKey, new Uint8Array(base64.decode(dataToDecrypt.ciphertext)));
|
|
56
|
+
return new TextDecoder().decode(decryptedData);
|
|
57
57
|
};
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region src/crypto/aes_gcm/encryptBytesWithAesGcmKey.ts
|
|
60
|
+
/**
|
|
61
|
+
* Encrypts raw bytes with an AES-GCM key, returning the binary nonce + ciphertext. The bytes
|
|
62
|
+
* counterpart of {@link encryptTextDataWithAesGcmKey} — use it for binary channels (msgpack frames)
|
|
63
|
+
* to avoid base64 inflation. A fresh 12-byte nonce is generated per call (never reuse a nonce).
|
|
64
|
+
*/
|
|
65
|
+
const encryptBytesWithAesGcmKey = async ({ aesGcmKey, dataToEncrypt }) => {
|
|
66
|
+
const nonce = crypto.getRandomValues(new Uint8Array(12));
|
|
67
|
+
const encryptedData = await crypto.subtle.encrypt({
|
|
68
|
+
name: "AES-GCM",
|
|
69
|
+
iv: nonce
|
|
70
|
+
}, aesGcmKey, new Uint8Array(dataToEncrypt));
|
|
71
|
+
return {
|
|
72
|
+
nonce,
|
|
73
|
+
ciphertext: new Uint8Array(encryptedData)
|
|
74
|
+
};
|
|
66
75
|
};
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
nonce: base642.encode(nonce),
|
|
80
|
-
ciphertext: base642.encode(new Uint8Array(encryptedData))
|
|
81
|
-
};
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/crypto/aes_gcm/encryptTextDataWithAesGcmKey.ts
|
|
78
|
+
const encryptTextDataWithAesGcmKey = async ({ aesGcmKey, dataToEncrypt }) => {
|
|
79
|
+
const nonce = crypto.getRandomValues(new Uint8Array(12));
|
|
80
|
+
const encryptedData = await crypto.subtle.encrypt({
|
|
81
|
+
name: "AES-GCM",
|
|
82
|
+
iv: nonce
|
|
83
|
+
}, aesGcmKey, new TextEncoder().encode(dataToEncrypt));
|
|
84
|
+
return {
|
|
85
|
+
nonce: base64.encode(nonce),
|
|
86
|
+
ciphertext: base64.encode(new Uint8Array(encryptedData))
|
|
87
|
+
};
|
|
82
88
|
};
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return new Uint8Array(signature);
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/crypto/ed25519/signTextDataWithKeyEd25519.ts
|
|
91
|
+
const signTextDataWithKeyEd25519 = async (data, cryptoKey) => {
|
|
92
|
+
const dataBuffer = new TextEncoder().encode(data);
|
|
93
|
+
const signature = await crypto.subtle.sign({ name: "ED25519" }, cryptoKey, dataBuffer);
|
|
94
|
+
return new Uint8Array(signature);
|
|
90
95
|
};
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/crypto/ed25519/signCombinedTextDataWithKeyEd25519.ts
|
|
98
|
+
const DEFAULT_COMBINED_TEXT_DATA_SEPARATOR = "::";
|
|
99
|
+
const signCombinedTextDataWithKeyEd25519 = async (data, cryptoKey, separator = "::") => {
|
|
100
|
+
return await signTextDataWithKeyEd25519(data.join(separator), cryptoKey);
|
|
96
101
|
};
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/crypto/client_key_link/buildVerifyKeyBoundInfoString.ts
|
|
104
|
+
/**
|
|
105
|
+
* The canonical HKDF `info` for a client-to-client shared key that binds both sides' verify
|
|
106
|
+
* public keys into the derivation.
|
|
107
|
+
*
|
|
108
|
+
* When the two keys are relayed through an intermediary, a tampered key produces mismatched AES
|
|
109
|
+
* keys on the two sides — the very first decryption fails, so key substitution is detected without
|
|
110
|
+
* any extra signature ceremony.
|
|
111
|
+
*
|
|
112
|
+
* The keys are sorted lexicographically so the result is independent of which side is "local" —
|
|
113
|
+
* both ends of a link compute the identical string without coordinating an order. Used internally
|
|
114
|
+
* by ClientCryptoKeyLink (`bindVerifyKeysIntoDerivation`); exported for code that derives the same
|
|
115
|
+
* key outside the link.
|
|
116
|
+
*/
|
|
117
|
+
const buildVerifyKeyBoundInfoString = ({ infoString, verifyPublicKeys }) => {
|
|
118
|
+
const sortedKeys = [...verifyPublicKeys].sort();
|
|
119
|
+
return [...infoString != null ? [infoString] : [], ...sortedKeys].join("::");
|
|
105
120
|
};
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
clearAll: async () => {
|
|
139
|
-
await storageAdapter.clearAll();
|
|
140
|
-
}
|
|
141
|
-
};
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/storage_adapter/typed_storage/createTypedStorage.ts
|
|
123
|
+
function createTypedStorage({ storageAdapter }) {
|
|
124
|
+
const getJson = async (key) => {
|
|
125
|
+
return storageAdapter.getJson(key);
|
|
126
|
+
};
|
|
127
|
+
const getJsonOrDef = async (key, defVal) => {
|
|
128
|
+
return await storageAdapter.getJson(key) ?? defVal;
|
|
129
|
+
};
|
|
130
|
+
const setJson = async (key, val) => {
|
|
131
|
+
return storageAdapter.setJson(key, val);
|
|
132
|
+
};
|
|
133
|
+
const removeItem = async (key) => {
|
|
134
|
+
await storageAdapter.removeItem(key);
|
|
135
|
+
};
|
|
136
|
+
const updateJson = async (key, updater) => {
|
|
137
|
+
await storageAdapter.updateJson(key, updater);
|
|
138
|
+
};
|
|
139
|
+
const updateJsonWithDef = async (key, defaultVal, updater) => {
|
|
140
|
+
await storageAdapter.updateJsonOrDef(key, defaultVal, updater);
|
|
141
|
+
};
|
|
142
|
+
return {
|
|
143
|
+
getJson,
|
|
144
|
+
getJsonOrDef,
|
|
145
|
+
setJson,
|
|
146
|
+
removeItem,
|
|
147
|
+
updateJson,
|
|
148
|
+
updateJsonWithDef,
|
|
149
|
+
clearAll: async () => {
|
|
150
|
+
await storageAdapter.clearAll();
|
|
151
|
+
}
|
|
152
|
+
};
|
|
142
153
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
"sign",
|
|
148
|
-
"verify"
|
|
149
|
-
]);
|
|
150
|
-
return keyPair;
|
|
154
|
+
//#endregion
|
|
155
|
+
//#region src/crypto/ed25519/generateEd25519KeyPair.ts
|
|
156
|
+
const generateEd25519KeyPair = async () => {
|
|
157
|
+
return await crypto.subtle.generateKey({ name: "Ed25519" }, true, ["sign", "verify"]);
|
|
151
158
|
};
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
return {
|
|
173
|
-
formattedString: inputDataString,
|
|
174
|
-
type,
|
|
175
|
-
format,
|
|
176
|
-
data: parsedData
|
|
177
|
-
};
|
|
159
|
+
//#endregion
|
|
160
|
+
//#region src/core/createDataStringConverter_stringToObject.ts
|
|
161
|
+
const createDataStringConverter_stringToObject = ({ transformJsonForFormats = [], transformJson = false } = {}) => (inputDataString) => {
|
|
162
|
+
const [type, format, dataString] = inputDataString.split("::");
|
|
163
|
+
let parsedData = dataString;
|
|
164
|
+
if (transformJson || transformJsonForFormats.includes(format)) try {
|
|
165
|
+
parsedData = JSON.parse(dataString);
|
|
166
|
+
} catch (error) {
|
|
167
|
+
const err = /* @__PURE__ */ new Error(`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)}`);
|
|
168
|
+
err.cause = error;
|
|
169
|
+
throw err;
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
formattedString: inputDataString,
|
|
173
|
+
type,
|
|
174
|
+
format,
|
|
175
|
+
data: parsedData
|
|
176
|
+
};
|
|
178
177
|
};
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
formatKind
|
|
191
|
-
}) => {
|
|
192
|
-
const _typeKind = typeKind ?? "data_type";
|
|
193
|
-
const _formatKind = formatKind ?? "data_format";
|
|
194
|
-
return v.pipe(v.custom((input) => {
|
|
195
|
-
if (typeof input !== "string")
|
|
196
|
-
return false;
|
|
197
|
-
const [typePart, formatPart, dataPart] = input.split("::");
|
|
198
|
-
return typePart === type && formatPart === format && typeof dataPart === "string";
|
|
199
|
-
}, `Invalid format, expected '<${_typeKind}>::<${_formatKind}>::<value>' where "${_typeKind}" is "${type}", "${_formatKind}" is "${format}", and "value" is a string in the specified format`));
|
|
178
|
+
//#endregion
|
|
179
|
+
//#region src/core/core_valibot_schemas.ts
|
|
180
|
+
const vBase64 = v.pipe(v.string(), v.base64());
|
|
181
|
+
const vCreateSchema_TypeAndFormatPrefixedDataString = ({ type, format, typeKind, formatKind }) => {
|
|
182
|
+
const _typeKind = typeKind ?? "data_type";
|
|
183
|
+
const _formatKind = formatKind ?? "data_format";
|
|
184
|
+
return v.pipe(v.custom((input) => {
|
|
185
|
+
if (typeof input !== "string") return false;
|
|
186
|
+
const [typePart, formatPart, dataPart] = input.split("::");
|
|
187
|
+
return typePart === type && formatPart === format && typeof dataPart === "string";
|
|
188
|
+
}, `Invalid format, expected '<${_typeKind}>::<${_formatKind}>::<value>' where "${_typeKind}" is "${type}", "${_formatKind}" is "${format}", and "value" is a string in the specified format`));
|
|
200
189
|
};
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
190
|
+
//#endregion
|
|
191
|
+
//#region src/crypto/crypto.schema.ts
|
|
192
|
+
let ECryptoKeyAlgo = /* @__PURE__ */ function(ECryptoKeyAlgo) {
|
|
193
|
+
ECryptoKeyAlgo["ed25519"] = "ed25519";
|
|
194
|
+
ECryptoKeyAlgo["x25519"] = "x25519";
|
|
195
|
+
return ECryptoKeyAlgo;
|
|
196
|
+
}({});
|
|
197
|
+
let ECryptoKeyFormat = /* @__PURE__ */ function(ECryptoKeyFormat) {
|
|
198
|
+
ECryptoKeyFormat["raw_base64"] = "raw_base64";
|
|
199
|
+
ECryptoKeyFormat["jwk"] = "jwk";
|
|
200
|
+
return ECryptoKeyFormat;
|
|
201
|
+
}({});
|
|
202
|
+
const vSerializedCryptoKeyDataEd25519_Raw = vCreateSchema_TypeAndFormatPrefixedDataString({
|
|
203
|
+
format: "raw_base64",
|
|
204
|
+
type: "ed25519",
|
|
205
|
+
typeKind: "algo"
|
|
217
206
|
});
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
207
|
+
const vSerializedCryptoKeyDataEd25519_Jwk = vCreateSchema_TypeAndFormatPrefixedDataString({
|
|
208
|
+
format: "jwk",
|
|
209
|
+
type: "ed25519",
|
|
210
|
+
typeKind: "algo",
|
|
211
|
+
transformJson: true
|
|
223
212
|
});
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
213
|
+
const vSerializedCryptoKeyDataX25519_Raw = vCreateSchema_TypeAndFormatPrefixedDataString({
|
|
214
|
+
format: "raw_base64",
|
|
215
|
+
type: "x25519",
|
|
216
|
+
typeKind: "algo"
|
|
228
217
|
});
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
218
|
+
const vSerializedCryptoKeyDataX25519_Jwk = vCreateSchema_TypeAndFormatPrefixedDataString({
|
|
219
|
+
format: "jwk",
|
|
220
|
+
type: "x25519",
|
|
221
|
+
typeKind: "algo",
|
|
222
|
+
transformJson: true
|
|
234
223
|
});
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
224
|
+
const vCryptoKeyPairDataX25519 = v.object({
|
|
225
|
+
publicKey: vSerializedCryptoKeyDataX25519_Raw,
|
|
226
|
+
privateKey: vSerializedCryptoKeyDataX25519_Jwk
|
|
238
227
|
});
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
228
|
+
const vCryptoKeyPairDataEd25519 = v.object({
|
|
229
|
+
publicKey: vSerializedCryptoKeyDataEd25519_Raw,
|
|
230
|
+
privateKey: vSerializedCryptoKeyDataEd25519_Jwk
|
|
242
231
|
});
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
232
|
+
const vVerifyChallengeWithSignature_Input = v.object({
|
|
233
|
+
challenge: v.string(),
|
|
234
|
+
signatureBase64: vBase64
|
|
246
235
|
});
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
})
|
|
252
|
-
]);
|
|
253
|
-
var vEncryptedAesGcmPayload = v2.object({
|
|
254
|
-
nonce: vBase64,
|
|
255
|
-
ciphertext: vBase64
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
// src/crypto/crypto.converters.ts
|
|
259
|
-
var convertEd25519RawDataStringToObject = createDataStringConverter_stringToObject();
|
|
260
|
-
var convertEd25519JwkDataStringToObject = createDataStringConverter_stringToObject({ transformJson: true });
|
|
261
|
-
var convertEd25519FormattedStringToObject = createDataStringConverter_stringToObject({
|
|
262
|
-
transformJsonForFormats: ["jwk" /* jwk */]
|
|
236
|
+
const vVerifyChallengeWithSignature_WithThrow_Input = v.intersect([vVerifyChallengeWithSignature_Input, v.object({ throwOnInvalid: v.optional(v.boolean()) })]);
|
|
237
|
+
const vEncryptedAesGcmPayload = v.object({
|
|
238
|
+
nonce: vBase64,
|
|
239
|
+
ciphertext: vBase64
|
|
263
240
|
});
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
241
|
+
//#endregion
|
|
242
|
+
//#region src/crypto/crypto.converters.ts
|
|
243
|
+
/**
|
|
244
|
+
*
|
|
245
|
+
* [CRYPTO ALGO] ED25519
|
|
246
|
+
*
|
|
247
|
+
*/
|
|
248
|
+
const convertEd25519RawDataStringToObject = createDataStringConverter_stringToObject();
|
|
249
|
+
const convertEd25519JwkDataStringToObject = createDataStringConverter_stringToObject({ transformJson: true });
|
|
250
|
+
const convertEd25519FormattedStringToObject = createDataStringConverter_stringToObject({ transformJsonForFormats: ["jwk"] });
|
|
251
|
+
const convertEd25519RawDataStringToSerializedKeyData = (input) => {
|
|
252
|
+
return {
|
|
253
|
+
prefixed: input,
|
|
254
|
+
transformed: convertEd25519RawDataStringToObject(input)
|
|
255
|
+
};
|
|
270
256
|
};
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
};
|
|
257
|
+
const convertEd25519JwkDataStringToSerializedKeyData = (input) => {
|
|
258
|
+
return {
|
|
259
|
+
prefixed: input,
|
|
260
|
+
transformed: convertEd25519JwkDataStringToObject(input)
|
|
261
|
+
};
|
|
277
262
|
};
|
|
278
|
-
|
|
279
|
-
|
|
263
|
+
const convertEd25519FormattedStringToSerializedKeyData = (input) => {
|
|
264
|
+
return convertEd25519FormattedStringToObject(input);
|
|
280
265
|
};
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
266
|
+
/**
|
|
267
|
+
*
|
|
268
|
+
* [CRYPTO ALGO] X25519
|
|
269
|
+
*
|
|
270
|
+
*/
|
|
271
|
+
const convertX25519RawDataStringToObject = createDataStringConverter_stringToObject();
|
|
272
|
+
const convertX25519JwkDataStringToObject = createDataStringConverter_stringToObject({ transformJson: true });
|
|
273
|
+
const convertX25519FormattedStringToObject = createDataStringConverter_stringToObject({ transformJsonForFormats: ["jwk"] });
|
|
274
|
+
const convertX25519RawDataStringToSerializedKeyData = (input) => {
|
|
275
|
+
return {
|
|
276
|
+
prefixed: input,
|
|
277
|
+
transformed: convertX25519RawDataStringToObject(input)
|
|
278
|
+
};
|
|
292
279
|
};
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
};
|
|
280
|
+
const convertX25519JwkDataStringToSerializedKeyData = (input) => {
|
|
281
|
+
return {
|
|
282
|
+
prefixed: input,
|
|
283
|
+
transformed: convertX25519JwkDataStringToObject(input)
|
|
284
|
+
};
|
|
299
285
|
};
|
|
300
|
-
|
|
301
|
-
|
|
286
|
+
const convertX25519FormattedStringToSerializedKeyData = (input) => {
|
|
287
|
+
return convertX25519FormattedStringToObject(input);
|
|
302
288
|
};
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
289
|
+
//#endregion
|
|
290
|
+
//#region src/crypto/ed25519/importEd25519Key.ts
|
|
291
|
+
const fromBase64$1 = async (dataBase64, keyUsage, extractable) => {
|
|
292
|
+
const keyBuffer = Uint8Array.from(base64.decode(dataBase64));
|
|
293
|
+
return await crypto.subtle.importKey("raw", keyBuffer, { name: "Ed25519" }, extractable, keyUsage);
|
|
308
294
|
};
|
|
309
|
-
|
|
310
|
-
|
|
295
|
+
const fromJwk$1 = async (jwk, keyUsage, extractable = true) => {
|
|
296
|
+
return await crypto.subtle.importKey("jwk", jwk, { name: "Ed25519" }, extractable, keyUsage);
|
|
311
297
|
};
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
}
|
|
316
|
-
return await fromBase64(serialized.data, keyUsage, extractable);
|
|
298
|
+
const fromSerializedObject$1 = async (serialized, keyUsage, extractable = true) => {
|
|
299
|
+
if (serialized.format === "jwk") return await fromJwk$1(serialized.data, keyUsage, extractable);
|
|
300
|
+
return await fromBase64$1(serialized.data, keyUsage, extractable);
|
|
317
301
|
};
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
return await fromSerializedObject(transformed, keyUsage, extractable);
|
|
302
|
+
const fromFormattedString$1 = async (dataString, keyUsage, extractable = true) => {
|
|
303
|
+
return await fromSerializedObject$1(convertEd25519FormattedStringToSerializedKeyData(dataString), keyUsage, extractable);
|
|
321
304
|
};
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
305
|
+
const extractableOrNonExtractable$1 = (keyUsage, func) => ({
|
|
306
|
+
extractable: (input) => func(input, keyUsage, true),
|
|
307
|
+
nonExtractable: (input) => func(input, keyUsage, false)
|
|
325
308
|
});
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
309
|
+
const importEd25519Key = {
|
|
310
|
+
private: {
|
|
311
|
+
fromFormattedString: extractableOrNonExtractable$1(["sign"], fromFormattedString$1),
|
|
312
|
+
fromSerializedObject: extractableOrNonExtractable$1(["sign"], fromSerializedObject$1),
|
|
313
|
+
fromJwk: extractableOrNonExtractable$1(["sign"], fromJwk$1)
|
|
314
|
+
},
|
|
315
|
+
public: {
|
|
316
|
+
fromBase64: extractableOrNonExtractable$1(["verify"], fromBase64$1),
|
|
317
|
+
fromFormattedString: extractableOrNonExtractable$1(["verify"], fromFormattedString$1),
|
|
318
|
+
fromSerializedObject: extractableOrNonExtractable$1(["verify"], fromSerializedObject$1),
|
|
319
|
+
fromJwk: extractableOrNonExtractable$1(["verify"], fromJwk$1)
|
|
320
|
+
}
|
|
338
321
|
};
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
322
|
+
//#endregion
|
|
323
|
+
//#region src/crypto/ed25519/serializeEd25519Key_Jwk.ts
|
|
324
|
+
const serializeEd25519Key_Jwk = async (key) => {
|
|
325
|
+
const keyJwk = await crypto.subtle.exportKey("jwk", key);
|
|
326
|
+
const prefixed = `ed25519::jwk::${JSON.stringify(keyJwk)}`;
|
|
327
|
+
return {
|
|
328
|
+
transformed: {
|
|
329
|
+
formattedString: prefixed,
|
|
330
|
+
type: "ed25519",
|
|
331
|
+
data: keyJwk,
|
|
332
|
+
format: "jwk"
|
|
333
|
+
},
|
|
334
|
+
prefixed
|
|
335
|
+
};
|
|
351
336
|
};
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
337
|
+
//#endregion
|
|
338
|
+
//#region src/crypto/ed25519/serializeEd25519Key_Raw.ts
|
|
339
|
+
const serializeEd25519Key_Raw = async (publicKey) => {
|
|
340
|
+
const publicKeyBuffer = await crypto.subtle.exportKey("raw", publicKey);
|
|
341
|
+
const publicKeyBase64 = base64.encode(new Uint8Array(publicKeyBuffer));
|
|
342
|
+
const prefixed = `ed25519::raw_base64::${publicKeyBase64}`;
|
|
343
|
+
return {
|
|
344
|
+
transformed: {
|
|
345
|
+
formattedString: prefixed,
|
|
346
|
+
type: "ed25519",
|
|
347
|
+
data: publicKeyBase64,
|
|
348
|
+
format: "raw_base64"
|
|
349
|
+
},
|
|
350
|
+
prefixed
|
|
351
|
+
};
|
|
366
352
|
};
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
publicKey
|
|
374
|
-
}) => {
|
|
375
|
-
const signatureBuffer = Uint8Array.from(base646.decode(signatureBase64));
|
|
376
|
-
const challengeBuffer = new TextEncoder().encode(challenge);
|
|
377
|
-
return await crypto.subtle.verify({
|
|
378
|
-
name: "ED25519"
|
|
379
|
-
}, publicKey, signatureBuffer, challengeBuffer);
|
|
353
|
+
//#endregion
|
|
354
|
+
//#region src/crypto/ed25519/verifyWithKeyEd25519.ts
|
|
355
|
+
const verifyWithKeyEd25519 = async ({ challenge, signatureBase64, publicKey }) => {
|
|
356
|
+
const signatureBuffer = Uint8Array.from(base64.decode(signatureBase64));
|
|
357
|
+
const challengeBuffer = new TextEncoder().encode(challenge);
|
|
358
|
+
return await crypto.subtle.verify({ name: "ED25519" }, publicKey, signatureBuffer, challengeBuffer);
|
|
380
359
|
};
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
"deriveKey",
|
|
386
|
-
"deriveBits"
|
|
387
|
-
]);
|
|
388
|
-
return keyPair;
|
|
360
|
+
//#endregion
|
|
361
|
+
//#region src/crypto/x25519/generateX25519KeyPair.ts
|
|
362
|
+
const generateX25519KeyPair = async () => {
|
|
363
|
+
return await crypto.subtle.generateKey({ name: "X25519" }, true, ["deriveKey", "deriveBits"]);
|
|
389
364
|
};
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
return await crypto.subtle.importKey("raw", keyBuffer, { name: "X25519" }, extractable, keyUsage);
|
|
365
|
+
//#endregion
|
|
366
|
+
//#region src/crypto/x25519/importX25519Key.ts
|
|
367
|
+
const fromBase64 = async (dataBase64, keyUsage, extractable) => {
|
|
368
|
+
const keyBuffer = Uint8Array.from(base64.decode(dataBase64));
|
|
369
|
+
return await crypto.subtle.importKey("raw", keyBuffer, { name: "X25519" }, extractable, keyUsage);
|
|
396
370
|
};
|
|
397
|
-
|
|
398
|
-
|
|
371
|
+
const fromJwk = async (jwk, keyUsage, extractable = true) => {
|
|
372
|
+
return await crypto.subtle.importKey("jwk", jwk, { name: "X25519" }, extractable, keyUsage);
|
|
399
373
|
};
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
}
|
|
404
|
-
return await fromBase642(serialized.data, keyUsage, extractable);
|
|
374
|
+
const fromSerializedObject = async (serialized, keyUsage, extractable = true) => {
|
|
375
|
+
if (serialized.format === "jwk") return await fromJwk(serialized.data, keyUsage, extractable);
|
|
376
|
+
return await fromBase64(serialized.data, keyUsage, extractable);
|
|
405
377
|
};
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
return await fromSerializedObject2(transformed, keyUsage, extractable);
|
|
378
|
+
const fromFormattedString = async (dataString, keyUsage, extractable = true) => {
|
|
379
|
+
return await fromSerializedObject(convertX25519FormattedStringToSerializedKeyData(dataString), keyUsage, extractable);
|
|
409
380
|
};
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
381
|
+
const extractableOrNonExtractable = (keyUsage, func) => ({
|
|
382
|
+
extractable: (input) => func(input, keyUsage, true),
|
|
383
|
+
nonExtractable: (input) => func(input, keyUsage, false)
|
|
413
384
|
});
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
385
|
+
const importX25519Key = {
|
|
386
|
+
private: {
|
|
387
|
+
fromFormattedString: extractableOrNonExtractable(["deriveKey", "deriveBits"], fromFormattedString),
|
|
388
|
+
fromSerializedObject: extractableOrNonExtractable(["deriveKey", "deriveBits"], fromSerializedObject),
|
|
389
|
+
fromJwk: extractableOrNonExtractable(["deriveKey", "deriveBits"], fromJwk)
|
|
390
|
+
},
|
|
391
|
+
public: {
|
|
392
|
+
fromBase64: extractableOrNonExtractable([], fromBase64),
|
|
393
|
+
fromFormattedString: extractableOrNonExtractable([], fromFormattedString),
|
|
394
|
+
fromSerializedObject: extractableOrNonExtractable([], fromSerializedObject),
|
|
395
|
+
fromJwk: extractableOrNonExtractable([], fromJwk)
|
|
396
|
+
}
|
|
426
397
|
};
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
398
|
+
//#endregion
|
|
399
|
+
//#region src/crypto/x25519/serializeX25519Key_Jwk.ts
|
|
400
|
+
const serializeX25519Key_Jwk = async (key) => {
|
|
401
|
+
const publicKeyJwk = await crypto.subtle.exportKey("jwk", key);
|
|
402
|
+
const prefixed = `x25519::jwk::${JSON.stringify(publicKeyJwk)}`;
|
|
403
|
+
return {
|
|
404
|
+
transformed: {
|
|
405
|
+
formattedString: prefixed,
|
|
406
|
+
type: "x25519",
|
|
407
|
+
data: publicKeyJwk,
|
|
408
|
+
format: "jwk"
|
|
409
|
+
},
|
|
410
|
+
prefixed
|
|
411
|
+
};
|
|
439
412
|
};
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
413
|
+
//#endregion
|
|
414
|
+
//#region src/crypto/x25519/serializeX25519Key_Raw.ts
|
|
415
|
+
const serializeX25519Key_Raw = async (key) => {
|
|
416
|
+
const publicKeyBuffer = await crypto.subtle.exportKey("raw", key);
|
|
417
|
+
const publicKeyBase64 = base64.encode(new Uint8Array(publicKeyBuffer));
|
|
418
|
+
const prefixed = `x25519::raw_base64::${publicKeyBase64}`;
|
|
419
|
+
return {
|
|
420
|
+
transformed: {
|
|
421
|
+
formattedString: prefixed,
|
|
422
|
+
type: "x25519",
|
|
423
|
+
data: publicKeyBase64,
|
|
424
|
+
format: "raw_base64"
|
|
425
|
+
},
|
|
426
|
+
prefixed
|
|
427
|
+
};
|
|
454
428
|
};
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
const newVal = updater(currentVal);
|
|
926
|
-
await this.setJson(rawKey, newVal);
|
|
927
|
-
return newVal;
|
|
928
|
-
}
|
|
929
|
-
createJsonGetterSetter(rawKey) {
|
|
930
|
-
return {
|
|
931
|
-
get: () => this.getJson(rawKey),
|
|
932
|
-
set: (value) => this.setJson(rawKey, value)
|
|
933
|
-
};
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
// src/storage_adapter/specific/browser/browser_storage.ts
|
|
429
|
+
//#endregion
|
|
430
|
+
//#region src/crypto/client_key_link/ClientCryptoKeyLink.ts
|
|
431
|
+
var ClientCryptoKeyLink = class {
|
|
432
|
+
localExchangeKeyPair;
|
|
433
|
+
localVerifyKeyPair;
|
|
434
|
+
linkedClientKeys = /* @__PURE__ */ new Map();
|
|
435
|
+
storage;
|
|
436
|
+
initialized = false;
|
|
437
|
+
initializePromise;
|
|
438
|
+
localExchangeKeyPairPromise;
|
|
439
|
+
localVerifyKeyPairPromise;
|
|
440
|
+
constructor({ storageAdapter } = {}) {
|
|
441
|
+
if (storageAdapter != null) this.storage = createTypedStorage({ storageAdapter });
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Loads the local key pairs and any linked client public keys from storage (when a storage
|
|
445
|
+
* adapter was provided), generating and persisting fresh local key pairs if none exist yet.
|
|
446
|
+
*
|
|
447
|
+
* Must be called (and awaited) before any sign/verify/encrypt/decrypt operation.
|
|
448
|
+
*/
|
|
449
|
+
async initialize() {
|
|
450
|
+
if (this.initialized) return;
|
|
451
|
+
this.initializePromise ??= this.runInitialize();
|
|
452
|
+
try {
|
|
453
|
+
await this.initializePromise;
|
|
454
|
+
} finally {
|
|
455
|
+
this.initializePromise = void 0;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
async runInitialize() {
|
|
459
|
+
await this.loadStoredLocalKeys();
|
|
460
|
+
await this.loadLinkedClients();
|
|
461
|
+
this.initialized = true;
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Loads the local key pairs from storage if they were previously persisted. Does NOT generate
|
|
465
|
+
* fresh keys — local identity is created lazily on first use (see {@link ensureLocalExchangeKeyPair}
|
|
466
|
+
* / {@link ensureLocalVerifyKeyPair}), so a verify-only or otherwise key-less consumer never
|
|
467
|
+
* generates or stores keys it does not need.
|
|
468
|
+
*/
|
|
469
|
+
async loadStoredLocalKeys() {
|
|
470
|
+
const storedExchange = await this.storage?.getJson("localExchangeKeyPair");
|
|
471
|
+
if (storedExchange != null) this.localExchangeKeyPair = {
|
|
472
|
+
privateKey: await importX25519Key.private.fromFormattedString.extractable(storedExchange.privateKey),
|
|
473
|
+
publicKey: await importX25519Key.public.fromFormattedString.extractable(storedExchange.publicKey)
|
|
474
|
+
};
|
|
475
|
+
const storedVerify = await this.storage?.getJson("localVerifyKeyPair");
|
|
476
|
+
if (storedVerify != null) this.localVerifyKeyPair = {
|
|
477
|
+
privateKey: await importEd25519Key.private.fromFormattedString.extractable(storedVerify.privateKey),
|
|
478
|
+
publicKey: await importEd25519Key.public.fromFormattedString.extractable(storedVerify.publicKey)
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Returns the local exchange (X25519) key pair, generating and persisting it on first use.
|
|
483
|
+
* Concurrent callers share a single generation.
|
|
484
|
+
*/
|
|
485
|
+
async ensureLocalExchangeKeyPair() {
|
|
486
|
+
if (this.localExchangeKeyPair != null) return this.localExchangeKeyPair;
|
|
487
|
+
this.localExchangeKeyPairPromise ??= (async () => {
|
|
488
|
+
const keyPair = await generateX25519KeyPair();
|
|
489
|
+
this.localExchangeKeyPair = keyPair;
|
|
490
|
+
if (this.storage != null) await this.storage.setJson("localExchangeKeyPair", await this.serializeExchangeKeyPair(keyPair));
|
|
491
|
+
return keyPair;
|
|
492
|
+
})();
|
|
493
|
+
try {
|
|
494
|
+
return await this.localExchangeKeyPairPromise;
|
|
495
|
+
} finally {
|
|
496
|
+
this.localExchangeKeyPairPromise = void 0;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Returns the local verify (Ed25519) key pair, generating and persisting it on first use.
|
|
501
|
+
* Concurrent callers share a single generation.
|
|
502
|
+
*/
|
|
503
|
+
async ensureLocalVerifyKeyPair() {
|
|
504
|
+
if (this.localVerifyKeyPair != null) return this.localVerifyKeyPair;
|
|
505
|
+
this.localVerifyKeyPairPromise ??= (async () => {
|
|
506
|
+
const keyPair = await generateEd25519KeyPair();
|
|
507
|
+
this.localVerifyKeyPair = keyPair;
|
|
508
|
+
if (this.storage != null) await this.storage.setJson("localVerifyKeyPair", await this.serializeVerifyKeyPair(keyPair));
|
|
509
|
+
return keyPair;
|
|
510
|
+
})();
|
|
511
|
+
try {
|
|
512
|
+
return await this.localVerifyKeyPairPromise;
|
|
513
|
+
} finally {
|
|
514
|
+
this.localVerifyKeyPairPromise = void 0;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
async loadLinkedClients() {
|
|
518
|
+
const storedLinkedClients = await this.storage?.getJson("linkedClientPublicKeys");
|
|
519
|
+
if (storedLinkedClients == null) return;
|
|
520
|
+
for (const [linkedClientId, publicKeys] of Object.entries(storedLinkedClients)) await this.linkClient({
|
|
521
|
+
linkedClientId,
|
|
522
|
+
verifyPublicKey: publicKeys.verifyPublicKey,
|
|
523
|
+
exchangePublicKey: publicKeys.exchangePublicKey,
|
|
524
|
+
saltString: publicKeys.saltString,
|
|
525
|
+
infoString: publicKeys.infoString,
|
|
526
|
+
bindVerifyKeysIntoDerivation: publicKeys.bindVerifyKeysIntoDerivation
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
async serializeExchangeKeyPair(keyPair) {
|
|
530
|
+
return {
|
|
531
|
+
publicKey: (await serializeX25519Key_Raw(keyPair.publicKey)).prefixed,
|
|
532
|
+
privateKey: (await serializeX25519Key_Jwk(keyPair.privateKey)).prefixed
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
async serializeVerifyKeyPair(keyPair) {
|
|
536
|
+
return {
|
|
537
|
+
publicKey: (await serializeEd25519Key_Raw(keyPair.publicKey)).prefixed,
|
|
538
|
+
privateKey: (await serializeEd25519Key_Jwk(keyPair.privateKey)).prefixed
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* The local public keys that should be shared with a linked client so that it can verify this
|
|
543
|
+
* client's signatures and derive a shared encryption key. Generates the local identity on first
|
|
544
|
+
* use.
|
|
545
|
+
*/
|
|
546
|
+
async getLocalPublicKeys() {
|
|
547
|
+
return {
|
|
548
|
+
verifyPublicKey: await this.getLocalVerifyPublicKey(),
|
|
549
|
+
exchangePublicKey: await this.getLocalExchangePublicKey()
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* The local exchange (X25519) public key, generating the exchange key pair on first use. Does not
|
|
554
|
+
* touch the verify key pair — useful for an exchange-only consumer (e.g. a bridge) that never
|
|
555
|
+
* signs.
|
|
556
|
+
*/
|
|
557
|
+
async getLocalExchangePublicKey() {
|
|
558
|
+
return (await serializeX25519Key_Raw((await this.ensureLocalExchangeKeyPair()).publicKey)).prefixed;
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* The local verify (Ed25519) public key, generating the verify key pair on first use. Does not
|
|
562
|
+
* touch the exchange key pair.
|
|
563
|
+
*/
|
|
564
|
+
async getLocalVerifyPublicKey() {
|
|
565
|
+
return (await serializeEd25519Key_Raw((await this.ensureLocalVerifyKeyPair()).publicKey)).prefixed;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Registers (or updates) the public keys of a linked client in memory only — nothing is written
|
|
569
|
+
* to storage. Use this for ephemeral links (e.g. a per-session bridge or end-to-end peer keyed by
|
|
570
|
+
* a session salt/info), so the derived shared key never outlives the process.
|
|
571
|
+
*
|
|
572
|
+
* Re-linking with a new exchange public key, salt, or info invalidates any previously cached
|
|
573
|
+
* shared key for the link.
|
|
574
|
+
*/
|
|
575
|
+
async linkClient({ linkedClientId, verifyPublicKey, exchangePublicKey, saltString, infoString, bindVerifyKeysIntoDerivation }) {
|
|
576
|
+
const existing = this.linkedClientKeys.get(linkedClientId);
|
|
577
|
+
const verify = verifyPublicKey != null ? {
|
|
578
|
+
publicKey: await importEd25519Key.public.fromFormattedString.extractable(verifyPublicKey),
|
|
579
|
+
publicKeySerialized: verifyPublicKey
|
|
580
|
+
} : existing?.verify;
|
|
581
|
+
const verifyKeyChanged = verifyPublicKey != null && verifyPublicKey !== existing?.verify?.publicKeySerialized;
|
|
582
|
+
let exchange = existing?.exchange;
|
|
583
|
+
if (exchangePublicKey != null || saltString !== void 0 || infoString !== void 0 || bindVerifyKeysIntoDerivation !== void 0) {
|
|
584
|
+
const nextPublicKeySerialized = exchangePublicKey ?? existing?.exchange?.publicKeySerialized;
|
|
585
|
+
if (nextPublicKeySerialized == null) throw new Error(`ClientCryptoKeyLink: Cannot set salt/info for ${linkedClientId} without an exchange public key`);
|
|
586
|
+
const nextSalt = saltString !== void 0 ? saltString : existing?.exchange?.saltString;
|
|
587
|
+
const nextInfo = infoString !== void 0 ? infoString : existing?.exchange?.infoString;
|
|
588
|
+
const nextBind = bindVerifyKeysIntoDerivation !== void 0 ? bindVerifyKeysIntoDerivation : existing?.exchange?.bindVerifyKeysIntoDerivation;
|
|
589
|
+
exchange = {
|
|
590
|
+
publicKey: exchangePublicKey != null ? await importX25519Key.public.fromFormattedString.extractable(exchangePublicKey) : existing.exchange.publicKey,
|
|
591
|
+
publicKeySerialized: nextPublicKeySerialized,
|
|
592
|
+
saltString: nextSalt,
|
|
593
|
+
infoString: nextInfo,
|
|
594
|
+
bindVerifyKeysIntoDerivation: nextBind,
|
|
595
|
+
sharedEncryptKey: nextPublicKeySerialized === existing?.exchange?.publicKeySerialized && nextSalt === existing?.exchange?.saltString && nextInfo === existing?.exchange?.infoString && nextBind === existing?.exchange?.bindVerifyKeysIntoDerivation && !(nextBind === true && verifyKeyChanged) ? existing?.exchange?.sharedEncryptKey : void 0
|
|
596
|
+
};
|
|
597
|
+
} else if (exchange?.bindVerifyKeysIntoDerivation === true && verifyKeyChanged && exchange.sharedEncryptKey != null) exchange = {
|
|
598
|
+
...exchange,
|
|
599
|
+
sharedEncryptKey: void 0
|
|
600
|
+
};
|
|
601
|
+
this.linkedClientKeys.set(linkedClientId, {
|
|
602
|
+
verify,
|
|
603
|
+
exchange
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Like {@link linkClient}, but also persists the linked client's public keys (and salt/info) to
|
|
608
|
+
* storage so the link survives a reload.
|
|
609
|
+
*
|
|
610
|
+
* NOTE: salt/info are written in plaintext. When they are session secrets (e.g. a partner secret
|
|
611
|
+
* or bridge salt), prefer {@link linkClient} and re-establish the link per session instead.
|
|
612
|
+
*/
|
|
613
|
+
async linkClientAndStore(input) {
|
|
614
|
+
await this.linkClient(input);
|
|
615
|
+
if (this.storage == null) return;
|
|
616
|
+
const { linkedClientId, verifyPublicKey, exchangePublicKey, saltString, infoString, bindVerifyKeysIntoDerivation } = input;
|
|
617
|
+
await this.storage.updateJsonWithDef("linkedClientPublicKeys", {}, (current) => ({
|
|
618
|
+
...current,
|
|
619
|
+
[linkedClientId]: {
|
|
620
|
+
...current[linkedClientId],
|
|
621
|
+
...verifyPublicKey != null ? { verifyPublicKey } : {},
|
|
622
|
+
...exchangePublicKey != null ? { exchangePublicKey } : {},
|
|
623
|
+
...saltString !== void 0 ? { saltString } : {},
|
|
624
|
+
...infoString !== void 0 ? { infoString } : {},
|
|
625
|
+
...bindVerifyKeysIntoDerivation !== void 0 ? { bindVerifyKeysIntoDerivation } : {}
|
|
626
|
+
}
|
|
627
|
+
}));
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Whether a linked client is currently registered (in memory) under this id.
|
|
631
|
+
*/
|
|
632
|
+
hasLinkedClient(linkedClientId) {
|
|
633
|
+
return this.linkedClientKeys.has(linkedClientId);
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* The serialized public keys registered for a linked client, or undefined when the client is not
|
|
637
|
+
* linked. Useful when a holder needs to relay a linked client's keys onward (e.g. a backend
|
|
638
|
+
* relaying a wallet's verify key to a partner).
|
|
639
|
+
*/
|
|
640
|
+
getLinkedClientPublicKeys(linkedClientId) {
|
|
641
|
+
const linkedClient = this.linkedClientKeys.get(linkedClientId);
|
|
642
|
+
if (linkedClient == null) return;
|
|
643
|
+
return {
|
|
644
|
+
verifyPublicKey: linkedClient.verify?.publicKeySerialized,
|
|
645
|
+
exchangePublicKey: linkedClient.exchange?.publicKeySerialized
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* Removes a single linked client from memory and, when storage is available, from persisted
|
|
650
|
+
* state. Any cached shared key for the link is dropped with it.
|
|
651
|
+
*/
|
|
652
|
+
async unlinkClient(linkedClientId) {
|
|
653
|
+
this.linkedClientKeys.delete(linkedClientId);
|
|
654
|
+
if (this.storage != null) await this.storage.updateJson("linkedClientPublicKeys", (current) => {
|
|
655
|
+
if (current == null) return {};
|
|
656
|
+
const { [linkedClientId]: _removed, ...rest } = current;
|
|
657
|
+
return rest;
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Removes all linked clients from memory and persisted state, while keeping the local identity
|
|
662
|
+
* key pairs intact.
|
|
663
|
+
*/
|
|
664
|
+
async unlinkAllClients() {
|
|
665
|
+
this.linkedClientKeys.clear();
|
|
666
|
+
if (this.storage != null) await this.storage.setJson("linkedClientPublicKeys", {});
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* Wipes everything this instance owns — local identity key pairs and all linked clients, in
|
|
670
|
+
* memory and in storage. After a reset, {@link initialize} must be called again before use (it
|
|
671
|
+
* will generate a fresh local identity).
|
|
672
|
+
*
|
|
673
|
+
* Only the keys owned by this util are removed, so a shared storage adapter's other data is left
|
|
674
|
+
* untouched.
|
|
675
|
+
*/
|
|
676
|
+
async reset() {
|
|
677
|
+
this.linkedClientKeys.clear();
|
|
678
|
+
this.localExchangeKeyPair = void 0;
|
|
679
|
+
this.localVerifyKeyPair = void 0;
|
|
680
|
+
this.initialized = false;
|
|
681
|
+
if (this.storage != null) {
|
|
682
|
+
await this.storage.removeItem("linkedClientPublicKeys");
|
|
683
|
+
await this.storage.removeItem("localExchangeKeyPair");
|
|
684
|
+
await this.storage.removeItem("localVerifyKeyPair");
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
getLinkedClient(linkedClientId) {
|
|
688
|
+
const linkedClient = this.linkedClientKeys.get(linkedClientId);
|
|
689
|
+
if (linkedClient == null) throw new Error(`ClientCryptoKeyLink: No linked client for ${linkedClientId}`);
|
|
690
|
+
return linkedClient;
|
|
691
|
+
}
|
|
692
|
+
async getAesGcmKeyForLinkedClient(externalClientSourceId) {
|
|
693
|
+
const linkedClient = this.getLinkedClient(externalClientSourceId);
|
|
694
|
+
if (linkedClient.exchange?.sharedEncryptKey != null) return linkedClient.exchange.sharedEncryptKey;
|
|
695
|
+
if (linkedClient.exchange?.publicKey == null) throw new Error(`ClientCryptoKeyLink: No public exchange key set for ${externalClientSourceId}`);
|
|
696
|
+
const localExchangeKeyPair = await this.ensureLocalExchangeKeyPair();
|
|
697
|
+
let infoString = linkedClient.exchange.infoString;
|
|
698
|
+
if (linkedClient.exchange.bindVerifyKeysIntoDerivation === true) {
|
|
699
|
+
const linkedVerifyPublicKey = linkedClient.verify?.publicKeySerialized;
|
|
700
|
+
if (linkedVerifyPublicKey == null) throw new Error(`ClientCryptoKeyLink: Link for ${externalClientSourceId} binds verify keys into the derivation, but no verify public key is set`);
|
|
701
|
+
infoString = buildVerifyKeyBoundInfoString({
|
|
702
|
+
infoString: linkedClient.exchange.infoString,
|
|
703
|
+
verifyPublicKeys: [await this.getLocalVerifyPublicKey(), linkedVerifyPublicKey]
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
const sharedEncryptKey = await createAesGcmKeyFromX25519Keys({
|
|
707
|
+
internalX25519PrivateKey: localExchangeKeyPair.privateKey,
|
|
708
|
+
externalX25519PublicKey: linkedClient.exchange.publicKey,
|
|
709
|
+
saltString: linkedClient.exchange.saltString,
|
|
710
|
+
infoString
|
|
711
|
+
});
|
|
712
|
+
this.linkedClientKeys.set(externalClientSourceId, {
|
|
713
|
+
...linkedClient,
|
|
714
|
+
exchange: {
|
|
715
|
+
...linkedClient.exchange,
|
|
716
|
+
sharedEncryptKey
|
|
717
|
+
}
|
|
718
|
+
});
|
|
719
|
+
return sharedEncryptKey;
|
|
720
|
+
}
|
|
721
|
+
async encryptDataForLinkedClient({ dataToEncrypt, linkedClientId }) {
|
|
722
|
+
return await encryptTextDataWithAesGcmKey({
|
|
723
|
+
dataToEncrypt,
|
|
724
|
+
aesGcmKey: await this.getAesGcmKeyForLinkedClient(linkedClientId)
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
async decryptDataFromLinkedClient({ dataToDecrypt, linkedClientId }) {
|
|
728
|
+
return await decryptTextDataWithAesGcmKey({
|
|
729
|
+
dataToDecrypt,
|
|
730
|
+
aesGcmKey: await this.getAesGcmKeyForLinkedClient(linkedClientId)
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Bytes counterpart of {@link encryptDataForLinkedClient} — encrypts raw bytes with the shared
|
|
735
|
+
* AES-GCM key, returning a binary nonce + ciphertext. Use it for binary channels (e.g. msgpack
|
|
736
|
+
* WebSocket frames) to avoid base64 inflation.
|
|
737
|
+
*/
|
|
738
|
+
async encryptBytesForLinkedClient({ dataToEncrypt, linkedClientId }) {
|
|
739
|
+
return await encryptBytesWithAesGcmKey({
|
|
740
|
+
dataToEncrypt,
|
|
741
|
+
aesGcmKey: await this.getAesGcmKeyForLinkedClient(linkedClientId)
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
/** Bytes counterpart of {@link decryptDataFromLinkedClient}. */
|
|
745
|
+
async decryptBytesFromLinkedClient({ dataToDecrypt, linkedClientId }) {
|
|
746
|
+
return await decryptBytesWithAesGcmKey({
|
|
747
|
+
dataToDecrypt,
|
|
748
|
+
aesGcmKey: await this.getAesGcmKeyForLinkedClient(linkedClientId)
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
async signAndEncryptDataForLinkedClient({ dataToEncrypt, linkedClientId }) {
|
|
752
|
+
const { signatureBase64 } = await this.signChallenge([dataToEncrypt]);
|
|
753
|
+
return {
|
|
754
|
+
encryptedData: await this.encryptDataForLinkedClient({
|
|
755
|
+
dataToEncrypt,
|
|
756
|
+
linkedClientId
|
|
757
|
+
}),
|
|
758
|
+
signatureBase64
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
/**
|
|
762
|
+
* Decrypts a payload from a linked client and verifies that the decrypted plaintext was signed
|
|
763
|
+
* by that client. Counterpart to {@link signAndEncryptDataForLinkedClient}.
|
|
764
|
+
*
|
|
765
|
+
* Returns the decrypted `data` alongside `isValid` — the caller decides how to handle an invalid
|
|
766
|
+
* signature. (A tampered ciphertext fails earlier at AES-GCM decryption.)
|
|
767
|
+
*/
|
|
768
|
+
async decryptAndVerifyDataFromLinkedClient({ dataToDecrypt, linkedClientId, signatureBase64 }) {
|
|
769
|
+
const data = await this.decryptDataFromLinkedClient({
|
|
770
|
+
dataToDecrypt,
|
|
771
|
+
linkedClientId
|
|
772
|
+
});
|
|
773
|
+
return {
|
|
774
|
+
data,
|
|
775
|
+
isValid: await this.verifyChallengeFromLinkedClient({
|
|
776
|
+
linkedClientId,
|
|
777
|
+
challenge: data,
|
|
778
|
+
signatureBase64
|
|
779
|
+
})
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
async signChallenge(challenge) {
|
|
783
|
+
if (challenge.length === 0) throw new Error("Challenge must contain at least one string");
|
|
784
|
+
const localVerifyKeyPair = await this.ensureLocalVerifyKeyPair();
|
|
785
|
+
const signature = challenge.length > 1 ? await signCombinedTextDataWithKeyEd25519(challenge, localVerifyKeyPair.privateKey) : await signTextDataWithKeyEd25519(challenge[0], localVerifyKeyPair.privateKey);
|
|
786
|
+
return { signatureBase64: base64.encode(signature) };
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Verifies a signature over `challenge` against the linked client's verify (Ed25519) public key.
|
|
790
|
+
*/
|
|
791
|
+
async verifyChallengeFromLinkedClient({ linkedClientId, challenge, signatureBase64 }) {
|
|
792
|
+
const linkedClient = this.getLinkedClient(linkedClientId);
|
|
793
|
+
if (linkedClient.verify?.publicKey == null) throw new Error(`ClientCryptoKeyLink: No verify public key set for ${linkedClientId}`);
|
|
794
|
+
return await verifyWithKeyEd25519({
|
|
795
|
+
challenge,
|
|
796
|
+
signatureBase64,
|
|
797
|
+
publicKey: linkedClient.verify.publicKey
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
};
|
|
801
|
+
//#endregion
|
|
802
|
+
//#region src/storage_adapter/storage_adapter.types.ts
|
|
803
|
+
let EStorageAdapterType = /* @__PURE__ */ function(EStorageAdapterType) {
|
|
804
|
+
EStorageAdapterType["string"] = "string";
|
|
805
|
+
EStorageAdapterType["json"] = "json";
|
|
806
|
+
return EStorageAdapterType;
|
|
807
|
+
}({});
|
|
808
|
+
//#endregion
|
|
809
|
+
//#region src/storage_adapter/StorageAdapter.ts
|
|
810
|
+
var StorageAdapter = class StorageAdapter {
|
|
811
|
+
implementation;
|
|
812
|
+
keyPrefix;
|
|
813
|
+
adapterStorage;
|
|
814
|
+
constructor({ methods, keyPrefix, trackKeysForClearing: trackKeys }) {
|
|
815
|
+
this.implementation = methods;
|
|
816
|
+
this.keyPrefix = keyPrefix ?? "";
|
|
817
|
+
const _trackKeys = trackKeys ?? true;
|
|
818
|
+
this.adapterStorage = _trackKeys ? createTypedStorage({ storageAdapter: new StorageAdapter({
|
|
819
|
+
methods,
|
|
820
|
+
keyPrefix,
|
|
821
|
+
trackKeysForClearing: false
|
|
822
|
+
}) }) : void 0;
|
|
823
|
+
}
|
|
824
|
+
getPrefixedKey(rawKey) {
|
|
825
|
+
return `${this.keyPrefix}${rawKey}`;
|
|
826
|
+
}
|
|
827
|
+
async trackUsedKey(rawKey) {
|
|
828
|
+
if (!this.adapterStorage) return;
|
|
829
|
+
await this.adapterStorage.updateJsonWithDef("__usedKeys__", [], (currentKeys) => {
|
|
830
|
+
if (!currentKeys.includes(rawKey)) return [...currentKeys, rawKey];
|
|
831
|
+
return currentKeys;
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
async untrackUsedKey(rawKey) {
|
|
835
|
+
if (!this.adapterStorage) return;
|
|
836
|
+
await this.adapterStorage.updateJsonWithDef("__usedKeys__", [], (currentKeys) => {
|
|
837
|
+
return currentKeys.filter((k) => k !== rawKey);
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
async clearAll() {
|
|
841
|
+
if (!this.adapterStorage) return;
|
|
842
|
+
const allKeys = await this.adapterStorage.getJsonOrDef("__usedKeys__", []) ?? [];
|
|
843
|
+
await Promise.all(allKeys.map(async (key) => {
|
|
844
|
+
await this.removeItem(key);
|
|
845
|
+
}));
|
|
846
|
+
await this.adapterStorage.setJson("__usedKeys__", []);
|
|
847
|
+
}
|
|
848
|
+
async removeItem(rawKey) {
|
|
849
|
+
await this.implementation.removeItem(this.getPrefixedKey(rawKey));
|
|
850
|
+
await this.untrackUsedKey(rawKey);
|
|
851
|
+
}
|
|
852
|
+
async setJson(rawKey, value) {
|
|
853
|
+
const key = this.getPrefixedKey(rawKey);
|
|
854
|
+
if (this.implementation.type === "string") await this.implementation.setItem(key, JSON.stringify(value));
|
|
855
|
+
else await this.implementation.setItem(key, value);
|
|
856
|
+
await this.trackUsedKey(rawKey);
|
|
857
|
+
}
|
|
858
|
+
async getJson(rawKey) {
|
|
859
|
+
const key = this.getPrefixedKey(rawKey);
|
|
860
|
+
if (this.implementation.type === "string") {
|
|
861
|
+
const val = await this.implementation.getItem(key);
|
|
862
|
+
if (val == null || val === "undefined" || val === "null") return;
|
|
863
|
+
return JSON.parse(val);
|
|
864
|
+
} else {
|
|
865
|
+
const val = await this.implementation.getItem(key);
|
|
866
|
+
if (val == null || val === "undefined" || val === "null") return;
|
|
867
|
+
return val;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
async getJsonOrDef(rawKey, defVal) {
|
|
871
|
+
if (this.implementation.type === "string") {
|
|
872
|
+
const val = await this.implementation.getItem(this.getPrefixedKey(rawKey));
|
|
873
|
+
if (val == null || val === "undefined" || val === "null") return defVal;
|
|
874
|
+
return JSON.parse(val);
|
|
875
|
+
}
|
|
876
|
+
const val = await this.implementation.getItem(this.getPrefixedKey(rawKey));
|
|
877
|
+
if (val == null || val === "undefined" || val === "null") return defVal;
|
|
878
|
+
return val;
|
|
879
|
+
}
|
|
880
|
+
async updateJson(rawKey, updater) {
|
|
881
|
+
const newVal = updater(await this.getJson(rawKey));
|
|
882
|
+
await this.setJson(rawKey, newVal);
|
|
883
|
+
return newVal;
|
|
884
|
+
}
|
|
885
|
+
async updateJsonOrDef(rawKey, defVal, updater) {
|
|
886
|
+
const newVal = updater(await this.getJsonOrDef(rawKey, defVal));
|
|
887
|
+
await this.setJson(rawKey, newVal);
|
|
888
|
+
return newVal;
|
|
889
|
+
}
|
|
890
|
+
createJsonGetterSetter(rawKey) {
|
|
891
|
+
return {
|
|
892
|
+
get: () => this.getJson(rawKey),
|
|
893
|
+
set: (value) => this.setJson(rawKey, value)
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
};
|
|
897
|
+
//#endregion
|
|
898
|
+
//#region src/storage_adapter/specific/browser/browser_storage.ts
|
|
937
899
|
function createWebLocalStorageMethods(_localStorage) {
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
900
|
+
return {
|
|
901
|
+
type: "string",
|
|
902
|
+
getItem: async (key) => _localStorage.getItem(key),
|
|
903
|
+
setItem: async (key, value) => {
|
|
904
|
+
_localStorage.setItem(key, value);
|
|
905
|
+
},
|
|
906
|
+
removeItem: async (key) => {
|
|
907
|
+
_localStorage.removeItem(key);
|
|
908
|
+
}
|
|
909
|
+
};
|
|
948
910
|
}
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
methods: createWebLocalStorageMethods(_localStorage),
|
|
955
|
-
...options
|
|
956
|
-
});
|
|
911
|
+
const createWebLocalStorageAdapter = ({ localStorage: _localStorage, ...options }) => {
|
|
912
|
+
return new StorageAdapter({
|
|
913
|
+
methods: createWebLocalStorageMethods(_localStorage),
|
|
914
|
+
...options
|
|
915
|
+
});
|
|
957
916
|
};
|
|
958
917
|
function createTypedWebLocalStorage(options) {
|
|
959
|
-
|
|
960
|
-
storageAdapter: createWebLocalStorageAdapter(options)
|
|
961
|
-
});
|
|
918
|
+
return createTypedStorage({ storageAdapter: createWebLocalStorageAdapter(options) });
|
|
962
919
|
}
|
|
963
920
|
function createWebSessionStorageMethods(_sessionStorage) {
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
921
|
+
return {
|
|
922
|
+
type: "string",
|
|
923
|
+
getItem: async (key) => _sessionStorage.getItem(key),
|
|
924
|
+
setItem: async (key, value) => {
|
|
925
|
+
_sessionStorage.setItem(key, value);
|
|
926
|
+
},
|
|
927
|
+
removeItem: async (key) => {
|
|
928
|
+
_sessionStorage.removeItem(key);
|
|
929
|
+
}
|
|
930
|
+
};
|
|
974
931
|
}
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
methods: createWebSessionStorageMethods(_sessionStorage),
|
|
981
|
-
...options
|
|
982
|
-
});
|
|
932
|
+
const createWebSessionStorageAdapter = ({ sessionStorage: _sessionStorage, ...options }) => {
|
|
933
|
+
return new StorageAdapter({
|
|
934
|
+
methods: createWebSessionStorageMethods(_sessionStorage),
|
|
935
|
+
...options
|
|
936
|
+
});
|
|
983
937
|
};
|
|
984
938
|
function createTypedWebSessionStorage(options) {
|
|
985
|
-
|
|
986
|
-
storageAdapter: createWebSessionStorageAdapter(options)
|
|
987
|
-
});
|
|
939
|
+
return createTypedStorage({ storageAdapter: createWebSessionStorageAdapter(options) });
|
|
988
940
|
}
|
|
989
|
-
|
|
941
|
+
//#endregion
|
|
942
|
+
//#region src/storage_adapter/specific/cloudflare/durable_object/durable_object_storage.ts
|
|
990
943
|
function createDurableObjectStorageMethods(durableObjectStorage) {
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
944
|
+
return {
|
|
945
|
+
type: "json",
|
|
946
|
+
getItem: (key) => durableObjectStorage.get(key),
|
|
947
|
+
setItem: (key, value) => durableObjectStorage.put(key, value),
|
|
948
|
+
removeItem: async (key) => {
|
|
949
|
+
await durableObjectStorage.delete(key);
|
|
950
|
+
}
|
|
951
|
+
};
|
|
999
952
|
}
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
953
|
+
/**
|
|
954
|
+
* Wraps a Durable Object's storage in the generic StorageAdapter interface, e.g. for handing to a
|
|
955
|
+
* ClientCryptoKeyLink so it can persist its keys inside the DO's own storage.
|
|
956
|
+
*/
|
|
957
|
+
const createDurableObjectStorageAdapter = ({ durableObjectStorage, ...options }) => {
|
|
958
|
+
return new StorageAdapter({
|
|
959
|
+
methods: createDurableObjectStorageMethods(durableObjectStorage),
|
|
960
|
+
...options
|
|
961
|
+
});
|
|
1008
962
|
};
|
|
1009
963
|
function createDurableObjectTypedStorage(options) {
|
|
1010
|
-
|
|
1011
|
-
storageAdapter: createDurableObjectStorageAdapter(options)
|
|
1012
|
-
});
|
|
964
|
+
return createTypedStorage({ storageAdapter: createDurableObjectStorageAdapter(options) });
|
|
1013
965
|
}
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
removeItem: (key) => kvNamespace.delete(key)
|
|
1024
|
-
};
|
|
966
|
+
//#endregion
|
|
967
|
+
//#region src/storage_adapter/specific/cloudflare/kv/kv_storage.ts
|
|
968
|
+
function createKVStorageMethods({ kvNamespace, defaultPutOptions }) {
|
|
969
|
+
return {
|
|
970
|
+
type: "string",
|
|
971
|
+
getItem: (key) => kvNamespace.get(key),
|
|
972
|
+
setItem: (key, value) => kvNamespace.put(key, value, defaultPutOptions),
|
|
973
|
+
removeItem: (key) => kvNamespace.delete(key)
|
|
974
|
+
};
|
|
1025
975
|
}
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
}) => {
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
976
|
+
/**
|
|
977
|
+
* Wraps a Cloudflare KV namespace binding in the generic StorageAdapter interface, e.g. for handing
|
|
978
|
+
* to a ClientCryptoKeyLink so it can persist its keys inside KV.
|
|
979
|
+
*/
|
|
980
|
+
const createKVStorageAdapter = ({ kvNamespace, defaultPutOptions, ...options }) => {
|
|
981
|
+
return new StorageAdapter({
|
|
982
|
+
methods: createKVStorageMethods({
|
|
983
|
+
kvNamespace,
|
|
984
|
+
defaultPutOptions
|
|
985
|
+
}),
|
|
986
|
+
...options
|
|
987
|
+
});
|
|
1035
988
|
};
|
|
1036
989
|
function createKVTypedStorage(options) {
|
|
1037
|
-
|
|
1038
|
-
storageAdapter: createKVStorageAdapter(options)
|
|
1039
|
-
});
|
|
990
|
+
return createTypedStorage({ storageAdapter: createKVStorageAdapter(options) });
|
|
1040
991
|
}
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
992
|
+
//#endregion
|
|
993
|
+
//#region src/storage_adapter/specific/memory/memory_storage.ts
|
|
994
|
+
function createMemoryStorageMethods_string(memoryStorageMap = /* @__PURE__ */ new Map()) {
|
|
995
|
+
return {
|
|
996
|
+
type: "string",
|
|
997
|
+
getItem: async (key) => memoryStorageMap.get(key) ?? null,
|
|
998
|
+
setItem: async (key, value) => {
|
|
999
|
+
memoryStorageMap.set(key, value);
|
|
1000
|
+
},
|
|
1001
|
+
removeItem: async (key) => {
|
|
1002
|
+
memoryStorageMap.delete(key);
|
|
1003
|
+
}
|
|
1004
|
+
};
|
|
1053
1005
|
}
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1006
|
+
const createMemoryStorageAdapter_string = (options) => {
|
|
1007
|
+
return new StorageAdapter({
|
|
1008
|
+
methods: createMemoryStorageMethods_string(options?.memoryStorageMap),
|
|
1009
|
+
...options
|
|
1010
|
+
});
|
|
1059
1011
|
};
|
|
1060
1012
|
function createTypedMemoryStorage_string(options) {
|
|
1061
|
-
|
|
1062
|
-
storageAdapter: createMemoryStorageAdapter_string(options)
|
|
1063
|
-
});
|
|
1013
|
+
return createTypedStorage({ storageAdapter: createMemoryStorageAdapter_string(options) });
|
|
1064
1014
|
}
|
|
1065
|
-
function createMemoryStorageMethods_json(memoryStorageMap = new Map) {
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1015
|
+
function createMemoryStorageMethods_json(memoryStorageMap = /* @__PURE__ */ new Map()) {
|
|
1016
|
+
return {
|
|
1017
|
+
type: "json",
|
|
1018
|
+
getItem: async (key) => memoryStorageMap.get(key),
|
|
1019
|
+
setItem: async (key, value) => {
|
|
1020
|
+
memoryStorageMap.set(key, value);
|
|
1021
|
+
},
|
|
1022
|
+
removeItem: async (key) => {
|
|
1023
|
+
memoryStorageMap.delete(key);
|
|
1024
|
+
}
|
|
1025
|
+
};
|
|
1076
1026
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1027
|
+
const createMemoryStorageAdapter_json = (options) => {
|
|
1028
|
+
return new StorageAdapter({
|
|
1029
|
+
methods: createMemoryStorageMethods_json(options?.memoryStorageMap),
|
|
1030
|
+
...options
|
|
1031
|
+
});
|
|
1082
1032
|
};
|
|
1083
1033
|
function createTypedMemoryStorage_json(options) {
|
|
1084
|
-
|
|
1085
|
-
storageAdapter: createMemoryStorageAdapter_json(options)
|
|
1086
|
-
});
|
|
1034
|
+
return createTypedStorage({ storageAdapter: createMemoryStorageAdapter_json(options) });
|
|
1087
1035
|
}
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
vSerializedCryptoKeyDataX25519_Raw,
|
|
1093
|
-
vSerializedCryptoKeyDataX25519_Jwk,
|
|
1094
|
-
vSerializedCryptoKeyDataEd25519_Raw,
|
|
1095
|
-
vSerializedCryptoKeyDataEd25519_Jwk,
|
|
1096
|
-
vEncryptedAesGcmPayload,
|
|
1097
|
-
vCryptoKeyPairDataX25519,
|
|
1098
|
-
vCryptoKeyPairDataEd25519,
|
|
1099
|
-
signTextDataWithKeyEd25519,
|
|
1100
|
-
signCombinedTextDataWithKeyEd25519,
|
|
1101
|
-
serializeX25519Key_Raw,
|
|
1102
|
-
serializeX25519Key_Jwk,
|
|
1103
|
-
serializeEd25519Key_Raw,
|
|
1104
|
-
serializeEd25519Key_Jwk,
|
|
1105
|
-
importX25519Key,
|
|
1106
|
-
importEd25519Key,
|
|
1107
|
-
generateX25519KeyPair,
|
|
1108
|
-
generateEd25519KeyPair,
|
|
1109
|
-
encryptTextDataWithAesGcmKey,
|
|
1110
|
-
encryptBytesWithAesGcmKey,
|
|
1111
|
-
decryptTextDataWithAesGcmKey,
|
|
1112
|
-
decryptBytesWithAesGcmKey,
|
|
1113
|
-
createWebSessionStorageMethods,
|
|
1114
|
-
createWebSessionStorageAdapter,
|
|
1115
|
-
createWebLocalStorageMethods,
|
|
1116
|
-
createWebLocalStorageAdapter,
|
|
1117
|
-
createTypedWebSessionStorage,
|
|
1118
|
-
createTypedWebLocalStorage,
|
|
1119
|
-
createTypedStorage,
|
|
1120
|
-
createTypedMemoryStorage_string,
|
|
1121
|
-
createTypedMemoryStorage_json,
|
|
1122
|
-
createSharedBitsFromX25519,
|
|
1123
|
-
createMemoryStorageMethods_string,
|
|
1124
|
-
createMemoryStorageMethods_json,
|
|
1125
|
-
createMemoryStorageAdapter_string,
|
|
1126
|
-
createMemoryStorageAdapter_json,
|
|
1127
|
-
createKVTypedStorage,
|
|
1128
|
-
createKVStorageMethods,
|
|
1129
|
-
createKVStorageAdapter,
|
|
1130
|
-
createDurableObjectTypedStorage,
|
|
1131
|
-
createDurableObjectStorageMethods,
|
|
1132
|
-
createDurableObjectStorageAdapter,
|
|
1133
|
-
createAesGcmKeyFromX25519Keys,
|
|
1134
|
-
convertX25519RawDataStringToSerializedKeyData,
|
|
1135
|
-
convertX25519RawDataStringToObject,
|
|
1136
|
-
convertX25519JwkDataStringToSerializedKeyData,
|
|
1137
|
-
convertX25519JwkDataStringToObject,
|
|
1138
|
-
convertX25519FormattedStringToSerializedKeyData,
|
|
1139
|
-
convertX25519FormattedStringToObject,
|
|
1140
|
-
convertEd25519RawDataStringToSerializedKeyData,
|
|
1141
|
-
convertEd25519RawDataStringToObject,
|
|
1142
|
-
convertEd25519JwkDataStringToSerializedKeyData,
|
|
1143
|
-
convertEd25519JwkDataStringToObject,
|
|
1144
|
-
convertEd25519FormattedStringToSerializedKeyData,
|
|
1145
|
-
convertEd25519FormattedStringToObject,
|
|
1146
|
-
buildVerifyKeyBoundInfoString,
|
|
1147
|
-
StorageAdapter,
|
|
1148
|
-
EStorageAdapterType,
|
|
1149
|
-
ECryptoKeyFormat,
|
|
1150
|
-
ECryptoKeyAlgo,
|
|
1151
|
-
DEFAULT_COMBINED_TEXT_DATA_SEPARATOR,
|
|
1152
|
-
ClientCryptoKeyLink
|
|
1153
|
-
};
|
|
1036
|
+
//#endregion
|
|
1037
|
+
export { ClientCryptoKeyLink, DEFAULT_COMBINED_TEXT_DATA_SEPARATOR, ECryptoKeyAlgo, ECryptoKeyFormat, EStorageAdapterType, StorageAdapter, buildVerifyKeyBoundInfoString, convertEd25519FormattedStringToObject, convertEd25519FormattedStringToSerializedKeyData, convertEd25519JwkDataStringToObject, convertEd25519JwkDataStringToSerializedKeyData, convertEd25519RawDataStringToObject, convertEd25519RawDataStringToSerializedKeyData, convertX25519FormattedStringToObject, convertX25519FormattedStringToSerializedKeyData, convertX25519JwkDataStringToObject, convertX25519JwkDataStringToSerializedKeyData, convertX25519RawDataStringToObject, convertX25519RawDataStringToSerializedKeyData, createAesGcmKeyFromX25519Keys, createDurableObjectStorageAdapter, createDurableObjectStorageMethods, createDurableObjectTypedStorage, createKVStorageAdapter, createKVStorageMethods, createKVTypedStorage, createMemoryStorageAdapter_json, createMemoryStorageAdapter_string, createMemoryStorageMethods_json, createMemoryStorageMethods_string, createSharedBitsFromX25519, createTypedMemoryStorage_json, createTypedMemoryStorage_string, createTypedStorage, createTypedWebLocalStorage, createTypedWebSessionStorage, createWebLocalStorageAdapter, createWebLocalStorageMethods, createWebSessionStorageAdapter, createWebSessionStorageMethods, decryptBytesWithAesGcmKey, decryptTextDataWithAesGcmKey, encryptBytesWithAesGcmKey, encryptTextDataWithAesGcmKey, generateEd25519KeyPair, generateX25519KeyPair, importEd25519Key, importX25519Key, serializeEd25519Key_Jwk, serializeEd25519Key_Raw, serializeX25519Key_Jwk, serializeX25519Key_Raw, signCombinedTextDataWithKeyEd25519, signTextDataWithKeyEd25519, vCryptoKeyPairDataEd25519, vCryptoKeyPairDataX25519, vEncryptedAesGcmPayload, vSerializedCryptoKeyDataEd25519_Jwk, vSerializedCryptoKeyDataEd25519_Raw, vSerializedCryptoKeyDataX25519_Jwk, vSerializedCryptoKeyDataX25519_Raw, vVerifyChallengeWithSignature_Input, vVerifyChallengeWithSignature_WithThrow_Input, verifyWithKeyEd25519 };
|
|
1038
|
+
|
|
1039
|
+
//# sourceMappingURL=index.js.map
|