diff --git a/install.sh b/install.sh index a19c44e..1f9028b 100755 --- a/install.sh +++ b/install.sh @@ -14,3 +14,4 @@ rm -r /srv/www/html/panel/f3/.git find /srv/www/html/panel -type d -exec chmod 755 {} + find /srv/www/html/panel -type f -exec chmod 644 {} + chown -R vpanel:vpanel /srv/www/html/panel + diff --git a/panel/classes/Panel.php b/panel/classes/Panel.php index 11afc45..8bfa8e2 100644 --- a/panel/classes/Panel.php +++ b/panel/classes/Panel.php @@ -95,7 +95,7 @@ class Panel { } - public static function validateEmailPassword($password, $password_confirm) { + public static function validatePassword($password, $password_confirm) { global $f3; @@ -303,6 +303,136 @@ class Panel { } + public static function validateUsername($username) { + + global $f3; + + $messages = array(); + + if(strlen($username) < 3) { + + $messages[] = "Usernames must be at least 3 characters long."; + + } + + if(strlen($username) > 16) { + + $messages[] = "Usernames can not be longer than 16 characters."; + + } + + if (!preg_match('/^[[:lower:][:digit:]\.\_\-]{3,16}$/', $username)) { + + $messages[] = "Usernames can only contain letters, numbers, and the special characters . _ -"; + + } + + if (preg_match('/^[[:digit:]\.\_\-]/', $username)) { + + $messages[] = "Usernames must begin with an alphabetic character."; + + } + + if (preg_match('/[\.\_\-]$/', $username)) { + + $messages[] = "Usernames may not end with a Special Character."; + + } + + if (preg_match('/[\.\_\-]{2,}/', $username)) { + + $messages[] = "Usernames may not have consecutive Special Characters."; + + } + + if (count($messages) > 0) { + if ($f3->exists('SESSION.messages')) { + $f3->set('SESSION.messages', array_merge($f3->get('SESSION.messages'), $messages)); + } else { + $f3->set('SESSION.messages', $messages); + } + return false; + } else { + return true; + } + + } + + public static function verifyVhostDomainExists($domain) { + + global $f3; + + exec("/usr/local/bin/vhost-get.sh -d $domain -c", $output, $result_code); + if ($result_code == 0) { + return TRUE; + } else { + if (count($output) > 0) { + if ($output[0] != "ERROR: $domain not found") { + $f3->set('SESSION.messages', $output[0]); + } + } + return FALSE; + } + + } + + public static function verifyCertificateExists($domain) { + + global $f3; + + exec("/usr/local/bin/letsencrypt-get.sh -d $domain -c", $output, $result_code); + if ($result_code == 0) { + return TRUE; + } else { + if (count($output) > 0) { + if ($output[0] != "ERROR: Certificate for $domain not found") { + $f3->set('SESSION.messages', $output[0]); + } + } + return FALSE; + } + + } + + public static function verifyVmailDomainExists($domain) { + + global $f3; + + exec("/usr/local/bin/vmail-domains-get.sh -d $domain -c", $output, $result_code); + if ($result_code == 0) { + if (count($output) == 0) { + return FALSE; + } else { + // add check for domain row??? + return TRUE; + } + } else { + $f3->set('SESSION.messages', "System error checking if email domain exists."); + return FALSE; + } + + } + + public static function verifyDkimExists($domain) { + + global $f3; + + exec("/usr/local/bin/vmail-dkim-get.sh -d $domain -c", $output, $result_code); + if ($result_code == 0) { + return TRUE; + } else { + if (count($output) > 0) { + if ($output[0] != "ERROR: DKIM for $domain does not exist.") { + if (count($output) > 0) { + $f3->set('SESSION.messages', $output[0]); + } + } + } + return FALSE; + } + + } + public static function vGet($cmd, $return404 = TRUE) { global $f3; diff --git a/panel/classes/Panel/Cert.php b/panel/classes/Panel/Cert.php new file mode 100644 index 0000000..f1371c9 --- /dev/null +++ b/panel/classes/Panel/Cert.php @@ -0,0 +1,31 @@ + + * GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + */ + +namespace Panel; + +class Cert extends \Panel { + + function beforeRoute($f3) { + + parent::beforeRoute($f3); + + if ($f3->exists('SESSION.domain')) { + + /* set base path for vhost links */ + if ($f3->get('NAV.mapping') == 'cert') { + $f3->set('NAV.certbase', preg_replace('/\/$/', '', $f3->get('BASE'))); + } elseif ($f3->get('NAV.mapping') == 'vpanel') { + $f3->set('NAV.certbase', preg_replace('/\/$/', '', $f3->get('BASE') . '/Certs/' . $f3->get('SESSION.cert'))); + } + + } + + } + +} diff --git a/panel/classes/Panel/Cert/Certs.php b/panel/classes/Panel/Cert/Certs.php new file mode 100644 index 0000000..3db73a8 --- /dev/null +++ b/panel/classes/Panel/Cert/Certs.php @@ -0,0 +1,92 @@ + + * GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + */ + +namespace Panel\Cert; + +class Certs extends \Panel\Cert { + + /* use this to make query */ + function beforeRoute($f3) { + + parent::beforeRoute($f3); + + if ($f3->exists('PARAMS.cert')) { + $cert = $f3->get('PARAMS.cert'); + if ($cert_array = $f3->call('\Panel::vGet', array("letsencrypt-get.sh -d $cert -c", FALSE))) { + $f3->set('cert_array', $cert_array[0]); + } + } else { + if ($certs_array = $f3->call('\Panel::vGet', array("letsencrypt-get.sh -c", FALSE))) { + $f3->set('certs_array', $certs_array); + } + } + + } + + static function get($f3) { + + if ($f3->exists('PARAMS.cert')) { + + $cert_array = $f3->get('cert_array'); + /* remove time from creation date */ + $start = $cert_array['start']; + $start_array = explode(' ', $start); + unset($start_array[2]); + $start = implode(' ', $start_array); + $cert_array['start'] = $start; + /* remove time from expiration date */ + $end = $cert_array['end']; + $end_array = explode(' ', $end); + unset($end_array[2]); + $end = implode(' ', $end_array); + $cert_array['end'] = $end; + /* remove main cert name from alternatives */ + // $common = $cert_array['common']; + $alternative = $cert_array['alternative']; + // $alternative = preg_replace("/^$common/", '', $alternative); + // $alternative = trim($alternative); + $alternative = preg_replace('/ /', '
', $alternative); + $cert_array['alternative'] = $alternative; + $f3->set('cert_array', $cert_array); + + $cert = $f3->get('PARAMS.cert'); + $f3->set('page_header', "Certificate Details for $cert"); + echo \Template::instance()->render('cert/certs-cert.html'); + + } else { + + $certs_array = $f3->get('certs_array'); + if (is_array($certs_array) && count($certs_array) > 0) { + foreach ($certs_array as $k=>$cert_array) { + /* remove time from expiration date */ + $end = $cert_array['end']; + $end_array = explode(' ', $end); + unset($end_array[2]); + $end = implode(' ', $end_array); + $cert_array['end'] = $end; + /* remove main cert name from alternatives */ + // $common = $cert_array['common']; + $alternative = $cert_array['alternative']; + // $alternative = preg_replace("/^$common/", '', $alternative); + // $alternative = trim($alternative); + $alternative = preg_replace('/ /', '
', $alternative); + $cert_array['alternative'] = $alternative; + $certs_array[$k] = $cert_array; + } + $f3->set('certs_array', $certs_array); + } + + $f3->set('page_header', "Certificates"); + echo \Template::instance()->render('cert/certs.html'); + + } + + } + +} diff --git a/panel/classes/Panel/Cert/CertsAdd.php b/panel/classes/Panel/Cert/CertsAdd.php new file mode 100644 index 0000000..e415536 --- /dev/null +++ b/panel/classes/Panel/Cert/CertsAdd.php @@ -0,0 +1,69 @@ + + * GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + */ + +namespace Panel\Cert; + +class CertsAdd extends \Panel\Cert { + + function beforeRoute($f3) { + + parent::beforeRoute($f3); + + } + + static function get($f3) { + + if ($f3->exists('PARAMS.cert')) { + $domain = $f3->get('PARAMS.cert'); + if ($f3->call('\Panel::validateDomain', $domain)) { + if ($certdomain_dns = dns_get_record("$domain", DNS_A)) { + if ($certdomain_dns[0]['ip'] == $_SERVER['SERVER_ADDR']) { + if (is_dir('/var/tmp/letsencrypt/')) { + if (is_writable('/var/tmp/letsencrypt/')) { + touch("/var/tmp/letsencrypt/$domain"); + $messages = $f3->get('SESSION.messages'); + $messages[] = "A background job to create a Security Certificate for $domain has been started."; + $messages[] = "It can take a few seconds, up to one minute, for this job to complete."; + $messages[] = "Wait few seconds and then reload this page to check for the new Security Certificate."; + $f3->set('SESSION.messages', $messages); + } else { + $messages = $f3->get('SESSION.messages'); + $messages[] = "System error with Security Certificate system."; + $messages[] = "Please try again later."; + $f3->set('SESSION.messages', $messages); + } + } else { + $messages = $f3->get('SESSION.messages'); + $messages[] = "System error with Security Certificate system."; + $messages[] = "Please try again later."; + $f3->set('SESSION.messages', $messages); + } + } else { + $messages = $f3->get('SESSION.messages'); + $messages[] = "DNS for $domain does not point to this server IP."; + $messages[] = "Please update DNS and try again."; + $f3->set('SESSION.messages', $messages); + } + } else { + $messages = $f3->get('SESSION.messages'); + $messages[] = "Error verifying DNS, try again later."; + $f3->set('SESSION.messages', $messages); + } + } + parse_str($f3->get('QUERY'), $output); + if (isset($output['r'])) { + $f3->reroute($output['r']); + } + + } + /* default reroute as fallback */ + $f3->reroute('/'); + } + +} diff --git a/panel/classes/Panel/Cert/CertsDelete.php b/panel/classes/Panel/Cert/CertsDelete.php new file mode 100644 index 0000000..6653c27 --- /dev/null +++ b/panel/classes/Panel/Cert/CertsDelete.php @@ -0,0 +1,70 @@ + + * GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + */ + +namespace Panel\Cert; + +class CertsDelete extends \Panel\Cert { + + function beforeRoute($f3) { + + parent::beforeRoute($f3); + + } + + static function get($f3) { + + $messages = $f3->get('SESSION.messages'); + + if ($f3->exists('PARAMS.cert')) { + $domain = $f3->get('PARAMS.cert'); + if ($f3->call('\Panel::validateDomain', $domain)) { + if ($f3->call('\Panel::verifyCertificateExists', $domain)) { + + /* delete the cert */ + $f3->call('\Panel::vGet', array("letsencrypt-delete.sh -d $domain -r", FALSE)); + + /* check for and delete dovecot config */ + if (preg_match('/^mail\./i', $domain)) { + $mxdomain = preg_replace('/^mail\./i', '', $f3->get('HOST')); + $f3->call('\Panel::vGet', array("vmail-dovecot-disable.sh -d $mxdomain", FALSE)); + } + + /* delete apache config (vhost or webmail) */ + if (is_link("/etc/apache2/sites-enabled/$domain.conf")) { + $f3->call('\Panel::vGet', array("vhost-disable.sh -d $domain", FALSE)); + } + + $messages[] = "The Security Certificate and related configs for $domain have been deleted."; + + } else { + + $messages[] = "Security Certificate for $domain not found."; + + } + + } else { + + $messages[] = "Invalid domain name ($domain)."; + + } + + } + + /* reroute user to page the originated from */ + parse_str($f3->get('QUERY'), $output); + if (isset($output['r'])) { + $f3->reroute($output['r']); + } else { + /* default reroute as fallback */ + $f3->reroute('/'); + } + + } + +} diff --git a/panel/classes/Panel/MySQL.php b/panel/classes/Panel/MySQL.php new file mode 100644 index 0000000..251baa1 --- /dev/null +++ b/panel/classes/Panel/MySQL.php @@ -0,0 +1,20 @@ + + * GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + */ + +namespace Panel; + +class MySQL extends \Panel { + + function beforeRoute($f3) { + + parent::beforeRoute($f3); + + } + +} diff --git a/panel/classes/Panel/MySQL/Databases.php b/panel/classes/Panel/MySQL/Databases.php new file mode 100644 index 0000000..c4011e4 --- /dev/null +++ b/panel/classes/Panel/MySQL/Databases.php @@ -0,0 +1,27 @@ + + * GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + */ + +namespace Panel\MySQL; + +class Databases extends \Panel\MySQL { + + /* use this to make query */ + function beforeRoute($f3) { + + parent::beforeRoute($f3); + + } + + static function get($f3) { + + echo \Template::instance()->render('mysql/databases.html'); + + } + +} diff --git a/panel/classes/Panel/Vhost/Users.php b/panel/classes/Panel/Vhost/Users.php new file mode 100644 index 0000000..61bf938 --- /dev/null +++ b/panel/classes/Panel/Vhost/Users.php @@ -0,0 +1,62 @@ + + * GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + */ + +namespace Panel\Vhost; + +class Users extends \Panel\Vhost { + + /* use this to make query */ + function beforeRoute($f3) { + + parent::beforeRoute($f3); + + if ($f3->exists('PARAMS.username')) { + $username = $f3->get('PARAMS.username'); + if ($users_array = $f3->call('\Panel::vGet', array("vhost-user-get.sh -u $username -c", FALSE))) { + if ($users_array[0]['passwd'] == "") { + $users_array[0]['passwd'] = '(unavailable)'; + } + $f3->set('users_array', $users_array[0]); + if ($vhosts_array = $f3->call('\Panel::vGet', array("vhost-get.sh -u $username -c", FALSE))) { + $f3->set('vhosts_array', $vhosts_array); + } + } + } else { + if ($users_array = $f3->call('\Panel::vGet', array("vhost-user-get.sh -c", FALSE))) { + if (is_array($users_array) && count($users_array) > 0) { + foreach ($users_array as $k=>$user_array) { + if ($user_array['passwd'] == "") { + $users_array[$k]['passwd'] = '(unavailable)'; + } + } + $f3->set('users_array', $users_array); + } + } + } + + } + + static function get($f3) { + + if ($f3->exists('PARAMS.username')) { + + $username = $f3->get('PARAMS.username'); + $f3->set('page_header', "User Details"); + echo \Template::instance()->render('vhost/users-user.html'); + + } else { + + $f3->set('page_header', "Users"); + echo \Template::instance()->render('vhost/users.html'); + + } + + } + +} diff --git a/panel/classes/Panel/Vhost/UsersAdd.php b/panel/classes/Panel/Vhost/UsersAdd.php new file mode 100644 index 0000000..b2c034a --- /dev/null +++ b/panel/classes/Panel/Vhost/UsersAdd.php @@ -0,0 +1,90 @@ + + * GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + */ + +namespace Panel\Vhost; + +class UsersAdd extends \Panel\Vhost { + + function beforeRoute($f3) { + + parent::beforeRoute($f3); + + /* get system defaults for new users */ + $user = array(); + $user['username'] = ''; + $user['password'] = ''; + $user['password_confirm'] = ''; + if ($f3->get('JAILUSER') == '1') { + $user['jailuser'] = 1; + } else { + $user['jailuser'] = 0; + } + $user['fpmmax'] = $f3->get('FPMMAX'); + if ($f3->get('WRITEUSERINFO') == '1') { + $user['writeuserinfo'] = 1; + } else { + $user['writeuserinfo'] = 0; + } + if ($f3->get('SHOWWRITEINFO') == '1') { + $user['showwriteinfo'] = 1; + } else { + $user['showwriteinfo'] = 0; + } + $f3->set('user', $user); + + } + + static function get($f3) { + + echo \Template::instance()->render('vhost/users-add.html'); + + } + + function post($f3) { + + extract($_POST); + + /* force username to be all lower case */ + $username = strtolower($username); + $f3->call('\Panel::validateUsername', $username); + /* only validate password if one was submitted, otherwise script will generate random password */ + if ($password != '' || $password_confirm != '') { + $f3->call('\Panel::validatePassword', array($password, $password_confirm)); + } + + /* check for validation errors */ + if ($f3->exists('SESSION.messages')) { + $messages = $f3->get('SESSION.messages'); + $messages[] = "Please make changes and re-submit the form to try again."; + $f3->set('SESSION.messages', $messages); + $f3->set('user', $_POST); + $f3->call('\Panel\Vhost\UsersAdd::get', $f3); + } else { + $domain = $f3->get('PARAMS.domain'); + if ($password != '') { + $password = "-p " . escapeshellarg($password); + } + exec("/usr/local/bin/vhost-user-add.sh -u $username -x $fpmmax $password -w $writeuserinfo", $output, $result_code); + if ($result_code == 0) { + $messages[] = "Success: User $username added."; + if ($jailuser == 1) { + exec("/usr/local/bin/vhost-user-jail.sh -u $username >/dev/null 2>/dev/null &", $output, $result_code); + $messages[] = "Note: User is being jailed. Setting up the jail environment takes about a minute to complete and is run in the background now."; + } + $f3->set('SESSION.messages', $messages); + $f3->reroute("/Users"); + } else { + $messages[] = "Error adding user."; + $f3->set('SESSION.messages', $messages); + $f3->call('\Panel\Vhost\UsersAdd::get', $f3); + } + } + } + +} diff --git a/panel/classes/Panel/Vhost/UsersDelete.php b/panel/classes/Panel/Vhost/UsersDelete.php new file mode 100644 index 0000000..8a011ad --- /dev/null +++ b/panel/classes/Panel/Vhost/UsersDelete.php @@ -0,0 +1,52 @@ + + * GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + */ + +namespace Panel\Vhost; + +class UsersDelete extends \Panel\Vhost { + + function beforeRoute($f3) { + + parent::beforeRoute($f3); + + /* verify user exists */ + + } + + static function get($f3) { + + $f3->set('confirm', 'true'); + echo \Template::instance()->render('vhost/users-delete.html'); + + } + + function post($f3) { + + /* run delete command here */ + $username = $f3->get('PARAMS.username'); + $messages = array(); + $output = system("/usr/local/bin/vhost-user-del.sh -u $username", $result_code); + if ($result_code == 0) { + $messages[] = "User '$username' has been deleted."; + } else { + $messages[] = "Error deleting user '$username'."; + $messages[] = $output; + } + $f3->set('SESSION.messages', $messages); + $f3->reroute("/Users"); +// $mapping = $f3->get('NAV.mapping'); +// if ($mapping == 'vmail') { +// $f3->reroute("/Users"); +// } else { +// $f3->reroute("/Email/$domain/Accounts"); +// } + + } + +} diff --git a/panel/classes/Panel/Vhost/UsersEdit.php b/panel/classes/Panel/Vhost/UsersEdit.php new file mode 100644 index 0000000..68194c7 --- /dev/null +++ b/panel/classes/Panel/Vhost/UsersEdit.php @@ -0,0 +1,150 @@ + + * GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + */ + +namespace Panel\Vhost; + +class UsersEdit extends \Panel\Vhost { + + function beforeRoute($f3) { + + parent::beforeRoute($f3); + $username = $f3->get('PARAMS.username'); + if ($user_array = $f3->call('\Panel::vGet', array("vhost-user-get.sh -u $username -c", FALSE))) { + if ($user_array[0]['passwd'] == "") { + $user_array[0]['passwd'] = '(unavailable)'; + } + $f3->set('user_array', $user_array[0]); + } + + } + + static public function get($f3) { + + if ($f3->exists('PARAMS.username')) { + + $username = $f3->get('PARAMS.username'); + $f3->set('page_header', "Edit User: $username"); + echo \Template::instance()->render('vhost/users-edit.html'); + + } else { + + $f3->set('page_header', "Users"); + echo \Template::instance()->render('vhost/users.html'); + + } + + } + + function post($f3) { + + $username = $f3->get('PARAMS.username'); + $action = $_POST['action']; + + if ($action == 'password') { + $password = $_POST['password']; + $password_confirm = $_POST['password_confirm']; + $f3->call('\Panel::validatePassword', array($password, $password_confirm)); + /* check for validation errors */ + if ($f3->exists('SESSION.messages')) { + $messages = $f3->get('SESSION.messages'); + } else { + $password = escapeshellarg($password); + if ($f3->get('WRITEUSERINFO') == '1') { + exec("/usr/local/bin/vhost-user-mod.sh -u $username -p $password -w", $output, $result_code); + } else { + exec("/usr/local/bin/vhost-user-mod.sh -u $username -p $password", $output, $result_code); + } + if ($result_code == 0) { + $messages[] = "Success: Password for $username updated."; + } else { + $messages[] = "Error updating password."; + } + } + } elseif ($action == 'jail') { + exec("/usr/local/bin/vhost-user-jail.sh -u $username >/dev/null 2>/dev/null &", $output, $result_code); + $messages[] = "User is being jailed. Note: Setting up the jail environment takes about a minute to complete and is run in the background now."; + $f3->reroute("/Users/$username"); + } elseif ($action == 'fpmmax') { + $fpmmax = $_POST['fpmmax']; + exec("/usr/local/bin/vhost-user-mod.sh -u $username -x $fpmmax", $output, $result_code); + if ($result_code == 0) { + $messages[] = "Success: PHP Workers updated."; + } else { + $messages[] = "Error updating PHP Workers."; + } + } else { + $messages[] = "Unkown edit action."; + } + + $f3->set('SESSION.messages', $messages); + $f3->reroute("/Users/$username"); + + + // /* run mod command here */ + // $mbox = $f3->get('PARAMS.mbox'); + // $domain = $f3->get('PARAMS.domain'); + // $mbox_array = $_POST; + // $f3->set('mbox_array', $mbox_array); + // foreach ($mbox_array as $k=>$v) { + // if (strtolower($v) == 'unlimited') { + // $mbox_array[$k] = 'NULL'; + // } + // } + // extract($mbox_array); + // + // if ($password != '') { + // $f3->call('\Panel::validatePassword', array($password, $password_confirm)); + // } + // settype($status, "integer"); + // $f3->call('\Panel::validateEmailStatus', $status); + // if (strtolower($quota == 'unlimited') || strtolower($quota == 'null')) { + // $quota = "NULL"; + // } else { + // settype($quota, "integer"); + // } + // $f3->call('\Panel::validateEmailQuota', $quota); + // if (strtolower($ratelimit == 'unlimited') || strtolower($ratelimit == 'null')) { + // $ratelimit = "NULL"; + // } + // $f3->call('\Panel::validateEmailRatelimit', $ratelimit); + // $f3->call('\Panel::validateEmailFiltering', $filter); + // + // /* check for validation errors */ + // if ($f3->exists('SESSION.messages')) { + // $messages = $f3->get('SESSION.messages'); + // $messages[] = "Please make changes and re-submit the form to try again."; + // $f3->set('SESSION.messages', $messages); + // $f3->call('\Panel\Vmail\MboxesEdit::get', $f3); + // } else { + // if ($password != '') { + // $password = escapeshellarg($password); + // $pword_cmd = "-p $password"; + // } else { + // $pword_cmd = ''; + // } + // exec("/usr/local/bin/vmail-mboxes-mod.sh -e $mbox@$domain $pword_cmd -q $quota -r $ratelimit -s $status -j $filter", $output, $result_code); + // if ($result_code == 0) { + // $messages[] = "Success: Email account $mbox@$domain updated."; + // $f3->set('SESSION.messages', $messages); + // $mapping = $f3->get('NAV.mapping'); + // if ($mapping == 'vmail') { + // $f3->reroute("/Accounts/$mbox"); + // } else { + // $f3->reroute("/Email/$domain/Accounts/$mbox"); + // } + // } else { + // $messages[] = "Error."; + // $f3->set('SESSION.messages', $messages); + // $f3->call('\Panel\Vmail\MboxesEdit::get', $f3); + // } + // } + + } + +} diff --git a/panel/classes/Panel/Vhost/Vhosts.php b/panel/classes/Panel/Vhost/Vhosts.php index 1dc7b23..212e264 100644 --- a/panel/classes/Panel/Vhost/Vhosts.php +++ b/panel/classes/Panel/Vhost/Vhosts.php @@ -20,6 +20,39 @@ class Vhosts extends \Panel\Vhost { $vhost = $f3->get('PARAMS.vhost'); if ($vhost_array = $f3->call('\Panel::vGet', array("vhost-get.sh -d $vhost -c", FALSE))) { $f3->set('vhost_array', $vhost_array[0]); + /* get cert info */ + if ($f3->call('\Panel::verifyCertificateExists', $vhost)) { + if ($cert_array = $f3->call('\Panel::vGet', array("letsencrypt-get.sh -d $vhost -c", FALSE))) { + $cert_array = $cert_array[0]; + /* remove time from expiration date */ + $end = $cert_array['end']; + $end_array = explode(' ', $end); + unset($end_array[2]); + $end = implode(' ', $end_array); + $cert_array['end'] = $end; + /* add line breaks */ + $common = $cert_array['common']; + $alternative = $cert_array['alternative']; + $alternative = preg_replace('/ /', '
', $alternative); + $cert_array['alternative'] = $alternative; + $f3->set('cert_array', $cert_array); + } + } + /* get user info */ + $username = $vhost_array[0]['username']; + if ($users_array = $f3->call('\Panel::vGet', array("vhost-user-get.sh -u $username -c", FALSE))) { + if ($users_array[0]['passwd'] == "") { + $users_array[0]['passwd'] = '(unavailable)'; + } + $f3->set('users_array', $users_array[0]); + } + /* get mysql db info */ + if ($mysqlinfo_array = $f3->call('\Panel::vGet', array("vhost-mysql-db-get.sh -d $vhost -c", FALSE))) { + $f3->set('mysqlinfo_array', $mysqlinfo_array[0]); + } else { + $mysqlinfo_array = array('(unknown)', '(unknown)', '(unknown)', '(unknown)'); + $f3->set('mysqlinfo_array', $mysqlinfo_array); + } } } else { if ($vhosts_array = $f3->call('\Panel::vGet', array("vhost-get.sh -c", FALSE))) { @@ -41,7 +74,7 @@ class Vhosts extends \Panel\Vhost { $f3->set('vhost_array', $vhost_array); $vhost = $f3->get('PARAMS.vhost'); - $f3->set('page_header', "Website Hosting for $vhost"); + $f3->set('page_header', "Details for $vhost"); echo \Template::instance()->render('vhost/vhosts-vhost.html'); } else { diff --git a/panel/classes/Panel/Vhost/VhostsAdd.php b/panel/classes/Panel/Vhost/VhostsAdd.php index ef90961..c84ed0b 100644 --- a/panel/classes/Panel/Vhost/VhostsAdd.php +++ b/panel/classes/Panel/Vhost/VhostsAdd.php @@ -15,9 +15,26 @@ class VhostsAdd extends \Panel\Vhost { parent::beforeRoute($f3); -// /* get vm_domains defaults for "add new" form */ -// $vm_domains_defaults = $f3->call('\Panel::vGet', array("vmail-defaults-get.sh -c", FALSE)); -// $f3->set('vm_domains_defaults', $vm_domains_defaults[0]); + /* get system defaults for new websites */ + $deploy = array(); + $deploy['username'] = ''; + if ($users_array = $f3->call('\Panel::vGet', array("vhost-user-get.sh -c", FALSE))) { + $deploy['users_array'] = $users_array; + } else { + $deploy['users_array'] = array(); + } + + if ($f3->get('WRITEUSERINFO') == '1') { + $deploy['writeuserinfo'] = 1; + } else { + $deploy['writeuserinfo'] = 0; + } + if ($f3->get('SHOWWRITEINFO') == '1') { + $deploy['showwriteinfo'] = 1; + } else { + $deploy['showwriteinfo'] = 0; + } + $f3->set('deploy', $deploy); } @@ -34,93 +51,61 @@ class VhostsAdd extends \Panel\Vhost { $messages = array(); /* validate domain */ - if (preg_match('/^[0-9a-z]([-.]?[0-9a-z])*\.[a-z]{2,24}$/i', strtolower($_POST['domain']))) { - // strip www - $domain = strtolower($_POST['domain']); - } else { - $messages[] = "Invalid domain name."; - } - - /* validate status */ - if ($_POST['status'] != 0 && $_POST['status'] != 1) { - $messages[] = "Invalid 'Status'."; - } else { - $status = $_POST['status']; - } - - /* validate mbox_limit */ - if (strtolower($_POST['mbox_limit']) == 'unlimited' || strtolower($_POST['mbox_limit'] == 'null')) { - $mbox_limit = "NULL"; - } elseif (is_numeric($_POST['mbox_limit'])) { - /* make sure mbox_limit is a possitive integer */ - $mbox_limit = abs(intval($_POST['mbox_limit'])); - if ($mbox_limit < 1) { - echo "Mailbox Limit must be a positive number or \"Unlimited\".\n"; - $messages[] = "Mailbox Limit must be a positive number or \"Unlimited\"."; - } - } else { - $messages[] = "Mailbox Limit must be a positive number or \"Unlimited\"."; - } - - /* validate mbox_quota_default */ - if (strtolower($_POST['mbox_quota_default']) == 'unlimited' || strtolower($_POST['mbox_quota_default'] == 'null')) { - $mbox_quota_default = "NULL"; - } elseif (is_numeric($_POST['mbox_quota_default'])) { - /* make sure mbox_quota_default is a possitive integer */ - $mbox_quota_default = abs(intval($_POST['mbox_quota_default'])); - if ($mbox_quota_default < 1) { - echo "Default Quota must be a positive number or \"Unlimited\".\n"; - $messages[] = "Default Quota must be a positive number or \"Unlimited\"."; - } - } else { - $messages[] = "Default Quota must be a positive number or \"Unlimited\"."; - } - - /* validate mbox_ratelimit_default */ - if (strtolower($_POST['mbox_ratelimit_default']) == 'unlimited' || strtolower($_POST['mbox_ratelimit_default'] == 'null')) { - $mbox_ratelimit_default = "NULL"; - } elseif (is_numeric($_POST['mbox_ratelimit_default'])) { - /* make sure mbox_ratelimit_default is a possitive integer */ - $mbox_ratelimit_default = abs(intval($_POST['mbox_ratelimit_default'])); - if ($mbox_ratelimit_default < 1) { - $messages[] = "Default Rate Limit must be a positive number or \"Unlimited\"."; - } - } else { - $messages[] = "Default Rate Limit must be a positive number or \"Unlimited\"."; - } - - /* check for validation errors */ - if (count($messages) > 0) { - $messages[] = "Please re-submit the form to try again."; - $f3->set('SESSION.messages', $messages); - $f3->call('\Panel\Vmail\DomainsAdd::get', $f3); - } else { - /* check if vmail domain already exists */ - $domain_array = $f3->call('\Panel::vGet', array("vmail-domains-get.sh -d $domain -c", FALSE)); - if (count($domain_array) == 0) { - /* add email domain */ - exec("/usr/local/bin/vmail-domains-add.sh -d $domain -l $mbox_limit -q $mbox_quota_default -r $mbox_ratelimit_default -s $status", $output, $result_code); - if ($result_code == 0) { - $messages[] = "Email Domain $domain has been added."; - $f3->set('SESSION.messages', $messages); - $f3->reroute("/Email/$domain"); - } else { - if (count($output) > 0) { - foreach ($output as $k=>$output_message) { - $messages[] = "$output_message"; - } - } else { - $messages[] = "Unknown error adding Email Domain $domain."; - } - $f3->set('SESSION.messages', $messages); - $f3->call('\Panel\Vmail\DomainsAdd::get', $f3); - } - } else { - $messages[] = "Email Domain '$domain' already exists."; + $domain = strtolower($_POST['domain']); + $domain = preg_replace('/^www\./', '', $domain); + if ($f3->call('\Panel::validateDomain', $domain)) { + if ($f3->call('\Panel::verifyVhostDomainExists', $domain)) { + $messages = $f3->get('SESSION.messages'); + $messages[] = "$domain already exists on this server."; $f3->set('SESSION.messages', $messages); - $f3->reroute("/Email/$domain"); + $f3->reroute("/Websites/Add"); + } else { + $cmd = "/usr/local/bin/vhost-deploy.sh -d $domain"; + } + } else { + $f3->reroute("/Websites/Add"); + } + + /* validate username & set related options */ + $username = strtolower($_POST['username']); + if ($f3->get('JAILUSER') == '1') { + $jailuser = 1; + } else { + $jailuser = 0; + } + if ($username == '') { + $cmd = "$cmd -j $jailuser"; + } else { + if ($f3->call('\Panel::vGet', array("vhost-user-get.sh -u $username -c", FALSE))) { + $cmd = "$cmd -u $username"; + } else { + $messages = $f3->get('SESSION.messages'); + $messages[] = "Error validating username $username."; + $f3->set('SESSION.messages', $messages); + $f3->reroute("/Websites/Add"); } } + + if ($f3->get('WRITEUSERINFO') == '1') { + $writeuserinfo = 1; + } else { + $writeuserinfo = 0; + } + $cmd = "$cmd -w $writeuserinfo"; + exec("$cmd", $output, $result_code); + if ($result_code == 0) { + $messages[] = "Success: Website $domain added."; + if ($username == '' && $jailuser == 1) { + $messages[] = "Note: New user is being jailed. Setting up the jail environment takes about a minute to complete and is being run in the background now."; + } + $f3->set('SESSION.messages', $messages); + $f3->reroute("/Websites"); + } else { + $messages[] = "Error adding website."; + $f3->set('SESSION.messages', $messages); + $f3->reroute("/Websites/Add"); + } + } } diff --git a/panel/classes/Panel/Vhost/VhostsDelete.php b/panel/classes/Panel/Vhost/VhostsDelete.php new file mode 100644 index 0000000..21f2bef --- /dev/null +++ b/panel/classes/Panel/Vhost/VhostsDelete.php @@ -0,0 +1,52 @@ + + * GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + */ + +namespace Panel\Vhost; + +class VhostsDelete extends \Panel\Vhost { + + function beforeRoute($f3) { + + parent::beforeRoute($f3); + + /* verify user exists */ + + } + + static function get($f3) { + + $f3->set('confirm', 'true'); + echo \Template::instance()->render('vhost/vhosts-delete.html'); + + } + + function post($f3) { + + /* run delete command here */ + $domain = $f3->get('PARAMS.vhost'); + $messages = array(); + $output = system("/usr/local/bin/vhost-destroy.sh -d $domain", $result_code); + if ($result_code == 0) { + $messages[] = "Website '$domain' has been deleted."; + } else { + $messages[] = "Error deleting website '$domain'."; + $messages[] = $output; + } + $f3->set('SESSION.messages', $messages); + $f3->reroute("/Websites"); +// $mapping = $f3->get('NAV.mapping'); +// if ($mapping == 'vmail') { +// $f3->reroute("/Users"); +// } else { +// $f3->reroute("/Email/$domain/Accounts"); +// } + + } + +} diff --git a/panel/classes/Panel/Vhost/VhostsDisable.php b/panel/classes/Panel/Vhost/VhostsDisable.php new file mode 100644 index 0000000..2d9a21d --- /dev/null +++ b/panel/classes/Panel/Vhost/VhostsDisable.php @@ -0,0 +1,47 @@ + + * GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + */ + +namespace Panel\Vhost; + +class VhostsDisable extends \Panel\Vhost { + + function beforeRoute($f3) { + + parent::beforeRoute($f3); + + /* verify user exists */ + + } + + static function get($f3) { + + /* run delete command here */ + $domain = $f3->get('PARAMS.vhost'); + $messages = array(); + $output = system("/usr/local/bin/vhost-disable.sh -d $domain", $result_code); + if ($result_code == 0) { + $messages[] = "Website '$domain' has been disabled."; + $messages[] = "NOTICE: Nothing has been deleted and the site can be re-enabled at any time."; + } else { + $messages[] = "Error disabling website '$domain'."; + $messages[] = $output; + } + $f3->set('SESSION.messages', $messages); + $f3->reroute("/Websites/$domain"); +// $mapping = $f3->get('NAV.mapping'); +// if ($mapping == 'vmail') { +// $f3->reroute("/Users"); +// } else { +// $f3->reroute("/Email/$domain/Accounts"); +// } + + } + + +} diff --git a/panel/classes/Panel/Vhost/VhostsEnable.php b/panel/classes/Panel/Vhost/VhostsEnable.php new file mode 100644 index 0000000..8bdd376 --- /dev/null +++ b/panel/classes/Panel/Vhost/VhostsEnable.php @@ -0,0 +1,37 @@ + + * GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + */ + +namespace Panel\Vhost; + +class VhostsEnable extends \Panel\Vhost { + + function beforeRoute($f3) { + + parent::beforeRoute($f3); + + } + + static function get($f3) { + + /* run enable command here */ + $domain = $f3->get('PARAMS.vhost'); + $messages = array(); + $output = system("/usr/local/bin/vhost-enable.sh -d $domain", $result_code); + if ($result_code == 0) { + $messages[] = "Website '$domain' has been enabled."; + } else { + $messages[] = "Error enabling website '$domain'."; + $messages[] = $output; + } + $f3->set('SESSION.messages', $messages); + $f3->reroute("/Websites/$domain"); + + } + +} diff --git a/panel/classes/Panel/Vmail/Dkim.php b/panel/classes/Panel/Vmail/Dkim.php new file mode 100644 index 0000000..2c43caf --- /dev/null +++ b/panel/classes/Panel/Vmail/Dkim.php @@ -0,0 +1,66 @@ + + * GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + */ + +namespace Panel\Vmail; + +class Dkim extends \Panel\Vmail { + + /* use this to make query */ + function beforeRoute($f3) { + + parent::beforeRoute($f3); + + if ($f3->exists('PARAMS.domain')) { + $domain = $f3->get('PARAMS.domain'); + $dkim_array = array(); + if ($f3->call('\Panel::verifyDkimExists', $domain)) { + if ($dkim_array = $f3->call('\Panel::vGet', array("vmail-dkim-get.sh -d $domain -c", FALSE))) { + $dkim_array = $dkim_array[0]; + $dkim_array['dns']['host'] = $dkim_array['selector'] . "._domainkey.$domain"; + if ($dns_txt_records = dns_get_record($dkim_array['dns']['host'], DNS_TXT)) { + $dkim_array['dns']['status'] = "Verified"; + } else { + $dkim_array['dns']['status'] = "Update"; + } + } else { + $dkim_array['dns']['status'] = "Error"; + } + } else { + $dkim_array['dns']['status'] = "Create"; + } + $f3->set('dkim_array', $dkim_array); + } else { + $messages = $f3->get('SESSION.messages'); + $messages[] = "Domain not set, must specify domain for DKIM info."; + $f3->set('SESSION.messages', $messages); + $f3->reroute('/'); + } + + } + + static function get($f3) { + + if ($f3->exists('PARAMS.domain')) { + + $domain = $f3->get('PARAMS.domain'); + $f3->set('page_header', "DKIM Details for $domain"); + + } else { + + $messages = $f3->get('SESSION.messages'); + $messages[] = "Domain not set, must specify domain for DKIM info."; + $f3->set('SESSION.messages', $messages); + + } + + echo \Template::instance()->render('vmail/dkim.html'); + + } + +} diff --git a/panel/classes/Panel/Vmail/DkimAdd.php b/panel/classes/Panel/Vmail/DkimAdd.php new file mode 100644 index 0000000..eeea02b --- /dev/null +++ b/panel/classes/Panel/Vmail/DkimAdd.php @@ -0,0 +1,60 @@ + + * GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + */ + +namespace Panel\Vmail; + +class DkimAdd extends \Panel\Vmail { + + function beforeRoute($f3) { + + parent::beforeRoute($f3); + + } + + static function get($f3) { + + if ($f3->exists('PARAMS.domain')) { + $domain = $f3->get('PARAMS.domain'); + if ($f3->call('\Panel::validateDomain', $domain)) { + if ($f3->call('\Panel::verifyVmailDomainExists', $domain)) { + if ($f3->call('\Panel::verifyDkimExists', $domain)) { + $messages = $f3->get('SESSION.messages'); + $messages[] = "DKIM for $domain already exists."; + $f3->set('SESSION.messages', $messages); + } else { + exec("/usr/local/bin/vmail-dkim-add.sh -d $domain", $output, $result_code); + $messages = $f3->get('SESSION.messages'); + if ($result_code == 0) { + $messages[] = "DKIM for $domain has been added."; + } else { + $messages[] = "ERROR: adding DKIM for $domain failed."; + } + $f3->set('SESSION.messages', $messages); + } + } else { + $messages = $f3->get('SESSION.messages'); + $messages[] = "ERROR: $domain is not configured for email on this server."; + $f3->set('SESSION.messages', $messages); + } + } else { + $messages = $f3->get('SESSION.messages'); + $messages[] = "ERROR: Invalid domain: $domain."; + $f3->set('SESSION.messages', $messages); + } + } + parse_str($f3->get('QUERY'), $output); + if (isset($output['r'])) { + $f3->reroute($output['r']); + } else { + $f3->reroute('/'); + } + + } + +} diff --git a/panel/classes/Panel/Vmail/DkimDelete.php b/panel/classes/Panel/Vmail/DkimDelete.php new file mode 100644 index 0000000..f440381 --- /dev/null +++ b/panel/classes/Panel/Vmail/DkimDelete.php @@ -0,0 +1,61 @@ + + * GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + */ + +namespace Panel\Vmail; + +class DkimDelete extends \Panel\Vmail { + + function beforeRoute($f3) { + + parent::beforeRoute($f3); + + } + + static function get($f3) { + + $f3->set('confirm', 'true'); + echo \Template::instance()->render('vmail/dkim-delete.html'); + + } + + static function post($f3) { + + if ($f3->exists('PARAMS.domain')) { + $domain = $f3->get('PARAMS.domain'); + if ($f3->call('\Panel::validateDomain', $domain)) { + if ($f3->call('\Panel::verifyDkimExists', $domain)) { + /* delete the dkim keys */ + exec("/usr/local/bin/vmail-dkim-del.sh -d $domain", $output, $result_code); + $messages = $f3->get('SESSION.messages'); + if ($result_code == 0) { + $messages[] = "DKIM keys for $domain have been deleted."; + $messages[] = "Note that you probably want to delete the associated DNS record now too."; + } else { + $messages[] = "Error deleting DKIM keys for $domain."; + } + } else { + $messages = $f3->get('SESSION.messages'); + $messages[] = "DKIM keys for $domain not found."; + } + } else { + $messages = $f3->get('SESSION.messages'); + $messages[] = "Invalid domain name ($domain)."; + } + } + $f3->set('SESSION.messages', $messages); + $mapping = $f3->get('NAV.mapping'); + if ($mapping == 'vmail') { + $f3->reroute("/"); + } else { + $f3->reroute("/Email/$domain"); + } + + } + +} diff --git a/panel/classes/Panel/Vmail/Domains.php b/panel/classes/Panel/Vmail/Domains.php index d752ae3..96275b6 100644 --- a/panel/classes/Panel/Vmail/Domains.php +++ b/panel/classes/Panel/Vmail/Domains.php @@ -19,15 +19,132 @@ class Domains extends \Panel\Vmail { $domain = $f3->get('PARAMS.domain'); if ($domain_array = $f3->call('\Panel::vGet', array("vmail-domains-get.sh -d $domain -c", FALSE))) { $f3->set('domain_array', $domain_array[0]); + /* get cert info */ + $mxdomain = "mail.$domain"; + if ($f3->call('\Panel::verifyCertificateExists', $mxdomain)) { + if ($cert_array = $f3->call('\Panel::vGet', array("letsencrypt-get.sh -d $mxdomain -c", FALSE))) { + $cert_array = $cert_array[0]; + /* remove time from expiration date */ + $end = $cert_array['end']; + $end_array = explode(' ', $end); + unset($end_array[2]); + $end = implode(' ', $end_array); + $cert_array['end'] = $end; + /* add line breaks */ + $common = $cert_array['common']; + $alternative = $cert_array['alternative']; + $alternative = preg_replace('/ /', '
', $alternative); + $cert_array['alternative'] = $alternative; + $f3->set('cert_array', $cert_array); + } + } + /* get dns info */ + $dnsinfo = array(); + $dnsinfo['verified_count'] = 0; + $dnsinfo['server_addr'] = $_SERVER['SERVER_ADDR']; + # A record + $dnsinfo['a']['color'] = "red"; + if ($certdomain_dns = dns_get_record("$mxdomain", DNS_A)) { + if ($certdomain_dns[0]['ip'] == $dnsinfo['server_addr']) { + $dnsinfo['a']['status'] = "Verified"; + $dnsinfo['a']['color'] = "black"; + $dnsinfo['verified_count']++; + } else { + $dnsinfo['a']['status'] = "Update"; + } + } else { + $dnsinfo['a']['status'] = "Create"; + } + # MX record + $dnsinfo['mx']['color'] = "red"; + if (getmxrr($domain, $mx)) { + if (in_array($mxdomain, $mx)) { + $dnsinfo['mx']['status'] = "Verified"; + $dnsinfo['mx']['color'] = "black"; + $dnsinfo['verified_count']++; + } else { + $dnsinfo['mx']['status'] = "Update"; + } + } else { + $dnsinfo['mx']['status'] = "Create"; + } + # SPF (TXT) record + $dnsinfo['spf']['status'] = "Create"; + $dnsinfo['spf']['color'] = "red"; + if ($dns_txt_records = dns_get_record("$domain", DNS_TXT)) { + foreach ($dns_txt_records as $k=>$dns_txt_record) { + if (str_starts_with($dns_txt_record['txt'], 'v=spf1')) { + $dnsinfo['spf']['status'] = "Update"; + if (str_contains($dns_txt_record['txt'], ' mx ')) { + $dnsinfo['spf']['status'] = "Verified"; + $dnsinfo['spf']['color'] = "black"; + $dnsinfo['verified_count']++; + } + } + } + } + # DKIM + $dnsinfo['dkim']['color'] = "red"; + if ($f3->call('\Panel::verifyDkimExists', $domain)) { + if ($dkim_array = $f3->call('\Panel::vGet', array("vmail-dkim-get.sh -d $domain -c", FALSE))) { + $dkim_hostname = $dkim_array[0]['selector'] . "._domainkey.$domain"; + if ($dns_txt_records = dns_get_record($dkim_hostname, DNS_TXT)) { + $dnsinfo['dkim']['status'] = "Verified"; + $dnsinfo['dkim']['color'] = "black"; + $dnsinfo['verified_count']++; + } else { + $dnsinfo['dkim']['status'] = "Update"; + $dnsinfo['dkim']['selector'] = $dkim_array[0]['selector']; + $dnsinfo['dkim']['dkim'] = $dkim_array[0]['dkim']; + } + } else { + $dnsinfo['dkim']['status'] = "Error"; + } + } else { + $dnsinfo['dkim']['status'] = "Create"; + } + + if ($dnsinfo['verified_count'] == 4) { + $dnsinfo['status'] = 'Verified'; + } else { + $dnsinfo['status'] = 'Update'; + } + + $f3->set('dnsinfo', $dnsinfo); + } } else { if ($domains_array = $f3->call('\Panel::vGet', array("vmail-domains-get.sh -c", FALSE))) { $f3->set('domains_array', $domains_array); } } - } + // $dnsinfo['mx']['status'] = ready/update/none + // $dnsinfo['spf']['status'] = ready/update/none + // $dnsinfo['spf']['data'] = current_record + // $dnsinfo['dkim']['status'] = ready/update/none + // $dnsinfo['dkim']['selector'] = + // $dnsinfo['dkim']['data'] = + + // dns_a gethostbyname() + // dns_mx getmxrr() / dns_get_mx() + // dns_spf checkdnsrr() / dns_check_record() + // dns_dkim + // # domain does not have cert yet, check DNS + // $dns_a_record = $_SERVER['SERVER_ADDR']; + // if ($certdomain_dns = dns_get_record("$certdomain", DNS_A)) { + // if ($certdomain_dns[0]['ip'] == $dns_a_record) { + // $dns_status = "ready"; + // } else { + // $dns_status = "update"; + // } + // } else { + // $dns_status = "none"; + // } + // $f3->set('dns_a_record', $dns_a_record); + // $f3->set('dns_status', $dns_status); + static function get($f3) { if ($f3->exists('PARAMS.domain')) { diff --git a/panel/classes/Panel/Vmail/DomainsAdd.php b/panel/classes/Panel/Vmail/DomainsAdd.php index 55cf616..64fac1d 100644 --- a/panel/classes/Panel/Vmail/DomainsAdd.php +++ b/panel/classes/Panel/Vmail/DomainsAdd.php @@ -34,10 +34,13 @@ class DomainsAdd extends \Panel\Vmail { $messages = array(); /* validate domain */ - if (preg_match('/^[0-9a-z]([-.]?[0-9a-z])*\.[a-z]{2,24}$/i', strtolower($_POST['domain']))) { - $domain = strtolower($_POST['domain']); - } else { - $messages[] = "Invalid domain name."; + $domain = strtolower($_POST['domain']); + $domain = preg_replace('/^mail\./', '', $domain); + $domain = preg_replace('/^www\./', '', $domain); + if ($f3->call('\Panel::validateDomain', $domain)) { + if ($f3->call('\Panel::verifyVmailDomainExists', $domain)) { + $messages[] = "Email Domain '$domain' already exists."; + } } /* validate status */ @@ -94,32 +97,23 @@ class DomainsAdd extends \Panel\Vmail { $f3->set('SESSION.messages', $messages); $f3->call('\Panel\Vmail\DomainsAdd::get', $f3); } else { - /* check if vmail domain already exists */ - $domain_array = $f3->call('\Panel::vGet', array("vmail-domains-get.sh -d $domain -c", FALSE)); - if (count($domain_array) == 0) { - /* add email domain */ - exec("/usr/local/bin/vmail-domains-add.sh -d $domain -l $mbox_limit -q $mbox_quota_default -r $mbox_ratelimit_default -s $status", $output, $result_code); - if ($result_code == 0) { - $messages[] = "Email Domain $domain has been added."; - $f3->set('SESSION.messages', $messages); - $f3->reroute("/Email/$domain"); - } else { - if (count($output) > 0) { - foreach ($output as $k=>$output_message) { - $messages[] = "$output_message"; - } - } else { - $messages[] = "Unknown error adding Email Domain $domain."; - } - $f3->set('SESSION.messages', $messages); - $f3->call('\Panel\Vmail\DomainsAdd::get', $f3); - } - } else { - $messages[] = "Email Domain '$domain' already exists."; + /* add email domain */ + exec("/usr/local/bin/vmail-domains-add.sh -d $domain -l $mbox_limit -q $mbox_quota_default -r $mbox_ratelimit_default -s $status", $output, $result_code); + if ($result_code == 0) { + $messages[] = "Email Domain $domain has been added."; $f3->set('SESSION.messages', $messages); $f3->reroute("/Email/$domain"); + } else { + if (count($output) > 0) { + foreach ($output as $k=>$output_message) { + $messages[] = "$output_message"; + } + } else { + $messages[] = "Unknown error adding Email Domain $domain."; + } + $f3->set('SESSION.messages', $messages); + $f3->call('\Panel\Vmail\DomainsAdd::get', $f3); } } } - } diff --git a/panel/classes/Panel/Vmail/MboxesAdd.php b/panel/classes/Panel/Vmail/MboxesAdd.php index 30cab53..39ccdb2 100644 --- a/panel/classes/Panel/Vmail/MboxesAdd.php +++ b/panel/classes/Panel/Vmail/MboxesAdd.php @@ -58,7 +58,7 @@ class MboxesAdd extends \Panel\Vmail { extract($_POST); $f3->call('\Panel::validateEmailLocalpart', $localpart); - $f3->call('\Panel::validateEmailPassword', array($password, $password_confirm)); + $f3->call('\Panel::validatePassword', array($password, $password_confirm)); settype($status, "integer"); $f3->call('\Panel::validateEmailStatus', $status); if (strtolower($quota == 'unlimited') || strtolower($quota == 'null')) { diff --git a/panel/classes/Panel/Vmail/MboxesEdit.php b/panel/classes/Panel/Vmail/MboxesEdit.php index edec05a..11de74c 100644 --- a/panel/classes/Panel/Vmail/MboxesEdit.php +++ b/panel/classes/Panel/Vmail/MboxesEdit.php @@ -62,7 +62,7 @@ class MboxesEdit extends \Panel\Vmail { extract($mbox_array); if ($password != '') { - $f3->call('\Panel::validateEmailPassword', array($password, $password_confirm)); + $f3->call('\Panel::validatePassword', array($password, $password_confirm)); } settype($status, "integer"); $f3->call('\Panel::validateEmailStatus', $status); diff --git a/panel/config/config.ini b/panel/config/config.ini index af814f4..7ccd7ad 100644 --- a/panel/config/config.ini +++ b/panel/config/config.ini @@ -16,6 +16,15 @@ LICENSE=GPL-3.0 LICENSEURL=https://www.gnu.org/licenses/gpl-3.0.txt CASELESS=FALSE CACHE=TRUE -; session lifetime in seconds +; Session lifetime in seconds TIMEOUT=900 +; Remote IP address that is automatically logged in without auth ADMINIP= +; Jail new users by default. 1 = Yes, blank or 0 = No +JAILUSER=1 +; PHP-FPM pm.max_children. Recommended range 2-12 on Shared Server +FPMMAX=4 +; Write user info to /home/username/.passwd. 1 = Yes, blank or 0 = No +WRITEUSERINFO=1 +; Show "Write User Info" & "Write DB Info" options. If no then just use defaults above without giving users the option to change. 1 = Yes, blank or 0 = No +SHOWWRITEINFO=0 diff --git a/panel/config/maps-vpanel.ini b/panel/config/maps-vpanel.ini index 61106c9..bebb7cb 100644 --- a/panel/config/maps-vpanel.ini +++ b/panel/config/maps-vpanel.ini @@ -30,6 +30,9 @@ /Email/@domain/Accounts/@mbox/Forwarding/Add [sync] = Panel\Vmail\ForwardsAdd /Email/@domain/Accounts/@mbox/Forwarding/Edit [sync] = Panel\Vmail\ForwardsEdit /Email/@domain/Accounts/@mbox/Forwarding/Delete [sync] = Panel\Vmail\ForwardsDelete +/Email/@domain/Dkim [sync] = Panel\Vmail\Dkim +/Email/@domain/Dkim/Add [sync] = Panel\Vmail\DkimAdd +/Email/@domain/Dkim/Delete [sync] = Panel\Vmail\DkimDelete /Email/@domain/Aliases [sync] = Panel\Vmail\Aliases /Email/@domain/Aliases/@alias [sync] = Panel\Vmail\Aliases /Email/@domain/Autoresponders [sync] = Panel\Vmail\Autoresponders @@ -38,16 +41,17 @@ /Websites [sync] = Panel\Vhost\Vhosts /Websites/Add [sync] = Panel\Vhost\VhostsAdd /Websites/@vhost [sync] = Panel\Vhost\Vhosts -/Websites/@vhost/Edit [sync] = Panel\Vhost\VhostsEdit +/Websites/@vhost/Disable [sync] = Panel\Vhost\VhostsDisable +/Websites/@vhost/Enable [sync] = Panel\Vhost\VhostsEnable /Websites/@vhost/Delete [sync] = Panel\Vhost\VhostsDelete -/Websites/@vhost/Databases [sync] = Panel\Vhost\Databases -/Websites/@vhost/Databases/Add [sync] = Panel\Vhost\DatabasesAdd -/Websites/@vhost/Databases/Delete [sync] = Panel\Vhost\DatabasesDelete -/Websites/@vhost/Databases/Users [sync] = Panel\Vhost\DatabasesUsers -/Websites/@vhost/Databases/Users/Add [sync] = Panel\Vhost\DatabasesUsersAdd -/Websites/@vhost/Databases/Users/Edit [sync] = Panel\Vhost\DatabasesUsersEdit -/Websites/@vhost/Databases/Users/Delete [sync] = Panel\Vhost\DatabasesUsersDelete +; /Websites/@vhost/Databases [sync] = Panel\Vhost\Databases +; /Websites/@vhost/Databases/Add [sync] = Panel\Vhost\DatabasesAdd +; /Websites/@vhost/Databases/Delete [sync] = Panel\Vhost\DatabasesDelete +; /Websites/@vhost/Databases/Users [sync] = Panel\Vhost\DatabasesUsers +; /Websites/@vhost/Databases/Users/Add [sync] = Panel\Vhost\DatabasesUsersAdd +; /Websites/@vhost/Databases/Users/Edit [sync] = Panel\Vhost\DatabasesUsersEdit +; /Websites/@vhost/Databases/Users/Delete [sync] = Panel\Vhost\DatabasesUsersDelete /Websites/Redirects [sync] = Panel\Vhost\Redirects /Websites/Redirects/Add [sync] = Panel\Vhost\RedirectsAdd @@ -70,6 +74,14 @@ ; System users (ssh, websites) /Users [sync] = Panel\Vhost\Users /Users/Add [sync] = Panel\Vhost\UsersAdd -/Users/@user [sync] = Panel\Vhost\Users -/Users/@user/Edit [sync] = Panel\Vhost\UsersEdit -/Users/@user/Delete [sync] = Panel\Vhost\UsersDelete +/Users/@username [sync] = Panel\Vhost\Users +/Users/@username/Edit [sync] = Panel\Vhost\UsersEdit +/Users/@username/Delete [sync] = Panel\Vhost\UsersDelete + +/Certs [sync] = Panel\Cert\Certs +/Certs/@cert [sync] = Panel\Cert\Certs +/Certs/@cert/Add [sync] = Panel\Cert\CertsAdd +/Certs/@cert/Delete [sync] = Panel\Cert\CertsDelete + +/Databases [sync] = Panel\MySQL\Databases + diff --git a/panel/ui/cert/certs-cert.html b/panel/ui/cert/certs-cert.html new file mode 100644 index 0000000..5494673 --- /dev/null +++ b/panel/ui/cert/certs-cert.html @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + +
CertificateExpirationSecured HostnamesAction
{{ @cert_array.common }}{{ @cert_array.end }}{{ @cert_array.alternative | raw }}Delete
+ +

+ + + diff --git a/panel/ui/cert/certs.html b/panel/ui/cert/certs.html new file mode 100644 index 0000000..89abbc6 --- /dev/null +++ b/panel/ui/cert/certs.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + +
CertificateExpirationSecured Hostnames
{{ @cert_array.common }}{{ @cert_array.end }}{{ @cert_array.alternative | raw }}
+

+ Certificate is the name of the configuration and is normally the primary domain secured.
+ Expiration is the date the certificate expires. Certificates are automatically renewed 30 days before expiration.
+ Secured Hostnames is the full list of domain names secured by the certificate.
+

+
+ +

There are no security certificates on this server.

+
+
+ +

+Add new Certificate form +

+ + diff --git a/panel/ui/header.html b/panel/ui/header.html index a2055d3..74e9ce0 100644 --- a/panel/ui/header.html +++ b/panel/ui/header.html @@ -10,6 +10,17 @@ {{@PACKAGE}} + + +
@@ -19,8 +30,9 @@ Websites | Email | - Databases | - Certificates | + Databases | + Certificates | + Users | Logout diff --git a/panel/ui/mysql/databases.html b/panel/ui/mysql/databases.html new file mode 100644 index 0000000..9aa6205 --- /dev/null +++ b/panel/ui/mysql/databases.html @@ -0,0 +1,8 @@ + + +phpMyAdmin can be reached at https://{{@HOST}}/phpMyAdmin +
+
+Note that phpMyAdmin requires a two-stage login process.
First use the websites "Remote Access" info (SFTP/SSH username & password) for the popup authentication.
Then use the MySQL info for the database login page.
+ + diff --git a/panel/ui/vhost/users-add.html b/panel/ui/vhost/users-add.html new file mode 100644 index 0000000..e9235f2 --- /dev/null +++ b/panel/ui/vhost/users-add.html @@ -0,0 +1,185 @@ + + +
+
+ Add New System User + + + + + + + + + + Leave both password fields blank for random password generation. + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +

+Username is the system username that a website can be installed under. It will be used for SFTP & SSH access. Mixed case usernames are converted to all lower case.
+Password must be at least 8 characters with 12 or more being highly recommended.
+Passwords under 15 characters must contain characters from at least three of the following four groups:
+Lower Case Letters, Uppler Case Leters, Numbers, Puncuation/Special Characters.
+Passwords 15 or more characters long do not have any complexity requirements.
+Jail determines if the user will be "jailed". This is recommended on a Shared Server. Once a user is Jailed it can't be undone by these admins.
+ +Write User Info writes user account information to /home/username/.passwd. Includes encrypted password, which can be unencrypted.
+
+PHP Workers is maximum number of PHP processes that this user can have running at one time. Any website(s) installed for this user will be limited by this.
+

+ + + diff --git a/panel/ui/vhost/users-delete.html b/panel/ui/vhost/users-delete.html new file mode 100644 index 0000000..4f9547d --- /dev/null +++ b/panel/ui/vhost/users-delete.html @@ -0,0 +1,20 @@ + + + + +
+
+ Really Delete User {{ @PARAMS.username }} +
+ +
+ CAUTION: This will permanently remove the user {{ @PARAMS.username }} and any related settings and files from this server. There is no undo after this! +
+
+
+ + Go to Users
+
+
+ + diff --git a/panel/ui/vhost/users-edit.html b/panel/ui/vhost/users-edit.html new file mode 100644 index 0000000..0bf5dd3 --- /dev/null +++ b/panel/ui/vhost/users-edit.html @@ -0,0 +1,176 @@ + + + +

+

+
+ Change Password for {{ @user_array.username }} + + + + + + + + + + +
+ +Password must be at least 8 characters with 12 or more being highly recommended.
+Passwords under 15 characters must contain characters from at least three of the following four groups:
+Lower Case Letters, Uppler Case Leters, Numbers, Puncuation/Special Characters.
+Passwords 15 or more characters long do not have any complexity requirements.
+ +
+
+

+ +

+ +

+
+ Jail User {{ @user_array.username }} + + + + User is Jailed. This can not be undone by this admin. + + +
+ Jail User puts existing user in a secure jail. This is recommended on a Shared Server. Once a user is Jailed it can't be undone by these admins.
+
+
+
+
+

+ + +

+

+
+ Adjust PHP Workers for {{ @user_array.username }} + + + + User {{ @user_array.username }} does not have PHP enabled. + + + + + + +
+ PHP Workers is maximum number of PHP processes that this user can have running at one time. Any website(s) installed for this user will be limited by this.
+
+
+
+
+

+ + diff --git a/panel/ui/vhost/users-user.html b/panel/ui/vhost/users-user.html new file mode 100644 index 0000000..5e4b542 --- /dev/null +++ b/panel/ui/vhost/users-user.html @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + +
UsernamePasswordJailedPHP WorkersAction
{{ @users_array.username }}{{ @users_array.jailed }}{{ @users_array.fpmmax }}Edit Delete
+ +

+ +

Websites

+ +
+ + + + + + + + + + + + + + + + + + + + + + +
WebsiteUsernameStatusAction
{{ @vhost_domain.virtualhost }}{{ @vhost_domain.username }}{{ @vhost_domain.status }}Disable Delete
+
+ + There are no websites for this user. + +
+ + diff --git a/panel/ui/vhost/users.html b/panel/ui/vhost/users.html new file mode 100644 index 0000000..596c7ca --- /dev/null +++ b/panel/ui/vhost/users.html @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + +
UsernamePasswordJailedPHP Workers
{{ @userinfo.username }}{{ @userinfo.jailed }}{{ @userinfo.fpmmax }}
+

+ Select a Username name above for more details and options.
+ Username is the system username that owns the website files.
+ + Password is the unencrypted password for the user, if available. Scroll over field to reveal password.
+ Jailed is a flag indicating if the user is jailed.
+ PHP Workers is maximum number of PHP processes that this user can have running at one time.
+

+
+ +

There are no website system users on this server.

+
+
+ +

+Add new User form +

+ + diff --git a/panel/ui/vhost/vhosts-add.html b/panel/ui/vhost/vhosts-add.html index b75613a..975e2bf 100644 --- a/panel/ui/vhost/vhosts-add.html +++ b/panel/ui/vhost/vhosts-add.html @@ -7,22 +7,31 @@ - - + + - - - + Add user here first if you want to create a specific username for this site. - - +

@@ -34,10 +43,8 @@

-Username
-Jail
-Config
-Status can be used to temporarily disable the website domain without deleting any settings or files.
+Domain Name Enter the website domain name without the leading www.
+Username By default this should be left blank which will create a new (unique) username just for this site. Optionally you can pick from a list of existing users, or first go to the User admin and create a specific username & password.

diff --git a/panel/ui/vhost/vhosts-delete.html b/panel/ui/vhost/vhosts-delete.html new file mode 100644 index 0000000..2fcd2d0 --- /dev/null +++ b/panel/ui/vhost/vhosts-delete.html @@ -0,0 +1,20 @@ + + + + +
+
+ Really Delete Website {{ @PARAMS.vhost }} +
+ +
+ CAUTION: This will permanently remove the {{ @PARAMS.vhost }} website and any related databases and username from this server. There is no undo after this! +
+
+
+ + Go to Websites
+
+
+ + diff --git a/panel/ui/vhost/vhosts-vhost.html b/panel/ui/vhost/vhosts-vhost.html index ed4adc1..a62981e 100644 --- a/panel/ui/vhost/vhosts-vhost.html +++ b/panel/ui/vhost/vhosts-vhost.html @@ -2,35 +2,97 @@ - + - - - - - - + - - - - - - - - + + +
DomainWebsite StatusMailbox LimitDefault QuotaDefault Rate LimitActionAction
{{ @vhost_array.domain }}{{ @vhost_array.status }}{{ @vhost_array.mbox_limit }}{{ @vhost_array.mbox_quota_default }}{{ @vhost_array.mbox_ratelimit_default }}Edit Delete{{ @vhost_array.virtualhost }}{{ @vhost_array.status }} + + Disable + Enable + + Delete +
- +

+ + + + + + + + + + + + +
System UserPHP WorkersAction
{{ @vhost_array.username }}{{ @users_array.fpmmax }}Edit
+ +

+ + + + + + + + + + + + + + + + +
CertificateExpirationSecured HostnamesAction
{{ @cert_array.common }}{{ @cert_array.end }}{{ @cert_array.alternative | raw }}Delete
+
+ +Add Security Certificate + +
+ +

+ + + + + + + + + + + + +
Remote Access
Protocol:SFTP (SSH File Transfer Protocol)
Hostname:{{ @vhost_array.virtualhost }}
Username:{{ @vhost_array.username }}
Password: ← hover mouse here to reveal
User Home Directory:/home/{{ @vhost_array.username }}/
Website Files Directory:/srv/www/{{ @vhost_array.username }}/html/
User Jailed:{{ @users_array.jailed }}
Action:Edit User
Notes:The above information can also be used for SSH access.
+ +

+ + + + + + + + + +
MySQL Database Info
Hostname:{{ @mysqlinfo_array.hostname }}
Database:{{ @mysqlinfo_array.database }}
Username:{{ @mysqlinfo_array.username }}
Password: ← hover mouse here to reveal
phpMyAdmin: + + + https://{{ @vhost_array.virtualhost }}/phpMyAdmin + + + https://{{ @HOST }}/phpMyAdmin + + +
Notes:phpMyAdmin requires a two-stage login process.
First use the "Remote Access" info for the popup authentication.
Then use the MySQL info for the database login page.
diff --git a/panel/ui/vhost/vhosts.html b/panel/ui/vhost/vhosts.html index daaa167..d6d5e3b 100644 --- a/panel/ui/vhost/vhosts.html +++ b/panel/ui/vhost/vhosts.html @@ -6,16 +6,14 @@ Website Username - Config Status - {{ @vhost_domain.virtualhost }} - {{ @vhost_domain.username }} - {{ @vhost_domain.config }} + {{ @vhost_domain.virtualhost }} + {{ @vhost_domain.username }} {{ @vhost_domain.status }} diff --git a/panel/ui/vmail/dkim-delete.html b/panel/ui/vmail/dkim-delete.html new file mode 100644 index 0000000..d7e5227 --- /dev/null +++ b/panel/ui/vmail/dkim-delete.html @@ -0,0 +1,20 @@ + + + + +
+
+ Really Delete DKIM {{ @PARAMS.domain }} +
+ +
+ CAUTION: This will permanently remove the DKIM keys for {{ @PARAMS.domain }}.
You probably want to delete the associated DNS entry too.
+
+
+
+ + Go to {{ @PARAMS.domain }}
+
+
+ + diff --git a/panel/ui/vmail/dkim.html b/panel/ui/vmail/dkim.html new file mode 100644 index 0000000..9051b0c --- /dev/null +++ b/panel/ui/vmail/dkim.html @@ -0,0 +1,44 @@ + + + + + + + DKIM for {{@PARAMS.domain}} does not exist.
+ Click here to add a DKIM Key now. +
+ + + + Error checking for DKIM for {{@PARAMS.domain}}. Try again later. + + + + + + + + + + + + + + + + + +
DKIM (TXT) Record for {{ @PARAMS.domain }}
This DNS record is all set, nothing to do.
Please update DNS with the following info.
Type:TXT
Host:{{ @dkim_array.dns.host }}
Value:"k=rsa; p={{ @dkim_array.dkim }}"
TTL:3600 (or default)
This should be the only record for this specific Host value listed above.
+ +

+ Click here to delete this DKIM Key. + +
+
+
+
+
+
+ + + diff --git a/panel/ui/vmail/domains-domain.html b/panel/ui/vmail/domains-domain.html index 231fe68..c00c084 100644 --- a/panel/ui/vmail/domains-domain.html +++ b/panel/ui/vmail/domains-domain.html @@ -12,11 +12,11 @@ - {{ @domain_array.domain }} - {{ @domain_array.status }} - {{ @domain_array.mbox_limit }} - {{ @domain_array.mbox_quota_default }} - {{ @domain_array.mbox_ratelimit_default }} + {{ @domain_array.domain }} + {{ @domain_array.status }} + {{ @domain_array.mbox_limit }} + {{ @domain_array.mbox_quota_default }} + {{ @domain_array.mbox_ratelimit_default }} Edit Delete @@ -32,29 +32,171 @@ +
+ + + + + + + + + + + + + + + + +
CertificateExpirationSecured HostnamesAction
{{ @cert_array.common }}{{ @cert_array.end }}{{ @cert_array.alternative | raw }}Delete
+
+ + + + You need a Security Certificate. Click Here to add one now. + + + You need a Security Certificate for {{ @domain_array.domain }}. Before you can add one you must create the DNS "A" record below. Once that's completed come back here and this message will change to an option to create a Security Certificate. + + + +
- + + + ✓ All email related DNS settings for {{ @domain_array.domain }} have been verified. +

+ Webmail is available at: https://mail.{{ @domain_array.domain }} +
+ +

NOTICE: You need to update the DNS settings for {{ @domain_array.domain }}:

+ Note that after you add DNS records it can take some time for the changes to propagate and show up here. +

+ + + + + + + + + + + + + + +
{{ @dnsinfo.a.status }} A Record for mail.{{ @domain_array.domain }}
This DNS record is all set, nothing to do.
Type:A
Host:mail.{{ @domain_array.domain }}
Value:{{ @dnsinfo.server_addr }}
TTL:3600 (or default)
This should be the only A record for mail.{{ @domain_array.domain }}.
+ +

+ + + + + + + + + + + + + + + + +
{{ @dnsinfo.mx.status }} MX Record for {{ @domain_array.domain }}
This DNS record is all set, nothing to do.
Type:MX
Host:{{ @domain_array.domain }}
Value:mail.{{ @domain_array.domain }}
TTL:3600 (or default)
Priority:10 (or default)
This should be the only MX record for {{ @domain_array.domain }}
unless you have a backup MX system.
+ +

+ + + + + + + + + + + + + + +
{{ @dnsinfo.spf.status }} SPF (TXT) Record for {{ @domain_array.domain }}
This DNS record is all set, nothing to do.
Type:TXT
Host:{{ @domain_array.domain }}
Value:"v=spf1 a mx -all"
TTL:3600 (or default)
There may be other TXT records for {{ @domain_array.domain }}.
+ +

+ + + + + + + + + + + + + + + + + + + + + + +
{{ @dnsinfo.dkim.status }} DKIM (TXT) Record for {{ @domain_array.domain }}
DKIM is all set, nothing to do.
Type:TXT
Host:{{ @dnsinfo.dkim.selector }}._domainkey.{{ @domain_array.domain }}
Value:"k=rsa; p={{ @dnsinfo.dkim.dkim }}"
TTL:3600 (or default)
This should be the only TXT record for this specific Host name.
Add DKIM Key
Use the link above to create a DKIM configuration. Once that's completed come back here and this message will change to instructions on adding an associated DNS record.
+
+
+ + + +
+

Email Client Configuration Options

+Use the settings below to configure email clients like
Mozilla Thunderbird, Apple Mail, Microsoft Outlook, et cetera.
+

+ + + + + + + + + + +
Incoming Server Settings
Protocol:IMAP
Hostname:mail.{{ @domain_array.domain }}
Port143
Connection Security:STARTTLS
Authentication Method:Normal password
Username:(full email address)
Notes:Alternative options that work:
Connection Security: SSL/TLS
Port: 993
+ +

+ + + + + + + + + + +
Outgoing Server Settings
Protocol:SMTP
Hostname:mail.{{ @domain_array.domain }}
Port587
Connection Security:STARTTLS
Authentication Method:Normal password
Username:(full email address)
Notes:Alternative options that work:
Connection Security: SSL/TLS
Port: 465
+ +

+ + + + + + + + + + + +
Alternative Incoming Server Settings
Protocol:POP3
Hostname:mail.{{ @domain_array.domain }}
Port110
Connection Security:STARTTLS
Authentication Method:Normal password
Username:(full email address)
Notes:Alternative options that work:
Connection Security: SSL/TLS
Port: 995
IMAP (listed above) keeps your folders and emails synced on your
server and is the recommended default.
POP3 listed here keeps your folders and emails on your local
computer and can sometimes be a prefered configuration.
+