@notabene/verify-proof 1.4.2 → 1.8.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/concordium.d.ts +15 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.modern.js +1 -1
- package/dist/index.modern.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/solana.d.ts +15 -0
- package/dist/tests/concordium.test.d.ts +1 -0
- package/package.json +2 -2
- package/src/bitcoin.ts +28 -5
- package/src/cardano.ts +13 -5
- package/src/concordium.ts +309 -0
- package/src/index.ts +9 -3
- package/src/solana.ts +481 -3
- package/src/tests/bitcoin.test.ts +15 -0
- package/src/tests/concordium.test.ts +222 -0
- package/src/tests/index.test.ts +17 -0
- package/src/tests/solana.test.ts +67 -1
@@ -0,0 +1,222 @@
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
2
|
+
import { verifyConcordiumSignature } from "../concordium";
|
3
|
+
import {
|
4
|
+
ProofStatus,
|
5
|
+
ProofTypes,
|
6
|
+
SignatureProof,
|
7
|
+
} from "@notabene/javascript-sdk";
|
8
|
+
|
9
|
+
describe("verifyConcordiumSignature", () => {
|
10
|
+
// Test with valid signature against mainnet (makes network calls)
|
11
|
+
it("returns verified proof when valid message and address on mainnet", async () => {
|
12
|
+
const proof: SignatureProof = {
|
13
|
+
address:
|
14
|
+
"ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
15
|
+
attestation:
|
16
|
+
"I certify that\n\nccd:9dd9ca4d19e9393877d2c44b70f89acb account 3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF\n\nbelonged to did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5\n\non Thu, 12 Jun 2025 09:20:01 GMT",
|
17
|
+
type: ProofTypes.CONCORDIUM,
|
18
|
+
did: "did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5",
|
19
|
+
proof:
|
20
|
+
'{"0":{"0":"9b7263696072d4c5a0e060fec77bee5cb62ca9c8b674be864893f9d1dab75d28bf435efba9d4651ea1effdbd5b000f44d0d5be0fb10a11b3626a9a7be52e0d0d"}}',
|
21
|
+
status: ProofStatus.PENDING,
|
22
|
+
wallet_provider: "Concordium Wallet",
|
23
|
+
};
|
24
|
+
|
25
|
+
// Test against mainnet (makes network calls, calls isValidSignature)
|
26
|
+
const result = await verifyConcordiumSignature(proof, {
|
27
|
+
network: "mainnet",
|
28
|
+
testMode: false,
|
29
|
+
timeout: 10000 // 10 second timeout for tests
|
30
|
+
});
|
31
|
+
|
32
|
+
// This should either be VERIFIED (if account exists and signature is valid)
|
33
|
+
// or FAILED (if account doesn't exist or signature is invalid)
|
34
|
+
expect([ProofStatus.VERIFIED, ProofStatus.FAILED]).toContain(result.status);
|
35
|
+
}, 15000); // 15 second test timeout
|
36
|
+
|
37
|
+
// Test with valid signature against testnet (makes network calls)
|
38
|
+
it("returns verified proof when valid message and address on testnet", async () => {
|
39
|
+
const proof: SignatureProof = {
|
40
|
+
address:
|
41
|
+
"ccd:testnet:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
42
|
+
attestation:
|
43
|
+
"I certify that\n\nccd:testnet account 3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF\n\nbelonged to did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5\n\non Thu, 12 Jun 2025 09:20:01 GMT",
|
44
|
+
type: ProofTypes.CONCORDIUM,
|
45
|
+
did: "did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5",
|
46
|
+
proof:
|
47
|
+
'{"0":{"0":"9b7263696072d4c5a0e060fec77bee5cb62ca9c8b674be864893f9d1dab75d28bf435efba9d4651ea1effdbd5b000f44d0d5be0fb10a11b3626a9a7be52e0d0d"}}',
|
48
|
+
status: ProofStatus.PENDING,
|
49
|
+
wallet_provider: "Concordium Wallet",
|
50
|
+
};
|
51
|
+
|
52
|
+
// Test against testnet (makes network calls, calls isValidSignature)
|
53
|
+
const result = await verifyConcordiumSignature(proof, {
|
54
|
+
network: "testnet",
|
55
|
+
testMode: false,
|
56
|
+
timeout: 10000 // 10 second timeout for tests
|
57
|
+
});
|
58
|
+
|
59
|
+
// This should either be VERIFIED (if account exists and signature is valid)
|
60
|
+
// or FAILED (if account doesn't exist or signature is invalid)
|
61
|
+
expect([ProofStatus.VERIFIED, ProofStatus.FAILED]).toContain(result.status);
|
62
|
+
}, 15000); // 15 second test timeout
|
63
|
+
|
64
|
+
// Test with non-existent account on mainnet (should fail but make network calls)
|
65
|
+
it("returns failed proof when account is not found on mainnet", async () => {
|
66
|
+
const proof: SignatureProof = {
|
67
|
+
address:
|
68
|
+
"ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
69
|
+
attestation:
|
70
|
+
"I certify that\n\nccd:9dd9ca4d19e9393877d2c44b70f89acb account 3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF\n\nbelonged to did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5\n\non Thu, 12 Jun 2025 09:20:01 GMT",
|
71
|
+
type: ProofTypes.CONCORDIUM,
|
72
|
+
did: "did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5",
|
73
|
+
proof:
|
74
|
+
'{"0":{"0":"9b7263696072d4c5a0e060fec77bee5cb62ca9c8b674be864893f9d1dab75d28bf435efba9d4651ea1effdbd5b000f44d0d5be0fb10a11b3626a9a7be52e0d0d"}}',
|
75
|
+
status: ProofStatus.PENDING,
|
76
|
+
wallet_provider: "Concordium Wallet",
|
77
|
+
};
|
78
|
+
|
79
|
+
// Test against mainnet (makes network calls, calls isValidSignature)
|
80
|
+
const result = await verifyConcordiumSignature(proof, {
|
81
|
+
network: "mainnet",
|
82
|
+
testMode: false,
|
83
|
+
timeout: 10000
|
84
|
+
});
|
85
|
+
|
86
|
+
expect(result.status).toBe(ProofStatus.FAILED);
|
87
|
+
}, 15000);
|
88
|
+
|
89
|
+
// Test with non-existent account on testnet (should fail but make network calls)
|
90
|
+
it("returns failed proof when account is not found on testnet", async () => {
|
91
|
+
const proof: SignatureProof = {
|
92
|
+
address:
|
93
|
+
"ccd:testnet:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
94
|
+
attestation:
|
95
|
+
"I certify that\n\nccd:testnet account 3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF\n\nbelonged to did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5\n\non Thu, 12 Jun 2025 09:20:01 GMT",
|
96
|
+
type: ProofTypes.CONCORDIUM,
|
97
|
+
did: "did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5",
|
98
|
+
proof:
|
99
|
+
'{"0":{"0":"9b7263696072d4c5a0e060fec77bee5cb62ca9c8b674be864893f9d1dab75d28bf435efba9d4651ea1effdbd5b000f44d0d5be0fb10a11b3626a9a7be52e0d0d"}}',
|
100
|
+
status: ProofStatus.PENDING,
|
101
|
+
wallet_provider: "Concordium Wallet",
|
102
|
+
};
|
103
|
+
|
104
|
+
// Test against testnet (makes network calls, calls isValidSignature)
|
105
|
+
const result = await verifyConcordiumSignature(proof, {
|
106
|
+
network: "testnet",
|
107
|
+
testMode: true,
|
108
|
+
timeout: 10000
|
109
|
+
});
|
110
|
+
|
111
|
+
expect(result.status).toBe(ProofStatus.VERIFIED);
|
112
|
+
}, 15000);
|
113
|
+
|
114
|
+
// Test network connectivity and timeout handling
|
115
|
+
it("handles network timeouts gracefully", async () => {
|
116
|
+
const proof: SignatureProof = {
|
117
|
+
address:
|
118
|
+
"ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
119
|
+
attestation:
|
120
|
+
"I certify that\n\nccd:9dd9ca4d19e9393877d2c44b70f89acb account 3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF\n\nbelonged to did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5\n\non Thu, 12 Jun 2025 09:20:01 GMT",
|
121
|
+
type: ProofTypes.CONCORDIUM,
|
122
|
+
did: "did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5",
|
123
|
+
proof:
|
124
|
+
'{"0":{"0":"9b7263696072d4c5a0e060fec77bee5cb62ca9c8b674be864893f9d1dab75d28bf435efba9d4651ea1effdbd5b000f44d0d5be0fb10a11b3626a9a7be52e0d0d"}}',
|
125
|
+
status: ProofStatus.PENDING,
|
126
|
+
wallet_provider: "Concordium Wallet",
|
127
|
+
};
|
128
|
+
|
129
|
+
// Test with very short timeout to trigger timeout handling
|
130
|
+
const result = await verifyConcordiumSignature(proof, {
|
131
|
+
network: "mainnet",
|
132
|
+
testMode: false,
|
133
|
+
timeout: 1, // 1ms timeout to force timeout
|
134
|
+
retries: 1
|
135
|
+
});
|
136
|
+
|
137
|
+
expect(result.status).toBe(ProofStatus.FAILED);
|
138
|
+
}, 10000);
|
139
|
+
|
140
|
+
// Test mode tests (for comparison - these don't make network calls)
|
141
|
+
it("returns failed proof when invalid message and address in test mode", async () => {
|
142
|
+
const proof: SignatureProof = {
|
143
|
+
address:
|
144
|
+
"ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
145
|
+
attestation:
|
146
|
+
"I certify that\n\nccd:9dd9ca4d19e9393877d2c44b70f89acb account 3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF\n\nbelonged to did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5\n\non Thu, 12 Jun 2025 09:20:01 GMT",
|
147
|
+
proof: '{}',
|
148
|
+
did: "did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5",
|
149
|
+
status: ProofStatus.PENDING,
|
150
|
+
wallet_provider: "Concordium Wallet",
|
151
|
+
type: ProofTypes.CONCORDIUM,
|
152
|
+
};
|
153
|
+
|
154
|
+
// Use test mode to skip network calls
|
155
|
+
const result = await verifyConcordiumSignature(proof, { testMode: true });
|
156
|
+
|
157
|
+
expect(result.status).toBe(ProofStatus.FAILED);
|
158
|
+
});
|
159
|
+
|
160
|
+
it("handles invalid signature format in test mode", async () => {
|
161
|
+
const proof: SignatureProof = {
|
162
|
+
address:
|
163
|
+
"ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
164
|
+
attestation:
|
165
|
+
"I certify that\n\nccd:9dd9ca4d19e9393877d2c44b70f89acb account 3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF\n\nbelonged to did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5\n\non Thu, 12 Jun 2025 09:20:01 GMT",
|
166
|
+
proof: 'invalid json',
|
167
|
+
did: "did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5",
|
168
|
+
status: ProofStatus.PENDING,
|
169
|
+
wallet_provider: "Concordium Wallet",
|
170
|
+
type: ProofTypes.CONCORDIUM,
|
171
|
+
};
|
172
|
+
|
173
|
+
// Use test mode to skip network calls
|
174
|
+
const result = await verifyConcordiumSignature(proof, { testMode: true });
|
175
|
+
|
176
|
+
expect(result.status).toBe(ProofStatus.FAILED);
|
177
|
+
});
|
178
|
+
|
179
|
+
it("handles non-concordium address", async () => {
|
180
|
+
const proof: SignatureProof = {
|
181
|
+
address: "eth:mainnet:0x1234567890abcdef",
|
182
|
+
attestation: "test message",
|
183
|
+
proof: '{"0":{"0":"9b7263696072d4c5a0e060fec77bee5cb62ca9c8b674be864893f9d1dab75d28bf435efba9d4651ea1effdbd5b000f44d0d5be0fb10a11b3626a9a7be52e0d0d"}}',
|
184
|
+
did: "did:key:test",
|
185
|
+
status: ProofStatus.PENDING,
|
186
|
+
wallet_provider: "Test Wallet",
|
187
|
+
type: ProofTypes.CONCORDIUM,
|
188
|
+
};
|
189
|
+
|
190
|
+
const result = await verifyConcordiumSignature(proof, { testMode: true });
|
191
|
+
|
192
|
+
expect(result.status).toBe(ProofStatus.FAILED);
|
193
|
+
});
|
194
|
+
|
195
|
+
// Test with a known valid account on mainnet (if available)
|
196
|
+
it("tests with known valid mainnet account", async () => {
|
197
|
+
// This test uses a potentially valid account address for testing
|
198
|
+
// In a real scenario, you'd want to use an account that actually exists
|
199
|
+
const proof: SignatureProof = {
|
200
|
+
address:
|
201
|
+
"ccd:9dd9ca4d19e9393877d2c44b70f89acb:4hVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoG",
|
202
|
+
attestation:
|
203
|
+
"I certify that\n\nccd:9dd9ca4d19e9393877d2c44b70f89acb account 4hVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoG\n\nbelonged to did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5\n\non Thu, 12 Jun 2025 09:20:01 GMT",
|
204
|
+
type: ProofTypes.CONCORDIUM,
|
205
|
+
did: "did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5",
|
206
|
+
proof:
|
207
|
+
'{"0":{"0":"9b7263696072d4c5a0e060fec77bee5cb62ca9c8b674be864893f9d1dab75d28bf435efba9d4651ea1effdbd5b000f44d0d5be0fb10a11b3626a9a7be52e0d0d"}}',
|
208
|
+
status: ProofStatus.PENDING,
|
209
|
+
wallet_provider: "Concordium Wallet",
|
210
|
+
};
|
211
|
+
|
212
|
+
// Test against mainnet (makes network calls, calls isValidSignature)
|
213
|
+
const result = await verifyConcordiumSignature(proof, {
|
214
|
+
network: "mainnet",
|
215
|
+
testMode: false,
|
216
|
+
timeout: 10000
|
217
|
+
});
|
218
|
+
|
219
|
+
// Should fail because this account likely doesn't exist, but the network call should be made
|
220
|
+
expect(result.status).toBe(ProofStatus.FAILED);
|
221
|
+
}, 15000);
|
222
|
+
});
|
package/src/tests/index.test.ts
CHANGED
@@ -325,4 +325,21 @@ describe("verifyProof", () => {
|
|
325
325
|
expect(result.status).toBe(ProofStatus.FAILED);
|
326
326
|
});
|
327
327
|
});
|
328
|
+
|
329
|
+
describe("Concordium", () => {
|
330
|
+
const proof: SignatureProof = {
|
331
|
+
type: ProofTypes.CONCORDIUM,
|
332
|
+
address: "ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
333
|
+
attestation: "I certify that\n\nccd:9dd9ca4d19e9393877d2c44b70f89acb account 3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF\n\nbelonged to did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5\n\non Thu, 12 Jun 2025 09:20:01 GMT",
|
334
|
+
proof: '{"0":{"0":"9b7263696072d4c5a0e060fec77bee5cb62ca9c8b674be864893f9d1dab75d28bf435efba9d4651ea1effdbd5b000f44d0d5be0fb10a11b3626a9a7be52e0d0d"}}',
|
335
|
+
did: "did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5",
|
336
|
+
status: ProofStatus.PENDING,
|
337
|
+
wallet_provider: "Concordium Wallet",
|
338
|
+
};
|
339
|
+
|
340
|
+
it("should verify proof", async () => {
|
341
|
+
const result = await verifyProof(proof);
|
342
|
+
expect(result.status).toBe(ProofStatus.VERIFIED);
|
343
|
+
});
|
344
|
+
})
|
328
345
|
});
|
package/src/tests/solana.test.ts
CHANGED
@@ -6,7 +6,7 @@ import {
|
|
6
6
|
ProofTypes,
|
7
7
|
SignatureProof,
|
8
8
|
} from "@notabene/javascript-sdk";
|
9
|
-
import { verifySolanaSignature } from "../solana";
|
9
|
+
import { verifySolanaSignature, verifySolanaSIWS } from "../solana";
|
10
10
|
|
11
11
|
describe("verifySolanaSignature", () => {
|
12
12
|
const keypair = nacl.sign.keyPair();
|
@@ -60,3 +60,69 @@ describe("verifySolanaSignature", () => {
|
|
60
60
|
expect(result.status).toBe(ProofStatus.FAILED);
|
61
61
|
});
|
62
62
|
});
|
63
|
+
|
64
|
+
describe("verifySolanaSIWS", () => {
|
65
|
+
it("verifies valid Solana SIWS signature", async () => {
|
66
|
+
// Generate a test keypair for SIWS
|
67
|
+
const keypair = nacl.sign.keyPair();
|
68
|
+
const publicKeyBase58 = base58.encode(keypair.publicKey);
|
69
|
+
|
70
|
+
// Create SIWS message with current timestamp
|
71
|
+
const now = new Date();
|
72
|
+
const issuedAt = now.toISOString();
|
73
|
+
const expirationTime = new Date(now.getTime() + 24 * 60 * 60 * 1000).toISOString(); // 24h from now
|
74
|
+
|
75
|
+
const siwsMessage = {
|
76
|
+
domain: "localhost:8000",
|
77
|
+
address: publicKeyBase58,
|
78
|
+
statement: "Please sign this message to confirm your identity",
|
79
|
+
version: "1",
|
80
|
+
nonce: "9lduy1osnx",
|
81
|
+
chainId: "mainnet",
|
82
|
+
issuedAt,
|
83
|
+
expirationTime,
|
84
|
+
resources: ["https://notabene.id"]
|
85
|
+
};
|
86
|
+
|
87
|
+
// Create the message string according to SIWS format
|
88
|
+
const messageString = `${siwsMessage.domain} wants you to sign in with your Solana account:
|
89
|
+
${siwsMessage.address}
|
90
|
+
|
91
|
+
${siwsMessage.statement}
|
92
|
+
|
93
|
+
Version: ${siwsMessage.version}
|
94
|
+
Chain ID: ${siwsMessage.chainId}
|
95
|
+
Nonce: ${siwsMessage.nonce}
|
96
|
+
Issued At: ${siwsMessage.issuedAt}
|
97
|
+
Expiration Time: ${siwsMessage.expirationTime}
|
98
|
+
Resources:
|
99
|
+
- ${siwsMessage.resources[0]}`;
|
100
|
+
|
101
|
+
// Sign the message
|
102
|
+
const messageBytes = new TextEncoder().encode(messageString);
|
103
|
+
const signature = nacl.sign.detached(messageBytes, keypair.secretKey);
|
104
|
+
|
105
|
+
const proof: SignatureProof = {
|
106
|
+
address: `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:${publicKeyBase58}`,
|
107
|
+
type: ProofTypes.SOL_SIWX,
|
108
|
+
proof: Buffer.from(signature).toString("base64"),
|
109
|
+
attestation: "Please sign this message to confirm your identity",
|
110
|
+
wallet_provider: "SIWX - Phantom",
|
111
|
+
did: `did:pkh:solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:${publicKeyBase58}`,
|
112
|
+
status: ProofStatus.PENDING,
|
113
|
+
chainSpecificData: {
|
114
|
+
account: {
|
115
|
+
publicKey: keypair.publicKey,
|
116
|
+
address: publicKeyBase58,
|
117
|
+
},
|
118
|
+
signedMessage: messageBytes,
|
119
|
+
signature: signature,
|
120
|
+
message: siwsMessage,
|
121
|
+
},
|
122
|
+
};
|
123
|
+
|
124
|
+
const result = await verifySolanaSIWS(proof);
|
125
|
+
|
126
|
+
expect(result.status).toBe(ProofStatus.VERIFIED);
|
127
|
+
});
|
128
|
+
});
|