@tgoliveira/vault-core 0.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/API_REFERENCE.md +36 -0
- package/ARCHITECTURE.md +32 -0
- package/LICENSE +21 -0
- package/MIGRATION_FROM_LIQSENSE.md +42 -0
- package/PASSKEY_PRF_ENVELOPES.md +9 -0
- package/PASSWORD_ENVELOPES.md +7 -0
- package/README.md +78 -0
- package/RECOVERY_PHRASE.md +9 -0
- package/SECURITY.md +31 -0
- package/dist/browser.d.ts +11 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +71 -0
- package/dist/browser.js.map +1 -0
- package/dist/constants.d.ts +5 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +5 -0
- package/dist/constants.js.map +1 -0
- package/dist/crypto/aad.d.ts +4 -0
- package/dist/crypto/aad.d.ts.map +1 -0
- package/dist/crypto/aad.js +23 -0
- package/dist/crypto/aad.js.map +1 -0
- package/dist/crypto/aes-gcm.d.ts +9 -0
- package/dist/crypto/aes-gcm.d.ts.map +1 -0
- package/dist/crypto/aes-gcm.js +58 -0
- package/dist/crypto/aes-gcm.js.map +1 -0
- package/dist/crypto/encoding.d.ts +6 -0
- package/dist/crypto/encoding.d.ts.map +1 -0
- package/dist/crypto/encoding.js +27 -0
- package/dist/crypto/encoding.js.map +1 -0
- package/dist/crypto/random.d.ts +2 -0
- package/dist/crypto/random.d.ts.map +1 -0
- package/dist/crypto/random.js +4 -0
- package/dist/crypto/random.js.map +1 -0
- package/dist/crypto/serialization.d.ts +3 -0
- package/dist/crypto/serialization.d.ts.map +1 -0
- package/dist/crypto/serialization.js +7 -0
- package/dist/crypto/serialization.js.map +1 -0
- package/dist/envelopes/passkey-prf.d.ts +21 -0
- package/dist/envelopes/passkey-prf.d.ts.map +1 -0
- package/dist/envelopes/passkey-prf.js +78 -0
- package/dist/envelopes/passkey-prf.js.map +1 -0
- package/dist/envelopes/password.d.ts +20 -0
- package/dist/envelopes/password.d.ts.map +1 -0
- package/dist/envelopes/password.js +41 -0
- package/dist/envelopes/password.js.map +1 -0
- package/dist/envelopes/recovery.d.ts +46 -0
- package/dist/envelopes/recovery.d.ts.map +1 -0
- package/dist/envelopes/recovery.js +167 -0
- package/dist/envelopes/recovery.js.map +1 -0
- package/dist/errors/vault-errors.d.ts +20 -0
- package/dist/errors/vault-errors.d.ts.map +1 -0
- package/dist/errors/vault-errors.js +37 -0
- package/dist/errors/vault-errors.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/kdf/argon2id.d.ts +24 -0
- package/dist/kdf/argon2id.d.ts.map +1 -0
- package/dist/kdf/argon2id.js +57 -0
- package/dist/kdf/argon2id.js.map +1 -0
- package/dist/kdf/params.d.ts +9 -0
- package/dist/kdf/params.d.ts.map +1 -0
- package/dist/kdf/params.js +8 -0
- package/dist/kdf/params.js.map +1 -0
- package/dist/keys/user-vault-key.d.ts +7 -0
- package/dist/keys/user-vault-key.d.ts.map +1 -0
- package/dist/keys/user-vault-key.js +15 -0
- package/dist/keys/user-vault-key.js.map +1 -0
- package/dist/payload/encrypted-payload.d.ts +5 -0
- package/dist/payload/encrypted-payload.d.ts.map +1 -0
- package/dist/payload/encrypted-payload.js +14 -0
- package/dist/payload/encrypted-payload.js.map +1 -0
- package/dist/profile.d.ts +21 -0
- package/dist/profile.d.ts.map +1 -0
- package/dist/profile.js +9 -0
- package/dist/profile.js.map +1 -0
- package/dist/react/index.d.ts +6 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +6 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/session/use-vault-session.d.ts +11 -0
- package/dist/react/session/use-vault-session.d.ts.map +1 -0
- package/dist/react/session/use-vault-session.js +29 -0
- package/dist/react/session/use-vault-session.js.map +1 -0
- package/dist/react/session/use-vault-unlocked.d.ts +3 -0
- package/dist/react/session/use-vault-unlocked.d.ts.map +1 -0
- package/dist/react/session/use-vault-unlocked.js +9 -0
- package/dist/react/session/use-vault-unlocked.js.map +1 -0
- package/dist/react/session/vault-session-provider.d.ts +9 -0
- package/dist/react/session/vault-session-provider.d.ts.map +1 -0
- package/dist/react/session/vault-session-provider.js +16 -0
- package/dist/react/session/vault-session-provider.js.map +1 -0
- package/dist/react/status/resolve-vault-client-status.d.ts +8 -0
- package/dist/react/status/resolve-vault-client-status.d.ts.map +1 -0
- package/dist/react/status/resolve-vault-client-status.js +13 -0
- package/dist/react/status/resolve-vault-client-status.js.map +1 -0
- package/dist/react/status/use-vault-client-status.d.ts +3 -0
- package/dist/react/status/use-vault-client-status.d.ts.map +1 -0
- package/dist/react/status/use-vault-client-status.js +8 -0
- package/dist/react/status/use-vault-client-status.js.map +1 -0
- package/dist/recovery/kit.d.ts +16 -0
- package/dist/recovery/kit.d.ts.map +1 -0
- package/dist/recovery/kit.js +33 -0
- package/dist/recovery/kit.js.map +1 -0
- package/dist/session/auto-lock.d.ts +18 -0
- package/dist/session/auto-lock.d.ts.map +1 -0
- package/dist/session/auto-lock.js +86 -0
- package/dist/session/auto-lock.js.map +1 -0
- package/dist/session/memory-session.d.ts +8 -0
- package/dist/session/memory-session.d.ts.map +1 -0
- package/dist/session/memory-session.js +20 -0
- package/dist/session/memory-session.js.map +1 -0
- package/dist/testing/fixtures/liqsense-compat.d.ts +32 -0
- package/dist/testing/fixtures/liqsense-compat.d.ts.map +1 -0
- package/dist/testing/fixtures/liqsense-compat.js +31 -0
- package/dist/testing/fixtures/liqsense-compat.js.map +1 -0
- package/dist/testing/no-plaintext.d.ts +2 -0
- package/dist/testing/no-plaintext.d.ts.map +1 -0
- package/dist/testing/no-plaintext.js +2 -0
- package/dist/testing/no-plaintext.js.map +1 -0
- package/dist/testing.d.ts +2 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +2 -0
- package/dist/testing.js.map +1 -0
- package/dist/validation/aad-assert.d.ts +5 -0
- package/dist/validation/aad-assert.d.ts.map +1 -0
- package/dist/validation/aad-assert.js +29 -0
- package/dist/validation/aad-assert.js.map +1 -0
- package/dist/validation/plaintext-reject.d.ts +23 -0
- package/dist/validation/plaintext-reject.d.ts.map +1 -0
- package/dist/validation/plaintext-reject.js +75 -0
- package/dist/validation/plaintext-reject.js.map +1 -0
- package/dist/validation/schemas.d.ts +203 -0
- package/dist/validation/schemas.d.ts.map +1 -0
- package/dist/validation/schemas.js +39 -0
- package/dist/validation/schemas.js.map +1 -0
- package/package.json +100 -0
package/API_REFERENCE.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# API Reference
|
|
2
|
+
|
|
3
|
+
See TypeScript exports from:
|
|
4
|
+
|
|
5
|
+
- `@tgoliveira/vault-core`
|
|
6
|
+
- `@tgoliveira/vault-core/browser`
|
|
7
|
+
- `@tgoliveira/vault-core/testing`
|
|
8
|
+
- `@tgoliveira/vault-core/react`
|
|
9
|
+
|
|
10
|
+
## Core types
|
|
11
|
+
|
|
12
|
+
- `VaultCryptoProfile`, `VaultCryptoVersion`
|
|
13
|
+
- `EncryptedVaultPayload`, `VaultEnvelope`, `PasswordEnvelope`, `RecoveryPhraseEnvelope`, `PasskeyPrfEnvelope`
|
|
14
|
+
- `RecoveryPhraseWordCount` (`12 | 24`)
|
|
15
|
+
- `VaultUnlockResult<TPayload>`, `VaultCoreError`
|
|
16
|
+
|
|
17
|
+
## Core functions
|
|
18
|
+
|
|
19
|
+
- `createUserVaultKey()`
|
|
20
|
+
- `encryptVaultPayload<T>(payload, key, scope, profile)`
|
|
21
|
+
- `decryptVaultPayload<T>(encrypted, key)`
|
|
22
|
+
- `createPasswordEnvelope` / `unlockWithPasswordEnvelope`
|
|
23
|
+
- `createRecoveryPhrase` / `createRecoveryEnvelope` / `unlockWithRecoveryEnvelope`
|
|
24
|
+
- `createPasskeyPrfEnvelope` / `unlockWithPasskeyPrfEnvelope`
|
|
25
|
+
- `createRecoveryKitText(...)`
|
|
26
|
+
- `assertVaultKeyAad` / `assertVaultPayloadAad`
|
|
27
|
+
- `assertNoVaultPlaintextFields` / `validateNoPlaintextLeak`
|
|
28
|
+
|
|
29
|
+
Deprecated aliases (`wrapVaultKeyForPassword`, etc.) remain for migration.
|
|
30
|
+
|
|
31
|
+
## React entry (`@tgoliveira/vault-core/react`)
|
|
32
|
+
|
|
33
|
+
- `useVaultUnlocked()`, `useVaultLockState()`
|
|
34
|
+
- `useVaultSession()`, `VaultSessionProvider`
|
|
35
|
+
- `resolveVaultClientStatus()`, `useVaultClientStatus()`
|
|
36
|
+
- `VaultClientStatus`, `VaultServerStatusSnapshot`
|
package/ARCHITECTURE.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Vault Core Architecture
|
|
2
|
+
|
|
3
|
+
## User Vault Key (UVK)
|
|
4
|
+
|
|
5
|
+
256-bit AES-GCM key generated client-side. Wrapped by envelopes; encrypts app payload JSON.
|
|
6
|
+
|
|
7
|
+
## Envelopes
|
|
8
|
+
|
|
9
|
+
| Method | KDF | Wraps |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| Password | Argon2id | UVK |
|
|
12
|
+
| Recovery phrase | Argon2id (BIP39 normalized phrase) | UVK |
|
|
13
|
+
| Passkey PRF | PRF output → AES key | UVK |
|
|
14
|
+
|
|
15
|
+
Envelope AAD field: `vault_key` with app `aadContextEnvelope`.
|
|
16
|
+
|
|
17
|
+
## Encrypted payload
|
|
18
|
+
|
|
19
|
+
Generic JSON encrypted under UVK. AAD field: `vault_payload` with app `aadContextVault`.
|
|
20
|
+
|
|
21
|
+
Format: `enc-v1` / `AES-GCM` / `kdf-v1`.
|
|
22
|
+
|
|
23
|
+
## Package layers
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
@tgoliveira/vault-core crypto + envelopes + payload + validation
|
|
27
|
+
@tgoliveira/vault-core/browser session + auto-lock + PRF salt + kit DOM
|
|
28
|
+
@tgoliveira/vault-core/testing sentinels + scan helpers
|
|
29
|
+
@tgoliveira/vault-core/react headless React session/status hooks
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Apps own: persistence, routes, product UI, product payload schema, WebAuthn ceremony.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Thiago Oliveira
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Migration from LiqSense
|
|
2
|
+
|
|
3
|
+
## LiqSense profile (frozen)
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
export const LIQSENSE_VAULT_PROFILE = {
|
|
7
|
+
cryptoVersion: "vault-v1",
|
|
8
|
+
aadContextVault: "liqsense:vault:v1",
|
|
9
|
+
aadContextEnvelope: "liqsense:vault-envelope:v1",
|
|
10
|
+
};
|
|
11
|
+
export const LIQSENSE_PRF_SALT_PREFIX = "liqsense-passkey-prf-v1:";
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Import mapping
|
|
15
|
+
|
|
16
|
+
| LiqSense (legacy) | vault-core |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| `generateUserVaultKey` | `createUserVaultKey` |
|
|
19
|
+
| `wrapVaultKeyForPassword` | `createPasswordEnvelope` + profile |
|
|
20
|
+
| `unwrapVaultKeyFromPassword` | `unlockWithPasswordEnvelope` |
|
|
21
|
+
| `wrapVaultKeyForRecoveryPhrase` | `createRecoveryEnvelope` + profile |
|
|
22
|
+
| `generateRecoveryPhrase` | `createRecoveryPhrase` |
|
|
23
|
+
|
|
24
|
+
LiqSense keeps thin wrappers in `src/modules/vault/core/` binding `LIQSENSE_VAULT_PROFILE`.
|
|
25
|
+
|
|
26
|
+
## Local dev
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
"@tgoliveira/vault-core": "file:../vault-core"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Build vault-core first. LiqSense uses `next build --webpack` for local package resolution.
|
|
33
|
+
|
|
34
|
+
## React hooks
|
|
35
|
+
|
|
36
|
+
Import from `@tgoliveira/vault-core/react` (not a separate package):
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { useVaultUnlocked, resolveVaultClientStatus } from "@tgoliveira/vault-core/react";
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The standalone `@tgoliveira/vault-react` package is deprecated.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Passkey PRF Envelopes
|
|
2
|
+
|
|
3
|
+
- Separate from account passkey login
|
|
4
|
+
- App provides PRF output bytes (≥ 32 bytes) from WebAuthn ceremony
|
|
5
|
+
- Package wraps UVK with PRF-derived AES key
|
|
6
|
+
- API: `createPasskeyPrfEnvelope` / `unlockWithPasskeyPrfEnvelope`
|
|
7
|
+
- Browser helpers: `buildPrfSaltBytes(prefix, userId)`, capability probes
|
|
8
|
+
|
|
9
|
+
PRF output never sent to server. WebAuthn ceremony stays in the app.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Password Envelopes
|
|
2
|
+
|
|
3
|
+
- Vault password normalized with NFKC before Argon2id
|
|
4
|
+
- Default params: memory 65536 KiB, iterations 3, parallelism 1, 32-byte hash, 16-byte salt
|
|
5
|
+
- API: `createPasswordEnvelope` / `unlockWithPasswordEnvelope`
|
|
6
|
+
|
|
7
|
+
Vault password never sent to server.
|
package/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# @tgoliveira/vault-core
|
|
2
|
+
|
|
3
|
+
Framework-independent vault crypto primitives extracted from LiqSense.
|
|
4
|
+
|
|
5
|
+
## Scope
|
|
6
|
+
|
|
7
|
+
- User Vault Key (UVK) generation
|
|
8
|
+
- AES-GCM encrypted payloads with canonical AAD
|
|
9
|
+
- Argon2id password and recovery phrase envelopes
|
|
10
|
+
- Passkey PRF envelope wrap/unwrap (PRF bytes only — no WebAuthn ceremony)
|
|
11
|
+
- BIP39 12/24-word recovery phrases
|
|
12
|
+
- No-plaintext validation helpers
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @tgoliveira/vault-core
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Local development with LiqSense:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
"@tgoliveira/vault-core": "file:../vault-core"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Build vault-core before consuming:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
cd ../vault-core && npm run validate
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quick start
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import {
|
|
36
|
+
createUserVaultKey,
|
|
37
|
+
createPasswordEnvelope,
|
|
38
|
+
unlockWithPasswordEnvelope,
|
|
39
|
+
encryptVaultPayload,
|
|
40
|
+
decryptVaultPayload,
|
|
41
|
+
type VaultCryptoProfile,
|
|
42
|
+
} from "@tgoliveira/vault-core";
|
|
43
|
+
|
|
44
|
+
const profile: VaultCryptoProfile = {
|
|
45
|
+
cryptoVersion: "vault-v1",
|
|
46
|
+
aadContextVault: "myapp:vault:v1",
|
|
47
|
+
aadContextEnvelope: "myapp:vault-envelope:v1",
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const userId = "00000000-0000-4000-8000-000000000001";
|
|
51
|
+
const scope = { userId, resourceId: userId };
|
|
52
|
+
const vaultKey = await createUserVaultKey();
|
|
53
|
+
|
|
54
|
+
const { envelope } = await createPasswordEnvelope(
|
|
55
|
+
vaultKey,
|
|
56
|
+
userVaultPassword,
|
|
57
|
+
scope,
|
|
58
|
+
profile
|
|
59
|
+
);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Exports
|
|
63
|
+
|
|
64
|
+
| Entry | Purpose |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| `@tgoliveira/vault-core` | Core crypto, envelopes, payload, validation |
|
|
67
|
+
| `@tgoliveira/vault-core/browser` | In-memory session, auto-lock, PRF salt, recovery kit DOM helpers |
|
|
68
|
+
| `@tgoliveira/vault-core/testing` | Sentinels and plaintext scan helpers |
|
|
69
|
+
| `@tgoliveira/vault-core/react` | Headless React session/status hooks (optional peer: `react`) |
|
|
70
|
+
|
|
71
|
+
## Boundaries
|
|
72
|
+
|
|
73
|
+
- Does **not** include account authentication
|
|
74
|
+
- Does **not** require React, Next.js, or product payload schemas on the default entry
|
|
75
|
+
- `./react` is optional and requires `react >= 18`
|
|
76
|
+
- Vault password, recovery phrase, UVK, PRF output, and decrypted payload must stay client-side
|
|
77
|
+
|
|
78
|
+
See `SECURITY.md`, `ARCHITECTURE.md`, and `MIGRATION_FROM_LIQSENSE.md`.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Recovery Phrase
|
|
2
|
+
|
|
3
|
+
- BIP39 English wordlist via `@scure/bip39`
|
|
4
|
+
- Supported lengths: **12 words** (128-bit) and **24 words** (256-bit, default)
|
|
5
|
+
- Normalization: trim, lowercase, single-space separated
|
|
6
|
+
- Confirmation helpers: deterministic word indices (3 for 12 words, 4 for 24)
|
|
7
|
+
- Recovery kit text via `createRecoveryKitText({ productName, ... })`
|
|
8
|
+
|
|
9
|
+
Recovery phrase never sent to server.
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Vault Core Security Model
|
|
2
|
+
|
|
3
|
+
## Separation from account auth
|
|
4
|
+
|
|
5
|
+
Account login, password reset, TOTP, OAuth, and passkey **login** must not unlock the vault.
|
|
6
|
+
|
|
7
|
+
Vault unlock requires a separate vault password, recovery phrase, or passkey PRF envelope.
|
|
8
|
+
|
|
9
|
+
## Server must never receive
|
|
10
|
+
|
|
11
|
+
- Vault password
|
|
12
|
+
- Recovery phrase (plaintext)
|
|
13
|
+
- User Vault Key
|
|
14
|
+
- PRF output
|
|
15
|
+
- Decrypted vault payload
|
|
16
|
+
|
|
17
|
+
Use `assertNoVaultPlaintextFields()` on API request bodies.
|
|
18
|
+
|
|
19
|
+
## Client must never persist
|
|
20
|
+
|
|
21
|
+
- Decrypted vault payload in localStorage or IndexedDB
|
|
22
|
+
|
|
23
|
+
Browser session helpers clear UVK on lock and `pagehide`.
|
|
24
|
+
|
|
25
|
+
## Crypto constants (per app profile)
|
|
26
|
+
|
|
27
|
+
Apps define `VaultCryptoProfile` with stable AAD contexts. Existing ciphertext breaks if contexts change.
|
|
28
|
+
|
|
29
|
+
## Logging
|
|
30
|
+
|
|
31
|
+
Never log vault secrets, request bodies containing envelopes, or decrypted payloads.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { extractPasskeyPrfOutput, isPasskeySupported, isPrfExtensionSupported } from "./envelopes/passkey-prf.js";
|
|
2
|
+
export declare function buildPrfSaltBytes(prefix: string, userId: string): Promise<ArrayBuffer>;
|
|
3
|
+
export declare function createRecoveryKitDownload(content: string, filename: string): void;
|
|
4
|
+
export declare function printRecoveryKitContent(content: string): void;
|
|
5
|
+
export declare function assertNoDecryptedVaultInLocalStorage(storagePrefix: string): boolean;
|
|
6
|
+
export declare function assertNoDecryptedVaultInIndexedDB(storagePrefix: string): Promise<boolean>;
|
|
7
|
+
export declare function persistVaultRecordLocally(): never;
|
|
8
|
+
export { extractPasskeyPrfOutput, isPasskeySupported, isPrfExtensionSupported, };
|
|
9
|
+
export { configureVaultSession, subscribeVaultSession, isVaultManuallyLocked, clearVaultAutoLockTimer, scheduleVaultAutoLock, touchVaultSession, unlockVaultSession, lockVaultSession, lockVaultSessionManually, resetVaultSessionLockState, registerVaultUnloadGuard, getVaultAutoLockRemainingMs, getSessionVaultKey, setSessionVaultKey, lockVault, isVaultUnlocked, clearVaultClientState, type VaultSessionConfig, } from "./session/auto-lock.js";
|
|
10
|
+
export { createRecoveryKitText, buildRecoveryKitContent } from "./recovery/kit.js";
|
|
11
|
+
//# sourceMappingURL=browser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AACA,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,uBAAuB,EACxB,MAAM,4BAA4B,CAAC;AAEpC,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAG5F;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,IAAI,CASN;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAU7D;AASD,wBAAgB,oCAAoC,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAWnF;AAED,wBAAsB,iCAAiC,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAgB/F;AAED,wBAAgB,yBAAyB,IAAI,KAAK,CAEjD;AAED,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,uBAAuB,GACxB,CAAC;AAEF,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,wBAAwB,EACxB,0BAA0B,EAC1B,wBAAwB,EACxB,2BAA2B,EAC3B,kBAAkB,EAClB,kBAAkB,EAClB,SAAS,EACT,eAAe,EACf,qBAAqB,EACrB,KAAK,kBAAkB,GACxB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/browser.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { stringToBytes, toBufferSource } from "./crypto/encoding.js";
|
|
2
|
+
import { extractPasskeyPrfOutput, isPasskeySupported, isPrfExtensionSupported, } from "./envelopes/passkey-prf.js";
|
|
3
|
+
export async function buildPrfSaltBytes(prefix, userId) {
|
|
4
|
+
const input = toBufferSource(stringToBytes(`${prefix}${userId}`));
|
|
5
|
+
return crypto.subtle.digest("SHA-256", input);
|
|
6
|
+
}
|
|
7
|
+
export function createRecoveryKitDownload(content, filename) {
|
|
8
|
+
if (typeof window === "undefined")
|
|
9
|
+
return;
|
|
10
|
+
const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
|
|
11
|
+
const url = URL.createObjectURL(blob);
|
|
12
|
+
const anchor = document.createElement("a");
|
|
13
|
+
anchor.href = url;
|
|
14
|
+
anchor.download = filename;
|
|
15
|
+
anchor.click();
|
|
16
|
+
URL.revokeObjectURL(url);
|
|
17
|
+
}
|
|
18
|
+
export function printRecoveryKitContent(content) {
|
|
19
|
+
if (typeof window === "undefined")
|
|
20
|
+
return;
|
|
21
|
+
const printWindow = window.open("", "_blank", "noopener,noreferrer,width=640,height=720");
|
|
22
|
+
if (!printWindow)
|
|
23
|
+
return;
|
|
24
|
+
printWindow.document.write(`<pre style="font-family:monospace;white-space:pre-wrap;padding:24px;">${escapeHtml(content)}</pre>`);
|
|
25
|
+
printWindow.document.close();
|
|
26
|
+
printWindow.focus();
|
|
27
|
+
printWindow.print();
|
|
28
|
+
}
|
|
29
|
+
function escapeHtml(value) {
|
|
30
|
+
return value
|
|
31
|
+
.replace(/&/g, "&")
|
|
32
|
+
.replace(/</g, "<")
|
|
33
|
+
.replace(/>/g, ">");
|
|
34
|
+
}
|
|
35
|
+
export function assertNoDecryptedVaultInLocalStorage(storagePrefix) {
|
|
36
|
+
if (typeof window === "undefined")
|
|
37
|
+
return true;
|
|
38
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
39
|
+
const key = localStorage.key(i);
|
|
40
|
+
if (!key)
|
|
41
|
+
continue;
|
|
42
|
+
if (key.startsWith(storagePrefix)) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
export async function assertNoDecryptedVaultInIndexedDB(storagePrefix) {
|
|
49
|
+
if (typeof window === "undefined" || typeof indexedDB === "undefined")
|
|
50
|
+
return true;
|
|
51
|
+
return new Promise((resolve) => {
|
|
52
|
+
const request = indexedDB.databases?.();
|
|
53
|
+
if (!request) {
|
|
54
|
+
resolve(true);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
void request
|
|
58
|
+
.then((databases) => {
|
|
59
|
+
const hasVaultDb = databases.some((db) => db.name?.startsWith(storagePrefix));
|
|
60
|
+
resolve(!hasVaultDb);
|
|
61
|
+
})
|
|
62
|
+
.catch(() => resolve(true));
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
export function persistVaultRecordLocally() {
|
|
66
|
+
throw new Error("Decrypted vault state must not be persisted to localStorage or IndexedDB");
|
|
67
|
+
}
|
|
68
|
+
export { extractPasskeyPrfOutput, isPasskeySupported, isPrfExtensionSupported, };
|
|
69
|
+
export { configureVaultSession, subscribeVaultSession, isVaultManuallyLocked, clearVaultAutoLockTimer, scheduleVaultAutoLock, touchVaultSession, unlockVaultSession, lockVaultSession, lockVaultSessionManually, resetVaultSessionLockState, registerVaultUnloadGuard, getVaultAutoLockRemainingMs, getSessionVaultKey, setSessionVaultKey, lockVault, isVaultUnlocked, clearVaultClientState, } from "./session/auto-lock.js";
|
|
70
|
+
export { createRecoveryKitText, buildRecoveryKitContent } from "./recovery/kit.js";
|
|
71
|
+
//# sourceMappingURL=browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,EAAG,QAAiB,CAAC;AACpD,eAAO,MAAM,cAAc,EAAG,SAAkB,CAAC;AACjD,eAAO,MAAM,oBAAoB,EAAG,UAAmB,CAAC;AACxD,eAAO,MAAM,+BAA+B,KAAK,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,kBAAkB,GAAG,QAAiB,CAAC;AACpD,MAAM,CAAC,MAAM,cAAc,GAAG,SAAkB,CAAC;AACjD,MAAM,CAAC,MAAM,oBAAoB,GAAG,UAAmB,CAAC;AACxD,MAAM,CAAC,MAAM,+BAA+B,GAAG,EAAE,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { EncryptedVaultPayload } from "../validation/schemas.js";
|
|
2
|
+
export declare function canonicalAadString(aad: EncryptedVaultPayload["aad"]): string;
|
|
3
|
+
export declare function aadByteCandidates(aad: EncryptedVaultPayload["aad"]): Uint8Array[];
|
|
4
|
+
//# sourceMappingURL=aad.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aad.d.ts","sourceRoot":"","sources":["../../src/crypto/aad.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAGtE,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,qBAAqB,CAAC,KAAK,CAAC,GAAG,MAAM,CAO5E;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,qBAAqB,CAAC,KAAK,CAAC,GAAG,UAAU,EAAE,CAajF"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { stringToBytes } from "./encoding.js";
|
|
2
|
+
export function canonicalAadString(aad) {
|
|
3
|
+
return JSON.stringify({
|
|
4
|
+
context: aad.context,
|
|
5
|
+
field: aad.field,
|
|
6
|
+
resourceId: aad.resourceId,
|
|
7
|
+
userId: aad.userId,
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
export function aadByteCandidates(aad) {
|
|
11
|
+
const variants = new Set([
|
|
12
|
+
canonicalAadString(aad),
|
|
13
|
+
JSON.stringify({
|
|
14
|
+
userId: aad.userId,
|
|
15
|
+
resourceId: aad.resourceId,
|
|
16
|
+
field: aad.field,
|
|
17
|
+
context: aad.context,
|
|
18
|
+
}),
|
|
19
|
+
JSON.stringify(aad),
|
|
20
|
+
]);
|
|
21
|
+
return Array.from(variants).map((value) => stringToBytes(value));
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=aad.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aad.js","sourceRoot":"","sources":["../../src/crypto/aad.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,UAAU,kBAAkB,CAAC,GAAiC;IAClE,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,MAAM,EAAE,GAAG,CAAC,MAAM;KACnB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAiC;IACjE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAS;QAC/B,kBAAkB,CAAC,GAAG,CAAC;QACvB,IAAI,CAAC,SAAS,CAAC;YACb,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,OAAO,EAAE,GAAG,CAAC,OAAO;SACrB,CAAC;QACF,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;KACpB,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;AACnE,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { VaultCryptoProfile, VaultAadScope } from "../profile.js";
|
|
2
|
+
import type { EncryptedVaultPayload } from "../validation/schemas.js";
|
|
3
|
+
export declare function generateAesKey(): Promise<CryptoKey>;
|
|
4
|
+
export declare function importAesKey(rawKey: Uint8Array): Promise<CryptoKey>;
|
|
5
|
+
export declare function exportAesKey(key: CryptoKey): Promise<Uint8Array>;
|
|
6
|
+
export type EncryptFieldAad = VaultAadScope;
|
|
7
|
+
export declare function encryptField(plaintext: string, key: CryptoKey, aad: EncryptFieldAad, profile: VaultCryptoProfile): Promise<EncryptedVaultPayload>;
|
|
8
|
+
export declare function decryptField(payload: EncryptedVaultPayload, key: CryptoKey): Promise<string>;
|
|
9
|
+
//# sourceMappingURL=aes-gcm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aes-gcm.d.ts","sourceRoot":"","sources":["../../src/crypto/aes-gcm.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEvE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAYtE,wBAAsB,cAAc,IAAI,OAAO,CAAC,SAAS,CAAC,CAKzD;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAQzE;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAGtE;AAED,MAAM,MAAM,eAAe,GAAG,aAAa,CAAC;AAE5C,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,SAAS,EACd,GAAG,EAAE,eAAe,EACpB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,qBAAqB,CAAC,CAyBhC;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,qBAAqB,EAC9B,GAAG,EAAE,SAAS,GACb,OAAO,CAAC,MAAM,CAAC,CAuBjB"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ENCRYPTION_ALG, ENCRYPTION_VERSION } from "../constants.js";
|
|
2
|
+
import { resolveAadContext } from "../profile.js";
|
|
3
|
+
import { canonicalAadString, aadByteCandidates } from "./aad.js";
|
|
4
|
+
import { bytesToBase64Url, base64UrlToBytes, stringToBytes, bytesToString, toBufferSource, } from "./encoding.js";
|
|
5
|
+
const IV_LENGTH = 12;
|
|
6
|
+
export async function generateAesKey() {
|
|
7
|
+
return crypto.subtle.generateKey({ name: ENCRYPTION_ALG, length: 256 }, true, [
|
|
8
|
+
"encrypt",
|
|
9
|
+
"decrypt",
|
|
10
|
+
]);
|
|
11
|
+
}
|
|
12
|
+
export async function importAesKey(rawKey) {
|
|
13
|
+
return crypto.subtle.importKey("raw", toBufferSource(rawKey), { name: ENCRYPTION_ALG, length: 256 }, true, ["encrypt", "decrypt"]);
|
|
14
|
+
}
|
|
15
|
+
export async function exportAesKey(key) {
|
|
16
|
+
const raw = await crypto.subtle.exportKey("raw", key);
|
|
17
|
+
return new Uint8Array(raw);
|
|
18
|
+
}
|
|
19
|
+
export async function encryptField(plaintext, key, aad, profile) {
|
|
20
|
+
const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));
|
|
21
|
+
const aadWithContext = {
|
|
22
|
+
...aad,
|
|
23
|
+
context: resolveAadContext(aad, profile),
|
|
24
|
+
};
|
|
25
|
+
const aadBytes = stringToBytes(canonicalAadString(aadWithContext));
|
|
26
|
+
const ciphertextBuffer = await crypto.subtle.encrypt({
|
|
27
|
+
name: ENCRYPTION_ALG,
|
|
28
|
+
iv: toBufferSource(iv),
|
|
29
|
+
additionalData: toBufferSource(aadBytes),
|
|
30
|
+
}, key, toBufferSource(stringToBytes(plaintext)));
|
|
31
|
+
return {
|
|
32
|
+
version: ENCRYPTION_VERSION,
|
|
33
|
+
alg: ENCRYPTION_ALG,
|
|
34
|
+
iv: bytesToBase64Url(iv),
|
|
35
|
+
ciphertext: bytesToBase64Url(new Uint8Array(ciphertextBuffer)),
|
|
36
|
+
aad: aadWithContext,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export async function decryptField(payload, key) {
|
|
40
|
+
const iv = base64UrlToBytes(payload.iv);
|
|
41
|
+
const ciphertext = base64UrlToBytes(payload.ciphertext);
|
|
42
|
+
let lastError;
|
|
43
|
+
for (const aadBytes of aadByteCandidates(payload.aad)) {
|
|
44
|
+
try {
|
|
45
|
+
const plaintextBuffer = await crypto.subtle.decrypt({
|
|
46
|
+
name: ENCRYPTION_ALG,
|
|
47
|
+
iv: toBufferSource(iv),
|
|
48
|
+
additionalData: toBufferSource(aadBytes),
|
|
49
|
+
}, key, toBufferSource(ciphertext));
|
|
50
|
+
return bytesToString(new Uint8Array(plaintextBuffer));
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
lastError = error;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
throw lastError instanceof Error ? lastError : new Error("Decryption failed");
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=aes-gcm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aes-gcm.js","sourceRoot":"","sources":["../../src/crypto/aes-gcm.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function bytesToBase64Url(bytes: Uint8Array): string;
|
|
2
|
+
export declare function base64UrlToBytes(base64url: string): Uint8Array;
|
|
3
|
+
export declare function stringToBytes(str: string): Uint8Array;
|
|
4
|
+
export declare function toBufferSource(bytes: Uint8Array): Uint8Array<ArrayBuffer>;
|
|
5
|
+
export declare function bytesToString(bytes: Uint8Array): string;
|
|
6
|
+
//# sourceMappingURL=encoding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encoding.d.ts","sourceRoot":"","sources":["../../src/crypto/encoding.ts"],"names":[],"mappings":"AAAA,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAM1D;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,CAS9D;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAErD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAAC,WAAW,CAAC,CAEzE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEvD"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function bytesToBase64Url(bytes) {
|
|
2
|
+
let binary = "";
|
|
3
|
+
for (const byte of bytes) {
|
|
4
|
+
binary += String.fromCharCode(byte);
|
|
5
|
+
}
|
|
6
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
7
|
+
}
|
|
8
|
+
export function base64UrlToBytes(base64url) {
|
|
9
|
+
const base64 = base64url.replace(/-/g, "+").replace(/_/g, "/");
|
|
10
|
+
const padded = base64 + "=".repeat((4 - (base64.length % 4)) % 4);
|
|
11
|
+
const binary = atob(padded);
|
|
12
|
+
const bytes = new Uint8Array(binary.length);
|
|
13
|
+
for (let i = 0; i < binary.length; i++) {
|
|
14
|
+
bytes[i] = binary.charCodeAt(i);
|
|
15
|
+
}
|
|
16
|
+
return bytes;
|
|
17
|
+
}
|
|
18
|
+
export function stringToBytes(str) {
|
|
19
|
+
return new TextEncoder().encode(str);
|
|
20
|
+
}
|
|
21
|
+
export function toBufferSource(bytes) {
|
|
22
|
+
return new Uint8Array(bytes);
|
|
23
|
+
}
|
|
24
|
+
export function bytesToString(bytes) {
|
|
25
|
+
return new TextDecoder().decode(bytes);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=encoding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encoding.js","sourceRoot":"","sources":["../../src/crypto/encoding.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,gBAAgB,CAAC,KAAiB;IAChD,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACjF,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,SAAiB;IAChD,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAClE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAiB;IAC9C,OAAO,IAAI,UAAU,CAAC,KAAK,CAA4B,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"random.d.ts","sourceRoot":"","sources":["../../src/crypto/random.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAEtD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"random.js","sourceRoot":"","sources":["../../src/crypto/random.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,OAAO,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialization.d.ts","sourceRoot":"","sources":["../../src/crypto/serialization.ts"],"names":[],"mappings":"AAAA,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAE9D;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,CAEpD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialization.js","sourceRoot":"","sources":["../../src/crypto/serialization.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAI,IAAY;IAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAM,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { EncryptedVaultPayload, PasskeyPrfEnvelope } from "../validation/schemas.js";
|
|
2
|
+
import type { VaultCryptoProfile, VaultAadScope } from "../profile.js";
|
|
3
|
+
export declare function isPasskeySupported(): boolean;
|
|
4
|
+
export declare function isPrfExtensionSupported(): boolean;
|
|
5
|
+
export declare function extractPasskeyPrfOutput(clientExtensionResults: Record<string, unknown>): Uint8Array | null;
|
|
6
|
+
type WrapScope = Pick<VaultAadScope, "userId" | "resourceId">;
|
|
7
|
+
export declare function createPasskeyPrfEnvelope(vaultKey: CryptoKey, prfOutput: Uint8Array, scope: WrapScope, profile: VaultCryptoProfile, publicMetadata?: Record<string, unknown>): Promise<PasskeyPrfEnvelope>;
|
|
8
|
+
export declare function unwrapVaultKeyFromPasskey(encryptedVaultKey: EncryptedVaultPayload, prfOutput: Uint8Array): Promise<CryptoKey>;
|
|
9
|
+
export declare function unlockWithPasskeyPrfEnvelope(envelope: PasskeyPrfEnvelope | {
|
|
10
|
+
encryptedVaultKey: EncryptedVaultPayload;
|
|
11
|
+
}, prfOutput: Uint8Array | null, options?: {
|
|
12
|
+
prfRequired?: boolean;
|
|
13
|
+
}): Promise<CryptoKey>;
|
|
14
|
+
/** @deprecated Use unlockWithPasskeyPrfEnvelope */
|
|
15
|
+
export declare function unlockVaultFromPasskeyEnvelope(encryptedVaultKeyOrEnvelope: EncryptedVaultPayload | PasskeyPrfEnvelope, prfOutput: Uint8Array | null, options?: {
|
|
16
|
+
prfRequired?: boolean;
|
|
17
|
+
}): Promise<CryptoKey>;
|
|
18
|
+
/** @deprecated Use createPasskeyPrfEnvelope */
|
|
19
|
+
export declare function wrapVaultKeyForPasskey(vaultKey: CryptoKey, prfOutput: Uint8Array, userId: string, resourceId: string, profile: VaultCryptoProfile, publicMetadata?: Record<string, unknown>): Promise<EncryptedVaultPayload>;
|
|
20
|
+
export { PasskeyPrfRequiredError, PasskeyUnlockError } from "../errors/vault-errors.js";
|
|
21
|
+
//# sourceMappingURL=passkey-prf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passkey-prf.d.ts","sourceRoot":"","sources":["../../src/envelopes/passkey-prf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC1F,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAavE,wBAAgB,kBAAkB,IAAI,OAAO,CAG5C;AAED,wBAAgB,uBAAuB,IAAI,OAAO,CAIjD;AAED,wBAAgB,uBAAuB,CACrC,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9C,UAAU,GAAG,IAAI,CAKnB;AAaD,KAAK,SAAS,GAAG,IAAI,CAAC,aAAa,EAAE,QAAQ,GAAG,YAAY,CAAC,CAAC;AAE9D,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,SAAS,EACnB,SAAS,EAAE,UAAU,EACrB,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,kBAAkB,EAC3B,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvC,OAAO,CAAC,kBAAkB,CAAC,CAqB7B;AAED,wBAAsB,yBAAyB,CAC7C,iBAAiB,EAAE,qBAAqB,EACxC,SAAS,EAAE,UAAU,GACpB,OAAO,CAAC,SAAS,CAAC,CAOpB;AAED,wBAAsB,4BAA4B,CAChD,QAAQ,EAAE,kBAAkB,GAAG;IAAE,iBAAiB,EAAE,qBAAqB,CAAA;CAAE,EAC3E,SAAS,EAAE,UAAU,GAAG,IAAI,EAC5B,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,GAClC,OAAO,CAAC,SAAS,CAAC,CAsBpB;AAED,mDAAmD;AACnD,wBAAsB,8BAA8B,CAClD,2BAA2B,EAAE,qBAAqB,GAAG,kBAAkB,EACvE,SAAS,EAAE,UAAU,GAAG,IAAI,EAC5B,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,GAClC,OAAO,CAAC,SAAS,CAAC,CAMpB;AAED,+CAA+C;AAC/C,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,SAAS,EACnB,SAAS,EAAE,UAAU,EACrB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,kBAAkB,EAC3B,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvC,OAAO,CAAC,qBAAqB,CAAC,CAShC;AAED,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC"}
|