@learncard/sss-key-manager 0.1.19 → 0.1.21
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/dist/api-client.d.ts +49 -0
- package/dist/api-client.d.ts.map +1 -0
- package/dist/atomic-operations.d.ts +101 -0
- package/dist/atomic-operations.d.ts.map +1 -0
- package/dist/auth-coordinator.d.ts +10 -0
- package/dist/auth-coordinator.d.ts.map +1 -0
- package/dist/crypto.d.ts +31 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/key-manager.d.ts +30 -0
- package/dist/key-manager.d.ts.map +1 -0
- package/dist/passkey.d.ts +23 -0
- package/dist/passkey.d.ts.map +1 -0
- package/dist/qr-crypto.d.ts +56 -0
- package/dist/qr-crypto.d.ts.map +1 -0
- package/dist/qr-login.d.ts +122 -0
- package/dist/qr-login.d.ts.map +1 -0
- package/dist/recovery-phrase.d.ts +14 -0
- package/dist/recovery-phrase.d.ts.map +1 -0
- package/dist/sss-key-manager.cjs.development.js +39 -3
- package/dist/sss-key-manager.cjs.development.js.map +2 -2
- package/dist/sss-key-manager.cjs.production.min.js +20 -20
- package/dist/sss-key-manager.cjs.production.min.js.map +3 -3
- package/dist/sss-key-manager.esm.js +39 -3
- package/dist/sss-key-manager.esm.js.map +2 -2
- package/dist/sss-strategy.d.ts +82 -0
- package/dist/sss-strategy.d.ts.map +1 -0
- package/dist/sss.d.ts +15 -0
- package/dist/sss.d.ts.map +1 -0
- package/dist/storage.d.ts +46 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/types.d.ts +155 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +8 -8
- package/src/crypto.ts +9 -14
- package/src/recovery-phrase.ts +7 -4
- package/src/sss-strategy.test.ts +404 -246
- package/dist/sss-key-manager.d.ts +0 -898
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSS Key Derivation Strategy
|
|
3
|
+
*
|
|
4
|
+
* Implements KeyDerivationStrategy using Shamir's Secret Sharing.
|
|
5
|
+
* This is the default key derivation strategy for LearnCard.
|
|
6
|
+
*
|
|
7
|
+
* The strategy owns:
|
|
8
|
+
* - Local key storage (IndexedDB device share)
|
|
9
|
+
* - Key splitting and reconstruction (SSS 2-of-4)
|
|
10
|
+
* - Server communication for auth shares
|
|
11
|
+
* - Optional email backup share delivery
|
|
12
|
+
* - Recovery method execution and setup
|
|
13
|
+
* - Storage cleanup knowledge
|
|
14
|
+
*/
|
|
15
|
+
import type { SSSKeyDerivationStrategy } from './types';
|
|
16
|
+
export interface SSSStorageFunctions {
|
|
17
|
+
storeDeviceShare: (share: string, id?: string) => Promise<void>;
|
|
18
|
+
getDeviceShare: (id?: string) => Promise<string | null>;
|
|
19
|
+
hasDeviceShare: (id?: string) => Promise<boolean>;
|
|
20
|
+
clearAllShares: (id?: string) => Promise<void>;
|
|
21
|
+
storeShareVersion: (version: number, id?: string) => Promise<void>;
|
|
22
|
+
getShareVersion: (id?: string) => Promise<number | null>;
|
|
23
|
+
}
|
|
24
|
+
export interface SSSStrategyConfig {
|
|
25
|
+
/** Server URL for key share operations */
|
|
26
|
+
serverUrl: string;
|
|
27
|
+
/** Custom storage functions (defaults to IndexedDB) */
|
|
28
|
+
storage?: SSSStorageFunctions;
|
|
29
|
+
/**
|
|
30
|
+
* Whether to automatically send a backup share to the user's email
|
|
31
|
+
* during key setup and recovery. The share is relayed through the server
|
|
32
|
+
* but never persisted — fire-and-forget.
|
|
33
|
+
*
|
|
34
|
+
* Defaults to false. Controlled by VITE_ENABLE_EMAIL_BACKUP_SHARE env var.
|
|
35
|
+
*/
|
|
36
|
+
enableEmailBackupShare?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Tenant identifier forwarded as `X-Tenant-Id` on every server request.
|
|
39
|
+
* The lca-api uses this to brand recovery / OTP emails for the active
|
|
40
|
+
* tenant. Defaults to the server's fallback tenant (learncard) when unset.
|
|
41
|
+
*/
|
|
42
|
+
tenantId?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Format an email share with a 4-character hex version prefix.
|
|
46
|
+
*
|
|
47
|
+
* Example: version 12 + share "47dee4…" → "000c47dee4…"
|
|
48
|
+
*
|
|
49
|
+
* The 4-hex-digit prefix keeps the entire string as one contiguous
|
|
50
|
+
* hex blob, so double-clicking in an email selects the whole thing
|
|
51
|
+
* (no word-boundary characters like ":" to trip up selection).
|
|
52
|
+
*/
|
|
53
|
+
export declare const VERSION_PREFIX_LEN = 4;
|
|
54
|
+
export declare const formatVersionedEmailShare: (emailShare: string, shareVersion: number) => string;
|
|
55
|
+
/**
|
|
56
|
+
* Parse a versioned email share string back into its components.
|
|
57
|
+
* Expects a 4-char hex version prefix followed by the hex share.
|
|
58
|
+
* Returns the raw hex share and the version number (if present).
|
|
59
|
+
*/
|
|
60
|
+
export declare const parseVersionedEmailShare: (input: string) => {
|
|
61
|
+
share: string;
|
|
62
|
+
version: number | undefined;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Create an SSS key derivation strategy.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* const sssStrategy = createSSSStrategy({
|
|
70
|
+
* serverUrl: 'https://api.learncard.com',
|
|
71
|
+
* });
|
|
72
|
+
*
|
|
73
|
+
* // Use with AuthCoordinator
|
|
74
|
+
* const coordinator = createAuthCoordinator({
|
|
75
|
+
* authProvider,
|
|
76
|
+
* keyDerivation: sssStrategy,
|
|
77
|
+
* });
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export declare function createSSSStrategy(config: SSSStrategyConfig): SSSKeyDerivationStrategy;
|
|
81
|
+
export type { SSSKeyDerivationStrategy };
|
|
82
|
+
//# sourceMappingURL=sss-strategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sss-strategy.d.ts","sourceRoot":"","sources":["../src/sss-strategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EACR,wBAAwB,EAU3B,MAAM,SAAS,CAAC;AA4BjB,MAAM,WAAW,mBAAmB;IAChC,gBAAgB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,cAAc,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACxD,cAAc,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAClD,cAAc,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,iBAAiB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,eAAe,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC5D;AAED,MAAM,WAAW,iBAAiB;IAC9B,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAElB,uDAAuD;IACvD,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAE9B;;;;;;OAMG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAmID;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC,eAAO,MAAM,yBAAyB,GAAI,YAAY,MAAM,EAAE,cAAc,MAAM,KAAG,MACT,CAAC;AAE7E;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GACjC,OAAO,MAAM,KACd;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;CAY9C,CAAC;AAqGF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,wBAAwB,CA8uBrF;AAED,YAAY,EAAE,wBAAwB,EAAE,CAAC"}
|
package/dist/sss.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shamir Secret Sharing operations
|
|
3
|
+
*/
|
|
4
|
+
export declare const SSS_TOTAL_SHARES = 4;
|
|
5
|
+
export declare const SSS_THRESHOLD = 2;
|
|
6
|
+
export interface SSSShares {
|
|
7
|
+
deviceShare: string;
|
|
8
|
+
authShare: string;
|
|
9
|
+
recoveryShare: string;
|
|
10
|
+
emailShare: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function splitPrivateKey(privateKeyHex: string): Promise<SSSShares>;
|
|
13
|
+
export declare function reconstructPrivateKey(share1Hex: string, share2Hex: string): Promise<string>;
|
|
14
|
+
export declare function reconstructFromShares(shares: string[]): Promise<string>;
|
|
15
|
+
//# sourceMappingURL=sss.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sss.d.ts","sourceRoot":"","sources":["../src/sss.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAClC,eAAO,MAAM,aAAa,IAAI,CAAC;AAE/B,MAAM,WAAW,SAAS;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAW/E;AAED,wBAAsB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAOjG;AAED,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAS7E"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Device-side storage for SSS shares
|
|
3
|
+
* Reuses patterns from webSecureStorage but specialized for SSS
|
|
4
|
+
*/
|
|
5
|
+
export declare function storeDeviceShare(share: string, id?: string): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* Store the share version alongside a device share.
|
|
8
|
+
* Stored as a separate key `{id}:version` to avoid changing the encryption format.
|
|
9
|
+
*/
|
|
10
|
+
export declare function storeShareVersion(version: number, id?: string): Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* Retrieve the share version for a device share.
|
|
13
|
+
* Returns null if no version is stored (legacy shares).
|
|
14
|
+
*/
|
|
15
|
+
export declare function getShareVersion(id?: string): Promise<number | null>;
|
|
16
|
+
export declare function getDeviceShare(id?: string): Promise<string | null>;
|
|
17
|
+
export declare function hasDeviceShare(id?: string): Promise<boolean>;
|
|
18
|
+
export declare function deleteDeviceShare(id?: string): Promise<void>;
|
|
19
|
+
export interface DeviceShareEntry {
|
|
20
|
+
id: string;
|
|
21
|
+
preview: string;
|
|
22
|
+
shareVersion?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* List all device shares stored in IndexedDB.
|
|
26
|
+
* Returns the storage key and a truncated preview for each share.
|
|
27
|
+
* Useful for debugging multi-account storage.
|
|
28
|
+
*/
|
|
29
|
+
export declare function listAllDeviceShares(): Promise<DeviceShareEntry[]>;
|
|
30
|
+
export declare function isPublicComputerMode(): boolean;
|
|
31
|
+
export declare function setPublicComputerMode(enabled: boolean): void;
|
|
32
|
+
/**
|
|
33
|
+
* Create storage functions that dynamically route to sessionStorage (public
|
|
34
|
+
* computer mode) or IndexedDB (normal mode) based on the `lc-session-mode`
|
|
35
|
+
* flag in sessionStorage. Checked at call time, not at creation time.
|
|
36
|
+
*/
|
|
37
|
+
export declare function createAdaptiveStorage(): {
|
|
38
|
+
storeDeviceShare: (share: string, id?: string) => Promise<void>;
|
|
39
|
+
getDeviceShare: (id?: string) => Promise<string | null>;
|
|
40
|
+
hasDeviceShare: (id?: string) => Promise<boolean>;
|
|
41
|
+
clearAllShares: (id?: string) => Promise<void>;
|
|
42
|
+
storeShareVersion: (version: number, id?: string) => Promise<void>;
|
|
43
|
+
getShareVersion: (id?: string) => Promise<number | null>;
|
|
44
|
+
};
|
|
45
|
+
export declare function clearAllShares(id?: string): Promise<void>;
|
|
46
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgJH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAE,MAAgC,GAAG,OAAO,CAAC,IAAI,CAAC,CASzG;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,GAAE,MAAgC,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ5G;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,EAAE,GAAE,MAAgC,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAYlG;AAED,wBAAsB,cAAc,CAAC,EAAE,GAAE,MAAgC,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAqCjG;AAED,wBAAsB,cAAc,CAAC,EAAE,GAAE,MAAgC,GAAG,OAAO,CAAC,OAAO,CAAC,CAG3F;AAED,wBAAsB,iBAAiB,CAAC,EAAE,GAAE,MAAgC,GAAG,OAAO,CAAC,IAAI,CAAC,CAU3F;AAED,MAAM,WAAW,gBAAgB;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAoDvE;AAYD,wBAAgB,oBAAoB,IAAI,OAAO,CAO9C;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAU5D;AAiDD;;;;GAIG;AACH,wBAAgB,qBAAqB;8BAEH,MAAM,OAAO,MAAM;0BAKvB,MAAM;0BAKN,MAAM;0BAKN,MAAM;iCAKC,MAAM,OAAO,MAAM;2BAKzB,MAAM;EAKpC;AAED,wBAAsB,cAAc,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsC/D"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSS Key Manager Types
|
|
3
|
+
*
|
|
4
|
+
* Re-exports provider-agnostic interfaces from @learncard/types
|
|
5
|
+
* and defines SSS-specific types (recovery shapes, backup files, etc.).
|
|
6
|
+
*/
|
|
7
|
+
export { AuthSessionError, type AuthProviderType, type AuthUser, type AuthProvider, type RecoveryMethodInfo, type RecoveryResult, type ServerKeyStatus, type KeyDerivationStrategy, } from '@learncard/types';
|
|
8
|
+
import type { AuthProvider, AuthProviderType, KeyDerivationStrategy, RecoveryMethodInfo } from '@learncard/types';
|
|
9
|
+
export type ContactMethodType = 'email' | 'phone';
|
|
10
|
+
export interface ContactMethod {
|
|
11
|
+
type: ContactMethodType;
|
|
12
|
+
value: string;
|
|
13
|
+
}
|
|
14
|
+
export interface AuthProviderMapping {
|
|
15
|
+
type: AuthProviderType;
|
|
16
|
+
id: string;
|
|
17
|
+
}
|
|
18
|
+
export type SecurityLevel = 'basic' | 'enhanced' | 'advanced';
|
|
19
|
+
export declare const SecurityLevels: readonly SecurityLevel[];
|
|
20
|
+
/**
|
|
21
|
+
* SSS recovery method type identifiers.
|
|
22
|
+
* These are the specific recovery methods supported by the SSS strategy.
|
|
23
|
+
*/
|
|
24
|
+
export type RecoveryMethodType = 'passkey' | 'backup' | 'phrase' | 'email';
|
|
25
|
+
export interface PasskeyRecoveryMethod {
|
|
26
|
+
type: 'passkey';
|
|
27
|
+
credentialId?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface BackupFileRecoveryMethod {
|
|
30
|
+
type: 'backup';
|
|
31
|
+
fileContents: string;
|
|
32
|
+
password: string;
|
|
33
|
+
}
|
|
34
|
+
export interface RecoveryPhraseRecoveryMethod {
|
|
35
|
+
type: 'phrase';
|
|
36
|
+
phrase: string;
|
|
37
|
+
}
|
|
38
|
+
/** @deprecated Use RecoveryInput instead. Kept for legacy SSSKeyManager class. */
|
|
39
|
+
export type RecoveryMethod = PasskeyRecoveryMethod | BackupFileRecoveryMethod | RecoveryPhraseRecoveryMethod;
|
|
40
|
+
/**
|
|
41
|
+
* SSS-specific recovery input — what the user provides to recover their key.
|
|
42
|
+
*/
|
|
43
|
+
export type RecoveryInput = {
|
|
44
|
+
method: 'passkey';
|
|
45
|
+
credentialId: string;
|
|
46
|
+
} | {
|
|
47
|
+
method: 'phrase';
|
|
48
|
+
phrase: string;
|
|
49
|
+
} | {
|
|
50
|
+
method: 'backup';
|
|
51
|
+
fileContents: string;
|
|
52
|
+
password: string;
|
|
53
|
+
} | {
|
|
54
|
+
method: 'email';
|
|
55
|
+
emailShare: string;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* SSS-specific recovery setup input — what the user provides to set up a method.
|
|
59
|
+
*/
|
|
60
|
+
export type RecoverySetupInput = {
|
|
61
|
+
method: 'passkey';
|
|
62
|
+
} | {
|
|
63
|
+
method: 'phrase';
|
|
64
|
+
} | {
|
|
65
|
+
method: 'backup';
|
|
66
|
+
password: string;
|
|
67
|
+
did: string;
|
|
68
|
+
} | {
|
|
69
|
+
method: 'email';
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* SSS-specific recovery setup result.
|
|
73
|
+
*/
|
|
74
|
+
export type RecoverySetupResult = {
|
|
75
|
+
method: 'passkey';
|
|
76
|
+
credentialId: string;
|
|
77
|
+
} | {
|
|
78
|
+
method: 'phrase';
|
|
79
|
+
phrase: string;
|
|
80
|
+
} | {
|
|
81
|
+
method: 'backup';
|
|
82
|
+
backupFile: BackupFile;
|
|
83
|
+
} | {
|
|
84
|
+
method: 'email';
|
|
85
|
+
};
|
|
86
|
+
export interface EncryptedShare {
|
|
87
|
+
encryptedData: string;
|
|
88
|
+
iv: string;
|
|
89
|
+
salt?: string;
|
|
90
|
+
}
|
|
91
|
+
export interface ServerEncryptedShare {
|
|
92
|
+
encryptedData: string;
|
|
93
|
+
encryptedDek: string;
|
|
94
|
+
iv: string;
|
|
95
|
+
}
|
|
96
|
+
export interface UserKeyRecord {
|
|
97
|
+
contactMethod: ContactMethod;
|
|
98
|
+
authProviders: AuthProviderMapping[];
|
|
99
|
+
primaryDid: string;
|
|
100
|
+
linkedDids: string[];
|
|
101
|
+
keyProvider: 'web3auth' | 'sss';
|
|
102
|
+
authShare?: ServerEncryptedShare;
|
|
103
|
+
securityLevel: SecurityLevel;
|
|
104
|
+
recoveryMethods: RecoveryMethodInfo[];
|
|
105
|
+
migratedFromWeb3Auth: boolean;
|
|
106
|
+
migratedAt?: Date;
|
|
107
|
+
createdAt: Date;
|
|
108
|
+
updatedAt: Date;
|
|
109
|
+
}
|
|
110
|
+
export interface BackupFile {
|
|
111
|
+
version: 1;
|
|
112
|
+
createdAt: string;
|
|
113
|
+
primaryDid: string;
|
|
114
|
+
shareVersion?: number;
|
|
115
|
+
encryptedShare: {
|
|
116
|
+
ciphertext: string;
|
|
117
|
+
iv: string;
|
|
118
|
+
salt: string;
|
|
119
|
+
kdfParams: {
|
|
120
|
+
algorithm: 'argon2id';
|
|
121
|
+
timeCost: number;
|
|
122
|
+
memoryCost: number;
|
|
123
|
+
parallelism: number;
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
export interface SSSKeyManagerConfig {
|
|
128
|
+
serverUrl: string;
|
|
129
|
+
authProvider: AuthProvider;
|
|
130
|
+
deviceStorageKey?: string;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* The SSS key derivation strategy — a KeyDerivationStrategy narrowed
|
|
134
|
+
* with SSS-specific recovery input/output types.
|
|
135
|
+
*/
|
|
136
|
+
export type SSSKeyDerivationStrategy = KeyDerivationStrategy<RecoveryInput, RecoverySetupInput, RecoverySetupResult>;
|
|
137
|
+
/** @deprecated Use KeyDerivationStrategy instead. Kept for legacy SSSKeyManager class. */
|
|
138
|
+
export interface KeyDerivationProvider {
|
|
139
|
+
readonly name: string;
|
|
140
|
+
connect(): Promise<string>;
|
|
141
|
+
disconnect(): Promise<void>;
|
|
142
|
+
isInitialized(): boolean;
|
|
143
|
+
hasLocalKey(): Promise<boolean>;
|
|
144
|
+
canMigrate?(): Promise<boolean>;
|
|
145
|
+
migrate?(privateKey: string): Promise<void>;
|
|
146
|
+
}
|
|
147
|
+
/** @deprecated Use KeyDerivationStrategy instead. Kept for legacy SSSKeyManager class. */
|
|
148
|
+
export interface SSSKeyDerivationProvider extends KeyDerivationProvider {
|
|
149
|
+
addRecoveryMethod(method: RecoveryMethod): Promise<void>;
|
|
150
|
+
getRecoveryMethods(): Promise<RecoveryMethodInfo[]>;
|
|
151
|
+
recover(method: RecoveryMethod): Promise<string>;
|
|
152
|
+
getSecurityLevel(): Promise<SecurityLevel>;
|
|
153
|
+
exportBackup(password: string): Promise<BackupFile>;
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@learncard/sss-key-manager",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
4
4
|
"description": "Shamir Secret Sharing key manager for LearnCard - replaces Web3Auth SFA",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/sss-key-manager.esm.js",
|
|
7
|
-
"types": "./dist/
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
8
|
"files": [
|
|
9
9
|
"dist",
|
|
10
10
|
"src"
|
|
11
11
|
],
|
|
12
12
|
"scripts": {
|
|
13
|
-
"build": "node ./scripts/build.mjs && shx cp ./scripts/mixedEntrypoint.js ./dist/index.js &&
|
|
13
|
+
"build": "node ./scripts/build.mjs && shx cp ./scripts/mixedEntrypoint.js ./dist/index.js && tsc --p tsconfig.json",
|
|
14
14
|
"dev": "node ./scripts/build.mjs --watch",
|
|
15
15
|
"test": "vitest run",
|
|
16
16
|
"test:watch": "vitest",
|
|
17
|
-
"typecheck": "tsc --noEmit"
|
|
17
|
+
"typecheck": "tsc --noEmit",
|
|
18
|
+
"test:coverage": "vitest run --coverage"
|
|
18
19
|
},
|
|
19
20
|
"author": "Learning Economy Foundation (www.learningeconomy.io)",
|
|
20
21
|
"license": "MIT",
|
|
@@ -29,16 +30,15 @@
|
|
|
29
30
|
"devDependencies": {
|
|
30
31
|
"@esbuild-plugins/node-resolve": "^0.1.4",
|
|
31
32
|
"@types/node": "^18.7.19",
|
|
32
|
-
"dts-bundle-generator": "^6.10.0",
|
|
33
33
|
"esbuild": "^0.27.1",
|
|
34
34
|
"fake-indexeddb": "^6.2.5",
|
|
35
35
|
"jsdom": "^24.0.0",
|
|
36
36
|
"shx": "^0.3.4",
|
|
37
37
|
"typescript": "^5.0.0",
|
|
38
|
-
"vitest": "
|
|
38
|
+
"vitest": "4.1.10"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@learncard/types": "5.18.
|
|
41
|
+
"@learncard/types": "5.18.3",
|
|
42
42
|
"@noble/ed25519": "^2.0.0",
|
|
43
43
|
"@scure/bip39": "^1.2.1",
|
|
44
44
|
"hash-wasm": "^4.11.0",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"exports": {
|
|
56
56
|
".": {
|
|
57
57
|
"development": "./src/index.ts",
|
|
58
|
-
"types": "./dist/
|
|
58
|
+
"types": "./dist/index.d.ts",
|
|
59
59
|
"import": "./dist/sss-key-manager.esm.js",
|
|
60
60
|
"require": "./dist/index.js",
|
|
61
61
|
"default": "./dist/sss-key-manager.esm.js"
|
package/src/crypto.ts
CHANGED
|
@@ -32,7 +32,7 @@ export function bufferToBase64(buf: ArrayBuffer): string {
|
|
|
32
32
|
return btoa(binary);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
export function base64ToBuffer(b64: string): Uint8Array {
|
|
35
|
+
export function base64ToBuffer(b64: string): Uint8Array<ArrayBuffer> {
|
|
36
36
|
const binary = atob(b64);
|
|
37
37
|
const bytes = new Uint8Array(binary.length);
|
|
38
38
|
for (let i = 0; i < binary.length; i++) {
|
|
@@ -41,7 +41,7 @@ export function base64ToBuffer(b64: string): Uint8Array {
|
|
|
41
41
|
return bytes;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
export function hexToBytes(hex: string): Uint8Array {
|
|
44
|
+
export function hexToBytes(hex: string): Uint8Array<ArrayBuffer> {
|
|
45
45
|
const bytes = new Uint8Array(hex.length / 2);
|
|
46
46
|
for (let i = 0; i < hex.length; i += 2) {
|
|
47
47
|
bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
|
|
@@ -59,7 +59,7 @@ export async function deriveKeyFromPassword(
|
|
|
59
59
|
password: string,
|
|
60
60
|
salt: Uint8Array,
|
|
61
61
|
params: KdfParams = DEFAULT_KDF_PARAMS
|
|
62
|
-
): Promise<Uint8Array
|
|
62
|
+
): Promise<Uint8Array<ArrayBuffer>> {
|
|
63
63
|
const hash = await argon2id({
|
|
64
64
|
password,
|
|
65
65
|
salt: salt as unknown as Uint8Array,
|
|
@@ -69,7 +69,7 @@ export async function deriveKeyFromPassword(
|
|
|
69
69
|
hashLength: ARGON2_HASH_LENGTH,
|
|
70
70
|
outputType: 'binary',
|
|
71
71
|
});
|
|
72
|
-
return
|
|
72
|
+
return Uint8Array.from(hash);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
export async function encryptWithPassword(
|
|
@@ -148,11 +148,7 @@ export async function encryptShare(
|
|
|
148
148
|
encryptParams.additionalData = encoder.encode(aad);
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
const ciphertextBuffer = await crypto.subtle.encrypt(
|
|
152
|
-
encryptParams,
|
|
153
|
-
key,
|
|
154
|
-
encoder.encode(share) as ArrayBuffer
|
|
155
|
-
);
|
|
151
|
+
const ciphertextBuffer = await crypto.subtle.encrypt(encryptParams, key, encoder.encode(share));
|
|
156
152
|
|
|
157
153
|
return {
|
|
158
154
|
encryptedData: bufferToBase64(ciphertextBuffer),
|
|
@@ -186,11 +182,10 @@ export async function decryptShare(
|
|
|
186
182
|
}
|
|
187
183
|
|
|
188
184
|
export async function generateAesKey(): Promise<CryptoKey> {
|
|
189
|
-
return crypto.subtle.generateKey(
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
);
|
|
185
|
+
return crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, true, [
|
|
186
|
+
'encrypt',
|
|
187
|
+
'decrypt',
|
|
188
|
+
]);
|
|
194
189
|
}
|
|
195
190
|
|
|
196
191
|
export function generateRandomBytes(length: number): Uint8Array {
|
package/src/recovery-phrase.ts
CHANGED
|
@@ -27,7 +27,7 @@ function bytesToBits(bytes: Uint8Array): string {
|
|
|
27
27
|
.join('');
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
function bitsToBytes(bits: string): Uint8Array {
|
|
30
|
+
function bitsToBytes(bits: string): Uint8Array<ArrayBuffer> {
|
|
31
31
|
const bytes = new Uint8Array(Math.ceil(bits.length / 8));
|
|
32
32
|
for (let i = 0; i < bytes.length; i++) {
|
|
33
33
|
bytes[i] = parseInt(bits.slice(i * 8, (i + 1) * 8).padEnd(8, '0'), 2);
|
|
@@ -35,7 +35,7 @@ function bitsToBytes(bits: string): Uint8Array {
|
|
|
35
35
|
return bytes;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
async function computeChecksum(data: Uint8Array): Promise<string> {
|
|
38
|
+
async function computeChecksum(data: Uint8Array<ArrayBuffer>): Promise<string> {
|
|
39
39
|
const hash = await crypto.subtle.digest('SHA-256', data);
|
|
40
40
|
const hashBits = bytesToBits(new Uint8Array(hash));
|
|
41
41
|
const checksumLength = Math.floor(data.length / 4);
|
|
@@ -98,7 +98,7 @@ export async function recoveryPhraseToShare(phrase: string): Promise<string> {
|
|
|
98
98
|
|
|
99
99
|
const checksumLength = Math.floor(dataByteCount / 4);
|
|
100
100
|
const dataBitCount = dataByteCount * 8;
|
|
101
|
-
|
|
101
|
+
|
|
102
102
|
const dataBits = bits.slice(0, dataBitCount);
|
|
103
103
|
const checksumBits = bits.slice(dataBitCount, dataBitCount + checksumLength);
|
|
104
104
|
|
|
@@ -127,5 +127,8 @@ export async function validateRecoveryPhrase(phrase: string): Promise<boolean> {
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
export function countWords(phrase: string): number {
|
|
130
|
-
return phrase
|
|
130
|
+
return phrase
|
|
131
|
+
.trim()
|
|
132
|
+
.split(/\s+/)
|
|
133
|
+
.filter(w => w.length > 0).length;
|
|
131
134
|
}
|