@didcid/keymaster 0.3.0 → 0.3.1

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.
@@ -0,0 +1,1213 @@
1
+ #!/usr/bin/env node
2
+ import { program } from 'commander';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import dotenv from 'dotenv';
6
+ import Keymaster from './keymaster.js';
7
+ import GatekeeperClient from '@didcid/gatekeeper/client';
8
+ import CipherNode from '@didcid/cipher/node';
9
+ import WalletJson from './db/json.js';
10
+ import WalletSQLite from './db/sqlite.js';
11
+ dotenv.config();
12
+ let keymaster;
13
+ const UPDATE_OK = "OK";
14
+ const UPDATE_FAILED = "Update failed";
15
+ program
16
+ .version('0.2.0')
17
+ .description('Keymaster CLI - Archon wallet management tool')
18
+ .configureHelp({ sortSubcommands: true });
19
+ // Wallet commands
20
+ program
21
+ .command('create-wallet')
22
+ .description('Create a new wallet (or show existing wallet)')
23
+ .action(async () => {
24
+ try {
25
+ const wallet = await keymaster.loadWallet();
26
+ console.log(JSON.stringify(wallet, null, 4));
27
+ }
28
+ catch (error) {
29
+ console.error(error.error || error.message || error);
30
+ }
31
+ });
32
+ program
33
+ .command('new-wallet')
34
+ .description('Create a new wallet')
35
+ .action(async () => {
36
+ try {
37
+ await keymaster.newWallet("", true);
38
+ const wallet = await keymaster.loadWallet();
39
+ console.log(JSON.stringify(wallet, null, 4));
40
+ }
41
+ catch (error) {
42
+ console.error(error.error || error.message || error);
43
+ }
44
+ });
45
+ program
46
+ .command('check-wallet')
47
+ .description('Validate DIDs in wallet')
48
+ .action(async () => {
49
+ try {
50
+ const { checked, invalid, deleted } = await keymaster.checkWallet();
51
+ if (invalid === 0 && deleted === 0) {
52
+ console.log(`${checked} DIDs checked, no problems found`);
53
+ }
54
+ else {
55
+ console.log(`${checked} DIDs checked, ${invalid} invalid DIDs found, ${deleted} deleted DIDs found`);
56
+ }
57
+ }
58
+ catch (error) {
59
+ console.error(error.error || error.message || error);
60
+ }
61
+ });
62
+ program
63
+ .command('fix-wallet')
64
+ .description('Remove invalid DIDs from the wallet')
65
+ .action(async () => {
66
+ try {
67
+ const { idsRemoved, ownedRemoved, heldRemoved, namesRemoved } = await keymaster.fixWallet();
68
+ console.log(`${idsRemoved} IDs and ${ownedRemoved} owned DIDs and ${heldRemoved} held DIDs and ${namesRemoved} names were removed`);
69
+ }
70
+ catch (error) {
71
+ console.error(error.error || error.message || error);
72
+ }
73
+ });
74
+ program
75
+ .command('import-wallet <recovery-phrase>')
76
+ .description('Create new wallet from a recovery phrase')
77
+ .action(async (recoveryPhrase) => {
78
+ try {
79
+ const wallet = await keymaster.newWallet(recoveryPhrase);
80
+ console.log(JSON.stringify(wallet, null, 4));
81
+ }
82
+ catch (error) {
83
+ console.error(error.error || error.message || error);
84
+ }
85
+ });
86
+ program
87
+ .command('show-wallet')
88
+ .description('Show wallet')
89
+ .action(async () => {
90
+ try {
91
+ const wallet = await keymaster.loadWallet();
92
+ console.log(JSON.stringify(wallet, null, 4));
93
+ }
94
+ catch (error) {
95
+ console.error(error.error || error.message || error);
96
+ }
97
+ });
98
+ program
99
+ .command('backup-wallet-file <file>')
100
+ .description('Backup wallet to file')
101
+ .action(async (file) => {
102
+ try {
103
+ const wallet = await keymaster.exportEncryptedWallet();
104
+ fs.writeFileSync(file, JSON.stringify(wallet, null, 4));
105
+ console.log(UPDATE_OK);
106
+ }
107
+ catch (error) {
108
+ console.error(error.error || error.message || error);
109
+ }
110
+ });
111
+ program
112
+ .command('restore-wallet-file <file>')
113
+ .description('Restore wallet from backup file')
114
+ .action(async (file) => {
115
+ try {
116
+ const contents = fs.readFileSync(file).toString();
117
+ const wallet = JSON.parse(contents);
118
+ const ok = await keymaster.saveWallet(wallet, true);
119
+ console.log(ok ? UPDATE_OK : UPDATE_FAILED);
120
+ }
121
+ catch (error) {
122
+ console.error(error.error || error.message || error);
123
+ }
124
+ });
125
+ program
126
+ .command('show-mnemonic')
127
+ .description('Show recovery phrase for wallet')
128
+ .action(async () => {
129
+ try {
130
+ const mnemonic = await keymaster.decryptMnemonic();
131
+ console.log(mnemonic);
132
+ }
133
+ catch (error) {
134
+ console.error(error.error || error.message || error);
135
+ }
136
+ });
137
+ program
138
+ .command('backup-wallet-did')
139
+ .description('Backup wallet to encrypted DID and seed bank')
140
+ .action(async () => {
141
+ try {
142
+ const did = await keymaster.backupWallet();
143
+ console.log(did);
144
+ }
145
+ catch (error) {
146
+ console.error(error.error || error.message || error);
147
+ }
148
+ });
149
+ program
150
+ .command('recover-wallet-did [did]')
151
+ .description('Recover wallet from seed bank or encrypted DID')
152
+ .action(async (did) => {
153
+ try {
154
+ const wallet = await keymaster.recoverWallet(did);
155
+ console.log(JSON.stringify(wallet, null, 4));
156
+ }
157
+ catch (error) {
158
+ console.error(error.error || error.message || error);
159
+ }
160
+ });
161
+ // Identity commands
162
+ program
163
+ .command('create-id <name>')
164
+ .description('Create a new decentralized ID')
165
+ .option('-r, --registry <registry>', 'registry to use')
166
+ .action(async (name, options) => {
167
+ try {
168
+ const { registry } = options;
169
+ const did = await keymaster.createId(name, { registry });
170
+ console.log(did);
171
+ }
172
+ catch (error) {
173
+ console.error(error.error || error.message || error);
174
+ }
175
+ });
176
+ program
177
+ .command('resolve-id')
178
+ .description('Resolves the current ID')
179
+ .action(async () => {
180
+ try {
181
+ const current = await keymaster.getCurrentId();
182
+ if (!current) {
183
+ console.error('No current ID set');
184
+ return;
185
+ }
186
+ const doc = await keymaster.resolveDID(current);
187
+ console.log(JSON.stringify(doc, null, 4));
188
+ }
189
+ catch (error) {
190
+ console.error(error.error || error.message || error);
191
+ }
192
+ });
193
+ program
194
+ .command('backup-id')
195
+ .description('Backup the current ID to its registry')
196
+ .action(async () => {
197
+ try {
198
+ const ok = await keymaster.backupId();
199
+ console.log(ok ? UPDATE_OK : UPDATE_FAILED);
200
+ }
201
+ catch (error) {
202
+ console.error(error.error || error.message || error);
203
+ }
204
+ });
205
+ program
206
+ .command('recover-id <did>')
207
+ .description('Recovers the ID from the DID')
208
+ .action(async (did) => {
209
+ try {
210
+ const response = await keymaster.recoverId(did);
211
+ console.log(response);
212
+ }
213
+ catch (error) {
214
+ console.error(error.error || error.message || error);
215
+ }
216
+ });
217
+ program
218
+ .command('remove-id <name>')
219
+ .description('Deletes named ID')
220
+ .action(async (name) => {
221
+ try {
222
+ await keymaster.removeId(name);
223
+ console.log(`ID ${name} removed`);
224
+ }
225
+ catch (error) {
226
+ console.error(error.error || error.message || error);
227
+ }
228
+ });
229
+ program
230
+ .command('rename-id <oldName> <newName>')
231
+ .description('Renames the ID')
232
+ .action(async (oldName, newName) => {
233
+ try {
234
+ const ok = await keymaster.renameId(oldName, newName);
235
+ console.log(ok ? UPDATE_OK : UPDATE_FAILED);
236
+ }
237
+ catch (error) {
238
+ console.error(error.error || error.message || error);
239
+ }
240
+ });
241
+ program
242
+ .command('list-ids')
243
+ .description('List IDs and show current ID')
244
+ .action(async () => {
245
+ try {
246
+ const current = await keymaster.getCurrentId();
247
+ const ids = await keymaster.listIds();
248
+ for (const id of ids) {
249
+ if (id === current) {
250
+ console.log(id, ' <<< current');
251
+ }
252
+ else {
253
+ console.log(id);
254
+ }
255
+ }
256
+ }
257
+ catch (error) {
258
+ console.error(error.error || error.message || error);
259
+ }
260
+ });
261
+ program
262
+ .command('use-id <name>')
263
+ .description('Set the current ID')
264
+ .action(async (name) => {
265
+ try {
266
+ await keymaster.setCurrentId(name);
267
+ console.log(UPDATE_OK);
268
+ }
269
+ catch (error) {
270
+ console.error(error.error || error.message || error);
271
+ }
272
+ });
273
+ program
274
+ .command('rotate-keys')
275
+ .description('Generates new set of keys for current ID')
276
+ .action(async () => {
277
+ try {
278
+ const ok = await keymaster.rotateKeys();
279
+ console.log(ok ? UPDATE_OK : UPDATE_FAILED);
280
+ }
281
+ catch (error) {
282
+ console.error(error.error || error.message || error);
283
+ }
284
+ });
285
+ // DID commands
286
+ program
287
+ .command('resolve-did <did> [confirm]')
288
+ .description('Return document associated with DID')
289
+ .action(async (did, confirm) => {
290
+ try {
291
+ const doc = await keymaster.resolveDID(did, { confirm: !!confirm });
292
+ console.log(JSON.stringify(doc, null, 4));
293
+ }
294
+ catch (error) {
295
+ console.error(`cannot resolve ${did}`);
296
+ }
297
+ });
298
+ program
299
+ .command('resolve-did-version <did> <version>')
300
+ .description('Return specified version of document associated with DID')
301
+ .action(async (did, version) => {
302
+ try {
303
+ const doc = await keymaster.resolveDID(did, { versionSequence: parseInt(version, 10) });
304
+ console.log(JSON.stringify(doc, null, 4));
305
+ }
306
+ catch (error) {
307
+ console.error(`cannot resolve ${did}`);
308
+ }
309
+ });
310
+ program
311
+ .command('revoke-did <did>')
312
+ .description('Permanently revoke a DID')
313
+ .action(async (did) => {
314
+ try {
315
+ const ok = await keymaster.revokeDID(did);
316
+ console.log(ok ? UPDATE_OK : UPDATE_FAILED);
317
+ }
318
+ catch (error) {
319
+ console.error(`cannot revoke ${did}`);
320
+ }
321
+ });
322
+ // Encryption commands
323
+ program
324
+ .command('encrypt-message <message> <did>')
325
+ .description('Encrypt a message for a DID')
326
+ .action(async (msg, did) => {
327
+ try {
328
+ const cipherDid = await keymaster.encryptMessage(msg, did);
329
+ console.log(cipherDid);
330
+ }
331
+ catch (error) {
332
+ console.error(error.error || error.message || error);
333
+ }
334
+ });
335
+ program
336
+ .command('encrypt-file <file> <did>')
337
+ .description('Encrypt a file for a DID')
338
+ .action(async (file, did) => {
339
+ try {
340
+ const contents = fs.readFileSync(file).toString();
341
+ const cipherDid = await keymaster.encryptMessage(contents, did);
342
+ console.log(cipherDid);
343
+ }
344
+ catch (error) {
345
+ console.error(error.error || error.message || error);
346
+ }
347
+ });
348
+ program
349
+ .command('decrypt-did <did>')
350
+ .description('Decrypt an encrypted message DID')
351
+ .action(async (did) => {
352
+ try {
353
+ const plaintext = await keymaster.decryptMessage(did);
354
+ console.log(plaintext);
355
+ }
356
+ catch (error) {
357
+ console.error(`cannot decrypt ${did}`);
358
+ }
359
+ });
360
+ program
361
+ .command('decrypt-json <did>')
362
+ .description('Decrypt an encrypted JSON DID')
363
+ .action(async (did) => {
364
+ try {
365
+ const json = await keymaster.decryptJSON(did);
366
+ console.log(JSON.stringify(json, null, 4));
367
+ }
368
+ catch (error) {
369
+ console.error(`cannot decrypt ${did}`);
370
+ }
371
+ });
372
+ // Signing commands
373
+ program
374
+ .command('sign-file <file>')
375
+ .description('Sign a JSON file')
376
+ .action(async (file) => {
377
+ try {
378
+ const contents = fs.readFileSync(file).toString();
379
+ const json = await keymaster.addProof(JSON.parse(contents));
380
+ console.log(JSON.stringify(json, null, 4));
381
+ }
382
+ catch (error) {
383
+ console.error(error.error || error.message || error);
384
+ }
385
+ });
386
+ program
387
+ .command('verify-file <file>')
388
+ .description('Verify the proof in a JSON file')
389
+ .action(async (file) => {
390
+ try {
391
+ const json = JSON.parse(fs.readFileSync(file).toString());
392
+ const isValid = await keymaster.verifyProof(json);
393
+ console.log(`proof in ${file}`, isValid ? 'is valid' : 'is NOT valid');
394
+ }
395
+ catch (error) {
396
+ console.error(error.error || error.message || error);
397
+ }
398
+ });
399
+ // Challenge commands
400
+ program
401
+ .command('create-challenge [file]')
402
+ .description('Create a challenge (optionally from a file)')
403
+ .option('-n, --name <name>', 'DID name')
404
+ .action(async (file, options) => {
405
+ try {
406
+ const { name } = options;
407
+ const challenge = file ? JSON.parse(fs.readFileSync(file).toString()) : undefined;
408
+ const did = await keymaster.createChallenge(challenge, { name });
409
+ console.log(did);
410
+ }
411
+ catch (error) {
412
+ console.error(error.error || error.message || error);
413
+ }
414
+ });
415
+ program
416
+ .command('create-challenge-cc <did>')
417
+ .description('Create a challenge from a credential DID')
418
+ .option('-n, --name <name>', 'DID name')
419
+ .action(async (credentialDID, options) => {
420
+ try {
421
+ const { name } = options;
422
+ const challenge = { credentials: [{ schema: credentialDID }] };
423
+ const did = await keymaster.createChallenge(challenge, { name });
424
+ console.log(did);
425
+ }
426
+ catch (error) {
427
+ console.error(error.error || error.message || error);
428
+ }
429
+ });
430
+ program
431
+ .command('create-response <challenge>')
432
+ .description('Create a response to a challenge')
433
+ .action(async (challenge) => {
434
+ try {
435
+ const did = await keymaster.createResponse(challenge);
436
+ console.log(did);
437
+ }
438
+ catch (error) {
439
+ console.error(error.error || error.message || error);
440
+ }
441
+ });
442
+ program
443
+ .command('verify-response <response>')
444
+ .description('Decrypt and validate a response to a challenge')
445
+ .action(async (response) => {
446
+ try {
447
+ const vp = await keymaster.verifyResponse(response);
448
+ console.log(JSON.stringify(vp, null, 4));
449
+ }
450
+ catch (error) {
451
+ console.error(error.error || error.message || error);
452
+ }
453
+ });
454
+ // Credential commands
455
+ program
456
+ .command('bind-credential <schema> <subject>')
457
+ .description('Create bound credential for a user')
458
+ .action(async (schema, subject) => {
459
+ try {
460
+ const vc = await keymaster.bindCredential(subject, { schema });
461
+ console.log(JSON.stringify(vc, null, 4));
462
+ }
463
+ catch (error) {
464
+ console.error(error.error || error.message || error);
465
+ }
466
+ });
467
+ program
468
+ .command('issue-credential <file>')
469
+ .description('Sign and encrypt a bound credential file')
470
+ .option('-n, --name <name>', 'DID name')
471
+ .option('-r, --registry <registry>', 'registry to use')
472
+ .action(async (file, options) => {
473
+ try {
474
+ const { name, registry } = options;
475
+ const vc = JSON.parse(fs.readFileSync(file).toString());
476
+ const did = await keymaster.issueCredential(vc, { registry, name });
477
+ console.log(did);
478
+ }
479
+ catch (error) {
480
+ console.error(error.error || error.message || error);
481
+ }
482
+ });
483
+ program
484
+ .command('list-issued')
485
+ .description('List issued credentials')
486
+ .action(async () => {
487
+ try {
488
+ const response = await keymaster.listIssued();
489
+ console.log(JSON.stringify(response, null, 4));
490
+ }
491
+ catch (error) {
492
+ console.error(error.error || error.message || error);
493
+ }
494
+ });
495
+ program
496
+ .command('revoke-credential <did>')
497
+ .description('Revokes a verifiable credential')
498
+ .action(async (did) => {
499
+ try {
500
+ const ok = await keymaster.revokeCredential(did);
501
+ console.log(ok ? UPDATE_OK : UPDATE_FAILED);
502
+ }
503
+ catch (error) {
504
+ console.error(error.error || error.message || error);
505
+ }
506
+ });
507
+ program
508
+ .command('accept-credential <did>')
509
+ .description('Save verifiable credential for current ID')
510
+ .option('-n, --name <name>', 'DID name')
511
+ .action(async (did, options) => {
512
+ const { name } = options;
513
+ try {
514
+ const ok = await keymaster.acceptCredential(did);
515
+ if (ok) {
516
+ console.log(UPDATE_OK);
517
+ if (name) {
518
+ await keymaster.addName(name, did);
519
+ }
520
+ }
521
+ else {
522
+ console.log(UPDATE_FAILED);
523
+ }
524
+ }
525
+ catch (error) {
526
+ console.error(error.error || error.message || error);
527
+ }
528
+ });
529
+ program
530
+ .command('list-credentials')
531
+ .description('List credentials by current ID')
532
+ .action(async () => {
533
+ try {
534
+ const held = await keymaster.listCredentials();
535
+ console.log(JSON.stringify(held, null, 4));
536
+ }
537
+ catch (error) {
538
+ console.error(error.error || error.message || error);
539
+ }
540
+ });
541
+ program
542
+ .command('get-credential <did>')
543
+ .description('Get credential by DID')
544
+ .action(async (did) => {
545
+ try {
546
+ const credential = await keymaster.getCredential(did);
547
+ console.log(JSON.stringify(credential, null, 4));
548
+ }
549
+ catch (error) {
550
+ console.error(error.error || error.message || error);
551
+ }
552
+ });
553
+ program
554
+ .command('publish-credential <did>')
555
+ .description('Publish the existence of a credential to the current user manifest')
556
+ .action(async (did) => {
557
+ try {
558
+ const response = await keymaster.publishCredential(did, { reveal: false });
559
+ console.log(JSON.stringify(response, null, 4));
560
+ }
561
+ catch (error) {
562
+ console.error(error.error || error.message || error);
563
+ }
564
+ });
565
+ program
566
+ .command('reveal-credential <did>')
567
+ .description('Reveal a credential to the current user manifest')
568
+ .action(async (did) => {
569
+ try {
570
+ const response = await keymaster.publishCredential(did, { reveal: true });
571
+ console.log(JSON.stringify(response, null, 4));
572
+ }
573
+ catch (error) {
574
+ console.error(error.error || error.message || error);
575
+ }
576
+ });
577
+ program
578
+ .command('unpublish-credential <did>')
579
+ .description('Remove a credential from the current user manifest')
580
+ .action(async (did) => {
581
+ try {
582
+ const response = await keymaster.unpublishCredential(did);
583
+ console.log(response);
584
+ }
585
+ catch (error) {
586
+ console.error(error.error || error.message || error);
587
+ }
588
+ });
589
+ // Name commands
590
+ program
591
+ .command('add-name <name> <did>')
592
+ .description('Add a name for a DID')
593
+ .action(async (name, did) => {
594
+ try {
595
+ await keymaster.addName(name, did);
596
+ console.log(UPDATE_OK);
597
+ }
598
+ catch (error) {
599
+ console.error(error.error || error.message || error);
600
+ }
601
+ });
602
+ program
603
+ .command('get-name <name>')
604
+ .description('Get DID assigned to name')
605
+ .action(async (name) => {
606
+ try {
607
+ const did = await keymaster.getName(name);
608
+ console.log(did || `${name} not found`);
609
+ }
610
+ catch (error) {
611
+ console.error(error.error || error.message || error);
612
+ }
613
+ });
614
+ program
615
+ .command('remove-name <name>')
616
+ .description('Removes a name for a DID')
617
+ .action(async (name) => {
618
+ try {
619
+ await keymaster.removeName(name);
620
+ console.log(UPDATE_OK);
621
+ }
622
+ catch (error) {
623
+ console.error(error.error || error.message || error);
624
+ }
625
+ });
626
+ program
627
+ .command('list-names')
628
+ .description('List DID names (aliases)')
629
+ .action(async () => {
630
+ try {
631
+ const names = await keymaster.listNames();
632
+ if (names) {
633
+ console.log(JSON.stringify(names, null, 4));
634
+ }
635
+ else {
636
+ console.log("No names defined");
637
+ }
638
+ }
639
+ catch (error) {
640
+ console.error(error.error || error.message || error);
641
+ }
642
+ });
643
+ // Group commands
644
+ program
645
+ .command('create-group <groupName>')
646
+ .description('Create a new group')
647
+ .option('-n, --name <name>', 'DID name')
648
+ .option('-r, --registry <registry>', 'registry to use')
649
+ .action(async (groupName, options) => {
650
+ try {
651
+ const { name, registry } = options;
652
+ const did = await keymaster.createGroup(groupName, { name, registry });
653
+ console.log(did);
654
+ }
655
+ catch (error) {
656
+ console.error(error.error || error.message || error);
657
+ }
658
+ });
659
+ program
660
+ .command('list-groups')
661
+ .description('List groups owned by current ID')
662
+ .action(async () => {
663
+ try {
664
+ const groups = await keymaster.listGroups();
665
+ console.log(JSON.stringify(groups, null, 4));
666
+ }
667
+ catch (error) {
668
+ console.error(error.error || error.message || error);
669
+ }
670
+ });
671
+ program
672
+ .command('get-group <did>')
673
+ .description('Get group by DID')
674
+ .action(async (did) => {
675
+ try {
676
+ const group = await keymaster.getGroup(did);
677
+ console.log(JSON.stringify(group, null, 4));
678
+ }
679
+ catch (error) {
680
+ console.error(error.error || error.message || error);
681
+ }
682
+ });
683
+ program
684
+ .command('add-group-member <group> <member>')
685
+ .description('Add a member to a group')
686
+ .action(async (group, member) => {
687
+ try {
688
+ const response = await keymaster.addGroupMember(group, member);
689
+ console.log(response);
690
+ }
691
+ catch (error) {
692
+ console.error(error.error || error.message || error);
693
+ }
694
+ });
695
+ program
696
+ .command('remove-group-member <group> <member>')
697
+ .description('Remove a member from a group')
698
+ .action(async (group, member) => {
699
+ try {
700
+ const response = await keymaster.removeGroupMember(group, member);
701
+ console.log(response);
702
+ }
703
+ catch (error) {
704
+ console.error(error.error || error.message || error);
705
+ }
706
+ });
707
+ program
708
+ .command('test-group <group> [member]')
709
+ .description('Determine if a member is in a group')
710
+ .action(async (group, member) => {
711
+ try {
712
+ const response = await keymaster.testGroup(group, member);
713
+ console.log(response);
714
+ }
715
+ catch (error) {
716
+ console.error(error.error || error.message || error);
717
+ }
718
+ });
719
+ // Schema commands
720
+ program
721
+ .command('create-schema <file>')
722
+ .description('Create a schema from a file')
723
+ .option('-n, --name <name>', 'DID name')
724
+ .option('-r, --registry <registry>', 'registry to use')
725
+ .action(async (file, options) => {
726
+ try {
727
+ const { name, registry } = options;
728
+ const schema = JSON.parse(fs.readFileSync(file).toString());
729
+ const did = await keymaster.createSchema(schema, { name, registry });
730
+ console.log(did);
731
+ }
732
+ catch (error) {
733
+ console.error(error.error || error.message || error);
734
+ }
735
+ });
736
+ program
737
+ .command('list-schemas')
738
+ .description('List schemas owned by current ID')
739
+ .action(async () => {
740
+ try {
741
+ const schemas = await keymaster.listSchemas();
742
+ console.log(JSON.stringify(schemas, null, 4));
743
+ }
744
+ catch (error) {
745
+ console.error(error.error || error.message || error);
746
+ }
747
+ });
748
+ program
749
+ .command('get-schema <did>')
750
+ .description('Get schema by DID')
751
+ .action(async (did) => {
752
+ try {
753
+ const schema = await keymaster.getSchema(did);
754
+ console.log(JSON.stringify(schema, null, 4));
755
+ }
756
+ catch (error) {
757
+ console.error(error.error || error.message || error);
758
+ }
759
+ });
760
+ program
761
+ .command('create-schema-template <schema>')
762
+ .description('Create a template from a schema')
763
+ .action(async (schema) => {
764
+ try {
765
+ const template = await keymaster.createTemplate(schema);
766
+ console.log(JSON.stringify(template, null, 4));
767
+ }
768
+ catch (error) {
769
+ console.error(error.error || error.message || error);
770
+ }
771
+ });
772
+ // Asset commands
773
+ program
774
+ .command('create-asset')
775
+ .description('Create an empty asset')
776
+ .option('-n, --name <name>', 'DID name')
777
+ .option('-r, --registry <registry>', 'registry to use')
778
+ .action(async (options) => {
779
+ try {
780
+ const { name, registry } = options;
781
+ const did = await keymaster.createAsset({}, { name, registry });
782
+ console.log(did);
783
+ }
784
+ catch (error) {
785
+ console.error(error.error || error.message || error);
786
+ }
787
+ });
788
+ program
789
+ .command('create-asset-json <file>')
790
+ .description('Create an asset from a JSON file')
791
+ .option('-n, --name <name>', 'DID name')
792
+ .option('-r, --registry <registry>', 'registry to use')
793
+ .action(async (file, options) => {
794
+ try {
795
+ const { name, registry } = options;
796
+ const data = JSON.parse(fs.readFileSync(file).toString());
797
+ const did = await keymaster.createAsset(data, { name, registry });
798
+ console.log(did);
799
+ }
800
+ catch (error) {
801
+ console.error(error.error || error.message || error);
802
+ }
803
+ });
804
+ program
805
+ .command('create-asset-image <file>')
806
+ .description('Create an asset from an image file')
807
+ .option('-n, --name <name>', 'DID name')
808
+ .option('-r, --registry <registry>', 'registry to use')
809
+ .action(async (file, options) => {
810
+ try {
811
+ const { name, registry } = options;
812
+ const data = fs.readFileSync(file);
813
+ const did = await keymaster.createImage(data, { name, registry });
814
+ console.log(did);
815
+ }
816
+ catch (error) {
817
+ console.error(error.error || error.message || error);
818
+ }
819
+ });
820
+ program
821
+ .command('create-asset-document <file>')
822
+ .description('Create an asset from a document file')
823
+ .option('-n, --name <name>', 'DID name')
824
+ .option('-r, --registry <registry>', 'registry to use')
825
+ .action(async (file, options) => {
826
+ try {
827
+ const { name, registry } = options;
828
+ const data = fs.readFileSync(file);
829
+ const filename = file.split('/').pop();
830
+ const did = await keymaster.createDocument(data, { filename, name, registry });
831
+ console.log(did);
832
+ }
833
+ catch (error) {
834
+ console.error(error.error || error.message || error);
835
+ }
836
+ });
837
+ program
838
+ .command('get-asset <id>')
839
+ .description('Get asset by name or DID')
840
+ .action(async (id) => {
841
+ try {
842
+ const asset = await keymaster.resolveAsset(id);
843
+ console.log(JSON.stringify(asset, null, 4));
844
+ }
845
+ catch (error) {
846
+ console.error(error.error || error.message || error);
847
+ }
848
+ });
849
+ program
850
+ .command('update-asset-json <id> <file>')
851
+ .description('Update an asset from a JSON file')
852
+ .action(async (id, file) => {
853
+ try {
854
+ const data = JSON.parse(fs.readFileSync(file).toString());
855
+ const ok = await keymaster.updateAsset(id, data);
856
+ console.log(ok ? UPDATE_OK : UPDATE_FAILED);
857
+ }
858
+ catch (error) {
859
+ console.error(error.error || error.message || error);
860
+ }
861
+ });
862
+ program
863
+ .command('update-asset-image <id> <file>')
864
+ .description('Update an asset from an image file')
865
+ .action(async (id, file) => {
866
+ try {
867
+ const data = fs.readFileSync(file);
868
+ const ok = await keymaster.updateImage(id, data);
869
+ console.log(ok ? UPDATE_OK : UPDATE_FAILED);
870
+ }
871
+ catch (error) {
872
+ console.error(error.error || error.message || error);
873
+ }
874
+ });
875
+ program
876
+ .command('update-asset-document <id> <file>')
877
+ .description('Update an asset from a document file')
878
+ .action(async (id, file) => {
879
+ try {
880
+ const data = fs.readFileSync(file);
881
+ const filename = file.split('/').pop();
882
+ const ok = await keymaster.updateDocument(id, data, { filename });
883
+ console.log(ok ? UPDATE_OK : UPDATE_FAILED);
884
+ }
885
+ catch (error) {
886
+ console.error(error.error || error.message || error);
887
+ }
888
+ });
889
+ program
890
+ .command('transfer-asset <id> <controller>')
891
+ .description('Transfer asset to a new controller')
892
+ .action(async (id, controller) => {
893
+ try {
894
+ const ok = await keymaster.transferAsset(id, controller);
895
+ console.log(ok ? UPDATE_OK : UPDATE_FAILED);
896
+ }
897
+ catch (error) {
898
+ console.error(error.error || error.message || error);
899
+ }
900
+ });
901
+ program
902
+ .command('clone-asset <id>')
903
+ .description('Clone an asset')
904
+ .option('-n, --name <name>', 'DID name')
905
+ .option('-r, --registry <registry>', 'registry to use')
906
+ .action(async (id, options) => {
907
+ try {
908
+ const { name, registry } = options;
909
+ const did = await keymaster.cloneAsset(id, { name, registry });
910
+ console.log(did);
911
+ }
912
+ catch (error) {
913
+ console.error(error.error || error.message || error);
914
+ }
915
+ });
916
+ program
917
+ .command('set-property <id> <key> [value]')
918
+ .description('Assign a key-value pair to an asset')
919
+ .action(async (id, key, value) => {
920
+ try {
921
+ const data = await keymaster.resolveAsset(id);
922
+ if (value) {
923
+ try {
924
+ data[key] = JSON.parse(value);
925
+ }
926
+ catch {
927
+ data[key] = value;
928
+ }
929
+ }
930
+ else {
931
+ delete data[key];
932
+ }
933
+ const ok = await keymaster.updateAsset(id, data);
934
+ console.log(ok ? UPDATE_OK : UPDATE_FAILED);
935
+ }
936
+ catch (error) {
937
+ console.error(error.error || error.message || error);
938
+ }
939
+ });
940
+ program
941
+ .command('list-assets')
942
+ .description('List assets owned by current ID')
943
+ .action(async () => {
944
+ try {
945
+ const assets = await keymaster.listAssets();
946
+ console.log(JSON.stringify(assets, null, 4));
947
+ }
948
+ catch (error) {
949
+ console.error(error.error || error.message || error);
950
+ }
951
+ });
952
+ // Poll commands
953
+ program
954
+ .command('create-poll-template')
955
+ .description('Create a poll template')
956
+ .action(async () => {
957
+ try {
958
+ const template = await keymaster.pollTemplate();
959
+ console.log(JSON.stringify(template, null, 4));
960
+ }
961
+ catch (error) {
962
+ console.error(error.error || error.message || error);
963
+ }
964
+ });
965
+ program
966
+ .command('create-poll <file>')
967
+ .description('Create a poll')
968
+ .option('-n, --name <name>', 'DID name')
969
+ .option('-r, --registry <registry>', 'registry to use')
970
+ .action(async (file, options) => {
971
+ try {
972
+ const { name, registry } = options;
973
+ const poll = JSON.parse(fs.readFileSync(file).toString());
974
+ const did = await keymaster.createPoll(poll, { name, registry });
975
+ console.log(did);
976
+ }
977
+ catch (error) {
978
+ console.error(error.error || error.message || error);
979
+ }
980
+ });
981
+ program
982
+ .command('view-poll <poll>')
983
+ .description('View poll details')
984
+ .action(async (poll) => {
985
+ try {
986
+ const response = await keymaster.viewPoll(poll);
987
+ console.log(JSON.stringify(response, null, 4));
988
+ }
989
+ catch (error) {
990
+ console.error(error.error || error.message || error);
991
+ }
992
+ });
993
+ program
994
+ .command('vote-poll <poll> <vote> [spoil]')
995
+ .description('Vote in a poll')
996
+ .action(async (poll, vote, spoil) => {
997
+ try {
998
+ const did = await keymaster.votePoll(poll, vote, spoil);
999
+ console.log(did);
1000
+ }
1001
+ catch (error) {
1002
+ console.error(error.error || error.message || error);
1003
+ }
1004
+ });
1005
+ program
1006
+ .command('update-poll <ballot>')
1007
+ .description('Add a ballot to the poll')
1008
+ .action(async (ballot) => {
1009
+ try {
1010
+ const ok = await keymaster.updatePoll(ballot);
1011
+ console.log(ok ? UPDATE_OK : UPDATE_FAILED);
1012
+ }
1013
+ catch (error) {
1014
+ console.error(error.error || error.message || error);
1015
+ }
1016
+ });
1017
+ program
1018
+ .command('publish-poll <poll>')
1019
+ .description('Publish results to poll, hiding ballots')
1020
+ .action(async (poll) => {
1021
+ try {
1022
+ const ok = await keymaster.publishPoll(poll);
1023
+ console.log(ok ? UPDATE_OK : UPDATE_FAILED);
1024
+ }
1025
+ catch (error) {
1026
+ console.error(error.error || error.message || error);
1027
+ }
1028
+ });
1029
+ program
1030
+ .command('reveal-poll <poll>')
1031
+ .description('Publish results to poll, revealing ballots')
1032
+ .action(async (poll) => {
1033
+ try {
1034
+ const ok = await keymaster.publishPoll(poll, { reveal: true });
1035
+ console.log(ok ? UPDATE_OK : UPDATE_FAILED);
1036
+ }
1037
+ catch (error) {
1038
+ console.error(error.error || error.message || error);
1039
+ }
1040
+ });
1041
+ program
1042
+ .command('unpublish-poll <poll>')
1043
+ .description('Remove results from poll')
1044
+ .action(async (poll) => {
1045
+ try {
1046
+ const ok = await keymaster.unpublishPoll(poll);
1047
+ console.log(ok ? UPDATE_OK : UPDATE_FAILED);
1048
+ }
1049
+ catch (error) {
1050
+ console.error(error.error || error.message || error);
1051
+ }
1052
+ });
1053
+ // Vault commands
1054
+ program
1055
+ .command('create-vault')
1056
+ .description('Create a vault')
1057
+ .option('-n, --name <name>', 'DID name')
1058
+ .option('-r, --registry <registry>', 'registry to use')
1059
+ .option('-s, --secretMembers', 'keep member list secret from each other')
1060
+ .action(async (options) => {
1061
+ try {
1062
+ const did = await keymaster.createVault(options);
1063
+ console.log(did);
1064
+ }
1065
+ catch (error) {
1066
+ console.error(error.error || error.message || error);
1067
+ }
1068
+ });
1069
+ program
1070
+ .command('list-vault-items <id>')
1071
+ .description('List items in the vault')
1072
+ .action(async (id) => {
1073
+ try {
1074
+ const items = await keymaster.listVaultItems(id);
1075
+ console.log(JSON.stringify(items, null, 4));
1076
+ }
1077
+ catch (error) {
1078
+ console.error(error.error || error.message || error);
1079
+ }
1080
+ });
1081
+ program
1082
+ .command('add-vault-member <id> <member>')
1083
+ .description('Add a member to a vault')
1084
+ .action(async (id, member) => {
1085
+ try {
1086
+ const ok = await keymaster.addVaultMember(id, member);
1087
+ console.log(ok ? UPDATE_OK : UPDATE_FAILED);
1088
+ }
1089
+ catch (error) {
1090
+ console.error(error.error || error.message || error);
1091
+ }
1092
+ });
1093
+ program
1094
+ .command('remove-vault-member <id> <member>')
1095
+ .description('Remove a member from a vault')
1096
+ .action(async (id, member) => {
1097
+ try {
1098
+ const ok = await keymaster.removeVaultMember(id, member);
1099
+ console.log(ok ? UPDATE_OK : UPDATE_FAILED);
1100
+ }
1101
+ catch (error) {
1102
+ console.error(error.error || error.message || error);
1103
+ }
1104
+ });
1105
+ program
1106
+ .command('list-vault-members <id>')
1107
+ .description('List members of a vault')
1108
+ .action(async (id) => {
1109
+ try {
1110
+ const members = await keymaster.listVaultMembers(id);
1111
+ console.log(JSON.stringify(members, null, 4));
1112
+ }
1113
+ catch (error) {
1114
+ console.error(error.error || error.message || error);
1115
+ }
1116
+ });
1117
+ program
1118
+ .command('add-vault-item <id> <file>')
1119
+ .description('Add an item (file) to a vault')
1120
+ .action(async (id, file) => {
1121
+ try {
1122
+ const data = fs.readFileSync(file);
1123
+ const name = file.split('/').pop();
1124
+ const ok = await keymaster.addVaultItem(id, name, data);
1125
+ console.log(ok ? UPDATE_OK : UPDATE_FAILED);
1126
+ }
1127
+ catch (error) {
1128
+ console.error(error.error || error.message || error);
1129
+ }
1130
+ });
1131
+ program
1132
+ .command('remove-vault-item <id> <item>')
1133
+ .description('Remove an item from a vault')
1134
+ .action(async (id, item) => {
1135
+ try {
1136
+ const ok = await keymaster.removeVaultItem(id, item);
1137
+ console.log(ok ? UPDATE_OK : UPDATE_FAILED);
1138
+ }
1139
+ catch (error) {
1140
+ console.error(error.error || error.message || error);
1141
+ }
1142
+ });
1143
+ program
1144
+ .command('get-vault-item <id> <item> <file>')
1145
+ .description('Save an item from a vault to a file')
1146
+ .action(async (id, item, file) => {
1147
+ try {
1148
+ const data = await keymaster.getVaultItem(id, item);
1149
+ if (data) {
1150
+ fs.writeFileSync(file, data);
1151
+ console.log(`Data written to ${file}`);
1152
+ }
1153
+ else {
1154
+ console.error(`Item ${item} not found in vault`);
1155
+ }
1156
+ }
1157
+ catch (error) {
1158
+ console.error(error.error || error.message || error);
1159
+ }
1160
+ });
1161
+ // Initialize and run
1162
+ async function run() {
1163
+ // Handle --help and --version without full initialization
1164
+ if (process.argv.includes('--help') || process.argv.includes('-h') ||
1165
+ process.argv.includes('--version') || process.argv.includes('-V') ||
1166
+ process.argv.length <= 2) {
1167
+ program.parse(process.argv);
1168
+ return;
1169
+ }
1170
+ const gatekeeperURL = process.env.ARCHON_GATEKEEPER_URL || 'http://localhost:4224';
1171
+ const walletPath = process.env.ARCHON_WALLET_PATH || './wallet.json';
1172
+ const walletType = process.env.ARCHON_WALLET_TYPE || 'json';
1173
+ const passphrase = process.env.ARCHON_PASSPHRASE;
1174
+ const defaultRegistry = process.env.ARCHON_DEFAULT_REGISTRY;
1175
+ if (!passphrase) {
1176
+ console.error('Error: ARCHON_PASSPHRASE environment variable is required');
1177
+ console.error('Set it with: export ARCHON_PASSPHRASE=your-passphrase');
1178
+ process.exit(1);
1179
+ }
1180
+ try {
1181
+ // Initialize gatekeeper client
1182
+ const gatekeeper = new GatekeeperClient();
1183
+ await gatekeeper.connect({
1184
+ url: gatekeeperURL,
1185
+ waitUntilReady: true,
1186
+ intervalSeconds: 3,
1187
+ chatty: false,
1188
+ becomeChattyAfter: 2
1189
+ });
1190
+ // Initialize wallet
1191
+ let wallet;
1192
+ if (walletType === 'sqlite') {
1193
+ wallet = await WalletSQLite.create(walletPath);
1194
+ }
1195
+ else {
1196
+ // WalletJson expects (filename, folder) - parse the path
1197
+ const walletDir = path.dirname(walletPath);
1198
+ const walletFile = path.basename(walletPath);
1199
+ wallet = new WalletJson(walletFile, walletDir);
1200
+ }
1201
+ // Initialize cipher
1202
+ const cipher = new CipherNode();
1203
+ // Initialize keymaster
1204
+ keymaster = new Keymaster({ gatekeeper, wallet, cipher, defaultRegistry, passphrase });
1205
+ program.parse(process.argv);
1206
+ }
1207
+ catch (error) {
1208
+ console.error('Failed to initialize:', error.message || error);
1209
+ process.exit(1);
1210
+ }
1211
+ }
1212
+ run();
1213
+ //# sourceMappingURL=cli.js.map