<style> .title { margin: 1em; text-align: center; } .subtitle { margin: 2em; text-align: center; } .login { margin: 0 auto; max-width: 32em; } .login #loginOtp { display: none; } #loginForm.is-twofactor #loginOtp { display: block } </style> <h1 class="title">{{hostname}}</h1> {% if no_users_exist or no_admins_exist %} <div class="row"> <div class="col-md-offset-2 col-md-8"> {% if no_users_exist %} <p class="text-danger">There are no users on this system! To make an administrative user, log into this machine using SSH (like when you first set it up) and run:</p> <pre>cd mailinabox sudo management/cli.py user add me@{{hostname}} sudo management/cli.py user make-admin me@{{hostname}}</pre> {% else %} <p class="text-danger">There are no administrative users on this system! To make an administrative user, log into this machine using SSH (like when you first set it up) and run:</p> <pre>cd mailinabox sudo management/cli.py user make-admin me@{{hostname}}</pre> {% endif %} <hr> </div> </div> {% endif %} <p class="subtitle">Log in here for your Mail-in-a-Box control panel.</p> <div class="login"> <form id="loginForm" class="form-horizontal" role="form" onsubmit="do_login(); return false;" method="get"> <div class="form-group"> <label for="inputEmail3" class="col-sm-3 control-label">Email</label> <div class="col-sm-9"> <input name="email" type="email" class="form-control" id="loginEmail" placeholder="Email"> </div> </div> <div class="form-group"> <label for="inputPassword3" class="col-sm-3 control-label">Password</label> <div class="col-sm-9"> <input name="password" type="password" class="form-control" id="loginPassword" placeholder="Password"> </div> </div> <div class="form-group" id="loginOtp"> <label for="loginOtpInput" class="col-sm-3 control-label">Code</label> <div class="col-sm-9"> <input type="text" class="form-control" id="loginOtpInput" placeholder="6-digit code" autocomplete="off"> <div class="help-block" style="margin-top: 5px; font-size: 90%">Enter the six-digit code generated by your two factor authentication app.</div> </div> </div> <div class="form-group"> <div class="col-sm-offset-3 col-sm-9"> <div class="checkbox"> <label> <input name='remember' type="checkbox" id="loginRemember"> Remember me </label> </div> </div> </div> <div class="form-group"> <div class="col-sm-offset-3 col-sm-9"> <button type="submit" class="btn btn-default">Sign in</button> </div> </div> </form> </div> <script> function do_login() { if ($('#loginEmail').val() == "") { show_modal_error("Login Failed", "Enter your email address.", function() { $('#loginEmail').focus(); }); return false; } if ($('#loginPassword').val() == "") { show_modal_error("Login Failed", "Enter your email password.", function() { $('#loginPassword').focus(); }); return false; } // Exchange the email address & password for an API key. api_credentials = { username: $('#loginEmail').val(), session_key: $('#loginPassword').val() } api( "/login", "POST", {}, function(response) { // This API call always succeeds. It returns a JSON object indicating // whether the request was authenticated or not. if (response.status != 'ok') { if (response.status === 'missing-totp-token' || (response.status === 'invalid' && response.reason == 'invalid-totp-token')) { $('#loginForm').addClass('is-twofactor'); if (response.reason === "invalid-totp-token") { show_modal_error("Login Failed", "Incorrect two factor authentication token."); } else { setTimeout(() => { $('#loginOtpInput').focus(); }); } } else { $('#loginForm').removeClass('is-twofactor'); // Show why the login failed. show_modal_error("Login Failed", response.reason) // Reset any saved credentials. do_logout(); } } else if (!("api_key" in response)) { // Login succeeded but user might not be authorized! show_modal_error("Login Failed", "You are not an administrator on this system.") // Reset any saved credentials. do_logout(); } else { // Login succeeded. // Save the new credentials. api_credentials = { username: response.email, session_key: response.api_key, privileges: response.privileges }; // Try to wipe the username/password information. $('#loginEmail').val(''); $('#loginPassword').val(''); $('#loginOtpInput').val(''); $('#loginForm').removeClass('is-twofactor'); // Remember the credentials. if (typeof localStorage != 'undefined' && typeof sessionStorage != 'undefined') { if ($('#loginRemember').val()) { localStorage.setItem("miab-cp-credentials", JSON.stringify(api_credentials)); sessionStorage.removeItem("miab-cp-credentials"); } else { localStorage.removeItem("miab-cp-credentials"); sessionStorage.setItem("miab-cp-credentials", JSON.stringify(api_credentials)); } } // Toggle menus. show_hide_menus(); // Open the next panel the user wants to go to. Do this after the XHR response // is over so that we don't start a new XHR request while this one is finishing, // which confuses the loading indicator. setTimeout(function() { show_panel(!switch_back_to_panel || switch_back_to_panel == "login" ? 'welcome' : switch_back_to_panel) }, 300); } }, undefined, { 'x-auth-token': $('#loginOtpInput').val() }); } function show_login() { $('#loginForm').removeClass('is-twofactor'); $('#loginOtpInput').val(''); $('#loginEmail,#loginPassword').each(function() { var input = $(this); if (!$.trim(input.val())) { input.focus(); return false; } }); } function show_hide_menus() { var is_logged_in = (api_credentials != null); var privs = api_credentials ? api_credentials.privileges : []; $('.if-logged-in').toggle(is_logged_in); $('.if-logged-in-admin, .if-logged-in-not-admin').toggle(false); if (is_logged_in) { $('.if-logged-in-not-admin').toggle(true); privs.forEach(function(priv) { $('.if-logged-in-' + priv).toggle(true); $('.if-logged-in-not-' + priv).toggle(false); }); } $('.if-not-logged-in').toggle(!is_logged_in); } </script>