@bcts/xid 1.0.0-alpha.17 → 1.0.0-alpha.18
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 +1 -1
- package/dist/index.cjs +324 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +145 -9
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +145 -9
- package/dist/index.d.mts.map +1 -1
- package/dist/index.iife.js +326 -40
- package/dist/index.iife.js.map +1 -1
- package/dist/index.mjs +316 -43
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -9
- package/src/index.ts +3 -0
- package/src/key.ts +81 -15
- package/src/provenance.ts +75 -19
- package/src/service.ts +17 -1
- package/src/xid-document.ts +334 -29
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bcts/xid",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.18",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Blockchain Commons XID for TypeScript",
|
|
6
6
|
"license": "BSD-2-Clause-Patent",
|
|
@@ -68,11 +68,11 @@
|
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@bcts/eslint": "^0.1.0",
|
|
71
|
-
"@bcts/rand": "^1.0.0-alpha.
|
|
71
|
+
"@bcts/rand": "^1.0.0-alpha.18",
|
|
72
72
|
"@bcts/tsconfig": "^0.1.0",
|
|
73
73
|
"@eslint/js": "^9.39.2",
|
|
74
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
75
|
-
"@typescript-eslint/parser": "^8.
|
|
74
|
+
"@typescript-eslint/eslint-plugin": "^8.54.0",
|
|
75
|
+
"@typescript-eslint/parser": "^8.54.0",
|
|
76
76
|
"eslint": "^9.39.2",
|
|
77
77
|
"ts-node": "^10.9.2",
|
|
78
78
|
"tsdown": "^0.20.1",
|
|
@@ -81,10 +81,10 @@
|
|
|
81
81
|
"vitest": "^4.0.18"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
|
-
"@bcts/components": "^1.0.0-alpha.
|
|
85
|
-
"@bcts/dcbor": "^1.0.0-alpha.
|
|
86
|
-
"@bcts/envelope": "^1.0.0-alpha.
|
|
87
|
-
"@bcts/known-values": "^1.0.0-alpha.
|
|
88
|
-
"@bcts/provenance-mark": "^1.0.0-alpha.
|
|
84
|
+
"@bcts/components": "^1.0.0-alpha.18",
|
|
85
|
+
"@bcts/dcbor": "^1.0.0-alpha.18",
|
|
86
|
+
"@bcts/envelope": "^1.0.0-alpha.18",
|
|
87
|
+
"@bcts/known-values": "^1.0.0-alpha.18",
|
|
88
|
+
"@bcts/provenance-mark": "^1.0.0-alpha.18"
|
|
89
89
|
}
|
|
90
90
|
}
|
package/src/index.ts
CHANGED
|
@@ -64,5 +64,8 @@ export {
|
|
|
64
64
|
XIDVerifySignature,
|
|
65
65
|
} from "./xid-document";
|
|
66
66
|
|
|
67
|
+
// Re-export Attachments and Edges from envelope for convenience
|
|
68
|
+
export { Attachments, Edges, type Edgeable } from "@bcts/envelope";
|
|
69
|
+
|
|
67
70
|
// Version information
|
|
68
71
|
export const VERSION = "1.0.0-alpha.3";
|
package/src/key.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { Envelope, type EnvelopeEncodable } from "@bcts/envelope";
|
|
11
11
|
import { ENDPOINT, NICKNAME, PRIVATE_KEY, SALT, type KnownValue } from "@bcts/known-values";
|
|
12
12
|
import type { EnvelopeEncodableValue } from "@bcts/envelope";
|
|
13
|
+
import { type Cbor } from "@bcts/dcbor";
|
|
13
14
|
|
|
14
15
|
// Helper to convert KnownValue to EnvelopeEncodableValue
|
|
15
16
|
const kv = (v: KnownValue): EnvelopeEncodableValue => v as unknown as EnvelopeEncodableValue;
|
|
@@ -19,8 +20,12 @@ import {
|
|
|
19
20
|
PublicKeys,
|
|
20
21
|
PrivateKeys,
|
|
21
22
|
type PrivateKeyBase,
|
|
23
|
+
type SigningPublicKey,
|
|
24
|
+
type EncapsulationPublicKey,
|
|
22
25
|
type Verifier,
|
|
23
26
|
type Signature,
|
|
27
|
+
type KeyDerivationMethod,
|
|
28
|
+
defaultKeyDerivationMethod,
|
|
24
29
|
} from "@bcts/components";
|
|
25
30
|
import { Permissions, type HasPermissions } from "./permissions";
|
|
26
31
|
import { type Privilege } from "./privilege";
|
|
@@ -47,6 +52,7 @@ export enum XIDPrivateKeyOptions {
|
|
|
47
52
|
export interface XIDPrivateKeyEncryptConfig {
|
|
48
53
|
type: XIDPrivateKeyOptions.Encrypt;
|
|
49
54
|
password: Uint8Array;
|
|
55
|
+
method?: KeyDerivationMethod;
|
|
50
56
|
}
|
|
51
57
|
|
|
52
58
|
/**
|
|
@@ -121,8 +127,8 @@ export class Key implements HasNickname, HasPermissions, EnvelopeEncodable, Veri
|
|
|
121
127
|
* Create a new Key with private key base (derives keys from it).
|
|
122
128
|
*/
|
|
123
129
|
static newWithPrivateKeyBase(privateKeyBase: PrivateKeyBase): Key {
|
|
124
|
-
const privateKeys = privateKeyBase.
|
|
125
|
-
const publicKeys = privateKeyBase.
|
|
130
|
+
const privateKeys = privateKeyBase.schnorrPrivateKeys();
|
|
131
|
+
const publicKeys = privateKeyBase.schnorrPublicKeys();
|
|
126
132
|
return Key.newWithPrivateKeys(privateKeys, publicKeys);
|
|
127
133
|
}
|
|
128
134
|
|
|
@@ -172,6 +178,20 @@ export class Key implements HasNickname, HasPermissions, EnvelopeEncodable, Veri
|
|
|
172
178
|
return this._publicKeys.reference();
|
|
173
179
|
}
|
|
174
180
|
|
|
181
|
+
/**
|
|
182
|
+
* Get the signing public key.
|
|
183
|
+
*/
|
|
184
|
+
signingPublicKey(): SigningPublicKey {
|
|
185
|
+
return this._publicKeys.signingPublicKey();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Get the encapsulation public key.
|
|
190
|
+
*/
|
|
191
|
+
encapsulationPublicKey(): EncapsulationPublicKey {
|
|
192
|
+
return this._publicKeys.encapsulationPublicKey();
|
|
193
|
+
}
|
|
194
|
+
|
|
175
195
|
// ============================================================================
|
|
176
196
|
// Verifier Interface
|
|
177
197
|
// ============================================================================
|
|
@@ -271,9 +291,13 @@ export class Key implements HasNickname, HasPermissions, EnvelopeEncodable, Veri
|
|
|
271
291
|
case XIDPrivateKeyOptions.Encrypt: {
|
|
272
292
|
if (typeof privateKeyOptions === "object") {
|
|
273
293
|
const privateKeysEnvelope = Envelope.new(data.privateKeys.taggedCborData());
|
|
294
|
+
const method: KeyDerivationMethod =
|
|
295
|
+
privateKeyOptions.method ?? defaultKeyDerivationMethod();
|
|
274
296
|
const encrypted = (
|
|
275
|
-
privateKeysEnvelope as unknown as {
|
|
276
|
-
|
|
297
|
+
privateKeysEnvelope as unknown as {
|
|
298
|
+
lockSubject(m: KeyDerivationMethod, p: Uint8Array): Envelope;
|
|
299
|
+
}
|
|
300
|
+
).lockSubject(method, privateKeyOptions.password);
|
|
277
301
|
envelope = envelope.addAssertion(kv(PRIVATE_KEY), encrypted);
|
|
278
302
|
envelope = envelope.addAssertion(kv(SALT), salt.toData());
|
|
279
303
|
}
|
|
@@ -316,19 +340,29 @@ export class Key implements HasNickname, HasPermissions, EnvelopeEncodable, Veri
|
|
|
316
340
|
asByteString(): Uint8Array | undefined;
|
|
317
341
|
subject(): Envelope;
|
|
318
342
|
assertionsWithPredicate(p: unknown): Envelope[];
|
|
319
|
-
|
|
343
|
+
unlockSubject(p: Uint8Array): Envelope;
|
|
344
|
+
isLockedWithPassword(): boolean;
|
|
320
345
|
};
|
|
321
346
|
const env = envelope as EnvelopeExt;
|
|
322
347
|
|
|
323
|
-
// Extract PublicKeys from subject
|
|
324
|
-
//
|
|
348
|
+
// Extract PublicKeys from subject.
|
|
349
|
+
// Rust-generated documents store PublicKeys as tagged CBOR directly in the leaf.
|
|
350
|
+
// TS-generated documents may store the tagged CBOR binary inside a byte string.
|
|
325
351
|
const envCase = env.case();
|
|
326
352
|
const subject = envCase.type === "node" ? env.subject() : env;
|
|
353
|
+
let publicKeys: PublicKeys;
|
|
327
354
|
const publicKeysData = (subject as EnvelopeExt).asByteString();
|
|
328
|
-
if (publicKeysData
|
|
329
|
-
|
|
355
|
+
if (publicKeysData !== undefined) {
|
|
356
|
+
// TS format: tagged CBOR binary stored as a byte string
|
|
357
|
+
publicKeys = PublicKeys.fromTaggedCborData(publicKeysData);
|
|
358
|
+
} else {
|
|
359
|
+
// Rust format: tagged CBOR stored directly as the leaf CBOR value
|
|
360
|
+
const leaf = (subject as unknown as { asLeaf(): Cbor | undefined }).asLeaf?.();
|
|
361
|
+
if (leaf === undefined) {
|
|
362
|
+
throw XIDError.component(new Error("Could not extract public keys from envelope"));
|
|
363
|
+
}
|
|
364
|
+
publicKeys = PublicKeys.fromTaggedCbor(leaf);
|
|
330
365
|
}
|
|
331
|
-
const publicKeys = PublicKeys.fromTaggedCborData(publicKeysData);
|
|
332
366
|
|
|
333
367
|
// Extract optional private key
|
|
334
368
|
let privateKeyData: { data: PrivateKeyData; salt: Salt } | undefined;
|
|
@@ -356,13 +390,12 @@ export class Key implements HasNickname, HasPermissions, EnvelopeEncodable, Veri
|
|
|
356
390
|
if (assertionCase.type === "assertion") {
|
|
357
391
|
const privateKeyObject = assertionCase.assertion.object() as EnvelopeExt;
|
|
358
392
|
|
|
359
|
-
// Check if
|
|
360
|
-
|
|
361
|
-
if (objCase.type === "encrypted") {
|
|
393
|
+
// Check if locked with password (uses hasSecret assertion with EncryptedKey)
|
|
394
|
+
if (privateKeyObject.isLockedWithPassword()) {
|
|
362
395
|
if (password !== undefined) {
|
|
363
396
|
try {
|
|
364
|
-
const decrypted = privateKeyObject.
|
|
365
|
-
const decryptedData = decrypted.asByteString();
|
|
397
|
+
const decrypted = privateKeyObject.unlockSubject(password) as EnvelopeExt;
|
|
398
|
+
const decryptedData = (decrypted.subject() as EnvelopeExt).asByteString();
|
|
366
399
|
if (decryptedData !== undefined) {
|
|
367
400
|
// Parse PrivateKeys from tagged CBOR
|
|
368
401
|
const privateKeys = PrivateKeys.fromTaggedCborData(decryptedData);
|
|
@@ -431,6 +464,39 @@ export class Key implements HasNickname, HasPermissions, EnvelopeEncodable, Veri
|
|
|
431
464
|
return new Key(publicKeys, privateKeyData, nickname, endpoints, permissions);
|
|
432
465
|
}
|
|
433
466
|
|
|
467
|
+
/**
|
|
468
|
+
* Get the private key envelope, optionally decrypting it.
|
|
469
|
+
*
|
|
470
|
+
* Returns:
|
|
471
|
+
* - undefined if no private keys
|
|
472
|
+
* - The decrypted private key envelope if unencrypted
|
|
473
|
+
* - The decrypted envelope if encrypted + correct password
|
|
474
|
+
* - The encrypted envelope as-is if encrypted + no password
|
|
475
|
+
* - Throws on wrong password
|
|
476
|
+
*/
|
|
477
|
+
privateKeyEnvelope(password?: string): Envelope | undefined {
|
|
478
|
+
if (this._privateKeyData === undefined) {
|
|
479
|
+
return undefined;
|
|
480
|
+
}
|
|
481
|
+
const { data } = this._privateKeyData;
|
|
482
|
+
if (data.type === "decrypted") {
|
|
483
|
+
return Envelope.new(data.privateKeys.taggedCborData());
|
|
484
|
+
}
|
|
485
|
+
// Encrypted case
|
|
486
|
+
if (password !== undefined) {
|
|
487
|
+
try {
|
|
488
|
+
const decrypted = (
|
|
489
|
+
data.envelope as unknown as { unlockSubject(p: Uint8Array): Envelope }
|
|
490
|
+
).unlockSubject(new TextEncoder().encode(password));
|
|
491
|
+
return decrypted;
|
|
492
|
+
} catch {
|
|
493
|
+
throw XIDError.invalidPassword();
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
// No password — return encrypted envelope as-is
|
|
497
|
+
return data.envelope;
|
|
498
|
+
}
|
|
499
|
+
|
|
434
500
|
/**
|
|
435
501
|
* Check equality with another Key.
|
|
436
502
|
*/
|
package/src/provenance.ts
CHANGED
|
@@ -9,14 +9,21 @@
|
|
|
9
9
|
|
|
10
10
|
import { Envelope, type EnvelopeEncodable, type EnvelopeEncodableValue } from "@bcts/envelope";
|
|
11
11
|
import { PROVENANCE_GENERATOR, SALT, type KnownValue } from "@bcts/known-values";
|
|
12
|
-
import { Salt } from "@bcts/components";
|
|
12
|
+
import { Salt, type KeyDerivationMethod, defaultKeyDerivationMethod } from "@bcts/components";
|
|
13
13
|
|
|
14
14
|
// Helper to convert KnownValue to EnvelopeEncodableValue
|
|
15
15
|
const kv = (v: KnownValue): EnvelopeEncodableValue => v as unknown as EnvelopeEncodableValue;
|
|
16
16
|
import { ProvenanceMark, ProvenanceMarkGenerator } from "@bcts/provenance-mark";
|
|
17
|
-
import { cborData, decodeCbor } from "@bcts/dcbor";
|
|
18
17
|
import { XIDError } from "./error";
|
|
19
18
|
|
|
19
|
+
// Encode generator JSON as bytes for storage in envelope
|
|
20
|
+
const encodeGeneratorJSON = (json: Record<string, unknown>): Uint8Array =>
|
|
21
|
+
new TextEncoder().encode(JSON.stringify(json));
|
|
22
|
+
|
|
23
|
+
// Decode generator JSON from bytes stored in envelope
|
|
24
|
+
const decodeGeneratorJSON = (data: Uint8Array): Record<string, unknown> =>
|
|
25
|
+
JSON.parse(new TextDecoder().decode(data)) as Record<string, unknown>;
|
|
26
|
+
|
|
20
27
|
/**
|
|
21
28
|
* Options for handling generators in envelopes.
|
|
22
29
|
*/
|
|
@@ -37,6 +44,7 @@ export enum XIDGeneratorOptions {
|
|
|
37
44
|
export interface XIDGeneratorEncryptConfig {
|
|
38
45
|
type: XIDGeneratorOptions.Encrypt;
|
|
39
46
|
password: Uint8Array;
|
|
47
|
+
method?: KeyDerivationMethod;
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
/**
|
|
@@ -150,7 +158,8 @@ export class Provenance implements EnvelopeEncodable {
|
|
|
150
158
|
*/
|
|
151
159
|
generatorMut(password?: Uint8Array): ProvenanceMarkGenerator | undefined {
|
|
152
160
|
type EnvelopeExt = Envelope & {
|
|
153
|
-
|
|
161
|
+
unlockSubject(p: Uint8Array): Envelope;
|
|
162
|
+
subject(): Envelope;
|
|
154
163
|
tryUnwrap(): Envelope;
|
|
155
164
|
asByteString(): Uint8Array | undefined;
|
|
156
165
|
};
|
|
@@ -165,12 +174,12 @@ export class Provenance implements EnvelopeEncodable {
|
|
|
165
174
|
if (password !== undefined) {
|
|
166
175
|
const encryptedEnvelope = this._generator.data.envelope as EnvelopeExt;
|
|
167
176
|
try {
|
|
168
|
-
const decrypted = encryptedEnvelope.
|
|
169
|
-
const unwrapped = decrypted.tryUnwrap() as EnvelopeExt;
|
|
177
|
+
const decrypted = encryptedEnvelope.unlockSubject(password) as EnvelopeExt;
|
|
178
|
+
const unwrapped = (decrypted.subject() as EnvelopeExt).tryUnwrap() as EnvelopeExt;
|
|
170
179
|
// Extract generator from unwrapped envelope
|
|
171
180
|
const generatorData = unwrapped.asByteString();
|
|
172
181
|
if (generatorData !== undefined) {
|
|
173
|
-
const json =
|
|
182
|
+
const json = decodeGeneratorJSON(generatorData);
|
|
174
183
|
const generator = ProvenanceMarkGenerator.fromJSON(json);
|
|
175
184
|
// Replace encrypted with decrypted
|
|
176
185
|
this._generator = {
|
|
@@ -187,6 +196,47 @@ export class Provenance implements EnvelopeEncodable {
|
|
|
187
196
|
throw XIDError.invalidPassword();
|
|
188
197
|
}
|
|
189
198
|
|
|
199
|
+
/**
|
|
200
|
+
* Get the generator envelope, optionally decrypting it.
|
|
201
|
+
*
|
|
202
|
+
* Returns:
|
|
203
|
+
* - undefined if no generator
|
|
204
|
+
* - An envelope containing the generator if unencrypted
|
|
205
|
+
* - The decrypted envelope if encrypted + correct password
|
|
206
|
+
* - The encrypted envelope as-is if encrypted + no password
|
|
207
|
+
* - Throws on wrong password
|
|
208
|
+
*/
|
|
209
|
+
generatorEnvelope(password?: string): Envelope | undefined {
|
|
210
|
+
type EnvelopeExt = Envelope & {
|
|
211
|
+
unlockSubject(p: Uint8Array): Envelope;
|
|
212
|
+
subject(): Envelope;
|
|
213
|
+
tryUnwrap(): Envelope;
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
if (this._generator === undefined) {
|
|
217
|
+
return undefined;
|
|
218
|
+
}
|
|
219
|
+
const { data } = this._generator;
|
|
220
|
+
if (data.type === "decrypted") {
|
|
221
|
+
const generatorBytes = encodeGeneratorJSON(data.generator.toJSON());
|
|
222
|
+
return Envelope.new(generatorBytes);
|
|
223
|
+
}
|
|
224
|
+
// Encrypted case
|
|
225
|
+
if (password !== undefined) {
|
|
226
|
+
try {
|
|
227
|
+
const decrypted = (data.envelope as EnvelopeExt).unlockSubject(
|
|
228
|
+
new TextEncoder().encode(password),
|
|
229
|
+
) as EnvelopeExt;
|
|
230
|
+
const unwrapped = (decrypted.subject() as EnvelopeExt).tryUnwrap();
|
|
231
|
+
return unwrapped;
|
|
232
|
+
} catch {
|
|
233
|
+
throw XIDError.invalidPassword();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// No password — return encrypted envelope as-is
|
|
237
|
+
return data.envelope;
|
|
238
|
+
}
|
|
239
|
+
|
|
190
240
|
/**
|
|
191
241
|
* Convert to envelope with specified options.
|
|
192
242
|
*/
|
|
@@ -194,7 +244,7 @@ export class Provenance implements EnvelopeEncodable {
|
|
|
194
244
|
type EnvelopeExt = Envelope & {
|
|
195
245
|
elide(): Envelope;
|
|
196
246
|
wrap(): Envelope;
|
|
197
|
-
|
|
247
|
+
lockSubject(m: KeyDerivationMethod, p: Uint8Array): Envelope;
|
|
198
248
|
};
|
|
199
249
|
|
|
200
250
|
// Create envelope with the mark as subject
|
|
@@ -215,13 +265,13 @@ export class Provenance implements EnvelopeEncodable {
|
|
|
215
265
|
|
|
216
266
|
switch (option) {
|
|
217
267
|
case XIDGeneratorOptions.Include: {
|
|
218
|
-
const generatorBytes =
|
|
268
|
+
const generatorBytes = encodeGeneratorJSON(data.generator.toJSON());
|
|
219
269
|
envelope = envelope.addAssertion(kv(PROVENANCE_GENERATOR), generatorBytes);
|
|
220
270
|
envelope = envelope.addAssertion(kv(SALT), salt.toData());
|
|
221
271
|
break;
|
|
222
272
|
}
|
|
223
273
|
case XIDGeneratorOptions.Elide: {
|
|
224
|
-
const generatorBytes2 =
|
|
274
|
+
const generatorBytes2 = encodeGeneratorJSON(data.generator.toJSON());
|
|
225
275
|
const baseAssertion = Envelope.newAssertion(kv(PROVENANCE_GENERATOR), generatorBytes2);
|
|
226
276
|
const elidedAssertion = (baseAssertion as EnvelopeExt).elide();
|
|
227
277
|
envelope = envelope.addAssertionEnvelope(elidedAssertion);
|
|
@@ -230,10 +280,15 @@ export class Provenance implements EnvelopeEncodable {
|
|
|
230
280
|
}
|
|
231
281
|
case XIDGeneratorOptions.Encrypt: {
|
|
232
282
|
if (typeof generatorOptions === "object") {
|
|
233
|
-
const generatorBytes3 =
|
|
283
|
+
const generatorBytes3 = encodeGeneratorJSON(data.generator.toJSON());
|
|
234
284
|
const generatorEnvelope = Envelope.new(generatorBytes3) as EnvelopeExt;
|
|
235
285
|
const wrapped = generatorEnvelope.wrap() as EnvelopeExt;
|
|
236
|
-
const
|
|
286
|
+
const method: KeyDerivationMethod =
|
|
287
|
+
generatorOptions.method ?? defaultKeyDerivationMethod();
|
|
288
|
+
const encrypted = (wrapped as unknown as EnvelopeExt).lockSubject(
|
|
289
|
+
method,
|
|
290
|
+
generatorOptions.password,
|
|
291
|
+
);
|
|
237
292
|
envelope = envelope.addAssertion(kv(PROVENANCE_GENERATOR), encrypted);
|
|
238
293
|
envelope = envelope.addAssertion(kv(SALT), salt.toData());
|
|
239
294
|
}
|
|
@@ -261,8 +316,10 @@ export class Provenance implements EnvelopeEncodable {
|
|
|
261
316
|
static tryFromEnvelope(envelope: Envelope, password?: Uint8Array): Provenance {
|
|
262
317
|
type EnvelopeExt = Envelope & {
|
|
263
318
|
asByteString(): Uint8Array | undefined;
|
|
319
|
+
subject(): Envelope;
|
|
264
320
|
assertionsWithPredicate(p: unknown): Envelope[];
|
|
265
|
-
|
|
321
|
+
unlockSubject(p: Uint8Array): Envelope;
|
|
322
|
+
isLockedWithPassword(): boolean;
|
|
266
323
|
tryUnwrap(): Envelope;
|
|
267
324
|
};
|
|
268
325
|
const env = envelope as EnvelopeExt;
|
|
@@ -304,16 +361,15 @@ export class Provenance implements EnvelopeEncodable {
|
|
|
304
361
|
if (assertionCase.type === "assertion") {
|
|
305
362
|
const generatorObject = assertionCase.assertion.object() as EnvelopeExt;
|
|
306
363
|
|
|
307
|
-
// Check if
|
|
308
|
-
|
|
309
|
-
if (objCase.type === "encrypted") {
|
|
364
|
+
// Check if locked with password (uses hasSecret assertion with EncryptedKey)
|
|
365
|
+
if (generatorObject.isLockedWithPassword()) {
|
|
310
366
|
if (password !== undefined) {
|
|
311
367
|
try {
|
|
312
|
-
const decrypted = generatorObject.
|
|
313
|
-
const unwrapped = decrypted.tryUnwrap() as EnvelopeExt;
|
|
368
|
+
const decrypted = generatorObject.unlockSubject(password) as EnvelopeExt;
|
|
369
|
+
const unwrapped = (decrypted.subject() as EnvelopeExt).tryUnwrap() as EnvelopeExt;
|
|
314
370
|
const generatorData = unwrapped.asByteString();
|
|
315
371
|
if (generatorData !== undefined) {
|
|
316
|
-
const json =
|
|
372
|
+
const json = decodeGeneratorJSON(generatorData);
|
|
317
373
|
const gen = ProvenanceMarkGenerator.fromJSON(json);
|
|
318
374
|
generator = {
|
|
319
375
|
data: { type: "decrypted", generator: gen },
|
|
@@ -338,7 +394,7 @@ export class Provenance implements EnvelopeEncodable {
|
|
|
338
394
|
// Plain text generator
|
|
339
395
|
const generatorData = generatorObject.asByteString();
|
|
340
396
|
if (generatorData !== undefined) {
|
|
341
|
-
const json2 =
|
|
397
|
+
const json2 = decodeGeneratorJSON(generatorData);
|
|
342
398
|
const gen = ProvenanceMarkGenerator.fromJSON(json2);
|
|
343
399
|
generator = {
|
|
344
400
|
data: { type: "decrypted", generator: gen },
|
package/src/service.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { KEY, DELEGATE, NAME, CAPABILITY, ALLOW, type KnownValue } from "@bcts/k
|
|
|
12
12
|
|
|
13
13
|
// Helper to convert KnownValue to EnvelopeEncodableValue
|
|
14
14
|
const kv = (v: KnownValue): EnvelopeEncodableValue => v as unknown as EnvelopeEncodableValue;
|
|
15
|
-
import
|
|
15
|
+
import { Reference, type PublicKeys, type XID } from "@bcts/components";
|
|
16
16
|
import { Permissions, type HasPermissions } from "./permissions";
|
|
17
17
|
import { privilegeFromEnvelope } from "./privilege";
|
|
18
18
|
import { XIDError } from "./error";
|
|
@@ -147,6 +147,22 @@ export class Service implements HasPermissions, EnvelopeEncodable {
|
|
|
147
147
|
this.addDelegateReferenceHex(delegateReference.toHex());
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Add a key by its public keys provider (convenience method).
|
|
152
|
+
* Matches Rust's `add_key(&mut self, key: &dyn PublicKeysProvider)`.
|
|
153
|
+
*/
|
|
154
|
+
addKey(keyProvider: { publicKeys(): PublicKeys }): void {
|
|
155
|
+
this.addKeyReference(keyProvider.publicKeys().reference());
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Add a delegate by its XID provider (convenience method).
|
|
160
|
+
* Matches Rust's `add_delegate(&mut self, delegate: &dyn XIDProvider)`.
|
|
161
|
+
*/
|
|
162
|
+
addDelegate(xidProvider: { xid(): XID }): void {
|
|
163
|
+
this.addDelegateReference(Reference.hash(xidProvider.xid().toData()));
|
|
164
|
+
}
|
|
165
|
+
|
|
150
166
|
/**
|
|
151
167
|
* Get the name.
|
|
152
168
|
*/
|