commit
bdba65686b
|
@ -8,10 +8,9 @@ while mysqladmin ping --host mysql --silent; do
|
||||||
mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP VIEW IF EXISTS sogo_view"
|
mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP VIEW IF EXISTS sogo_view"
|
||||||
|
|
||||||
mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
|
mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
|
||||||
CREATE VIEW sogo_view (c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, senderacl, home, kind, multiple_bookings) AS
|
CREATE VIEW sogo_view (c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, home, kind, multiple_bookings) AS
|
||||||
SELECT mailbox.username, mailbox.domain, mailbox.username, mailbox.password, mailbox.name, mailbox.username, IFNULL(ga.aliases, ''), IFNULL(gda.ad_alias, ''), IFNULL(gs.send_as, ''), CONCAT('/var/vmail/', maildir), mailbox.kind, mailbox.multiple_bookings FROM mailbox
|
SELECT mailbox.username, mailbox.domain, mailbox.username, mailbox.password, mailbox.name, mailbox.username, IFNULL(ga.aliases, ''), IFNULL(gda.ad_alias, ''), CONCAT('/var/vmail/', maildir), mailbox.kind, mailbox.multiple_bookings FROM mailbox
|
||||||
LEFT OUTER JOIN grouped_mail_aliases ga ON ga.username = mailbox.username
|
LEFT OUTER JOIN grouped_mail_aliases ga ON ga.username = mailbox.username
|
||||||
LEFT OUTER JOIN grouped_sender_acl gs ON gs.username = mailbox.username
|
|
||||||
LEFT OUTER JOIN grouped_domain_alias_address gda ON gda.username = mailbox.username
|
LEFT OUTER JOIN grouped_domain_alias_address gda ON gda.username = mailbox.username
|
||||||
WHERE mailbox.active = '1';
|
WHERE mailbox.active = '1';
|
||||||
EOF
|
EOF
|
||||||
|
@ -50,11 +49,10 @@ EOF
|
||||||
# Generate multi-domain setup
|
# Generate multi-domain setup
|
||||||
while read line
|
while read line
|
||||||
do
|
do
|
||||||
DOMAIN_SANE=$(echo ${line} | tr '-' 'b' | tr '.' 'p' | tr -cd '[[:alnum:]]')
|
|
||||||
echo " <key>${line}</key>
|
echo " <key>${line}</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>SOGoMailDomain</key>
|
<key>SOGoMailDomain</key>
|
||||||
<string>${DOMAIN_SANE}</string>
|
<string>${line}</string>
|
||||||
<key>SOGoUserSources</key>
|
<key>SOGoUserSources</key>
|
||||||
<array>
|
<array>
|
||||||
<dict>
|
<dict>
|
||||||
|
@ -62,7 +60,6 @@ while read line
|
||||||
<array>
|
<array>
|
||||||
<string>aliases</string>
|
<string>aliases</string>
|
||||||
<string>ad_aliases</string>
|
<string>ad_aliases</string>
|
||||||
<string>senderacl</string>
|
|
||||||
</array>
|
</array>
|
||||||
<key>KindFieldName</key>
|
<key>KindFieldName</key>
|
||||||
<string>kind</string>
|
<string>kind</string>
|
||||||
|
@ -98,4 +95,4 @@ chmod 600 /var/lib/sogo/GNUstep/Defaults/sogod.plist
|
||||||
|
|
||||||
sleep 99999
|
sleep 99999
|
||||||
|
|
||||||
done;
|
done
|
||||||
|
|
|
@ -39,7 +39,7 @@ server {
|
||||||
|
|
||||||
rewrite ^(/save.+)$ /rspamd$1 last;
|
rewrite ^(/save.+)$ /rspamd$1 last;
|
||||||
location /rspamd/ {
|
location /rspamd/ {
|
||||||
proxy_pass http://rspamd:11334/;
|
proxy_pass http://172.22.1.253:11334/;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
|
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
|
||||||
|
@ -61,7 +61,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location ^~ /Microsoft-Server-ActiveSync {
|
location ^~ /Microsoft-Server-ActiveSync {
|
||||||
proxy_pass http://sogo:20000/SOGo/Microsoft-Server-ActiveSync;
|
proxy_pass http://172.22.1.252:20000/SOGo/Microsoft-Server-ActiveSync;
|
||||||
proxy_connect_timeout 1000;
|
proxy_connect_timeout 1000;
|
||||||
proxy_next_upstream timeout error;
|
proxy_next_upstream timeout error;
|
||||||
proxy_send_timeout 1000;
|
proxy_send_timeout 1000;
|
||||||
|
@ -83,7 +83,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location ^~ /SOGo {
|
location ^~ /SOGo {
|
||||||
proxy_pass http://sogo:20000;
|
proxy_pass http://172.22.1.252:20000;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
|
@ -105,7 +105,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location /SOGo.woa/WebServerResources/ {
|
location /SOGo.woa/WebServerResources/ {
|
||||||
proxy_pass http://sogo:9192/WebServerResources/;
|
proxy_pass http://172.22.1.252:9192/WebServerResources/;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_cache sogo;
|
proxy_cache sogo;
|
||||||
proxy_cache_valid 200 1d;
|
proxy_cache_valid 200 1d;
|
||||||
|
@ -115,7 +115,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location /SOGo/WebServerResources/ {
|
location /SOGo/WebServerResources/ {
|
||||||
proxy_pass http://sogo:9192/WebServerResources/;
|
proxy_pass http://172.22.1.252:9192/WebServerResources/;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_cache sogo;
|
proxy_cache sogo;
|
||||||
proxy_cache_valid 200 1d;
|
proxy_cache_valid 200 1d;
|
||||||
|
@ -125,7 +125,7 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location (^/SOGo/so/ControlPanel/Products/[^/]*UI/Resources/.*\.(jpg|png|gif|css|js)$ {
|
location (^/SOGo/so/ControlPanel/Products/[^/]*UI/Resources/.*\.(jpg|png|gif|css|js)$ {
|
||||||
proxy_pass http://sogo:9192/$1.SOGo/Resources/$2;
|
proxy_pass http://172.22.1.252:9192/$1.SOGo/Resources/$2;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_cache sogo;
|
proxy_cache sogo;
|
||||||
proxy_cache_valid 200 1d;
|
proxy_cache_valid 200 1d;
|
||||||
|
|
|
@ -14,4 +14,9 @@ $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
while ($row = array_shift($rows)) {
|
while ($row = array_shift($rows)) {
|
||||||
echo strtolower(trim($row['username'])) . PHP_EOL;
|
echo strtolower(trim($row['username'])) . PHP_EOL;
|
||||||
}
|
}
|
||||||
|
$stmt = $pdo->query("SELECT CONCAT(mailbox.local_part, '@', alias_domain.alias_domain) as `tag_ad` FROM `mailbox` INNER JOIN `alias_domain` ON mailbox.domain = alias_domain.target_domain WHERE mailbox.wants_tagged_subject='1';");
|
||||||
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
while ($row = array_shift($rows)) {
|
||||||
|
echo strtolower(trim($row['tag_ad'])) . PHP_EOL;
|
||||||
|
}
|
||||||
?>
|
?>
|
|
@ -27,11 +27,25 @@ rspamd_config.ADD_DELIMITER_TAG = {
|
||||||
callback = function(task)
|
callback = function(task)
|
||||||
local util = require("rspamd_util")
|
local util = require("rspamd_util")
|
||||||
local rspamd_logger = require "rspamd_logger"
|
local rspamd_logger = require "rspamd_logger"
|
||||||
local user_tagged = task:get_recipients(1)[1]['user']
|
|
||||||
|
local user_env_tagged = task:get_recipients(1)[1]['user']
|
||||||
|
local user_to_tagged = task:get_recipients(2)[1]['user']
|
||||||
|
|
||||||
local domain = task:get_recipients(1)[1]['domain']
|
local domain = task:get_recipients(1)[1]['domain']
|
||||||
local user, tag = user_tagged:match("([^+]+)+(.*)")
|
|
||||||
|
local user_env, tag_env = user_env_tagged:match("([^+]+)+(.*)")
|
||||||
|
local user_to, tag_to = user_to_tagged:match("([^+]+)+(.*)")
|
||||||
|
|
||||||
local authdomain = auth_domain_map:get_key(domain)
|
local authdomain = auth_domain_map:get_key(domain)
|
||||||
|
|
||||||
|
if tag_env then
|
||||||
|
tag = tag_env
|
||||||
|
user = user_env
|
||||||
|
elseif tag_to then
|
||||||
|
tag = tag_to
|
||||||
|
user = user_env
|
||||||
|
end
|
||||||
|
|
||||||
if tag and authdomain then
|
if tag and authdomain then
|
||||||
rspamd_logger.infox("Domain %s is part of mailcow, start reading tag settings", domain)
|
rspamd_logger.infox("Domain %s is part of mailcow, start reading tag settings", domain)
|
||||||
local user_untagged = user .. '@' .. domain
|
local user_untagged = user .. '@' .. domain
|
||||||
|
|
|
@ -4,6 +4,7 @@ require_once("inc/prerequisites.inc.php");
|
||||||
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admin") {
|
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admin") {
|
||||||
require_once("inc/header.inc.php");
|
require_once("inc/header.inc.php");
|
||||||
$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
||||||
|
$tfa_data = get_tfa();
|
||||||
?>
|
?>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h4><span class="glyphicon glyphicon-user" aria-hidden="true"></span> <?=$lang['admin']['access'];?></h4>
|
<h4><span class="glyphicon glyphicon-user" aria-hidden="true"></span> <?=$lang['admin']['access'];?></h4>
|
||||||
|
@ -43,12 +44,26 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-3 col-xs-5 text-right"><?=$lang['tfa']['tfa'];?>:</div>
|
<div class="col-sm-3 col-xs-5 text-right"><?=$lang['tfa']['tfa'];?>:</div>
|
||||||
<div class="col-sm-9 col-xs-7">
|
<div class="col-sm-9 col-xs-7">
|
||||||
<p><?=get_tfa()['pretty'];?></p>
|
<p id="tfa_pretty"><?=$tfa_data['pretty'];?></p>
|
||||||
|
<div id="tfa_additional">
|
||||||
|
<?php if($tfa_data['additional']):
|
||||||
|
foreach ($tfa_data['additional'] as $key_info): ?>
|
||||||
|
<form style="display:inline;" method="post">
|
||||||
|
<input type="hidden" name="unset_tfa_key" value="<?=$key_info['id'];?>" />
|
||||||
|
<div style="padding:4px;margin:4px" class="label label-<?=($_SESSION['tfa_id'] == $key_info['id']) ? 'success' : 'default'; ?>">
|
||||||
|
<?=$key_info['key_id'];?>
|
||||||
|
<a href="#" style="font-weight:bold;color:white" onClick="$(this).closest('form').submit()">[<?=strtolower($lang['admin']['remove']);?>]</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<?php endforeach;
|
||||||
|
endif;?>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3 col-xs-5 text-right"><?=$lang['tfa']['set_tfa'];?>:</div>
|
<div class="col-sm-3 col-xs-5 text-right"><?=$lang['tfa']['set_tfa'];?>:</div>
|
||||||
<div class="col-md-9 col-xs-7">
|
<div class="col-sm-9 col-xs-7">
|
||||||
<select data-width="auto" id="selectTFA" class="selectpicker" title="<?=$lang['tfa']['select'];?>">
|
<select data-width="auto" id="selectTFA" class="selectpicker" title="<?=$lang['tfa']['select'];?>">
|
||||||
<option value="yubi_otp"><?=$lang['tfa']['yubi_otp'];?></option>
|
<option value="yubi_otp"><?=$lang['tfa']['yubi_otp'];?></option>
|
||||||
<option value="u2f"><?=$lang['tfa']['u2f'];?></option>
|
<option value="u2f"><?=$lang['tfa']['u2f'];?></option>
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
<?php
|
|
||||||
require_once 'inc/vars.inc.php';
|
require_once 'inc/vars.inc.php';
|
||||||
|
|
||||||
ini_set('error_reporting', '0');
|
ini_set('error_reporting', '0');
|
||||||
$config = array(
|
$config = array(
|
||||||
'useEASforOutlook' => 'yes',
|
'useEASforOutlook' => 'yes',
|
||||||
|
@ -31,7 +29,7 @@ if ($config['useEASforOutlook'] == 'no') {
|
||||||
$config['autodiscoverType'] = 'imap';
|
$config['autodiscoverType'] = 'imap';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
require_once 'inc/functions.inc.php';
|
|
||||||
$dsn = "$database_type:host=$database_host;dbname=$database_name";
|
$dsn = "$database_type:host=$database_host;dbname=$database_name";
|
||||||
$opt = [
|
$opt = [
|
||||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -114,7 +114,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label><input type="checkbox" name="delete_tfa"> <?=$lang['tfa']['delete_tfa'];?></label>
|
<label><input type="checkbox" name="disable_tfa"> <?=$lang['tfa']['disable_tfa'];?></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -24,9 +24,9 @@ endif;
|
||||||
?>
|
?>
|
||||||
<div style="margin-bottom:100px"></div>
|
<div style="margin-bottom:100px"></div>
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script>
|
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script>
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.2/js/bootstrap-switch.min.js"></script>
|
<script src="/js/bootstrap-switch.min.js"></script>
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/7.0.2/bootstrap-slider.min.js"></script>
|
<script src="/js/bootstrap-slider.min.js"></script>
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.9.4/js/bootstrap-select.js"></script>
|
<script src="/js/bootstrap-select.min.js"></script>
|
||||||
<script src="/js/u2f-api.js"></script>
|
<script src="/js/u2f-api.js"></script>
|
||||||
<script>
|
<script>
|
||||||
// Select language and reopen active URL without POST
|
// Select language and reopen active URL without POST
|
||||||
|
@ -74,6 +74,7 @@ $(document).ready(function() {
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
// Set TFA modals
|
// Set TFA modals
|
||||||
|
|
||||||
$('#selectTFA').change(function () {
|
$('#selectTFA').change(function () {
|
||||||
if ($(this).val() == "yubi_otp") {
|
if ($(this).val() == "yubi_otp") {
|
||||||
$('#YubiOTPModal').modal('show');
|
$('#YubiOTPModal').modal('show');
|
||||||
|
|
|
@ -63,6 +63,7 @@ function hasMailboxObjectAccess($username, $role, $object) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
function init_db_schema() {
|
function init_db_schema() {
|
||||||
|
// This will be much better in future releases...
|
||||||
global $pdo;
|
global $pdo;
|
||||||
try {
|
try {
|
||||||
$stmt = $pdo->prepare("SELECT NULL FROM `admin`, `imapsync`, `tfa`");
|
$stmt = $pdo->prepare("SELECT NULL FROM `admin`, `imapsync`, `tfa`");
|
||||||
|
@ -101,7 +102,7 @@ function init_db_schema() {
|
||||||
$stmt = $pdo->query("SHOW COLUMNS FROM `mailbox` LIKE 'kind'");
|
$stmt = $pdo->query("SHOW COLUMNS FROM `mailbox` LIKE 'kind'");
|
||||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||||
if ($num_results == 0) {
|
if ($num_results == 0) {
|
||||||
$pdo->query("ALTER TABLE `mailbox` ADD `kind` varchar(100) NOT NULL DEFAULT ''");
|
$pdo->query("ALTER TABLE `mailbox` ADD `kind` VARCHAR(100) NOT NULL DEFAULT ''");
|
||||||
}
|
}
|
||||||
$stmt = $pdo->query("SHOW COLUMNS FROM `mailbox` LIKE 'multiple_bookings'");
|
$stmt = $pdo->query("SHOW COLUMNS FROM `mailbox` LIKE 'multiple_bookings'");
|
||||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||||
|
@ -113,6 +114,11 @@ function init_db_schema() {
|
||||||
if ($num_results == 0) {
|
if ($num_results == 0) {
|
||||||
$pdo->query("ALTER TABLE `mailbox` ADD `wants_tagged_subject` tinyint(1) NOT NULL DEFAULT '0'");
|
$pdo->query("ALTER TABLE `mailbox` ADD `wants_tagged_subject` tinyint(1) NOT NULL DEFAULT '0'");
|
||||||
}
|
}
|
||||||
|
$stmt = $pdo->query("SHOW COLUMNS FROM `tfa` LIKE 'key_id'");
|
||||||
|
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||||
|
if ($num_results == 0) {
|
||||||
|
$pdo->query("ALTER TABLE `tfa` ADD `key_id` VARCHAR(255) DEFAULT 'unidentified'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function verify_ssha256($hash, $password) {
|
function verify_ssha256($hash, $password) {
|
||||||
// Remove tag if any
|
// Remove tag if any
|
||||||
|
@ -198,6 +204,8 @@ function check_login($user, $pass) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
unset($_SESSION['ldelay']);
|
unset($_SESSION['ldelay']);
|
||||||
|
$stmt = $pdo->prepare("UPDATE `tfa` SET `active`='1' WHERE `username` = :user");
|
||||||
|
$stmt->execute(array(':user' => $user));
|
||||||
return "domainadmin";
|
return "domainadmin";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1806,6 +1814,10 @@ function set_tfa($postarray) {
|
||||||
|
|
||||||
switch ($postarray["tfa_method"]) {
|
switch ($postarray["tfa_method"]) {
|
||||||
case "yubi_otp":
|
case "yubi_otp":
|
||||||
|
(!isset($postarray["key_id"])) ? $key_id = 'unidentified' : $key_id = $postarray["key_id"];
|
||||||
|
$yubico_id = $postarray['yubico_id'];
|
||||||
|
$yubico_key = $postarray['yubico_key'];
|
||||||
|
$yubi = new Auth_Yubico($yubico_id, $yubico_key);
|
||||||
if (!$yubi) {
|
if (!$yubi) {
|
||||||
$_SESSION['return'] = array(
|
$_SESSION['return'] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
|
@ -1824,16 +1836,21 @@ function set_tfa($postarray) {
|
||||||
if (PEAR::isError($yauth)) {
|
if (PEAR::isError($yauth)) {
|
||||||
$_SESSION['return'] = array(
|
$_SESSION['return'] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'msg' => 'Yubico Authentication error: ' . $yauth->getMessage()
|
'msg' => 'Yubico API: ' . $yauth->getMessage()
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `authmech` = 'yubi_otp' AND `username` = :username");
|
// We could also do a modhex translation here
|
||||||
$stmt->execute(array(':username' => $username));
|
$yubico_modhex_id = substr($postarray["otp_token"], 0, 12);
|
||||||
$stmt = $pdo->prepare("INSERT INTO `tfa` (`username`, `authmech`, `active`) VALUES
|
$stmt = $pdo->prepare("DELETE FROM `tfa`
|
||||||
(:username, 'yubi_otp', 1)");
|
WHERE `username` = :username
|
||||||
$stmt->execute(array(':username' => $username));
|
AND (`authmech` != 'yubi_otp')
|
||||||
|
OR (`authmech` = 'yubi_otp' AND `secret` LIKE :modhex)");
|
||||||
|
$stmt->execute(array(':username' => $username, ':modhex' => '%' . $yubico_modhex_id));
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `tfa` (`key_id`, `username`, `authmech`, `active`, `secret`) VALUES
|
||||||
|
(:key_id, :username, 'yubi_otp', '1', :secret)");
|
||||||
|
$stmt->execute(array(':key_id' => $key_id, ':username' => $username, ':secret' => $yubico_id . ':' . $yubico_key . ':' . $yubico_modhex_id));
|
||||||
}
|
}
|
||||||
catch (PDOException $e) {
|
catch (PDOException $e) {
|
||||||
$_SESSION['return'] = array(
|
$_SESSION['return'] = array(
|
||||||
|
@ -1850,9 +1867,12 @@ function set_tfa($postarray) {
|
||||||
|
|
||||||
case "u2f":
|
case "u2f":
|
||||||
try {
|
try {
|
||||||
|
(!isset($postarray["key_id"])) ? $key_id = 'unidentified' : $key_id = $postarray["key_id"];
|
||||||
$reg = $u2f->doRegister(json_decode($_SESSION['regReq']), json_decode($postarray['token']));
|
$reg = $u2f->doRegister(json_decode($_SESSION['regReq']), json_decode($postarray['token']));
|
||||||
$stmt = $pdo->prepare("INSERT INTO `tfa` (`username`, `authmech`, `keyHandle`, `publicKey`, `certificate`, `counter`) VALUES (?, 'u2f', ?, ?, ?, ?)");
|
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username AND `authmech` != 'u2f'");
|
||||||
$stmt->execute(array($username, $reg->keyHandle, $reg->publicKey, $reg->certificate, $reg->counter));
|
$stmt->execute(array(':username' => $username));
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `tfa` (`username`, `key_id`, `authmech`, `keyHandle`, `publicKey`, `certificate`, `counter`, `active`) VALUES (?, ?, 'u2f', ?, ?, ?, ?, '1')");
|
||||||
|
$stmt->execute(array($username, $key_id, $reg->keyHandle, $reg->publicKey, $reg->certificate, $reg->counter));
|
||||||
$_SESSION['return'] = array(
|
$_SESSION['return'] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
'msg' => sprintf($lang['success']['object_modified'], $username)
|
'msg' => sprintf($lang['success']['object_modified'], $username)
|
||||||
|
@ -1887,6 +1907,55 @@ function set_tfa($postarray) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function unset_tfa_key($postarray) {
|
||||||
|
// Can only unset own keys
|
||||||
|
// Needs at least one key left
|
||||||
|
global $pdo;
|
||||||
|
global $lang;
|
||||||
|
$id = intval($postarray['unset_tfa_key']);
|
||||||
|
if ($_SESSION['mailcow_cc_role'] != "domainadmin" &&
|
||||||
|
$_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => sprintf($lang['danger']['access_denied'])
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$username = $_SESSION['mailcow_cc_username'];
|
||||||
|
try {
|
||||||
|
if (!is_numeric($id)) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => sprintf($lang['danger']['access_denied'])
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$stmt = $pdo->prepare("SELECT COUNT(*) AS `keys` FROM `tfa`
|
||||||
|
WHERE `username` = :username AND `active` = '1'");
|
||||||
|
$stmt->execute(array(':username' => $username));
|
||||||
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
if ($row['keys'] == "1") {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => sprintf($lang['danger']['last_key'])
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username AND `id` = :id");
|
||||||
|
$stmt->execute(array(':username' => $username, ':id' => $id));
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'msg' => sprintf($lang['success']['object_modified'], $username)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (PDOException $e) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'MySQL: '.$e
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
function get_tfa($username = null) {
|
function get_tfa($username = null) {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
if (isset($_SESSION['mailcow_cc_username'])) {
|
if (isset($_SESSION['mailcow_cc_username'])) {
|
||||||
|
@ -1896,8 +1965,8 @@ function get_tfa($username = null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $pdo->prepare("SELECT `authmech` FROM `tfa`
|
$stmt = $pdo->prepare("SELECT * FROM `tfa`
|
||||||
WHERE `username` = :username");
|
WHERE `username` = :username AND `active` = '1'");
|
||||||
$stmt->execute(array(':username' => $username));
|
$stmt->execute(array(':username' => $username));
|
||||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
@ -1905,11 +1974,27 @@ function get_tfa($username = null) {
|
||||||
case "yubi_otp":
|
case "yubi_otp":
|
||||||
$data['name'] = "yubi_otp";
|
$data['name'] = "yubi_otp";
|
||||||
$data['pretty'] = "Yubico OTP";
|
$data['pretty'] = "Yubico OTP";
|
||||||
|
$stmt = $pdo->prepare("SELECT `id`, `key_id`, RIGHT(`secret`, 12) AS 'modhex' FROM `tfa` WHERE `authmech` = 'yubi_otp' AND `username` = :username");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':username' => $username,
|
||||||
|
));
|
||||||
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
while($row = array_shift($rows)) {
|
||||||
|
$data['additional'][] = $row;
|
||||||
|
}
|
||||||
return $data;
|
return $data;
|
||||||
break;
|
break;
|
||||||
case "u2f":
|
case "u2f":
|
||||||
$data['name'] = "u2f";
|
$data['name'] = "u2f";
|
||||||
$data['pretty'] = "Fido U2F";
|
$data['pretty'] = "Fido U2F";
|
||||||
|
$stmt = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = :username");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':username' => $username,
|
||||||
|
));
|
||||||
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
while($row = array_shift($rows)) {
|
||||||
|
$data['additional'][] = $row;
|
||||||
|
}
|
||||||
return $data;
|
return $data;
|
||||||
break;
|
break;
|
||||||
case "hotp":
|
case "hotp":
|
||||||
|
@ -1935,7 +2020,7 @@ function verify_tfa_login($username, $token) {
|
||||||
global $yubi;
|
global $yubi;
|
||||||
|
|
||||||
$stmt = $pdo->prepare("SELECT `authmech` FROM `tfa`
|
$stmt = $pdo->prepare("SELECT `authmech` FROM `tfa`
|
||||||
WHERE `username` = :username");
|
WHERE `username` = :username AND `active` = '1'");
|
||||||
$stmt->execute(array(':username' => $username));
|
$stmt->execute(array(':username' => $username));
|
||||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
@ -1944,6 +2029,16 @@ function verify_tfa_login($username, $token) {
|
||||||
if (!ctype_alnum($token) || strlen($token) != 44) {
|
if (!ctype_alnum($token) || strlen($token) != 44) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
$yubico_modhex_id = substr($token, 0, 12);
|
||||||
|
$stmt = $pdo->prepare("SELECT `id`, `secret` FROM `tfa`
|
||||||
|
WHERE `username` = :username
|
||||||
|
AND `authmech` = 'yubi_otp'
|
||||||
|
AND `active`='1'
|
||||||
|
AND `secret` LIKE :modhex");
|
||||||
|
$stmt->execute(array(':username' => $username, ':modhex' => '%' . $yubico_modhex_id));
|
||||||
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
$yubico_auth = explode(':', $row['secret']);
|
||||||
|
$yubi = new Auth_Yubico($yubico_auth[0], $yubico_auth[1]);
|
||||||
$yauth = $yubi->verify($token);
|
$yauth = $yubi->verify($token);
|
||||||
if (PEAR::isError($yauth)) {
|
if (PEAR::isError($yauth)) {
|
||||||
$_SESSION['return'] = array(
|
$_SESSION['return'] = array(
|
||||||
|
@ -1953,6 +2048,7 @@ function verify_tfa_login($username, $token) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
$_SESSION['tfa_id'] = $row['id'];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1963,6 +2059,7 @@ function verify_tfa_login($username, $token) {
|
||||||
$reg = $u2f->doAuthenticate(json_decode($_SESSION['authReq']), get_u2f_registrations($username), json_decode($token));
|
$reg = $u2f->doAuthenticate(json_decode($_SESSION['authReq']), get_u2f_registrations($username), json_decode($token));
|
||||||
$stmt = $pdo->prepare("UPDATE `tfa` SET `counter` = ? WHERE `id` = ?");
|
$stmt = $pdo->prepare("UPDATE `tfa` SET `counter` = ? WHERE `id` = ?");
|
||||||
$stmt->execute(array($reg->counter, $reg->id));
|
$stmt->execute(array($reg->counter, $reg->id));
|
||||||
|
$_SESSION['tfa_id'] = $reg->id;
|
||||||
$_SESSION['authReq'] = null;
|
$_SESSION['authReq'] = null;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2089,8 +2186,8 @@ function edit_domain_admin($postarray) {
|
||||||
':modified' => date('Y-m-d H:i:s'),
|
':modified' => date('Y-m-d H:i:s'),
|
||||||
':active' => $active
|
':active' => $active
|
||||||
));
|
));
|
||||||
if (isset($postarray['delete_tfa'])) {
|
if (isset($postarray['disable_tfa'])) {
|
||||||
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username");
|
$stmt = $pdo->prepare("UPDATE `tfa` SET `active` = '0' WHERE `username` = :username");
|
||||||
$stmt->execute(array(':username' => $username_now));
|
$stmt->execute(array(':username' => $username_now));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -2115,8 +2212,8 @@ function edit_domain_admin($postarray) {
|
||||||
':modified' => date('Y-m-d H:i:s'),
|
':modified' => date('Y-m-d H:i:s'),
|
||||||
':active' => $active
|
':active' => $active
|
||||||
));
|
));
|
||||||
if (isset($postarray['delete_tfa'])) {
|
if (isset($postarray['disable_tfa'])) {
|
||||||
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username");
|
$stmt = $pdo->prepare("UPDATE `tfa` SET `active` = '0' WHERE `username` = :username");
|
||||||
$stmt->execute(array(':username' => $username));
|
$stmt->execute(array(':username' => $username));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -4818,23 +4915,8 @@ function mailbox_get_sender_acl_handles($mailbox) {
|
||||||
}
|
}
|
||||||
function get_u2f_registrations($username) {
|
function get_u2f_registrations($username) {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
$sel = $pdo->prepare("SELECT * FROM `tfa` WHERE `username` = ?");
|
$sel = $pdo->prepare("SELECT * FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = ? AND `active` = '1'");
|
||||||
$sel->execute(array($username));
|
$sel->execute(array($username));
|
||||||
return $sel->fetchAll(PDO::FETCH_OBJ);
|
return $sel->fetchAll(PDO::FETCH_OBJ);
|
||||||
}
|
}
|
||||||
function add_u2f_registration($username, $reg) {
|
|
||||||
global $pdo;
|
|
||||||
global $lang;
|
|
||||||
$ins = $pdo->prepare("INSERT INTO `tfa` (`username`, `authmech`, `keyHandle`, `publicKey`, `certificate`, `counter`) VALUES (?, 'u2f', ?, ?, ?, ?)");
|
|
||||||
$ins->execute(array($username, $reg->keyHandle, $reg->publicKey, $reg->certificate, $reg->counter));
|
|
||||||
$_SESSION['return'] = array(
|
|
||||||
'type' => 'success',
|
|
||||||
'msg' => sprintf($lang['success']['object_modified'], $username)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
function edit_u2f_registration($reg) {
|
|
||||||
global $pdo;
|
|
||||||
$upd = $pdo->prepare("update tfa set counter = ? where id = ?");
|
|
||||||
$upd->execute(array($reg->counter, $reg->id));
|
|
||||||
}
|
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -12,9 +12,9 @@
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.0/jquery.min.js" integrity="sha384-XxcvoeNF5V0ZfksTnV+bejnCsJjOOIzN6UVwF85WBsAnU3zeYh5bloN+L4WLgeNE" crossorigin="anonymous"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.0/jquery.min.js" integrity="sha384-XxcvoeNF5V0ZfksTnV+bejnCsJjOOIzN6UVwF85WBsAnU3zeYh5bloN+L4WLgeNE" crossorigin="anonymous"></script>
|
||||||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css">
|
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css">
|
||||||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootswatch/3.3.6/<?=strtolower(trim($DEFAULT_THEME));?>/bootstrap.min.css">
|
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootswatch/3.3.6/<?=strtolower(trim($DEFAULT_THEME));?>/bootstrap.min.css">
|
||||||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.9.4/css/bootstrap-select.min.css">
|
<link rel="stylesheet" href="/css/bootstrap-select.min.css">
|
||||||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/7.0.2/css/bootstrap-slider.min.css">
|
<link rel="stylesheet" href="/css/bootstrap-slider.min.css">
|
||||||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.2/css/bootstrap3/bootstrap-switch.min.css">
|
<link rel="stylesheet" href="/css/bootstrap-switch.min.css">
|
||||||
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Source+Sans+Pro:400,600,700&subset=latin,latin-ext">
|
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Source+Sans+Pro:400,600,700&subset=latin,latin-ext">
|
||||||
<link rel="stylesheet" href="/inc/languages.min.css">
|
<link rel="stylesheet" href="/inc/languages.min.css">
|
||||||
<link rel="stylesheet" href="/css/mailcow.css">
|
<link rel="stylesheet" href="/css/mailcow.css">
|
||||||
|
@ -45,6 +45,7 @@
|
||||||
<ul class="dropdown-menu" role="menu">
|
<ul class="dropdown-menu" role="menu">
|
||||||
<li <?=($_SESSION['mailcow_locale'] == 'de') ? 'class="active"' : ''?>> <a href="?<?= http_build_query(array_merge($_GET, array("lang" => "de"))) ?>"><span class="lang-xs lang-lbl-full" lang="de"></span></a></li>
|
<li <?=($_SESSION['mailcow_locale'] == 'de') ? 'class="active"' : ''?>> <a href="?<?= http_build_query(array_merge($_GET, array("lang" => "de"))) ?>"><span class="lang-xs lang-lbl-full" lang="de"></span></a></li>
|
||||||
<li <?=($_SESSION['mailcow_locale'] == 'en') ? 'class="active"' : ''?>> <a href="?<?= http_build_query(array_merge($_GET, array("lang" => "en"))) ?>"><span class="lang-xs lang-lbl-full" lang="en"></span></a></li>
|
<li <?=($_SESSION['mailcow_locale'] == 'en') ? 'class="active"' : ''?>> <a href="?<?= http_build_query(array_merge($_GET, array("lang" => "en"))) ?>"><span class="lang-xs lang-lbl-full" lang="en"></span></a></li>
|
||||||
|
<li <?=($_SESSION['mailcow_locale'] == 'es') ? 'class="active"' : ''?>> <a href="?<?= http_build_query(array_merge($_GET, array("lang" => "es"))) ?>"><span class="lang-xs lang-lbl-full" lang="es"></span></a></li>
|
||||||
<li <?=($_SESSION['mailcow_locale'] == 'nl') ? 'class="active"' : ''?>> <a href="?<?= http_build_query(array_merge($_GET, array("lang" => "nl"))) ?>"><span class="lang-xs lang-lbl-full" lang="nl"></span></a></li>
|
<li <?=($_SESSION['mailcow_locale'] == 'nl') ? 'class="active"' : ''?>> <a href="?<?= http_build_query(array_merge($_GET, array("lang" => "nl"))) ?>"><span class="lang-xs lang-lbl-full" lang="nl"></span></a></li>
|
||||||
<li <?=($_SESSION['mailcow_locale'] == 'pt') ? 'class="active"' : ''?>> <a href="?<?= http_build_query(array_merge($_GET, array("lang" => "pt"))) ?>"><span class="lang-xs lang-lbl-full" lang="pt"></span></a></li>
|
<li <?=($_SESSION['mailcow_locale'] == 'pt') ? 'class="active"' : ''?>> <a href="?<?= http_build_query(array_merge($_GET, array("lang" => "pt"))) ?>"><span class="lang-xs lang-lbl-full" lang="pt"></span></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -22,10 +22,8 @@ if (file_exists('./inc/vars.local.inc.php')) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yubi OTP API
|
// Yubi OTP API
|
||||||
if (!empty($YUBI_API['ID']) && !empty($YUBI_API['KEY'])) {
|
|
||||||
require_once 'inc/lib/Yubico.php';
|
require_once 'inc/lib/Yubico.php';
|
||||||
$yubi = new Auth_Yubico($YUBI_API['ID'], $YUBI_API['KEY']);
|
|
||||||
}
|
|
||||||
// U2F API
|
// U2F API
|
||||||
require_once 'inc/lib/U2F.php';
|
require_once 'inc/lib/U2F.php';
|
||||||
$scheme = isset($_SERVER['HTTPS']) ? "https://" : "http://";
|
$scheme = isset($_SERVER['HTTPS']) ? "https://" : "http://";
|
||||||
|
@ -59,6 +57,10 @@ if (isset($_COOKIE['language'])) {
|
||||||
$_SESSION['mailcow_locale'] = 'en';
|
$_SESSION['mailcow_locale'] = 'en';
|
||||||
setcookie('language', 'en');
|
setcookie('language', 'en');
|
||||||
break;
|
break;
|
||||||
|
case "es":
|
||||||
|
$_SESSION['mailcow_locale'] = 'es';
|
||||||
|
setcookie('language', 'es');
|
||||||
|
break;
|
||||||
case "nl":
|
case "nl":
|
||||||
$_SESSION['mailcow_locale'] = 'nl';
|
$_SESSION['mailcow_locale'] = 'nl';
|
||||||
setcookie('language', 'nl');
|
setcookie('language', 'nl');
|
||||||
|
@ -79,6 +81,10 @@ if (isset($_GET['lang'])) {
|
||||||
$_SESSION['mailcow_locale'] = 'en';
|
$_SESSION['mailcow_locale'] = 'en';
|
||||||
setcookie('language', 'en');
|
setcookie('language', 'en');
|
||||||
break;
|
break;
|
||||||
|
case "es":
|
||||||
|
$_SESSION['mailcow_locale'] = 'es';
|
||||||
|
setcookie('language', 'es');
|
||||||
|
break;
|
||||||
case "nl":
|
case "nl":
|
||||||
$_SESSION['mailcow_locale'] = 'nl';
|
$_SESSION['mailcow_locale'] = 'nl';
|
||||||
setcookie('language', 'nl');
|
setcookie('language', 'nl');
|
||||||
|
|
|
@ -4,6 +4,18 @@
|
||||||
<div class="modal-header"><b><?=$lang['tfa']['yubi_otp'];?></b></div>
|
<div class="modal-header"><b><?=$lang['tfa']['yubi_otp'];?></b></div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<form role="form" method="post">
|
<form role="form" method="post">
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="text" class="form-control" name="key_id" id="key_id" placeholder="<?=$lang['tfa']['key_id'];?>" autocomplete="off" required>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<p class="help-block"><?=$lang['tfa']['api_register'];?></p>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="text" class="form-control" name="yubico_id" id="yubico_id" placeholder="Yubico API ID" autocomplete="off" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="text" class="form-control" name="yubico_key" id="yubico_key" placeholder="Yubico API Key" autocomplete="off" required>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="password" class="form-control" name="confirm_password" id="confirm_password" placeholder="<?=$lang['user']['password_now'];?>" autocomplete="off" required>
|
<input type="password" class="form-control" name="confirm_password" id="confirm_password" placeholder="<?=$lang['user']['password_now'];?>" autocomplete="off" required>
|
||||||
</div>
|
</div>
|
||||||
|
@ -27,6 +39,9 @@
|
||||||
<div class="modal-header"><b><?=$lang['tfa']['u2f'];?></b></div>
|
<div class="modal-header"><b><?=$lang['tfa']['u2f'];?></b></div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<form role="form" method="post" id="u2f_reg_form">
|
<form role="form" method="post" id="u2f_reg_form">
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="text" class="form-control" name="key_id" id="key_id" placeholder="<?=$lang['tfa']['key_id'];?>" autocomplete="off" required>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="password" class="form-control" name="confirm_password" id="confirm_password" placeholder="<?=$lang['user']['password_now'];?>" autocomplete="off" required>
|
<input type="password" class="form-control" name="confirm_password" id="confirm_password" placeholder="<?=$lang['user']['password_now'];?>" autocomplete="off" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -115,6 +115,9 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||||
if (isset($_POST["set_tfa"])) {
|
if (isset($_POST["set_tfa"])) {
|
||||||
set_tfa($_POST);
|
set_tfa($_POST);
|
||||||
}
|
}
|
||||||
|
if (isset($_POST["unset_tfa_key"])) {
|
||||||
|
unset_tfa_key($_POST);
|
||||||
|
}
|
||||||
if (isset($_POST["add_policy_list_item"])) {
|
if (isset($_POST["add_policy_list_item"])) {
|
||||||
add_policy_list_item($_POST);
|
add_policy_list_item($_POST);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,8 +35,4 @@ $DEFAULT_LANG = "en";
|
||||||
// See https://bootswatch.com/
|
// See https://bootswatch.com/
|
||||||
$DEFAULT_THEME = "lumen";
|
$DEFAULT_THEME = "lumen";
|
||||||
|
|
||||||
// If you want to use Yubico TFA methods, setup an ID and a key here: https://upgrade.yubico.com/getapikey/
|
|
||||||
// Remember to override this value using vars.local.inc.php, do not change it here.
|
|
||||||
$YUBI_API['ID'] = "";
|
|
||||||
$YUBI_API['KEY'] = "";
|
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -48,6 +48,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li <?=($_SESSION['mailcow_locale'] == 'de') ? 'class="active"' : ''?>><a href="?<?= http_build_query(array_merge($_GET, array("lang" => "de"))) ?>"><span class="lang-xs lang-lbl-full" lang="de"></span></a></li>
|
<li <?=($_SESSION['mailcow_locale'] == 'de') ? 'class="active"' : ''?>><a href="?<?= http_build_query(array_merge($_GET, array("lang" => "de"))) ?>"><span class="lang-xs lang-lbl-full" lang="de"></span></a></li>
|
||||||
<li <?=($_SESSION['mailcow_locale'] == 'en') ? 'class="active"' : ''?>><a href="?<?= http_build_query(array_merge($_GET, array("lang" => "en"))) ?>"><span class="lang-xs lang-lbl-full" lang="en"></span></a></li>
|
<li <?=($_SESSION['mailcow_locale'] == 'en') ? 'class="active"' : ''?>><a href="?<?= http_build_query(array_merge($_GET, array("lang" => "en"))) ?>"><span class="lang-xs lang-lbl-full" lang="en"></span></a></li>
|
||||||
|
<li <?=($_SESSION['mailcow_locale'] == 'es') ? 'class="active"' : ''?>><a href="?<?= http_build_query(array_merge($_GET, array("lang" => "es"))) ?>"><span class="lang-xs lang-lbl-full" lang="es"></span></a></li>
|
||||||
<li <?=($_SESSION['mailcow_locale'] == 'nl') ? 'class="active"' : ''?>><a href="?<?= http_build_query(array_merge($_GET, array("lang" => "nl"))) ?>"><span class="lang-xs lang-lbl-full" lang="nl"></span></a></li>
|
<li <?=($_SESSION['mailcow_locale'] == 'nl') ? 'class="active"' : ''?>><a href="?<?= http_build_query(array_merge($_GET, array("lang" => "nl"))) ?>"><span class="lang-xs lang-lbl-full" lang="nl"></span></a></li>
|
||||||
<li <?=($_SESSION['mailcow_locale'] == 'pt') ? 'class="active"' : ''?>><a href="?<?= http_build_query(array_merge($_GET, array("lang" => "pt"))) ?>"><span class="lang-xs lang-lbl-full" lang="pt"></span></a></li>
|
<li <?=($_SESSION['mailcow_locale'] == 'pt') ? 'class="active"' : ''?>><a href="?<?= http_build_query(array_merge($_GET, array("lang" => "pt"))) ?>"><span class="lang-xs lang-lbl-full" lang="pt"></span></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -29,6 +29,7 @@ $lang['danger']['policy_list_from_exists'] = 'Ein Eintrag mit diesem Wert existi
|
||||||
$lang['danger']['policy_list_from_invalid'] = 'Eintrag hat ungültiges Format';
|
$lang['danger']['policy_list_from_invalid'] = 'Eintrag hat ungültiges Format';
|
||||||
$lang['danger']['alias_invalid'] = 'Alias-Adrese ist ungültig';
|
$lang['danger']['alias_invalid'] = 'Alias-Adrese ist ungültig';
|
||||||
$lang['danger']['goto_invalid'] = 'Ziel-Adrese ist ungültig';
|
$lang['danger']['goto_invalid'] = 'Ziel-Adrese ist ungültig';
|
||||||
|
$lang['danger']['last_key'] = 'Letzter Key kann nicht gelöscht werden';
|
||||||
$lang['danger']['alias_domain_invalid'] = 'Alias-Domain ist ungültig';
|
$lang['danger']['alias_domain_invalid'] = 'Alias-Domain ist ungültig';
|
||||||
$lang['danger']['target_domain_invalid'] = 'Ziel-Domain ist ungültig';
|
$lang['danger']['target_domain_invalid'] = 'Ziel-Domain ist ungültig';
|
||||||
$lang['danger']['object_exists'] = 'Objekt %s existiert bereits';
|
$lang['danger']['object_exists'] = 'Objekt %s existiert bereits';
|
||||||
|
@ -374,11 +375,14 @@ $lang['login']['delayed'] = 'Login wurde zur Sicherheit um %s Sekunde/n verzöge
|
||||||
$lang['tfa']['tfa'] = "Two-Factor Authentication";
|
$lang['tfa']['tfa'] = "Two-Factor Authentication";
|
||||||
$lang['tfa']['set_tfa'] = "Konfiguriere Two-Factor Authentication Methode";
|
$lang['tfa']['set_tfa'] = "Konfiguriere Two-Factor Authentication Methode";
|
||||||
$lang['tfa']['yubi_otp'] = "Yubico OTP Authentifizierung";
|
$lang['tfa']['yubi_otp'] = "Yubico OTP Authentifizierung";
|
||||||
|
$lang['tfa']['key_id'] = "Ein Name für diesen YubiKey";
|
||||||
|
$lang['tfa']['api_register'] = 'mailcow verwendet die Yubico Cloud API. Ein API-Key für den Yubico Stick kann <a href="https://upgrade.yubico.com/getapikey/" target="_blank">hier</a> bezogen werden.';
|
||||||
$lang['tfa']['u2f'] = "U2F Authentifizierung";
|
$lang['tfa']['u2f'] = "U2F Authentifizierung";
|
||||||
$lang['tfa']['hotp'] = "HOTP Authentifizierung";
|
$lang['tfa']['hotp'] = "HOTP Authentifizierung";
|
||||||
$lang['tfa']['totp'] = "TOTP Authentifizierung";
|
$lang['tfa']['totp'] = "TOTP Authentifizierung";
|
||||||
$lang['tfa']['none'] = "Deaktiviert";
|
$lang['tfa']['none'] = "Deaktiviert";
|
||||||
$lang['tfa']['delete_tfa'] = "Deaktiviere TFA";
|
$lang['tfa']['delete_tfa'] = "Deaktiviere TFA";
|
||||||
|
$lang['tfa']['disable_tfa'] = "Deaktiviere TFA bis zur nächsten erfolgreichen Anmeldung";
|
||||||
$lang['tfa']['confirm_tfa'] = "Please confirm your one-time password in the below field";
|
$lang['tfa']['confirm_tfa'] = "Please confirm your one-time password in the below field";
|
||||||
$lang['tfa']['confirm'] = "Bestätigen";
|
$lang['tfa']['confirm'] = "Bestätigen";
|
||||||
$lang['tfa']['otp'] = "Einmalpasswort";
|
$lang['tfa']['otp'] = "Einmalpasswort";
|
||||||
|
|
|
@ -24,6 +24,7 @@ $lang['danger']['mailbox_quota_exceeds_domain_quota'] = "Max. quota exceeds doma
|
||||||
$lang['danger']['object_is_not_numeric'] = "Value %s is not numeric";
|
$lang['danger']['object_is_not_numeric'] = "Value %s is not numeric";
|
||||||
$lang['success']['domain_added'] = "Added domain %s";
|
$lang['success']['domain_added'] = "Added domain %s";
|
||||||
$lang['danger']['alias_empty'] = "Alias address must not be empty";
|
$lang['danger']['alias_empty'] = "Alias address must not be empty";
|
||||||
|
$lang['danger']['last_key'] = 'Last key cannot be deleted';
|
||||||
$lang['danger']['goto_empty'] = "Goto address must not be empty";
|
$lang['danger']['goto_empty'] = "Goto address must not be empty";
|
||||||
$lang['danger']['policy_list_from_exists'] = "A record with given name exists";
|
$lang['danger']['policy_list_from_exists'] = "A record with given name exists";
|
||||||
$lang['danger']['policy_list_from_invalid'] = "Record has invalid format";
|
$lang['danger']['policy_list_from_invalid'] = "Record has invalid format";
|
||||||
|
@ -377,11 +378,14 @@ $lang['login']['delayed'] = 'Login was delayed by %s seconds.';
|
||||||
$lang['tfa']['tfa'] = "Two-factor authentication";
|
$lang['tfa']['tfa'] = "Two-factor authentication";
|
||||||
$lang['tfa']['set_tfa'] = "Set two-factor authentication method";
|
$lang['tfa']['set_tfa'] = "Set two-factor authentication method";
|
||||||
$lang['tfa']['yubi_otp'] = "Yubico OTP authentication";
|
$lang['tfa']['yubi_otp'] = "Yubico OTP authentication";
|
||||||
|
$lang['tfa']['key_id'] = "An identifier for your YubiKey";
|
||||||
|
$lang['tfa']['api_register'] = 'mailcow uses the Yubico Cloud API. Please get an API key for your key <a href="https://upgrade.yubico.com/getapikey/" target="_blank">here</a>';
|
||||||
$lang['tfa']['u2f'] = "U2F authentication";
|
$lang['tfa']['u2f'] = "U2F authentication";
|
||||||
$lang['tfa']['hotp'] = "HOTP authentication";
|
$lang['tfa']['hotp'] = "HOTP authentication";
|
||||||
$lang['tfa']['totp'] = "TOTP authentication";
|
$lang['tfa']['totp'] = "TOTP authentication";
|
||||||
$lang['tfa']['none'] = "Deaktiviert";
|
$lang['tfa']['none'] = "Deaktiviert";
|
||||||
$lang['tfa']['delete_tfa'] = "Disable TFA";
|
$lang['tfa']['delete_tfa'] = "Disable TFA";
|
||||||
|
$lang['tfa']['disable_tfa'] = "Disable TFA until next successful login";
|
||||||
$lang['tfa']['confirm_tfa'] = "Please confirm your one-time password in the below field";
|
$lang['tfa']['confirm_tfa'] = "Please confirm your one-time password in the below field";
|
||||||
$lang['tfa']['confirm'] = "Confirm";
|
$lang['tfa']['confirm'] = "Confirm";
|
||||||
$lang['tfa']['otp'] = "One-time password";
|
$lang['tfa']['otp'] = "One-time password";
|
||||||
|
|
|
@ -8,6 +8,7 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'doma
|
||||||
|
|
||||||
require_once("inc/header.inc.php");
|
require_once("inc/header.inc.php");
|
||||||
$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
||||||
|
$tfa_data = get_tfa();
|
||||||
$username = $_SESSION['mailcow_cc_username'];
|
$username = $_SESSION['mailcow_cc_username'];
|
||||||
?>
|
?>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
@ -23,8 +24,19 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'doma
|
||||||
<hr>
|
<hr>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3 col-xs-5 text-right"><?=$lang['tfa']['tfa'];?></div>
|
<div class="col-md-3 col-xs-5 text-right"><?=$lang['tfa']['tfa'];?></div>
|
||||||
<div class="col-md-9 col-xs-7">
|
<div class="col-sm-9 col-xs-7">
|
||||||
<p><?=get_tfa()['pretty'];?></p>
|
<p id="tfa_pretty"><?=$tfa_data['pretty'];?></p>
|
||||||
|
<div id="tfa_additional">
|
||||||
|
<?php if($tfa_data['additional']):
|
||||||
|
foreach ($tfa_data['additional'] as $key_info): ?>
|
||||||
|
<form style="display:inline;" method="post">
|
||||||
|
<input type="hidden" name="unset_tfa_key" value="<?=$key_info['id'];?>" />
|
||||||
|
<div class="label label-default">🔑 <?=$key_info['key_id'];?> <a href="#" style="font-weight:bold;color:white" onClick="$(this).closest('form').submit()">[<?=strtolower($lang['admin']['remove']);?>]</a></div>
|
||||||
|
</form>
|
||||||
|
<?php endforeach;
|
||||||
|
endif;?>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -32,6 +44,7 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'doma
|
||||||
<div class="col-md-9 col-xs-7">
|
<div class="col-md-9 col-xs-7">
|
||||||
<select id="selectTFA" class="selectpicker" title="<?=$lang['tfa']['select'];?>">
|
<select id="selectTFA" class="selectpicker" title="<?=$lang['tfa']['select'];?>">
|
||||||
<option value="yubi_otp"><?=$lang['tfa']['yubi_otp'];?></option>
|
<option value="yubi_otp"><?=$lang['tfa']['yubi_otp'];?></option>
|
||||||
|
<option value="u2f"><?=$lang['tfa']['u2f'];?></option>
|
||||||
<option value="none"><?=$lang['tfa']['none'];?></option>
|
<option value="none"><?=$lang['tfa']['none'];?></option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,6 +3,9 @@ version: '2.1'
|
||||||
services:
|
services:
|
||||||
pdns-mailcow:
|
pdns-mailcow:
|
||||||
image: andryyy/mailcow-dockerized:pdns
|
image: andryyy/mailcow-dockerized:pdns
|
||||||
|
depends_on:
|
||||||
|
mysql-mailcow:
|
||||||
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/conf/pdns/:/etc/powerdns/
|
- ./data/conf/pdns/:/etc/powerdns/
|
||||||
restart: always
|
restart: always
|
||||||
|
@ -14,9 +17,11 @@ services:
|
||||||
|
|
||||||
mysql-mailcow:
|
mysql-mailcow:
|
||||||
image: mariadb:10.1
|
image: mariadb:10.1
|
||||||
depends_on:
|
healthcheck:
|
||||||
- pdns-mailcow
|
test: ["CMD", "mysqladmin", "ping", "--host", "localhost", "--silent"]
|
||||||
command: mysqld
|
interval: 10s
|
||||||
|
timeout: 30s
|
||||||
|
retries: 5
|
||||||
volumes:
|
volumes:
|
||||||
- mysql-vol-1:/var/lib/mysql/
|
- mysql-vol-1:/var/lib/mysql/
|
||||||
- ./data/conf/mysql/:/etc/mysql/conf.d/:ro
|
- ./data/conf/mysql/:/etc/mysql/conf.d/:ro
|
||||||
|
@ -52,7 +57,7 @@ services:
|
||||||
rspamd-mailcow:
|
rspamd-mailcow:
|
||||||
image: andryyy/mailcow-dockerized:rspamd
|
image: andryyy/mailcow-dockerized:rspamd
|
||||||
depends_on:
|
depends_on:
|
||||||
- pdns-mailcow
|
- nginx-mailcow
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/conf/rspamd/override.d/:/etc/rspamd/override.d:ro
|
- ./data/conf/rspamd/override.d/:/etc/rspamd/override.d:ro
|
||||||
- ./data/conf/rspamd/local.d/:/etc/rspamd/local.d:ro
|
- ./data/conf/rspamd/local.d/:/etc/rspamd/local.d:ro
|
||||||
|
@ -65,6 +70,7 @@ services:
|
||||||
dns_search: mailcow-network
|
dns_search: mailcow-network
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
|
ipv4_address: 172.22.1.253
|
||||||
aliases:
|
aliases:
|
||||||
- rspamd
|
- rspamd
|
||||||
|
|
||||||
|
@ -95,7 +101,6 @@ services:
|
||||||
image: andryyy/mailcow-dockerized:sogo
|
image: andryyy/mailcow-dockerized:sogo
|
||||||
depends_on:
|
depends_on:
|
||||||
- pdns-mailcow
|
- pdns-mailcow
|
||||||
- mysql-mailcow
|
|
||||||
environment:
|
environment:
|
||||||
- DBNAME=${DBNAME}
|
- DBNAME=${DBNAME}
|
||||||
- DBUSER=${DBUSER}
|
- DBUSER=${DBUSER}
|
||||||
|
@ -110,6 +115,7 @@ services:
|
||||||
restart: always
|
restart: always
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
|
ipv4_address: 172.22.1.252
|
||||||
aliases:
|
aliases:
|
||||||
- sogo
|
- sogo
|
||||||
|
|
||||||
|
@ -197,10 +203,8 @@ services:
|
||||||
|
|
||||||
nginx-mailcow:
|
nginx-mailcow:
|
||||||
depends_on:
|
depends_on:
|
||||||
- mysql-mailcow
|
|
||||||
- sogo-mailcow
|
- sogo-mailcow
|
||||||
- php-fpm-mailcow
|
- php-fpm-mailcow
|
||||||
- rspamd-mailcow
|
|
||||||
image: nginx:mainline
|
image: nginx:mainline
|
||||||
command: /bin/bash -c "envsubst < /etc/nginx/conf.d/listen.template > /etc/nginx/conf.d/listen.active && nginx -g 'daemon off;'"
|
command: /bin/bash -c "envsubst < /etc/nginx/conf.d/listen.template > /etc/nginx/conf.d/listen.active && nginx -g 'daemon off;'"
|
||||||
environment:
|
environment:
|
||||||
|
|
Loading…
Reference in New Issue