kych

OAuth 2.0 API for Swiyu to enable Taler integration of Swiyu for KYC (experimental)
Log | Files | Refs | README

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>