Microservice to bring 2FA to self hosted PDSes
at sendmail 4.9 kB view raw
1<html lang="en" class=" "> 2<head> 3 <meta charset="utf-8"/> 4 <meta 5 name="viewport" 6 content="width=device-width, initial-scale=1, minimum-scale=1, viewport-fit=cover" 7 /> 8 <meta name="referrer" content="origin-when-cross-origin"/> 9 10 <title> 11 {{pds}} - Captcha 12 </title> 13 <style> 14 :root, 15 :root.light-mode { 16 --brand-color: rgb(16, 131, 254); 17 --primary-color: rgb(7, 10, 13); 18 --secondary-color: rgb(66, 86, 108); 19 --bg-primary-color: rgb(255, 255, 255); 20 --bg-secondary-color: rgb(240, 242, 245); 21 } 22 23 @media (prefers-color-scheme: dark) { 24 :root { 25 --brand-color: rgb(16, 131, 254); 26 --primary-color: rgb(255, 255, 255); 27 --secondary-color: rgb(133, 152, 173); 28 --bg-primary-color: rgb(7, 10, 13); 29 --bg-secondary-color: rgb(13, 18, 23); 30 } 31 } 32 33 :root.dark-mode { 34 --brand-color: rgb(16, 131, 254); 35 --primary-color: rgb(255, 255, 255); 36 --secondary-color: rgb(133, 152, 173); 37 --bg-primary-color: rgb(7, 10, 13); 38 --bg-secondary-color: rgb(13, 18, 23); 39 } 40 41 body { 42 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, 43 Arial, sans-serif; 44 background: var(--bg-primary-color); 45 color: var(--primary-color); 46 text-rendering: optimizeLegibility; 47 -webkit-font-smoothing: antialiased; 48 } 49 50 .info { 51 border-radius: 8px; 52 padding: 12px 14px; 53 letter-spacing: 0.25px; 54 font-weight: 400; 55 background-color: var(--bg-secondary-color); 56 color: var(--secondary-color); 57 } 58 59 .gate-page, 60 .error-page { 61 margin: 0; 62 margin-top: 10px; 63 display: flex; 64 justify-content: center; 65 } 66 67 .gate-page .main, 68 .error-page .main { 69 max-width: 600px; 70 width: 100%; 71 display: flex; 72 flex-direction: column; 73 } 74 75 .gate-page .main { 76 padding: 0; 77 } 78 79 .error-page .main { 80 padding: 20px; 81 } 82 83 .gate-page .main > :not(:first-child), 84 .error-page .main > :not(:first-child) { 85 margin-top: 20px; 86 } 87 88 .gate-page #gate-form { 89 margin: 0; 90 } 91 92 .gate-page #hcaptcha { 93 display: flex; 94 justify-content: center; 95 } 96 97 .pds-title { 98 font-size: 2.25rem; 99 font-weight: 700; 100 line-height: 1.2; 101 text-align: center; 102 color: var(--primary-color); 103 margin: 10px 0 16px; 104 } 105 106 </style> 107 108 <script type="text/javascript"> 109 function onCaptchaReady() { 110 const theme = document.documentElement.classList.contains('dark-mode') ? 111 'dark' : 112 document.documentElement.classList.contains('light-mode') ? 113 'light' : 114 window.matchMedia('(prefers-color-scheme: dark)').matches ? 115 'dark' : 116 'light' 117 hcaptcha.render('hcaptcha', {theme}); 118 } 119 120 function onCaptchaComplete() { 121 setTimeout(function () { 122 document.getElementById('gate-form').submit(); 123 }, 1000); 124 } 125 126 function onCaptchaError() { 127 const url = new URL(location.href); 128 url.searchParams.set('error', 'true'); 129 location.assign(url.search); 130 } 131 132 function onCaptchaExpired() { 133 const url = new URL(location.href); 134 url.searchParams.set('error', 'expired'); 135 location.assign(url.search); 136 } 137 </script> 138 <script 139 src="https://js.hcaptcha.com/1/api.js?render=explicit&onload=onCaptchaReady" 140 async 141 defer 142 ></script> 143 <link rel="stylesheet" href="/gate/signup/assets/common.css"/> 144</head> 145 146<body class="gate-page"> 147<div class="main"> 148 <div class="pds-title">{{pds}}</div> 149 <form id="gate-form" action="" method="POST"> 150 <div 151 id="hcaptcha" 152 data-sitekey="{{captcha_site_key}}" 153 data-callback="onCaptchaComplete" 154 data-error-callback="onCaptchaError" 155 data-expired-callback="onCaptchaExpired" 156 data-chalexpired-callback="onCaptchaExpired" 157 ></div> 158 <input type="hidden" name="redirect_url" value="{{redirect_url}}"/> 159 </form> 160 {{#if error_message }} 161 <div class="info">{{error_message}}</div> 162 {{/if}} 163 164</div> 165</body> 166</html>