@enbox/auth 0.6.32 → 0.6.33
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 +78 -43
- package/dist/esm/auth-manager.js.map +1 -1
- package/dist/esm/connect/lifecycle.js +29 -31
- package/dist/esm/connect/lifecycle.js.map +1 -1
- package/dist/esm/connect/restore.js +3 -2
- package/dist/esm/connect/restore.js.map +1 -1
- package/dist/esm/connect/wallet.js +10 -2
- package/dist/esm/connect/wallet.js.map +1 -1
- package/dist/esm/identity-session.js +11 -23
- package/dist/esm/identity-session.js.map +1 -1
- package/dist/esm/password-provider.js.map +1 -1
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/wallet-connect-client.js +12 -10
- package/dist/esm/wallet-connect-client.js.map +1 -1
- package/dist/types/auth-manager.d.ts +36 -12
- package/dist/types/auth-manager.d.ts.map +1 -1
- package/dist/types/connect/lifecycle.d.ts +16 -2
- package/dist/types/connect/lifecycle.d.ts.map +1 -1
- package/dist/types/connect/restore.d.ts.map +1 -1
- package/dist/types/connect/wallet.d.ts.map +1 -1
- package/dist/types/identity-session.d.ts +11 -42
- package/dist/types/identity-session.d.ts.map +1 -1
- package/dist/types/password-provider.d.ts +25 -9
- package/dist/types/password-provider.d.ts.map +1 -1
- package/dist/types/types.d.ts +18 -13
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/wallet-connect-client.d.ts.map +1 -1
- package/package.json +11 -7
- package/src/auth-manager.ts +98 -57
- package/src/connect/lifecycle.ts +58 -36
- package/src/connect/restore.ts +15 -5
- package/src/connect/wallet.ts +11 -3
- package/src/identity-session.ts +11 -55
- package/src/password-provider.ts +27 -11
- package/src/types.ts +19 -15
- package/src/wallet-connect-client.ts +13 -11
package/src/connect/restore.ts
CHANGED
|
@@ -12,7 +12,8 @@ import type { RestoreSessionOptions } from '../types.js';
|
|
|
12
12
|
|
|
13
13
|
import type { StorageAdapter } from '../types.js';
|
|
14
14
|
|
|
15
|
-
import type {
|
|
15
|
+
import type { RecordsWriteMessage } from '@enbox/dwn-sdk-js';
|
|
16
|
+
import type { DwnDataEncodedRecordsWriteMessage, EnboxUserAgent } from '@enbox/agent';
|
|
16
17
|
|
|
17
18
|
import { Convert } from '@enbox/common';
|
|
18
19
|
import { DataStream } from '@enbox/dwn-sdk-js';
|
|
@@ -392,7 +393,16 @@ async function ensureRevocationGrantOnRemote(
|
|
|
392
393
|
});
|
|
393
394
|
if (reply.status.code !== 200 || !reply.entry?.recordsWrite) { return; }
|
|
394
395
|
|
|
395
|
-
|
|
396
|
+
// `RecordsWriteMessage` doesn't declare `encodedData`, but the
|
|
397
|
+
// wire-format reply may include it; widen the local type to
|
|
398
|
+
// acknowledge that without `any`.
|
|
399
|
+
// NOSONAR S4325 false positive: the cast is required to typecheck
|
|
400
|
+
// the destructuring of the undeclared optional `encodedData`
|
|
401
|
+
// property; removing it fails TS2339. Sonar reads the intersection-
|
|
402
|
+
// with-optional-field as a no-op widening, which it isn't here.
|
|
403
|
+
type RecordsWriteWireMessage = RecordsWriteMessage & { encodedData?: string };
|
|
404
|
+
const { encodedData: _encoded, ...rawMessage } =
|
|
405
|
+
reply.entry.recordsWrite as RecordsWriteWireMessage; // NOSONAR
|
|
396
406
|
const data = reply.entry.data
|
|
397
407
|
? new Blob([await DataStream.toBytes(reply.entry.data) as BlobPart])
|
|
398
408
|
: undefined;
|
|
@@ -439,18 +449,18 @@ async function revokeAndSendSingle(
|
|
|
439
449
|
messageType : DwnInterface.RecordsRead,
|
|
440
450
|
messageParams : { filter: { recordId: entry.grantId } },
|
|
441
451
|
});
|
|
442
|
-
if (readReply.status.code !== 200 || !readReply.entry) { return false; }
|
|
452
|
+
if (readReply.status.code !== 200 || !readReply.entry?.recordsWrite) { return false; }
|
|
443
453
|
|
|
444
454
|
// Reconstruct DwnDataEncodedRecordsWriteMessage: RecordsRead returns
|
|
445
455
|
// the data as a stream, but PermissionGrant.parse needs encodedData.
|
|
446
456
|
const grantDataBytes = readReply.entry.data
|
|
447
457
|
? await DataStream.toBytes(readReply.entry.data)
|
|
448
458
|
: new Uint8Array(0);
|
|
449
|
-
const grantMessageWithData = {
|
|
459
|
+
const grantMessageWithData: DwnDataEncodedRecordsWriteMessage = {
|
|
450
460
|
...readReply.entry.recordsWrite,
|
|
451
461
|
encodedData: Convert.uint8Array(grantDataBytes).toBase64Url(),
|
|
452
462
|
};
|
|
453
|
-
const grant = DwnPermissionGrant.parse(grantMessageWithData
|
|
463
|
+
const grant = DwnPermissionGrant.parse(grantMessageWithData);
|
|
454
464
|
|
|
455
465
|
const { message } = await userAgent.permissions.createRevocation({
|
|
456
466
|
author : connectedDid,
|
package/src/connect/wallet.ts
CHANGED
|
@@ -60,7 +60,6 @@ export async function walletConnect(
|
|
|
60
60
|
const identity = await importDelegateAndSetupSync({
|
|
61
61
|
userAgent, delegatePortableDid, connectedDid, delegateGrants,
|
|
62
62
|
delegateDecryptionKeys, delegateContextKeys, delegateMultiPartyProtocols,
|
|
63
|
-
sessionRevocations,
|
|
64
63
|
flowName: 'Wallet connect',
|
|
65
64
|
});
|
|
66
65
|
|
|
@@ -80,9 +79,18 @@ export async function walletConnect(
|
|
|
80
79
|
);
|
|
81
80
|
}
|
|
82
81
|
|
|
83
|
-
// Finalize session.
|
|
82
|
+
// Finalize session. Pass the transient delegate state explicitly so
|
|
83
|
+
// `persistOrClearDelegateSecrets` doesn't have to read it back off
|
|
84
|
+
// the identity object (which was the old `(identity as any)._foo`
|
|
85
|
+
// smuggling pattern).
|
|
84
86
|
return finalizeDelegateSession({
|
|
85
87
|
userAgent, emitter, storage, identity,
|
|
86
|
-
connectedDid, delegateDid: delegatePortableDid.uri, sync,
|
|
88
|
+
connectedDid, delegateDid : delegatePortableDid.uri, sync,
|
|
89
|
+
delegateState : {
|
|
90
|
+
delegateDecryptionKeys,
|
|
91
|
+
delegateContextKeys,
|
|
92
|
+
delegateMultiPartyProtocols,
|
|
93
|
+
sessionRevocations,
|
|
94
|
+
},
|
|
87
95
|
});
|
|
88
96
|
}
|
package/src/identity-session.ts
CHANGED
|
@@ -1,65 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* AuthSession
|
|
3
|
-
* @module
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { EnboxAgent } from '@enbox/agent';
|
|
7
|
-
|
|
8
|
-
import type { IdentityInfo } from './types.js';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* An active, authenticated session bound to a specific identity.
|
|
2
|
+
* `AuthSession` is an alias for {@link AgentSession} from `@enbox/agent`.
|
|
12
3
|
*
|
|
13
|
-
* The
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
4
|
+
* The alias exists so `@enbox/auth`'s public surface stays self-contained.
|
|
5
|
+
* `new AuthSession(...)` constructs an `AgentSession`, and `instanceof
|
|
6
|
+
* AuthSession` and `instanceof AgentSession` both succeed on any session
|
|
7
|
+
* created through either name. New code should prefer `AgentSession`
|
|
8
|
+
* directly.
|
|
17
9
|
*
|
|
10
|
+
* @example
|
|
18
11
|
* ```ts
|
|
19
12
|
* import { Enbox } from '@enbox/api';
|
|
20
13
|
*
|
|
21
14
|
* const session = await auth.connect();
|
|
22
|
-
* const enbox = Enbox.
|
|
23
|
-
* agent: session.agent,
|
|
24
|
-
* connectedDid: session.did,
|
|
25
|
-
* delegateDid: session.delegateDid,
|
|
26
|
-
* });
|
|
15
|
+
* const enbox = Enbox.fromSession(session);
|
|
27
16
|
* ```
|
|
17
|
+
*
|
|
18
|
+
* @module
|
|
28
19
|
*/
|
|
29
|
-
export class AuthSession {
|
|
30
|
-
/** The authenticated Enbox agent managing keys, DIDs, and DWN access. */
|
|
31
|
-
readonly agent: EnboxAgent;
|
|
32
|
-
|
|
33
|
-
/** The DID URI of the connected identity. */
|
|
34
|
-
readonly did: string;
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* The delegate DID URI, present when connected via wallet connect.
|
|
38
|
-
* This is the locally-created DID that holds delegated permissions
|
|
39
|
-
* from the wallet's identity.
|
|
40
|
-
*/
|
|
41
|
-
readonly delegateDid?: string;
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* The BIP-39 recovery phrase, present only on first-time local connect.
|
|
45
|
-
* Should be shown to the user for backup and then discarded from memory.
|
|
46
|
-
*/
|
|
47
|
-
readonly recoveryPhrase?: string;
|
|
48
|
-
|
|
49
|
-
/** Metadata about the connected identity. */
|
|
50
|
-
readonly identity: IdentityInfo;
|
|
51
20
|
|
|
52
|
-
|
|
53
|
-
agent: EnboxAgent;
|
|
54
|
-
did: string;
|
|
55
|
-
delegateDid?: string;
|
|
56
|
-
recoveryPhrase?: string;
|
|
57
|
-
identity: IdentityInfo;
|
|
58
|
-
}) {
|
|
59
|
-
this.agent = params.agent;
|
|
60
|
-
this.did = params.did;
|
|
61
|
-
this.delegateDid = params.delegateDid;
|
|
62
|
-
this.recoveryPhrase = params.recoveryPhrase;
|
|
63
|
-
this.identity = params.identity;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
21
|
+
export { AgentSession as AuthSession } from '@enbox/agent';
|
package/src/password-provider.ts
CHANGED
|
@@ -56,15 +56,25 @@ export interface PasswordProvider {
|
|
|
56
56
|
|
|
57
57
|
// ─── Internal I/O interfaces (for testing) ───────────────────────
|
|
58
58
|
|
|
59
|
-
/**
|
|
59
|
+
/**
|
|
60
|
+
* Minimal interface for an stdin-like readable stream.
|
|
61
|
+
*
|
|
62
|
+
* The signature shape mirrors Node's `tty.ReadStream` closely enough
|
|
63
|
+
* that `process.stdin` is directly assignable without a cast — the
|
|
64
|
+
* payoff is that `readPasswordRawMode` is testable with a tiny in-memory
|
|
65
|
+
* stub and the production call site needs no `as` to bridge to Node's
|
|
66
|
+
* actual stdin type.
|
|
67
|
+
*
|
|
68
|
+
* @internal
|
|
69
|
+
*/
|
|
60
70
|
export interface TtyReadable {
|
|
61
71
|
isTTY?: boolean;
|
|
62
|
-
setRawMode(mode: boolean):
|
|
63
|
-
setEncoding(encoding
|
|
64
|
-
resume():
|
|
65
|
-
pause():
|
|
66
|
-
on(event: 'data', listener: (chunk: string) => void):
|
|
67
|
-
removeListener(event: 'data', listener: (chunk: string) => void):
|
|
72
|
+
setRawMode(mode: boolean): unknown;
|
|
73
|
+
setEncoding(encoding?: BufferEncoding): unknown;
|
|
74
|
+
resume(): unknown;
|
|
75
|
+
pause(): unknown;
|
|
76
|
+
on(event: 'data', listener: (chunk: string) => void): unknown;
|
|
77
|
+
removeListener(event: 'data', listener: (chunk: string) => void): unknown;
|
|
68
78
|
}
|
|
69
79
|
|
|
70
80
|
/** @internal Minimal interface for an stdout-like writable stream. */
|
|
@@ -127,13 +137,19 @@ export function readPasswordRawMode(
|
|
|
127
137
|
});
|
|
128
138
|
}
|
|
129
139
|
|
|
130
|
-
/**
|
|
140
|
+
/**
|
|
141
|
+
* @internal Injectable I/O for testing `readPasswordDevTty`.
|
|
142
|
+
*
|
|
143
|
+
* `execSync`'s `stdio` is narrowed to the literal-union Node accepts so
|
|
144
|
+
* the implementation below can call `child_process.execSync` without a
|
|
145
|
+
* `stdio: string -> stdio: StdioOptions` cast.
|
|
146
|
+
*/
|
|
131
147
|
export interface DevTtyIo {
|
|
132
148
|
openSync(path: string, flags: string): number;
|
|
133
149
|
readSync(fd: number, buf: Uint8Array, offset: number, length: number, position: null): number;
|
|
134
150
|
writeSync(fd: number, data: string): number;
|
|
135
151
|
closeSync(fd: number): void;
|
|
136
|
-
execSync(cmd: string, opts: { stdio:
|
|
152
|
+
execSync(cmd: string, opts: { stdio: 'pipe' | 'ignore' | 'inherit' }): void;
|
|
137
153
|
}
|
|
138
154
|
|
|
139
155
|
/**
|
|
@@ -162,7 +178,7 @@ export async function readPasswordDevTty(
|
|
|
162
178
|
readSync,
|
|
163
179
|
writeSync,
|
|
164
180
|
closeSync,
|
|
165
|
-
execSync: (cmd: string, opts: { stdio:
|
|
181
|
+
execSync: (cmd: string, opts: { stdio: 'pipe' | 'ignore' | 'inherit' }): void => { execSync(cmd, opts); },
|
|
166
182
|
};
|
|
167
183
|
}
|
|
168
184
|
|
|
@@ -303,7 +319,7 @@ export namespace PasswordProvider {
|
|
|
303
319
|
}
|
|
304
320
|
|
|
305
321
|
return readPasswordRawMode(
|
|
306
|
-
process.stdin
|
|
322
|
+
process.stdin,
|
|
307
323
|
process.stdout,
|
|
308
324
|
prompt,
|
|
309
325
|
);
|
package/src/types.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { PortableDid } from '@enbox/dids';
|
|
7
|
-
import type { ConnectPermissionRequest, DelegateContextKey, DelegateDecryptionKey, DwnDataEncodedRecordsWriteMessage, DwnProtocolDefinition, EnboxUserAgent, HdIdentityVault, LocalDwnStrategy, PortableIdentity } from '@enbox/agent';
|
|
7
|
+
import type { AgentSessionIdentity, ConnectPermissionRequest, DelegateContextKey, DelegateDecryptionKey, DwnDataEncodedRecordsWriteMessage, DwnProtocolDefinition, EnboxUserAgent, HdIdentityVault, LocalDwnStrategy, PortableIdentity } from '@enbox/agent';
|
|
8
8
|
|
|
9
9
|
import type { PasswordProvider } from './password-provider.js';
|
|
10
10
|
|
|
@@ -79,20 +79,15 @@ export type AuthEventHandler<E extends AuthEvent = AuthEvent> =
|
|
|
79
79
|
|
|
80
80
|
// ─── Identity ────────────────────────────────────────────────────
|
|
81
81
|
|
|
82
|
-
/**
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
* Present when this identity is a delegate of another DID
|
|
92
|
-
* (i.e. connected via wallet connect).
|
|
93
|
-
*/
|
|
94
|
-
connectedDid?: string;
|
|
95
|
-
}
|
|
82
|
+
/**
|
|
83
|
+
* Lightweight metadata about a stored identity.
|
|
84
|
+
*
|
|
85
|
+
* @deprecated Prefer {@link AgentSessionIdentity} from `@enbox/agent` — this
|
|
86
|
+
* alias exists for `@enbox/auth`'s self-contained public surface but the
|
|
87
|
+
* canonical name lives in the agent package. The two are structurally
|
|
88
|
+
* identical; new code should import `AgentSessionIdentity` directly.
|
|
89
|
+
*/
|
|
90
|
+
export type IdentityInfo = AgentSessionIdentity;
|
|
96
91
|
|
|
97
92
|
/** Serializable session info for the `session-start` event. */
|
|
98
93
|
export interface AuthSessionInfo {
|
|
@@ -492,6 +487,15 @@ export interface HandlerConnectOptions {
|
|
|
492
487
|
*/
|
|
493
488
|
connectHandler?: ConnectHandler;
|
|
494
489
|
|
|
490
|
+
/**
|
|
491
|
+
* Vault password for this call (overrides the manager default).
|
|
492
|
+
*
|
|
493
|
+
* The handler flow still needs to unlock the local agent's vault to receive
|
|
494
|
+
* delegated grants — passing `password` per-call lets callers override the
|
|
495
|
+
* default supplied to `AuthManager.create()`.
|
|
496
|
+
*/
|
|
497
|
+
password?: string;
|
|
498
|
+
|
|
495
499
|
/** Override manager default sync interval. */
|
|
496
500
|
sync?: SyncOption;
|
|
497
501
|
}
|
|
@@ -126,7 +126,7 @@ async function initClient({
|
|
|
126
126
|
// Sign the request as a JWT.
|
|
127
127
|
const requestJwt = await EnboxConnectProtocol.signJwt({
|
|
128
128
|
did : clientDid,
|
|
129
|
-
data : request
|
|
129
|
+
data : request,
|
|
130
130
|
});
|
|
131
131
|
|
|
132
132
|
if (!requestJwt) {
|
|
@@ -191,18 +191,20 @@ async function initClient({
|
|
|
191
191
|
// Get the PIN from the user and use it as AAD to decrypt.
|
|
192
192
|
const pin = await validatePin();
|
|
193
193
|
const jwt = await EnboxConnectProtocol.decryptResponse(clientDid, jwe, pin);
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
194
|
+
const verifiedPayload = await EnboxConnectProtocol.verifyJwt({ jwt });
|
|
195
|
+
// Runtime narrowing — see `assertConnectResponse` in @enbox/agent for
|
|
196
|
+
// the shape validated. After this line `verifiedPayload` is narrowed
|
|
197
|
+
// to `EnboxConnectResponse`.
|
|
198
|
+
EnboxConnectProtocol.assertConnectResponse(verifiedPayload);
|
|
197
199
|
|
|
198
200
|
return {
|
|
199
|
-
delegateGrants :
|
|
200
|
-
delegatePortableDid :
|
|
201
|
-
connectedDid :
|
|
202
|
-
delegateDecryptionKeys :
|
|
203
|
-
delegateContextKeys :
|
|
204
|
-
delegateMultiPartyProtocols :
|
|
205
|
-
sessionRevocations :
|
|
201
|
+
delegateGrants : verifiedPayload.delegateGrants,
|
|
202
|
+
delegatePortableDid : verifiedPayload.delegatePortableDid,
|
|
203
|
+
connectedDid : verifiedPayload.providerDid,
|
|
204
|
+
delegateDecryptionKeys : verifiedPayload.delegateDecryptionKeys,
|
|
205
|
+
delegateContextKeys : verifiedPayload.delegateContextKeys,
|
|
206
|
+
delegateMultiPartyProtocols : verifiedPayload.delegateMultiPartyProtocols,
|
|
207
|
+
sessionRevocations : verifiedPayload.sessionRevocations,
|
|
206
208
|
};
|
|
207
209
|
}
|
|
208
210
|
}
|