@wishknish/knishio-client-js 0.9.4 → 1.1.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/README.md +13 -0
- package/dist/client.cjs.js +38 -40
- package/dist/client.cjs.js.map +1 -1
- package/dist/client.es.mjs +6660 -9256
- package/dist/client.es.mjs.map +1 -1
- package/dist/client.iife.js +38 -40
- package/dist/client.iife.js.map +1 -1
- package/package.json +10 -11
- package/src/AuthToken.js +25 -3
- package/src/KnishIOClient.js +54 -15
- package/src/Molecule.js +15 -7
- package/src/Wallet.js +137 -30
- package/src/exception/SecretStorageException.js +10 -0
- package/src/index.js +11 -1
- package/src/libraries/urql/UrqlClientWrapper.js +7 -2
- package/src/storage/FileStorageBackend.js +199 -0
- package/src/storage/MemorySecretStorageProvider.js +69 -1
- package/src/storage/NonExtractableKeySecretStorageProvider.js +514 -0
- package/src/storage/WebAuthnPrfSecretStorageProvider.js +646 -0
- package/src/storage/WebCryptoSecretStorageProvider.js +107 -129
- package/src/storage/WebStorageBackend.js +117 -0
- package/src/storage/index.js +25 -3
- package/src/storage/secretEnvelope.js +208 -0
|
@@ -48,6 +48,14 @@ License: https://github.com/WishKnish/KnishIO-Client-JS/blob/master/LICENSE
|
|
|
48
48
|
|
|
49
49
|
import SecretStorageException from '../exception/SecretStorageException.js'
|
|
50
50
|
import { zeroizeBytes, withSecureBytes } from '../libraries/secureMemory.js'
|
|
51
|
+
import {
|
|
52
|
+
sealEnvelope,
|
|
53
|
+
openEnvelope,
|
|
54
|
+
deriveEnvelopeKey,
|
|
55
|
+
DEFAULT_ITERATIONS,
|
|
56
|
+
SECRET_KEY_PREFIX,
|
|
57
|
+
RECOVERY_KEY_PREFIX
|
|
58
|
+
} from './secretEnvelope.js'
|
|
51
59
|
|
|
52
60
|
/**
|
|
53
61
|
* Default in-memory backend for WebCrypto encrypted payloads
|
|
@@ -74,67 +82,34 @@ export class MemoryStorageBackend {
|
|
|
74
82
|
}
|
|
75
83
|
}
|
|
76
84
|
|
|
77
|
-
/**
|
|
78
|
-
* Helper to convert Uint8Array to base64
|
|
79
|
-
*
|
|
80
|
-
* @param {Uint8Array} bytes
|
|
81
|
-
* @returns {string}
|
|
82
|
-
*/
|
|
83
|
-
function uint8ArrayToBase64 (bytes) {
|
|
84
|
-
let binary = ''
|
|
85
|
-
const len = bytes.byteLength
|
|
86
|
-
for (let i = 0; i < len; i++) {
|
|
87
|
-
const byte = bytes[i]
|
|
88
|
-
if (byte !== undefined) {
|
|
89
|
-
binary += String.fromCharCode(byte)
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return btoa(binary)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Helper to convert base64 to Uint8Array
|
|
97
|
-
*
|
|
98
|
-
* @param {string} base64
|
|
99
|
-
* @returns {Uint8Array}
|
|
100
|
-
*/
|
|
101
|
-
function base64ToUint8Array (base64) {
|
|
102
|
-
const binary = atob(base64)
|
|
103
|
-
const len = binary.length
|
|
104
|
-
const bytes = new Uint8Array(len)
|
|
105
|
-
for (let i = 0; i < len; i++) {
|
|
106
|
-
bytes[i] = binary.charCodeAt(i)
|
|
107
|
-
}
|
|
108
|
-
return bytes
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const textEncoder = new TextEncoder()
|
|
112
85
|
const textDecoder = new TextDecoder()
|
|
113
|
-
const KEY_PREFIX =
|
|
114
|
-
const DEFAULT_ITERATIONS = 100000
|
|
86
|
+
const KEY_PREFIX = SECRET_KEY_PREFIX
|
|
115
87
|
|
|
116
88
|
/**
|
|
117
|
-
*
|
|
118
|
-
*
|
|
89
|
+
* Software envelope-encryption secret storage provider: WebCrypto AES-256-GCM with PBKDF2-HMAC-SHA256.
|
|
90
|
+
* Writes the cross-SDK envelope format; never hardware-backed.
|
|
119
91
|
*/
|
|
120
92
|
export default class WebCryptoSecretStorageProvider {
|
|
121
93
|
/**
|
|
122
|
-
* @param {{ backend?: object, defaultPassphrase?: string
|
|
94
|
+
* @param {{ backend?: object, defaultPassphrase?: string }} [options]
|
|
123
95
|
*/
|
|
124
96
|
constructor (options = {}) {
|
|
125
97
|
this.providerType = 'webcrypto-aes-gcm'
|
|
126
98
|
this.backend = options.backend || new MemoryStorageBackend()
|
|
127
99
|
this.defaultPassphrase = options.defaultPassphrase
|
|
128
|
-
this.hardwareBacked = options.hardwareBacked || false
|
|
129
100
|
}
|
|
130
101
|
|
|
131
102
|
/**
|
|
132
|
-
*
|
|
103
|
+
* True only when this provider holds a non-exportable key inside platform-secure
|
|
104
|
+
* hardware (Android TEE/StrongBox, Secure Enclave, TPM) and learned that from the
|
|
105
|
+
* platform itself — never from a caller argument. Software envelope providers
|
|
106
|
+
* return false. The value is persisted as `metadata.hardwareBacked` in every
|
|
107
|
+
* envelope this provider writes.
|
|
133
108
|
*
|
|
134
109
|
* @returns {boolean}
|
|
135
110
|
*/
|
|
136
111
|
isHardwareBacked () {
|
|
137
|
-
return
|
|
112
|
+
return false
|
|
138
113
|
}
|
|
139
114
|
|
|
140
115
|
/**
|
|
@@ -161,32 +136,7 @@ export default class WebCryptoSecretStorageProvider {
|
|
|
161
136
|
if (!await this.isAvailable()) {
|
|
162
137
|
throw SecretStorageException.unavailable(this.providerType, 'WebCrypto API is not available')
|
|
163
138
|
}
|
|
164
|
-
|
|
165
|
-
const passphraseBytes = textEncoder.encode(passphrase)
|
|
166
|
-
try {
|
|
167
|
-
const baseKey = await globalThis.crypto.subtle.importKey(
|
|
168
|
-
'raw',
|
|
169
|
-
passphraseBytes,
|
|
170
|
-
'PBKDF2',
|
|
171
|
-
false,
|
|
172
|
-
['deriveKey']
|
|
173
|
-
)
|
|
174
|
-
|
|
175
|
-
return await globalThis.crypto.subtle.deriveKey(
|
|
176
|
-
{
|
|
177
|
-
name: 'PBKDF2',
|
|
178
|
-
salt,
|
|
179
|
-
iterations,
|
|
180
|
-
hash: 'SHA-256'
|
|
181
|
-
},
|
|
182
|
-
baseKey,
|
|
183
|
-
{ name: 'AES-GCM', length: 256 },
|
|
184
|
-
false,
|
|
185
|
-
['encrypt', 'decrypt']
|
|
186
|
-
)
|
|
187
|
-
} finally {
|
|
188
|
-
zeroizeBytes(passphraseBytes)
|
|
189
|
-
}
|
|
139
|
+
return await deriveEnvelopeKey(passphrase, salt, iterations)
|
|
190
140
|
}
|
|
191
141
|
|
|
192
142
|
/**
|
|
@@ -210,49 +160,39 @@ export default class WebCryptoSecretStorageProvider {
|
|
|
210
160
|
throw new SecretStorageException('Passphrase required for envelope encryption')
|
|
211
161
|
}
|
|
212
162
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
globalThis.crypto.getRandomValues(iv)
|
|
217
|
-
|
|
218
|
-
const key = await this.deriveKey(passphrase, salt, DEFAULT_ITERATIONS)
|
|
219
|
-
const secretBytes = textEncoder.encode(secret)
|
|
163
|
+
if (!await this.isAvailable()) {
|
|
164
|
+
throw SecretStorageException.unavailable(this.providerType, 'WebCrypto API is not available')
|
|
165
|
+
}
|
|
220
166
|
|
|
221
167
|
try {
|
|
222
|
-
const encryptedBuffer = await globalThis.crypto.subtle.encrypt(
|
|
223
|
-
{
|
|
224
|
-
name: 'AES-GCM',
|
|
225
|
-
iv
|
|
226
|
-
},
|
|
227
|
-
key,
|
|
228
|
-
secretBytes
|
|
229
|
-
)
|
|
230
|
-
|
|
231
|
-
const ciphertext = uint8ArrayToBase64(new Uint8Array(encryptedBuffer))
|
|
232
168
|
const metadata = {
|
|
233
169
|
bundleHash,
|
|
234
170
|
label: options.label,
|
|
235
171
|
createdAt: Date.now(),
|
|
236
|
-
hardwareBacked:
|
|
172
|
+
hardwareBacked: false,
|
|
237
173
|
providerType: this.providerType
|
|
238
174
|
}
|
|
239
175
|
|
|
240
|
-
const payload =
|
|
241
|
-
version: 1,
|
|
242
|
-
ciphertext,
|
|
243
|
-
iv: uint8ArrayToBase64(iv),
|
|
244
|
-
salt: uint8ArrayToBase64(salt),
|
|
245
|
-
algorithm: 'AES-GCM',
|
|
246
|
-
iterations: DEFAULT_ITERATIONS,
|
|
247
|
-
metadata
|
|
248
|
-
}
|
|
249
|
-
|
|
176
|
+
const payload = await sealEnvelope(secret, passphrase, metadata)
|
|
250
177
|
await this.backend.setItem(`${KEY_PREFIX}${bundleHash}`, JSON.stringify(payload))
|
|
178
|
+
|
|
179
|
+
if (options.recoveryPassphrase) {
|
|
180
|
+
const recoveryMetadata = {
|
|
181
|
+
bundleHash,
|
|
182
|
+
label: options.label,
|
|
183
|
+
createdAt: Date.now(),
|
|
184
|
+
hardwareBacked: false,
|
|
185
|
+
providerType: 'webcrypto-aes-gcm'
|
|
186
|
+
}
|
|
187
|
+
const recoveryPayload = await sealEnvelope(secret, options.recoveryPassphrase, recoveryMetadata)
|
|
188
|
+
await this.backend.setItem(`${RECOVERY_KEY_PREFIX}${bundleHash}`, JSON.stringify(recoveryPayload))
|
|
189
|
+
}
|
|
251
190
|
} catch (err) {
|
|
191
|
+
if (err instanceof SecretStorageException) {
|
|
192
|
+
throw err
|
|
193
|
+
}
|
|
252
194
|
const msg = err instanceof Error ? err.message : String(err)
|
|
253
195
|
throw new SecretStorageException(`Encryption failed: ${msg}`)
|
|
254
|
-
} finally {
|
|
255
|
-
zeroizeBytes(secretBytes)
|
|
256
196
|
}
|
|
257
197
|
}
|
|
258
198
|
|
|
@@ -280,29 +220,21 @@ export default class WebCryptoSecretStorageProvider {
|
|
|
280
220
|
if (!passphrase) {
|
|
281
221
|
throw new SecretStorageException('Passphrase required for secret decryption')
|
|
282
222
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
const ciphertext = base64ToUint8Array(payload.ciphertext)
|
|
223
|
+
if (!await this.isAvailable()) {
|
|
224
|
+
throw SecretStorageException.unavailable(this.providerType, 'WebCrypto API is not available')
|
|
225
|
+
}
|
|
287
226
|
|
|
288
227
|
try {
|
|
289
|
-
const
|
|
290
|
-
const decryptedBuffer = await globalThis.crypto.subtle.decrypt(
|
|
291
|
-
{
|
|
292
|
-
name: 'AES-GCM',
|
|
293
|
-
iv
|
|
294
|
-
},
|
|
295
|
-
key,
|
|
296
|
-
ciphertext
|
|
297
|
-
)
|
|
298
|
-
|
|
299
|
-
const decryptedBytes = new Uint8Array(decryptedBuffer)
|
|
228
|
+
const decryptedBytes = await openEnvelope(payload, passphrase)
|
|
300
229
|
try {
|
|
301
230
|
return textDecoder.decode(decryptedBytes)
|
|
302
231
|
} finally {
|
|
303
232
|
zeroizeBytes(decryptedBytes)
|
|
304
233
|
}
|
|
305
234
|
} catch (err) {
|
|
235
|
+
if (err instanceof SecretStorageException) {
|
|
236
|
+
throw err
|
|
237
|
+
}
|
|
306
238
|
const msg = err instanceof Error ? err.message : String(err)
|
|
307
239
|
throw SecretStorageException.decryptionFailed(msg)
|
|
308
240
|
}
|
|
@@ -316,7 +248,9 @@ export default class WebCryptoSecretStorageProvider {
|
|
|
316
248
|
*/
|
|
317
249
|
async deleteSecret (bundleHash) {
|
|
318
250
|
const key = `${KEY_PREFIX}${bundleHash}`
|
|
251
|
+
const recoveryKey = `${RECOVERY_KEY_PREFIX}${bundleHash}`
|
|
319
252
|
const result = await this.backend.removeItem(key)
|
|
253
|
+
await this.backend.removeItem(recoveryKey)
|
|
320
254
|
return result !== false
|
|
321
255
|
}
|
|
322
256
|
|
|
@@ -338,7 +272,7 @@ export default class WebCryptoSecretStorageProvider {
|
|
|
338
272
|
*/
|
|
339
273
|
async listSecrets () {
|
|
340
274
|
const keys = await this.backend.keys()
|
|
341
|
-
const matchingKeys = keys.filter(k => k.startsWith(KEY_PREFIX))
|
|
275
|
+
const matchingKeys = keys.filter(k => k.startsWith(KEY_PREFIX) && !k.startsWith(RECOVERY_KEY_PREFIX))
|
|
342
276
|
const results = []
|
|
343
277
|
|
|
344
278
|
for (const key of matchingKeys) {
|
|
@@ -385,22 +319,12 @@ export default class WebCryptoSecretStorageProvider {
|
|
|
385
319
|
throw new SecretStorageException('Passphrase required for secret decryption')
|
|
386
320
|
}
|
|
387
321
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
322
|
+
if (!await this.isAvailable()) {
|
|
323
|
+
throw SecretStorageException.unavailable(this.providerType, 'WebCrypto API is not available')
|
|
324
|
+
}
|
|
391
325
|
|
|
392
326
|
try {
|
|
393
|
-
const
|
|
394
|
-
const decryptedBuffer = await globalThis.crypto.subtle.decrypt(
|
|
395
|
-
{
|
|
396
|
-
name: 'AES-GCM',
|
|
397
|
-
iv
|
|
398
|
-
},
|
|
399
|
-
key,
|
|
400
|
-
ciphertext
|
|
401
|
-
)
|
|
402
|
-
|
|
403
|
-
const decryptedBytes = new Uint8Array(decryptedBuffer)
|
|
327
|
+
const decryptedBytes = await openEnvelope(payload, passphrase)
|
|
404
328
|
return await withSecureBytes(decryptedBytes, async (bytes) => {
|
|
405
329
|
const secretString = textDecoder.decode(bytes)
|
|
406
330
|
return await fn(secretString)
|
|
@@ -413,4 +337,58 @@ export default class WebCryptoSecretStorageProvider {
|
|
|
413
337
|
throw SecretStorageException.decryptionFailed(msg)
|
|
414
338
|
}
|
|
415
339
|
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Recover a secret using its recovery envelope and re-enroll it
|
|
343
|
+
*
|
|
344
|
+
* @param {string} bundleHash
|
|
345
|
+
* @param {string} recoveryPassphrase
|
|
346
|
+
* @param {{ label?: string, passphrase?: string }} [options]
|
|
347
|
+
* @returns {Promise<void>}
|
|
348
|
+
*/
|
|
349
|
+
async recoverSecret (bundleHash, recoveryPassphrase, options = {}) {
|
|
350
|
+
if (!bundleHash) {
|
|
351
|
+
throw new SecretStorageException('Bundle hash cannot be empty')
|
|
352
|
+
}
|
|
353
|
+
if (!recoveryPassphrase) {
|
|
354
|
+
throw new SecretStorageException('Recovery passphrase cannot be empty')
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const raw = await this.backend.getItem(`${RECOVERY_KEY_PREFIX}${bundleHash}`)
|
|
358
|
+
if (!raw) {
|
|
359
|
+
throw SecretStorageException.notFound(bundleHash)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
let payload
|
|
363
|
+
try {
|
|
364
|
+
payload = JSON.parse(raw)
|
|
365
|
+
} catch {
|
|
366
|
+
throw SecretStorageException.decryptionFailed('Corrupted recovery payload format')
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
let decryptedBytes
|
|
370
|
+
try {
|
|
371
|
+
decryptedBytes = await openEnvelope(payload, recoveryPassphrase)
|
|
372
|
+
} catch (err) {
|
|
373
|
+
if (err instanceof SecretStorageException) {
|
|
374
|
+
throw err
|
|
375
|
+
}
|
|
376
|
+
const msg = err instanceof Error ? err.message : String(err)
|
|
377
|
+
throw SecretStorageException.decryptionFailed(msg)
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
let secretStr
|
|
381
|
+
try {
|
|
382
|
+
secretStr = textDecoder.decode(decryptedBytes)
|
|
383
|
+
} finally {
|
|
384
|
+
zeroizeBytes(decryptedBytes)
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
const storePassphrase = options.passphrase || this.defaultPassphrase || recoveryPassphrase
|
|
388
|
+
await this.storeSecret(bundleHash, secretStr, {
|
|
389
|
+
...options,
|
|
390
|
+
passphrase: storePassphrase,
|
|
391
|
+
recoveryPassphrase
|
|
392
|
+
})
|
|
393
|
+
}
|
|
416
394
|
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/*
|
|
2
|
+
(
|
|
3
|
+
(/(
|
|
4
|
+
(//(
|
|
5
|
+
(///(
|
|
6
|
+
(/////(
|
|
7
|
+
(//////( )
|
|
8
|
+
(////////( (/)
|
|
9
|
+
(////////( (///)
|
|
10
|
+
(//////////( (////)
|
|
11
|
+
(//////////( (//////)
|
|
12
|
+
(////////////( (///////)
|
|
13
|
+
(/////////////( (/////////)
|
|
14
|
+
(//////////////( (///////////)
|
|
15
|
+
(///////////////( (/////////////)
|
|
16
|
+
(////////////////( (//////////////)
|
|
17
|
+
((((((((((((((((((( (((((((((((((((
|
|
18
|
+
((((((((((((((((((( ((((((((((((((
|
|
19
|
+
((((((((((((((((((( ((((((((((((((
|
|
20
|
+
(((((((((((((((((((( (((((((((((((
|
|
21
|
+
(((((((((((((((((((( ((((((((((((
|
|
22
|
+
((((((((((((((((((( ((((((((((((
|
|
23
|
+
((((((((((((((((((( ((((((((((
|
|
24
|
+
((((((((((((((((((/ (((((((((
|
|
25
|
+
(((((((((((((((((( ((((((((
|
|
26
|
+
((((((((((((((((( (((((((
|
|
27
|
+
(((((((((((((((((( (((((
|
|
28
|
+
################# ##
|
|
29
|
+
################ #
|
|
30
|
+
################# ##
|
|
31
|
+
%################ ###
|
|
32
|
+
###############( ####
|
|
33
|
+
############### ####
|
|
34
|
+
############### ######
|
|
35
|
+
%#############( (#######
|
|
36
|
+
%############# #########
|
|
37
|
+
############( ##########
|
|
38
|
+
########### #############
|
|
39
|
+
######### ##############
|
|
40
|
+
%######
|
|
41
|
+
|
|
42
|
+
Powered by Knish.IO: Connecting a Decentralized World
|
|
43
|
+
|
|
44
|
+
Please visit https://github.com/WishKnish/KnishIO-Client-JS for information.
|
|
45
|
+
|
|
46
|
+
License: https://github.com/WishKnish/KnishIO-Client-JS/blob/master/LICENSE
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
import SecretStorageException from '../exception/SecretStorageException.js'
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Browser persistent storage backend wrapping Web Storage (localStorage or sessionStorage).
|
|
53
|
+
* Adapts the Web Storage API (length + key(i)) to IStorageBackend.keys(), filtering
|
|
54
|
+
* by a prefix (defaults to 'knishio:') so unrelated items are ignored.
|
|
55
|
+
*/
|
|
56
|
+
export default class WebStorageBackend {
|
|
57
|
+
/**
|
|
58
|
+
* @param {Storage} [storage]
|
|
59
|
+
* @param {string} [prefix]
|
|
60
|
+
*/
|
|
61
|
+
constructor (storage, prefix = 'knishio:') {
|
|
62
|
+
if (storage) {
|
|
63
|
+
this.storage = storage
|
|
64
|
+
} else if (typeof globalThis !== 'undefined' && globalThis.localStorage) {
|
|
65
|
+
this.storage = globalThis.localStorage
|
|
66
|
+
} else {
|
|
67
|
+
throw SecretStorageException.unavailable(
|
|
68
|
+
'web-storage',
|
|
69
|
+
'WebStorageBackend requires a Storage object or global localStorage'
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
this.prefix = prefix
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @param {string} key
|
|
77
|
+
* @returns {string|null}
|
|
78
|
+
*/
|
|
79
|
+
getItem (key) {
|
|
80
|
+
return this.storage.getItem(key)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @param {string} key
|
|
85
|
+
* @param {string} value
|
|
86
|
+
*/
|
|
87
|
+
setItem (key, value) {
|
|
88
|
+
this.storage.setItem(key, value)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @param {string} key
|
|
93
|
+
* @returns {boolean}
|
|
94
|
+
*/
|
|
95
|
+
removeItem (key) {
|
|
96
|
+
const existed = this.storage.getItem(key) !== null
|
|
97
|
+
this.storage.removeItem(key)
|
|
98
|
+
return existed
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @returns {string[]}
|
|
103
|
+
*/
|
|
104
|
+
keys () {
|
|
105
|
+
const result = []
|
|
106
|
+
const len = this.storage.length
|
|
107
|
+
for (let i = 0; i < len; i++) {
|
|
108
|
+
const k = this.storage.key(i)
|
|
109
|
+
if (k !== null) {
|
|
110
|
+
if (!this.prefix || k.startsWith(this.prefix)) {
|
|
111
|
+
result.push(k)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return result
|
|
116
|
+
}
|
|
117
|
+
}
|
package/src/storage/index.js
CHANGED
|
@@ -51,6 +51,29 @@ export {
|
|
|
51
51
|
default as WebCryptoSecretStorageProvider,
|
|
52
52
|
MemoryStorageBackend
|
|
53
53
|
} from './WebCryptoSecretStorageProvider.js'
|
|
54
|
+
export { default as FileStorageBackend } from './FileStorageBackend.js'
|
|
55
|
+
export { default as WebStorageBackend } from './WebStorageBackend.js'
|
|
56
|
+
export {
|
|
57
|
+
default as WebAuthnPrfSecretStorageProvider,
|
|
58
|
+
PRF_SALT_LABEL,
|
|
59
|
+
KEK_INFO
|
|
60
|
+
} from './WebAuthnPrfSecretStorageProvider.js'
|
|
61
|
+
export {
|
|
62
|
+
default as NonExtractableKeySecretStorageProvider,
|
|
63
|
+
IndexedDbKeyStore,
|
|
64
|
+
MemoryKeyStore
|
|
65
|
+
} from './NonExtractableKeySecretStorageProvider.js'
|
|
66
|
+
export {
|
|
67
|
+
sealEnvelope,
|
|
68
|
+
openEnvelope,
|
|
69
|
+
uint8ArrayToBase64,
|
|
70
|
+
base64ToUint8Array,
|
|
71
|
+
deriveEnvelopeKey,
|
|
72
|
+
ENVELOPE_ALGORITHM,
|
|
73
|
+
DEFAULT_ITERATIONS,
|
|
74
|
+
SECRET_KEY_PREFIX,
|
|
75
|
+
RECOVERY_KEY_PREFIX
|
|
76
|
+
} from './secretEnvelope.js'
|
|
54
77
|
|
|
55
78
|
import MemorySecretStorageProvider from './MemorySecretStorageProvider.js'
|
|
56
79
|
import WebCryptoSecretStorageProvider from './WebCryptoSecretStorageProvider.js'
|
|
@@ -58,7 +81,7 @@ import WebCryptoSecretStorageProvider from './WebCryptoSecretStorageProvider.js'
|
|
|
58
81
|
/**
|
|
59
82
|
* Factory function to create a secret storage provider
|
|
60
83
|
*
|
|
61
|
-
* @param {{ type?: 'webcrypto'|'memory', defaultPassphrase?: string, backend?: object
|
|
84
|
+
* @param {{ type?: 'webcrypto'|'memory', defaultPassphrase?: string, backend?: object }} [options]
|
|
62
85
|
* @returns {object}
|
|
63
86
|
*/
|
|
64
87
|
export function createDefaultSecretStorage (options = {}) {
|
|
@@ -70,8 +93,7 @@ export function createDefaultSecretStorage (options = {}) {
|
|
|
70
93
|
if (typeof globalThis.crypto !== 'undefined' && typeof globalThis.crypto.subtle !== 'undefined') {
|
|
71
94
|
return new WebCryptoSecretStorageProvider({
|
|
72
95
|
backend: options.backend,
|
|
73
|
-
defaultPassphrase: options.defaultPassphrase
|
|
74
|
-
hardwareBacked: options.hardwareBacked
|
|
96
|
+
defaultPassphrase: options.defaultPassphrase
|
|
75
97
|
})
|
|
76
98
|
}
|
|
77
99
|
|