@notabene/verify-proof 1.11.1-next.1 → 1.12.0-next.2
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-QRNV23F7.js +45 -0
- package/dist/concordium-QRNV23F7.js.map +1 -0
- package/dist/concordium-YD34X2QM.cjs +47 -0
- package/dist/concordium-YD34X2QM.cjs.map +1 -0
- package/dist/index.cjs +1 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/src/concordium.ts +40 -284
- package/src/index.ts +0 -1
- package/src/tests/bitcoin.test.ts +335 -16
- package/src/tests/concordium.test.ts +96 -134
- package/src/tests/index.test.ts +7 -7
- package/dist/concordium-HQC37GCK.cjs +0 -188
- package/dist/concordium-HQC37GCK.cjs.map +0 -1
- package/dist/concordium-XX4XYLLU.js +0 -186
- package/dist/concordium-XX4XYLLU.js.map +0 -1
|
@@ -7,216 +7,178 @@ import {
|
|
|
7
7
|
} from "@notabene/javascript-sdk";
|
|
8
8
|
|
|
9
9
|
describe("verifyConcordiumSignature", () => {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
it("returns verified proof when valid presentation on testnet", async () => {
|
|
11
|
+
const proof: SignatureProof = {
|
|
12
|
+
"address": "ccd:9dd9ca4d19e9393877d2c44b70f89acb:3Soqc3mEU5WC4R9Qho9fxm4CJ1157q6qsJbPvtGV8iT8FbQdv2",
|
|
13
|
+
"attestation": "b74a8e64f1568f1fb22a57b033bc8ef2b8f6ba23ff8e831e7abfbb671927fda1",
|
|
14
|
+
"type": ProofTypes.CONCORDIUM,
|
|
15
|
+
"did": "did:pkh:ccd:9dd9ca4d19e9393877d2c44b70f89acb:3Soqc3mEU5WC4R9Qho9fxm4CJ1157q6qsJbPvtGV8iT8FbQdv2",
|
|
16
|
+
"proof": "{\"presentationContext\":\"b74a8e64f1568f1fb22a57b033bc8ef2b8f6ba23ff8e831e7abfbb671927fda1\",\"proof\":{\"created\":\"2025-12-10T10:39:14.395Z\",\"proofValue\":[],\"type\":\"ConcordiumWeakLinkingProofV1\"},\"type\":\"VerifiablePresentation\",\"verifiableCredential\":[{\"credentialSubject\":{\"id\":\"did:ccd:mainnet:cred:91a1f28bc42222096856a54fb157f7c80b9827457d4ece682b9592bca964948f01dce51a7deb392ea9bd0c1e1630d17b\",\"proof\":{\"created\":\"2025-12-10T10:39:14.395Z\",\"proofValue\":[{\"proof\":\"988f08d03bc8adaac4d51986dfaafe70874ab3bb22e8c09c32da5bfcd0ff0407203770533220e74ba4386acb36f7b7288e38c461279f7edf6f41b8b285d629280a5ca297e7fc42155222c5b1ad3cc74f770d5c87addbba6935ade425460b1616a587d9c45a4676f7fc751b31110cd37b25998c61d7d85c84e4db155491665e556778a9784e557799f06531bafe6b4b8ca2ce386d66f7759079eaff74b1e519550c9d137a13851c0987ee434feb6dae0ca659d67661b27e92d7cca9567a1a6ecd2175c574f5a6c2f4691597cbf3680f65abab72633d050746211c56961277064d694a31c2a93ef3b64c4957ff8261978a53d8b65d40ff23ddc7ee65d0ea0817702be58fbaec3954322e00667c6c94736eba8d3aa3f2686b89f257ca34c90ae1200000000785c57df969a45b25b1d39bdb388d33a756147e98f285891e83ce58eab3bb1f466c25a0946fc62513b16f3f02397b15418ebc131b5e1a8c0f05d6983cd3c44cc40ab8364c1aa209c2e8c0e8e84694587053542fd5cbb918f025723a5a0c200f08875728874571f50cb8b54d1c8629a10c76f0a982ad667efcfa280943f7c8753d3fa859a8d5d9837e6bdd5026d54546a3ae5918055208b5d2f77e0206d7861b4c472c634ec4cece107aeb14c42fe3d801aba38aa38e15785152e7c061561a5594a6cabb34f469b3121c15437df5d6ba0638ba3a192f2106d07e2f7bfd73310f669d3e8bdeb1b43244455d7bd7fa5917a1af2b23dc3433dac68ee4571bea2b0c22ce2ed665e22cee5676b9c3de0169926e72c847f7e3f2caa671e55ab5c4530205845b08ee12bba954f4a41e5638b05043a93ed212f402273c2b477f95f7b82ddbe4621f1758f80fcec726df755a76d0f585eda201dff2b91147cca5eae5d5319b7e1438c0f4af42b9fe4f7e845d0c643328ddd5dead96bfd345ae972312650a9ab6e6d7fa3d3f5d1fe68e5ff513095e3caa5bb21bec64dae007e62b4494986ac40b9e14b61255a84ea51780b8439adaeeae0b83a8bcee382491dd8e7b2f1921e8eeffe39a45bffd470b5a8f74d82ccdb8ccda651c387844f61704cc04f51d65fb9069900cb1febfc0b2ba02ffc857c45c12a7b306440e6627995d67353e9f6327b6f6cfa6ad0b859ea904f087a5b29a888043ba21ccb3e36da0a2da797310c2f2ce56c275d6fc48b60aade4b4e6bb6ff62d5f5be1a529c8d71cab2b0904fa306cb779a897872f5f047df7c7bee150ca6be6f3ad840a862ecc0793bb27f0594ff8741a4ab426b53d72acbdbde6c20a7c4399ca181d81a4b0ac437c23220f52ff8e9095ae35a53f8cd58913c4999a8153b656fabb162feafe8fc8708eaeb2b5ce0d347e5733cd685783271eaf564e05efce61996686ee9f50663204841ff30416061721a5cab8e1c80708809b58d2bc9c402da453e486ce08e0ec6c72c1f0e9dc15\",\"type\":\"AttributeInRange\"}],\"type\":\"ConcordiumZKProofV3\"},\"statement\":[{\"attributeTag\":\"dob\",\"lower\":\"19300101\",\"type\":\"AttributeInRange\",\"upper\":\"99990101\"}]},\"issuer\":\"did:ccd:mainnet:idp:1\",\"type\":[\"VerifiableCredential\",\"ConcordiumVerifiableCredential\"]}]}",
|
|
17
|
+
"wallet_provider": "Concordium Browser",
|
|
18
|
+
"status": ProofStatus.PENDING
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const result = await verifyConcordiumSignature(proof);
|
|
22
|
+
|
|
23
|
+
expect(result.status).toBe(ProofStatus.VERIFIED);
|
|
24
|
+
}, 15000);
|
|
25
|
+
|
|
26
|
+
it("returns failed proof when proof field contains invalid JSON", async () => {
|
|
12
27
|
const proof: SignatureProof = {
|
|
13
28
|
address:
|
|
14
29
|
"ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
|
15
30
|
attestation:
|
|
16
|
-
"
|
|
31
|
+
"d9380ba535f3fc379d507e7fabba726104ff4640b05a7c5696d0b0830d3a1983",
|
|
17
32
|
type: ProofTypes.CONCORDIUM,
|
|
18
|
-
did: "did:
|
|
19
|
-
proof:
|
|
20
|
-
|
|
33
|
+
did: "did:pkh:ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
|
34
|
+
proof: "invalid json string",
|
|
35
|
+
wallet_provider: "Concordium Browser",
|
|
21
36
|
status: ProofStatus.PENDING,
|
|
22
|
-
wallet_provider: "Concordium Wallet",
|
|
23
37
|
};
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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 () => {
|
|
38
|
+
|
|
39
|
+
const result = await verifyConcordiumSignature(proof);
|
|
40
|
+
expect(result.status).toBe(ProofStatus.FAILED);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("returns failed proof when proof field is empty string", async () => {
|
|
39
44
|
const proof: SignatureProof = {
|
|
40
45
|
address:
|
|
41
|
-
"ccd:
|
|
46
|
+
"ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
|
42
47
|
attestation:
|
|
43
|
-
"
|
|
48
|
+
"d9380ba535f3fc379d507e7fabba726104ff4640b05a7c5696d0b0830d3a1983",
|
|
44
49
|
type: ProofTypes.CONCORDIUM,
|
|
45
|
-
did: "did:
|
|
46
|
-
proof:
|
|
47
|
-
|
|
50
|
+
did: "did:pkh:ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
|
51
|
+
proof: "",
|
|
52
|
+
wallet_provider: "Concordium Browser",
|
|
48
53
|
status: ProofStatus.PENDING,
|
|
49
|
-
wallet_provider: "Concordium Wallet",
|
|
50
54
|
};
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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 () => {
|
|
55
|
+
|
|
56
|
+
const result = await verifyConcordiumSignature(proof);
|
|
57
|
+
expect(result.status).toBe(ProofStatus.FAILED);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("returns failed proof when proof field is empty object", async () => {
|
|
66
61
|
const proof: SignatureProof = {
|
|
67
62
|
address:
|
|
68
63
|
"ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
|
69
64
|
attestation:
|
|
70
|
-
"
|
|
65
|
+
"d9380ba535f3fc379d507e7fabba726104ff4640b05a7c5696d0b0830d3a1983",
|
|
71
66
|
type: ProofTypes.CONCORDIUM,
|
|
72
|
-
did: "did:
|
|
73
|
-
proof:
|
|
74
|
-
|
|
67
|
+
did: "did:pkh:ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
|
68
|
+
proof: "{}",
|
|
69
|
+
wallet_provider: "Concordium Browser",
|
|
75
70
|
status: ProofStatus.PENDING,
|
|
76
|
-
wallet_provider: "Concordium Wallet",
|
|
77
71
|
};
|
|
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
72
|
|
|
73
|
+
const result = await verifyConcordiumSignature(proof);
|
|
86
74
|
expect(result.status).toBe(ProofStatus.FAILED);
|
|
87
|
-
}
|
|
75
|
+
});
|
|
88
76
|
|
|
89
|
-
|
|
90
|
-
it("returns failed proof when account is not found on testnet", async () => {
|
|
77
|
+
it("returns failed proof when presentation is missing verifiableCredential", async () => {
|
|
91
78
|
const proof: SignatureProof = {
|
|
92
79
|
address:
|
|
93
|
-
"ccd:
|
|
80
|
+
"ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
|
94
81
|
attestation:
|
|
95
|
-
"
|
|
82
|
+
"d9380ba535f3fc379d507e7fabba726104ff4640b05a7c5696d0b0830d3a1983",
|
|
96
83
|
type: ProofTypes.CONCORDIUM,
|
|
97
|
-
did: "did:
|
|
84
|
+
did: "did:pkh:ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
|
98
85
|
proof:
|
|
99
|
-
'{"
|
|
86
|
+
'{"presentationContext":"d9380ba535f3fc379d507e7fabba726104ff4640b05a7c5696d0b0830d3a1983","proof":{"created":"2025-11-22T15:53:04.074Z","proofValue":[],"type":"ConcordiumWeakLinkingProofV1"},"type":"VerifiablePresentation"}',
|
|
87
|
+
wallet_provider: "Concordium Browser",
|
|
100
88
|
status: ProofStatus.PENDING,
|
|
101
|
-
wallet_provider: "Concordium Wallet",
|
|
102
89
|
};
|
|
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
90
|
|
|
111
|
-
|
|
112
|
-
|
|
91
|
+
const result = await verifyConcordiumSignature(proof);
|
|
92
|
+
expect(result.status).toBe(ProofStatus.FAILED);
|
|
93
|
+
});
|
|
113
94
|
|
|
114
|
-
|
|
115
|
-
it("handles network timeouts gracefully", async () => {
|
|
95
|
+
it("returns failed proof when presentation has empty verifiableCredential array", async () => {
|
|
116
96
|
const proof: SignatureProof = {
|
|
117
97
|
address:
|
|
118
98
|
"ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
|
119
99
|
attestation:
|
|
120
|
-
"
|
|
100
|
+
"d9380ba535f3fc379d507e7fabba726104ff4640b05a7c5696d0b0830d3a1983",
|
|
121
101
|
type: ProofTypes.CONCORDIUM,
|
|
122
|
-
did: "did:
|
|
102
|
+
did: "did:pkh:ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
|
123
103
|
proof:
|
|
124
|
-
'{"
|
|
104
|
+
'{"presentationContext":"d9380ba535f3fc379d507e7fabba726104ff4640b05a7c5696d0b0830d3a1983","proof":{"created":"2025-11-22T15:53:04.074Z","proofValue":[],"type":"ConcordiumWeakLinkingProofV1"},"type":"VerifiablePresentation","verifiableCredential":[]}',
|
|
105
|
+
wallet_provider: "Concordium Browser",
|
|
125
106
|
status: ProofStatus.PENDING,
|
|
126
|
-
wallet_provider: "Concordium Wallet",
|
|
127
107
|
};
|
|
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
108
|
|
|
109
|
+
const result = await verifyConcordiumSignature(proof);
|
|
137
110
|
expect(result.status).toBe(ProofStatus.FAILED);
|
|
138
|
-
}
|
|
111
|
+
});
|
|
139
112
|
|
|
140
|
-
|
|
141
|
-
it("returns failed proof when invalid message and address in test mode", async () => {
|
|
113
|
+
it("returns failed proof when presentation is missing presentationContext", async () => {
|
|
142
114
|
const proof: SignatureProof = {
|
|
143
115
|
address:
|
|
144
116
|
"ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
|
145
117
|
attestation:
|
|
146
|
-
"
|
|
147
|
-
proof: '{}',
|
|
148
|
-
did: "did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5",
|
|
149
|
-
status: ProofStatus.PENDING,
|
|
150
|
-
wallet_provider: "Concordium Wallet",
|
|
118
|
+
"d9380ba535f3fc379d507e7fabba726104ff4640b05a7c5696d0b0830d3a1983",
|
|
151
119
|
type: ProofTypes.CONCORDIUM,
|
|
120
|
+
did: "did:pkh:ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
|
121
|
+
proof:
|
|
122
|
+
'{"proof":{"created":"2025-11-22T15:53:04.074Z","proofValue":[],"type":"ConcordiumWeakLinkingProofV1"},"type":"VerifiablePresentation","verifiableCredential":[{"credentialSubject":{"id":"did:ccd:testnet:cred:8f73851550a5d2c2ed4df215731cf9e3f33614d4be6c1c336f0f8858522c94afa34a759258a2b3281f9bacd0a8a3cd09","proof":{"created":"2025-11-22T15:53:04.074Z","proofValue":[{"proof":"test","type":"AttributeInRange"}],"type":"ConcordiumZKProofV3"},"statement":[{"attributeTag":"dob","lower":"19300101","type":"AttributeInRange","upper":"99990101"}]},"issuer":"did:ccd:testnet:idp:0","type":["VerifiableCredential","ConcordiumVerifiableCredential"]}]}',
|
|
123
|
+
wallet_provider: "Concordium Browser",
|
|
124
|
+
status: ProofStatus.PENDING,
|
|
152
125
|
};
|
|
153
126
|
|
|
154
|
-
|
|
155
|
-
const result = await verifyConcordiumSignature(proof, { testMode: true });
|
|
156
|
-
|
|
127
|
+
const result = await verifyConcordiumSignature(proof);
|
|
157
128
|
expect(result.status).toBe(ProofStatus.FAILED);
|
|
158
129
|
});
|
|
159
130
|
|
|
160
|
-
it("
|
|
131
|
+
it("returns failed proof when credential is missing credentialSubject", async () => {
|
|
161
132
|
const proof: SignatureProof = {
|
|
162
133
|
address:
|
|
163
134
|
"ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
|
164
135
|
attestation:
|
|
165
|
-
"
|
|
166
|
-
proof: 'invalid json',
|
|
167
|
-
did: "did:key:z6MksamQq4oVRktkeSDxs6pbixYFUaUca8xgCvnTVLQA5PC5",
|
|
168
|
-
status: ProofStatus.PENDING,
|
|
169
|
-
wallet_provider: "Concordium Wallet",
|
|
136
|
+
"d9380ba535f3fc379d507e7fabba726104ff4640b05a7c5696d0b0830d3a1983",
|
|
170
137
|
type: ProofTypes.CONCORDIUM,
|
|
138
|
+
did: "did:pkh:ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
|
139
|
+
proof:
|
|
140
|
+
'{"presentationContext":"d9380ba535f3fc379d507e7fabba726104ff4640b05a7c5696d0b0830d3a1983","proof":{"created":"2025-11-22T15:53:04.074Z","proofValue":[],"type":"ConcordiumWeakLinkingProofV1"},"type":"VerifiablePresentation","verifiableCredential":[{"issuer":"did:ccd:testnet:idp:0","type":["VerifiableCredential","ConcordiumVerifiableCredential"]}]}',
|
|
141
|
+
wallet_provider: "Concordium Browser",
|
|
142
|
+
status: ProofStatus.PENDING,
|
|
171
143
|
};
|
|
172
144
|
|
|
173
|
-
|
|
174
|
-
const result = await verifyConcordiumSignature(proof, { testMode: true });
|
|
175
|
-
|
|
145
|
+
const result = await verifyConcordiumSignature(proof);
|
|
176
146
|
expect(result.status).toBe(ProofStatus.FAILED);
|
|
177
147
|
});
|
|
178
148
|
|
|
179
|
-
it("
|
|
149
|
+
it("returns failed proof with tampered proof signature", async () => {
|
|
180
150
|
const proof: SignatureProof = {
|
|
181
|
-
address:
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
status: ProofStatus.PENDING,
|
|
186
|
-
wallet_provider: "Test Wallet",
|
|
151
|
+
address:
|
|
152
|
+
"ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
|
153
|
+
attestation:
|
|
154
|
+
"d9380ba535f3fc379d507e7fabba726104ff4640b05a7c5696d0b0830d3a1983",
|
|
187
155
|
type: ProofTypes.CONCORDIUM,
|
|
156
|
+
did: "did:pkh:ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
|
157
|
+
proof:
|
|
158
|
+
'{"presentationContext":"d9380ba535f3fc379d507e7fabba726104ff4640b05a7c5696d0b0830d3a1983","proof":{"created":"2025-11-22T15:53:04.074Z","proofValue":[],"type":"ConcordiumWeakLinkingProofV1"},"type":"VerifiablePresentation","verifiableCredential":[{"credentialSubject":{"id":"did:ccd:testnet:cred:8f73851550a5d2c2ed4df215731cf9e3f33614d4be6c1c336f0f8858522c94afa34a759258a2b3281f9bacd0a8a3cd09","proof":{"created":"2025-11-22T15:53:04.074Z","proofValue":[{"proof":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","type":"AttributeInRange"}],"type":"ConcordiumZKProofV3"},"statement":[{"attributeTag":"dob","lower":"19300101","type":"AttributeInRange","upper":"99990101"}]},"issuer":"did:ccd:testnet:idp:0","type":["VerifiableCredential","ConcordiumVerifiableCredential"]}]}',
|
|
159
|
+
wallet_provider: "Concordium Browser",
|
|
160
|
+
status: ProofStatus.PENDING,
|
|
188
161
|
};
|
|
189
162
|
|
|
190
|
-
const result = await verifyConcordiumSignature(proof
|
|
191
|
-
|
|
163
|
+
const result = await verifyConcordiumSignature(proof);
|
|
192
164
|
expect(result.status).toBe(ProofStatus.FAILED);
|
|
193
|
-
});
|
|
165
|
+
}, 15000);
|
|
194
166
|
|
|
195
|
-
|
|
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
|
|
167
|
+
it("returns failed proof with mismatched presentationContext and attestation", async () => {
|
|
199
168
|
const proof: SignatureProof = {
|
|
200
169
|
address:
|
|
201
|
-
"ccd:9dd9ca4d19e9393877d2c44b70f89acb:
|
|
170
|
+
"ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
|
202
171
|
attestation:
|
|
203
|
-
"
|
|
172
|
+
"0000000000000000000000000000000000000000000000000000000000000000",
|
|
204
173
|
type: ProofTypes.CONCORDIUM,
|
|
205
|
-
did: "did:
|
|
174
|
+
did: "did:pkh:ccd:9dd9ca4d19e9393877d2c44b70f89acb:3thVBVWVwz1oHb4ob2VgehUGF7zyAJHkm5UDW8NdQKFKCvFnoF",
|
|
206
175
|
proof:
|
|
207
|
-
'{"
|
|
176
|
+
'{"presentationContext":"d9380ba535f3fc379d507e7fabba726104ff4640b05a7c5696d0b0830d3a1983","proof":{"created":"2025-11-22T15:53:04.074Z","proofValue":[],"type":"ConcordiumWeakLinkingProofV1"},"type":"VerifiablePresentation","verifiableCredential":[{"credentialSubject":{"id":"did:ccd:testnet:cred:8f73851550a5d2c2ed4df215731cf9e3f33614d4be6c1c336f0f8858522c94afa34a759258a2b3281f9bacd0a8a3cd09","proof":{"created":"2025-11-22T15:53:04.074Z","proofValue":[{"proof":"a9f68ef2cb10cfe4b7734ab0464e6af952e9ebeb7d8701c00d6894ee64ee9f110d6dfbbdfd7de737ebaf0d3e85512ae98e7047e9db92d7d8bf5c4414f30443e13461bda7da17bd7a1e95d65add4e6fdc2d2da7338b9e2b71359a834df422d90682d490d1dc266806981c48cc39c1d7dfad0c86364cc1607d15dffe36a5f67b229f34567adcd9bbe249e9b3e521ecc4ccb260512d37da8cc7e61b224be723140b00412dfb57deb54ed8f0cd74e1cf31f64b50e649b7c262433f167c9e490cb06f4b12a3da45d25c45a76cfb94e21bf1b5950bb4edc83730ef882ecc376ff0e83957ef73535557ea865be9391f7948b6b34f5778025fcc681b469b9d1922e7605f1e768c0fd4280b6c1f338d7922a545536d5fb3c0e88b1da8b17020c9c26b544c00000007b15c3faa19a2f749f762be0f87820a299de52ccbea2e38dcc2c1275eca95e808bda09bffc4afdc0affca5e40308b2b00a1bf346359c0effc8c0cafbb17eb217cee0ac4239e053b5e058cd14fe8b687259255c5c9c110f11926f31760cf8ce4d2ae8fa37bdf19efaf35661fd2d31d45c535735e5af7871afbe8bea0783b01c1e66f62df3fce23309a7f743ebc7e27d9a5951821b5031c443310bb777ad4a04c3111ec017b18cdecab0a107f1a086bbfa513a2ed61e72665b8332e9f4809b04595a6bf76ed0ea0b38ca897aa5811a17df35bdab1a0a02ab6a8379acde4c9c01908de128821739028359e5173e7222fca0b8cad1206e0e6ca938a7bae3864445ca22ee60f7de2aceecb98d1f40a0c7a0519af09df4d7c536017c0236b7e579c73ea8aeb20762d31b3daa5a966f4f5824eb51ea037b3686cbd8a9d8daa0927fbe26ac1d9d41f0d96ce1896e6eaa69cfa88a09682079406a50718a47539999be699d4bfe2a414a13dc39d96a911e5113fab61a09b66346c74bc67c2bdbace3dcc74eca8e30bf2e64b2f577b0a4a9d484ff7696771e8e347bf870f51a9ef2d88b2bac8f53a0ae5ba2a537121b26977a57d585d8ef41596a8663ebada0626fcc4a919c115c8f766216abb76355970c5431152087d8e727aea7b245912ee35ca169bdf43ab89f1d2c857038faf337b7f0cfe16162fb43339a879159290116b95d64379d2a927b4b99e5aa50e784aa0b0ee930b17b31c778e09d3dd8879578179dc17e70f92252d0cc2226da0e70a0c1d6a375cca572818034242443f5f5e3d7bacff47d380e2698afc0e67fefc66fbb4e336744bde829f68ede5e4fac6315fd005471045fdee23a6f9c43ff69a2adddc597372f8acd2f02507ed99e195396412f181b207a3711ec68ce5b0811c46fe1be324fb64e8866d2850c16c33bb953a6ddf1bd8650f26db28333a7e2fd69f32e64778efd02c60730a96adad0fb12fa872d2c48268075c5335724f03d118b1e32593dc71e4141a5febcd078c1a85f21dd36d35af77","type":"AttributeInRange"}],"type":"ConcordiumZKProofV3"},"statement":[{"attributeTag":"dob","lower":"19300101","type":"AttributeInRange","upper":"99990101"}]},"issuer":"did:ccd:testnet:idp:0","type":["VerifiableCredential","ConcordiumVerifiableCredential"]}]}',
|
|
177
|
+
wallet_provider: "Concordium Browser",
|
|
208
178
|
status: ProofStatus.PENDING,
|
|
209
|
-
wallet_provider: "Concordium Wallet",
|
|
210
179
|
};
|
|
211
|
-
|
|
212
|
-
|
|
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
|
|
180
|
+
|
|
181
|
+
const result = await verifyConcordiumSignature(proof);
|
|
220
182
|
expect(result.status).toBe(ProofStatus.FAILED);
|
|
221
183
|
}, 15000);
|
|
222
184
|
});
|
package/src/tests/index.test.ts
CHANGED
|
@@ -328,13 +328,13 @@ describe("verifyProof", () => {
|
|
|
328
328
|
|
|
329
329
|
describe("Concordium", () => {
|
|
330
330
|
const proof: SignatureProof = {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
331
|
+
"address": "ccd:9dd9ca4d19e9393877d2c44b70f89acb:3Soqc3mEU5WC4R9Qho9fxm4CJ1157q6qsJbPvtGV8iT8FbQdv2",
|
|
332
|
+
"attestation": "b74a8e64f1568f1fb22a57b033bc8ef2b8f6ba23ff8e831e7abfbb671927fda1",
|
|
333
|
+
"type": ProofTypes.CONCORDIUM,
|
|
334
|
+
"did": "did:pkh:ccd:9dd9ca4d19e9393877d2c44b70f89acb:3Soqc3mEU5WC4R9Qho9fxm4CJ1157q6qsJbPvtGV8iT8FbQdv2",
|
|
335
|
+
"proof": "{\"presentationContext\":\"b74a8e64f1568f1fb22a57b033bc8ef2b8f6ba23ff8e831e7abfbb671927fda1\",\"proof\":{\"created\":\"2025-12-10T10:39:14.395Z\",\"proofValue\":[],\"type\":\"ConcordiumWeakLinkingProofV1\"},\"type\":\"VerifiablePresentation\",\"verifiableCredential\":[{\"credentialSubject\":{\"id\":\"did:ccd:mainnet:cred:91a1f28bc42222096856a54fb157f7c80b9827457d4ece682b9592bca964948f01dce51a7deb392ea9bd0c1e1630d17b\",\"proof\":{\"created\":\"2025-12-10T10:39:14.395Z\",\"proofValue\":[{\"proof\":\"988f08d03bc8adaac4d51986dfaafe70874ab3bb22e8c09c32da5bfcd0ff0407203770533220e74ba4386acb36f7b7288e38c461279f7edf6f41b8b285d629280a5ca297e7fc42155222c5b1ad3cc74f770d5c87addbba6935ade425460b1616a587d9c45a4676f7fc751b31110cd37b25998c61d7d85c84e4db155491665e556778a9784e557799f06531bafe6b4b8ca2ce386d66f7759079eaff74b1e519550c9d137a13851c0987ee434feb6dae0ca659d67661b27e92d7cca9567a1a6ecd2175c574f5a6c2f4691597cbf3680f65abab72633d050746211c56961277064d694a31c2a93ef3b64c4957ff8261978a53d8b65d40ff23ddc7ee65d0ea0817702be58fbaec3954322e00667c6c94736eba8d3aa3f2686b89f257ca34c90ae1200000000785c57df969a45b25b1d39bdb388d33a756147e98f285891e83ce58eab3bb1f466c25a0946fc62513b16f3f02397b15418ebc131b5e1a8c0f05d6983cd3c44cc40ab8364c1aa209c2e8c0e8e84694587053542fd5cbb918f025723a5a0c200f08875728874571f50cb8b54d1c8629a10c76f0a982ad667efcfa280943f7c8753d3fa859a8d5d9837e6bdd5026d54546a3ae5918055208b5d2f77e0206d7861b4c472c634ec4cece107aeb14c42fe3d801aba38aa38e15785152e7c061561a5594a6cabb34f469b3121c15437df5d6ba0638ba3a192f2106d07e2f7bfd73310f669d3e8bdeb1b43244455d7bd7fa5917a1af2b23dc3433dac68ee4571bea2b0c22ce2ed665e22cee5676b9c3de0169926e72c847f7e3f2caa671e55ab5c4530205845b08ee12bba954f4a41e5638b05043a93ed212f402273c2b477f95f7b82ddbe4621f1758f80fcec726df755a76d0f585eda201dff2b91147cca5eae5d5319b7e1438c0f4af42b9fe4f7e845d0c643328ddd5dead96bfd345ae972312650a9ab6e6d7fa3d3f5d1fe68e5ff513095e3caa5bb21bec64dae007e62b4494986ac40b9e14b61255a84ea51780b8439adaeeae0b83a8bcee382491dd8e7b2f1921e8eeffe39a45bffd470b5a8f74d82ccdb8ccda651c387844f61704cc04f51d65fb9069900cb1febfc0b2ba02ffc857c45c12a7b306440e6627995d67353e9f6327b6f6cfa6ad0b859ea904f087a5b29a888043ba21ccb3e36da0a2da797310c2f2ce56c275d6fc48b60aade4b4e6bb6ff62d5f5be1a529c8d71cab2b0904fa306cb779a897872f5f047df7c7bee150ca6be6f3ad840a862ecc0793bb27f0594ff8741a4ab426b53d72acbdbde6c20a7c4399ca181d81a4b0ac437c23220f52ff8e9095ae35a53f8cd58913c4999a8153b656fabb162feafe8fc8708eaeb2b5ce0d347e5733cd685783271eaf564e05efce61996686ee9f50663204841ff30416061721a5cab8e1c80708809b58d2bc9c402da453e486ce08e0ec6c72c1f0e9dc15\",\"type\":\"AttributeInRange\"}],\"type\":\"ConcordiumZKProofV3\"},\"statement\":[{\"attributeTag\":\"dob\",\"lower\":\"19300101\",\"type\":\"AttributeInRange\",\"upper\":\"99990101\"}]},\"issuer\":\"did:ccd:mainnet:idp:1\",\"type\":[\"VerifiableCredential\",\"ConcordiumVerifiableCredential\"]}]}",
|
|
336
|
+
"wallet_provider": "Concordium Browser",
|
|
337
|
+
"status": ProofStatus.PENDING
|
|
338
338
|
};
|
|
339
339
|
|
|
340
340
|
it("should verify proof", async () => {
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var buffer = require('buffer');
|
|
4
|
-
require('./chunk-OAXNH5XR.cjs');
|
|
5
|
-
var javascriptSdk = require('@notabene/javascript-sdk');
|
|
6
|
-
|
|
7
|
-
if (typeof globalThis !== 'undefined' && !globalThis.Buffer) { globalThis.Buffer = buffer.Buffer; }
|
|
8
|
-
var NETWORKS = {
|
|
9
|
-
testnet: {
|
|
10
|
-
grpcUrl: "https://grpc.testnet.concordium.com:20000",
|
|
11
|
-
walletProxyUrl: "https://wallet-proxy.testnet.concordium.com"
|
|
12
|
-
},
|
|
13
|
-
mainnet: {
|
|
14
|
-
grpcUrl: "https://grpc.mainnet.concordium.com:20000",
|
|
15
|
-
walletProxyUrl: "https://wallet-proxy.mainnet.concordium.software"
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
var DEFAULT_OPTIONS = {
|
|
19
|
-
network: "testnet",
|
|
20
|
-
timeout: 5e4,
|
|
21
|
-
// 10 seconds
|
|
22
|
-
retries: 3,
|
|
23
|
-
testMode: true
|
|
24
|
-
};
|
|
25
|
-
var verifyConcordiumSignature = async (proof, options = {}) => {
|
|
26
|
-
const config = { ...DEFAULT_OPTIONS, ...options };
|
|
27
|
-
const [ns, networkId, address] = proof.address.split(/:/);
|
|
28
|
-
if (ns !== "ccd") {
|
|
29
|
-
return { ...proof, status: javascriptSdk.ProofStatus.FAILED };
|
|
30
|
-
}
|
|
31
|
-
let network = config.network;
|
|
32
|
-
if (networkId) {
|
|
33
|
-
network = networkId.includes("testnet") ? "testnet" : "mainnet";
|
|
34
|
-
}
|
|
35
|
-
try {
|
|
36
|
-
let signature;
|
|
37
|
-
try {
|
|
38
|
-
signature = JSON.parse(proof.proof);
|
|
39
|
-
} catch {
|
|
40
|
-
return { ...proof, status: javascriptSdk.ProofStatus.FAILED };
|
|
41
|
-
}
|
|
42
|
-
if (!signature || typeof signature !== "object" || Object.keys(signature).length === 0) {
|
|
43
|
-
return { ...proof, status: javascriptSdk.ProofStatus.FAILED };
|
|
44
|
-
}
|
|
45
|
-
if (config.testMode) {
|
|
46
|
-
try {
|
|
47
|
-
const signatureHex = convertSignatureToHex(signature);
|
|
48
|
-
if (!signatureHex || signatureHex.length < 64 || !/^[0-9a-fA-F]+$/.test(signatureHex)) {
|
|
49
|
-
return { ...proof, status: javascriptSdk.ProofStatus.FAILED };
|
|
50
|
-
}
|
|
51
|
-
return { ...proof, status: javascriptSdk.ProofStatus.VERIFIED };
|
|
52
|
-
} catch {
|
|
53
|
-
return { ...proof, status: javascriptSdk.ProofStatus.FAILED };
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
const accountInfo = await retryWithTimeout(
|
|
57
|
-
() => validateAccountAndGetInfo(address, network, config.timeout),
|
|
58
|
-
config.retries
|
|
59
|
-
);
|
|
60
|
-
if (!accountInfo) {
|
|
61
|
-
return { ...proof, status: javascriptSdk.ProofStatus.FAILED };
|
|
62
|
-
}
|
|
63
|
-
const isValidSignature = await retryWithTimeout(
|
|
64
|
-
() => verifyCryptographicSignature(
|
|
65
|
-
signature,
|
|
66
|
-
config.timeout
|
|
67
|
-
// proof.attestation,
|
|
68
|
-
// address,
|
|
69
|
-
// network
|
|
70
|
-
),
|
|
71
|
-
config.retries
|
|
72
|
-
);
|
|
73
|
-
if (isValidSignature) {
|
|
74
|
-
return { ...proof, status: javascriptSdk.ProofStatus.VERIFIED };
|
|
75
|
-
} else {
|
|
76
|
-
return { ...proof, status: javascriptSdk.ProofStatus.FAILED };
|
|
77
|
-
}
|
|
78
|
-
} catch {
|
|
79
|
-
return { ...proof, status: javascriptSdk.ProofStatus.FAILED };
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
async function validateAccountAndGetInfo(address, network, timeout) {
|
|
83
|
-
const networkConfig = NETWORKS[network];
|
|
84
|
-
try {
|
|
85
|
-
const controller = new AbortController();
|
|
86
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
87
|
-
const response = await fetch(
|
|
88
|
-
`${networkConfig.walletProxyUrl}/v0/accEncryptionKey/${address}`,
|
|
89
|
-
{
|
|
90
|
-
method: "GET",
|
|
91
|
-
headers: {
|
|
92
|
-
"Accept": "application/json",
|
|
93
|
-
"User-Agent": "verify-proof/1.6.0"
|
|
94
|
-
},
|
|
95
|
-
signal: controller.signal
|
|
96
|
-
}
|
|
97
|
-
);
|
|
98
|
-
clearTimeout(timeoutId);
|
|
99
|
-
return response.ok;
|
|
100
|
-
} catch (error) {
|
|
101
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
102
|
-
throw new Error(`Account validation timeout after ${timeout}ms`);
|
|
103
|
-
}
|
|
104
|
-
throw error;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
async function verifyCryptographicSignature(signature, timeout) {
|
|
108
|
-
try {
|
|
109
|
-
const signatureHex = convertSignatureToHex(signature);
|
|
110
|
-
if (!signatureHex || signatureHex.length < 64) {
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
return signatureHex.length >= 64 && /^[0-9a-fA-F]+$/.test(signatureHex);
|
|
114
|
-
} catch (error) {
|
|
115
|
-
if (error instanceof Error) {
|
|
116
|
-
if (error.message?.includes("timeout")) {
|
|
117
|
-
throw new Error(`Signature verification timeout after ${timeout}ms`);
|
|
118
|
-
}
|
|
119
|
-
if (error.message?.includes("UNAVAILABLE")) {
|
|
120
|
-
throw new Error("Concordium node unavailable");
|
|
121
|
-
}
|
|
122
|
-
if (error.message?.includes("NOT_FOUND")) {
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
throw error;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
function convertSignatureToHex(signature) {
|
|
130
|
-
try {
|
|
131
|
-
if (typeof signature === "string") {
|
|
132
|
-
return signature;
|
|
133
|
-
}
|
|
134
|
-
if (signature && typeof signature === "object") {
|
|
135
|
-
const extractSignature = (obj) => {
|
|
136
|
-
if (typeof obj === "string") {
|
|
137
|
-
return obj;
|
|
138
|
-
}
|
|
139
|
-
if (obj && typeof obj === "object") {
|
|
140
|
-
for (const key in obj) {
|
|
141
|
-
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
142
|
-
const value = obj[key];
|
|
143
|
-
if (typeof value === "string") {
|
|
144
|
-
return value;
|
|
145
|
-
} else if (typeof value === "object") {
|
|
146
|
-
const result = extractSignature(value);
|
|
147
|
-
if (result) return result;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
return null;
|
|
153
|
-
};
|
|
154
|
-
const extractedSig = extractSignature(signature);
|
|
155
|
-
if (extractedSig) {
|
|
156
|
-
return extractedSig;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
throw new Error("Unable to extract signature from object");
|
|
160
|
-
} catch (error) {
|
|
161
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
162
|
-
throw new Error(`Invalid signature format: ${errorMessage}`);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
async function retryWithTimeout(operation, maxRetries) {
|
|
166
|
-
let lastError = new Error("No attempts made");
|
|
167
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
168
|
-
try {
|
|
169
|
-
return await operation();
|
|
170
|
-
} catch (error) {
|
|
171
|
-
const errorInstance = error instanceof Error ? error : new Error(String(error));
|
|
172
|
-
lastError = errorInstance;
|
|
173
|
-
if (errorInstance.message?.includes("Invalid signature") || errorInstance.message?.includes("Account not found")) {
|
|
174
|
-
throw errorInstance;
|
|
175
|
-
}
|
|
176
|
-
if (attempt === maxRetries) {
|
|
177
|
-
break;
|
|
178
|
-
}
|
|
179
|
-
const delay = Math.min(Math.pow(2, attempt) * 1e3, 5e3);
|
|
180
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
throw lastError;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
exports.verifyConcordiumSignature = verifyConcordiumSignature;
|
|
187
|
-
//# sourceMappingURL=concordium-HQC37GCK.cjs.map
|
|
188
|
-
//# sourceMappingURL=concordium-HQC37GCK.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/concordium.ts"],"names":["ProofStatus"],"mappings":"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","file":"concordium-HQC37GCK.cjs","sourcesContent":["import { ProofStatus, SignatureProof } from \"@notabene/javascript-sdk\";\n\n// Concordium network configurations\ninterface ConcordiumNetwork {\n grpcUrl: string;\n walletProxyUrl: string;\n}\n\nconst NETWORKS: Record<string, ConcordiumNetwork> = {\n testnet: {\n grpcUrl: \"https://grpc.testnet.concordium.com:20000\",\n walletProxyUrl: \"https://wallet-proxy.testnet.concordium.com\"\n },\n mainnet: {\n grpcUrl: \"https://grpc.mainnet.concordium.com:20000\", \n walletProxyUrl: \"https://wallet-proxy.mainnet.concordium.software\"\n }\n};\n\n// Configuration options for verification\ninterface ConcordiumVerificationOptions {\n network?: \"testnet\" | \"mainnet\";\n timeout?: number; // timeout in milliseconds\n retries?: number; // number of retry attempts\n testMode?: boolean; // skip network calls for testing\n}\n\n// Signature object type\ninterface ConcordiumSignature {\n [key: string]: string | ConcordiumSignature;\n}\n\n// Default options\nconst DEFAULT_OPTIONS: Required<ConcordiumVerificationOptions> = {\n network: \"testnet\",\n timeout: 50000, // 10 seconds\n retries: 3,\n testMode: true\n};\n\n/**\n * Verifies a Concordium signature proof with proper cryptographic validation\n * @param proof The signature proof to verify\n * @param options Optional configuration for network and timeouts\n * @returns Promise resolving to the proof with updated status\n */\nexport const verifyConcordiumSignature = async (\n proof: SignatureProof,\n options: ConcordiumVerificationOptions = {}\n): Promise<SignatureProof> => {\n // Merge with default options\n const config = { ...DEFAULT_OPTIONS, ...options };\n \n // Parse and validate address format\n const [ns, networkId, address] = proof.address.split(/:/);\n if (ns !== \"ccd\") {\n return { ...proof, status: ProofStatus.FAILED };\n }\n\n // Determine network from address or use config\n let network = config.network;\n if (networkId) {\n // If network ID is specified in address, use it to determine network\n network = networkId.includes(\"testnet\") ? \"testnet\" : \"mainnet\";\n }\n\n try {\n // Validate signature format and extract signature data\n let signature: ConcordiumSignature;\n try {\n signature = JSON.parse(proof.proof) as ConcordiumSignature;\n } catch {\n return { ...proof, status: ProofStatus.FAILED };\n }\n\n // Basic signature structure validation\n if (!signature || typeof signature !== 'object' || Object.keys(signature).length === 0) {\n return { ...proof, status: ProofStatus.FAILED };\n }\n\n // In test mode, skip network validation but still validate signature structure\n if (config.testMode) {\n // Perform signature format validation\n try {\n const signatureHex = convertSignatureToHex(signature);\n \n // Validate signature format\n if (!signatureHex || signatureHex.length < 64 || !/^[0-9a-fA-F]+$/.test(signatureHex)) {\n return { ...proof, status: ProofStatus.FAILED };\n }\n \n return { ...proof, status: ProofStatus.VERIFIED };\n \n } catch {\n return { ...proof, status: ProofStatus.FAILED };\n }\n }\n\n // Production mode: validate account existence and get account info with retry logic\n const accountInfo = await retryWithTimeout(\n () => validateAccountAndGetInfo(address, network, config.timeout),\n config.retries\n );\n\n if (!accountInfo) {\n return { ...proof, status: ProofStatus.FAILED };\n }\n\n // Perform cryptographic signature verification\n const isValidSignature = await retryWithTimeout(\n () => verifyCryptographicSignature(\n signature,\n config.timeout,\n // proof.attestation,\n // address,\n // network\n ),\n config.retries\n );\n\n if (isValidSignature) {\n return { ...proof, status: ProofStatus.VERIFIED };\n } else {\n return { ...proof, status: ProofStatus.FAILED };\n }\n\n } catch {\n return { ...proof, status: ProofStatus.FAILED };\n }\n};\n\n/**\n * Validates that a Concordium account exists and retrieves account information\n */\nasync function validateAccountAndGetInfo(\n address: string,\n network: \"testnet\" | \"mainnet\",\n timeout: number\n): Promise<boolean> {\n const networkConfig = NETWORKS[network];\n \n try {\n // Check account existence via wallet proxy (faster than gRPC for existence check)\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n const response = await fetch(\n `${networkConfig.walletProxyUrl}/v0/accEncryptionKey/${address}`,\n {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'User-Agent': 'verify-proof/1.6.0'\n },\n signal: controller.signal\n }\n );\n\n clearTimeout(timeoutId);\n return response.ok;\n\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new Error(`Account validation timeout after ${timeout}ms`);\n }\n throw error;\n }\n}\n\n/**\n * Performs cryptographic verification of the signature using Concordium SDK\n * For production use, this would use the actual Concordium SDK verification methods\n * Currently implementing a comprehensive validation approach\n */\nasync function verifyCryptographicSignature(\n signature: ConcordiumSignature,\n timeout: number,\n // message?: string, // intentionally left out for now. Will enable for mainnet.\n // address?: string,\n // network?: \"testnet\" | \"mainnet\"\n): Promise<boolean> {\n try {\n // Convert signature format for verification\n const signatureHex = convertSignatureToHex(signature);\n \n // For production, implement proper signature verification\n // This is a placeholder for the actual SDK verification\n // The exact method depends on the available SDK version\n \n // Validate that we have a proper signature hex string\n if (!signatureHex || signatureHex.length < 64) {\n return false;\n }\n\n // For now, return true if we have a valid signature structure\n // In production, this should call the actual SDK verification method\n // Example: \n // const client = new ConcordiumGRPCNodeClient(networkConfig.grpcUrl, 20000, credentials.createInsecure(), { timeout });\n // const result = await client.verifyAccountSignature(address, message, signatureHex);\n \n // Placeholder validation - replace with actual SDK call\n return signatureHex.length >= 64 && /^[0-9a-fA-F]+$/.test(signatureHex);\n\n } catch (error) {\n // Handle specific error types\n if (error instanceof Error) {\n if (error.message?.includes(\"timeout\")) {\n throw new Error(`Signature verification timeout after ${timeout}ms`);\n }\n \n if (error.message?.includes(\"UNAVAILABLE\")) {\n throw new Error(\"Concordium node unavailable\");\n }\n\n if (error.message?.includes(\"NOT_FOUND\")) {\n return false;\n }\n }\n\n throw error;\n }\n}\n\n/**\n * Converts the signature object to the format expected by Concordium SDK\n */\nfunction convertSignatureToHex(signature: ConcordiumSignature): string {\n try {\n // Handle different signature formats\n if (typeof signature === 'string') {\n return signature;\n }\n\n // Handle nested signature object format (common from wallet)\n if (signature && typeof signature === 'object') {\n // Extract signature from nested structure\n const extractSignature = (obj: ConcordiumSignature): string | null => {\n if (typeof obj === 'string') {\n return obj;\n }\n \n if (obj && typeof obj === 'object') {\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n const value = obj[key];\n if (typeof value === 'string') {\n return value;\n } else if (typeof value === 'object') {\n const result = extractSignature(value);\n if (result) return result;\n }\n }\n }\n }\n \n return null;\n };\n\n const extractedSig = extractSignature(signature);\n if (extractedSig) {\n return extractedSig;\n }\n }\n\n throw new Error(\"Unable to extract signature from object\");\n \n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n throw new Error(`Invalid signature format: ${errorMessage}`);\n }\n}\n\n/**\n * Utility function to retry operations with exponential backoff\n */\nasync function retryWithTimeout<T>(\n operation: () => Promise<T>,\n maxRetries: number\n): Promise<T> {\n let lastError: Error = new Error(\"No attempts made\");\n \n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await operation();\n } catch (error) {\n const errorInstance = error instanceof Error ? error : new Error(String(error));\n lastError = errorInstance;\n \n // Don't retry on certain types of errors\n if (\n errorInstance.message?.includes(\"Invalid signature\") ||\n errorInstance.message?.includes(\"Account not found\")\n ) {\n throw errorInstance;\n }\n\n // Don't retry on the last attempt\n if (attempt === maxRetries) {\n break;\n }\n\n // Exponential backoff: wait 2^attempt * 1000ms\n const delay = Math.min(Math.pow(2, attempt) * 1000, 5000);\n await new Promise(resolve => setTimeout(resolve, delay));\n }\n }\n\n throw lastError;\n}\n"]}
|