blob: 8738cc64a85fdcaac9c115df75fca1eededc8d18 [file] [log] [blame]
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001<?php
2require_once $_SERVER['DOCUMENT_ROOT'] . '/modals/footer.php';
3logger();
4
5$hash = $js_minifier->getDataHash();
6$JSPath = '/tmp/' . $hash . '.js';
7if(!file_exists($JSPath)) {
8 $js_minifier->minify($JSPath);
9 cleanupJS($hash);
10}
11?>
12<script src="/cache/<?=basename($JSPath)?>"></script>
13<script>
14<?php
15$lang_footer = json_encode($lang['footer']);
16$lang_acl = json_encode($lang['acl']);
17$lang_tfa = json_encode($lang['tfa']);
18$lang_fido2 = json_encode($lang['fido2']);
19echo "var lang_footer = ". $lang_footer . ";\n";
20echo "var lang_acl = ". $lang_acl . ";\n";
21echo "var lang_tfa = ". $lang_tfa . ";\n";
22echo "var lang_fido2 = ". $lang_fido2 . ";\n";
23echo "var docker_timeout = ". $DOCKER_TIMEOUT * 1000 . ";\n";
24?>
25$(window).scroll(function() {
26 sessionStorage.scrollTop = $(this).scrollTop();
27});
28// Select language and reopen active URL without POST
29function setLang(sel) {
30 $.post( "<?= $_SERVER['REQUEST_URI']; ?>", {lang: sel} );
31 window.location.href = window.location.pathname + window.location.search;
32}
33// FIDO2 functions
34function arrayBufferToBase64(buffer) {
35 let binary = '';
36 let bytes = new Uint8Array(buffer);
37 let len = bytes.byteLength;
38 for (let i = 0; i < len; i++) {
39 binary += String.fromCharCode( bytes[ i ] );
40 }
41 return window.btoa(binary);
42}
43function recursiveBase64StrToArrayBuffer(obj) {
44 let prefix = '=?BINARY?B?';
45 let suffix = '?=';
46 if (typeof obj === 'object') {
47 for (let key in obj) {
48 if (typeof obj[key] === 'string') {
49 let str = obj[key];
50 if (str.substring(0, prefix.length) === prefix && str.substring(str.length - suffix.length) === suffix) {
51 str = str.substring(prefix.length, str.length - suffix.length);
52 let binary_string = window.atob(str);
53 let len = binary_string.length;
54 let bytes = new Uint8Array(len);
55 for (let i = 0; i < len; i++) {
56 bytes[i] = binary_string.charCodeAt(i);
57 }
58 obj[key] = bytes.buffer;
59 }
60 } else {
61 recursiveBase64StrToArrayBuffer(obj[key]);
62 }
63 }
64 }
65}
66$(window).load(function() {
67 $(".overlay").hide();
68});
69$(document).ready(function() {
70 $(document).on('shown.bs.modal', function(e) {
71 modal_id = $(e.relatedTarget).data('target');
72 $(modal_id).attr("aria-hidden","false");
73 });
74 // TFA, CSRF, Alerts in footer.inc.php
75 // Other general functions in mailcow.js
76 <?php
77 $alertbox_log_parser = alertbox_log_parser($_SESSION);
78 if (is_array($alertbox_log_parser)) {
79 foreach($alertbox_log_parser as $log) {
80 $alerts[$log['type']][] = $log['msg'];
81 }
82 foreach($alerts as $alert_type => $alert_msg) {
83 ?>
84 mailcow_alert_box(<?=json_encode(implode('<hr class="alert-hr">', $alert_msg));?>, <?=$alert_type;?>);
85 <?php
86 }
87 unset($_SESSION['return']);
88 }
89 ?>
90 // Confirm TFA modal
91 <?php if (isset($_SESSION['pending_tfa_method'])):?>
92 $('#ConfirmTFAModal').modal({
93 backdrop: 'static',
94 keyboard: false
95 });
96 $('#u2f_status_auth').html('<p><span class="glyphicon glyphicon-refresh glyphicon-spin"></span> ' + lang_tfa.init_u2f + '</p>');
97 $('#ConfirmTFAModal').on('shown.bs.modal', function(){
98 $(this).find('input[name=token]').focus();
99 // If U2F
100 if(document.getElementById("u2f_auth_data") !== null) {
101 $.ajax({
102 type: "GET",
103 cache: false,
104 dataType: 'script',
105 url: "/api/v1/get/u2f-authentication/<?= (isset($_SESSION['pending_mailcow_cc_username'])) ? rawurlencode($_SESSION['pending_mailcow_cc_username']) : null; ?>",
106 complete: function(data){
107 $('#u2f_status_auth').html(lang_tfa.waiting_usb_auth);
108 data;
109 setTimeout(function() {
110 console.log("Ready to authenticate");
111 u2f.sign(appId, challenge, registeredKeys, function(data) {
112 var form = document.getElementById('u2f_auth_form');
113 var auth = document.getElementById('u2f_auth_data');
114 console.log("Authenticate callback", data);
115 auth.value = JSON.stringify(data);
116 form.submit();
117 });
118 }, 1000);
119 }
120 });
121 }
122 });
123 $('#ConfirmTFAModal').on('hidden.bs.modal', function(){
124 $.ajax({
125 type: "GET",
126 cache: false,
127 dataType: 'script',
128 url: '/inc/ajax/destroy_tfa_auth.php',
129 complete: function(data){
130 window.location = window.location.href.split("#")[0];
131 }
132 });
133 });
134 <?php endif; ?>
135 // Validate FIDO2
136 $("#fido2-login").click(function(){
137 $('#fido2-alerts').html();
138 if (!window.fetch || !navigator.credentials || !navigator.credentials.create) {
139 window.alert('Browser not supported.');
140 return;
141 }
142 window.fetch("/api/v1/get/fido2-get-args", {method:'GET',cache:'no-cache'}).then(function(response) {
143 return response.json();
144 }).then(function(json) {
145 if (json.success === false) {
146 throw new Error();
147 }
148 recursiveBase64StrToArrayBuffer(json);
149 return json;
150 }).then(function(getCredentialArgs) {
151 return navigator.credentials.get(getCredentialArgs);
152 }).then(function(cred) {
153 return {
154 id: cred.rawId ? arrayBufferToBase64(cred.rawId) : null,
155 clientDataJSON: cred.response.clientDataJSON ? arrayBufferToBase64(cred.response.clientDataJSON) : null,
156 authenticatorData: cred.response.authenticatorData ? arrayBufferToBase64(cred.response.authenticatorData) : null,
157 signature : cred.response.signature ? arrayBufferToBase64(cred.response.signature) : null
158 };
159 }).then(JSON.stringify).then(function(AuthenticatorAttestationResponse) {
160 return window.fetch("/api/v1/process/fido2-args", {method:'POST', body: AuthenticatorAttestationResponse, cache:'no-cache'});
161 }).then(function(response) {
162 return response.json();
163 }).then(function(json) {
164 if (json.success) {
165 window.location = window.location.href.split("#")[0];
166 } else {
167 throw new Error();
168 }
169 }).catch(function(err) {
170 if (typeof err.message === 'undefined') {
171 mailcow_alert_box(lang_fido2.fido2_validation_failed, "danger");
172 } else {
173 mailcow_alert_box(lang_fido2.fido2_validation_failed + ":<br><i>" + err.message + "</i>", "danger");
174 }
175 });
176 });
177 // Set TFA/FIDO2
178 $("#register-fido2").click(function(){
179 $("option:selected").prop("selected", false);
180 if (!window.fetch || !navigator.credentials || !navigator.credentials.create) {
181 window.alert('Browser not supported.');
182 return;
183 }
184 window.fetch("/api/v1/get/fido2-registration/<?= (isset($_SESSION['mailcow_cc_username'])) ? rawurlencode($_SESSION['mailcow_cc_username']) : null; ?>", {method:'GET',cache:'no-cache'}).then(function(response) {
185 return response.json();
186 }).then(function(json) {
187 if (json.success === false) {
188 throw new Error(json.msg);
189 }
190 recursiveBase64StrToArrayBuffer(json);
191 return json;
192 }).then(function(createCredentialArgs) {
193 console.log(createCredentialArgs);
194 return navigator.credentials.create(createCredentialArgs);
195 }).then(function(cred) {
196 return {
197 clientDataJSON: cred.response.clientDataJSON ? arrayBufferToBase64(cred.response.clientDataJSON) : null,
198 attestationObject: cred.response.attestationObject ? arrayBufferToBase64(cred.response.attestationObject) : null
199 };
200 }).then(JSON.stringify).then(function(AuthenticatorAttestationResponse) {
201 return window.fetch("/api/v1/add/fido2-registration", {method:'POST', body: AuthenticatorAttestationResponse, cache:'no-cache'});
202 }).then(function(response) {
203 return response.json();
204 }).then(function(json) {
205 if (json.success) {
206 window.location = window.location.href.split("#")[0];
207 } else {
208 throw new Error(json.msg);
209 }
210 }).catch(function(err) {
211 $('#fido2-alerts').html('<span class="text-danger"><b>' + err.message + '</b></span>');
212 });
213 });
214 $('#selectTFA').change(function () {
215 if ($(this).val() == "yubi_otp") {
216 $('#YubiOTPModal').modal('show');
217 $("option:selected").prop("selected", false);
218 }
219 if ($(this).val() == "totp") {
220 $('#TOTPModal').modal('show');
221 request_token = $('#tfa-qr-img').data('totp-secret');
222 $.ajax({
223 url: '/inc/ajax/qr_gen.php',
224 data: {
225 token: request_token,
226 },
227 }).done(function (result) {
228 $("#tfa-qr-img").attr("src", result);
229 });
230 $("option:selected").prop("selected", false);
231 }
232 if ($(this).val() == "u2f") {
233 $('#U2FModal').modal('show');
234 $("option:selected").prop("selected", false);
235 $("#start_u2f_register").click(function(){
236 $('#u2f_return_code').html('');
237 $('#u2f_return_code').hide();
238 $('#u2f_status_reg').html('<p><span class="glyphicon glyphicon-refresh glyphicon-spin"></span> ' + lang_tfa.init_u2f + '</p>');
239 $.ajax({
240 type: "GET",
241 cache: false,
242 dataType: 'script',
243 url: "/api/v1/get/u2f-registration/<?= (isset($_SESSION['mailcow_cc_username'])) ? rawurlencode($_SESSION['mailcow_cc_username']) : null; ?>",
244 complete: function(data){
245 data;
246 setTimeout(function() {
247 console.log("Ready to register");
248 $('#u2f_status_reg').html(lang_tfa.waiting_usb_register);
249 u2f.register(appId, registerRequests, registeredKeys, function(deviceResponse) {
250 var form = document.getElementById('u2f_reg_form');
251 var reg = document.getElementById('u2f_register_data');
252 console.log("Register callback: ", data);
253 if (deviceResponse.errorCode && deviceResponse.errorCode != 0) {
254 var u2f_return_code = document.getElementById('u2f_return_code');
255 u2f_return_code.style.display = u2f_return_code.style.display === 'none' ? '' : null;
256 if (deviceResponse.errorCode == "4") {
257 deviceResponse.errorCode = "4 - The presented device is not eligible for this request. For a registration request this may mean that the token is already registered, and for a sign request it may mean that the token does not know the presented key handle";
258 }
259 else if (deviceResponse.errorCode == "5") {
260 deviceResponse.errorCode = "5 - Timeout reached before request could be satisfied.";
261 }
262 u2f_return_code.innerHTML = lang_tfa.error_code + ': ' + deviceResponse.errorCode + ' ' + lang_tfa.reload_retry;
263 return;
264 }
265 reg.value = JSON.stringify(deviceResponse);
266 form.submit();
267 });
268 }, 1000);
269 }
270 });
271 });
272 }
273 if ($(this).val() == "none") {
274 $('#DisableTFAModal').modal('show');
275 $("option:selected").prop("selected", false);
276 }
277 });
278
279 // Reload after session timeout
280 var session_lifetime = <?=((int)$SESSION_LIFETIME * 1000) + 15000;?>;
281 <?php
282 if (isset($_SESSION['mailcow_cc_username'])):
283 ?>
284 setTimeout(function() {
285 location.reload();
286 }, session_lifetime);
287 <?php
288 endif;
289 ?>
290
291 // CSRF
292 $('<input type="hidden" value="<?= $_SESSION['CSRF']['TOKEN']; ?>">').attr('name', 'csrf_token').appendTo('form');
293 if (sessionStorage.scrollTop != "undefined") {
294 $(window).scrollTop(sessionStorage.scrollTop);
295 }
296});
297</script>
298
299 <div class="container footer">
300 <?php if (!empty($UI_TEXTS['ui_footer'])) { ?>
301 <hr><span class="rot-enc"><?=str_rot13($UI_TEXTS['ui_footer']);?></span>
302 <?php } ?>
303 </div>
304</body>
305</html>
306<?php
307$stmt = null;
308$pdo = null;