mirror of
				https://github.com/mail-in-a-box/mailinabox.git
				synced 2025-11-02 19:20:54 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			404 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			404 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<!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.0/css/bootstrap.min.css">
 | 
						|
        <style>
 | 
						|
            @import url(https://fonts.googleapis.com/css?family=Raleway:400,700);
 | 
						|
            @import url(https://fonts.googleapis.com/css?family=Ubuntu:300);
 | 
						|
 | 
						|
	    html {
 | 
						|
		overflow-y: scroll;
 | 
						|
	    }
 | 
						|
 | 
						|
            body {
 | 
						|
                padding-top: 50px;
 | 
						|
                padding-bottom: 20px;
 | 
						|
            }
 | 
						|
 | 
						|
            p {
 | 
						|
              margin-bottom: 1.25em;
 | 
						|
            }
 | 
						|
 | 
						|
            h1, h2, h3, h4 {
 | 
						|
              font-family: Raleway, 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.0/css/bootstrap-theme.min.css">
 | 
						|
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
 | 
						|
    </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-fixed-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="#ssl" onclick="return show_panel(this);">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 Options</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>
 | 
						|
              </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_ssl" 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.1/jquery.min.js"></script>
 | 
						|
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></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(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({
 | 
						|
    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>
 |