@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/dist/cjs/assets/abi/ZKPassportVerifier.json +14 -14
- package/dist/cjs/index.d.ts +10 -5
- package/dist/cjs/index.js +85 -104
- package/dist/esm/assets/abi/ZKPassportVerifier.json +14 -14
- package/dist/esm/index.d.ts +10 -5
- package/dist/esm/index.js +86 -105
- package/package.json +3 -2
- package/src/assets/abi/ZKPassportVerifier.json +14 -14
- package/src/index.ts +94 -119
- package/src/encryption.ts +0 -45
- package/src/json-rpc.ts +0 -61
- package/src/mobile.ts +0 -186
- package/src/websocket.ts +0 -16
package/src/mobile.ts
DELETED
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
import { bytesToHex } from "@noble/ciphers/utils"
|
|
2
|
-
import { getWebSocketClient, WebSocketClient } from "./websocket"
|
|
3
|
-
import { sendEncryptedJsonRpcRequest } from "./json-rpc"
|
|
4
|
-
import { decrypt, generateECDHKeyPair, getSharedSecret } from "./encryption"
|
|
5
|
-
import type { JsonRpcRequest } from "@zkpassport/utils"
|
|
6
|
-
import { noLogger as logger } from "./logger"
|
|
7
|
-
|
|
8
|
-
export class ZkPassportProver {
|
|
9
|
-
private domain?: string
|
|
10
|
-
private topicToKeyPair: Record<string, { privateKey: Uint8Array; publicKey: Uint8Array }> = {}
|
|
11
|
-
private topicToWebSocketClient: Record<string, WebSocketClient> = {}
|
|
12
|
-
private topicToRemoteDomainVerified: Record<string, boolean> = {}
|
|
13
|
-
private topicToSharedSecret: Record<string, Uint8Array> = {}
|
|
14
|
-
private topicToRemotePublicKey: Record<string, Uint8Array> = {}
|
|
15
|
-
|
|
16
|
-
private onDomainVerifiedCallbacks: Record<string, Array<() => void>> = {}
|
|
17
|
-
private onBridgeConnectCallbacks: Record<string, Array<() => void>> = {}
|
|
18
|
-
private onWebsiteDomainVerifyFailureCallbacks: Record<string, Array<() => void>> = {}
|
|
19
|
-
|
|
20
|
-
constructor() {}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* @notice Handle an encrypted message.
|
|
24
|
-
* @param request The request.
|
|
25
|
-
* @param outerRequest The outer request.
|
|
26
|
-
*/
|
|
27
|
-
private async handleEncryptedMessage(
|
|
28
|
-
topic: string,
|
|
29
|
-
request: JsonRpcRequest,
|
|
30
|
-
outerRequest: JsonRpcRequest,
|
|
31
|
-
) {
|
|
32
|
-
logger.debug("Received encrypted message:", request)
|
|
33
|
-
if (request.method === "hello") {
|
|
34
|
-
logger.info(`Successfully verified origin domain name: ${outerRequest.origin}`)
|
|
35
|
-
this.topicToRemoteDomainVerified[topic] = true
|
|
36
|
-
await Promise.all(this.onDomainVerifiedCallbacks[topic].map((callback) => callback()))
|
|
37
|
-
} else if (request.method === "closed_page") {
|
|
38
|
-
// TODO: Implement
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* @notice Scan a credentirequest QR code.
|
|
44
|
-
* @returns
|
|
45
|
-
*/
|
|
46
|
-
public async scan(
|
|
47
|
-
url: string,
|
|
48
|
-
{
|
|
49
|
-
keyPairOverride,
|
|
50
|
-
}: {
|
|
51
|
-
keyPairOverride?: { privateKey: Uint8Array; publicKey: Uint8Array }
|
|
52
|
-
} = {},
|
|
53
|
-
) {
|
|
54
|
-
const parsedUrl = new URL(url)
|
|
55
|
-
const domain = parsedUrl.searchParams.get("d")
|
|
56
|
-
const topic = parsedUrl.searchParams.get("t")
|
|
57
|
-
const pubkeyHex = parsedUrl.searchParams.get("p")
|
|
58
|
-
|
|
59
|
-
if (!domain || !topic || !pubkeyHex) {
|
|
60
|
-
throw new Error("Invalid URL: missing required parameters")
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const pubkey = new Uint8Array(Buffer.from(pubkeyHex, "hex"))
|
|
64
|
-
|
|
65
|
-
this.domain = domain
|
|
66
|
-
const keyPair = keyPairOverride || (await generateECDHKeyPair())
|
|
67
|
-
|
|
68
|
-
this.topicToKeyPair[topic] = {
|
|
69
|
-
privateKey: keyPair.privateKey,
|
|
70
|
-
publicKey: keyPair.publicKey,
|
|
71
|
-
}
|
|
72
|
-
this.topicToRemotePublicKey[topic] = pubkey
|
|
73
|
-
this.topicToSharedSecret[topic] = await getSharedSecret(
|
|
74
|
-
bytesToHex(keyPair.privateKey),
|
|
75
|
-
bytesToHex(pubkey),
|
|
76
|
-
)
|
|
77
|
-
this.topicToRemoteDomainVerified[topic] = false
|
|
78
|
-
this.onDomainVerifiedCallbacks[topic] = []
|
|
79
|
-
this.onBridgeConnectCallbacks[topic] = []
|
|
80
|
-
|
|
81
|
-
// Set up WebSocket connection
|
|
82
|
-
const wsClient = getWebSocketClient(
|
|
83
|
-
`wss://bridge.zkpassport.id?topic=${topic}&pubkey=${bytesToHex(keyPair.publicKey)}`,
|
|
84
|
-
)
|
|
85
|
-
this.topicToWebSocketClient[topic] = wsClient
|
|
86
|
-
|
|
87
|
-
wsClient.onopen = async () => {
|
|
88
|
-
logger.info("[mobile] WebSocket connection established")
|
|
89
|
-
await Promise.all(this.onBridgeConnectCallbacks[topic].map((callback) => callback()))
|
|
90
|
-
// Server sends handshake automatically (when it sees a pubkey in websocket URI)
|
|
91
|
-
// wsClient.send(
|
|
92
|
-
// JSON.stringify(
|
|
93
|
-
// createJsonRpcRequest('handshake', {
|
|
94
|
-
// pubkey: bytesToHex(keyPair.publicKey),
|
|
95
|
-
// }),
|
|
96
|
-
// ),
|
|
97
|
-
// )
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
wsClient.addEventListener("message", async (event: any) => {
|
|
101
|
-
logger.info("[mobile] Received message:", event.data)
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
const data: JsonRpcRequest = JSON.parse(event.data)
|
|
105
|
-
const originDomain = data.origin ? new URL(data.origin).hostname : undefined
|
|
106
|
-
// Origin domain must match domain in QR code
|
|
107
|
-
if (originDomain !== this.domain) {
|
|
108
|
-
logger.warn(
|
|
109
|
-
`[mobile] Origin does not match domain in QR code. Expected ${this.domain} but got ${originDomain}`,
|
|
110
|
-
)
|
|
111
|
-
return
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (data.method === "encryptedMessage") {
|
|
115
|
-
// Decode the payload from base64 to Uint8Array
|
|
116
|
-
const payload = new Uint8Array(
|
|
117
|
-
atob(data.params.payload)
|
|
118
|
-
.split("")
|
|
119
|
-
.map((c) => c.charCodeAt(0)),
|
|
120
|
-
)
|
|
121
|
-
try {
|
|
122
|
-
// Decrypt the payload using the shared secret
|
|
123
|
-
const decrypted = await decrypt(payload, this.topicToSharedSecret[topic], topic)
|
|
124
|
-
const decryptedJson: JsonRpcRequest = JSON.parse(decrypted)
|
|
125
|
-
await this.handleEncryptedMessage(topic, decryptedJson, data)
|
|
126
|
-
} catch (error) {
|
|
127
|
-
logger.error("[mobile] Error decrypting message:", error)
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
} catch (error) {
|
|
131
|
-
logger.error("[mobile] Error:", error)
|
|
132
|
-
}
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
wsClient.onerror = (error: Event) => {
|
|
136
|
-
logger.error("[mobile] WebSocket error:", error)
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return {
|
|
140
|
-
domain: this.domain,
|
|
141
|
-
requestId: topic,
|
|
142
|
-
isBridgeConnected: () => this.topicToWebSocketClient[topic].readyState === WebSocket.OPEN,
|
|
143
|
-
isDomainVerified: () => this.topicToRemoteDomainVerified[topic] === true,
|
|
144
|
-
onDomainVerified: (callback: () => void) =>
|
|
145
|
-
this.onDomainVerifiedCallbacks[topic].push(callback),
|
|
146
|
-
onBridgeConnect: (callback: () => void) =>
|
|
147
|
-
this.onBridgeConnectCallbacks[topic].push(callback),
|
|
148
|
-
notifyReject: async () => {
|
|
149
|
-
await sendEncryptedJsonRpcRequest(
|
|
150
|
-
"reject",
|
|
151
|
-
null,
|
|
152
|
-
this.topicToSharedSecret[topic],
|
|
153
|
-
topic,
|
|
154
|
-
this.topicToWebSocketClient[topic],
|
|
155
|
-
)
|
|
156
|
-
},
|
|
157
|
-
notifyAccept: async () => {
|
|
158
|
-
await sendEncryptedJsonRpcRequest(
|
|
159
|
-
"accept",
|
|
160
|
-
null,
|
|
161
|
-
this.topicToSharedSecret[topic],
|
|
162
|
-
topic,
|
|
163
|
-
this.topicToWebSocketClient[topic],
|
|
164
|
-
)
|
|
165
|
-
},
|
|
166
|
-
notifyDone: async (proof: any) => {
|
|
167
|
-
await sendEncryptedJsonRpcRequest(
|
|
168
|
-
"done",
|
|
169
|
-
{ proof },
|
|
170
|
-
this.topicToSharedSecret[topic],
|
|
171
|
-
topic,
|
|
172
|
-
this.topicToWebSocketClient[topic],
|
|
173
|
-
)
|
|
174
|
-
},
|
|
175
|
-
notifyError: async (error: string) => {
|
|
176
|
-
await sendEncryptedJsonRpcRequest(
|
|
177
|
-
"error",
|
|
178
|
-
{ error },
|
|
179
|
-
this.topicToSharedSecret[topic],
|
|
180
|
-
topic,
|
|
181
|
-
this.topicToWebSocketClient[topic],
|
|
182
|
-
)
|
|
183
|
-
},
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
package/src/websocket.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export function getWebSocketClient(url: string, origin?: string) {
|
|
2
|
-
if (typeof window !== "undefined" && window.WebSocket) {
|
|
3
|
-
// Browser environment
|
|
4
|
-
return new WebSocket(url)
|
|
5
|
-
} else {
|
|
6
|
-
// Node.js environment
|
|
7
|
-
const WebSocket = require("ws")
|
|
8
|
-
return new WebSocket(url, {
|
|
9
|
-
headers: {
|
|
10
|
-
Origin: origin || "nodejs",
|
|
11
|
-
},
|
|
12
|
-
}) as import("ws").WebSocket
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export type WebSocketClient = ReturnType<typeof getWebSocketClient>
|