@zkpassport/sdk 0.3.3 → 0.4.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/src/index.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { randomBytes } from "crypto"
2
1
  import { Alpha3Code, getAlpha3Code, registerLocale } from "i18n-iso-countries"
3
2
  import {
4
3
  type DisclosableIDCredential,
@@ -57,11 +56,9 @@ import {
57
56
  ProofData,
58
57
  getScopeFromOuterProof,
59
58
  getSubscopeFromOuterProof,
59
+ getServiceScopeHash,
60
60
  } from "@zkpassport/utils"
61
61
  import { bytesToHex } from "@noble/ciphers/utils"
62
- import { getWebSocketClient, WebSocketClient } from "./websocket"
63
- import { createEncryptedJsonRpcRequest } from "./json-rpc"
64
- import { decrypt, generateECDHKeyPair, getSharedSecret } from "./encryption"
65
62
  import { noLogger as logger } from "./logger"
66
63
  import { inflate } from "pako"
67
64
  import i18en from "i18n-iso-countries/langs/en.json"
@@ -70,6 +67,7 @@ import { sha256 } from "@noble/hashes/sha2"
70
67
  import { hexToBytes } from "@noble/hashes/utils"
71
68
  import ZKPassportVerifierAbi from "./assets/abi/ZKPassportVerifier.json"
72
69
  import { RegistryClient } from "@zkpassport/registry"
70
+ import { Bridge, BridgeInterface } from "@obsidion/bridge"
73
71
 
74
72
  const DEFAULT_DATE_VALUE = new Date(1111, 10, 11)
75
73
 
@@ -124,6 +122,24 @@ export type SolidityVerifierParameters = {
124
122
 
125
123
  export type EVMChain = "ethereum_sepolia" | "local_anvil"
126
124
 
125
+ function getChainIdFromEVMChain(chain: EVMChain): number {
126
+ if (chain === "ethereum_sepolia") {
127
+ return 11155111
128
+ } else if (chain === "local_anvil") {
129
+ return 31337
130
+ }
131
+ throw new Error(`Unsupported chain: ${chain}`)
132
+ }
133
+
134
+ function getEVMChainFromChainId(chainId: number): EVMChain {
135
+ if (chainId === 11155111) {
136
+ return "ethereum_sepolia"
137
+ } else if (chainId === 31337) {
138
+ return "local_anvil"
139
+ }
140
+ throw new Error(`Unsupported chain ID: ${chainId}`)
141
+ }
142
+
127
143
  registerLocale(i18en)
128
144
 
129
145
  function hasRequestedAccessToField(credentialsRequest: Query, field: IDCredential): boolean {
@@ -351,13 +367,12 @@ export class ZKPassport {
351
367
  devMode: boolean
352
368
  }
353
369
  > = {}
354
- private topicToKeyPair: Record<string, { privateKey: Uint8Array; publicKey: Uint8Array }> = {}
355
- private topicToWebSocketClient: Record<string, WebSocketClient> = {}
356
- private topicToSharedSecret: Record<string, Uint8Array> = {}
370
+ private topicToPublicKey: Record<string, string> = {}
371
+ private topicToBridge: Record<string, BridgeInterface> = {}
357
372
  private topicToRequestReceived: Record<string, boolean> = {}
358
373
  private topicToService: Record<
359
374
  string,
360
- { name: string; logo: string; purpose: string; scope?: string }
375
+ { name: string; logo: string; purpose: string; scope?: string; chainId?: number }
361
376
  > = {}
362
377
  private topicToProofs: Record<string, Array<ProofResult>> = {}
363
378
  private topicToExpectedProofCount: Record<string, number> = {}
@@ -400,6 +415,9 @@ export class ZKPassport {
400
415
  queryResult: result,
401
416
  validity: this.topicToLocalConfig[topic]?.validity,
402
417
  scope: this.topicToService[topic]?.scope,
418
+ evmChain: this.topicToService[topic]?.chainId
419
+ ? getEVMChainFromChainId(this.topicToService[topic]?.chainId)
420
+ : undefined,
403
421
  devMode: this.topicToLocalConfig[topic]?.devMode,
404
422
  })
405
423
  delete this.topicToProofs[topic]
@@ -498,11 +516,7 @@ export class ZKPassport {
498
516
  * @param request The request.
499
517
  * @param outerRequest The outer request.
500
518
  */
501
- private async handleEncryptedMessage(
502
- topic: string,
503
- request: JsonRpcRequest,
504
- outerRequest: JsonRpcRequest,
505
- ) {
519
+ private async handleEncryptedMessage(topic: string, request: JsonRpcRequest) {
506
520
  logger.debug("Received encrypted message:", request)
507
521
  if (request.method === "accept") {
508
522
  logger.debug(`User accepted the request and is generating a proof`)
@@ -512,31 +526,9 @@ export class ZKPassport {
512
526
  await Promise.all(this.onRejectCallbacks[topic].map((callback) => callback()))
513
527
  } else if (request.method === "proof") {
514
528
  logger.debug(`User generated proof`)
515
- // Uncompress the proof and convert it to a hex string
516
- const bytesProof = Buffer.from(request.params.proof, "base64")
517
- const bytesCommittedInputs = request.params.committedInputs
518
- ? Buffer.from(request.params.committedInputs, "base64")
519
- : null
520
- const uncompressedProof = inflate(bytesProof)
521
- const uncompressedCommittedInputs = bytesCommittedInputs
522
- ? inflate(bytesCommittedInputs)
523
- : null
524
- // The gzip lib in the app compress the proof as ASCII
525
- // and since the app passes the proof as a hex string, we can
526
- // just decode the bytes as hex characters using the TextDecoder
527
- const hexProof = new TextDecoder().decode(uncompressedProof)
528
- const processedProof: ProofResult = {
529
- proof: hexProof,
530
- vkeyHash: request.params.vkeyHash,
531
- name: request.params.name,
532
- version: request.params.version,
533
- committedInputs: uncompressedCommittedInputs
534
- ? JSON.parse(new TextDecoder().decode(uncompressedCommittedInputs))
535
- : undefined,
536
- }
537
- this.topicToProofs[topic].push(processedProof)
529
+ this.topicToProofs[topic].push(request.params)
538
530
  await Promise.all(
539
- this.onProofGeneratedCallbacks[topic].map((callback) => callback(processedProof)),
531
+ this.onProofGeneratedCallbacks[topic].map((callback) => callback(request.params)),
540
532
  )
541
533
  // If the results were received before all the proofs were generated,
542
534
  // we can handle the result now
@@ -651,7 +643,7 @@ export class ZKPassport {
651
643
  const base64Service = Buffer.from(JSON.stringify(this.topicToService[topic])).toString(
652
644
  "base64",
653
645
  )
654
- const pubkey = bytesToHex(this.topicToKeyPair[topic].publicKey)
646
+ const pubkey = this.topicToPublicKey[topic]
655
647
  this.setExpectedProofCount(topic)
656
648
  return {
657
649
  url: `https://zkpassport.id/r?d=${this.domain}&t=${topic}&c=${base64Config}&s=${base64Service}&p=${pubkey}&m=${this.topicToLocalConfig[topic].mode}`,
@@ -675,7 +667,7 @@ export class ZKPassport {
675
667
  onReject: (callback: () => void) => this.onRejectCallbacks[topic].push(callback),
676
668
  onError: (callback: (error: string) => void) =>
677
669
  this.onErrorCallbacks[topic].push(callback),
678
- isBridgeConnected: () => this.topicToWebSocketClient[topic].readyState === WebSocket.OPEN,
670
+ isBridgeConnected: () => this.topicToBridge[topic].isBridgeConnected(),
679
671
  requestReceived: () => this.topicToRequestReceived[topic] === true,
680
672
  }
681
673
  },
@@ -690,6 +682,7 @@ export class ZKPassport {
690
682
  * @param scope Scope this request to a specific use case
691
683
  * @param validity How many days ago should have the ID been last scanned by the user?
692
684
  * @param devMode Whether to enable dev mode. This will allow you to verify mock proofs (i.e. from ZKR)
685
+ * @param evmChain The EVM chain to use for the request (if using the proof onchain)
693
686
  * @returns The query builder object.
694
687
  */
695
688
  public async request({
@@ -698,6 +691,7 @@ export class ZKPassport {
698
691
  purpose,
699
692
  scope,
700
693
  mode,
694
+ evmChain,
701
695
  validity,
702
696
  devMode,
703
697
  topicOverride,
@@ -708,21 +702,27 @@ export class ZKPassport {
708
702
  purpose: string
709
703
  scope?: string
710
704
  mode?: ProofMode
705
+ evmChain?: EVMChain
711
706
  validity?: number
712
707
  devMode?: boolean
713
708
  topicOverride?: string
714
709
  keyPairOverride?: { privateKey: Uint8Array; publicKey: Uint8Array }
715
710
  }): Promise<QueryBuilder> {
716
- const topic = topicOverride || randomBytes(16).toString("hex")
711
+ const bridge = await Bridge.create({
712
+ keyPair: keyPairOverride,
713
+ bridgeId: topicOverride,
714
+ })
717
715
 
718
- const keyPair = keyPairOverride || (await generateECDHKeyPair())
719
- this.topicToKeyPair[topic] = {
720
- privateKey: keyPair.privateKey,
721
- publicKey: keyPair.publicKey,
722
- }
716
+ const topic = bridge.connection.getBridgeId()
723
717
 
724
718
  this.topicToConfig[topic] = {}
725
- this.topicToService[topic] = { name, logo, purpose, scope }
719
+ this.topicToService[topic] = {
720
+ name,
721
+ logo,
722
+ purpose,
723
+ scope,
724
+ chainId: evmChain ? getChainIdFromEVMChain(evmChain) : undefined,
725
+ }
726
726
  this.topicToProofs[topic] = []
727
727
  this.topicToExpectedProofCount[topic] = 0
728
728
  this.topicToLocalConfig[topic] = {
@@ -740,68 +740,22 @@ export class ZKPassport {
740
740
  this.onRejectCallbacks[topic] = []
741
741
  this.onErrorCallbacks[topic] = []
742
742
 
743
- const wsClient = getWebSocketClient(`wss://bridge.zkpassport.id?topic=${topic}`, this.domain)
744
- this.topicToWebSocketClient[topic] = wsClient
745
- wsClient.onopen = async () => {
746
- logger.info("[frontend] WebSocket connection established")
747
- await Promise.all(this.onBridgeConnectCallbacks[topic].map((callback) => callback()))
748
- }
749
- wsClient.addEventListener("message", async (event: any) => {
750
- logger.debug("[frontend] Received message:", event.data)
751
- try {
752
- const data: JsonRpcRequest = JSON.parse(event.data)
753
- // Handshake happens when the mobile app scans the QR code and connects to the bridge
754
- if (data.method === "handshake") {
755
- logger.debug("[frontend] Received handshake:", event.data)
756
-
757
- this.topicToRequestReceived[topic] = true
758
- this.topicToSharedSecret[topic] = await getSharedSecret(
759
- bytesToHex(keyPair.privateKey),
760
- data.params.pubkey,
761
- )
762
- logger.debug(
763
- "[frontend] Shared secret:",
764
- Buffer.from(this.topicToSharedSecret[topic]).toString("hex"),
765
- )
766
-
767
- const encryptedMessage = await createEncryptedJsonRpcRequest(
768
- "hello",
769
- null,
770
- this.topicToSharedSecret[topic],
771
- topic,
772
- )
773
- logger.debug("[frontend] Sending encrypted message:", encryptedMessage)
774
- wsClient.send(JSON.stringify(encryptedMessage))
775
-
776
- await Promise.all(this.onRequestReceivedCallbacks[topic].map((callback) => callback()))
777
- return
778
- }
743
+ this.topicToPublicKey[topic] = bridge.getPublicKey()
779
744
 
780
- // Handle encrypted messages
781
- if (data.method === "encryptedMessage") {
782
- // Decode the payload from base64 to Uint8Array
783
- const payload = new Uint8Array(
784
- atob(data.params.payload)
785
- .split("")
786
- .map((c) => c.charCodeAt(0)),
787
- )
788
- try {
789
- // Decrypt the payload using the shared secret
790
- const decrypted = await decrypt(payload, this.topicToSharedSecret[topic], topic)
791
- const decryptedJson: JsonRpcRequest = JSON.parse(decrypted)
792
- this.handleEncryptedMessage(topic, decryptedJson, data)
793
- } catch (error) {
794
- logger.error("[frontend] Error decrypting message:", error)
795
- }
796
- return
797
- }
798
- } catch (error) {
799
- logger.error("[frontend] Error:", error)
800
- }
745
+ this.topicToBridge[topic] = bridge
746
+ bridge.onConnect(async (reconnection: boolean) => {
747
+ logger.debug("Bridge connected")
748
+ logger.debug("Is reconnection:", reconnection)
749
+ await Promise.all(this.onBridgeConnectCallbacks[topic].map((callback) => callback()))
750
+ })
751
+ bridge.onSecureChannelEstablished(async () => {
752
+ logger.debug("Secure channel established")
753
+ await Promise.all(this.onRequestReceivedCallbacks[topic].map((callback) => callback()))
754
+ })
755
+ bridge.onSecureMessage(async (message: any) => {
756
+ logger.debug("Received message:", message)
757
+ this.handleEncryptedMessage(topic, message)
801
758
  })
802
- wsClient.onerror = (error: Event) => {
803
- logger.error("[frontend] WebSocket error:", error)
804
- }
805
759
  return this.getZkPassportRequest(topic)
806
760
  }
807
761
 
@@ -1780,13 +1734,17 @@ export class ZKPassport {
1780
1734
  queryResultErrors: QueryResultErrors,
1781
1735
  key: string,
1782
1736
  scope?: string,
1737
+ chainId?: number,
1783
1738
  ) {
1784
1739
  let isCorrect = true
1785
- if (this.domain && getScopeHash(this.domain) !== BigInt(proofData.publicInputs[1])) {
1740
+ if (
1741
+ this.domain &&
1742
+ getServiceScopeHash(this.domain, chainId) !== BigInt(proofData.publicInputs[1])
1743
+ ) {
1786
1744
  console.warn("The proof comes from a different domain than the one expected")
1787
1745
  isCorrect = false
1788
1746
  queryResultErrors[key as keyof QueryResultErrors].scope = {
1789
- expected: `Scope: ${getScopeHash(this.domain).toString()}`,
1747
+ expected: `Scope: ${getServiceScopeHash(this.domain, chainId).toString()}`,
1790
1748
  received: `Scope: ${BigInt(proofData.publicInputs[1]).toString()}`,
1791
1749
  message: "The proof comes from a different domain than the one expected",
1792
1750
  }
@@ -1840,6 +1798,7 @@ export class ZKPassport {
1840
1798
  queryResult: QueryResult,
1841
1799
  validity?: number,
1842
1800
  scope?: string,
1801
+ chainId?: number,
1843
1802
  ) {
1844
1803
  let commitmentIn: bigint | undefined
1845
1804
  let commitmentOut: bigint | undefined
@@ -1945,11 +1904,14 @@ export class ZKPassport {
1945
1904
  message: "The proof does not verify all the requested conditions and information",
1946
1905
  }
1947
1906
  }
1948
- if (this.domain && getScopeHash(this.domain) !== getScopeFromOuterProof(proofData)) {
1907
+ if (
1908
+ this.domain &&
1909
+ getServiceScopeHash(this.domain, chainId) !== getScopeFromOuterProof(proofData)
1910
+ ) {
1949
1911
  console.warn("The proof comes from a different domain than the one expected")
1950
1912
  isCorrect = false
1951
1913
  queryResultErrors.outer.scope = {
1952
- expected: `Scope: ${getScopeHash(this.domain).toString()}`,
1914
+ expected: `Scope: ${getServiceScopeHash(this.domain, chainId).toString()}`,
1953
1915
  received: `Scope: ${getScopeFromOuterProof(proofData).toString()}`,
1954
1916
  message: "The proof comes from a different domain than the one expected",
1955
1917
  }
@@ -2646,6 +2608,9 @@ export class ZKPassport {
2646
2608
  * @param proofs The proofs to verify.
2647
2609
  * @param queryResult The query result to verify against
2648
2610
  * @param validity How many days ago should have the ID been last scanned by the user?
2611
+ * @param scope Scope this request to a specific use case
2612
+ * @param evmChain The EVM chain to use for the verification (if using the proof onchain)
2613
+ * @param devMode Whether to enable dev mode. This will allow you to verify mock proofs (i.e. from ZKR)
2649
2614
  * @returns An object containing the unique identifier associated to the user
2650
2615
  * and a boolean indicating whether the proofs were successfully verified.
2651
2616
  */
@@ -2654,18 +2619,28 @@ export class ZKPassport {
2654
2619
  queryResult,
2655
2620
  validity,
2656
2621
  scope,
2622
+ evmChain,
2657
2623
  devMode = false,
2658
2624
  }: {
2659
2625
  proofs: Array<ProofResult>
2660
2626
  queryResult: QueryResult
2661
2627
  validity?: number
2662
2628
  scope?: string
2629
+ evmChain?: EVMChain
2663
2630
  devMode?: boolean
2664
2631
  }): Promise<{
2665
2632
  uniqueIdentifier: string | undefined
2666
2633
  verified: boolean
2667
2634
  queryResultErrors?: QueryResultErrors
2668
2635
  }> {
2636
+ // If no proofs were generated, the results can't be trusted.
2637
+ // We still return it but verified will be false
2638
+ if (!proofs || proofs.length === 0) {
2639
+ return {
2640
+ uniqueIdentifier: undefined,
2641
+ verified: false,
2642
+ }
2643
+ }
2669
2644
  const formattedResult: QueryResult = queryResult
2670
2645
  // Make sure to reconvert the dates to Date objects
2671
2646
  if (formattedResult.birthdate && formattedResult.birthdate.disclose) {
@@ -2684,11 +2659,12 @@ export class ZKPassport {
2684
2659
  let verified = true
2685
2660
  let uniqueIdentifier: string | undefined
2686
2661
  let queryResultErrors: QueryResultErrors | undefined
2662
+ const chainId = evmChain ? getChainIdFromEVMChain(evmChain) : undefined
2687
2663
  const {
2688
2664
  isCorrect,
2689
2665
  uniqueIdentifier: uniqueIdentifierFromPublicInputs,
2690
2666
  queryResultErrors: queryResultErrorsFromPublicInputs,
2691
- } = await this.checkPublicInputs(proofs, formattedResult, validity, scope)
2667
+ } = await this.checkPublicInputs(proofs, formattedResult, validity, scope, chainId)
2692
2668
  uniqueIdentifier = uniqueIdentifierFromPublicInputs
2693
2669
  verified = isCorrect
2694
2670
  queryResultErrors = isCorrect ? undefined : queryResultErrorsFromPublicInputs
@@ -2782,7 +2758,7 @@ export class ZKPassport {
2782
2758
  if (network === "ethereum_sepolia") {
2783
2759
  return {
2784
2760
  ...baseConfig,
2785
- address: "0x8c6982D77f7a8f60aE3133cA9b2FAA6f3e78c394",
2761
+ address: "0xDfE02DFd5c208854884B58bFf6522De5c42F73E3",
2786
2762
  }
2787
2763
  } else if (network === "local_anvil") {
2788
2764
  return {
@@ -2951,7 +2927,7 @@ export class ZKPassport {
2951
2927
  * @returns The URL of the request.
2952
2928
  */
2953
2929
  public getUrl(requestId: string) {
2954
- const pubkey = bytesToHex(this.topicToKeyPair[requestId].publicKey)
2930
+ const pubkey = this.topicToPublicKey[requestId]
2955
2931
  const base64Config = Buffer.from(JSON.stringify(this.topicToConfig[requestId])).toString(
2956
2932
  "base64",
2957
2933
  )
@@ -2966,14 +2942,13 @@ export class ZKPassport {
2966
2942
  * @param requestId The request ID.
2967
2943
  */
2968
2944
  public cancelRequest(requestId: string) {
2969
- if (this.topicToWebSocketClient[requestId]) {
2970
- this.topicToWebSocketClient[requestId].close()
2971
- delete this.topicToWebSocketClient[requestId]
2945
+ if (this.topicToBridge[requestId]) {
2946
+ this.topicToBridge[requestId].close()
2947
+ delete this.topicToBridge[requestId]
2972
2948
  }
2973
- delete this.topicToKeyPair[requestId]
2949
+ delete this.topicToPublicKey[requestId]
2974
2950
  delete this.topicToConfig[requestId]
2975
2951
  delete this.topicToLocalConfig[requestId]
2976
- delete this.topicToSharedSecret[requestId]
2977
2952
  delete this.topicToProofs[requestId]
2978
2953
  delete this.topicToExpectedProofCount[requestId]
2979
2954
  delete this.topicToFailedProofCount[requestId]
@@ -2990,7 +2965,7 @@ export class ZKPassport {
2990
2965
  * @notice Clears all requests.
2991
2966
  */
2992
2967
  public clearAllRequests() {
2993
- for (const requestId in this.topicToWebSocketClient) {
2968
+ for (const requestId in this.topicToBridge) {
2994
2969
  this.cancelRequest(requestId)
2995
2970
  }
2996
2971
  }
package/src/encryption.ts DELETED
@@ -1,45 +0,0 @@
1
- import { gcm } from "@noble/ciphers/aes"
2
- import { utf8ToBytes } from "@noble/ciphers/utils"
3
-
4
- async function sha256Truncate(topic: string): Promise<Uint8Array> {
5
- const encoder = new TextEncoder()
6
- const data = encoder.encode(topic)
7
- const hashBuffer = await crypto.subtle.digest("SHA-256", data)
8
- const fullHashArray = new Uint8Array(hashBuffer)
9
- const truncatedHashArray = fullHashArray.slice(0, 12)
10
- return truncatedHashArray
11
- }
12
-
13
- export async function generateECDHKeyPair() {
14
- const secp256k1 = await import("@noble/secp256k1")
15
- const privKey = secp256k1.utils.randomPrivateKey()
16
- const pubKey = secp256k1.getPublicKey(privKey)
17
- return {
18
- privateKey: privKey,
19
- publicKey: pubKey,
20
- }
21
- }
22
-
23
- export async function getSharedSecret(privateKey: string, publicKey: string) {
24
- const secp256k1 = await import("@noble/secp256k1")
25
- const sharedSecret = secp256k1.getSharedSecret(privateKey, publicKey)
26
- return sharedSecret.slice(0, 32)
27
- }
28
-
29
- export async function encrypt(message: string, sharedSecret: Uint8Array, topic: string) {
30
- // Nonce must be 12 bytes
31
- const nonce = await sha256Truncate(topic)
32
- const aes = gcm(sharedSecret, nonce)
33
- const data = utf8ToBytes(message)
34
- const ciphertext = aes.encrypt(data)
35
- return ciphertext
36
- }
37
-
38
- export async function decrypt(ciphertext: Uint8Array, sharedSecret: Uint8Array, topic: string) {
39
- // Nonce must be 12 bytes
40
- const nonce = await sha256Truncate(topic)
41
- const aes = gcm(sharedSecret, nonce)
42
- const data = aes.decrypt(ciphertext)
43
- const dataString = new TextDecoder().decode(data)
44
- return dataString
45
- }
package/src/json-rpc.ts DELETED
@@ -1,61 +0,0 @@
1
- import { randomBytes } from "crypto"
2
- import type { JsonRpcRequest, JsonRpcResponse } from "@zkpassport/utils"
3
- import { encrypt } from "./encryption"
4
- import { WebSocketClient } from "./websocket"
5
- import { noLogger as logger } from "./logger"
6
-
7
- export function createJsonRpcRequest(method: string, params: any): JsonRpcRequest {
8
- return {
9
- jsonrpc: "2.0",
10
- id: randomBytes(16).toString("hex"),
11
- method,
12
- params,
13
- }
14
- }
15
-
16
- export async function createEncryptedJsonRpcRequest(
17
- method: string,
18
- params: any,
19
- sharedSecret: Uint8Array,
20
- topic: string,
21
- ): Promise<JsonRpcRequest> {
22
- const encryptedMessage = await encrypt(
23
- JSON.stringify({ method, params: params || {} }),
24
- sharedSecret,
25
- topic,
26
- )
27
- return createJsonRpcRequest("encryptedMessage", {
28
- payload: Buffer.from(encryptedMessage).toString("base64"),
29
- })
30
- }
31
-
32
- export async function sendEncryptedJsonRpcRequest(
33
- method: string,
34
- params: any,
35
- sharedSecret: Uint8Array,
36
- topic: string,
37
- wsClient: WebSocketClient,
38
- ): Promise<boolean> {
39
- try {
40
- const message = { method, params: params || {} }
41
- const encryptedMessage = await encrypt(JSON.stringify(message), sharedSecret, topic)
42
- const request = createJsonRpcRequest("encryptedMessage", {
43
- payload: Buffer.from(encryptedMessage).toString("base64"),
44
- })
45
- logger.debug("Sending encrypted message (original):", message)
46
- logger.debug("Sending encrypted message (encrypted):", request)
47
- wsClient.send(JSON.stringify(request))
48
- return true
49
- } catch (error) {
50
- logger.error("Error sending encrypted message:", error)
51
- return false
52
- }
53
- }
54
-
55
- export function createJsonRpcResponse(id: string, result: any): JsonRpcResponse {
56
- return {
57
- jsonrpc: "2.0",
58
- id,
59
- result,
60
- }
61
- }