@@ -302,6 +302,48 @@ async function processPayload(payload, sourceTag) {
302302 }
303303}
304304
305+ // Keep repeat scans valid on the same device; local storage is only a warning, not proof of fraud.
306+ processPayload = async function processPayloadOverride ( payload , sourceTag ) {
307+ const parsed = parseQrPayload ( payload ) ;
308+ if ( ! parsed . ok ) {
309+ setStatus ( 'fake' , 'INVALID QR' ) ;
310+ renderCardHtml ( `<div class="fail">Credential Invalid âŒ</div><div>${ escapeHtml ( parsed . reason ) } </div>` ) ;
311+ return ;
312+ }
313+
314+ try {
315+ const alreadyConsumed = await isQrAlreadyConsumed ( parsed . qk ) ;
316+ const decodedQd = await decodeQdPayload ( parsed . qd ) ;
317+ const decoded = decodedQd . parsed ;
318+ const offlineCheck = await verifyJwsToken ( parsed . qk , decodedQd . payloadText , parsed . credentialId ) ;
319+
320+ if ( offlineCheck && offlineCheck . ok && ! alreadyConsumed ) {
321+ await markQrConsumed ( parsed . qk , parsed . credentialId ) ;
322+ }
323+
324+ const offlineReason = String ( offlineCheck ?. reason || '' ) ;
325+ const repeatedScanReason = alreadyConsumed
326+ ? `${ offlineReason } ${ offlineReason ? '. ' : '' } This QR was already scanned on this device earlier.`
327+ : offlineReason ;
328+
329+ renderDecodedSecret ( decoded , sourceTag , {
330+ ...offlineCheck ,
331+ reason : repeatedScanReason
332+ } ) ;
333+ } catch ( e ) {
334+ setStatus ( 'fake' , 'INVALID' ) ;
335+ renderCardHtml ( `<div class="fail">Credential Invalid âŒ</div><div>${ escapeHtml ( String ( e ) ) } </div>` ) ;
336+ }
337+ }
338+
339+ function getLandingPayloadFromPageUrl ( ) {
340+ const params = new URLSearchParams ( window . location . search ) ;
341+ if ( ! params . get ( 'id' ) || ! params . get ( 'qk' ) || ! params . get ( 'qd' ) ) {
342+ return null ;
343+ }
344+ return window . location . href ;
345+ }
346+
305347async function startCameraScan ( ) {
306348 if ( activeVideoTrack ) return ;
307349
@@ -402,3 +444,20 @@ qrFile.addEventListener('change', async (e) => {
402444 }
403445 } ) ;
404446} ) ( ) ;
447+
448+ ( async function autoVerifyLandingUrl ( ) {
449+ const landingPayload = getLandingPayloadFromPageUrl ( ) ;
450+ if ( ! landingPayload ) {
451+ return ;
452+ }
453+
454+ const ok = await loadIssuerRegistry ( ) ;
455+ if ( ! ok ) {
456+ return ;
457+ }
458+
459+ qrLinkInput . value = landingPayload ;
460+ setStatus ( 'pending' , 'VERIFYING' ) ;
461+ renderCardHtml ( '<div>QR payload detected in page URL. Verifying now...</div>' ) ;
462+ processPayload ( landingPayload , 'landing-url' ) ;
463+ } ) ( ) ;
0 commit comments