@lightsparkdev/core 0.3.11 → 1.0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @lightsparkdev/core
2
2
 
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 1f00a50: Change SigningKey hashing method depending on environment
8
+ BREAKING: NodeKeyCaches loadKey now requires signingKeyType as a parameter
9
+
3
10
  ## 0.3.11
4
11
 
5
12
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -36,13 +36,20 @@ __export(src_exports, {
36
36
  LightsparkException: () => LightsparkException_default,
37
37
  LightsparkSigningException: () => LightsparkSigningException_default,
38
38
  NodeKeyCache: () => NodeKeyCache_default,
39
+ RSASigningKey: () => RSASigningKey,
39
40
  Requester: () => Requester_default,
41
+ Secp256k1SigningKey: () => Secp256k1SigningKey,
40
42
  ServerEnvironment: () => ServerEnvironment_default,
43
+ SigningKey: () => SigningKey,
44
+ SigningKeyType: () => SigningKeyType,
41
45
  StubAuthProvider: () => StubAuthProvider,
42
46
  apiDomainForEnvironment: () => apiDomainForEnvironment,
43
47
  b64decode: () => b64decode,
44
48
  b64encode: () => b64encode,
49
+ bytesToHex: () => bytesToHex,
45
50
  convertCurrencyAmount: () => convertCurrencyAmount,
51
+ createSha256Hash: () => createSha256Hash,
52
+ hexToBytes: () => hexToBytes,
46
53
  isBrowser: () => isBrowser,
47
54
  isNode: () => isNode,
48
55
  isType: () => isType,
@@ -348,6 +355,50 @@ var KeyOrAlias = {
348
355
 
349
356
  // src/crypto/NodeKeyCache.ts
350
357
  var import_auto_bind = __toESM(require("auto-bind"), 1);
358
+
359
+ // src/crypto/SigningKey.ts
360
+ var import_secp256k1 = __toESM(require("secp256k1"), 1);
361
+ function isAlias(key) {
362
+ return "alias" in key;
363
+ }
364
+ var SigningKey = class {
365
+ type;
366
+ constructor(type) {
367
+ this.type = type;
368
+ }
369
+ };
370
+ var RSASigningKey = class extends SigningKey {
371
+ constructor(privateKey, cryptoImpl) {
372
+ super("RSASigningKey" /* RSASigningKey */);
373
+ this.privateKey = privateKey;
374
+ this.cryptoImpl = cryptoImpl;
375
+ }
376
+ async sign(data) {
377
+ const key = isAlias(this.privateKey) ? this.privateKey.alias : this.privateKey;
378
+ return this.cryptoImpl.sign(key, data);
379
+ }
380
+ };
381
+ var Secp256k1SigningKey = class extends SigningKey {
382
+ constructor(privateKey) {
383
+ super("Secp256k1SigningKey" /* Secp256k1SigningKey */);
384
+ this.privateKey = privateKey;
385
+ }
386
+ async sign(data) {
387
+ const keyBytes = new Uint8Array(hexToBytes(this.privateKey));
388
+ const hash = await createSha256Hash(data);
389
+ const signResult = import_secp256k1.default.ecdsaSign(hash, keyBytes);
390
+ return signResult.signature;
391
+ }
392
+ };
393
+
394
+ // src/crypto/types.ts
395
+ var SigningKeyType = /* @__PURE__ */ ((SigningKeyType2) => {
396
+ SigningKeyType2["RSASigningKey"] = "RSASigningKey";
397
+ SigningKeyType2["Secp256k1SigningKey"] = "Secp256k1SigningKey";
398
+ return SigningKeyType2;
399
+ })(SigningKeyType || {});
400
+
401
+ // src/crypto/NodeKeyCache.ts
351
402
  var NodeKeyCache = class {
352
403
  constructor(cryptoImpl = DefaultCrypto) {
353
404
  this.cryptoImpl = cryptoImpl;
@@ -355,16 +406,35 @@ var NodeKeyCache = class {
355
406
  (0, import_auto_bind.default)(this);
356
407
  }
357
408
  idToKey;
358
- async loadKey(id, keyOrAlias) {
409
+ async loadKey(id, keyOrAlias, signingKeyType) {
410
+ let signingKey;
359
411
  if (keyOrAlias.alias !== void 0) {
360
- this.idToKey.set(id, keyOrAlias.alias);
361
- return keyOrAlias.alias;
412
+ switch (signingKeyType) {
413
+ case "RSASigningKey" /* RSASigningKey */:
414
+ signingKey = new RSASigningKey(
415
+ { alias: keyOrAlias.alias },
416
+ this.cryptoImpl
417
+ );
418
+ break;
419
+ default:
420
+ throw new LightsparkSigningException_default(
421
+ `Aliases are not supported for signing key type ${signingKeyType}`
422
+ );
423
+ }
424
+ this.idToKey.set(id, signingKey);
425
+ return signingKey;
362
426
  }
363
- const decoded = b64decode(this.stripPemTags(keyOrAlias.key));
364
427
  try {
365
- const key = await this.cryptoImpl.importPrivateSigningKey(decoded);
366
- this.idToKey.set(id, key);
367
- return key;
428
+ if (signingKeyType === "Secp256k1SigningKey" /* Secp256k1SigningKey */) {
429
+ signingKey = new Secp256k1SigningKey(keyOrAlias.key);
430
+ } else {
431
+ const decoded = b64decode(this.stripPemTags(keyOrAlias.key));
432
+ const cryptoKeyOrAlias = await this.cryptoImpl.importPrivateSigningKey(decoded);
433
+ const key = typeof cryptoKeyOrAlias === "string" ? { alias: cryptoKeyOrAlias } : cryptoKeyOrAlias;
434
+ signingKey = new RSASigningKey(key, this.cryptoImpl);
435
+ }
436
+ this.idToKey.set(id, signingKey);
437
+ return signingKey;
368
438
  } catch (e) {
369
439
  console.log("Error importing key: ", e);
370
440
  }
@@ -564,7 +634,7 @@ var Requester = class {
564
634
  const encodedPayload = new TextEncoderImpl().encode(
565
635
  JSON.stringify(payload)
566
636
  );
567
- const signedPayload = await this.cryptoImpl.sign(key, encodedPayload);
637
+ const signedPayload = await key.sign(encodedPayload);
568
638
  const encodedSignedPayload = b64encode(signedPayload);
569
639
  headers["X-Lightspark-Signing"] = JSON.stringify({
570
640
  v: "1",
@@ -591,6 +661,16 @@ var apiDomainForEnvironment = (environment) => {
591
661
  };
592
662
  var ServerEnvironment_default = ServerEnvironment;
593
663
 
664
+ // src/utils/createHash.ts
665
+ var createSha256Hash = async (data) => {
666
+ if (isBrowser) {
667
+ return new Uint8Array(await window.crypto.subtle.digest("SHA-256", data));
668
+ } else {
669
+ const { createHash } = await import("crypto");
670
+ return createHash("sha256").update(data).digest();
671
+ }
672
+ };
673
+
594
674
  // src/utils/currency.ts
595
675
  var CONVERSION_MAP = {
596
676
  ["BITCOIN" /* BITCOIN */]: {
@@ -661,6 +741,20 @@ var convertCurrencyAmount = (from, toUnit) => {
661
741
  };
662
742
  };
663
743
 
744
+ // src/utils/hex.ts
745
+ var bytesToHex = (bytes) => {
746
+ return bytes.reduce((acc, byte) => {
747
+ return acc += ("0" + byte.toString(16)).slice(-2);
748
+ }, "");
749
+ };
750
+ var hexToBytes = (hex) => {
751
+ const bytes = [];
752
+ for (let c = 0; c < hex.length; c += 2) {
753
+ bytes.push(parseInt(hex.substr(c, 2), 16));
754
+ }
755
+ return Uint8Array.from(bytes);
756
+ };
757
+
664
758
  // src/utils/types.ts
665
759
  var isType = (typename) => (node) => {
666
760
  return node?.__typename === typename;
@@ -673,13 +767,20 @@ var isType = (typename) => (node) => {
673
767
  LightsparkException,
674
768
  LightsparkSigningException,
675
769
  NodeKeyCache,
770
+ RSASigningKey,
676
771
  Requester,
772
+ Secp256k1SigningKey,
677
773
  ServerEnvironment,
774
+ SigningKey,
775
+ SigningKeyType,
678
776
  StubAuthProvider,
679
777
  apiDomainForEnvironment,
680
778
  b64decode,
681
779
  b64encode,
780
+ bytesToHex,
682
781
  convertCurrencyAmount,
782
+ createSha256Hash,
783
+ hexToBytes,
683
784
  isBrowser,
684
785
  isNode,
685
786
  isType,
package/dist/index.d.ts CHANGED
@@ -66,12 +66,37 @@ declare const KeyOrAlias: {
66
66
  alias: (alias: string) => OnlyAlias;
67
67
  };
68
68
 
69
+ interface Alias {
70
+ alias: string;
71
+ }
72
+ declare abstract class SigningKey {
73
+ readonly type: SigningKeyType;
74
+ constructor(type: SigningKeyType);
75
+ abstract sign(data: Uint8Array): Promise<ArrayBuffer>;
76
+ }
77
+ declare class RSASigningKey extends SigningKey {
78
+ private readonly privateKey;
79
+ private readonly cryptoImpl;
80
+ constructor(privateKey: CryptoKey | Alias, cryptoImpl: CryptoInterface);
81
+ sign(data: Uint8Array): Promise<ArrayBuffer>;
82
+ }
83
+ declare class Secp256k1SigningKey extends SigningKey {
84
+ private readonly privateKey;
85
+ constructor(privateKey: string);
86
+ sign(data: Uint8Array): Promise<Uint8Array>;
87
+ }
88
+
89
+ declare enum SigningKeyType {
90
+ RSASigningKey = "RSASigningKey",
91
+ Secp256k1SigningKey = "Secp256k1SigningKey"
92
+ }
93
+
69
94
  declare class NodeKeyCache {
70
95
  private readonly cryptoImpl;
71
96
  private idToKey;
72
97
  constructor(cryptoImpl?: CryptoInterface);
73
- loadKey(id: string, keyOrAlias: KeyOrAliasType): Promise<CryptoKey | string | null>;
74
- getKey(id: string): CryptoKey | string | undefined;
98
+ loadKey(id: string, keyOrAlias: KeyOrAliasType, signingKeyType: SigningKeyType): Promise<SigningKey | null>;
99
+ getKey(id: string): SigningKey | undefined;
75
100
  hasKey(id: string): boolean;
76
101
  private stripPemTags;
77
102
  }
@@ -124,6 +149,8 @@ declare const b64decode: (encoded: string) => Uint8Array;
124
149
  declare const urlsafe_b64decode: (encoded: string) => Uint8Array;
125
150
  declare const b64encode: (data: ArrayBuffer) => string;
126
151
 
152
+ declare const createSha256Hash: (data: Uint8Array) => Promise<Uint8Array>;
153
+
127
154
  /** Represents the value and unit for an amount of currency. **/
128
155
  type CurrencyAmount = {
129
156
  /** The original numeric value for this CurrencyAmount. **/
@@ -169,6 +196,9 @@ declare const convertCurrencyAmount: (from: CurrencyAmount, toUnit: CurrencyUnit
169
196
  declare const isBrowser: boolean;
170
197
  declare const isNode: boolean;
171
198
 
199
+ declare const bytesToHex: (bytes: Uint8Array) => string;
200
+ declare const hexToBytes: (hex: string) => Uint8Array;
201
+
172
202
  type Maybe<T> = T | null | undefined;
173
203
  type ExpandRecursively<T> = T extends object ? T extends infer O ? {
174
204
  [K in keyof O]: ExpandRecursively<O[K]>;
@@ -183,4 +213,4 @@ declare const isType: <T extends string>(typename: T) => <N extends {
183
213
  __typename: T;
184
214
  }>;
185
215
 
186
- export { AuthProvider, ById, CryptoInterface, DefaultCrypto, ExpandRecursively, GeneratedKeyPair, KeyOrAlias, KeyOrAliasType, LightsparkAuthException, LightsparkException, LightsparkSigningException, Maybe, NodeKeyCache, OmitTypename, Query, Requester, ServerEnvironment, StubAuthProvider, apiDomainForEnvironment, b64decode, b64encode, convertCurrencyAmount, isBrowser, isNode, isType, urlsafe_b64decode };
216
+ export { AuthProvider, ById, CryptoInterface, DefaultCrypto, ExpandRecursively, GeneratedKeyPair, KeyOrAlias, KeyOrAliasType, LightsparkAuthException, LightsparkException, LightsparkSigningException, Maybe, NodeKeyCache, OmitTypename, Query, RSASigningKey, Requester, Secp256k1SigningKey, ServerEnvironment, SigningKey, SigningKeyType, StubAuthProvider, apiDomainForEnvironment, b64decode, b64encode, bytesToHex, convertCurrencyAmount, createSha256Hash, hexToBytes, isBrowser, isNode, isType, urlsafe_b64decode };
package/dist/index.js CHANGED
@@ -296,6 +296,50 @@ var KeyOrAlias = {
296
296
 
297
297
  // src/crypto/NodeKeyCache.ts
298
298
  import autoBind from "auto-bind";
299
+
300
+ // src/crypto/SigningKey.ts
301
+ import secp256k1 from "secp256k1";
302
+ function isAlias(key) {
303
+ return "alias" in key;
304
+ }
305
+ var SigningKey = class {
306
+ type;
307
+ constructor(type) {
308
+ this.type = type;
309
+ }
310
+ };
311
+ var RSASigningKey = class extends SigningKey {
312
+ constructor(privateKey, cryptoImpl) {
313
+ super("RSASigningKey" /* RSASigningKey */);
314
+ this.privateKey = privateKey;
315
+ this.cryptoImpl = cryptoImpl;
316
+ }
317
+ async sign(data) {
318
+ const key = isAlias(this.privateKey) ? this.privateKey.alias : this.privateKey;
319
+ return this.cryptoImpl.sign(key, data);
320
+ }
321
+ };
322
+ var Secp256k1SigningKey = class extends SigningKey {
323
+ constructor(privateKey) {
324
+ super("Secp256k1SigningKey" /* Secp256k1SigningKey */);
325
+ this.privateKey = privateKey;
326
+ }
327
+ async sign(data) {
328
+ const keyBytes = new Uint8Array(hexToBytes(this.privateKey));
329
+ const hash = await createSha256Hash(data);
330
+ const signResult = secp256k1.ecdsaSign(hash, keyBytes);
331
+ return signResult.signature;
332
+ }
333
+ };
334
+
335
+ // src/crypto/types.ts
336
+ var SigningKeyType = /* @__PURE__ */ ((SigningKeyType2) => {
337
+ SigningKeyType2["RSASigningKey"] = "RSASigningKey";
338
+ SigningKeyType2["Secp256k1SigningKey"] = "Secp256k1SigningKey";
339
+ return SigningKeyType2;
340
+ })(SigningKeyType || {});
341
+
342
+ // src/crypto/NodeKeyCache.ts
299
343
  var NodeKeyCache = class {
300
344
  constructor(cryptoImpl = DefaultCrypto) {
301
345
  this.cryptoImpl = cryptoImpl;
@@ -303,16 +347,35 @@ var NodeKeyCache = class {
303
347
  autoBind(this);
304
348
  }
305
349
  idToKey;
306
- async loadKey(id, keyOrAlias) {
350
+ async loadKey(id, keyOrAlias, signingKeyType) {
351
+ let signingKey;
307
352
  if (keyOrAlias.alias !== void 0) {
308
- this.idToKey.set(id, keyOrAlias.alias);
309
- return keyOrAlias.alias;
353
+ switch (signingKeyType) {
354
+ case "RSASigningKey" /* RSASigningKey */:
355
+ signingKey = new RSASigningKey(
356
+ { alias: keyOrAlias.alias },
357
+ this.cryptoImpl
358
+ );
359
+ break;
360
+ default:
361
+ throw new LightsparkSigningException_default(
362
+ `Aliases are not supported for signing key type ${signingKeyType}`
363
+ );
364
+ }
365
+ this.idToKey.set(id, signingKey);
366
+ return signingKey;
310
367
  }
311
- const decoded = b64decode(this.stripPemTags(keyOrAlias.key));
312
368
  try {
313
- const key = await this.cryptoImpl.importPrivateSigningKey(decoded);
314
- this.idToKey.set(id, key);
315
- return key;
369
+ if (signingKeyType === "Secp256k1SigningKey" /* Secp256k1SigningKey */) {
370
+ signingKey = new Secp256k1SigningKey(keyOrAlias.key);
371
+ } else {
372
+ const decoded = b64decode(this.stripPemTags(keyOrAlias.key));
373
+ const cryptoKeyOrAlias = await this.cryptoImpl.importPrivateSigningKey(decoded);
374
+ const key = typeof cryptoKeyOrAlias === "string" ? { alias: cryptoKeyOrAlias } : cryptoKeyOrAlias;
375
+ signingKey = new RSASigningKey(key, this.cryptoImpl);
376
+ }
377
+ this.idToKey.set(id, signingKey);
378
+ return signingKey;
316
379
  } catch (e) {
317
380
  console.log("Error importing key: ", e);
318
381
  }
@@ -512,7 +575,7 @@ var Requester = class {
512
575
  const encodedPayload = new TextEncoderImpl().encode(
513
576
  JSON.stringify(payload)
514
577
  );
515
- const signedPayload = await this.cryptoImpl.sign(key, encodedPayload);
578
+ const signedPayload = await key.sign(encodedPayload);
516
579
  const encodedSignedPayload = b64encode(signedPayload);
517
580
  headers["X-Lightspark-Signing"] = JSON.stringify({
518
581
  v: "1",
@@ -539,6 +602,16 @@ var apiDomainForEnvironment = (environment) => {
539
602
  };
540
603
  var ServerEnvironment_default = ServerEnvironment;
541
604
 
605
+ // src/utils/createHash.ts
606
+ var createSha256Hash = async (data) => {
607
+ if (isBrowser) {
608
+ return new Uint8Array(await window.crypto.subtle.digest("SHA-256", data));
609
+ } else {
610
+ const { createHash } = await import("crypto");
611
+ return createHash("sha256").update(data).digest();
612
+ }
613
+ };
614
+
542
615
  // src/utils/currency.ts
543
616
  var CONVERSION_MAP = {
544
617
  ["BITCOIN" /* BITCOIN */]: {
@@ -609,6 +682,20 @@ var convertCurrencyAmount = (from, toUnit) => {
609
682
  };
610
683
  };
611
684
 
685
+ // src/utils/hex.ts
686
+ var bytesToHex = (bytes) => {
687
+ return bytes.reduce((acc, byte) => {
688
+ return acc += ("0" + byte.toString(16)).slice(-2);
689
+ }, "");
690
+ };
691
+ var hexToBytes = (hex) => {
692
+ const bytes = [];
693
+ for (let c = 0; c < hex.length; c += 2) {
694
+ bytes.push(parseInt(hex.substr(c, 2), 16));
695
+ }
696
+ return Uint8Array.from(bytes);
697
+ };
698
+
612
699
  // src/utils/types.ts
613
700
  var isType = (typename) => (node) => {
614
701
  return node?.__typename === typename;
@@ -620,13 +707,20 @@ export {
620
707
  LightsparkException_default as LightsparkException,
621
708
  LightsparkSigningException_default as LightsparkSigningException,
622
709
  NodeKeyCache_default as NodeKeyCache,
710
+ RSASigningKey,
623
711
  Requester_default as Requester,
712
+ Secp256k1SigningKey,
624
713
  ServerEnvironment_default as ServerEnvironment,
714
+ SigningKey,
715
+ SigningKeyType,
625
716
  StubAuthProvider,
626
717
  apiDomainForEnvironment,
627
718
  b64decode,
628
719
  b64encode,
720
+ bytesToHex,
629
721
  convertCurrencyAmount,
722
+ createSha256Hash,
723
+ hexToBytes,
630
724
  isBrowser,
631
725
  isNode,
632
726
  isType,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightsparkdev/core",
3
- "version": "0.3.11",
3
+ "version": "1.0.0",
4
4
  "description": "Lightspark JS SDK",
5
5
  "author": "Lightspark Inc.",
6
6
  "keywords": [
@@ -36,7 +36,7 @@
36
36
  }
37
37
  },
38
38
  "engines": {
39
- "node": ">=14.16"
39
+ "node": ">=18.17.0"
40
40
  },
41
41
  "browser": {
42
42
  "crypto": false
@@ -68,6 +68,7 @@
68
68
  "dayjs": "^1.11.7",
69
69
  "graphql": "^16.6.0",
70
70
  "graphql-ws": "^5.11.3",
71
+ "secp256k1": "^5.0.0",
71
72
  "text-encoding": "^0.7.0",
72
73
  "ws": "^8.12.1",
73
74
  "zen-observable-ts": "^1.1.0"
@@ -76,13 +77,14 @@
76
77
  "@lightsparkdev/eslint-config": "*",
77
78
  "@lightsparkdev/tsconfig": "0.0.0",
78
79
  "@types/crypto-js": "^4.1.1",
80
+ "@types/secp256k1": "^4.0.3",
79
81
  "@types/ws": "^8.5.4",
80
82
  "eslint": "^8.3.0",
81
83
  "eslint-watch": "^8.0.0",
82
- "jest": "^29.4.1",
84
+ "jest": "^29.6.2",
83
85
  "prettier": "3.0.2",
84
86
  "prettier-plugin-organize-imports": "^3.2.2",
85
- "ts-jest": "^29.0.5",
87
+ "ts-jest": "^29.1.1",
86
88
  "tsc-absolute": "^1.0.1",
87
89
  "tsup": "^6.7.0",
88
90
  "typescript": "^4.9.5"
@@ -4,11 +4,18 @@ import autoBind from "auto-bind";
4
4
 
5
5
  import { b64decode } from "../utils/base64.js";
6
6
  import type { CryptoInterface } from "./crypto.js";
7
- import { DefaultCrypto } from "./crypto.js";
7
+ import { DefaultCrypto, LightsparkSigningException } from "./crypto.js";
8
8
  import type { KeyOrAliasType } from "./KeyOrAlias.js";
9
+ import {
10
+ RSASigningKey,
11
+ Secp256k1SigningKey,
12
+ type SigningKey,
13
+ } from "./SigningKey.js";
14
+ import { SigningKeyType } from "./types.js";
9
15
 
10
16
  class NodeKeyCache {
11
- private idToKey: Map<string, CryptoKey | string>;
17
+ private idToKey: Map<string, SigningKey>;
18
+
12
19
  constructor(private readonly cryptoImpl: CryptoInterface = DefaultCrypto) {
13
20
  this.idToKey = new Map();
14
21
  autoBind(this);
@@ -17,23 +24,51 @@ class NodeKeyCache {
17
24
  public async loadKey(
18
25
  id: string,
19
26
  keyOrAlias: KeyOrAliasType,
20
- ): Promise<CryptoKey | string | null> {
27
+ signingKeyType: SigningKeyType,
28
+ ): Promise<SigningKey | null> {
29
+ let signingKey: SigningKey;
30
+
21
31
  if (keyOrAlias.alias !== undefined) {
22
- this.idToKey.set(id, keyOrAlias.alias);
23
- return keyOrAlias.alias;
32
+ switch (signingKeyType) {
33
+ case SigningKeyType.RSASigningKey:
34
+ signingKey = new RSASigningKey(
35
+ { alias: keyOrAlias.alias },
36
+ this.cryptoImpl,
37
+ );
38
+ break;
39
+ default:
40
+ throw new LightsparkSigningException(
41
+ `Aliases are not supported for signing key type ${signingKeyType}`,
42
+ );
43
+ }
44
+
45
+ this.idToKey.set(id, signingKey);
46
+ return signingKey;
24
47
  }
25
- const decoded = b64decode(this.stripPemTags(keyOrAlias.key));
48
+
26
49
  try {
27
- const key = await this.cryptoImpl.importPrivateSigningKey(decoded);
28
- this.idToKey.set(id, key);
29
- return key;
50
+ if (signingKeyType === SigningKeyType.Secp256k1SigningKey) {
51
+ signingKey = new Secp256k1SigningKey(keyOrAlias.key);
52
+ } else {
53
+ const decoded = b64decode(this.stripPemTags(keyOrAlias.key));
54
+ const cryptoKeyOrAlias =
55
+ await this.cryptoImpl.importPrivateSigningKey(decoded);
56
+ const key =
57
+ typeof cryptoKeyOrAlias === "string"
58
+ ? { alias: cryptoKeyOrAlias }
59
+ : cryptoKeyOrAlias;
60
+ signingKey = new RSASigningKey(key, this.cryptoImpl);
61
+ }
62
+
63
+ this.idToKey.set(id, signingKey);
64
+ return signingKey;
30
65
  } catch (e) {
31
66
  console.log("Error importing key: ", e);
32
67
  }
33
68
  return null;
34
69
  }
35
70
 
36
- public getKey(id: string): CryptoKey | string | undefined {
71
+ public getKey(id: string): SigningKey | undefined {
37
72
  return this.idToKey.get(id);
38
73
  }
39
74
 
@@ -0,0 +1,54 @@
1
+ import secp256k1 from "secp256k1";
2
+ import {
3
+ createSha256Hash,
4
+ hexToBytes,
5
+ SigningKeyType,
6
+ type CryptoInterface,
7
+ } from "../index.js";
8
+
9
+ interface Alias {
10
+ alias: string;
11
+ }
12
+
13
+ function isAlias(key: CryptoKey | Alias): key is Alias {
14
+ return "alias" in key;
15
+ }
16
+
17
+ export abstract class SigningKey {
18
+ readonly type: SigningKeyType;
19
+
20
+ constructor(type: SigningKeyType) {
21
+ this.type = type;
22
+ }
23
+
24
+ abstract sign(data: Uint8Array): Promise<ArrayBuffer>;
25
+ }
26
+
27
+ export class RSASigningKey extends SigningKey {
28
+ constructor(
29
+ private readonly privateKey: CryptoKey | Alias,
30
+ private readonly cryptoImpl: CryptoInterface,
31
+ ) {
32
+ super(SigningKeyType.RSASigningKey);
33
+ }
34
+
35
+ async sign(data: Uint8Array) {
36
+ const key = isAlias(this.privateKey)
37
+ ? this.privateKey.alias
38
+ : this.privateKey;
39
+ return this.cryptoImpl.sign(key, data);
40
+ }
41
+ }
42
+
43
+ export class Secp256k1SigningKey extends SigningKey {
44
+ constructor(private readonly privateKey: string) {
45
+ super(SigningKeyType.Secp256k1SigningKey);
46
+ }
47
+
48
+ async sign(data: Uint8Array) {
49
+ const keyBytes = new Uint8Array(hexToBytes(this.privateKey));
50
+ const hash = await createSha256Hash(data);
51
+ const signResult = secp256k1.ecdsaSign(hash, keyBytes);
52
+ return signResult.signature;
53
+ }
54
+ }
@@ -4,3 +4,5 @@ export * from "./crypto.js";
4
4
  export * from "./KeyOrAlias.js";
5
5
  export { default as LightsparkSigningException } from "./LightsparkSigningException.js";
6
6
  export { default as NodeKeyCache } from "./NodeKeyCache.js";
7
+ export * from "./SigningKey.js";
8
+ export * from "./types.js";
@@ -0,0 +1,4 @@
1
+ export enum SigningKeyType {
2
+ RSASigningKey = "RSASigningKey",
3
+ Secp256k1SigningKey = "Secp256k1SigningKey",
4
+ }
@@ -228,9 +228,10 @@ class Requester {
228
228
  const encodedPayload = new TextEncoderImpl().encode(
229
229
  JSON.stringify(payload),
230
230
  );
231
- const signedPayload = await this.cryptoImpl.sign(key, encodedPayload);
232
- const encodedSignedPayload = b64encode(signedPayload);
233
231
 
232
+ const signedPayload = await key.sign(encodedPayload);
233
+
234
+ const encodedSignedPayload = b64encode(signedPayload);
234
235
  headers["X-Lightspark-Signing"] = JSON.stringify({
235
236
  v: "1",
236
237
  signature: encodedSignedPayload,
@@ -0,0 +1,12 @@
1
+ import { isBrowser } from "./environment.js";
2
+
3
+ export const createSha256Hash = async (
4
+ data: Uint8Array,
5
+ ): Promise<Uint8Array> => {
6
+ if (isBrowser) {
7
+ return new Uint8Array(await window.crypto.subtle.digest("SHA-256", data));
8
+ } else {
9
+ const { createHash } = await import("crypto");
10
+ return createHash("sha256").update(data).digest();
11
+ }
12
+ };
@@ -0,0 +1,15 @@
1
+ export const bytesToHex = (bytes: Uint8Array): string => {
2
+ return bytes.reduce((acc: string, byte: number) => {
3
+ return (acc += ("0" + byte.toString(16)).slice(-2));
4
+ }, "");
5
+ };
6
+
7
+ export const hexToBytes = (hex: string): Uint8Array => {
8
+ const bytes: number[] = [];
9
+
10
+ for (let c = 0; c < hex.length; c += 2) {
11
+ bytes.push(parseInt(hex.substr(c, 2), 16));
12
+ }
13
+
14
+ return Uint8Array.from(bytes);
15
+ };
@@ -1,6 +1,8 @@
1
1
  // Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
2
2
 
3
3
  export * from "./base64.js";
4
+ export * from "./createHash.js";
4
5
  export * from "./currency.js";
5
6
  export * from "./environment.js";
7
+ export * from "./hex.js";
6
8
  export * from "./types.js";