bsv-bap 0.0.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.
Files changed (62) hide show
  1. package/.babelrc +20 -0
  2. package/.eslintrc +46 -0
  3. package/LICENSE +25 -0
  4. package/README.md +819 -0
  5. package/babel.config.js +6 -0
  6. package/bun.lockb +0 -0
  7. package/coverage/clover.xml +6 -0
  8. package/coverage/coverage-final.json +1 -0
  9. package/coverage/lcov-report/base.css +224 -0
  10. package/coverage/lcov-report/block-navigation.js +87 -0
  11. package/coverage/lcov-report/favicon.png +0 -0
  12. package/coverage/lcov-report/index.html +101 -0
  13. package/coverage/lcov-report/prettify.css +1 -0
  14. package/coverage/lcov-report/prettify.js +2 -0
  15. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  16. package/coverage/lcov-report/sorter.js +196 -0
  17. package/coverage/lcov-report/src/constants.ts.html +113 -0
  18. package/coverage/lcov-report/src/id.ts.html +2207 -0
  19. package/coverage/lcov-report/src/index.html +156 -0
  20. package/coverage/lcov-report/src/index.ts.html +1877 -0
  21. package/coverage/lcov-report/src/utils.ts.html +404 -0
  22. package/coverage/lcov-report/tests/data/index.html +111 -0
  23. package/coverage/lcov-report/tests/data/keys.js.html +86 -0
  24. package/coverage/lcov.info +0 -0
  25. package/dist/jest.config.d.ts +8 -0
  26. package/dist/src/constants.d.ts +8 -0
  27. package/dist/src/id.d.ts +295 -0
  28. package/dist/src/index.d.ts +238 -0
  29. package/dist/src/interface.d.ts +23 -0
  30. package/dist/src/poa.d.ts +6 -0
  31. package/dist/src/utils.d.ts +54 -0
  32. package/dist/typescript-npm-package.cjs.d.ts +554 -0
  33. package/dist/typescript-npm-package.cjs.js +1320 -0
  34. package/dist/typescript-npm-package.cjs.js.map +1 -0
  35. package/dist/typescript-npm-package.esm.d.ts +554 -0
  36. package/dist/typescript-npm-package.esm.js +1312 -0
  37. package/dist/typescript-npm-package.esm.js.map +1 -0
  38. package/dist/typescript-npm-package.umd.d.ts +554 -0
  39. package/dist/typescript-npm-package.umd.js +110193 -0
  40. package/dist/typescript-npm-package.umd.js.map +1 -0
  41. package/jest.config.ts +196 -0
  42. package/jsdoc.json +16 -0
  43. package/package.json +80 -0
  44. package/rollup.config.js +64 -0
  45. package/setup-jest.js +1 -0
  46. package/src/README.md +80 -0
  47. package/src/attributes.json +119 -0
  48. package/src/constants.ts +11 -0
  49. package/src/id.ts +783 -0
  50. package/src/index.ts +631 -0
  51. package/src/interface.ts +26 -0
  52. package/src/poa.ts +9 -0
  53. package/src/utils.ts +111 -0
  54. package/tests/data/ids.json +30 -0
  55. package/tests/data/keys.js +2 -0
  56. package/tests/data/old-ids.json +25 -0
  57. package/tests/data/test-vectors.json +122 -0
  58. package/tests/id.test.js +286 -0
  59. package/tests/index.test.js +335 -0
  60. package/tests/regression.test.js +28 -0
  61. package/tests/utils.test.js +27 -0
  62. package/tsconfig.json +17 -0
package/src/index.ts ADDED
@@ -0,0 +1,631 @@
1
+ import { BigNumber, BSM, HD, type PublicKey, Signature, ECIES } from "@bsv/sdk";
2
+ import "node-fetch";
3
+
4
+ import { Utils } from "./utils";
5
+ import { BAP_ID } from "./id";
6
+ import {
7
+ ENCRYPTION_PATH,
8
+ BAP_SERVER,
9
+ BAP_BITCOM_ADDRESS,
10
+ BAP_BITCOM_ADDRESS_HEX,
11
+ AIP_BITCOM_ADDRESS,
12
+ } from "./constants";
13
+ import type { Attestation, Identity, PathPrefix } from "./interface";
14
+ import { Utils as BSVUtils } from "@bsv/sdk";
15
+ const { toArray, toUTF8, toBase64 } = BSVUtils;
16
+ const { bitcoreDecrypt, bitcoreEncrypt } = ECIES;
17
+
18
+ /**
19
+ * BAP class
20
+ *
21
+ * Creates an instance of the BAP class and uses the given HDPrivateKey for all BAP operations.
22
+ *
23
+ * @param HDPrivateKey
24
+ */
25
+ export const BAP = class {
26
+ #HDPrivateKey;
27
+ #ids: { [key: string]: BAP_ID } = {};
28
+ #BAP_SERVER = BAP_SERVER;
29
+ #BAP_TOKEN = "";
30
+ #lastIdPath = "";
31
+
32
+ constructor(HDPrivateKey: string, token = "") {
33
+ if (!HDPrivateKey) {
34
+ throw new Error("No HDPrivateKey given");
35
+ }
36
+ this.#HDPrivateKey = HD.fromString(HDPrivateKey);
37
+
38
+ if (token) {
39
+ this.#BAP_TOKEN = token;
40
+ }
41
+ }
42
+
43
+ get lastIdPath(): string {
44
+ return this.#lastIdPath;
45
+ }
46
+
47
+ /**
48
+ * Get the public key of the given childPath, or of the current HDPrivateKey of childPath is empty
49
+ *
50
+ * @param childPath Full derivation path for this child
51
+ * @returns {*}
52
+ */
53
+ getPublicKey(childPath = ""): string {
54
+ if (childPath) {
55
+ return this.#HDPrivateKey.derive(childPath).pubKey.toString();
56
+ }
57
+
58
+ return this.#HDPrivateKey.pubKey.toString();
59
+ }
60
+
61
+ /**
62
+ * Get the public key of the given childPath, or of the current HDPrivateKey of childPath is empty
63
+ *
64
+ * @param childPath Full derivation path for this child
65
+ * @returns {*}
66
+ */
67
+ getHdPublicKey(childPath = ""): string {
68
+ if (childPath) {
69
+ return this.#HDPrivateKey.derive(childPath).toPublic().toString();
70
+ }
71
+
72
+ return this.#HDPrivateKey.toPublic().toString();
73
+ }
74
+
75
+ set BAP_SERVER(bapServer) {
76
+ this.#BAP_SERVER = bapServer;
77
+ Object.keys(this.#ids).forEach((key) => {
78
+ // @ts-ignore - does not recognize private fields that can be set
79
+ this.#ids[key].BAP_SERVER = bapServer;
80
+ });
81
+ }
82
+
83
+ get BAP_SERVER(): string {
84
+ return this.#BAP_SERVER;
85
+ }
86
+
87
+ set BAP_TOKEN(token) {
88
+ this.#BAP_TOKEN = token;
89
+ Object.keys(this.#ids).forEach((key) => {
90
+ // @ts-ignore - does not recognize private fields that can be set
91
+ this.#ids[key].BAP_TOKEN = token;
92
+ });
93
+ }
94
+
95
+ get BAP_TOKEN(): string {
96
+ return this.#BAP_TOKEN;
97
+ }
98
+
99
+ /**
100
+ * This function verifies that the given bapId matches the given root address
101
+ * This is used as a data integrity check
102
+ *
103
+ * @param bapId BAP_ID instance
104
+ */
105
+ checkIdBelongs(bapId: BAP_ID): boolean {
106
+ const derivedChild = this.#HDPrivateKey.derive(bapId.rootPath);
107
+ const checkRootAddress = derivedChild.pubKey.toAddress();
108
+ if (checkRootAddress !== bapId.rootAddress) {
109
+ throw new Error("ID does not belong to this private key");
110
+ }
111
+
112
+ return true;
113
+ }
114
+
115
+ /**
116
+ * Returns a list of all the identity keys that are stored in this instance
117
+ *
118
+ * @returns {string[]}
119
+ */
120
+ listIds(): string[] {
121
+ return Object.keys(this.#ids);
122
+ }
123
+
124
+ /**
125
+ * Create a new Id and link it to this BAP instance
126
+ *
127
+ * This function uses the length of the #ids of this class to determine the next valid path.
128
+ * If not all ids related to this HDPrivateKey have been loaded, determine the path externally
129
+ * and pass it to newId when creating a new ID.
130
+ *
131
+ * @param path
132
+ * @param identityAttributes
133
+ * @param idSeed
134
+ * @returns {*}
135
+ */
136
+ newId(path = "", identityAttributes: any = {}, idSeed = ""): BAP_ID {
137
+ if (!path) {
138
+ // get next usable path for this key
139
+ path = this.getNextValidPath();
140
+ }
141
+
142
+ const newIdentity = new BAP_ID(
143
+ this.#HDPrivateKey,
144
+ identityAttributes,
145
+ idSeed,
146
+ );
147
+ newIdentity.BAP_SERVER = this.#BAP_SERVER;
148
+ newIdentity.BAP_TOKEN = this.#BAP_TOKEN;
149
+
150
+ newIdentity.rootPath = path;
151
+ newIdentity.currentPath = Utils.getNextPath(path);
152
+
153
+ const idKey = newIdentity.getIdentityKey();
154
+ this.#ids[idKey] = newIdentity;
155
+ this.#lastIdPath = path;
156
+
157
+ return this.#ids[idKey];
158
+ }
159
+
160
+ /**
161
+ * Remove identity
162
+ *
163
+ * @param idKey
164
+ * @returns {*}
165
+ */
166
+ removeId(idKey: string): void {
167
+ delete this.#ids[idKey];
168
+ }
169
+
170
+ /**
171
+ * Get the next valid path for the used HDPrivateKey and loaded #ids
172
+ *
173
+ * @returns {string}
174
+ */
175
+ getNextValidPath(): PathPrefix {
176
+ // prefer hardened paths
177
+ if (this.#lastIdPath) {
178
+ return Utils.getNextIdentityPath(this.#lastIdPath);
179
+ }
180
+
181
+ return `/0'/${Object.keys(this.#ids).length}'/0'`;
182
+ }
183
+
184
+ /**
185
+ * Get a certain Id
186
+ *
187
+ * @param identityKey
188
+ * @returns {null}
189
+ */
190
+ getId(identityKey: string): BAP_ID | null {
191
+ return this.#ids[identityKey] || null;
192
+ }
193
+
194
+ /**
195
+ * This function is used when manipulating ID's, adding or removing attributes etc
196
+ * First create an id through this class and then use getId to get it. Then you can add/edit or
197
+ * increment the signing path and then re-set it with this function.
198
+ *
199
+ * Note: when you getId() from this class, you will be working on the same object as this class
200
+ * has and any changes made will be propagated to the id in this class. When you call exportIds
201
+ * your new changes will also be included, without having to setId().
202
+ *
203
+ * @param bapId
204
+ */
205
+ setId(bapId: BAP_ID): void {
206
+ this.checkIdBelongs(bapId);
207
+ this.#ids[bapId.getIdentityKey()] = bapId;
208
+ }
209
+
210
+ /**
211
+ * This function is used to import IDs and attributes from some external storage
212
+ *
213
+ * The ID information should NOT be stored together with the HD private key !
214
+ *
215
+ * @param idData Array of ids that have been exported
216
+ * @param encrypted Whether the data should be treated as being encrypted (default true)
217
+ */
218
+ importIds(idData: any, encrypted = true): void {
219
+ if (encrypted) {
220
+ // we first need to decrypt the ids array using ECIES
221
+
222
+ const derivedChild = this.#HDPrivateKey.derive(ENCRYPTION_PATH);
223
+ const decrypted = toUTF8(bitcoreDecrypt(
224
+ toArray(
225
+ Buffer.from(idData, Utils.isHex(idData) ? "hex" : "base64").toString(
226
+ "hex",
227
+ ),
228
+ "hex",
229
+ ),
230
+ derivedChild.privKey,
231
+ ));
232
+ idData = JSON.parse(decrypted) as Identity[];
233
+ }
234
+
235
+ let oldFormatImport = false;
236
+ if (!idData.ids) {
237
+ // old format id container
238
+ oldFormatImport = true;
239
+ idData = {
240
+ lastIdPath: "",
241
+ ids: idData,
242
+ };
243
+ }
244
+
245
+ for (const id of idData.ids as Identity[]) {
246
+ if (!id.identityKey || !id.identityAttributes || !id.rootAddress) {
247
+ throw new Error("ID cannot be imported as it is not complete");
248
+ }
249
+ const importId = new BAP_ID(this.#HDPrivateKey, {}, id.idSeed);
250
+ importId.BAP_SERVER = this.#BAP_SERVER;
251
+ importId.BAP_TOKEN = this.#BAP_TOKEN;
252
+ importId.import(id);
253
+
254
+ this.checkIdBelongs(importId);
255
+
256
+ this.#ids[importId.getIdentityKey()] = importId;
257
+
258
+ if (oldFormatImport) {
259
+ // overwrite with the last value on this array
260
+ idData.lastIdPath = importId.currentPath;
261
+ }
262
+ }
263
+
264
+ this.#lastIdPath = idData.lastIdPath;
265
+ }
266
+
267
+ /**
268
+ * Export all the IDs of this instance for external storage
269
+ *
270
+ * By default this function will encrypt the data, using a derivative child of the main HD key
271
+ *
272
+ * @param encrypted Whether the data should be encrypted (default true)
273
+ * @returns {[]|*}
274
+ */
275
+ exportIds(encrypted = true): any {
276
+ const idData = {
277
+ lastIdPath: this.#lastIdPath,
278
+ ids: [] as Identity[],
279
+ };
280
+
281
+ for (const key of Object.keys(this.#ids)) {
282
+ idData.ids.push(this.#ids[key].export());
283
+ }
284
+
285
+ if (encrypted) {
286
+ const derivedChild = this.#HDPrivateKey.derive(ENCRYPTION_PATH);
287
+ return toBase64(bitcoreEncrypt(toArray(JSON.stringify(idData), 'utf8'), derivedChild.pubKey))
288
+ }
289
+
290
+ return idData;
291
+ }
292
+
293
+ /**
294
+ * Encrypt a string of data
295
+ *
296
+ * @param string
297
+ * @returns {string}
298
+ */
299
+ encrypt(string: string): string {
300
+
301
+ const derivedChild = this.#HDPrivateKey.derive(ENCRYPTION_PATH);
302
+ return toBase64(bitcoreEncrypt(toArray(string, 'utf8'), derivedChild.pubKey))
303
+ }
304
+
305
+ /**
306
+ * Decrypt a string of data
307
+ *
308
+ * @param string
309
+ * @returns {string}
310
+ */
311
+ decrypt(string: string): string {
312
+ const derivedChild = this.#HDPrivateKey.derive(ENCRYPTION_PATH);
313
+ return toUTF8(bitcoreDecrypt(toArray(string, 'base64'), derivedChild.privKey));
314
+ }
315
+
316
+ /**
317
+ * Sign an attestation for a user
318
+ *
319
+ * @param attestationHash The computed attestation hash for the user - this should be calculated with the BAP_ID class for an identity for the user
320
+ * @param identityKey The identity key we are using for the signing
321
+ * @param counter
322
+ * @param dataString Optional data string that will be appended to the BAP attestation
323
+ * @returns {string[]}
324
+ */
325
+ signAttestationWithAIP(
326
+ attestationHash: string,
327
+ identityKey: string,
328
+ counter = 0,
329
+ dataString = "",
330
+ ) {
331
+ const id = this.getId(identityKey);
332
+ if (!id) {
333
+ throw new Error("Could not find identity to attest with");
334
+ }
335
+
336
+ const attestationBuffer = this.getAttestationBuffer(
337
+ attestationHash,
338
+ counter,
339
+ dataString,
340
+ );
341
+ const { address, signature } = id.signMessage(attestationBuffer);
342
+
343
+ return this.createAttestationTransaction(
344
+ attestationHash,
345
+ counter,
346
+ address,
347
+ signature,
348
+ dataString,
349
+ );
350
+ }
351
+
352
+ /**
353
+ * Verify an AIP signed attestation for a user
354
+ *
355
+ * [
356
+ * '0x6a',
357
+ * '0x31424150537561506e66476e53424d33474c56397968785564596534764762644d54',
358
+ * '0x415454455354',
359
+ * '0x33656166366361396334313936356538353831366439336439643034333136393032376633396661623034386333633031333663343364663635376462383761',
360
+ * '0x30',
361
+ * '0x7c',
362
+ * '0x313550636948473232534e4c514a584d6f5355615756693757537163376843667661',
363
+ * '0x424954434f494e5f4543445341',
364
+ * '0x31477531796d52567a595557634638776f6f506a7a4a4c764d383550795a64655876',
365
+ * '0x20ef60c5555001ddb1039bb0f215e46571fcb39ee46f48b089d1c08b0304dbcb3366d8fdf8bafd82be24b5ac42dcd6a5e96c90705dd42e3ad918b1b47ac3ce6ac2'
366
+ * ]
367
+ *
368
+ * @param tx Array of hex values for the OP_RETURN values
369
+ * @returns {{}}
370
+ */
371
+ verifyAttestationWithAIP(tx: string[]): Attestation {
372
+ if (
373
+ !Array.isArray(tx) ||
374
+ tx[0] !== "0x6a" ||
375
+ tx[1] !== BAP_BITCOM_ADDRESS_HEX
376
+ ) {
377
+ throw new Error("Not a valid BAP transaction");
378
+ }
379
+
380
+ const dataOffset = tx[7] === "0x44415441" ? 5 : 0; // DATA
381
+ const attestation: Attestation = {
382
+ type: Utils.hexDecode(tx[2]),
383
+ hash: Utils.hexDecode(tx[3]),
384
+ sequence: Utils.hexDecode(tx[4]),
385
+ signingProtocol: Utils.hexDecode(tx[7 + dataOffset]),
386
+ signingAddress: Utils.hexDecode(tx[8 + dataOffset]),
387
+ signature: Utils.hexDecode(tx[9 + dataOffset], "base64"),
388
+ };
389
+
390
+ if (dataOffset && tx[3] === tx[8]) {
391
+ // valid data addition
392
+ attestation.data = Utils.hexDecode(tx[9]);
393
+ }
394
+
395
+ try {
396
+ const signatureBufferStatements = [];
397
+ for (let i = 0; i < 6 + dataOffset; i++) {
398
+ signatureBufferStatements.push(
399
+ Buffer.from(tx[i].replace("0x", ""), "hex"),
400
+ );
401
+ }
402
+ const attestationBuffer = Buffer.concat([...signatureBufferStatements]);
403
+ attestation.verified = this.verifySignature(
404
+ attestationBuffer,
405
+ attestation.signingAddress,
406
+ attestation.signature,
407
+ );
408
+ } catch (e) {
409
+ attestation.verified = false;
410
+ }
411
+
412
+ return attestation;
413
+ }
414
+
415
+ /**
416
+ * For BAP attestations we use all fields for the attestation
417
+ *
418
+ * @param attestationHash
419
+ * @param counter
420
+ * @param address
421
+ * @param signature
422
+ * @param dataString Optional data string that will be appended to the BAP attestation
423
+ * @returns {[string]}
424
+ */
425
+ createAttestationTransaction(
426
+ attestationHash: string,
427
+ counter: number,
428
+ address: string,
429
+ signature: string,
430
+ dataString = "",
431
+ ): string[] {
432
+ const transaction = ["0x6a", Utils.hexEncode(BAP_BITCOM_ADDRESS)];
433
+ transaction.push(Utils.hexEncode("ATTEST"));
434
+ transaction.push(Utils.hexEncode(attestationHash));
435
+ transaction.push(Utils.hexEncode(`${counter}`));
436
+ transaction.push("0x7c"); // |
437
+ if (dataString) {
438
+ // data should be a string, either encrypted or stringified JSON if applicable
439
+ transaction.push(Utils.hexEncode(BAP_BITCOM_ADDRESS));
440
+ transaction.push(Utils.hexEncode("DATA"));
441
+ transaction.push(Utils.hexEncode(attestationHash));
442
+ transaction.push(Utils.hexEncode(dataString));
443
+ transaction.push("0x7c"); // |
444
+ }
445
+ transaction.push(Utils.hexEncode(AIP_BITCOM_ADDRESS));
446
+ transaction.push(Utils.hexEncode("BITCOIN_ECDSA"));
447
+ transaction.push(Utils.hexEncode(address));
448
+ transaction.push(`0x${Buffer.from(signature, "base64").toString("hex")}`);
449
+
450
+ return transaction;
451
+ }
452
+
453
+ /**
454
+ * This is a re-creation of how the bitcoinfiles-sdk creates a hash to sign for AIP
455
+ *
456
+ * @param attestationHash
457
+ * @param counter
458
+ * @param dataString Optional data string
459
+ * @returns {Buffer}
460
+ */
461
+ getAttestationBuffer(
462
+ attestationHash: string,
463
+ counter = 0,
464
+ dataString = "",
465
+ ): Buffer {
466
+ // re-create how AIP creates the buffer to sign
467
+ let dataStringBuffer = Buffer.from("");
468
+ if (dataString) {
469
+ dataStringBuffer = Buffer.concat([
470
+ Buffer.from(BAP_BITCOM_ADDRESS),
471
+ Buffer.from("DATA"),
472
+ Buffer.from(attestationHash),
473
+ Buffer.from(dataString),
474
+ Buffer.from("7c", "hex"),
475
+ ]);
476
+ }
477
+ return Buffer.concat([
478
+ Buffer.from("6a", "hex"), // OP_RETURN
479
+ Buffer.from(BAP_BITCOM_ADDRESS),
480
+ Buffer.from("ATTEST"),
481
+ Buffer.from(attestationHash),
482
+ Buffer.from(`${counter}`),
483
+ Buffer.from("7c", "hex"),
484
+ dataStringBuffer,
485
+ ]);
486
+ }
487
+
488
+ /**
489
+ * Verify that the identity challenge is signed by the address
490
+ *
491
+ * @param message Buffer or utf-8 string
492
+ * @param address Bitcoin address of signee
493
+ * @param signature Signature base64 string
494
+ *
495
+ * @return boolean
496
+ */
497
+ verifySignature(
498
+ message: string | Buffer,
499
+ address: string,
500
+ signature: string,
501
+ ): boolean {
502
+ // check the signature against the challenge
503
+ const messageBuffer = Buffer.isBuffer(message)
504
+ ? message
505
+ : Buffer.from(message);
506
+ const sig = Signature.fromCompact(signature, "base64");
507
+ let publicKey: PublicKey | undefined;
508
+ const msg = toArray(messageBuffer.toString("hex"), "hex");
509
+ for (let recovery = 0; recovery < 4; recovery++) {
510
+ try {
511
+ publicKey = sig.RecoverPublicKey(
512
+ recovery,
513
+ new BigNumber(BSM.magicHash(msg)),
514
+ );
515
+ const sigFitsPubkey = BSM.verify(msg, sig, publicKey);
516
+ if (sigFitsPubkey && publicKey.toAddress() === address) {
517
+ return true;
518
+ }
519
+ } catch (e) {
520
+ // try next recovery
521
+ }
522
+ }
523
+ return false;
524
+ }
525
+
526
+ /**
527
+ * Check whether the given transaction (BAP OP_RETURN) is valid, is signed and that the
528
+ * identity signing is also valid at the time of signing
529
+ *
530
+ * @param idKey
531
+ * @param address
532
+ * @param challenge
533
+ * @param signature
534
+ *
535
+ * @returns {Promise<boolean|*>}
536
+ */
537
+ async verifyChallengeSignature(
538
+ idKey: string,
539
+ address: string,
540
+ challenge: string,
541
+ signature: string,
542
+ ): Promise<boolean> {
543
+ // first we test locally before sending to server
544
+ if (this.verifySignature(challenge, address, signature)) {
545
+ const result = await this.getApiData("/attestation/valid", {
546
+ idKey,
547
+ challenge,
548
+ signature,
549
+ });
550
+ return result.data;
551
+ }
552
+
553
+ return false;
554
+ }
555
+
556
+ /**
557
+ * Check whether the given transaction (BAP OP_RETURN) is valid, is signed and that the
558
+ * identity signing is also valid at the time of signing
559
+ *
560
+ * @param tx
561
+ * @returns {Promise<boolean|*>}
562
+ */
563
+ async isValidAttestationTransaction(tx: string[]): Promise<any> {
564
+ // first we test locally before sending to server
565
+ if (this.verifyAttestationWithAIP(tx)) {
566
+ return this.getApiData("/attestation/valid", {
567
+ tx,
568
+ });
569
+ }
570
+
571
+ return false;
572
+ }
573
+
574
+ /**
575
+ * Get all signing keys for the given idKey
576
+ *
577
+ * @param address
578
+ * @returns {Promise<*>}
579
+ */
580
+ async getIdentityFromAddress(address: string): Promise<any> {
581
+ return this.getApiData("/identity/from-address", {
582
+ address,
583
+ });
584
+ }
585
+
586
+ /**
587
+ * Get all signing keys for the given idKey
588
+ *
589
+ * @param idKey
590
+ * @returns {Promise<*>}
591
+ */
592
+ async getIdentity(idKey: string): Promise<any> {
593
+ return this.getApiData("/identity", {
594
+ idKey,
595
+ });
596
+ }
597
+
598
+ /**
599
+ * Get all attestations for the given attestation hash
600
+ *
601
+ * @param attestationHash
602
+ */
603
+ async getAttestationsForHash(attestationHash: string): Promise<any> {
604
+ // get all BAP ATTEST records for the given attestationHash
605
+ return this.getApiData("/attestations", {
606
+ hash: attestationHash,
607
+ });
608
+ }
609
+
610
+ /**
611
+ * Helper function to get attestation from a BAP API server
612
+ *
613
+ * @param apiUrl
614
+ * @param apiData
615
+ * @returns {Promise<any>}
616
+ */
617
+ async getApiData(apiUrl: string, apiData: any): Promise<any> {
618
+ const url = `${this.#BAP_SERVER}${apiUrl}`;
619
+ const response = await fetch(url, {
620
+ method: "post",
621
+ headers: {
622
+ "Content-type": "application/json; charset=utf-8",
623
+ token: this.#BAP_TOKEN,
624
+ format: "json",
625
+ },
626
+ body: JSON.stringify(apiData),
627
+ });
628
+
629
+ return response.json();
630
+ }
631
+ };
@@ -0,0 +1,26 @@
1
+
2
+ export interface Identity {
3
+ name: string;
4
+ description: string;
5
+ identityKey: string;
6
+ rootPath: string;
7
+ rootAddress: string;
8
+ previousPath: string;
9
+ currentPath: string;
10
+ lastIdPath: string;
11
+ idSeed: string;
12
+ identityAttributes: any;
13
+ }
14
+
15
+ export type PathPrefix = `/${number}/${number}/${number}` | `/${number}'/${number}'/${number}'`
16
+
17
+ export interface Attestation {
18
+ type: string;
19
+ hash: string;
20
+ sequence: string;
21
+ signingProtocol: string;
22
+ signingAddress: string;
23
+ signature: string;
24
+ data?: string;
25
+ verified?: boolean;
26
+ }
package/src/poa.ts ADDED
@@ -0,0 +1,9 @@
1
+ import type { HD } from '@bsv/sdk';
2
+
3
+ export const BAP_POA = class {
4
+ #HDPrivateKey: HD;
5
+
6
+ constructor(HDPrivateKey: HD) {
7
+ this.#HDPrivateKey = HDPrivateKey;
8
+ }
9
+ };