@interop/wallet-core 0.23.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -18
- package/dist/clients/revocation.d.ts +3 -6
- package/dist/clients/revocation.d.ts.map +1 -1
- package/dist/clients/revocation.js +5 -9
- package/dist/clients/revocation.js.map +1 -1
- package/dist/clients/rosterPolicy.d.ts +11 -17
- package/dist/clients/rosterPolicy.d.ts.map +1 -1
- package/dist/clients/rosterPolicy.js +22 -27
- package/dist/clients/rosterPolicy.js.map +1 -1
- package/dist/enrollment/enrollment.d.ts +2 -2
- package/dist/enrollment/enrollment.d.ts.map +1 -1
- package/dist/enrollment/enrollment.js +15 -10
- package/dist/enrollment/enrollment.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/keys/index.d.ts +11 -8
- package/dist/keys/index.d.ts.map +1 -1
- package/dist/keys/index.js +11 -8
- package/dist/keys/index.js.map +1 -1
- package/dist/keys/rosterLogStore.d.ts +34 -0
- package/dist/keys/rosterLogStore.d.ts.map +1 -0
- package/dist/keys/rosterLogStore.js +110 -0
- package/dist/keys/rosterLogStore.js.map +1 -0
- package/dist/keys/rosterStore.d.ts +18 -4
- package/dist/keys/rosterStore.d.ts.map +1 -1
- package/dist/keys/rosterStore.js +35 -16
- package/dist/keys/rosterStore.js.map +1 -1
- package/dist/keys/userKeyCascade.d.ts +1 -1
- package/dist/keys/userKeyCascade.js +1 -1
- package/dist/keys/userKeyRoster.d.ts +50 -97
- package/dist/keys/userKeyRoster.d.ts.map +1 -1
- package/dist/keys/userKeyRoster.js +44 -145
- package/dist/keys/userKeyRoster.js.map +1 -1
- package/dist/request/appKey.d.ts +254 -0
- package/dist/request/appKey.d.ts.map +1 -0
- package/dist/request/appKey.js +498 -0
- package/dist/request/appKey.js.map +1 -0
- package/dist/request/classify.d.ts +54 -3
- package/dist/request/classify.d.ts.map +1 -1
- package/dist/request/classify.js +106 -0
- package/dist/request/classify.js.map +1 -1
- package/dist/request/index.d.ts +4 -0
- package/dist/request/index.d.ts.map +1 -1
- package/dist/request/index.js +4 -0
- package/dist/request/index.js.map +1 -1
- package/dist/request/processRequest.d.ts.map +1 -1
- package/dist/request/processRequest.js +15 -6
- package/dist/request/processRequest.js.map +1 -1
- package/dist/request/types.d.ts +45 -2
- package/dist/request/types.d.ts.map +1 -1
- package/dist/resourceLog/append.d.ts +103 -0
- package/dist/resourceLog/append.d.ts.map +1 -0
- package/dist/resourceLog/append.js +190 -0
- package/dist/resourceLog/append.js.map +1 -0
- package/dist/resourceLog/controller.d.ts +57 -0
- package/dist/resourceLog/controller.d.ts.map +1 -0
- package/dist/resourceLog/controller.js +81 -0
- package/dist/resourceLog/controller.js.map +1 -0
- package/dist/resourceLog/entry.d.ts +68 -0
- package/dist/resourceLog/entry.d.ts.map +1 -0
- package/dist/resourceLog/entry.js +167 -0
- package/dist/resourceLog/entry.js.map +1 -0
- package/dist/resourceLog/errors.d.ts +75 -0
- package/dist/resourceLog/errors.d.ts.map +1 -0
- package/dist/resourceLog/errors.js +76 -0
- package/dist/resourceLog/errors.js.map +1 -0
- package/dist/resourceLog/index.d.ts +23 -0
- package/dist/resourceLog/index.d.ts.map +1 -0
- package/dist/resourceLog/index.js +23 -0
- package/dist/resourceLog/index.js.map +1 -0
- package/dist/resourceLog/pin.d.ts +44 -0
- package/dist/resourceLog/pin.d.ts.map +1 -0
- package/dist/resourceLog/pin.js +32 -0
- package/dist/resourceLog/pin.js.map +1 -0
- package/dist/resourceLog/verify.d.ts +89 -0
- package/dist/resourceLog/verify.d.ts.map +1 -0
- package/dist/resourceLog/verify.js +434 -0
- package/dist/resourceLog/verify.js.map +1 -0
- package/dist/space/collections.d.ts +14 -11
- package/dist/space/collections.d.ts.map +1 -1
- package/dist/space/collections.js +14 -11
- package/dist/space/collections.js.map +1 -1
- package/dist/space/index.d.ts +2 -2
- package/dist/space/index.d.ts.map +1 -1
- package/dist/space/index.js +2 -2
- package/dist/space/index.js.map +1 -1
- package/dist/webvh/didWeb.d.ts +4 -6
- package/dist/webvh/didWeb.d.ts.map +1 -1
- package/dist/webvh/didWeb.js.map +1 -1
- package/dist/webvh/didWebvh.d.ts +1 -2
- package/dist/webvh/didWebvh.d.ts.map +1 -1
- package/dist/webvh/didWebvh.js +1 -6
- package/dist/webvh/didWebvh.js.map +1 -1
- package/package.json +10 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"userKeyRoster.d.ts","sourceRoot":"","sources":["../../src/keys/userKeyRoster.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"userKeyRoster.d.ts","sourceRoot":"","sources":["../../src/keys/userKeyRoster.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,EAML,KAAK,yBAAyB,EAC9B,KAAK,kBAAkB,EACxB,MAAM,yBAAyB,CAAA;AAChC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAChE,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAE3C;;;;;GAKG;AACH,qBAAa,2BAA4B,SAAQ,KAAK;gBACxC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;GAKG;AACH,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,aAAa,EAAE,MAAM,CAAA;gBACT,EAAE,aAAa,EAAE,EAAE;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE;CAQzD;AAED;;;;;GAKG;AACH,qBAAa,wBAAyB,SAAQ,KAAK;gBACrC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,YAAY,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC3E,kBAAkB,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACzE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACT,EAAE;IACD,QAAQ,EAAE,gBAAgB,CAAA;CAC3B,GAAG,iBAAiB,CAgBpB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,mBAAmB,EACnB,wBAAwB,EACzB,EAAE;IACD,mBAAmB,EAAE,MAAM,CAAA;IAC3B,wBAAwB,EAAE,MAAM,CAAA;CACjC,GAAG,MAAM,CAET;AAgBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,8BAA8B,CAAC,EAC7C,QAAQ,EACT,EAAE;IACD,QAAQ,EAAE,uBAAuB,CAAA;CAClC,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAsCtD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,mBAAmB,CAAC,EACxC,KAAK,EACL,OAAO,EACP,qBAAqB,EACtB,EAAE;IACD,KAAK,EAAE,yBAAyB,CAAA;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,qBAAqB,EAAE,gBAAgB,CAAA;CACxC,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAUhC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,yBAAyB,CAAC,EAC9C,KAAK,EACL,SAAS,EACT,oBAAoB,EACrB,EAAE;IACD,KAAK,EAAE,yBAAyB,CAAA;IAChC,SAAS,EAAE,kBAAkB,CAAA;IAC7B,oBAAoB,EAAE,gBAAgB,CAAA;CACvC,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA0BhC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,mBAAmB,CAAC,EACxC,KAAK,EACL,QAAQ,EACR,iBAAiB,EAClB,EAAE;IACD,KAAK,EAAE,yBAAyB,CAAA;IAChC,QAAQ,EAAE,uBAAuB,CAAA;IACjC,iBAAiB,EAAE,MAAM,CAAA;CAC1B,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAOhC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAsB,+BAA+B,CAAC,EACpD,KAAK,EACL,QAAQ,EACR,UAAU,EACX,EAAE;IACD,KAAK,EAAE,yBAAyB,CAAA;IAChC,QAAQ,EAAE,uBAAuB,CAAA;IACjC,UAAU,CAAC,EAAE,oBAAoB,CAAA;CAClC,GAAG,OAAO,CAAC;IACV,OAAO,EAAE,OAAO,CAAA;IAChB,iBAAiB,EAAE,MAAM,EAAE,CAAA;IAC3B,UAAU,EAAE,oBAAoB,GAAG,IAAI,CAAA;CACxC,CAAC,CAgDD;AAED;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,oBAAoB,CAAA;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAsB,iBAAiB,CAAC,EACtC,KAAK,EACL,OAAO,EACP,qBAAqB,EACrB,aAAa,EACd,EAAE;IACD,KAAK,EAAE,yBAAyB,CAAA;IAChC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,qBAAqB,EAAE,gBAAgB,CAAA;IACvC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B,GAAG,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CA8D1C"}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import { addRecipient,
|
|
2
|
-
import { Ed25519VerificationKey } from '@interop/ed25519-verification-key';
|
|
3
|
-
import { base64urlnopad } from '@scure/base';
|
|
1
|
+
import { addRecipient, initRecipients, ownerRecipient, removeRecipient, unwrapEpochSecret } from '@interop/was-client/edv';
|
|
4
2
|
import { clientSigningKeyMultibase } from '../webvh/zcap.js';
|
|
5
3
|
/**
|
|
6
|
-
* Thrown when a served roster fails its client-side
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* Thrown when a served roster fails its client-side consistency checks: a
|
|
5
|
+
* descriptor whose `currentEpoch` names no epoch in its own list. The server
|
|
6
|
+
* (or whoever can write to it) has produced a configuration no enrolled
|
|
7
|
+
* client authenticated.
|
|
10
8
|
*/
|
|
11
9
|
export class UserKeyRosterIntegrityError extends Error {
|
|
12
10
|
constructor(message) {
|
|
@@ -18,8 +16,7 @@ export class UserKeyRosterIntegrityError extends Error {
|
|
|
18
16
|
* Thrown when a served roster conflicts with the locally pinned latest-seen
|
|
19
17
|
* epoch -- the epochs list no longer contains the pinned epoch, or
|
|
20
18
|
* `currentEpoch` precedes it in the (append-only) list. A rollback/replay of
|
|
21
|
-
* an older consistent configuration
|
|
22
|
-
* catch; refused rather than followed.
|
|
19
|
+
* an older consistent configuration; refused rather than followed.
|
|
23
20
|
*/
|
|
24
21
|
export class UserKeyRosterContinuityError extends Error {
|
|
25
22
|
pinnedEpochId;
|
|
@@ -43,85 +40,32 @@ export class UserKeyRosterUnwrapError extends Error {
|
|
|
43
40
|
}
|
|
44
41
|
}
|
|
45
42
|
/**
|
|
46
|
-
* The
|
|
47
|
-
* Ed25519
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const EPOCHS_SIG_ALG = 'EdDSA';
|
|
53
|
-
/**
|
|
54
|
-
* The roster's epoch-configuration signer: signs each roster write's epoch
|
|
55
|
-
* configuration with this client's own Ed25519 signing key, under a `kid`
|
|
56
|
-
* that is the key's public multibase -- exactly the string enrolled as this
|
|
57
|
-
* client's verification method in the did:webvh document, so a reader
|
|
58
|
-
* resolves the signature against the document rather than anything the
|
|
59
|
-
* roster (or the server) supplies.
|
|
43
|
+
* The roster's log signer: signs each roster log append with this client's
|
|
44
|
+
* own Ed25519 signing key, named by its public multibase -- exactly the
|
|
45
|
+
* string enrolled as this client's verification method in the did:webvh
|
|
46
|
+
* document, so a reader resolves the entry proof against the document rather
|
|
47
|
+
* than anything the roster (or the server) supplies. Successor of the retired
|
|
48
|
+
* `epochsSig` signer under the log design.
|
|
60
49
|
*
|
|
61
50
|
* @param options {object}
|
|
62
51
|
* @param options.keyAgent {ICapabilityAgent} this client's signing key
|
|
63
52
|
* agent (the `keyAgent` of `agentsFromSeed`)
|
|
64
|
-
* @returns {
|
|
53
|
+
* @returns {ResourceLogSigner} the signer for the log-governed store's
|
|
54
|
+
* appends
|
|
65
55
|
*/
|
|
66
|
-
export function
|
|
67
|
-
const
|
|
56
|
+
export function userKeyRosterLogSigner({ keyAgent }) {
|
|
57
|
+
const keyMultibase = clientSigningKeyMultibase({ keyAgent });
|
|
68
58
|
const signer = keyAgent.getSigner();
|
|
69
|
-
return
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
59
|
+
return {
|
|
60
|
+
keyMultibase,
|
|
61
|
+
async sign({ data }) {
|
|
62
|
+
const signature = await signer.sign({ data });
|
|
63
|
+
// Re-wrap as a plain Uint8Array: a signer may return a Node Buffer (or
|
|
64
|
+
// a cross-realm view), which the kernel's strict byte check rejects.
|
|
65
|
+
return new Uint8Array(signature.buffer, signature.byteOffset, signature.byteLength);
|
|
66
|
+
}
|
|
77
67
|
};
|
|
78
68
|
}
|
|
79
|
-
/**
|
|
80
|
-
* Verifies a served roster's `epochsSig` against the locally verified
|
|
81
|
-
* did:webvh document -- the root of trust the server cannot mint. The
|
|
82
|
-
* signature must be present and supported, its `kid` must be the public
|
|
83
|
-
* multibase of one of the document's verification methods (an enrolled
|
|
84
|
-
* client's signing key), and it must verify over the canonical
|
|
85
|
-
* epoch-configuration payload. Throws {@link UserKeyRosterIntegrityError}
|
|
86
|
-
* otherwise: a configuration no enrolled client signed.
|
|
87
|
-
*
|
|
88
|
-
* @param options {object}
|
|
89
|
-
* @param options.descriptor {CollectionEncryption} the served roster
|
|
90
|
-
* @param options.document {RosterRecipientDocument} the locally verified
|
|
91
|
-
* did:webvh document (never a server-supplied roster field)
|
|
92
|
-
* @returns {Promise<void>}
|
|
93
|
-
*/
|
|
94
|
-
export async function verifyUserKeyRosterEpochsSig({ descriptor, document }) {
|
|
95
|
-
const epochsSig = descriptor.epochsSig;
|
|
96
|
-
if (!epochsSig ||
|
|
97
|
-
epochsSig.v !== EPOCHS_SIG_V ||
|
|
98
|
-
epochsSig.alg !== EPOCHS_SIG_ALG) {
|
|
99
|
-
throw new UserKeyRosterIntegrityError('The user key roster carries no supported epoch-configuration signature.');
|
|
100
|
-
}
|
|
101
|
-
const backed = (document.verificationMethod ?? []).some(method => method.publicKeyMultibase === epochsSig.kid);
|
|
102
|
-
if (!backed) {
|
|
103
|
-
throw new UserKeyRosterIntegrityError('The user key roster epoch configuration is signed by a key the account ' +
|
|
104
|
-
'document does not back.');
|
|
105
|
-
}
|
|
106
|
-
let signature;
|
|
107
|
-
try {
|
|
108
|
-
signature = base64urlnopad.decode(epochsSig.sig);
|
|
109
|
-
}
|
|
110
|
-
catch {
|
|
111
|
-
throw new UserKeyRosterIntegrityError('The user key roster epoch-configuration signature is malformed.');
|
|
112
|
-
}
|
|
113
|
-
const verifier = new Ed25519VerificationKey({
|
|
114
|
-
controller: `did:key:${epochsSig.kid}`,
|
|
115
|
-
publicKeyMultibase: epochsSig.kid
|
|
116
|
-
}).verifier();
|
|
117
|
-
const verified = await verifier.verify({
|
|
118
|
-
data: epochsSigPayload(descriptor),
|
|
119
|
-
signature
|
|
120
|
-
});
|
|
121
|
-
if (!verified) {
|
|
122
|
-
throw new UserKeyRosterIntegrityError('The user key roster epoch-configuration signature failed verification.');
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
69
|
/**
|
|
126
70
|
* A wallet client's roster kid: its key-agreement key's id exactly as
|
|
127
71
|
* `agentsFromSeed` derives it at the client's own logins
|
|
@@ -212,12 +156,9 @@ export function userKeyRosterRecipientResolver({ document }) {
|
|
|
212
156
|
* @param options.userKey {UserKey} the account's user key
|
|
213
157
|
* @param options.clientKeyAgreementKey {IKeyAgreementKey} this client's own
|
|
214
158
|
* (identity) key-agreement key -- the roster recipient
|
|
215
|
-
* @param options.signEpochs {EpochsSigner} this client's epoch-configuration
|
|
216
|
-
* signer ({@link userKeyRosterEpochsSigner}), so the first configuration is
|
|
217
|
-
* vouched for by an enrollable key rather than only its own MAC
|
|
218
159
|
* @returns {Promise<CollectionEncryption>} the roster descriptor
|
|
219
160
|
*/
|
|
220
|
-
export async function ensureUserKeyRoster({ store, userKey, clientKeyAgreementKey
|
|
161
|
+
export async function ensureUserKeyRoster({ store, userKey, clientKeyAgreementKey }) {
|
|
221
162
|
const current = await store.read();
|
|
222
163
|
if (current !== null) {
|
|
223
164
|
return current.descriptor;
|
|
@@ -225,8 +166,7 @@ export async function ensureUserKeyRoster({ store, userKey, clientKeyAgreementKe
|
|
|
225
166
|
return initRecipients({
|
|
226
167
|
store,
|
|
227
168
|
recipients: [ownerRecipient({ keyAgreementKey: clientKeyAgreementKey })],
|
|
228
|
-
epoch: { epochId: userKey.id, secret: userKey.secret }
|
|
229
|
-
signEpochs
|
|
169
|
+
epoch: { epochId: userKey.id, secret: userKey.secret }
|
|
230
170
|
});
|
|
231
171
|
}
|
|
232
172
|
/**
|
|
@@ -295,18 +235,14 @@ export async function addUserKeyRosterRecipient({ store, recipient, ownerKeyAgre
|
|
|
295
235
|
* did:webvh document, AFTER the removal edit
|
|
296
236
|
* @param options.retireRecipientId {string} the removed recipient's roster
|
|
297
237
|
* kid
|
|
298
|
-
* @param options.signEpochs {EpochsSigner} the rotating client's
|
|
299
|
-
* epoch-configuration signer ({@link userKeyRosterEpochsSigner}), vouching for
|
|
300
|
-
* the fresh epoch so other clients' rotated reads accept it
|
|
301
238
|
* @returns {Promise<CollectionEncryption>} the rotated roster descriptor
|
|
302
239
|
*/
|
|
303
|
-
export async function rotateUserKeyRoster({ store, document, retireRecipientId
|
|
240
|
+
export async function rotateUserKeyRoster({ store, document, retireRecipientId }) {
|
|
304
241
|
return removeRecipient({
|
|
305
242
|
store,
|
|
306
243
|
recipientId: retireRecipientId,
|
|
307
244
|
resolveRecipientKey: userKeyRosterRecipientResolver({ document }),
|
|
308
|
-
pull: async () => { }
|
|
309
|
-
signEpochs
|
|
245
|
+
pull: async () => { }
|
|
310
246
|
});
|
|
311
247
|
}
|
|
312
248
|
/**
|
|
@@ -343,14 +279,11 @@ export async function rotateUserKeyRoster({ store, document, retireRecipientId,
|
|
|
343
279
|
* @param [options.descriptor] {CollectionEncryption} a descriptor the caller
|
|
344
280
|
* has just read (a login-time roster read), to save a re-read; omitted, the
|
|
345
281
|
* roster is read fresh
|
|
346
|
-
* @param options.signEpochs {EpochsSigner} the converging client's
|
|
347
|
-
* epoch-configuration signer ({@link userKeyRosterEpochsSigner}), for the
|
|
348
|
-
* rotation this call may perform
|
|
349
282
|
* @returns {Promise<object>} whether the roster rotated on this call, the
|
|
350
283
|
* stale recipient kids found, and the roster descriptor as it now stands
|
|
351
284
|
* (`null` when the account has no roster yet)
|
|
352
285
|
*/
|
|
353
|
-
export async function convergeUserKeyRosterToDocument({ store, document, descriptor
|
|
286
|
+
export async function convergeUserKeyRosterToDocument({ store, document, descriptor }) {
|
|
354
287
|
let roster = descriptor;
|
|
355
288
|
if (!roster) {
|
|
356
289
|
const read = await store.read();
|
|
@@ -388,8 +321,7 @@ export async function convergeUserKeyRosterToDocument({ store, document, descrip
|
|
|
388
321
|
const rotated = await rotateUserKeyRoster({
|
|
389
322
|
store,
|
|
390
323
|
document,
|
|
391
|
-
retireRecipientId: staleRecipientIds[0]
|
|
392
|
-
signEpochs
|
|
324
|
+
retireRecipientId: staleRecipientIds[0]
|
|
393
325
|
});
|
|
394
326
|
return { rotated: true, staleRecipientIds, descriptor: rotated };
|
|
395
327
|
}
|
|
@@ -398,24 +330,19 @@ export async function convergeUserKeyRosterToDocument({ store, document, descrip
|
|
|
398
330
|
* mismatch. Resolves `null` when the roster does not exist yet (an account
|
|
399
331
|
* provisioned before the roster, or provisioning still in flight); otherwise:
|
|
400
332
|
*
|
|
401
|
-
* 1. **
|
|
333
|
+
* 1. **Provenance** is the store's: a log-governed store resolves the read
|
|
334
|
+
* from the roster log's verified head -- entry proofs checked against the
|
|
335
|
+
* locally verified did:webvh document, chain-head pin enforced -- so
|
|
336
|
+
* every epoch this read can deliver was signed onto the log by an
|
|
337
|
+
* enrolled client. (The detached `epochsSig` this step used to verify on
|
|
338
|
+
* the adopt path is retired; the entry proof covers every read.)
|
|
339
|
+
* 2. **Continuity**: the served epochs must contain the pinned latest-seen
|
|
402
340
|
* epoch, and `currentEpoch` must not precede it in the append-only list
|
|
403
341
|
* (`UserKeyRosterContinuityError` -- the rollback/replay refusal).
|
|
404
|
-
*
|
|
342
|
+
* 3. **Possession**: `currentEpoch === userKey.id` confirms the cached user key
|
|
405
343
|
* current; otherwise the current epoch was rotated by another client and
|
|
406
344
|
* this client's wrap is unwrapped with its own key-agreement key
|
|
407
345
|
* (`UserKeyRosterUnwrapError` when it holds none).
|
|
408
|
-
* 3. **Provenance** (the rotated/first-read path only): the epoch
|
|
409
|
-
* configuration's `epochsSig` is verified against the locally verified
|
|
410
|
-
* did:webvh document ({@link verifyUserKeyRosterEpochsSig}) BEFORE the epoch
|
|
411
|
-
* it delivers is adopted. On this path the `epochsMac` alone proves
|
|
412
|
-
* nothing against the host -- its key is unwrapped from the served
|
|
413
|
-
* descriptor itself -- so an epoch no enrolled client signed is refused
|
|
414
|
-
* (`UserKeyRosterIntegrityError`). The cached-current path needs no signature:
|
|
415
|
-
* there the MAC is keyed by a secret this client already trusts.
|
|
416
|
-
* 4. **Authentication**: the descriptor's `epochsMac` is verified under the
|
|
417
|
-
* current epoch's secret (`UserKeyRosterIntegrityError` on any mismatch -- a
|
|
418
|
-
* fabricated configuration).
|
|
419
346
|
*
|
|
420
347
|
* A rotated read returns the fresh user key; its Ed25519 signing seed does not
|
|
421
348
|
* travel through the roster (the roster wraps the key-agreement secret
|
|
@@ -424,10 +351,7 @@ export async function convergeUserKeyRosterToDocument({ store, document, descrip
|
|
|
424
351
|
* A caller with no cached user key at all -- a freshly enrolled client making
|
|
425
352
|
* its first post-enrollment read -- omits `userKey` and always takes the unwrap
|
|
426
353
|
* path; the result's `rotated` is then true (the user key was adopted from the
|
|
427
|
-
* roster).
|
|
428
|
-
* (or a way to resolve it): `document` when it already holds a verified copy,
|
|
429
|
-
* or `resolveDocument` to fetch-and-verify lazily, only when the read actually
|
|
430
|
-
* rotates.
|
|
354
|
+
* roster).
|
|
431
355
|
*
|
|
432
356
|
* @param options {object}
|
|
433
357
|
* @param options.store {EncryptionDescriptorStore} the roster's descriptor
|
|
@@ -437,14 +361,9 @@ export async function convergeUserKeyRosterToDocument({ store, document, descrip
|
|
|
437
361
|
* (identity) key-agreement key, unwrapping a rotated epoch
|
|
438
362
|
* @param [options.pinnedEpochId] {string} the locally pinned latest-seen
|
|
439
363
|
* roster epoch, when this client has seen the roster before
|
|
440
|
-
* @param [options.document] {RosterRecipientDocument} the locally verified
|
|
441
|
-
* did:webvh document, when the caller already holds one
|
|
442
|
-
* @param [options.resolveDocument] {function} resolves the locally verified
|
|
443
|
-
* did:webvh document on demand; called only when the read takes the
|
|
444
|
-
* rotated/first-read path
|
|
445
364
|
* @returns {Promise<UserKeyRosterReadResult | null>}
|
|
446
365
|
*/
|
|
447
|
-
export async function readUserKeyRoster({ store, userKey, clientKeyAgreementKey, pinnedEpochId
|
|
366
|
+
export async function readUserKeyRoster({ store, userKey, clientKeyAgreementKey, pinnedEpochId }) {
|
|
448
367
|
const current = await store.read();
|
|
449
368
|
if (current === null) {
|
|
450
369
|
return null;
|
|
@@ -463,11 +382,6 @@ export async function readUserKeyRoster({ store, userKey, clientKeyAgreementKey,
|
|
|
463
382
|
throw new UserKeyRosterContinuityError({ pinnedEpochId });
|
|
464
383
|
}
|
|
465
384
|
}
|
|
466
|
-
// The epochsMac construction's own version/alg are the caller's to check.
|
|
467
|
-
const epochsMac = descriptor.epochsMac;
|
|
468
|
-
if (!epochsMac || epochsMac.v !== 1 || epochsMac.alg !== 'HS256') {
|
|
469
|
-
throw new UserKeyRosterIntegrityError('The user key roster carries no supported epoch-configuration MAC.');
|
|
470
|
-
}
|
|
471
385
|
let currentUserKey;
|
|
472
386
|
let rotated;
|
|
473
387
|
if (userKey && descriptor.currentEpoch === userKey.id) {
|
|
@@ -475,22 +389,10 @@ export async function readUserKeyRoster({ store, userKey, clientKeyAgreementKey,
|
|
|
475
389
|
rotated = false;
|
|
476
390
|
}
|
|
477
391
|
else {
|
|
478
|
-
// Rotated by another client (or this client's first read):
|
|
479
|
-
//
|
|
480
|
-
//
|
|
481
|
-
// locally verified account document backs.
|
|
482
|
-
// carry this: on this path its key comes out of the served descriptor
|
|
483
|
-
// itself.
|
|
484
|
-
const accountDocument = document ?? (resolveDocument ? await resolveDocument() : undefined);
|
|
485
|
-
if (!accountDocument) {
|
|
486
|
-
throw new Error('A user key roster read that adopts an epoch from the roster needs the ' +
|
|
487
|
-
'account document (pass `document` or `resolveDocument`) to verify ' +
|
|
488
|
-
'the epoch configuration signature.');
|
|
489
|
-
}
|
|
490
|
-
await verifyUserKeyRosterEpochsSig({
|
|
491
|
-
descriptor,
|
|
492
|
-
document: accountDocument
|
|
493
|
-
});
|
|
392
|
+
// Rotated by another client (or this client's first read): the epoch
|
|
393
|
+
// being adopted traces to a root of trust the server cannot mint through
|
|
394
|
+
// the store itself -- a log-governed read only ever resolves to a head
|
|
395
|
+
// whose entry proofs the locally verified account document backs.
|
|
494
396
|
// Unwrap this client's entry in the current epoch with its own
|
|
495
397
|
// key-agreement key (rotation delivery).
|
|
496
398
|
const entry = descriptor.epochs[currentIndex].recipients.find(recipient => recipient.header.kid === clientKeyAgreementKey.id);
|
|
@@ -507,9 +409,6 @@ export async function readUserKeyRoster({ store, userKey, clientKeyAgreementKey,
|
|
|
507
409
|
currentUserKey = { id: descriptor.currentEpoch, secret };
|
|
508
410
|
rotated = true;
|
|
509
411
|
}
|
|
510
|
-
if (!(await verifyEpochsMac({ descriptor, epochSecret: currentUserKey.secret }))) {
|
|
511
|
-
throw new UserKeyRosterIntegrityError('The user key roster epoch configuration failed authentication.');
|
|
512
|
-
}
|
|
513
412
|
return {
|
|
514
413
|
descriptor,
|
|
515
414
|
userKey: currentUserKey,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"userKeyRoster.js","sourceRoot":"","sources":["../../src/keys/userKeyRoster.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"userKeyRoster.js","sourceRoot":"","sources":["../../src/keys/userKeyRoster.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import type { IVerifiableCredential } from '@interop/data-integrity-core';
|
|
2
|
+
import type { IAppConnectApp } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* The key name mixed into seed derivation. Unlike the handle this is
|
|
5
|
+
* load-bearing: it is the HMAC message in `CapabilityAgent` derivation, so the
|
|
6
|
+
* exact string is a pinned input of the App Connect key-derivation rule --
|
|
7
|
+
* every existing app-key credential's identity depends on it.
|
|
8
|
+
*/
|
|
9
|
+
export declare const APP_KEY_KEY_NAME = "app-key";
|
|
10
|
+
/**
|
|
11
|
+
* The marker type every app-key credential carries, mapped to one stable IRI
|
|
12
|
+
* for every application. It makes "presents as an app key" a term check rather
|
|
13
|
+
* than a shape heuristic, which is what the store-time refusal
|
|
14
|
+
* ({@link assertStorableAppKey}) and the match path key off.
|
|
15
|
+
*
|
|
16
|
+
* It is a self-declaration, not evidence: the `type` array of a planted
|
|
17
|
+
* credential is attacker-controlled like the rest of it. The seed-to-subject
|
|
18
|
+
* binding ({@link appKeySeedBindsSubject}) authenticates only a credential's
|
|
19
|
+
* internal consistency, never its provenance (a fully attacker-generated
|
|
20
|
+
* credential binds perfectly). That is exactly why external ingest refuses on
|
|
21
|
+
* the marker alone, binding or not ({@link assertStorableAppKey}): app keys
|
|
22
|
+
* are wallet-minted, never imported.
|
|
23
|
+
*/
|
|
24
|
+
export declare const APP_KEY_CREDENTIAL_TYPE = "AppKeyCredential";
|
|
25
|
+
/**
|
|
26
|
+
* The fixed `type` array of every app-key credential: exactly two entries, in
|
|
27
|
+
* this order, identical for every application. Which application a credential
|
|
28
|
+
* belongs to is the `credentialSubject.appUrl` claim, not a type.
|
|
29
|
+
*/
|
|
30
|
+
export declare const APP_KEY_TYPE_ARRAY: readonly string[];
|
|
31
|
+
/**
|
|
32
|
+
* The static inline `@context` object every app-key credential carries as the
|
|
33
|
+
* second entry of its `@context` array (after the VC 1.1 context URL). The
|
|
34
|
+
* shape is normative and byte-identical for every application and every
|
|
35
|
+
* credential: carrying the terms inline keeps the credential verifiable with
|
|
36
|
+
* no remote vocabulary fetch on either side.
|
|
37
|
+
*/
|
|
38
|
+
export declare const APP_KEY_CONTEXT: Readonly<Record<string, unknown>>;
|
|
39
|
+
/**
|
|
40
|
+
* Whether a credential presents as an app key -- that is, carries the
|
|
41
|
+
* {@link APP_KEY_CREDENTIAL_TYPE} marker in its `type` array. Says nothing
|
|
42
|
+
* about whether it IS one; that is the seed-to-subject binding's job.
|
|
43
|
+
*
|
|
44
|
+
* @param credential {IVerifiableCredential}
|
|
45
|
+
* @returns {boolean}
|
|
46
|
+
*/
|
|
47
|
+
export declare function presentsAsAppKey(credential: IVerifiableCredential): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* The refusal a store path raises for a credential that presents as an app key
|
|
50
|
+
* but arrived from outside the wallet's own mint path. A distinct class so the
|
|
51
|
+
* UI can show its own translated wording rather than this message.
|
|
52
|
+
*/
|
|
53
|
+
export declare class AppKeyRefusedError extends Error {
|
|
54
|
+
constructor();
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Refuses any credential that presents as an app key, unconditionally --
|
|
58
|
+
* whether or not it binds to its own seed. Called on every path that puts a
|
|
59
|
+
* credential in the store from outside the wallet (a CHAPI store offer, a
|
|
60
|
+
* URL / QR / manual-paste import), so an externally arriving app key never
|
|
61
|
+
* reaches the store, the credential list, or the user's Space.
|
|
62
|
+
*
|
|
63
|
+
* The seed-to-subject binding ({@link appKeySeedBindsSubject}) authenticates
|
|
64
|
+
* only the credential's internal consistency, not its provenance: a fully
|
|
65
|
+
* attacker-generated credential binds perfectly (a fresh seed, the victim
|
|
66
|
+
* app's `origin` and `appUrl`, self-issued), and storing it would make its
|
|
67
|
+
* DID the controller the wallet delegates the user's storage to. So there is
|
|
68
|
+
* no "binds, so it stores" carve-out here: app-key credentials are
|
|
69
|
+
* wallet-minted, never imported, and only the wallet's own mint path may
|
|
70
|
+
* store one.
|
|
71
|
+
*
|
|
72
|
+
* A credential with no marker is left alone, so an ordinary credential that
|
|
73
|
+
* merely happens to carry a `seed` or `origin` claim is never caught.
|
|
74
|
+
*
|
|
75
|
+
* @param credential {IVerifiableCredential}
|
|
76
|
+
* @returns {void} throws the refusal reason
|
|
77
|
+
*/
|
|
78
|
+
export declare function assertStorableAppKey(credential: IVerifiableCredential): void;
|
|
79
|
+
/**
|
|
80
|
+
* Whether an app-key credential's subject DID is the one its own seed derives
|
|
81
|
+
* -- the binding that makes the credential an app key rather than merely a
|
|
82
|
+
* self-issued claim to be one. Self-issuance is a weak signal (anyone can
|
|
83
|
+
* self-issue); this is the strong one, and it is fully local: the credential
|
|
84
|
+
* carries the seed, so re-derive with the same call `mintAppKeyCredential`
|
|
85
|
+
* uses and compare. Fails closed on an absent, non-base64url, or otherwise
|
|
86
|
+
* unusable seed rather than throwing out of the match path.
|
|
87
|
+
*
|
|
88
|
+
* @param credential {IVerifiableCredential}
|
|
89
|
+
* @returns {Promise<boolean>}
|
|
90
|
+
*/
|
|
91
|
+
export declare function appKeySeedBindsSubject(credential: IVerifiableCredential): Promise<boolean>;
|
|
92
|
+
/**
|
|
93
|
+
* Raised by {@link assertMintedAppKey} when a credential offered to the mint
|
|
94
|
+
* path's store door does not carry the mint invariants. Reaching it means a
|
|
95
|
+
* caller tried to route a foreign credential through the wallet's own mint
|
|
96
|
+
* door -- a programming error, not a user-facing refusal, so it is not
|
|
97
|
+
* translated like {@link AppKeyRefusedError}.
|
|
98
|
+
*/
|
|
99
|
+
export declare class AppKeyMintInvariantError extends Error {
|
|
100
|
+
constructor();
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Asserts the mint invariants on a credential the wallet claims to have just
|
|
104
|
+
* minted: it presents as an app key (the marker type) and its subject DID
|
|
105
|
+
* re-derives from the seed it carries. The mirror image of
|
|
106
|
+
* {@link assertStorableAppKey} -- external ingest refuses every marker
|
|
107
|
+
* credential, the mint door stores only credentials that carry the full mint
|
|
108
|
+
* shape -- kept beside it so the two halves of the app-key store policy live
|
|
109
|
+
* in one module.
|
|
110
|
+
*
|
|
111
|
+
* @param credential {IVerifiableCredential}
|
|
112
|
+
* @returns {Promise<void>} throws {@link AppKeyMintInvariantError}
|
|
113
|
+
*/
|
|
114
|
+
export declare function assertMintedAppKey(credential: IVerifiableCredential): Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* The app-key candidates for an app + origin, latest-first: everything the
|
|
117
|
+
* cheap, synchronous predicates accept, so only plausible candidates pay for
|
|
118
|
+
* a key derivation. A candidate must carry the marker (required, not merely
|
|
119
|
+
* tolerated: a credential can then only reach the delegation path by carrying
|
|
120
|
+
* it, which is exactly what the store-time refusal screens), name the
|
|
121
|
+
* request's `appUrl` in `credentialSubject.appUrl` (both sides in serialized
|
|
122
|
+
* form -- the wallet mints the claim serialized, so the comparison is an
|
|
123
|
+
* exact string match), be self-issued, and be bound to the attested
|
|
124
|
+
* requesting origin. Sorting here (rather than after the binding check) lets
|
|
125
|
+
* {@link findAppKeyCredential} stop at the newest credential that binds.
|
|
126
|
+
*
|
|
127
|
+
* @param options {object}
|
|
128
|
+
* @param options.credentials {IVerifiableCredential[]}
|
|
129
|
+
* @param options.appUrl {string} - The request's `app.appUrl` in serialized
|
|
130
|
+
* form.
|
|
131
|
+
* @param options.origin {string} - The attested requesting origin.
|
|
132
|
+
* @returns {IVerifiableCredential[]}
|
|
133
|
+
*/
|
|
134
|
+
export declare function appKeyCandidates({ credentials, appUrl, origin }: {
|
|
135
|
+
credentials: IVerifiableCredential[];
|
|
136
|
+
appUrl: string;
|
|
137
|
+
origin: string;
|
|
138
|
+
}): IVerifiableCredential[];
|
|
139
|
+
/**
|
|
140
|
+
* The current (latest) app-key credential for an app + origin, or undefined
|
|
141
|
+
* when the user has none -- which signals first run for that (origin,
|
|
142
|
+
* `appUrl`) pair.
|
|
143
|
+
*
|
|
144
|
+
* @param options {object}
|
|
145
|
+
* @param options.credentials {IVerifiableCredential[]}
|
|
146
|
+
* @param options.appUrl {string} - The request's `app.appUrl` in serialized
|
|
147
|
+
* form.
|
|
148
|
+
* @param options.origin {string} - The attested requesting origin.
|
|
149
|
+
* @returns {Promise<IVerifiableCredential | undefined>}
|
|
150
|
+
*/
|
|
151
|
+
export declare function findAppKeyCredential({ credentials, appUrl, origin }: {
|
|
152
|
+
credentials: IVerifiableCredential[];
|
|
153
|
+
appUrl: string;
|
|
154
|
+
origin: string;
|
|
155
|
+
}): Promise<IVerifiableCredential | undefined>;
|
|
156
|
+
/**
|
|
157
|
+
* Mints a fresh app-key credential for an app + origin: generates a 32-byte
|
|
158
|
+
* seed, derives the seed's did:key, and self-issues the credential (issuer ==
|
|
159
|
+
* subject == the seed-derived DID) with the `credentialSubject.appUrl` claim
|
|
160
|
+
* set from the validated request value. Does NOT store the result -- the
|
|
161
|
+
* caller stores it before delegating, so a failed delegation is found as
|
|
162
|
+
* "returning" on the next attempt rather than minting a second identity.
|
|
163
|
+
*
|
|
164
|
+
* @param options {object}
|
|
165
|
+
* @param options.app {IAppConnectApp} - The validated app identity; its
|
|
166
|
+
* `appUrl` must already be in serialized form (`appConnectRequestOf`
|
|
167
|
+
* guarantees this).
|
|
168
|
+
* @param options.origin {string} - The attested requesting origin, never a
|
|
169
|
+
* value taken from the request body.
|
|
170
|
+
* @returns {Promise<{ credential: IVerifiableCredential; subjectDid: string }>}
|
|
171
|
+
*/
|
|
172
|
+
export declare function mintAppKeyCredential({ app, origin }: {
|
|
173
|
+
app: IAppConnectApp;
|
|
174
|
+
origin: string;
|
|
175
|
+
}): Promise<{
|
|
176
|
+
credential: IVerifiableCredential;
|
|
177
|
+
subjectDid: string;
|
|
178
|
+
}>;
|
|
179
|
+
/**
|
|
180
|
+
* The latest legacy app-key credential for an origin, or undefined. A legacy
|
|
181
|
+
* credential predates the `appUrl` model: it carries the marker and a
|
|
182
|
+
* per-app third type entry, but no `credentialSubject.appUrl` claim. Its
|
|
183
|
+
* identity was scoped to (origin, `credentialType`), and the request no
|
|
184
|
+
* longer carries a `credentialType` to select on, so the mapping is
|
|
185
|
+
* recoverable only when it is unambiguous: when the binding legacy candidates
|
|
186
|
+
* for the origin all name one subject DID. Two distinct legacy identities on
|
|
187
|
+
* one origin yield undefined rather than a guess -- re-issuing the wrong one
|
|
188
|
+
* would hand one application another's identity, which is worse than the
|
|
189
|
+
* caller treating the connect as a first run.
|
|
190
|
+
*
|
|
191
|
+
* @param options {object}
|
|
192
|
+
* @param options.credentials {IVerifiableCredential[]}
|
|
193
|
+
* @param options.origin {string} - The attested requesting origin.
|
|
194
|
+
* @returns {Promise<IVerifiableCredential | undefined>}
|
|
195
|
+
*/
|
|
196
|
+
export declare function findLegacyAppKeyCredential({ credentials, origin }: {
|
|
197
|
+
credentials: IVerifiableCredential[];
|
|
198
|
+
origin: string;
|
|
199
|
+
}): Promise<IVerifiableCredential | undefined>;
|
|
200
|
+
/**
|
|
201
|
+
* Re-issues a legacy app-key credential in place under the `appUrl` model:
|
|
202
|
+
* the same seed (so the same derived DID -- the app's identity and its
|
|
203
|
+
* encrypted-data access are preserved), the fixed two-entry type array, the
|
|
204
|
+
* static inline context, and the `credentialSubject.appUrl` claim set from
|
|
205
|
+
* the validated request value. A fresh mint would roll the seed and orphan
|
|
206
|
+
* the identity, and must never be the migration path. The fresh
|
|
207
|
+
* `issuanceDate` ranks the re-issued credential ahead of the legacy one, so
|
|
208
|
+
* subsequent connects match it directly.
|
|
209
|
+
*
|
|
210
|
+
* Does NOT store the result; the caller stores it through the mint door
|
|
211
|
+
* (it satisfies {@link assertMintedAppKey}) and may retire the legacy record.
|
|
212
|
+
*
|
|
213
|
+
* @param options {object}
|
|
214
|
+
* @param options.credential {IVerifiableCredential} - The legacy credential;
|
|
215
|
+
* it must bind per {@link appKeySeedBindsSubject} and be bound to `origin`,
|
|
216
|
+
* else this throws {@link AppKeyMintInvariantError}.
|
|
217
|
+
* @param options.app {IAppConnectApp} - The validated app identity; its
|
|
218
|
+
* `appUrl` must already be in serialized form.
|
|
219
|
+
* @param options.origin {string} - The attested requesting origin.
|
|
220
|
+
* @returns {Promise<{ credential: IVerifiableCredential; subjectDid: string }>}
|
|
221
|
+
*/
|
|
222
|
+
export declare function reissueAppKeyCredential({ credential, app, origin }: {
|
|
223
|
+
credential: IVerifiableCredential;
|
|
224
|
+
app: IAppConnectApp;
|
|
225
|
+
origin: string;
|
|
226
|
+
}): Promise<{
|
|
227
|
+
credential: IVerifiableCredential;
|
|
228
|
+
subjectDid: string;
|
|
229
|
+
}>;
|
|
230
|
+
/**
|
|
231
|
+
* The subject DID (`credentialSubject.id`) of an app-key credential, or
|
|
232
|
+
* undefined. For a valid app-key credential this equals the issuer.
|
|
233
|
+
*
|
|
234
|
+
* @param credential {IVerifiableCredential}
|
|
235
|
+
* @returns {string | undefined}
|
|
236
|
+
*/
|
|
237
|
+
export declare function appKeySubjectDid(credential: IVerifiableCredential): string | undefined;
|
|
238
|
+
/**
|
|
239
|
+
* The origin (`credentialSubject.origin`) an app-key credential is bound to,
|
|
240
|
+
* when present.
|
|
241
|
+
*
|
|
242
|
+
* @param credential {IVerifiableCredential}
|
|
243
|
+
* @returns {string | undefined}
|
|
244
|
+
*/
|
|
245
|
+
export declare function appKeyOrigin(credential: IVerifiableCredential): string | undefined;
|
|
246
|
+
/**
|
|
247
|
+
* The application URL (`credentialSubject.appUrl`) an app-key credential is
|
|
248
|
+
* scoped to, when present. Absent on a legacy (pre-`appUrl`) credential.
|
|
249
|
+
*
|
|
250
|
+
* @param credential {IVerifiableCredential}
|
|
251
|
+
* @returns {string | undefined}
|
|
252
|
+
*/
|
|
253
|
+
export declare function appKeyAppUrl(credential: IVerifiableCredential): string | undefined;
|
|
254
|
+
//# sourceMappingURL=appKey.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appKey.d.ts","sourceRoot":"","sources":["../../src/request/appKey.ts"],"names":[],"mappings":"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"}
|