@enbox/auth 0.6.34 → 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/connect/import.js +50 -39
- package/dist/esm/connect/import.js.map +1 -1
- package/dist/esm/connect/recovery.js +105 -0
- package/dist/esm/connect/recovery.js.map +1 -0
- package/dist/esm/connect/vault.js +41 -31
- package/dist/esm/connect/vault.js.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/recovery.d.ts +50 -0
- package/dist/types/connect/recovery.d.ts.map +1 -0
- package/dist/types/connect/vault.d.ts +3 -0
- package/dist/types/connect/vault.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/connect/import.ts +57 -46
- package/src/connect/recovery.ts +111 -0
- package/src/connect/vault.ts +45 -34
|
@@ -14,19 +14,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
14
14
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
15
15
|
});
|
|
16
16
|
};
|
|
17
|
-
import { IdentityProtocolDefinition, JwkProtocolDefinition } from '@enbox/agent';
|
|
18
17
|
import { DEFAULT_DWN_ENDPOINTS } from '../types.js';
|
|
19
18
|
import { registerWithDwnEndpoints } from '../registration.js';
|
|
20
19
|
import { createDefaultIdentity, ensureVaultReady, finalizeSession, registerSyncScopeForIdentity, resolveIdentityDids, startSyncIfEnabled } from './lifecycle.js';
|
|
21
|
-
|
|
22
|
-
IdentityProtocolDefinition.protocol,
|
|
23
|
-
JwkProtocolDefinition.protocol,
|
|
24
|
-
];
|
|
20
|
+
import { recoverIdentitiesFromRemote, registerAgentDidForSync } from './recovery.js';
|
|
25
21
|
/**
|
|
26
22
|
* Import (or recover) an identity from a BIP-39 recovery phrase.
|
|
27
23
|
*
|
|
28
24
|
* This re-initializes the vault with the given phrase and password,
|
|
29
|
-
* recovering the agent DID and all derived keys.
|
|
25
|
+
* recovering the agent DID and all derived keys. If the recovery phrase
|
|
26
|
+
* was previously used to create identities, they are pulled from the
|
|
27
|
+
* remote DWN. Otherwise a new default identity is created.
|
|
30
28
|
*/
|
|
31
29
|
export function importFromPhrase(ctx, options) {
|
|
32
30
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -45,51 +43,64 @@ export function importFromPhrase(ctx, options) {
|
|
|
45
43
|
recoveryPhrase,
|
|
46
44
|
dwnEndpoints,
|
|
47
45
|
});
|
|
48
|
-
//
|
|
49
|
-
// but the user identity might not exist yet — create one if needed.
|
|
50
|
-
const identities = yield userAgent.identity.list();
|
|
51
|
-
let identity = identities[0];
|
|
52
|
-
let isNewIdentity = false;
|
|
53
|
-
if (!identity) {
|
|
54
|
-
isNewIdentity = true;
|
|
55
|
-
identity = yield createDefaultIdentity(userAgent, dwnEndpoints);
|
|
56
|
-
}
|
|
57
|
-
const { connectedDid, delegateDid } = resolveIdentityDids(identity);
|
|
58
|
-
// Register with DWN endpoints (if registration options are provided).
|
|
46
|
+
// Register agent DID as tenant and for sync — prerequisites for recovery.
|
|
59
47
|
if (ctx.registration) {
|
|
60
48
|
yield registerWithDwnEndpoints({
|
|
61
|
-
userAgent
|
|
49
|
+
userAgent,
|
|
62
50
|
dwnEndpoints,
|
|
63
51
|
agentDid: userAgent.agentDid.uri,
|
|
64
|
-
connectedDid,
|
|
52
|
+
connectedDid: userAgent.agentDid.uri,
|
|
65
53
|
secretStore: userAgent.secrets,
|
|
66
|
-
storage
|
|
54
|
+
storage,
|
|
67
55
|
}, ctx.registration);
|
|
68
56
|
}
|
|
69
|
-
// Register sync. For delegate identities, always repair the registration
|
|
70
|
-
// (derive scope from active grants — revoked grants must not remain in a
|
|
71
|
-
// stale registration), regardless of whether the identity was just
|
|
72
|
-
// created or restored from storage. For local identities, register
|
|
73
|
-
// `protocols: 'all'` only on first creation; a pre-existing local
|
|
74
|
-
// identity was already registered during its initial flow.
|
|
75
|
-
if (delegateDid) {
|
|
76
|
-
yield registerSyncScopeForIdentity({ userAgent, connectedDid, delegateDid });
|
|
77
|
-
}
|
|
78
|
-
else if (isNewIdentity && sync !== 'off') {
|
|
79
|
-
yield registerSyncScopeForIdentity({ userAgent, connectedDid });
|
|
80
|
-
}
|
|
81
|
-
// Register the agent DID for sync (same rationale as vaultConnect).
|
|
82
57
|
if (sync !== 'off') {
|
|
58
|
+
yield registerAgentDidForSync(userAgent);
|
|
59
|
+
}
|
|
60
|
+
// Try to recover identities from the remote DWN before falling back
|
|
61
|
+
// to creating a new one.
|
|
62
|
+
let identities = yield userAgent.identity.list();
|
|
63
|
+
let identity = identities[0];
|
|
64
|
+
let isNewIdentity = false;
|
|
65
|
+
if (!identity && sync !== 'off') {
|
|
83
66
|
try {
|
|
84
|
-
yield userAgent.
|
|
85
|
-
|
|
86
|
-
options: { protocols: AGENT_DID_SYNC_PROTOCOLS },
|
|
87
|
-
});
|
|
67
|
+
identities = yield recoverIdentitiesFromRemote({ userAgent, dwnEndpoints, registration: ctx.registration, storage });
|
|
68
|
+
identity = identities[0];
|
|
88
69
|
}
|
|
89
|
-
catch (
|
|
90
|
-
|
|
70
|
+
catch (err) {
|
|
71
|
+
console.warn('[@enbox/auth] Seed phrase recovery failed:', err);
|
|
91
72
|
}
|
|
92
73
|
}
|
|
74
|
+
if (!identity) {
|
|
75
|
+
isNewIdentity = true;
|
|
76
|
+
identity = yield createDefaultIdentity(userAgent, dwnEndpoints);
|
|
77
|
+
}
|
|
78
|
+
const { connectedDid, delegateDid } = resolveIdentityDids(identity);
|
|
79
|
+
// Register sync for the identity DID.
|
|
80
|
+
if (isNewIdentity) {
|
|
81
|
+
// New identity: register as tenant first, then for sync.
|
|
82
|
+
if (ctx.registration) {
|
|
83
|
+
yield registerWithDwnEndpoints({
|
|
84
|
+
userAgent,
|
|
85
|
+
dwnEndpoints,
|
|
86
|
+
agentDid: userAgent.agentDid.uri,
|
|
87
|
+
connectedDid,
|
|
88
|
+
secretStore: userAgent.secrets,
|
|
89
|
+
storage,
|
|
90
|
+
}, ctx.registration);
|
|
91
|
+
}
|
|
92
|
+
if (delegateDid) {
|
|
93
|
+
yield registerSyncScopeForIdentity({ userAgent, connectedDid, delegateDid });
|
|
94
|
+
}
|
|
95
|
+
else if (sync !== 'off') {
|
|
96
|
+
yield registerSyncScopeForIdentity({ userAgent, connectedDid });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else if (delegateDid) {
|
|
100
|
+
// Pre-existing delegate identity: repair sync scope so revoked
|
|
101
|
+
// grants don't remain in a stale registration.
|
|
102
|
+
yield registerSyncScopeForIdentity({ userAgent, connectedDid, delegateDid });
|
|
103
|
+
}
|
|
93
104
|
// Start sync.
|
|
94
105
|
yield startSyncIfEnabled(userAgent, sync);
|
|
95
106
|
// Persist session info, build AuthSession, and emit lifecycle events.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import.js","sourceRoot":"","sources":["../../../src/connect/import.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;;;;;;;;;;AAMH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"import.js","sourceRoot":"","sources":["../../../src/connect/import.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
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
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
13
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
14
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
15
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
16
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
17
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
18
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
import { IdentityProtocolDefinition, JwkProtocolDefinition } from '@enbox/agent';
|
|
22
|
+
import { registerWithDwnEndpoints } from '../registration.js';
|
|
23
|
+
/**
|
|
24
|
+
* Internal protocols that store recovery-critical data in the agent DID's DWN.
|
|
25
|
+
* Syncing these ensures that seed phrase recovery can pull identity metadata,
|
|
26
|
+
* portable DIDs, and encrypted private keys from the remote.
|
|
27
|
+
*/
|
|
28
|
+
export const AGENT_DID_SYNC_PROTOCOLS = [
|
|
29
|
+
IdentityProtocolDefinition.protocol,
|
|
30
|
+
JwkProtocolDefinition.protocol,
|
|
31
|
+
];
|
|
32
|
+
/**
|
|
33
|
+
* Register the agent DID for sync with the recovery-critical protocols.
|
|
34
|
+
*
|
|
35
|
+
* This is a prerequisite for both normal operation (pushing identity
|
|
36
|
+
* metadata to the remote) and seed phrase recovery (pulling it back).
|
|
37
|
+
* Silently succeeds if the agent DID is already registered.
|
|
38
|
+
*/
|
|
39
|
+
export function registerAgentDidForSync(userAgent) {
|
|
40
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
41
|
+
try {
|
|
42
|
+
yield userAgent.sync.registerIdentity({
|
|
43
|
+
did: userAgent.agentDid.uri,
|
|
44
|
+
options: { protocols: AGENT_DID_SYNC_PROTOCOLS },
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch (_a) {
|
|
48
|
+
// Already registered from a previous session.
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Recover identities and their data from remote DWN endpoints.
|
|
54
|
+
*
|
|
55
|
+
* Assumes the agent DID is already registered for sync (via
|
|
56
|
+
* {@link registerAgentDidForSync}) and as a DWN tenant.
|
|
57
|
+
*
|
|
58
|
+
* Phase 1 — pull identity metadata and DID private keys stored in the
|
|
59
|
+
* agent DID's DWN.
|
|
60
|
+
*
|
|
61
|
+
* Phase 2 — register each recovered identity DID as a tenant and for
|
|
62
|
+
* sync, then pull their profile data, protocol configurations, and
|
|
63
|
+
* records.
|
|
64
|
+
*
|
|
65
|
+
* Returns the recovered identities, or an empty array if the remote
|
|
66
|
+
* had nothing (e.g. first-ever setup with a pre-generated phrase).
|
|
67
|
+
*/
|
|
68
|
+
export function recoverIdentitiesFromRemote(params) {
|
|
69
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
70
|
+
var _a;
|
|
71
|
+
const { userAgent, dwnEndpoints, registration, storage } = params;
|
|
72
|
+
const agentDid = userAgent.agentDid.uri;
|
|
73
|
+
// Phase 1: pull identity metadata + encrypted DID keys.
|
|
74
|
+
yield userAgent.sync.sync('pull');
|
|
75
|
+
const identities = yield userAgent.identity.list();
|
|
76
|
+
if (identities.length === 0) {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
// Register each recovered identity DID as a DWN tenant, then for sync.
|
|
80
|
+
// Tenant registration must come first — sync('pull') issues
|
|
81
|
+
// MessagesSync which requires the DID to be a recognised tenant.
|
|
82
|
+
for (const identity of identities) {
|
|
83
|
+
const did = (_a = identity.metadata.connectedDid) !== null && _a !== void 0 ? _a : identity.did.uri;
|
|
84
|
+
if (registration) {
|
|
85
|
+
try {
|
|
86
|
+
yield registerWithDwnEndpoints({ userAgent, dwnEndpoints, agentDid, connectedDid: did, secretStore: userAgent.secrets, storage }, registration);
|
|
87
|
+
}
|
|
88
|
+
catch (_b) {
|
|
89
|
+
// Best effort — the DID may already be registered, or the
|
|
90
|
+
// endpoint may be temporarily unreachable.
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
yield userAgent.sync.registerIdentity({ did, options: { protocols: 'all' } });
|
|
95
|
+
}
|
|
96
|
+
catch (_c) {
|
|
97
|
+
// Already registered from a previous session.
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Phase 2: pull profile data, protocol configurations, and records.
|
|
101
|
+
yield userAgent.sync.sync('pull');
|
|
102
|
+
return userAgent.identity.list();
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=recovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery.js","sourceRoot":"","sources":["../../../src/connect/recovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;;;;;;;;;;AAIH,OAAO,EAAE,0BAA0B,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAIjF,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAE9D;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAA0B;IAC7D,0BAA0B,CAAC,QAAQ;IACnC,qBAAqB,CAAC,QAAQ;CAC/B,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAgB,uBAAuB,CAAC,SAAyB;;QACrE,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC;gBACpC,GAAG,EAAO,SAAS,CAAC,QAAQ,CAAC,GAAG;gBAChC,OAAO,EAAG,EAAE,SAAS,EAAE,wBAAwB,EAAE;aAClD,CAAC,CAAC;QACL,CAAC;QAAC,WAAM,CAAC;YACP,8CAA8C;QAChD,CAAC;IACH,CAAC;CAAA;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAgB,2BAA2B,CAAC,MAKjD;;;QACC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;QAClE,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC;QAExC,wDAAwD;QACxD,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAElC,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,uEAAuE;QACvE,4DAA4D;QAC5D,iEAAiE;QACjE,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE,CAAC;YAClC,MAAM,GAAG,GAAG,MAAA,QAAQ,CAAC,QAAQ,CAAC,YAAY,mCAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;YAE/D,IAAI,YAAY,EAAE,CAAC;gBACjB,IAAI,CAAC;oBACH,MAAM,wBAAwB,CAC5B,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,EAAE,WAAW,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,EACjG,YAAY,CACb,CAAC;gBACJ,CAAC;gBAAC,WAAM,CAAC;oBACP,0DAA0D;oBAC1D,2CAA2C;gBAC7C,CAAC;YACH,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YAChF,CAAC;YAAC,WAAM,CAAC;gBACP,8CAA8C;YAChD,CAAC;QACH,CAAC;QAED,oEAAoE;QACpE,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAElC,OAAO,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IACnC,CAAC;CAAA"}
|
|
@@ -17,26 +17,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
17
17
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
18
|
});
|
|
19
19
|
};
|
|
20
|
-
import { IdentityProtocolDefinition, JwkProtocolDefinition } from '@enbox/agent';
|
|
21
20
|
import { applyLocalDwnDiscovery } from '../discovery.js';
|
|
22
21
|
import { DEFAULT_DWN_ENDPOINTS } from '../types.js';
|
|
23
22
|
import { registerWithDwnEndpoints } from '../registration.js';
|
|
24
23
|
import { createDefaultIdentity, ensureVaultReady, finalizeSession, resolveIdentityDids, resolvePassword, startSyncIfEnabled } from './lifecycle.js';
|
|
25
|
-
|
|
26
|
-
* Internal protocols that store recovery-critical data in the agent DID's DWN.
|
|
27
|
-
* These must be synced so that seed phrase recovery can pull identity metadata,
|
|
28
|
-
* portable DIDs, and encrypted private keys from the remote DWN.
|
|
29
|
-
*/
|
|
30
|
-
const AGENT_DID_SYNC_PROTOCOLS = [
|
|
31
|
-
IdentityProtocolDefinition.protocol,
|
|
32
|
-
JwkProtocolDefinition.protocol,
|
|
33
|
-
];
|
|
24
|
+
import { recoverIdentitiesFromRemote, registerAgentDidForSync } from './recovery.js';
|
|
34
25
|
/**
|
|
35
26
|
* Execute the vault connect flow.
|
|
36
27
|
*
|
|
37
28
|
* - On first launch: initializes the vault. Identity creation is opt-in via
|
|
38
29
|
* `options.createIdentity: true`.
|
|
39
30
|
* - On subsequent launches: unlocks the vault and reconnects to the existing identity.
|
|
31
|
+
* - On recovery: when `recoveryPhrase` is provided on a fresh vault, pulls
|
|
32
|
+
* identities and their data from the remote DWN before falling back to
|
|
33
|
+
* identity creation.
|
|
40
34
|
*
|
|
41
35
|
* When no identities exist and `createIdentity` is not `true`, the session
|
|
42
36
|
* is returned with the **agent DID** as the connected DID. This allows apps to
|
|
@@ -66,10 +60,38 @@ export function vaultConnect(ctx_1) {
|
|
|
66
60
|
if (!userAgent.dwn.isRemoteMode) {
|
|
67
61
|
yield applyLocalDwnDiscovery(userAgent, storage, emitter);
|
|
68
62
|
}
|
|
69
|
-
//
|
|
70
|
-
|
|
63
|
+
// Register the agent DID as a DWN tenant and for sync early — both are
|
|
64
|
+
// prerequisites for seed phrase recovery and for normal push/pull of
|
|
65
|
+
// identity metadata after identity creation.
|
|
66
|
+
if (ctx.registration) {
|
|
67
|
+
yield registerWithDwnEndpoints({
|
|
68
|
+
userAgent,
|
|
69
|
+
dwnEndpoints,
|
|
70
|
+
agentDid: userAgent.agentDid.uri,
|
|
71
|
+
connectedDid: userAgent.agentDid.uri,
|
|
72
|
+
secretStore: userAgent.secrets,
|
|
73
|
+
storage,
|
|
74
|
+
}, ctx.registration);
|
|
75
|
+
}
|
|
76
|
+
if (sync !== 'off') {
|
|
77
|
+
yield registerAgentDidForSync(userAgent);
|
|
78
|
+
}
|
|
79
|
+
// Find existing identities.
|
|
80
|
+
let identities = yield userAgent.identity.list();
|
|
71
81
|
let identity = identities[0];
|
|
72
82
|
let isNewIdentity = false;
|
|
83
|
+
// Seed phrase recovery: when a recovery phrase was provided on a fresh
|
|
84
|
+
// vault and no identities exist locally, pull them from the remote DWN.
|
|
85
|
+
if (!identity && isFirstLaunch && options.recoveryPhrase && sync !== 'off') {
|
|
86
|
+
try {
|
|
87
|
+
identities = yield recoverIdentitiesFromRemote({ userAgent, dwnEndpoints, registration: ctx.registration, storage });
|
|
88
|
+
identity = identities[0];
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
console.warn('[@enbox/auth] Seed phrase recovery failed:', err);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Create a default identity if none were found or recovered.
|
|
73
95
|
if (!identity && shouldCreateIdentity) {
|
|
74
96
|
isNewIdentity = true;
|
|
75
97
|
identity = yield createDefaultIdentity(userAgent, dwnEndpoints, (_e = (_d = options.metadata) === null || _d === void 0 ? void 0 : _d.name) !== null && _e !== void 0 ? _e : 'Default');
|
|
@@ -83,38 +105,26 @@ export function vaultConnect(ctx_1) {
|
|
|
83
105
|
const delegateDid = identity
|
|
84
106
|
? resolveIdentityDids(identity).delegateDid
|
|
85
107
|
: undefined;
|
|
86
|
-
// Register
|
|
87
|
-
|
|
108
|
+
// Register the new identity DID as a tenant and for sync.
|
|
109
|
+
// Tenant registration must come before sync registration — with live
|
|
110
|
+
// sync active, registerIdentity hot-adds a subscription that needs
|
|
111
|
+
// the DID to be a recognised tenant on the remote DWN.
|
|
112
|
+
if (isNewIdentity && ctx.registration) {
|
|
88
113
|
yield registerWithDwnEndpoints({
|
|
89
|
-
userAgent
|
|
114
|
+
userAgent,
|
|
90
115
|
dwnEndpoints,
|
|
91
116
|
agentDid: userAgent.agentDid.uri,
|
|
92
117
|
connectedDid,
|
|
93
118
|
secretStore: userAgent.secrets,
|
|
94
|
-
storage
|
|
119
|
+
storage,
|
|
95
120
|
}, ctx.registration);
|
|
96
121
|
}
|
|
97
|
-
// Register sync for new identities.
|
|
98
122
|
if (isNewIdentity && sync !== 'off') {
|
|
99
123
|
yield userAgent.sync.registerIdentity({
|
|
100
124
|
did: connectedDid,
|
|
101
125
|
options: { delegateDid, protocols: 'all' },
|
|
102
126
|
});
|
|
103
127
|
}
|
|
104
|
-
// Register the agent DID for sync so that identity metadata, portable
|
|
105
|
-
// DIDs, and encrypted private keys are pushed to the remote DWN. Without
|
|
106
|
-
// this, seed phrase recovery on a new device has nothing to pull.
|
|
107
|
-
if (sync !== 'off') {
|
|
108
|
-
try {
|
|
109
|
-
yield userAgent.sync.registerIdentity({
|
|
110
|
-
did: userAgent.agentDid.uri,
|
|
111
|
-
options: { protocols: AGENT_DID_SYNC_PROTOCOLS },
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
catch (_f) {
|
|
115
|
-
// Already registered from a previous session — no action needed.
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
128
|
// Start sync.
|
|
119
129
|
yield startSyncIfEnabled(userAgent, sync);
|
|
120
130
|
// Persist session info, build AuthSession, and emit lifecycle events.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vault.js","sourceRoot":"","sources":["../../../src/connect/vault.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;;;;;;;;;;AAMH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"vault.js","sourceRoot":"","sources":["../../../src/connect/vault.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;;;;;;;;;;AAMH,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,eAAe,EAAE,mBAAmB,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpJ,OAAO,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAErF;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAgB,YAAY;yDAChC,GAAgB,EAChB,UAA+B,EAAE;;QAEjC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,GAAG,CAAC;QAE5C,+CAA+C;QAC/C,MAAM,aAAa,GAAG,MAAM,SAAS,CAAC,WAAW,EAAE,CAAC;QACpD,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QAE7E,MAAM,IAAI,GAAG,MAAA,OAAO,CAAC,IAAI,mCAAI,GAAG,CAAC,WAAW,CAAC;QAC7C,MAAM,YAAY,GAAG,MAAA,MAAA,OAAO,CAAC,YAAY,mCAAI,GAAG,CAAC,mBAAmB,mCAAI,qBAAqB,CAAC;QAC9F,MAAM,oBAAoB,GAAG,OAAO,CAAC,cAAc,KAAK,IAAI,CAAC;QAE7D,wDAAwD;QACxD,MAAM,cAAc,GAAG,MAAM,gBAAgB,CAAC;YAC5C,SAAS;YACT,OAAO;YACP,QAAQ;YACR,aAAa;YACb,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,YAAY;SACb,CAAC,CAAC;QAEH,8EAA8E;QAC9E,sEAAsE;QACtE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;YAChC,MAAM,sBAAsB,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAC5D,CAAC;QAED,uEAAuE;QACvE,qEAAqE;QACrE,6CAA6C;QAC7C,IAAI,GAAG,CAAC,YAAY,EAAE,CAAC;YACrB,MAAM,wBAAwB,CAC5B;gBACE,SAAS;gBACT,YAAY;gBACZ,QAAQ,EAAO,SAAS,CAAC,QAAQ,CAAC,GAAG;gBACrC,YAAY,EAAG,SAAS,CAAC,QAAQ,CAAC,GAAG;gBACrC,WAAW,EAAI,SAAS,CAAC,OAAO;gBAChC,OAAO;aACR,EACD,GAAG,CAAC,YAAY,CACjB,CAAC;QACJ,CAAC;QACD,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;YACnB,MAAM,uBAAuB,CAAC,SAAS,CAAC,CAAC;QAC3C,CAAC;QAED,4BAA4B;QAC5B,IAAI,UAAU,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACjD,IAAI,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QAC7B,IAAI,aAAa,GAAG,KAAK,CAAC;QAE1B,uEAAuE;QACvE,wEAAwE;QACxE,IAAI,CAAC,QAAQ,IAAI,aAAa,IAAI,OAAO,CAAC,cAAc,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;YAC3E,IAAI,CAAC;gBACH,UAAU,GAAG,MAAM,2BAA2B,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,OAAO,EAAE,CAAC,CAAC;gBACrH,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YAC3B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CAAC,4CAA4C,EAAE,GAAG,CAAC,CAAC;YAClE,CAAC;QACH,CAAC;QAED,6DAA6D;QAC7D,IAAI,CAAC,QAAQ,IAAI,oBAAoB,EAAE,CAAC;YACtC,aAAa,GAAG,IAAI,CAAC;YACrB,QAAQ,GAAG,MAAM,qBAAqB,CAAC,SAAS,EAAE,YAAY,EAAE,MAAA,MAAA,OAAO,CAAC,QAAQ,0CAAE,IAAI,mCAAI,SAAS,CAAC,CAAC;QACvG,CAAC;QAED,2EAA2E;QAC3E,2EAA2E;QAC3E,yEAAyE;QACzE,MAAM,YAAY,GAAG,QAAQ;YAC3B,CAAC,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC,YAAY;YAC5C,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC;QAE3B,MAAM,WAAW,GAAG,QAAQ;YAC1B,CAAC,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC,WAAW;YAC3C,CAAC,CAAC,SAAS,CAAC;QAEd,0DAA0D;QAC1D,qEAAqE;QACrE,mEAAmE;QACnE,uDAAuD;QACvD,IAAI,aAAa,IAAI,GAAG,CAAC,YAAY,EAAE,CAAC;YACtC,MAAM,wBAAwB,CAC5B;gBACE,SAAS;gBACT,YAAY;gBACZ,QAAQ,EAAM,SAAS,CAAC,QAAQ,CAAC,GAAG;gBACpC,YAAY;gBACZ,WAAW,EAAG,SAAS,CAAC,OAAO;gBAC/B,OAAO;aACR,EACD,GAAG,CAAC,YAAY,CACjB,CAAC;QACJ,CAAC;QACD,IAAI,aAAa,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;YACpC,MAAM,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC;gBACpC,GAAG,EAAO,YAAY;gBACtB,OAAO,EAAG,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE;aAC5C,CAAC,CAAC;QACL,CAAC;QAED,cAAc;QACd,MAAM,kBAAkB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAE1C,sEAAsE;QACtE,OAAO,eAAe,CAAC;YACrB,SAAS;YACT,OAAO;YACP,OAAO;YACP,YAAY;YACZ,WAAW;YACX,cAAc;YACd,YAAY,EAAW,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,QAAQ,CAAC,IAAI;YAC9C,oBAAoB,EAAG,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,QAAQ,CAAC,YAAY;SACvD,CAAC,CAAC;IACL,CAAC;CAAA"}
|
|
@@ -12,7 +12,9 @@ import type { ImportFromPhraseOptions, ImportFromPortableOptions } from '../type
|
|
|
12
12
|
* Import (or recover) an identity from a BIP-39 recovery phrase.
|
|
13
13
|
*
|
|
14
14
|
* This re-initializes the vault with the given phrase and password,
|
|
15
|
-
* recovering the agent DID and all derived keys.
|
|
15
|
+
* recovering the agent DID and all derived keys. If the recovery phrase
|
|
16
|
+
* was previously used to create identities, they are pulled from the
|
|
17
|
+
* remote DWN. Otherwise a new default identity is created.
|
|
16
18
|
*/
|
|
17
19
|
export declare function importFromPhrase(ctx: FlowContext, options: ImportFromPhraseOptions): Promise<AuthSession>;
|
|
18
20
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../../src/connect/import.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,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../../src/connect/import.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,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAOtF;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,WAAW,CAAC,CAiGtB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,WAAW,CAAC,CA8CtB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
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
|
+
import type { BearerIdentity, EnboxUserAgent } from '@enbox/agent';
|
|
13
|
+
import type { RegistrationOptions, StorageAdapter } from '../types.js';
|
|
14
|
+
/**
|
|
15
|
+
* Internal protocols that store recovery-critical data in the agent DID's DWN.
|
|
16
|
+
* Syncing these ensures that seed phrase recovery can pull identity metadata,
|
|
17
|
+
* portable DIDs, and encrypted private keys from the remote.
|
|
18
|
+
*/
|
|
19
|
+
export declare const AGENT_DID_SYNC_PROTOCOLS: [string, ...string[]];
|
|
20
|
+
/**
|
|
21
|
+
* Register the agent DID for sync with the recovery-critical protocols.
|
|
22
|
+
*
|
|
23
|
+
* This is a prerequisite for both normal operation (pushing identity
|
|
24
|
+
* metadata to the remote) and seed phrase recovery (pulling it back).
|
|
25
|
+
* Silently succeeds if the agent DID is already registered.
|
|
26
|
+
*/
|
|
27
|
+
export declare function registerAgentDidForSync(userAgent: EnboxUserAgent): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Recover identities and their data from remote DWN endpoints.
|
|
30
|
+
*
|
|
31
|
+
* Assumes the agent DID is already registered for sync (via
|
|
32
|
+
* {@link registerAgentDidForSync}) and as a DWN tenant.
|
|
33
|
+
*
|
|
34
|
+
* Phase 1 — pull identity metadata and DID private keys stored in the
|
|
35
|
+
* agent DID's DWN.
|
|
36
|
+
*
|
|
37
|
+
* Phase 2 — register each recovered identity DID as a tenant and for
|
|
38
|
+
* sync, then pull their profile data, protocol configurations, and
|
|
39
|
+
* records.
|
|
40
|
+
*
|
|
41
|
+
* Returns the recovered identities, or an empty array if the remote
|
|
42
|
+
* had nothing (e.g. first-ever setup with a pre-generated phrase).
|
|
43
|
+
*/
|
|
44
|
+
export declare function recoverIdentitiesFromRemote(params: {
|
|
45
|
+
userAgent: EnboxUserAgent;
|
|
46
|
+
dwnEndpoints: string[];
|
|
47
|
+
registration?: RegistrationOptions;
|
|
48
|
+
storage: StorageAdapter;
|
|
49
|
+
}): Promise<BearerIdentity[]>;
|
|
50
|
+
//# sourceMappingURL=recovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../../../src/connect/recovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAInE,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIvE;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAG1D,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAAC,SAAS,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAStF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,2BAA2B,CAAC,MAAM,EAAE;IACxD,SAAS,EAAE,cAAc,CAAC;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,OAAO,EAAE,cAAc,CAAC;CACzB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAyC5B"}
|
|
@@ -17,6 +17,9 @@ import type { VaultConnectOptions } from '../types.js';
|
|
|
17
17
|
* - On first launch: initializes the vault. Identity creation is opt-in via
|
|
18
18
|
* `options.createIdentity: true`.
|
|
19
19
|
* - On subsequent launches: unlocks the vault and reconnects to the existing identity.
|
|
20
|
+
* - On recovery: when `recoveryPhrase` is provided on a fresh vault, pulls
|
|
21
|
+
* identities and their data from the remote DWN before falling back to
|
|
22
|
+
* identity creation.
|
|
20
23
|
*
|
|
21
24
|
* When no identities exist and `createIdentity` is not `true`, the session
|
|
22
25
|
* is returned with the **agent DID** as the connected DID. This allows apps to
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../../../src/connect/vault.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;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;
|
|
1
|
+
{"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../../../src/connect/vault.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;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;AAQvD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,WAAW,EAChB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,WAAW,CAAC,CAsHtB"}
|
package/package.json
CHANGED
package/src/connect/import.ts
CHANGED
|
@@ -10,22 +10,18 @@ import type { AuthSession } from '../identity-session.js';
|
|
|
10
10
|
import type { FlowContext } from './lifecycle.js';
|
|
11
11
|
import type { ImportFromPhraseOptions, ImportFromPortableOptions } from '../types.js';
|
|
12
12
|
|
|
13
|
-
import { IdentityProtocolDefinition, JwkProtocolDefinition } from '@enbox/agent';
|
|
14
|
-
|
|
15
13
|
import { DEFAULT_DWN_ENDPOINTS } from '../types.js';
|
|
16
14
|
import { registerWithDwnEndpoints } from '../registration.js';
|
|
17
15
|
import { createDefaultIdentity, ensureVaultReady, finalizeSession, registerSyncScopeForIdentity, resolveIdentityDids, startSyncIfEnabled } from './lifecycle.js';
|
|
18
|
-
|
|
19
|
-
const AGENT_DID_SYNC_PROTOCOLS: [string, ...string[]] = [
|
|
20
|
-
IdentityProtocolDefinition.protocol,
|
|
21
|
-
JwkProtocolDefinition.protocol,
|
|
22
|
-
];
|
|
16
|
+
import { recoverIdentitiesFromRemote, registerAgentDidForSync } from './recovery.js';
|
|
23
17
|
|
|
24
18
|
/**
|
|
25
19
|
* Import (or recover) an identity from a BIP-39 recovery phrase.
|
|
26
20
|
*
|
|
27
21
|
* This re-initializes the vault with the given phrase and password,
|
|
28
|
-
* recovering the agent DID and all derived keys.
|
|
22
|
+
* recovering the agent DID and all derived keys. If the recovery phrase
|
|
23
|
+
* was previously used to create identities, they are pulled from the
|
|
24
|
+
* remote DWN. Otherwise a new default identity is created.
|
|
29
25
|
*/
|
|
30
26
|
export async function importFromPhrase(
|
|
31
27
|
ctx: FlowContext,
|
|
@@ -47,58 +43,73 @@ export async function importFromPhrase(
|
|
|
47
43
|
dwnEndpoints,
|
|
48
44
|
});
|
|
49
45
|
|
|
50
|
-
//
|
|
51
|
-
// but the user identity might not exist yet — create one if needed.
|
|
52
|
-
const identities = await userAgent.identity.list();
|
|
53
|
-
let identity = identities[0];
|
|
54
|
-
let isNewIdentity = false;
|
|
55
|
-
|
|
56
|
-
if (!identity) {
|
|
57
|
-
isNewIdentity = true;
|
|
58
|
-
identity = await createDefaultIdentity(userAgent, dwnEndpoints);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const { connectedDid, delegateDid } = resolveIdentityDids(identity);
|
|
62
|
-
|
|
63
|
-
// Register with DWN endpoints (if registration options are provided).
|
|
46
|
+
// Register agent DID as tenant and for sync — prerequisites for recovery.
|
|
64
47
|
if (ctx.registration) {
|
|
65
48
|
await registerWithDwnEndpoints(
|
|
66
49
|
{
|
|
67
|
-
userAgent
|
|
50
|
+
userAgent,
|
|
68
51
|
dwnEndpoints,
|
|
69
|
-
agentDid
|
|
70
|
-
connectedDid,
|
|
71
|
-
secretStore
|
|
72
|
-
storage
|
|
52
|
+
agentDid : userAgent.agentDid.uri,
|
|
53
|
+
connectedDid : userAgent.agentDid.uri,
|
|
54
|
+
secretStore : userAgent.secrets,
|
|
55
|
+
storage,
|
|
73
56
|
},
|
|
74
57
|
ctx.registration,
|
|
75
58
|
);
|
|
76
59
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
// (derive scope from active grants — revoked grants must not remain in a
|
|
80
|
-
// stale registration), regardless of whether the identity was just
|
|
81
|
-
// created or restored from storage. For local identities, register
|
|
82
|
-
// `protocols: 'all'` only on first creation; a pre-existing local
|
|
83
|
-
// identity was already registered during its initial flow.
|
|
84
|
-
if (delegateDid) {
|
|
85
|
-
await registerSyncScopeForIdentity({ userAgent, connectedDid, delegateDid });
|
|
86
|
-
} else if (isNewIdentity && sync !== 'off') {
|
|
87
|
-
await registerSyncScopeForIdentity({ userAgent, connectedDid });
|
|
60
|
+
if (sync !== 'off') {
|
|
61
|
+
await registerAgentDidForSync(userAgent);
|
|
88
62
|
}
|
|
89
63
|
|
|
90
|
-
//
|
|
91
|
-
|
|
64
|
+
// Try to recover identities from the remote DWN before falling back
|
|
65
|
+
// to creating a new one.
|
|
66
|
+
let identities = await userAgent.identity.list();
|
|
67
|
+
let identity = identities[0];
|
|
68
|
+
let isNewIdentity = false;
|
|
69
|
+
|
|
70
|
+
if (!identity && sync !== 'off') {
|
|
92
71
|
try {
|
|
93
|
-
await userAgent.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
} catch {
|
|
98
|
-
// Already registered from a previous session.
|
|
72
|
+
identities = await recoverIdentitiesFromRemote({ userAgent, dwnEndpoints, registration: ctx.registration, storage });
|
|
73
|
+
identity = identities[0];
|
|
74
|
+
} catch (err) {
|
|
75
|
+
console.warn('[@enbox/auth] Seed phrase recovery failed:', err);
|
|
99
76
|
}
|
|
100
77
|
}
|
|
101
78
|
|
|
79
|
+
if (!identity) {
|
|
80
|
+
isNewIdentity = true;
|
|
81
|
+
identity = await createDefaultIdentity(userAgent, dwnEndpoints);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const { connectedDid, delegateDid } = resolveIdentityDids(identity);
|
|
85
|
+
|
|
86
|
+
// Register sync for the identity DID.
|
|
87
|
+
if (isNewIdentity) {
|
|
88
|
+
// New identity: register as tenant first, then for sync.
|
|
89
|
+
if (ctx.registration) {
|
|
90
|
+
await registerWithDwnEndpoints(
|
|
91
|
+
{
|
|
92
|
+
userAgent,
|
|
93
|
+
dwnEndpoints,
|
|
94
|
+
agentDid : userAgent.agentDid.uri,
|
|
95
|
+
connectedDid,
|
|
96
|
+
secretStore : userAgent.secrets,
|
|
97
|
+
storage,
|
|
98
|
+
},
|
|
99
|
+
ctx.registration,
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
if (delegateDid) {
|
|
103
|
+
await registerSyncScopeForIdentity({ userAgent, connectedDid, delegateDid });
|
|
104
|
+
} else if (sync !== 'off') {
|
|
105
|
+
await registerSyncScopeForIdentity({ userAgent, connectedDid });
|
|
106
|
+
}
|
|
107
|
+
} else if (delegateDid) {
|
|
108
|
+
// Pre-existing delegate identity: repair sync scope so revoked
|
|
109
|
+
// grants don't remain in a stale registration.
|
|
110
|
+
await registerSyncScopeForIdentity({ userAgent, connectedDid, delegateDid });
|
|
111
|
+
}
|
|
112
|
+
|
|
102
113
|
// Start sync.
|
|
103
114
|
await startSyncIfEnabled(userAgent, sync);
|
|
104
115
|
|
|
@@ -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
|
+
}
|
package/src/connect/vault.ts
CHANGED
|
@@ -13,22 +13,11 @@ import type { AuthSession } from '../identity-session.js';
|
|
|
13
13
|
import type { FlowContext } from './lifecycle.js';
|
|
14
14
|
import type { VaultConnectOptions } from '../types.js';
|
|
15
15
|
|
|
16
|
-
import { IdentityProtocolDefinition, JwkProtocolDefinition } from '@enbox/agent';
|
|
17
|
-
|
|
18
16
|
import { applyLocalDwnDiscovery } from '../discovery.js';
|
|
19
17
|
import { DEFAULT_DWN_ENDPOINTS } from '../types.js';
|
|
20
18
|
import { registerWithDwnEndpoints } from '../registration.js';
|
|
21
19
|
import { createDefaultIdentity, ensureVaultReady, finalizeSession, resolveIdentityDids, resolvePassword, startSyncIfEnabled } from './lifecycle.js';
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Internal protocols that store recovery-critical data in the agent DID's DWN.
|
|
25
|
-
* These must be synced so that seed phrase recovery can pull identity metadata,
|
|
26
|
-
* portable DIDs, and encrypted private keys from the remote DWN.
|
|
27
|
-
*/
|
|
28
|
-
const AGENT_DID_SYNC_PROTOCOLS: [string, ...string[]] = [
|
|
29
|
-
IdentityProtocolDefinition.protocol,
|
|
30
|
-
JwkProtocolDefinition.protocol,
|
|
31
|
-
];
|
|
20
|
+
import { recoverIdentitiesFromRemote, registerAgentDidForSync } from './recovery.js';
|
|
32
21
|
|
|
33
22
|
/**
|
|
34
23
|
* Execute the vault connect flow.
|
|
@@ -36,6 +25,9 @@ const AGENT_DID_SYNC_PROTOCOLS: [string, ...string[]] = [
|
|
|
36
25
|
* - On first launch: initializes the vault. Identity creation is opt-in via
|
|
37
26
|
* `options.createIdentity: true`.
|
|
38
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.
|
|
39
31
|
*
|
|
40
32
|
* When no identities exist and `createIdentity` is not `true`, the session
|
|
41
33
|
* is returned with the **agent DID** as the connected DID. This allows apps to
|
|
@@ -71,11 +63,43 @@ export async function vaultConnect(
|
|
|
71
63
|
await applyLocalDwnDiscovery(userAgent, storage, emitter);
|
|
72
64
|
}
|
|
73
65
|
|
|
74
|
-
//
|
|
75
|
-
|
|
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();
|
|
76
88
|
let identity = identities[0];
|
|
77
89
|
let isNewIdentity = false;
|
|
78
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.
|
|
79
103
|
if (!identity && shouldCreateIdentity) {
|
|
80
104
|
isNewIdentity = true;
|
|
81
105
|
identity = await createDefaultIdentity(userAgent, dwnEndpoints, options.metadata?.name ?? 'Default');
|
|
@@ -92,22 +116,23 @@ export async function vaultConnect(
|
|
|
92
116
|
? resolveIdentityDids(identity).delegateDid
|
|
93
117
|
: undefined;
|
|
94
118
|
|
|
95
|
-
// Register
|
|
96
|
-
|
|
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) {
|
|
97
124
|
await registerWithDwnEndpoints(
|
|
98
125
|
{
|
|
99
|
-
userAgent
|
|
126
|
+
userAgent,
|
|
100
127
|
dwnEndpoints,
|
|
101
128
|
agentDid : userAgent.agentDid.uri,
|
|
102
129
|
connectedDid,
|
|
103
130
|
secretStore : userAgent.secrets,
|
|
104
|
-
storage
|
|
131
|
+
storage,
|
|
105
132
|
},
|
|
106
133
|
ctx.registration,
|
|
107
134
|
);
|
|
108
135
|
}
|
|
109
|
-
|
|
110
|
-
// Register sync for new identities.
|
|
111
136
|
if (isNewIdentity && sync !== 'off') {
|
|
112
137
|
await userAgent.sync.registerIdentity({
|
|
113
138
|
did : connectedDid,
|
|
@@ -115,20 +140,6 @@ export async function vaultConnect(
|
|
|
115
140
|
});
|
|
116
141
|
}
|
|
117
142
|
|
|
118
|
-
// Register the agent DID for sync so that identity metadata, portable
|
|
119
|
-
// DIDs, and encrypted private keys are pushed to the remote DWN. Without
|
|
120
|
-
// this, seed phrase recovery on a new device has nothing to pull.
|
|
121
|
-
if (sync !== 'off') {
|
|
122
|
-
try {
|
|
123
|
-
await userAgent.sync.registerIdentity({
|
|
124
|
-
did : userAgent.agentDid.uri,
|
|
125
|
-
options : { protocols: AGENT_DID_SYNC_PROTOCOLS },
|
|
126
|
-
});
|
|
127
|
-
} catch {
|
|
128
|
-
// Already registered from a previous session — no action needed.
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
143
|
// Start sync.
|
|
133
144
|
await startSyncIfEnabled(userAgent, sync);
|
|
134
145
|
|