@@ -60,6 +60,15 @@ async function verifyHashHexSignature(hashHex, signatureBase64, publicKey) {
6060 ) ;
6161}
6262
63+ async function verifyCanonicalSignature ( canonicalStr , signatureBase64 , publicKey ) {
64+ return subtle . verify (
65+ { name : 'Ed25519' } ,
66+ publicKey ,
67+ base64ToBytes ( signatureBase64 ) ,
68+ new TextEncoder ( ) . encode ( canonicalStr ) ,
69+ ) ;
70+ }
71+
6372async function defaultTextResolver ( ) {
6473 return null ;
6574}
@@ -135,44 +144,56 @@ async function verifyReceipt(receiptInput, options = {}) {
135144 } ;
136145 }
137146
147+ const proof = receipt ?. metadata ?. proof || null ;
148+ const canonicalization = proof ?. canonical || proof ?. canonicalization || null ;
149+ const kid = receipt ?. signature ?. kid || proof ?. kid || null ;
150+ const sig = receipt ?. signature ?. sig || proof ?. signature || null ;
151+
138152 const schemaValid = Boolean (
139153 receipt &&
140154 typeof receipt === 'object' &&
141155 typeof receipt . signer === 'string' &&
142156 typeof receipt . verb === 'string' &&
143157 typeof receipt . ts === 'string' &&
144- receipt . metadata ?. proof ?. canonicalization &&
145- receipt . metadata ?. proof ?. hash_sha256 &&
146- receipt . signature ?. kid &&
147- receipt . signature ?. sig ,
158+ canonicalization &&
159+ kid &&
160+ sig ,
148161 ) ;
149162
150163 const ens = await resolveSignerFromEns ( receipt ?. signer , options . ens || { } ) ;
151- const expectedHash = receipt ?. metadata ?. proof ?. hash_sha256 || null ;
152- const canonicalization = receipt ?. metadata ?. proof ?. canonicalization || null ;
164+ const expectedHash = proof ?. hash_sha256 || null ;
165+ const isLegacyMode = Boolean ( expectedHash ) ;
153166 const canonicalPayload = canonicalReceiptPayload ( receipt ) ;
154- const recomputedHash = await sha256Hex ( canonicalize ( canonicalPayload ) ) ;
167+ const canonicalStr = canonicalize ( canonicalPayload ) ;
168+ const recomputedHash = await sha256Hex ( canonicalStr ) ;
155169
156170 const expectedCanonical = ens . records [ 'cl.sig.canonical' ] ;
157171 const canonicalizationOk = canonicalization === expectedCanonical ;
158172 const hashMatched = Boolean (
159173 schemaValid &&
160174 canonicalizationOk &&
175+ isLegacyMode &&
161176 typeof expectedHash === 'string' &&
162177 expectedHash === recomputedHash ,
163178 ) ;
164179
165- const keyIdMatched = receipt ?. signature ?. kid === ens . records [ 'cl.sig.kid' ] ;
180+ const keyIdMatched = kid === ens . records [ 'cl.sig.kid' ] ;
166181 const prefixedPubkey = ens . records [ 'cl.sig.pub' ] ;
167182 const pubkeyBase64 = typeof prefixedPubkey === 'string'
168183 ? prefixedPubkey . replace ( / ^ e d 2 5 5 1 9 : / , '' )
169184 : null ;
170185
171186 let signatureValid = false ;
172- if ( hashMatched && keyIdMatched && pubkeyBase64 && receipt ?. signature ?. sig ) {
187+ if ( keyIdMatched && pubkeyBase64 && sig ) {
173188 try {
174189 const publicKey = await importEd25519PublicKey ( pubkeyBase64 ) ;
175- signatureValid = await verifyHashHexSignature ( recomputedHash , receipt . signature . sig , publicKey ) ;
190+ if ( isLegacyMode ) {
191+ if ( hashMatched ) {
192+ signatureValid = await verifyHashHexSignature ( recomputedHash , sig , publicKey ) ;
193+ }
194+ } else {
195+ signatureValid = await verifyCanonicalSignature ( canonicalStr , sig , publicKey ) ;
196+ }
176197 } catch {
177198 signatureValid = false ;
178199 }
@@ -182,7 +203,13 @@ async function verifyReceipt(receiptInput, options = {}) {
182203 ens . records [ 'cl.receipt.signer' ] && receipt ?. signer === ens . records [ 'cl.receipt.signer' ] ,
183204 ) ;
184205
185- const ok = Boolean ( schemaValid && hashMatched && signatureValid && signerMatched && ens . ensResolved ) ;
206+ const ok = Boolean (
207+ schemaValid &&
208+ signatureValid &&
209+ signerMatched &&
210+ ens . ensResolved &&
211+ ( isLegacyMode ? hashMatched : true ) ,
212+ ) ;
186213
187214 return {
188215 ok,
@@ -194,7 +221,7 @@ async function verifyReceipt(receiptInput, options = {}) {
194221 hash_matches : hashMatched ,
195222 signature_valid : signatureValid ,
196223 ens_resolved : Boolean ( ens . ensResolved ) ,
197- key_id : receipt ?. signature ?. kid || null ,
224+ key_id : kid || null ,
198225 public_key_source : ens . keySource ,
199226 debug : {
200227 expected_hash_sha256 : expectedHash ,
0 commit comments