Allow non-admin login to the control panel and show/hide menu items depending on the login state

* When logged out, no menu items are shown.
* When logged in, Log Out is shown.
* When logged in as an admin, the remaining menu items are also shown.
* When logged in as a non-admin, the mail and contacts/calendar instruction pages are shown.

Fixes #1987
This commit is contained in:
Joshua Tauberer 2021-08-22 16:40:07 -04:00
parent 26932ecb10
commit e5909a6287
3 changed files with 57 additions and 23 deletions

View File

@ -62,6 +62,9 @@
ol li { ol li {
margin-bottom: 1em; margin-bottom: 1em;
} }
.if-logged-in { display: none; }
.if-logged-in-admin { display: none; }
</style> </style>
<link rel="stylesheet" href="/admin/assets/bootstrap/css/bootstrap-theme.min.css"> <link rel="stylesheet" href="/admin/assets/bootstrap/css/bootstrap-theme.min.css">
</head> </head>
@ -83,7 +86,7 @@
</div> </div>
<div class="navbar-collapse collapse"> <div class="navbar-collapse collapse">
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
<li class="dropdown"> <li class="dropdown if-logged-in-admin">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">System <b class="caret"></b></a> <a href="#" class="dropdown-toggle" data-toggle="dropdown">System <b class="caret"></b></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="#system_status" onclick="return show_panel(this);">Status Checks</a></li> <li><a href="#system_status" onclick="return show_panel(this);">Status Checks</a></li>
@ -96,7 +99,8 @@
<li><a href="/admin/munin" target="_blank">Munin Monitoring</a></li> <li><a href="/admin/munin" target="_blank">Munin Monitoring</a></li>
</ul> </ul>
</li> </li>
<li class="dropdown"> <li><a href="#mail-guide" onclick="return show_panel(this);" class="if-logged-in-not-admin">Mail</a></li>
<li class="dropdown if-logged-in-admin">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Mail &amp; Users <b class="caret"></b></a> <a href="#" class="dropdown-toggle" data-toggle="dropdown">Mail &amp; Users <b class="caret"></b></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="#mail-guide" onclick="return show_panel(this);">Instructions</a></li> <li><a href="#mail-guide" onclick="return show_panel(this);">Instructions</a></li>
@ -107,11 +111,11 @@
<li><a href="#mfa" onclick="return show_panel(this);">Two-Factor Authentication</a></li> <li><a href="#mfa" onclick="return show_panel(this);">Two-Factor Authentication</a></li>
</ul> </ul>
</li> </li>
<li><a href="#sync_guide" onclick="return show_panel(this);">Contacts/Calendar</a></li> <li><a href="#sync_guide" onclick="return show_panel(this);" class="if-logged-in">Contacts/Calendar</a></li>
<li><a href="#web" onclick="return show_panel(this);">Web</a></li> <li><a href="#web" onclick="return show_panel(this);" class="if-logged-in-admin">Web</a></li>
</ul> </ul>
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
<li><a href="#" onclick="do_logout(); return false;" style="color: white">Log out</a></li> <li class="if-logged-in"><a href="#" onclick="do_logout(); return false;" style="color: white">Log out</a></li>
</ul> </ul>
</div><!--/.navbar-collapse --> </div><!--/.navbar-collapse -->
</div> </div>
@ -302,7 +306,7 @@ function ajax_with_indicator(options) {
return false; // handy when called from onclick return false; // handy when called from onclick
} }
var api_credentials = ["", ""]; var api_credentials = null;
function api(url, method, data, callback, callback_error, headers) { function api(url, method, data, callback, callback_error, headers) {
// from http://www.webtoolkit.info/javascript-base64.html // from http://www.webtoolkit.info/javascript-base64.html
function base64encode(input) { function base64encode(input) {
@ -350,9 +354,10 @@ function api(url, method, data, callback, callback_error, headers) {
// We don't store user credentials in a cookie to avoid the hassle of CSRF // 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 // attacks. The Authorization header only gets set in our AJAX calls triggered
// by user actions. // by user actions.
if (api_credentials)
xhr.setRequestHeader( xhr.setRequestHeader(
'Authorization', 'Authorization',
'Basic ' + base64encode(api_credentials[0] + ':' + api_credentials[1])); 'Basic ' + base64encode(api_credentials.username + ':' + api_credentials.session_key));
}, },
success: callback, success: callback,
error: callback_error || default_error, error: callback_error || default_error,
@ -375,7 +380,7 @@ function do_logout() {
api("/logout", "POST"); api("/logout", "POST");
// Forget the token. // Forget the token.
api_credentials = ["", ""]; api_credentials = null;
if (typeof localStorage != 'undefined') if (typeof localStorage != 'undefined')
localStorage.removeItem("miab-cp-credentials"); localStorage.removeItem("miab-cp-credentials");
if (typeof sessionStorage != 'undefined') if (typeof sessionStorage != 'undefined')
@ -383,6 +388,9 @@ function do_logout() {
// Return to the start. // Return to the start.
show_panel('login'); show_panel('login');
// Reset menus.
show_hide_menus();
} }
function show_panel(panelid) { function show_panel(panelid) {
@ -405,15 +413,21 @@ function show_panel(panelid) {
$(function() { $(function() {
// Recall saved user credentials. // Recall saved user credentials.
try {
if (typeof sessionStorage != 'undefined' && sessionStorage.getItem("miab-cp-credentials")) if (typeof sessionStorage != 'undefined' && sessionStorage.getItem("miab-cp-credentials"))
api_credentials = sessionStorage.getItem("miab-cp-credentials").split(":"); api_credentials = JSON.parse(sessionStorage.getItem("miab-cp-credentials"));
else if (typeof localStorage != 'undefined' && localStorage.getItem("miab-cp-credentials")) else if (typeof localStorage != 'undefined' && localStorage.getItem("miab-cp-credentials"))
api_credentials = localStorage.getItem("miab-cp-credentials").split(":"); api_credentials = JSON.parse(localStorage.getItem("miab-cp-credentials"));
} catch (_) {
}
// Toggle menu state.
show_hide_menus();
// Recall what the user was last looking at. // Recall what the user was last looking at.
if (typeof localStorage != 'undefined' && localStorage.getItem("miab-cp-lastpanel")) { if (api_credentials != null && typeof localStorage != 'undefined' && localStorage.getItem("miab-cp-lastpanel")) {
show_panel(localStorage.getItem("miab-cp-lastpanel")); show_panel(localStorage.getItem("miab-cp-lastpanel"));
} else if (api_credentials[0] != "") { } else if (api_credentials != null) {
show_panel('welcome'); show_panel('welcome');
} else { } else {
show_panel('login'); show_panel('login');

View File

@ -102,7 +102,7 @@ function do_login() {
} }
// Exchange the email address & password for an API key. // Exchange the email address & password for an API key.
api_credentials = [$('#loginEmail').val(), $('#loginPassword').val()] api_credentials = { username: $('#loginEmail').val(), session_key: $('#loginPassword').val() }
api( api(
"/login", "/login",
@ -141,7 +141,9 @@ function do_login() {
// Login succeeded. // Login succeeded.
// Save the new credentials. // Save the new credentials.
api_credentials = [response.email, response.api_key]; api_credentials = { username: response.email,
session_key: response.api_key,
privileges: response.privileges };
// Try to wipe the username/password information. // Try to wipe the username/password information.
$('#loginEmail').val(''); $('#loginEmail').val('');
@ -152,14 +154,17 @@ function do_login() {
// Remember the credentials. // Remember the credentials.
if (typeof localStorage != 'undefined' && typeof sessionStorage != 'undefined') { if (typeof localStorage != 'undefined' && typeof sessionStorage != 'undefined') {
if ($('#loginRemember').val()) { if ($('#loginRemember').val()) {
localStorage.setItem("miab-cp-credentials", api_credentials.join(":")); localStorage.setItem("miab-cp-credentials", JSON.stringify(api_credentials));
sessionStorage.removeItem("miab-cp-credentials"); sessionStorage.removeItem("miab-cp-credentials");
} else { } else {
localStorage.removeItem("miab-cp-credentials"); localStorage.removeItem("miab-cp-credentials");
sessionStorage.setItem("miab-cp-credentials", api_credentials.join(":")); 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 // 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, // is over so that we don't start a new XHR request while this one is finishing,
// which confuses the loading indicator. // which confuses the loading indicator.
@ -183,4 +188,19 @@ function show_login() {
} }
}); });
} }
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> </script>

View File

@ -203,7 +203,7 @@ function users_set_password(elem) {
var email = $(elem).parents('tr').attr('data-email'); var email = $(elem).parents('tr').attr('data-email');
var yourpw = ""; var yourpw = "";
if (api_credentials != null && email == api_credentials[0]) if (api_credentials != null && email == api_credentials.username)
yourpw = "<p class='text-danger'>If you change your own password, you will be logged out of this control panel and will need to log in again.</p>"; yourpw = "<p class='text-danger'>If you change your own password, you will be logged out of this control panel and will need to log in again.</p>";
show_modal_confirm( show_modal_confirm(
@ -232,7 +232,7 @@ function users_remove(elem) {
var email = $(elem).parents('tr').attr('data-email'); var email = $(elem).parents('tr').attr('data-email');
// can't remove yourself // can't remove yourself
if (api_credentials != null && email == api_credentials[0]) { if (api_credentials != null && email == api_credentials.username) {
show_modal_error("Archive User", "You cannot archive your own account."); show_modal_error("Archive User", "You cannot archive your own account.");
return; return;
} }
@ -264,7 +264,7 @@ function mod_priv(elem, add_remove) {
var priv = $(elem).parents('td').find('.name').text(); var priv = $(elem).parents('td').find('.name').text();
// can't remove your own admin access // can't remove your own admin access
if (priv == "admin" && add_remove == "remove" && api_credentials != null && email == api_credentials[0]) { if (priv == "admin" && add_remove == "remove" && api_credentials != null && email == api_credentials.username) {
show_modal_error("Modify Privileges", "You cannot remove the admin privilege from yourself."); show_modal_error("Modify Privileges", "You cannot remove the admin privilege from yourself.");
return; return;
} }