authorize.html (6284B)
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>Identity Verification</title> 7 <script src="/js/qrcode.min.js"></script> 8 <style> 9 body { 10 font-family: system-ui, -apple-system, sans-serif; 11 max-width: 600px; 12 margin: 50px auto; 13 padding: 20px; 14 text-align: center; 15 background: #f5f5f5; 16 } 17 .container { 18 background: white; 19 padding: 40px; 20 border-radius: 8px; 21 box-shadow: 0 2px 8px rgba(0,0,0,0.1); 22 } 23 h1 { 24 color: #333; 25 margin-bottom: 10px; 26 } 27 p { 28 color: #666; 29 margin-bottom: 30px; 30 } 31 #qrcode { 32 margin: 20px auto; 33 display: inline-block; 34 padding: 20px; 35 background: white; 36 border: 2px solid #e0e0e0; 37 border-radius: 8px; 38 } 39 #qr-fallback { 40 display: none; 41 margin: 20px 0; 42 word-break: break-all; 43 } 44 .button { 45 display: inline-block; 46 padding: 12px 32px; 47 background: #007bff; 48 color: white; 49 text-decoration: none; 50 border-radius: 4px; 51 margin: 20px 0; 52 font-weight: 500; 53 transition: background 0.3s; 54 } 55 .button:hover { 56 background: #0056b3; 57 } 58 .error { 59 color: #dc3545; 60 padding: 16px; 61 background: #f8d7da; 62 border: 1px solid #f5c6cb; 63 border-radius: 4px; 64 margin: 20px 0; 65 display: none; 66 } 67 .status { 68 color: #6c757d; 69 font-size: 14px; 70 margin: 20px 0; 71 padding: 12px; 72 background: #e7f3ff; 73 border-radius: 4px; 74 } 75 .spinner { 76 display: inline-block; 77 width: 16px; 78 height: 16px; 79 border: 2px solid #f3f3f3; 80 border-top: 2px solid #007bff; 81 border-radius: 50%; 82 animation: spin 1s linear infinite; 83 margin-right: 8px; 84 vertical-align: middle; 85 } 86 @keyframes spin { 87 0% { transform: rotate(0deg); } 88 100% { transform: rotate(360deg); } 89 } 90 </style> 91 </head> 92 <body> 93 <div class="container"> 94 <h1>Identity Verification</h1> 95 <p>Scan the QR code with your Swiyu wallet or click the button below:</p> 96 97 <div id="qrcode"></div> 98 <div id="qr-fallback"> 99 <p>QR code failed to load. Use this link:</p> 100 <a href="{{ verification_url }}">{{ verification_url }}</a> 101 </div> 102 103 {% if !verification_deeplink.is_empty() %} 104 <div> 105 <a href="{{ verification_deeplink }}" class="button">Open Swiyu Wallet</a> 106 </div> 107 {% endif %} 108 109 <div id="status" class="status"> 110 <span class="spinner"></span> 111 <span>Waiting for verification...</span> 112 </div> 113 <div id="error" class="error"></div> 114 </div> 115 116 <script> 117 const verificationId = {{ verification_id_json|safe }}; 118 const state = {{ state_json|safe }}; 119 120 try { 121 new QRCode(document.getElementById("qrcode"), { 122 text: {{ verification_url_json|safe }}, 123 width: 256, 124 height: 256, 125 correctLevel: QRCode.CorrectLevel.M 126 }); 127 } catch (error) { 128 console.error('QR code generation failed:', error); 129 document.getElementById('qrcode').style.display = 'none'; 130 document.getElementById('qr-fallback').style.display = 'block'; 131 } 132 133 let attempts = 0; 134 const maxAttempts = 100; 135 const pollInterval = 3000; 136 137 async function checkStatus() { 138 attempts++; 139 140 if (attempts > maxAttempts) { 141 document.getElementById('status').style.display = 'none'; 142 document.getElementById('error').textContent = 'Verification timeout. Please try again.'; 143 document.getElementById('error').style.display = 'block'; 144 return; 145 } 146 147 try { 148 const response = await fetch(`/status/${verificationId}?state=${encodeURIComponent(state)}`); 149 150 if (!response.ok) { 151 if (response.status === 403) { 152 document.getElementById('status').style.display = 'none'; 153 document.getElementById('error').textContent = 'Security validation failed. Please start again.'; 154 document.getElementById('error').style.display = 'block'; 155 return; 156 } 157 throw new Error(`HTTP ${response.status}`); 158 } 159 160 const data = await response.json(); 161 162 if (data.status === 'verified') { 163 window.location.href = `/finalize/${verificationId}?state=${encodeURIComponent(state)}`; 164 return; 165 } 166 167 if (data.status === 'failed') { 168 document.getElementById('status').style.display = 'none'; 169 document.getElementById('error').textContent = 'Verification failed. Please try again.'; 170 document.getElementById('error').style.display = 'block'; 171 return; 172 } 173 174 if (data.status === 'expired') { 175 document.getElementById('status').style.display = 'none'; 176 document.getElementById('error').textContent = 'Session expired. Please start again.'; 177 document.getElementById('error').style.display = 'block'; 178 return; 179 } 180 181 setTimeout(checkStatus, pollInterval); 182 183 } catch (error) { 184 console.error('Polling error:', error); 185 setTimeout(checkStatus, pollInterval); 186 } 187 } 188 189 setTimeout(checkStatus, pollInterval); 190 </script> 191 </body> 192 </html>