@zkpassport/sdk 0.2.1 → 0.2.3

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.
@@ -1,5 +1,5 @@
1
- import type { JsonRpcRequest, JsonRpcResponse } from '@zkpassport/utils';
2
- import { WebSocketClient } from './websocket';
1
+ import type { JsonRpcRequest, JsonRpcResponse } from "@zkpassport/utils";
2
+ import { WebSocketClient } from "./websocket";
3
3
  export declare function createJsonRpcRequest(method: string, params: any): JsonRpcRequest;
4
4
  export declare function createEncryptedJsonRpcRequest(method: string, params: any, sharedSecret: Uint8Array, topic: string): Promise<JsonRpcRequest>;
5
5
  export declare function sendEncryptedJsonRpcRequest(method: string, params: any, sharedSecret: Uint8Array, topic: string, wsClient: WebSocketClient): Promise<boolean>;
@@ -1,40 +1,40 @@
1
- import { randomBytes } from 'crypto';
2
- import { encrypt } from './encryption';
3
- import logger from './logger';
1
+ import { randomBytes } from "crypto";
2
+ import { encrypt } from "./encryption";
3
+ import { noLogger as logger } from "./logger";
4
4
  export function createJsonRpcRequest(method, params) {
5
5
  return {
6
- jsonrpc: '2.0',
7
- id: randomBytes(16).toString('hex'),
6
+ jsonrpc: "2.0",
7
+ id: randomBytes(16).toString("hex"),
8
8
  method,
9
9
  params,
10
10
  };
11
11
  }
12
12
  export async function createEncryptedJsonRpcRequest(method, params, sharedSecret, topic) {
13
13
  const encryptedMessage = await encrypt(JSON.stringify({ method, params: params || {} }), sharedSecret, topic);
14
- return createJsonRpcRequest('encryptedMessage', {
15
- payload: Buffer.from(encryptedMessage).toString('base64'),
14
+ return createJsonRpcRequest("encryptedMessage", {
15
+ payload: Buffer.from(encryptedMessage).toString("base64"),
16
16
  });
17
17
  }
18
18
  export async function sendEncryptedJsonRpcRequest(method, params, sharedSecret, topic, wsClient) {
19
19
  try {
20
20
  const message = { method, params: params || {} };
21
21
  const encryptedMessage = await encrypt(JSON.stringify(message), sharedSecret, topic);
22
- const request = createJsonRpcRequest('encryptedMessage', {
23
- payload: Buffer.from(encryptedMessage).toString('base64'),
22
+ const request = createJsonRpcRequest("encryptedMessage", {
23
+ payload: Buffer.from(encryptedMessage).toString("base64"),
24
24
  });
25
- logger.debug('Sending encrypted message (original):', message);
26
- logger.debug('Sending encrypted message (encrypted):', request);
25
+ logger.debug("Sending encrypted message (original):", message);
26
+ logger.debug("Sending encrypted message (encrypted):", request);
27
27
  wsClient.send(JSON.stringify(request));
28
28
  return true;
29
29
  }
30
30
  catch (error) {
31
- logger.error('Error sending encrypted message:', error);
31
+ logger.error("Error sending encrypted message:", error);
32
32
  return false;
33
33
  }
34
34
  }
35
35
  export function createJsonRpcResponse(id, result) {
36
36
  return {
37
- jsonrpc: '2.0',
37
+ jsonrpc: "2.0",
38
38
  id,
39
39
  result,
40
40
  };
@@ -1,7 +1,12 @@
1
- declare const customLogger: {
1
+ export declare const customLogger: {
2
2
  debug: (message: string, ...args: any[]) => void;
3
3
  info: (message: string, ...args: any[]) => void;
4
4
  warn: (message: string, ...args: any[]) => void;
5
5
  error: (message: string, ...args: any[]) => void;
6
6
  };
7
- export default customLogger;
7
+ export declare const noLogger: {
8
+ debug: (..._: any[]) => void;
9
+ info: (..._: any[]) => void;
10
+ warn: (..._: any[]) => void;
11
+ error: (..._: any[]) => void;
12
+ };
@@ -1,37 +1,12 @@
1
- // import { createLogger, transports, format } from 'winston'
2
- // import colors from 'colors/safe'
3
- // import util from 'util'
4
- // const logger = createLogger({
5
- // level: 'debug',
6
- // format: format.combine(
7
- // format.timestamp({ format: 'HH:mm' }),
8
- // format.printf(({ timestamp, level, message, additionalInfo }) => {
9
- // const colorMap = {
10
- // debug: colors.cyan,
11
- // info: colors.green,
12
- // warn: colors.yellow,
13
- // error: colors.red,
14
- // } as const
15
- // const coloredLevel = (colorMap[level as keyof typeof colorMap] || colors.white)(level.toUpperCase())
16
- // let logMessage = `${timestamp} [${coloredLevel}] ${message}`
17
- // if (additionalInfo && additionalInfo.length > 0) {
18
- // logMessage += ' ' + util.inspect(additionalInfo, { depth: null, colors: true })
19
- // }
20
- // return logMessage
21
- // }),
22
- // ),
23
- // transports: [new transports.Console()],
24
- // })
25
- // const customLogger = {
26
- // debug: (message: string, ...args: any[]) => logger.debug(message, { additionalInfo: args }),
27
- // info: (message: string, ...args: any[]) => logger.info(message, { additionalInfo: args }),
28
- // warn: (message: string, ...args: any[]) => logger.warn(message, { additionalInfo: args }),
29
- // error: (message: string, ...args: any[]) => logger.error(message, { additionalInfo: args }),
30
- // }
31
- const customLogger = {
1
+ export const customLogger = {
32
2
  debug: (message, ...args) => console.debug(message, ...args),
33
3
  info: (message, ...args) => console.info(message, ...args),
34
4
  warn: (message, ...args) => console.warn(message, ...args),
35
5
  error: (message, ...args) => console.error(message, ...args),
36
6
  };
37
- export default customLogger;
7
+ export const noLogger = {
8
+ debug: (..._) => { },
9
+ info: (..._) => { },
10
+ warn: (..._) => { },
11
+ error: (..._) => { },
12
+ };
@@ -1,8 +1,8 @@
1
- import { bytesToHex } from '@noble/ciphers/utils';
2
- import { getWebSocketClient } from './websocket';
3
- import { sendEncryptedJsonRpcRequest } from './json-rpc';
4
- import { decrypt, generateECDHKeyPair, getSharedSecret } from './encryption';
5
- import logger from './logger';
1
+ import { bytesToHex } from "@noble/ciphers/utils";
2
+ import { getWebSocketClient } from "./websocket";
3
+ import { sendEncryptedJsonRpcRequest } from "./json-rpc";
4
+ import { decrypt, generateECDHKeyPair, getSharedSecret } from "./encryption";
5
+ import { noLogger as logger } from "./logger";
6
6
  export class ZkPassportProver {
7
7
  constructor() {
8
8
  this.topicToKeyPair = {};
@@ -20,13 +20,13 @@ export class ZkPassportProver {
20
20
  * @param outerRequest The outer request.
21
21
  */
22
22
  async handleEncryptedMessage(topic, request, outerRequest) {
23
- logger.debug('Received encrypted message:', request);
24
- if (request.method === 'hello') {
23
+ logger.debug("Received encrypted message:", request);
24
+ if (request.method === "hello") {
25
25
  logger.info(`Successfully verified origin domain name: ${outerRequest.origin}`);
26
26
  this.topicToRemoteDomainVerified[topic] = true;
27
27
  await Promise.all(this.onDomainVerifiedCallbacks[topic].map((callback) => callback()));
28
28
  }
29
- else if (request.method === 'closed_page') {
29
+ else if (request.method === "closed_page") {
30
30
  // TODO: Implement
31
31
  }
32
32
  }
@@ -36,13 +36,13 @@ export class ZkPassportProver {
36
36
  */
37
37
  async scan(url, { keyPairOverride, } = {}) {
38
38
  const parsedUrl = new URL(url);
39
- const domain = parsedUrl.searchParams.get('d');
40
- const topic = parsedUrl.searchParams.get('t');
41
- const pubkeyHex = parsedUrl.searchParams.get('p');
39
+ const domain = parsedUrl.searchParams.get("d");
40
+ const topic = parsedUrl.searchParams.get("t");
41
+ const pubkeyHex = parsedUrl.searchParams.get("p");
42
42
  if (!domain || !topic || !pubkeyHex) {
43
- throw new Error('Invalid URL: missing required parameters');
43
+ throw new Error("Invalid URL: missing required parameters");
44
44
  }
45
- const pubkey = new Uint8Array(Buffer.from(pubkeyHex, 'hex'));
45
+ const pubkey = new Uint8Array(Buffer.from(pubkeyHex, "hex"));
46
46
  this.domain = domain;
47
47
  const keyPair = keyPairOverride || (await generateECDHKeyPair());
48
48
  this.topicToKeyPair[topic] = {
@@ -58,7 +58,7 @@ export class ZkPassportProver {
58
58
  const wsClient = getWebSocketClient(`wss://bridge.zkpassport.id?topic=${topic}&pubkey=${bytesToHex(keyPair.publicKey)}`);
59
59
  this.topicToWebSocketClient[topic] = wsClient;
60
60
  wsClient.onopen = async () => {
61
- logger.info('[mobile] WebSocket connection established');
61
+ logger.info("[mobile] WebSocket connection established");
62
62
  await Promise.all(this.onBridgeConnectCallbacks[topic].map((callback) => callback()));
63
63
  // Server sends handshake automatically (when it sees a pubkey in websocket URI)
64
64
  // wsClient.send(
@@ -69,8 +69,8 @@ export class ZkPassportProver {
69
69
  // ),
70
70
  // )
71
71
  };
72
- wsClient.addEventListener('message', async (event) => {
73
- logger.info('[mobile] Received message:', event.data);
72
+ wsClient.addEventListener("message", async (event) => {
73
+ logger.info("[mobile] Received message:", event.data);
74
74
  try {
75
75
  const data = JSON.parse(event.data);
76
76
  const originDomain = data.origin ? new URL(data.origin).hostname : undefined;
@@ -79,10 +79,10 @@ export class ZkPassportProver {
79
79
  logger.warn(`[mobile] Origin does not match domain in QR code. Expected ${this.domain} but got ${originDomain}`);
80
80
  return;
81
81
  }
82
- if (data.method === 'encryptedMessage') {
82
+ if (data.method === "encryptedMessage") {
83
83
  // Decode the payload from base64 to Uint8Array
84
84
  const payload = new Uint8Array(atob(data.params.payload)
85
- .split('')
85
+ .split("")
86
86
  .map((c) => c.charCodeAt(0)));
87
87
  try {
88
88
  // Decrypt the payload using the shared secret
@@ -91,16 +91,16 @@ export class ZkPassportProver {
91
91
  await this.handleEncryptedMessage(topic, decryptedJson, data);
92
92
  }
93
93
  catch (error) {
94
- logger.error('[mobile] Error decrypting message:', error);
94
+ logger.error("[mobile] Error decrypting message:", error);
95
95
  }
96
96
  }
97
97
  }
98
98
  catch (error) {
99
- logger.error('[mobile] Error:', error);
99
+ logger.error("[mobile] Error:", error);
100
100
  }
101
101
  });
102
102
  wsClient.onerror = (error) => {
103
- logger.error('[mobile] WebSocket error:', error);
103
+ logger.error("[mobile] WebSocket error:", error);
104
104
  };
105
105
  return {
106
106
  domain: this.domain,
@@ -110,16 +110,16 @@ export class ZkPassportProver {
110
110
  onDomainVerified: (callback) => this.onDomainVerifiedCallbacks[topic].push(callback),
111
111
  onBridgeConnect: (callback) => this.onBridgeConnectCallbacks[topic].push(callback),
112
112
  notifyReject: async () => {
113
- await sendEncryptedJsonRpcRequest('reject', null, this.topicToSharedSecret[topic], topic, this.topicToWebSocketClient[topic]);
113
+ await sendEncryptedJsonRpcRequest("reject", null, this.topicToSharedSecret[topic], topic, this.topicToWebSocketClient[topic]);
114
114
  },
115
115
  notifyAccept: async () => {
116
- await sendEncryptedJsonRpcRequest('accept', null, this.topicToSharedSecret[topic], topic, this.topicToWebSocketClient[topic]);
116
+ await sendEncryptedJsonRpcRequest("accept", null, this.topicToSharedSecret[topic], topic, this.topicToWebSocketClient[topic]);
117
117
  },
118
118
  notifyDone: async (proof) => {
119
- await sendEncryptedJsonRpcRequest('done', { proof }, this.topicToSharedSecret[topic], topic, this.topicToWebSocketClient[topic]);
119
+ await sendEncryptedJsonRpcRequest("done", { proof }, this.topicToSharedSecret[topic], topic, this.topicToWebSocketClient[topic]);
120
120
  },
121
121
  notifyError: async (error) => {
122
- await sendEncryptedJsonRpcRequest('error', { error }, this.topicToSharedSecret[topic], topic, this.topicToWebSocketClient[topic]);
122
+ await sendEncryptedJsonRpcRequest("error", { error }, this.topicToSharedSecret[topic], topic, this.topicToWebSocketClient[topic]);
123
123
  },
124
124
  };
125
125
  }
@@ -1,14 +1,14 @@
1
1
  export function getWebSocketClient(url, origin) {
2
- if (typeof window !== 'undefined' && window.WebSocket) {
2
+ if (typeof window !== "undefined" && window.WebSocket) {
3
3
  // Browser environment
4
4
  return new WebSocket(url);
5
5
  }
6
6
  else {
7
7
  // Node.js environment
8
- const WebSocket = require('ws');
8
+ const WebSocket = require("ws");
9
9
  return new WebSocket(url, {
10
10
  headers: {
11
- Origin: origin || 'nodejs',
11
+ Origin: origin || "nodejs",
12
12
  },
13
13
  });
14
14
  }
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@zkpassport/sdk",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Privacy-preserving identity verification using passports and ID cards",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/esm/index.js",
7
7
  "types": "./dist/esm/index.d.ts",
8
+ "type": "module",
8
9
  "files": [
9
10
  "src/",
10
11
  "dist/**",
@@ -12,28 +13,37 @@
12
13
  "README.md"
13
14
  ],
14
15
  "scripts": {
15
- "prepublishOnly": "npm run build",
16
+ "prepublishOnly": "npm run test && npm run build",
16
17
  "build": "npm run build:esm && npm run build:cjs",
17
18
  "build:esm": "tsc -p tsconfig.json",
18
- "build:cjs": "tsc -p tsconfig.cjs.json"
19
+ "build:cjs": "tsc -p tsconfig.cjs.json",
20
+ "test": "NODE_OPTIONS='--require ts-node/register' NODE_NO_WARNINGS=1 node node_modules/.bin/jest --no-cache --passWithNoTests --runInBand **/*.test.ts",
21
+ "test:debug": "NODE_OPTIONS='--require ts-node/register' NODE_NO_WARNINGS=1 node --inspect-brk=0.0.0.0 node_modules/.bin/jest --no-cache --passWithNoTests --runInBand **/*.test.ts",
22
+ "deploy": "npm publish --access public"
19
23
  },
20
24
  "keywords": [],
21
25
  "author": "",
22
26
  "license": "Apache-2.0",
23
27
  "devDependencies": {
28
+ "@babel/plugin-proposal-decorators": "^7.25.9",
29
+ "@babel/preset-env": "^7.26.0",
30
+ "@babel/preset-typescript": "^7.26.0",
31
+ "@jest/globals": "^29.7.0",
32
+ "@types/jest": "^29.5.14",
24
33
  "@types/node": "^22.10.9",
25
34
  "@types/node-gzip": "^1.1.3",
26
35
  "@types/ws": "^8.5.12",
36
+ "jest": "^29.7.0",
27
37
  "typescript": "^5.6.2"
28
38
  },
29
39
  "dependencies": {
30
40
  "@aztec/bb.js": "^0.67.0",
31
- "@noble/ciphers": "^1.0.0",
32
- "@noble/secp256k1": "^2.1.0",
41
+ "@noble/ciphers": "^1.2.1",
42
+ "@noble/secp256k1": "^2.2.3",
33
43
  "@zkpassport/utils": "^0.2.12",
34
44
  "i18n-iso-countries": "^7.12.0",
35
45
  "node-gzip": "^1.1.2",
36
- "tslib": "^2.8.1",
37
46
  "ws": "^8.18.0"
38
- }
47
+ },
48
+ "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
39
49
  }
package/src/encryption.ts CHANGED
@@ -1,17 +1,17 @@
1
- import { gcm } from '@noble/ciphers/aes'
2
- import { utf8ToBytes } from '@noble/ciphers/utils'
1
+ import { gcm } from "@noble/ciphers/aes"
2
+ import { utf8ToBytes } from "@noble/ciphers/utils"
3
3
 
4
4
  async function sha256Truncate(topic: string): Promise<Uint8Array> {
5
5
  const encoder = new TextEncoder()
6
6
  const data = encoder.encode(topic)
7
- const hashBuffer = await crypto.subtle.digest('SHA-256', data)
7
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data)
8
8
  const fullHashArray = new Uint8Array(hashBuffer)
9
9
  const truncatedHashArray = fullHashArray.slice(0, 12)
10
10
  return truncatedHashArray
11
11
  }
12
12
 
13
13
  export async function generateECDHKeyPair() {
14
- const secp256k1 = await import('@noble/secp256k1')
14
+ const secp256k1 = await import("@noble/secp256k1")
15
15
  const privKey = secp256k1.utils.randomPrivateKey()
16
16
  const pubKey = secp256k1.getPublicKey(privKey)
17
17
  return {
@@ -21,7 +21,7 @@ export async function generateECDHKeyPair() {
21
21
  }
22
22
 
23
23
  export async function getSharedSecret(privateKey: string, publicKey: string) {
24
- const secp256k1 = await import('@noble/secp256k1')
24
+ const secp256k1 = await import("@noble/secp256k1")
25
25
  const sharedSecret = secp256k1.getSharedSecret(privateKey, publicKey)
26
26
  return sharedSecret.slice(0, 32)
27
27
  }