@enbox/auth 0.6.33 → 0.6.35
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/esm/auth-manager.js +34 -16
- package/dist/esm/auth-manager.js.map +1 -1
- package/dist/esm/connect/import.js +52 -24
- package/dist/esm/connect/import.js.map +1 -1
- package/dist/esm/connect/lifecycle.js +2 -2
- package/dist/esm/connect/recovery.js +105 -0
- package/dist/esm/connect/recovery.js.map +1 -0
- package/dist/esm/connect/{local.js → vault.js} +49 -12
- package/dist/esm/connect/vault.js.map +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/types.js.map +1 -1
- package/dist/types/auth-manager.d.ts +26 -12
- package/dist/types/auth-manager.d.ts.map +1 -1
- package/dist/types/connect/import.d.ts +3 -1
- package/dist/types/connect/import.d.ts.map +1 -1
- package/dist/types/connect/lifecycle.d.ts +3 -3
- package/dist/types/connect/recovery.d.ts +50 -0
- package/dist/types/connect/recovery.d.ts.map +1 -0
- package/dist/types/connect/{local.d.ts → vault.d.ts} +12 -6
- package/dist/types/connect/vault.d.ts.map +1 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/types.d.ts +7 -5
- package/dist/types/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/auth-manager.ts +35 -18
- package/src/connect/import.ts +58 -28
- package/src/connect/lifecycle.ts +3 -3
- package/src/connect/recovery.ts +111 -0
- package/src/connect/{local.ts → vault.ts} +54 -14
- package/src/index.ts +2 -1
- package/src/types.ts +8 -5
- package/dist/esm/connect/local.js.map +0 -1
- package/dist/types/connect/local.d.ts.map +0 -1
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seed phrase recovery helpers.
|
|
3
|
+
*
|
|
4
|
+
* When a vault is re-derived from a recovery phrase on a new device,
|
|
5
|
+
* the local DWN is empty. This module provides the building blocks
|
|
6
|
+
* for pulling identity metadata, keys, and user data from the remote
|
|
7
|
+
* DWN in a controlled two-phase sequence.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { BearerIdentity, EnboxUserAgent } from '@enbox/agent';
|
|
14
|
+
|
|
15
|
+
import { IdentityProtocolDefinition, JwkProtocolDefinition } from '@enbox/agent';
|
|
16
|
+
|
|
17
|
+
import type { RegistrationOptions, StorageAdapter } from '../types.js';
|
|
18
|
+
|
|
19
|
+
import { registerWithDwnEndpoints } from '../registration.js';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Internal protocols that store recovery-critical data in the agent DID's DWN.
|
|
23
|
+
* Syncing these ensures that seed phrase recovery can pull identity metadata,
|
|
24
|
+
* portable DIDs, and encrypted private keys from the remote.
|
|
25
|
+
*/
|
|
26
|
+
export const AGENT_DID_SYNC_PROTOCOLS: [string, ...string[]] = [
|
|
27
|
+
IdentityProtocolDefinition.protocol,
|
|
28
|
+
JwkProtocolDefinition.protocol,
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Register the agent DID for sync with the recovery-critical protocols.
|
|
33
|
+
*
|
|
34
|
+
* This is a prerequisite for both normal operation (pushing identity
|
|
35
|
+
* metadata to the remote) and seed phrase recovery (pulling it back).
|
|
36
|
+
* Silently succeeds if the agent DID is already registered.
|
|
37
|
+
*/
|
|
38
|
+
export async function registerAgentDidForSync(userAgent: EnboxUserAgent): Promise<void> {
|
|
39
|
+
try {
|
|
40
|
+
await userAgent.sync.registerIdentity({
|
|
41
|
+
did : userAgent.agentDid.uri,
|
|
42
|
+
options : { protocols: AGENT_DID_SYNC_PROTOCOLS },
|
|
43
|
+
});
|
|
44
|
+
} catch {
|
|
45
|
+
// Already registered from a previous session.
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Recover identities and their data from remote DWN endpoints.
|
|
51
|
+
*
|
|
52
|
+
* Assumes the agent DID is already registered for sync (via
|
|
53
|
+
* {@link registerAgentDidForSync}) and as a DWN tenant.
|
|
54
|
+
*
|
|
55
|
+
* Phase 1 — pull identity metadata and DID private keys stored in the
|
|
56
|
+
* agent DID's DWN.
|
|
57
|
+
*
|
|
58
|
+
* Phase 2 — register each recovered identity DID as a tenant and for
|
|
59
|
+
* sync, then pull their profile data, protocol configurations, and
|
|
60
|
+
* records.
|
|
61
|
+
*
|
|
62
|
+
* Returns the recovered identities, or an empty array if the remote
|
|
63
|
+
* had nothing (e.g. first-ever setup with a pre-generated phrase).
|
|
64
|
+
*/
|
|
65
|
+
export async function recoverIdentitiesFromRemote(params: {
|
|
66
|
+
userAgent: EnboxUserAgent;
|
|
67
|
+
dwnEndpoints: string[];
|
|
68
|
+
registration?: RegistrationOptions;
|
|
69
|
+
storage: StorageAdapter;
|
|
70
|
+
}): Promise<BearerIdentity[]> {
|
|
71
|
+
const { userAgent, dwnEndpoints, registration, storage } = params;
|
|
72
|
+
const agentDid = userAgent.agentDid.uri;
|
|
73
|
+
|
|
74
|
+
// Phase 1: pull identity metadata + encrypted DID keys.
|
|
75
|
+
await userAgent.sync.sync('pull');
|
|
76
|
+
|
|
77
|
+
const identities = await userAgent.identity.list();
|
|
78
|
+
if (identities.length === 0) {
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Register each recovered identity DID as a DWN tenant, then for sync.
|
|
83
|
+
// Tenant registration must come first — sync('pull') issues
|
|
84
|
+
// MessagesSync which requires the DID to be a recognised tenant.
|
|
85
|
+
for (const identity of identities) {
|
|
86
|
+
const did = identity.metadata.connectedDid ?? identity.did.uri;
|
|
87
|
+
|
|
88
|
+
if (registration) {
|
|
89
|
+
try {
|
|
90
|
+
await registerWithDwnEndpoints(
|
|
91
|
+
{ userAgent, dwnEndpoints, agentDid, connectedDid: did, secretStore: userAgent.secrets, storage },
|
|
92
|
+
registration,
|
|
93
|
+
);
|
|
94
|
+
} catch {
|
|
95
|
+
// Best effort — the DID may already be registered, or the
|
|
96
|
+
// endpoint may be temporarily unreachable.
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
await userAgent.sync.registerIdentity({ did, options: { protocols: 'all' } });
|
|
102
|
+
} catch {
|
|
103
|
+
// Already registered from a previous session.
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Phase 2: pull profile data, protocol configurations, and records.
|
|
108
|
+
await userAgent.sync.sync('pull');
|
|
109
|
+
|
|
110
|
+
return userAgent.identity.list();
|
|
111
|
+
}
|
|
@@ -1,34 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Vault connect flow.
|
|
3
3
|
*
|
|
4
4
|
* Creates or reconnects a local identity with vault-protected keys.
|
|
5
|
-
*
|
|
5
|
+
* Used by wallets and CLI tools that own the HD identity vault directly
|
|
6
|
+
* (as opposed to handler-based connect, which delegates credential
|
|
7
|
+
* acquisition to an external wallet).
|
|
8
|
+
*
|
|
6
9
|
* @module
|
|
7
10
|
*/
|
|
8
11
|
|
|
9
12
|
import type { AuthSession } from '../identity-session.js';
|
|
10
13
|
import type { FlowContext } from './lifecycle.js';
|
|
11
|
-
import type {
|
|
14
|
+
import type { VaultConnectOptions } from '../types.js';
|
|
12
15
|
|
|
13
16
|
import { applyLocalDwnDiscovery } from '../discovery.js';
|
|
14
17
|
import { DEFAULT_DWN_ENDPOINTS } from '../types.js';
|
|
15
18
|
import { registerWithDwnEndpoints } from '../registration.js';
|
|
16
19
|
import { createDefaultIdentity, ensureVaultReady, finalizeSession, resolveIdentityDids, resolvePassword, startSyncIfEnabled } from './lifecycle.js';
|
|
20
|
+
import { recoverIdentitiesFromRemote, registerAgentDidForSync } from './recovery.js';
|
|
17
21
|
|
|
18
22
|
/**
|
|
19
|
-
* Execute the
|
|
23
|
+
* Execute the vault connect flow.
|
|
20
24
|
*
|
|
21
25
|
* - On first launch: initializes the vault. Identity creation is opt-in via
|
|
22
26
|
* `options.createIdentity: true`.
|
|
23
27
|
* - On subsequent launches: unlocks the vault and reconnects to the existing identity.
|
|
28
|
+
* - On recovery: when `recoveryPhrase` is provided on a fresh vault, pulls
|
|
29
|
+
* identities and their data from the remote DWN before falling back to
|
|
30
|
+
* identity creation.
|
|
24
31
|
*
|
|
25
32
|
* When no identities exist and `createIdentity` is not `true`, the session
|
|
26
33
|
* is returned with the **agent DID** as the connected DID. This allows apps to
|
|
27
34
|
* manage identity creation separately from vault setup.
|
|
28
35
|
*/
|
|
29
|
-
export async function
|
|
36
|
+
export async function vaultConnect(
|
|
30
37
|
ctx: FlowContext,
|
|
31
|
-
options:
|
|
38
|
+
options: VaultConnectOptions = {},
|
|
32
39
|
): Promise<AuthSession> {
|
|
33
40
|
const { userAgent, emitter, storage } = ctx;
|
|
34
41
|
|
|
@@ -56,11 +63,43 @@ export async function localConnect(
|
|
|
56
63
|
await applyLocalDwnDiscovery(userAgent, storage, emitter);
|
|
57
64
|
}
|
|
58
65
|
|
|
59
|
-
//
|
|
60
|
-
|
|
66
|
+
// Register the agent DID as a DWN tenant and for sync early — both are
|
|
67
|
+
// prerequisites for seed phrase recovery and for normal push/pull of
|
|
68
|
+
// identity metadata after identity creation.
|
|
69
|
+
if (ctx.registration) {
|
|
70
|
+
await registerWithDwnEndpoints(
|
|
71
|
+
{
|
|
72
|
+
userAgent,
|
|
73
|
+
dwnEndpoints,
|
|
74
|
+
agentDid : userAgent.agentDid.uri,
|
|
75
|
+
connectedDid : userAgent.agentDid.uri,
|
|
76
|
+
secretStore : userAgent.secrets,
|
|
77
|
+
storage,
|
|
78
|
+
},
|
|
79
|
+
ctx.registration,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
if (sync !== 'off') {
|
|
83
|
+
await registerAgentDidForSync(userAgent);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Find existing identities.
|
|
87
|
+
let identities = await userAgent.identity.list();
|
|
61
88
|
let identity = identities[0];
|
|
62
89
|
let isNewIdentity = false;
|
|
63
90
|
|
|
91
|
+
// Seed phrase recovery: when a recovery phrase was provided on a fresh
|
|
92
|
+
// vault and no identities exist locally, pull them from the remote DWN.
|
|
93
|
+
if (!identity && isFirstLaunch && options.recoveryPhrase && sync !== 'off') {
|
|
94
|
+
try {
|
|
95
|
+
identities = await recoverIdentitiesFromRemote({ userAgent, dwnEndpoints, registration: ctx.registration, storage });
|
|
96
|
+
identity = identities[0];
|
|
97
|
+
} catch (err) {
|
|
98
|
+
console.warn('[@enbox/auth] Seed phrase recovery failed:', err);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Create a default identity if none were found or recovered.
|
|
64
103
|
if (!identity && shouldCreateIdentity) {
|
|
65
104
|
isNewIdentity = true;
|
|
66
105
|
identity = await createDefaultIdentity(userAgent, dwnEndpoints, options.metadata?.name ?? 'Default');
|
|
@@ -77,22 +116,23 @@ export async function localConnect(
|
|
|
77
116
|
? resolveIdentityDids(identity).delegateDid
|
|
78
117
|
: undefined;
|
|
79
118
|
|
|
80
|
-
// Register
|
|
81
|
-
|
|
119
|
+
// Register the new identity DID as a tenant and for sync.
|
|
120
|
+
// Tenant registration must come before sync registration — with live
|
|
121
|
+
// sync active, registerIdentity hot-adds a subscription that needs
|
|
122
|
+
// the DID to be a recognised tenant on the remote DWN.
|
|
123
|
+
if (isNewIdentity && ctx.registration) {
|
|
82
124
|
await registerWithDwnEndpoints(
|
|
83
125
|
{
|
|
84
|
-
userAgent
|
|
126
|
+
userAgent,
|
|
85
127
|
dwnEndpoints,
|
|
86
128
|
agentDid : userAgent.agentDid.uri,
|
|
87
129
|
connectedDid,
|
|
88
130
|
secretStore : userAgent.secrets,
|
|
89
|
-
storage
|
|
131
|
+
storage,
|
|
90
132
|
},
|
|
91
133
|
ctx.registration,
|
|
92
134
|
);
|
|
93
135
|
}
|
|
94
|
-
|
|
95
|
-
// Register sync for new identities.
|
|
96
136
|
if (isNewIdentity && sync !== 'off') {
|
|
97
137
|
await userAgent.sync.registerIdentity({
|
|
98
138
|
did : connectedDid,
|
package/src/index.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* import { AuthManager } from '@enbox/auth';
|
|
11
11
|
*
|
|
12
12
|
* const auth = await AuthManager.create({ sync: '15s' });
|
|
13
|
-
* const session = await auth.
|
|
13
|
+
* const session = await auth.connectVault({ password: userPin });
|
|
14
14
|
* ```
|
|
15
15
|
*
|
|
16
16
|
* @example Dapp with browser connect handler
|
|
@@ -90,6 +90,7 @@ export type {
|
|
|
90
90
|
ImportFromPortableOptions,
|
|
91
91
|
LocalConnectOptions,
|
|
92
92
|
LocalDwnStrategy,
|
|
93
|
+
VaultConnectOptions,
|
|
93
94
|
Permission,
|
|
94
95
|
PortableIdentity,
|
|
95
96
|
ProtocolRequest,
|
package/src/types.ts
CHANGED
|
@@ -381,7 +381,7 @@ export interface AuthManagerOptions {
|
|
|
381
381
|
* Default connect handler for delegated connect flows.
|
|
382
382
|
*
|
|
383
383
|
* Used by `connect()` when the caller provides `protocols` (or other
|
|
384
|
-
* non-
|
|
384
|
+
* non-vault-connect options) but does not pass a per-call handler.
|
|
385
385
|
*
|
|
386
386
|
* @example
|
|
387
387
|
* ```ts
|
|
@@ -398,8 +398,8 @@ export interface AuthManagerOptions {
|
|
|
398
398
|
connectHandler?: ConnectHandler;
|
|
399
399
|
}
|
|
400
400
|
|
|
401
|
-
/** Options for {@link AuthManager.
|
|
402
|
-
export interface
|
|
401
|
+
/** Options for {@link AuthManager.connectVault}. */
|
|
402
|
+
export interface VaultConnectOptions {
|
|
403
403
|
/** Vault password (overrides manager default). */
|
|
404
404
|
password?: string;
|
|
405
405
|
|
|
@@ -434,6 +434,9 @@ export interface LocalConnectOptions {
|
|
|
434
434
|
createIdentity?: boolean;
|
|
435
435
|
}
|
|
436
436
|
|
|
437
|
+
/** @deprecated Use {@link VaultConnectOptions} instead. */
|
|
438
|
+
export type LocalConnectOptions = VaultConnectOptions;
|
|
439
|
+
|
|
437
440
|
// ─── DWeb Connect ────────────────────────────────────────────────
|
|
438
441
|
|
|
439
442
|
/**
|
|
@@ -509,14 +512,14 @@ export interface HandlerConnectOptions {
|
|
|
509
512
|
* `connectHandler` is provided. Delegates to the connect handler
|
|
510
513
|
* for credential acquisition.
|
|
511
514
|
*
|
|
512
|
-
* - **
|
|
515
|
+
* - **Vault connect** (wallets / CLI): triggered when `password`,
|
|
513
516
|
* `createIdentity`, or `recoveryPhrase` is provided.
|
|
514
517
|
*
|
|
515
518
|
* In both cases, `connect()` first attempts to restore a previous session
|
|
516
519
|
* from storage. If a valid session exists, it is returned immediately
|
|
517
520
|
* without any user interaction.
|
|
518
521
|
*/
|
|
519
|
-
export type ConnectOptions = HandlerConnectOptions |
|
|
522
|
+
export type ConnectOptions = HandlerConnectOptions | VaultConnectOptions;
|
|
520
523
|
|
|
521
524
|
/** Options for {@link AuthManager.walletConnect}. */
|
|
522
525
|
export interface WalletConnectOptions {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../../src/connect/local.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../../src/connect/local.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAOvD;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,WAAW,EAChB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,WAAW,CAAC,CAqFtB"}
|