2014-08-17 22:43:57 +00:00
< h2 > Users< / h2 >
< style >
2015-03-22 13:59:05 +00:00
#user_table h4 { margin: 1em 0 0 0; }
2014-10-07 20:24:11 +00:00
#user_table tr.account_inactive td.address { color: #888; text-decoration: line-through; }
2014-09-21 17:06:38 +00:00
#user_table .actions { margin-top: .33em; font-size: 95%; }
#user_table .account_inactive .if_active { display: none; }
#user_table .account_active .if_inactive { display: none; }
2015-03-22 13:59:05 +00:00
#user_table .account_active.if_inactive { display: none; }
2014-08-17 22:43:57 +00:00
< / style >
< h3 > Add a mail user< / h3 >
internationalized domain names (DNS, web, CSRs, normalize to Unicode in database, prohibit non-ASCII characters in user account names)
* For non-ASCII domain names, we will keep the Unicode encoding in our users/aliases table. This is nice for the user and also simplifies things like sorting domain names (using Unicode lexicographic order is good, using ASCII lexicogrpahic order on IDNA is confusing).
* Write nsd config, nsd zone files, nginx config, and SSL CSRs with domains in IDNA-encoded ASCII.
* When checking SSL certificates, treat the CN and SANs as IDNA.
* Since Chrome has an interesting feature of converting Unicode to IDNA in <input type="email"> form fields, we'll also forcibly convert IDNA to Unicode in the domain part of email addresses before saving email addresses in the users/aliases tables so that the table is normalized to Unicode.
* Don't allow non-ASCII characters in user account email addresses. Dovecot gets confused when querying the Sqlite database (which we observed even for non-word ASCII characters too, so it may not be related to the character encoding).
2015-01-17 13:41:53 +00:00
< p > Add an email address to this system. This will create a new login username/password.< / p >
2014-08-17 22:43:57 +00:00
< form class = "form-inline" role = "form" onsubmit = "return do_add_user(); return false;" >
< div class = "form-group" >
< label class = "sr-only" for = "adduserEmail" > Email address< / label >
< input type = "email" class = "form-control" id = "adduserEmail" placeholder = "Email Address" >
< / div >
< div class = "form-group" >
< label class = "sr-only" for = "adduserPassword" > Password< / label >
< input type = "password" class = "form-control" id = "adduserPassword" placeholder = "Password" >
< / div >
< div class = "form-group" >
< select class = "form-control" id = "adduserPrivs" >
< option value = "" > Normal User< / option >
< option value = "admin" > Administrator< / option >
< / select >
< / div >
2016-01-24 14:43:16 +00:00
< div class = "form-group" >
2016-01-27 17:30:19 +00:00
< div class = "col-sm-15" >
< div id = "user_service_buttons" class = "btn-group btn-group" >
< button id = "adduserMailHandling" data-mode = "mail" class = "btn btn-success active" disabled > MAIL< / button >
< button id = "adduserDnsHandling" data-mode = "dns" class = "btn btn-success active" > DNS< / button >
< button id = "adduserWebHandling" data-mode = "www" class = "btn btn-success active" > WWW< / button >
2016-01-24 14:43:16 +00:00
< / div >
< / div >
< / div >
2014-08-17 22:43:57 +00:00
< button type = "submit" class = "btn btn-primary" > Add User< / button >
< / form >
2016-01-27 17:30:19 +00:00
< div id = "user_service_info" class = "text-info small" style = "display: none; margin: .5em 0 0 0;" >
< span class = "dns hidden" > When deactivated, the DNS service is not configured for the domain< / span >
< span class = "www hidden" > When deactivated, the Web services is not configured for the domain< / span >
< / div >
internationalized domain names (DNS, web, CSRs, normalize to Unicode in database, prohibit non-ASCII characters in user account names)
* For non-ASCII domain names, we will keep the Unicode encoding in our users/aliases table. This is nice for the user and also simplifies things like sorting domain names (using Unicode lexicographic order is good, using ASCII lexicogrpahic order on IDNA is confusing).
* Write nsd config, nsd zone files, nginx config, and SSL CSRs with domains in IDNA-encoded ASCII.
* When checking SSL certificates, treat the CN and SANs as IDNA.
* Since Chrome has an interesting feature of converting Unicode to IDNA in <input type="email"> form fields, we'll also forcibly convert IDNA to Unicode in the domain part of email addresses before saving email addresses in the users/aliases tables so that the table is normalized to Unicode.
* Don't allow non-ASCII characters in user account email addresses. Dovecot gets confused when querying the Sqlite database (which we observed even for non-word ASCII characters too, so it may not be related to the character encoding).
2015-01-17 13:41:53 +00:00
< ul style = "margin-top: 1em; padding-left: 1.5em; font-size: 90%;" >
2015-09-04 22:12:07 +00:00
< li > Passwords must be at least four characters and may not contain spaces. For best results, < a href = "#" onclick = "return generate_random_password()" > generate a random password< / a > .< / li >
2015-07-25 14:12:43 +00:00
< li > Use < a href = "#" onclick = "return show_panel('aliases')" > aliases< / a > to create email addresses that forward to existing accounts.< / li >
internationalized domain names (DNS, web, CSRs, normalize to Unicode in database, prohibit non-ASCII characters in user account names)
* For non-ASCII domain names, we will keep the Unicode encoding in our users/aliases table. This is nice for the user and also simplifies things like sorting domain names (using Unicode lexicographic order is good, using ASCII lexicogrpahic order on IDNA is confusing).
* Write nsd config, nsd zone files, nginx config, and SSL CSRs with domains in IDNA-encoded ASCII.
* When checking SSL certificates, treat the CN and SANs as IDNA.
* Since Chrome has an interesting feature of converting Unicode to IDNA in <input type="email"> form fields, we'll also forcibly convert IDNA to Unicode in the domain part of email addresses before saving email addresses in the users/aliases tables so that the table is normalized to Unicode.
* Don't allow non-ASCII characters in user account email addresses. Dovecot gets confused when querying the Sqlite database (which we observed even for non-word ASCII characters too, so it may not be related to the character encoding).
2015-01-17 13:41:53 +00:00
< li > Administrators get access to this control panel.< / li >
2015-07-25 14:12:43 +00:00
< li > User accounts cannot contain any international (non-ASCII) characters, but < a href = "#" onclick = "return show_panel('aliases');" > aliases< / a > can.< / li >
internationalized domain names (DNS, web, CSRs, normalize to Unicode in database, prohibit non-ASCII characters in user account names)
* For non-ASCII domain names, we will keep the Unicode encoding in our users/aliases table. This is nice for the user and also simplifies things like sorting domain names (using Unicode lexicographic order is good, using ASCII lexicogrpahic order on IDNA is confusing).
* Write nsd config, nsd zone files, nginx config, and SSL CSRs with domains in IDNA-encoded ASCII.
* When checking SSL certificates, treat the CN and SANs as IDNA.
* Since Chrome has an interesting feature of converting Unicode to IDNA in <input type="email"> form fields, we'll also forcibly convert IDNA to Unicode in the domain part of email addresses before saving email addresses in the users/aliases tables so that the table is normalized to Unicode.
* Don't allow non-ASCII characters in user account email addresses. Dovecot gets confused when querying the Sqlite database (which we observed even for non-word ASCII characters too, so it may not be related to the character encoding).
2015-01-17 13:41:53 +00:00
< / ul >
2014-08-17 22:43:57 +00:00
< h3 > Existing mail users< / h3 >
< table id = "user_table" class = "table" style = "width: auto" >
2014-10-07 20:24:11 +00:00
< thead >
< tr >
< th width = "50%" > Email Address< / th >
< th > Actions< / th >
< th > Mailbox Size< / th >
< / tr >
< / thead >
2014-08-17 22:43:57 +00:00
< tbody >
< / tbody >
< / table >
< div style = "display: none" >
< table >
< tr id = "user-template" >
2014-10-07 20:24:11 +00:00
< td class = 'address' >
< / td >
< td class = 'actions' >
2014-09-21 17:06:38 +00:00
< span class = 'privs' >
< / span >
2014-09-21 17:24:01 +00:00
< span class = "if_active" >
< a href = "#" onclick = "users_set_password(this); return false;" class = 'setpw' title = "Set Password" >
set password
< / a >
|
< / span >
2014-09-21 17:06:38 +00:00
< span class = 'add-privs' >
< / span >
< a href = "#" onclick = "users_remove(this); return false;" class = 'if_active' title = "Archive Account" >
archive account
< / a >
2014-10-07 20:24:11 +00:00
< / td >
< td class = 'mailboxsize' >
< / td >
< / tr >
2015-03-22 13:59:05 +00:00
< tr id = "user-extra-template" class = "if_inactive" >
< td colspan = "3" style = "border: 0; padding-top: 0" >
< div class = 'restore_info' style = 'color: #888; font-size: 90%' > To restore account, create a new account with this email address. Or to permanently delete the mailbox, delete the directory < tt > < / tt > on the machine.< / div >
2014-08-17 22:43:57 +00:00
< / td >
< / tr >
< / table >
< / div >
< script >
function show_users() {
$('#user_table tbody').html("< tr > < td colspan = '2' class = 'text-muted' > Loading...< / td > < / tr > ")
api(
"/mail/users",
"GET",
{ format: 'json' },
function(r) {
$('#user_table tbody').html("");
for (var i = 0; i < r.length ; i + + ) {
2015-03-22 13:59:05 +00:00
var hdr = $("< tr > < td colspan = '3' > < h4 / > < / td > < / tr > ");
2014-10-07 19:28:07 +00:00
hdr.find('h4').text(r[i].domain);
$('#user_table tbody').append(hdr);
2014-08-17 22:43:57 +00:00
2014-10-07 19:28:07 +00:00
for (var k = 0; k < r [ i ] . users . length ; k + + ) {
var user = r[i].users[k];
2014-09-03 10:17:46 +00:00
2014-10-07 19:28:07 +00:00
var n = $("#user-template").clone();
2014-10-07 20:24:11 +00:00
var n2 = $("#user-extra-template").clone();
2014-10-07 19:28:07 +00:00
n.attr('id', '');
2014-10-07 20:24:11 +00:00
n2.attr('id', '');
$('#user_table tbody').append(n);
$('#user_table tbody').append(n2);
2014-08-17 22:43:57 +00:00
2014-10-07 19:28:07 +00:00
n.addClass("account_" + user.status);
2014-10-07 20:24:11 +00:00
n2.addClass("account_" + user.status);
2014-10-07 19:28:07 +00:00
n.attr('data-email', user.email);
2014-10-07 20:24:11 +00:00
n.find('.address').text(user.email)
n.find('.mailboxsize').text(nice_size(user.mailbox_size))
n2.find('.restore_info tt').text(user.mailbox);
2014-08-17 22:43:57 +00:00
2014-10-07 19:28:07 +00:00
if (user.status == 'inactive') continue;
2014-08-17 22:43:57 +00:00
2014-10-07 19:28:07 +00:00
var add_privs = ["admin"];
for (var j = 0; j < user.privileges.length ; j + + ) {
var p = $("< span > < b > < span class = 'name' > < / span > < / b > (< a href = '#' onclick = 'mod_priv(this, \"remove\"); return false;' title = 'Remove Privilege' > remove privilege< / a > ) |< / span > ");
p.find('span.name').text(user.privileges[j]);
n.find('.privs').append(p);
if (add_privs.indexOf(user.privileges[j]) >= 0)
add_privs.splice(add_privs.indexOf(user.privileges[j]), 1);
}
for (var j = 0; j < add_privs.length ; j + + ) {
var p = $("< span > < a href = '#' onclick = 'mod_priv(this, \"add\"); return false;' title = 'Add Privilege' > make < span class = 'name' > < / span > < / a > | < / span > ");
p.find('span.name').text(add_privs[j]);
n.find('.add-privs').append(p);
}
2014-08-17 22:43:57 +00:00
}
}
})
2016-01-27 17:30:19 +00:00
// Service buttons
$('#user_service_buttons button').off('click').click(function() {
if ($(this).hasClass('active')) {
$(this).removeClass('active');
$(this).addClass('btn-default');
$(this).removeClass('btn-success');
$('#user_service_info .www').addClass('hidden');
$('#user_service_info .dns').addClass('hidden');
if ($(this).attr('data-mode') == "dns") {
$('#user_service_info').slideDown();
$('#user_service_info .dns').removeClass('hidden');
} else if ($(this).attr('data-mode') == "www") {
$('#user_service_info').slideDown();
$('#user_service_info .www').removeClass('hidden');
}
} else {
$(this).addClass('active');
$(this).removeClass('btn-default');
$(this).addClass('btn-success');
$('#user_service_info').slideUp();
$('#user_service_info .www').addClass('hidden');
$('#user_service_info .dns').addClass('hidden');
}
return false;
});
2014-08-17 22:43:57 +00:00
}
function do_add_user() {
var email = $("#adduserEmail").val();
var pw = $("#adduserPassword").val();
var privs = $("#adduserPrivs").val();
2016-01-27 17:30:19 +00:00
var form_dns = $('#adduserDnsHandling').hasClass('active');
var form_web = $('#adduserWebHandling').hasClass('active');
2014-08-17 22:43:57 +00:00
api(
"/mail/users/add",
"POST",
{
email: email,
password: pw,
2016-01-24 14:43:16 +00:00
privileges: privs,
dns_enabled: form_dns,
web_enabled: form_web
2014-08-17 22:43:57 +00:00
},
function(r) {
// Responses are multiple lines of pre-formatted text.
show_modal_error("Add User", $("< pre / > ").text(r));
show_users()
},
function(r) {
show_modal_error("Add User", r);
});
return false;
}
2014-09-21 17:24:01 +00:00
function users_set_password(elem) {
var email = $(elem).parents('tr').attr('data-email');
2015-06-06 12:33:31 +00:00
var yourpw = "";
if (api_credentials != null & & email == api_credentials[0])
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 > ";
2014-09-21 17:24:01 +00:00
show_modal_confirm(
"Archive User",
2015-06-06 12:33:31 +00:00
$("< p > Set a new password for < b > " + email + "< / b > ?< / p > < p > < label for = 'users_set_password_pw' style = 'display: block; font-weight: normal' > New Password:< / label > < input type = 'password' id = 'users_set_password_pw' > < / p > < p > < small > Passwords must be at least four characters and may not contain spaces.< / small > " + yourpw + "< / p > "),
2014-09-21 17:24:01 +00:00
"Set Password",
function() {
api(
"/mail/users/password",
"POST",
{
email: email,
password: $('#users_set_password_pw').val()
},
function(r) {
// Responses are multiple lines of pre-formatted text.
show_modal_error("Set Password", $("< pre / > ").text(r));
},
function(r) {
show_modal_error("Set Password", r);
});
});
}
2014-08-17 22:43:57 +00:00
function users_remove(elem) {
var email = $(elem).parents('tr').attr('data-email');
2015-04-28 11:14:35 +00:00
// can't remove yourself
if (api_credentials != null & & email == api_credentials[0]) {
show_modal_error("Archive User", "You cannot archive your own account.");
return;
}
2014-08-17 22:43:57 +00:00
show_modal_confirm(
"Archive User",
2014-09-21 17:24:01 +00:00
$("< p > Are you sure you want to archive < b > " + email + "< / b > ?< / p > < p > The user's mailboxes will not be deleted (you can do that later), but the user will no longer be able to log into any services on this machine.< / p > "),
2014-08-17 22:43:57 +00:00
"Archive",
function() {
api(
"/mail/users/remove",
"POST",
{
email: email
},
function(r) {
// Responses are multiple lines of pre-formatted text.
show_modal_error("Remove User", $("< pre / > ").text(r));
show_users();
},
function(r) {
show_modal_error("Remove User", r);
});
});
}
function mod_priv(elem, add_remove) {
var email = $(elem).parents('tr').attr('data-email');
var priv = $(elem).parents('td').find('.name').text();
// can't remove your own admin access
if (priv == "admin" & & add_remove == "remove" & & api_credentials != null & & email == api_credentials[0]) {
show_modal_error("Modify Privileges", "You cannot remove the admin privilege from yourself.");
return;
}
var add_remove1 = add_remove.charAt(0).toUpperCase() + add_remove.substring(1);
show_modal_confirm(
"Modify Privileges",
2015-04-19 13:08:53 +00:00
$("< p > Are you sure you want to " + add_remove + " the " + priv + " privilege for < b > " + email + "< / b > ?< / p > "),
2014-08-17 22:43:57 +00:00
add_remove1,
function() {
api(
"/mail/users/privileges/" + add_remove,
"POST",
{
email: email,
privilege: priv
},
function(r) {
show_users();
});
});
}
2015-09-04 22:12:07 +00:00
function generate_random_password() {
var pw = "";
var charset = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789"; // confusable characters skipped
for (var i = 0; i < 10 ; i + + )
pw += charset.charAt(Math.floor(Math.random() * charset.length));
show_modal_error("Random Password", "< p > Here, try this:< / p > < p > < code style = 'font-size: 110%' > " + pw + "< / code > < /pr");
return false; // cancel click
}
2014-09-03 10:17:46 +00:00
< / script >