<!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{{hostname}} - Mail-in-a-Box Control Panel</title> <meta name="robots" content="noindex, nofollow"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous"> <style> body { overflow-y: scroll; padding-bottom: 20px; } p { margin-bottom: 1.25em; } h1, h2, h3, h4 { font-family: sans-serif; font-weight: bold; } h2 { margin: 1em 0; } h3 { font-size: 130%; border-bottom: 1px solid black; padding-bottom: 3px; margin-bottom: 13px; margin-top: 30px; } .panel-heading h3 { border: none; padding: 0; margin: 0; } h4 { font-size: 110%; margin-bottom: 13px; margin-top: 18px; } h4:first-child { margin-top: 6px; } .admin_panel { display: none; } table.table { margin: 1.5em 0; } ol li { margin-bottom: 1em; } </style> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous"> </head> <body> <!--[if lt IE 8]><p>Internet Explorer version 8 or any modern web browser is required to use this website, sorry.<![endif]--> <!--[if gt IE 7]><!--> <div class="navbar navbar-inverse navbar-static-top" role="navigation"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">{{hostname}}</a> </div> <div class="navbar-collapse collapse"> <ul class="nav navbar-nav"> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">System <b class="caret"></b></a> <ul class="dropdown-menu"> <li><a href="#system_status" onclick="return show_panel(this);">Status Checks</a></li> <li><a href="#tls" onclick="return show_panel(this);">TLS (SSL) Certificates</a></li> <li><a href="#system_backup" onclick="return show_panel(this);">Backup Status</a></li> <li class="divider"></li> <li class="dropdown-header">Advanced Pages</li> <li><a href="#custom_dns" onclick="return show_panel(this);">Custom DNS</a></li> <li><a href="#external_dns" onclick="return show_panel(this);">External DNS</a></li> <li><a href="/admin/munin">Munin Monitoring</a></li> </ul> </li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">Mail <b class="caret"></b></a> <ul class="dropdown-menu"> <li><a href="#mail-guide" onclick="return show_panel(this);">Instructions</a></li> <li><a href="#users" onclick="return show_panel(this);">Users</a></li> <li><a href="#aliases" onclick="return show_panel(this);">Aliases</a></li> </ul> </li> <li><a href="#sync_guide" onclick="return show_panel(this);">Contacts/Calendar</a></li> <li><a href="#web" onclick="return show_panel(this);">Web</a></li> </ul> <ul class="nav navbar-nav navbar-right"> <li><a href="#" onclick="do_logout(); return false;" style="color: white">Log out?</a></li> </ul> </div><!--/.navbar-collapse --> </div> </div> <div class="container"> <div id="panel_system_status" class="admin_panel"> {% include "system-status.html" %} </div> <div id="panel_system_backup" class="admin_panel"> {% include "system-backup.html" %} </div> <div id="panel_external_dns" class="admin_panel"> {% include "external-dns.html" %} </div> <div id="panel_custom_dns" class="admin_panel"> {% include "custom-dns.html" %} </div> <div id="panel_login" class="admin_panel"> {% include "login.html" %} </div> <div id="panel_mail-guide" class="admin_panel"> {% include "mail-guide.html" %} </div> <div id="panel_users" class="admin_panel"> {% include "users.html" %} </div> <div id="panel_aliases" class="admin_panel"> {% include "aliases.html" %} </div> <div id="panel_sync_guide" class="admin_panel"> {% include "sync-guide.html" %} </div> <div id="panel_web" class="admin_panel"> {% include "web.html" %} </div> <div id="panel_tls" class="admin_panel"> {% include "ssl.html" %} </div> <hr> <footer> <p>This is a <a href="https://mailinabox.email">Mail-in-a-Box</a>.</p> </footer> </div> <!-- /container --> <div id="ajax_loading_indicator" style="display: none; position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-index: 100000; text-align: center; background-color: rgba(255,255,255,.75)"> <div style="margin: 20% auto"> <div><span class="fa fa-spinner fa-pulse"></span></div> <div>Loading...</div> </div> </div> <div id="global_modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="errorModalTitle" aria-hidden="true"> <div class="modal-dialog modal-sm"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <h4 class="modal-title" id="errorModalTitle"> </h4> </div> <div class="modal-body"> <p> </p> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">OK</button> <button type="button" class="btn btn-danger" data-dismiss="modal">Yes</button> </div> </div> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js" integrity="sha256-rsPUGdUPBXgalvIj4YKJrrUlmLXbOb6Cp7cdxn1qeUc=" crossorigin="anonymous"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script> <script> var global_modal_state = null; var global_modal_funcs = null; $(function() { $('#global_modal').on('shown.bs.modal', function (e) { // set focus to first input in the global modal's body var input = $('#global_modal .modal-body input'); if (input.length > 0) $(input[0]).focus(); }) $('#global_modal .btn-danger').click(function() { // Don't take action now. Wait for the modal to be totally hidden // so that we don't attempt to show another modal while this one // is closing. global_modal_state = 0; // OK }) $('#global_modal .btn-default').click(function() { global_modal_state = 1; // Cancel }) $('#global_modal').on('hidden.bs.modal', function (e) { // do the cancel function if (global_modal_state == null) global_modal_state = 1; // cancel if the user hit ESC or clicked outside of the modal if (global_modal_funcs && global_modal_funcs[global_modal_state]) global_modal_funcs[global_modal_state](); }) }) function show_modal_error(title, message, callback) { $('#global_modal h4').text(title); $('#global_modal .modal-body').html("<p/>"); if (typeof question == 'string') { $('#global_modal p').text(message); $('#global_modal .modal-dialog').addClass("modal-sm"); } else { $('#global_modal p').html("").append(message); $('#global_modal .modal-dialog').removeClass("modal-sm"); } $('#global_modal .btn-default').show().text("OK"); $('#global_modal .btn-danger').hide(); global_modal_funcs = [callback, callback]; global_modal_state = null; $('#global_modal').modal({}); return false; // handy when called from onclick } function show_modal_confirm(title, question, verb, yes_callback, cancel_callback) { $('#global_modal h4').text(title); if (typeof question == 'string') { $('#global_modal .modal-dialog').addClass("modal-sm"); $('#global_modal .modal-body').html("<p/>"); $('#global_modal p').text(question); } else { $('#global_modal .modal-dialog').removeClass("modal-sm"); $('#global_modal .modal-body').html("").append(question); } if (typeof verb == 'string') { $('#global_modal .btn-default').show().text("Cancel"); $('#global_modal .btn-danger').show().text(verb); } else { $('#global_modal .btn-default').show().text(verb[1]); $('#global_modal .btn-danger').show().text(verb[0]); } global_modal_funcs = [yes_callback, cancel_callback]; global_modal_state = null; $('#global_modal').modal({}); return false; // handy when called from onclick } var ajax_num_executing_requests = 0; function ajax_with_indicator(options) { setTimeout("if (ajax_num_executing_requests > 0) $('#ajax_loading_indicator').fadeIn()", 100); function hide_loading_indicator() { ajax_num_executing_requests--; if (ajax_num_executing_requests == 0) $('#ajax_loading_indicator').stop(true).hide(); // stop() prevents an ongoing fade from causing the thing to be shown again after this call } var old_success = options.success; var old_error = options.error; options.success = function(data) { hide_loading_indicator(); if (data.status == "error") show_modal_error("Error", data.message); else if (old_success) old_success(data); }; options.error = function(jqxhr) { hide_loading_indicator(); if (!old_error) show_modal_error("Error", "Something went wrong, sorry.") else old_error(jqxhr.responseText, jqxhr); }; ajax_num_executing_requests++; $.ajax(options); return false; // handy when called from onclick } var api_credentials = ["", ""]; function api(url, method, data, callback, callback_error) { // from http://www.webtoolkit.info/javascript-base64.html function base64encode(input) { _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; var output = ""; var chr1, chr2, chr3, enc1, enc2, enc3, enc4; var i = 0; while (i < input.length) { chr1 = input.charCodeAt(i++); chr2 = input.charCodeAt(i++); chr3 = input.charCodeAt(i++); enc1 = chr1 >> 2; enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); enc4 = chr3 & 63; if (isNaN(chr2)) { enc3 = enc4 = 64; } else if (isNaN(chr3)) { enc4 = 64; } output = output + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4); } return output; } function default_error(text, xhr) { if (xhr.status != 403) // else handled below show_modal_error("Error", "Something went wrong, sorry.") } ajax_with_indicator({ url: "/admin" + url, method: method, cache: false, data: data, // the custom DNS api sends raw POST/PUT bodies --- prevent URL-encoding processData: typeof data != "string", mimeType: typeof data == "string" ? "text/plain; charset=ascii" : null, beforeSend: function(xhr) { // We don't store user credentials in a cookie to avoid the hassle of CSRF // attacks. The Authorization header only gets set in our AJAX calls triggered // by user actions. xhr.setRequestHeader( 'Authorization', 'Basic ' + base64encode(api_credentials[0] + ':' + api_credentials[1])); }, success: callback, error: callback_error || default_error, statusCode: { 403: function(xhr) { // Credentials are no longer valid. Try to login again. var p = current_panel; show_panel('login'); switch_back_to_panel = p; } } }) } var current_panel = null; var switch_back_to_panel = null; function show_panel(panelid) { if (panelid.getAttribute) // we might be passed an HTMLElement <a>. panelid = panelid.getAttribute('href').substring(1); $('.admin_panel').hide(); $('#panel_' + panelid).show(); if (typeof localStorage != 'undefined') localStorage.setItem("miab-cp-lastpanel", panelid); if (window["show_" + panelid]) window["show_" + panelid](); current_panel = panelid; switch_back_to_panel = null; return false; // when called from onclick, cancel navigation } $(function() { // Recall saved user credentials. if (typeof sessionStorage != 'undefined' && sessionStorage.getItem("miab-cp-credentials")) api_credentials = sessionStorage.getItem("miab-cp-credentials").split(":"); else if (typeof localStorage != 'undefined' && localStorage.getItem("miab-cp-credentials")) api_credentials = localStorage.getItem("miab-cp-credentials").split(":"); // Recall what the user was last looking at. if (typeof localStorage != 'undefined' && localStorage.getItem("miab-cp-lastpanel")) { show_panel(localStorage.getItem("miab-cp-lastpanel")); } else { show_panel('login'); } }) </script> </body> </html>