public
nobgit
read
NobMail
Based on mailcow: dockerized
Languages
Repository composition by tracked source files.
PHP
49%
JavaScript
35%
HTML
9%
CSS
4%
Shell
2%
Python
1%
Lua
0%
Perl
0%
Ruby
0%
SCSS
0%
Create file
Wiki Documentation
Clone
https://nobgit.com/orgs/nobgit/nobmail.git
ssh://[email protected]:2222/orgs/nobgit/nobmail.git
Commit
[Web] Feature: TLS policy maps [Web] Avoid php extensions in links [Web] Minor fixes
f5799faf
data/web/edit.php | 65 +++++-
data/web/inc/functions.address_rewriting.inc.php | 198 ++++++------------
data/web/inc/functions.tls_policy_maps.inc.php | 157 ++++++++++++++
data/web/inc/header.inc.php | 250 +++++++++++------------
data/web/inc/init_db.inc.php | 22 +-
data/web/inc/prerequisites.inc.php | 1 +
data/web/index.php | 6 +-
data/web/js/admin.js | 4 +-
data/web/js/mailbox.js | 91 ++++++++-
data/web/js/user.js | 2 +-
data/web/json_api.php | 34 +++
data/web/lang/lang.de.php | 27 ++-
data/web/lang/lang.en.php | 22 +-
data/web/mailbox.php | 29 +++
data/web/modals/mailbox.php | 56 +++++
data/web/user.php | 2 +-
16 files changed, 682 insertions(+), 284 deletions(-)
create mode 100644 data/web/inc/functions.tls_policy_maps.inc.php
Diff
diff --git a/data/web/edit.php b/data/web/edit.php
index a2eb4fb7..d97b0ffa 100644
--- a/data/web/edit.php
+++ b/data/web/edit.php
@@ -731,7 +731,9 @@ if (isset($_SESSION['mailcow_cc_role'])) {
<?php
}
}
- elseif (isset($_GET['recipient_map']) && !empty($_GET["recipient_map"])) {
+ elseif (isset($_GET['recipient_map']) &&
+ !empty($_GET["recipient_map"]) &&
+ $_SESSION['mailcow_cc_role'] == "admin") {
$map = intval($_GET["recipient_map"]);
$result = recipient_map('details', $map);
if (substr($result['recipient_map_old'], 0, 1) == '@') {
@@ -778,6 +780,67 @@ if (isset($_SESSION['mailcow_cc_role'])) {
<?php
}
}
+ elseif (isset($_GET['tls_policy_map']) &&
+ !empty($_GET["tls_policy_map"]) &&
+ $_SESSION['mailcow_cc_role'] == "admin") {
+ $map = intval($_GET["tls_policy_map"]);
+ $result = tls_policy_maps('details', $map);
+ if (!empty($result)) {
+ ?>
+ <h4><?=$lang['mailbox']['tls_policy_maps']?>: <?=$result['dest'];?></h4>
+ <br />
+ <form class="form-horizontal" data-id="edit_tls_policy_maps" role="form" method="post">
+ <input type="hidden" value="0" name="active">
+ <div class="form-group">
+ <label class="control-label col-sm-2" for="dest"><?=$lang['mailbox']['tls_map_dest'];?></label>
+ <div class="col-sm-10">
+ <input value="<?=$result['dest'];?>" type="text" class="form-control" name="dest" id="dest">
+ <small><?=$lang['mailbox']['tls_map_dest_info'];?></small>
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="control-label col-sm-2" for="policy"><?=$lang['mailbox']['tls_map_policy'];?></label>
+ <div class="col-sm-10">
+ <select class="full-width-select" name="policy" required>
+ <option value="none" <?=($result['policy'] != 'none') ?: 'selected';?>>none</option>
+ <option value="may" <?=($result['policy'] != 'may') ?: 'selected';?>>may</option>
+ <option value="encrypt" <?=($result['policy'] != 'encrypt') ?: 'selected';?>>encrypt</option>
+ <option value="dane" <?=($result['policy'] != 'dane') ?: 'selected';?>>dane-only</option>
+ <option value="dane-only" <?=($result['policy'] != 'dane-only') ?: 'selected';?>>dane-only</option>
+ <option value="fingerprint" <?=($result['policy'] != 'fingerprint') ?: 'selected';?>>fingerprint</option>
+ <option value="verify" <?=($result['policy'] != 'verify') ?: 'selected';?>>verify</option>
+ <option value="secure" <?=($result['policy'] != 'secure') ?: 'selected';?>>secure</option>
+ </select>
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="control-label col-sm-2" for="parameters"><?=$lang['mailbox']['tls_map_parameters'];?></label>
+ <div class="col-sm-10">
+ <input value="<?=$result['parameters'];?>" type="text" class="form-control" name="parameters" id="parameters">
+ <small><?=$lang['mailbox']['tls_map_parameters_info'];?></small>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-offset-2 col-sm-10">
+ <div class="checkbox">
+ <label><input type="checkbox" value="1" name="active" <?php if (isset($result['active_int']) && $result['active_int']=="1") { echo "checked"; }; ?>> <?=$lang['edit']['active'];?></label>
+ </div>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-offset-2 col-sm-10">
+ <button class="btn btn-success" data-action="edit_selected" data-id="edit_tls_policy_maps" data-item="<?=$map;?>" data-api-url='edit/tls-policy-map' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
+ </div>
+ </div>
+ </form>
+ <?php
+ }
+ else {
+ ?>
+ <div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
+ <?php
+ }
+ }
}
if ($_SESSION['mailcow_cc_role'] == "admin" || $_SESSION['mailcow_cc_role'] == "domainadmin" || $_SESSION['mailcow_cc_role'] == "user") {
if (isset($_GET['syncjob']) &&
diff --git a/data/web/inc/functions.address_rewriting.inc.php b/data/web/inc/functions.address_rewriting.inc.php
index 994429f2..bbf36c42 100644
--- a/data/web/inc/functions.address_rewriting.inc.php
+++ b/data/web/inc/functions.address_rewriting.inc.php
@@ -87,25 +87,15 @@ function bcc($_action, $_data = null, $attr = null) {
);
return false;
}
- try {
- $stmt = $pdo->prepare("INSERT INTO `bcc_maps` (`local_dest`, `bcc_dest`, `domain`, `active`, `type`) VALUES
- (:local_dest, :bcc_dest, :domain, :active, :type)");
- $stmt->execute(array(
- ':local_dest' => $local_dest_sane,
- ':bcc_dest' => $bcc_dest,
- ':domain' => $domain,
- ':active' => $active,
- ':type' => $type
- ));
- }
- catch (PDOException $e) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
- 'msg' => array('mysql_error', $e)
- );
- return false;
- }
+ $stmt = $pdo->prepare("INSERT INTO `bcc_maps` (`local_dest`, `bcc_dest`, `domain`, `active`, `type`) VALUES
+ (:local_dest, :bcc_dest, :domain, :active, :type)");
+ $stmt->execute(array(
+ ':local_dest' => $local_dest_sane,
+ ':bcc_dest' => $bcc_dest,
+ ':domain' => $domain,
+ ':active' => $active,
+ ':type' => $type
+ ));
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
@@ -155,37 +145,27 @@ function bcc($_action, $_data = null, $attr = null) {
);
continue;
}
- try {
- $stmt = $pdo->prepare("SELECT `id` FROM `bcc_maps`
- WHERE `local_dest` = :local_dest AND `type` = :type");
- $stmt->execute(array(':local_dest' => $local_dest, ':type' => $type));
- $id_now = $stmt->fetch(PDO::FETCH_ASSOC)['id'];
+ $stmt = $pdo->prepare("SELECT `id` FROM `bcc_maps`
+ WHERE `local_dest` = :local_dest AND `type` = :type");
+ $stmt->execute(array(':local_dest' => $local_dest, ':type' => $type));
+ $id_now = $stmt->fetch(PDO::FETCH_ASSOC)['id'];
- if (isset($id_now) && $id_now != $id) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
- 'msg' => array('bcc_exists', htmlspecialchars($local_dest), $type)
- );
- continue;
- }
-
- $stmt = $pdo->prepare("UPDATE `bcc_maps` SET `bcc_dest` = :bcc_dest, `active` = :active, `type` = :type WHERE `id`= :id");
- $stmt->execute(array(
- ':bcc_dest' => $bcc_dest,
- ':active' => $active,
- ':type' => $type,
- ':id' => $id
- ));
- }
- catch (PDOException $e) {
+ if (isset($id_now) && $id_now != $id) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
- 'msg' => array('mysql_error', $e)
+ 'msg' => array('bcc_exists', htmlspecialchars($local_dest), $type)
);
continue;
}
+
+ $stmt = $pdo->prepare("UPDATE `bcc_maps` SET `bcc_dest` = :bcc_dest, `active` = :active, `type` = :type WHERE `id`= :id");
+ $stmt->execute(array(
+ ':bcc_dest' => $bcc_dest,
+ ':active' => $active,
+ ':type' => $type,
+ ':id' => $id
+ ));
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
@@ -246,29 +226,20 @@ function bcc($_action, $_data = null, $attr = null) {
if (!is_numeric($id)) {
return false;
}
- try {
- $stmt = $pdo->prepare("SELECT `domain` FROM `bcc_maps` WHERE id = :id");
- $stmt->execute(array(':id' => $id));
- $domain = $stmt->fetch(PDO::FETCH_ASSOC)['domain'];
- if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
- 'msg' => 'access_denied'
- );
- continue;
- }
- $stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `id`= :id");
- $stmt->execute(array(':id' => $id));
- }
- catch (PDOException $e) {
+ $stmt = $pdo->prepare("SELECT `domain` FROM `bcc_maps` WHERE id = :id");
+ $stmt->execute(array(':id' => $id));
+ $domain = $stmt->fetch(PDO::FETCH_ASSOC)['domain'];
+ if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
- 'msg' => array('mysql_error', $e)
+ 'msg' => 'access_denied'
);
continue;
}
+ $stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `id`= :id");
+ $stmt->execute(array(':id' => $id));
+
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
@@ -317,33 +288,22 @@ function recipient_map($_action, $_data = null, $attr = null) {
}
$rmaps = recipient_map('get');
foreach ($rmaps as $rmap) {
- $old_dests_existing[] = recipient_map('details', $rmap)['recipient_map_old'];
- }
- if (in_array($old_dest_sane, $old_dests_existing)) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
- 'msg' => array('recipient_map_entry_exists', htmlspecialchars($old_dest))
- );
- return false;
- }
- try {
- $stmt = $pdo->prepare("INSERT INTO `recipient_maps` (`old_dest`, `new_dest`, `active`) VALUES
- (:old_dest, :new_dest, :active)");
- $stmt->execute(array(
- ':old_dest' => $old_dest_sane,
- ':new_dest' => $new_dest,
- ':active' => $active
- ));
- }
- catch (PDOException $e) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
- 'msg' => array('mysql_error', $e)
- );
- return false;
+ if (recipient_map('details', $rmap)['recipient_map_old'] == $old_dest_sane) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => array('recipient_map_entry_exists', htmlspecialchars($old_dest_sane))
+ );
+ return false;
+ }
}
+ $stmt = $pdo->prepare("INSERT INTO `recipient_maps` (`old_dest`, `new_dest`, `active`) VALUES
+ (:old_dest, :new_dest, :active)");
+ $stmt->execute(array(
+ ':old_dest' => $old_dest_sane,
+ ':new_dest' => $new_dest,
+ ':active' => $active
+ ));
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
@@ -384,7 +344,6 @@ function recipient_map($_action, $_data = null, $attr = null) {
);
continue;
}
- $active = intval($_data['active']);
if (!filter_var($new_dest, FILTER_VALIDATE_EMAIL)) {
$_SESSION['return'][] = array(
'type' => 'danger',
@@ -395,38 +354,27 @@ function recipient_map($_action, $_data = null, $attr = null) {
}
$rmaps = recipient_map('get');
foreach ($rmaps as $rmap) {
- $old_dests_existing[] = recipient_map('details', $rmap)['recipient_map_old'];
- }
- if (in_array($old_dest_sane, $old_dests_existing) &&
- recipient_map('details', $id)['recipient_map_old'] != $old_dest_sane) {
+ if ($rmap == $id) { continue; }
+ if (recipient_map('details', $rmap)['recipient_map_old'] == $old_dest_sane) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('recipient_map_entry_exists', htmlspecialchars($old_dest_sane))
);
- continue;
- }
- try {
- $stmt = $pdo->prepare("UPDATE `recipient_maps` SET
- `old_dest` = :old_dest,
- `new_dest` = :new_dest,
- `active` = :active
- WHERE `id`= :id");
- $stmt->execute(array(
- ':old_dest' => $old_dest_sane,
- ':new_dest' => $new_dest,
- ':active' => $active,
- ':id' => $id
- ));
- }
- catch (PDOException $e) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
- 'msg' => array('mysql_error', $e)
- );
- return false;
+ return false;
+ }
}
+ $stmt = $pdo->prepare("UPDATE `recipient_maps` SET
+ `old_dest` = :old_dest,
+ `new_dest` = :new_dest,
+ `active` = :active
+ WHERE `id`= :id");
+ $stmt->execute(array(
+ ':old_dest' => $old_dest_sane,
+ ':new_dest' => $new_dest,
+ ':active' => $active,
+ ':id' => $id
+ ));
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
@@ -471,24 +419,14 @@ function recipient_map($_action, $_data = null, $attr = null) {
if (!is_numeric($id)) {
return false;
}
- try {
- $stmt = $pdo->prepare("DELETE FROM `recipient_maps` WHERE `id`= :id");
- $stmt->execute(array(':id' => $id));
- }
- catch (PDOException $e) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
- 'msg' => array('mysql_error', $e)
- );
- return false;
- }
+ $stmt = $pdo->prepare("DELETE FROM `recipient_maps` WHERE `id`= :id");
+ $stmt->execute(array(':id' => $id));
+ $_SESSION['return'][] = array(
+ 'type' => 'success',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => array('recipient_map_entry_deleted', htmlspecialchars($id))
+ );
}
- $_SESSION['return'][] = array(
- 'type' => 'success',
- 'msg' => array('recipient_map_entry_deleted', htmlspecialchars($old_dest))
- );
- return true;
break;
}
}
diff --git a/data/web/inc/functions.tls_policy_maps.inc.php b/data/web/inc/functions.tls_policy_maps.inc.php
new file mode 100644
index 00000000..6581b60d
--- /dev/null
+++ b/data/web/inc/functions.tls_policy_maps.inc.php
@@ -0,0 +1,157 @@
+<?php
+function tls_policy_maps($_action, $_data = null, $attr = null) {
+ global $pdo;
+ global $lang;
+ if ($_SESSION['mailcow_cc_role'] != "admin") {
+ return false;
+ }
+ switch ($_action) {
+ case 'add':
+ $dest = idn_to_ascii(trim($_data['dest']));
+ $policy = strtolower(trim($_data['policy']));
+ $parameters = (isset($_data['parameters']) && !empty($_data['parameters'])) ? $_data['parameters'] : '';
+ if (!empty($parameters)) {
+ foreach (explode(' ', $parameters) as $parameter) {
+ if (!preg_match('/(.+)\=(.+)/i', $parameter)) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => 'tls_policy_map_parameter_invalid'
+ );
+ return false;
+ }
+ }
+ }
+ $active = intval($_data['active']);
+ $tls_policy_maps = tls_policy_maps('get');
+ foreach ($tls_policy_maps as $tls_policy_map) {
+ if (tls_policy_maps('details', $tls_policy_map)['dest'] == $dest) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => array('tls_policy_map_entry_exists', htmlspecialchars($dest))
+ );
+ return false;
+ }
+ }
+ $stmt = $pdo->prepare("INSERT INTO `tls_policy_override` (`dest`, `policy`, `parameters`, `active`) VALUES
+ (:dest, :policy, :parameters, :active)");
+ $stmt->execute(array(
+ ':dest' => $dest,
+ ':policy' => $policy,
+ ':parameters' => $parameters,
+ ':active' => $active
+ ));
+ $_SESSION['return'][] = array(
+ 'type' => 'success',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => array('tls_policy_map_entry_saved', htmlspecialchars($dest))
+ );
+ break;
+ case 'edit':
+ $ids = (array)$_data['id'];
+ foreach ($ids as $id) {
+ $is_now = tls_policy_maps('details', $id);
+ if (!empty($is_now)) {
+ $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active_int'];
+ $dest = (!empty($_data['dest'])) ? $_data['dest'] : $is_now['dest'];
+ $policy = (!empty($_data['policy'])) ? $_data['policy'] : $is_now['policy'];
+ $parameters = (isset($_data['parameters'])) ? $_data['parameters'] : $is_now['parameters'];
+ }
+ else {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => 'access_denied'
+ );
+ continue;
+ }
+ if (!empty($parameters)) {
+ foreach (explode(' ', $parameters) as $parameter) {
+ if (!preg_match('/(.+)\=(.+)/i', $parameter)) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => 'tls_policy_map_parameter_invalid'
+ );
+ return false;
+ }
+ }
+ }
+ $tls_policy_maps = tls_policy_maps('get');
+ foreach ($tls_policy_maps as $tls_policy_map) {
+ if ($tls_policy_map == $id) { continue; }
+ if (tls_policy_maps('details', $tls_policy_map)['dest'] == $dest) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => array('recipient_map_entry_exists', htmlspecialchars($dest))
+ );
+ return false;
+ }
+ }
+ $stmt = $pdo->prepare("UPDATE `tls_policy_override` SET
+ `dest` = :dest,
+ `policy` = :policy,
+ `parameters` = :parameters,
+ `active` = :active
+ WHERE `id`= :id");
+ $stmt->execute(array(
+ ':dest' => $dest,
+ ':policy' => $policy,
+ ':parameters' => $parameters,
+ ':active' => $active,
+ ':id' => $id
+ ));
+ $_SESSION['return'][] = array(
+ 'type' => 'success',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => array('tls_policy_map_entry_saved', htmlspecialchars($dest))
+ );
+ }
+ break;
+ case 'details':
+ $mapdata = array();
+ $id = intval($_data);
+ $stmt = $pdo->prepare("SELECT `id`,
+ `dest`,
+ `policy`,
+ `parameters`,
+ `active` AS `active_int`,
+ CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`,
+ `created`,
+ `modified` FROM `tls_policy_override`
+ WHERE `id` = :id");
+ $stmt->execute(array(':id' => $id));
+ $mapdata = $stmt->fetch(PDO::FETCH_ASSOC);
+ return $mapdata;
+ break;
+ case 'get':
+ $mapdata = array();
+ $all_items = array();
+ $id = intval($_data);
+ $stmt = $pdo->query("SELECT `id` FROM `tls_policy_override`");
+ $all_items = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ foreach ($all_items as $i) {
+ $mapdata[] = $i['id'];
+ }
+ $all_items = null;
+ return $mapdata;
+ break;
+ case 'delete':
+ $ids = (array)$_data['id'];
+ foreach ($ids as $id) {
+ if (!is_numeric($id)) {
+ return false;
+ }
+ $stmt = $pdo->prepare("DELETE FROM `tls_policy_override` WHERE `id`= :id");
+ $stmt->execute(array(':id' => $id));
+ $_SESSION['return'][] = array(
+ 'type' => 'success',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => array('tls_policy_map_entry_deleted', htmlspecialchars($id))
+ );
+ }
+ break;
+ }
+}
diff --git a/data/web/inc/header.inc.php b/data/web/inc/header.inc.php
index 46384b7b..15dc4f02 100644
--- a/data/web/inc/header.inc.php
+++ b/data/web/inc/header.inc.php
@@ -1,145 +1,145 @@
<!DOCTYPE html>
<html lang="<?= $_SESSION['mailcow_locale'] ?>">
<head>
-<meta charset="utf-8">
-<meta http-equiv="X-UA-Compatible" content="IE=edge">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<meta name="theme-color" content="#F5D76E"/>
-<meta http-equiv="Referrer-Policy" content="same-origin">
-<title><?=$UI_TEXTS['title_name'];?></title>
-<!--[if lt IE 9]>
- <script src="/js/html5shiv.min.js"></script>
- <script src="/js/respond.min.js"></script>
-<![endif]-->
-<script src="/js/jquery-1.12.4.min.js"></script>
-<?php if (strtolower(trim($DEFAULT_THEME)) != "lumen"): ?>
-<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootswatch/3.3.7/<?= strtolower(trim($DEFAULT_THEME)); ?>/bootstrap.min.css">
-<?php else: ?>
-<link rel="stylesheet" href="/css/bootstrap.min.css">
-<?php endif; ?>
-<link rel="stylesheet" href="/css/breakpoint.min.css">
-<link rel="stylesheet" href="/css/bootstrap-select.min.css">
-<link rel="stylesheet" href="/css/bootstrap-slider.min.css">
-<link rel="stylesheet" href="/css/bootstrap-switch.min.css">
-<link rel="stylesheet" href="/css/footable.bootstrap.min.css">
-<link rel="stylesheet" href="/inc/languages.min.css">
-<link rel="stylesheet" href="/css/mailcow.css">
-<link rel="stylesheet" href="/css/animate.min.css">
-<link rel="stylesheet" href="/css/numberedtextarea.min.css">
-<link rel="stylesheet" href="/css/jquery.jqplot.min.css">
-<?= (preg_match("/mailbox.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/mailbox.css">' : null; ?>
-<?= (preg_match("/admin.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/admin.css">' : null; ?>
-<?= (preg_match("/user.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/user.css">' : null; ?>
-<?= (preg_match("/edit.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/edit.css">' : null; ?>
-<?= (preg_match("/quarantine.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/quarantine.css">' : null; ?>
-<?= (preg_match("/debug.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/debug.css">' : null; ?>
-<link rel="shortcut icon" href="/favicon.png" type="image/png">
-<link rel="icon" href="/favicon.png" type="image/png">
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta name="theme-color" content="#F5D76E"/>
+ <meta http-equiv="Referrer-Policy" content="same-origin">
+ <title><?=$UI_TEXTS['title_name'];?></title>
+ <!--[if lt IE 9]>
+ <script src="/js/html5shiv.min.js"></script>
+ <script src="/js/respond.min.js"></script>
+ <![endif]-->
+ <script src="/js/jquery-1.12.4.min.js"></script>
+ <?php if (strtolower(trim($DEFAULT_THEME)) != "lumen"): ?>
+ <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootswatch/3.3.7/<?= strtolower(trim($DEFAULT_THEME)); ?>/bootstrap.min.css">
+ <?php else: ?>
+ <link rel="stylesheet" href="/css/bootstrap.min.css">
+ <?php endif; ?>
+ <link rel="stylesheet" href="/css/breakpoint.min.css">
+ <link rel="stylesheet" href="/css/bootstrap-select.min.css">
+ <link rel="stylesheet" href="/css/bootstrap-slider.min.css">
+ <link rel="stylesheet" href="/css/bootstrap-switch.min.css">
+ <link rel="stylesheet" href="/css/footable.bootstrap.min.css">
+ <link rel="stylesheet" href="/inc/languages.min.css">
+ <link rel="stylesheet" href="/css/mailcow.css">
+ <link rel="stylesheet" href="/css/animate.min.css">
+ <link rel="stylesheet" href="/css/numberedtextarea.min.css">
+ <link rel="stylesheet" href="/css/jquery.jqplot.min.css">
+ <?= (preg_match("/mailbox/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/mailbox.css">' : null; ?>
+ <?= (preg_match("/admin/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/admin.css">' : null; ?>
+ <?= (preg_match("/user/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/user.css">' : null; ?>
+ <?= (preg_match("/edit/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/edit.css">' : null; ?>
+ <?= (preg_match("/quarantine/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/quarantine.css">' : null; ?>
+ <?= (preg_match("/debug/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/debug.css">' : null; ?>
+ <link rel="shortcut icon" href="/favicon.png" type="image/png">
+ <link rel="icon" href="/favicon.png" type="image/png">
</head>
<body id="top">
-<div class="overlay"></div>
-<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
- <div class="container-fluid">
- <div class="navbar-header">
- <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- </button>
- <a class="navbar-brand" href="/"><img alt="mailcow-logo" src="<?=($main_logo = customize('get', 'main_logo')) ? $main_logo : '/img/cow_mailcow.svg';?>"></a>
- </div>
- <div id="navbar" class="navbar-collapse collapse">
- <ul class="nav navbar-nav navbar-right">
- <?php
- if (isset($_SESSION['mailcow_locale'])) {
- ?>
- <li class="dropdown<?=(isset($_SESSION['mailcow_locale']) && count($AVAILABLE_LANGUAGES) === 1) ? ' lang-link-disabled"' : '' ?>">
- <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><span class="lang-sm lang-lbl" lang="<?= $_SESSION['mailcow_locale']; ?>"></span><span class="caret"></span></a>
- <ul class="dropdown-menu" role="menu">
- <?php
- foreach ($AVAILABLE_LANGUAGES as $language) {
- ?>
- <li<?= ($_SESSION['mailcow_locale'] == $language) ? ' class="active"' : ''; ?>><a href="?<?= http_build_query(array_merge($_GET, array('lang' => $language))); ?>"><span class="lang-xs lang-lbl-full" lang="<?= $language; ?>"></span></a></li>
- <?php
- }
- ?>
- </ul>
- </li>
- <?php
- }
- if (isset($_SESSION['mailcow_cc_role'])) {
- ?>
- <li class="dropdown">
- <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><?= $lang['header']['mailcow_settings']; ?> <span class="caret"></span></a>
- <ul class="dropdown-menu" role="menu">
- <?php
- if (isset($_SESSION['mailcow_cc_role'])) {
- if ($_SESSION['mailcow_cc_role'] == 'admin') {
- ?>
- <li<?= (preg_match("/admin/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/admin.php"><?= $lang['header']['administration']; ?></a></li>
- <li<?= (preg_match("/debug/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/debug.php"><?= $lang['header']['debug']; ?></a></li>
+ <div class="overlay"></div>
+ <nav class="navbar navbar-default navbar-fixed-top" role="navigation">
+ <div class="container-fluid">
+ <div class="navbar-header">
+ <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </button>
+ <a class="navbar-brand" href="/"><img alt="mailcow-logo" src="<?=($main_logo = customize('get', 'main_logo')) ? $main_logo : '/img/cow_mailcow.svg';?>"></a>
+ </div>
+ <div id="navbar" class="navbar-collapse collapse">
+ <ul class="nav navbar-nav navbar-right">
+ <?php
+ if (isset($_SESSION['mailcow_locale'])) {
+ ?>
+ <li class="dropdown<?=(isset($_SESSION['mailcow_locale']) && count($AVAILABLE_LANGUAGES) === 1) ? ' lang-link-disabled"' : '' ?>">
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><span class="lang-sm lang-lbl" lang="<?= $_SESSION['mailcow_locale']; ?>"></span><span class="caret"></span></a>
+ <ul class="dropdown-menu" role="menu">
<?php
- }
- if ($_SESSION['mailcow_cc_role'] == 'admin' || $_SESSION['mailcow_cc_role'] == 'domainadmin') {
+ foreach ($AVAILABLE_LANGUAGES as $language) {
?>
- <li<?= (preg_match("/mailbox/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/mailbox.php"><?= $lang['header']['mailboxes']; ?></a></li>
+ <li<?= ($_SESSION['mailcow_locale'] == $language) ? ' class="active"' : ''; ?>><a href="?<?= http_build_query(array_merge($_GET, array('lang' => $language))); ?>"><span class="lang-xs lang-lbl-full" lang="<?= $language; ?>"></span></a></li>
<?php
}
- if ($_SESSION['mailcow_cc_role'] != 'admin') {
?>
- <li<?= (preg_match("/user/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/user.php"><?= $lang['header']['user_settings']; ?></a></li>
+ </ul>
+ </li>
+ <?php
+ }
+ if (isset($_SESSION['mailcow_cc_role'])) {
+ ?>
+ <li class="dropdown">
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><?= $lang['header']['mailcow_settings']; ?> <span class="caret"></span></a>
+ <ul class="dropdown-menu" role="menu">
<?php
+ if (isset($_SESSION['mailcow_cc_role'])) {
+ if ($_SESSION['mailcow_cc_role'] == 'admin') {
+ ?>
+ <li<?= (preg_match("/admin/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/admin"><?= $lang['header']['administration']; ?></a></li>
+ <li<?= (preg_match("/debug/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/debug"><?= $lang['header']['debug']; ?></a></li>
+ <?php
+ }
+ if ($_SESSION['mailcow_cc_role'] == 'admin' || $_SESSION['mailcow_cc_role'] == 'domainadmin') {
+ ?>
+ <li<?= (preg_match("/mailbox/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/mailbox"><?= $lang['header']['mailboxes']; ?></a></li>
+ <?php
+ }
+ if ($_SESSION['mailcow_cc_role'] != 'admin') {
+ ?>
+ <li<?= (preg_match("/user/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/user"><?= $lang['header']['user_settings']; ?></a></li>
+ <?php
+ }
}
- }
- ?>
- </ul>
- </li>
- <?php
- if (isset($_SESSION['mailcow_cc_role'])) {
- ?>
- <li<?= (preg_match("/quarantine/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/quarantine.php"><span class="glyphicon glyphicon-briefcase"></span> <?= $lang['header']['quarantine']; ?></a></li>
- <?php
- }
- if ($_SESSION['mailcow_cc_role'] == 'admin') {
- ?>
- <li><a href data-toggle="modal" data-container="sogo-mailcow" data-target="#RestartContainer"><span class="glyphicon glyphicon-refresh"></span> <?= $lang['header']['restart_sogo']; ?></a></li>
- <?php
- }
- ?>
- <li class="dropdown">
- <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><span class="glyphicon glyphicon-link"></span> Apps <span class="caret"></span></a>
- <ul class="dropdown-menu" role="menu">
+ ?>
+ </ul>
+ </li>
<?php
- foreach ($MAILCOW_APPS as $app):
+ if (isset($_SESSION['mailcow_cc_role'])) {
?>
- <li title="<?= htmlspecialchars($app['description']); ?>"><a href="<?= htmlspecialchars($app['link']); ?>"><?= htmlspecialchars($app['name']); ?></a></li>
+ <li<?= (preg_match("/quarantine/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/quarantine"><span class="glyphicon glyphicon-briefcase"></span> <?= $lang['header']['quarantine']; ?></a></li>
<?php
- endforeach;
- $app_links = customize('get', 'app_links');
- foreach ($app_links as $row) {
- foreach ($row as $key => $val):
+ }
+ if ($_SESSION['mailcow_cc_role'] == 'admin') {
?>
- <li><a href="<?= htmlspecialchars($val); ?>"><?= htmlspecialchars($key); ?></a></li>
+ <li><a href data-toggle="modal" data-container="sogo-mailcow" data-target="#RestartContainer"><span class="glyphicon glyphicon-refresh"></span> <?= $lang['header']['restart_sogo']; ?></a></li>
<?php
+ }
+ ?>
+ <li class="dropdown">
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><span class="glyphicon glyphicon-link"></span> Apps <span class="caret"></span></a>
+ <ul class="dropdown-menu" role="menu">
+ <?php
+ foreach ($MAILCOW_APPS as $app):
+ ?>
+ <li title="<?= htmlspecialchars($app['description']); ?>"><a href="<?= htmlspecialchars($app['link']); ?>"><?= htmlspecialchars($app['name']); ?></a></li>
+ <?php
endforeach;
+ $app_links = customize('get', 'app_links');
+ foreach ($app_links as $row) {
+ foreach ($row as $key => $val):
+ ?>
+ <li><a href="<?= htmlspecialchars($val); ?>"><?= htmlspecialchars($key); ?></a></li>
+ <?php
+ endforeach;
+ }
+ ?>
+ </ul>
+ </li>
+ <?php
}
+ if (!isset($_SESSION['dual-login']) && isset($_SESSION['mailcow_cc_username'])):
+ ?>
+ <li class="logged-in-as"><a href="#" onclick="logout.submit()"><b class="username-lia"><?= htmlspecialchars($_SESSION['mailcow_cc_username']); ?></b> <span class="glyphicon glyphicon-log-out"></span></a></li>
+ <?php
+ elseif (isset($_SESSION['dual-login'])):
+ ?>
+ <li class="logged-in-as"><a href="#" onclick="logout.submit()"><b class="username-lia"><?= htmlspecialchars($_SESSION['mailcow_cc_username']); ?> <span class="text-info">(<?= htmlspecialchars($_SESSION['dual-login']['username']); ?>)</span> </b><span class="glyphicon glyphicon-log-out"></span></a></li>
+ <?php
+ endif;
?>
- </ul>
- </li>
- <?php
- }
- if (!isset($_SESSION['dual-login']) && isset($_SESSION['mailcow_cc_username'])):
- ?>
- <li class="logged-in-as"><a href="#" onclick="logout.submit()"><b class="username-lia"><?= htmlspecialchars($_SESSION['mailcow_cc_username']); ?></b> <span class="glyphicon glyphicon-log-out"></span></a></li>
- <?php
- elseif (isset($_SESSION['dual-login'])):
- ?>
- <li class="logged-in-as"><a href="#" onclick="logout.submit()"><b class="username-lia"><?= htmlspecialchars($_SESSION['mailcow_cc_username']); ?> <span class="text-info">(<?= htmlspecialchars($_SESSION['dual-login']['username']); ?>)</span> </b><span class="glyphicon glyphicon-log-out"></span></a></li>
- <?php
- endif;
- ?>
- </ul>
- </div><!--/.nav-collapse -->
- </div><!--/.container-fluid -->
-</nav>
-<form action="/" method="post" id="logout"><input type="hidden" name="logout"></form>
+ </ul>
+ </div><!--/.nav-collapse -->
+ </div><!--/.container-fluid -->
+ </nav>
+ <form action="/" method="post" id="logout"><input type="hidden" name="logout"></form>
diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php
index 571713be..8ece2544 100644
--- a/data/web/inc/init_db.inc.php
+++ b/data/web/inc/init_db.inc.php
@@ -3,7 +3,7 @@ function init_db_schema() {
try {
global $pdo;
- $db_version = "21092018_1902";
+ $db_version = "03102018_1502";
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
@@ -192,6 +192,26 @@ function init_db_schema() {
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
+ "tls_policy_override" => array(
+ "cols" => array(
+ "id" => "INT NOT NULL AUTO_INCREMENT",
+ "dest" => "VARCHAR(255) NOT NULL",
+ "policy" => "ENUM('none', 'may', 'encrypt', 'dane', 'dane-only', 'fingerprint', 'verify', 'secure') NOT NULL",
+ "parameters" => "VARCHAR(255) DEFAULT ''",
+ "created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
+ "modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
+ "active" => "TINYINT(1) NOT NULL DEFAULT '1'"
+ ),
+ "keys" => array(
+ "primary" => array(
+ "" => array("id")
+ ),
+ "unique" => array(
+ "dest" => array("dest")
+ ),
+ ),
+ "attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
+ ),
"quarantine" => array(
"cols" => array(
"id" => "INT NOT NULL AUTO_INCREMENT",
diff --git a/data/web/inc/prerequisites.inc.php b/data/web/inc/prerequisites.inc.php
index 209c7184..4cb742af 100644
--- a/data/web/inc/prerequisites.inc.php
+++ b/data/web/inc/prerequisites.inc.php
@@ -146,6 +146,7 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.fwdhost.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.ratelimit.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.relayhost.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.rsettings.inc.php';
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.tls_policy_maps.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.fail2ban.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.docker.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/init_db.inc.php';
diff --git a/data/web/index.php b/data/web/index.php
index 47339923..07fb4497 100644
--- a/data/web/index.php
+++ b/data/web/index.php
@@ -2,15 +2,15 @@
require_once 'inc/prerequisites.inc.php';
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'admin') {
- header('Location: /admin.php');
+ header('Location: /admin');
exit();
}
elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'domainadmin') {
- header('Location: /mailbox.php');
+ header('Location: /mailbox');
exit();
}
elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user') {
- header('Location: /user.php');
+ header('Location: /user');
exit();
}
require_once 'inc/header.inc.php';
diff --git a/data/web/js/admin.js b/data/web/js/admin.js
index 17df1cf0..d8f1e0ad 100644
--- a/data/web/js/admin.js
+++ b/data/web/js/admin.js
@@ -121,7 +121,7 @@ jQuery(function($){
$.each(data, function (i, item) {
item.action = '<div class="btn-group">' +
'<a href="#" data-toggle="modal" id="miau" data-target="#testRelayhostModal" data-relayhost-id="' + encodeURI(item.id) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-stats"></span> Test</a>' +
- '<a href="/edit.php?relayhost=' + encodeURI(item.id) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/relayhost/' + encodeURI(item.id) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-rlshost" data-api-url="delete/relayhost" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="rlyhosts" name="multi_select" value="' + item.id + '" />';
@@ -144,7 +144,7 @@ jQuery(function($){
item.selected_domains = escapeHtml(item.selected_domains.toString().replace(/,/g, " "));
item.chkbox = '<input type="checkbox" data-id="domain_admins" name="multi_select" value="' + item.username + '" />';
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?domainadmin=' + encodeURI(item.username) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/domainadmin/' + encodeURI(item.username) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-domain-admin" data-api-url="delete/domain-admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-success"><span class="glyphicon glyphicon-user"></span> Login</a>' +
'</div>';
diff --git a/data/web/js/mailbox.js b/data/web/js/mailbox.js
index 836ec872..8894e995 100644
--- a/data/web/js/mailbox.js
+++ b/data/web/js/mailbox.js
@@ -300,11 +300,11 @@ jQuery(function($){
item.chkbox = '<input type="checkbox" data-id="domain" name="multi_select" value="' + encodeURIComponent(item.domain_name) + '" />';
item.action = '<div class="btn-group">';
if (role == "admin") {
- item.action += '<a href="/edit.php?domain=' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-domain" data-api-url="delete/domain" data-item="' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>';
}
else {
- item.action += '<a href="/edit.php?domain=' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>';
+ item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>';
}
item.action += '<a href="#dnsInfoModal" class="btn btn-xs btn-info" data-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><span class="glyphicon glyphicon-question-sign"></span> DNS</a></div>';
});
@@ -353,6 +353,8 @@ jQuery(function($){
},
},
{"name":"spam_aliases","filterable": false,"title":lang.spam_aliases,"breakpoints":"xs sm md"},
+ {"name":"tls_enforce_in","filterable": false,"title":lang.tls_enforce_in,"breakpoints":"all"},
+ {"name":"tls_enforce_out","filterable": false,"title":lang.tls_enforce_out,"breakpoints":"all"},
{"name":"in_use","filterable": false,"type":"html","title":lang.in_use,"sortValue": function(value){
return Number($(value).find(".progress-bar").attr('aria-valuenow'));
},
@@ -382,16 +384,18 @@ jQuery(function($){
}).join('/1');
}
item.chkbox = '<input type="checkbox" data-id="mailbox" name="multi_select" value="' + encodeURIComponent(item.username) + '" />';
+ item.tls_enforce_in = '<span class="text-' + (item.attributes.tls_enforce_in == 1 ? 'success' : 'danger') + ' glyphicon glyphicon-lock"></span>';
+ item.tls_enforce_out = '<span class="text-' + (item.attributes.tls_enforce_out == 1 ? 'success' : 'danger') + ' glyphicon glyphicon-lock"></span>';
if (acl_data.login_as === 1) {
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?mailbox=' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="login_as btn btn-xs btn-success"><span class="glyphicon glyphicon-user"></span> Login</a>' +
'</div>';
}
else {
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?mailbox=' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
}
@@ -412,6 +416,7 @@ jQuery(function($){
"delay": 100,
"position": "left",
"connectors": false,
+ //"container": "#tab-mailboxes.panel",
"placeholder": lang.filter_table
},
"components": {
@@ -459,7 +464,7 @@ jQuery(function($){
item.multiple_bookings = '<span id="active-script" class="label label-danger">' + lang.booking_custom_short + ' (' + item.multiple_bookings + ')</span>';
}
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?resource=' + encodeURIComponent(item.name) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/resource/' + encodeURIComponent(item.name) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-resource" data-api-url="delete/resource" data-item="' + item.name + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="resource" name="multi_select" value="' + encodeURIComponent(item.name) + '" />';
@@ -518,7 +523,7 @@ jQuery(function($){
success: function (data) {
$.each(data, function (i, item) {
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?bcc=' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/bcc/' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-bcc" data-api-url="delete/bcc" data-item="' + item.id + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="bcc" name="multi_select" value="' + item.id + '" />';
@@ -581,7 +586,7 @@ jQuery(function($){
item.recipient_map_old = escapeHtml(item.recipient_map_old);
item.recipient_map_new = escapeHtml(item.recipient_map_new);
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?recipient_map=' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/recipient_map/' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-recipient_map" data-api-url="delete/recipient_map" data-item="' + item.id + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="recipient_map" name="multi_select" value="' + item.id + '" />';
@@ -614,6 +619,69 @@ jQuery(function($){
}
});
}
+ function draw_tls_policy_table() {
+ ft_tls_policy_table = FooTable.init('#tls_policy_table', {
+ "columns": [
+ {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
+ {"sorted": true,"name":"id","title":"ID","style":{"maxWidth":"60px","width":"60px","text-align":"center"}},
+ {"name":"dest","title":lang.tls_map_dest},
+ {"name":"policy","title":lang.tls_map_policy},
+ {"name":"parameters","title":lang.tls_map_parameters},
+ {"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active},
+ {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":(role == "admin" ? lang.action : ""),"breakpoints":"xs sm"}
+ ],
+ "empty": lang.empty,
+ "rows": $.ajax({
+ dataType: 'json',
+ url: '/api/v1/get/tls-policy-map/all',
+ jsonp: false,
+ error: function () {
+ console.log('Cannot draw tls policy map table');
+ },
+ success: function (data) {
+ if (role == "admin") {
+ $.each(data, function (i, item) {
+ item.dest = escapeHtml(item.dest);
+ item.policy = '<b>' + escapeHtml(item.policy) + '</b>';
+ if (item.parameters == '') {
+ item.parameters = '<code>-</code>';
+ } else {
+ item.parameters = '<code>' + escapeHtml(item.parameters) + '</code>';
+ }
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/tls_policy_map/' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="#" data-action="delete_selected" data-id="single-tls-policy-map" data-api-url="delete/tls-policy-map" data-item="' + item.id + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
+ '</div>';
+ item.chkbox = '<input type="checkbox" data-id="tls-policy-map" name="multi_select" value="' + item.id + '" />';
+ });
+ }
+ }
+ }),
+ "paging": {
+ "enabled": true,
+ "limit": 5,
+ "size": pagination_size
+ },
+ "filtering": {
+ "enabled": true,
+ "delay": 100,
+ "position": "left",
+ "connectors": false,
+ "placeholder": lang.filter_table
+ },
+ "sorting": {
+ "enabled": true
+ },
+ "on": {
+ "ready.ft.table": function(e, ft){
+ table_mailbox_ready(ft, 'tls_policy_table');
+ },
+ "after.ft.paging": function(e, ft){
+ paging_mailbox_after(ft, 'tls_policy_table');
+ }
+ }
+ });
+ }
function draw_alias_table() {
ft_alias_table = FooTable.init('#alias_table', {
"columns": [
@@ -636,7 +704,7 @@ jQuery(function($){
success: function (data) {
$.each(data, function (i, item) {
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?alias=' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/alias/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-alias" data-api-url="delete/alias" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="alias" name="multi_select" value="' + encodeURIComponent(item.id) + '" />';
@@ -711,7 +779,7 @@ jQuery(function($){
success: function (data) {
$.each(data, function (i, item) {
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?aliasdomain=' + encodeURIComponent(item.alias_domain) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/aliasdomain/' + encodeURIComponent(item.alias_domain) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-alias-domain" data-api-url="delete/alias-domain" data-item="' + encodeURIComponent(item.alias_domain) + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'<a href="#dnsInfoModal" class="btn btn-xs btn-info" data-toggle="modal" data-domain="' + encodeURIComponent(item.alias_domain) + '"><span class="glyphicon glyphicon-question-sign"></span> DNS</a></div>' +
'</div>';
@@ -779,7 +847,7 @@ jQuery(function($){
}
item.server_w_port = escapeHtml(item.user1) + '@' + item.host1 + ':' + item.port1;
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?syncjob=' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="syncjob" name="multi_select" value="' + item.id + '" />';
@@ -850,7 +918,7 @@ jQuery(function($){
item.script_data = '<pre style="margin:0px">' + escapeHtml(item.script_data) + '</pre>'
item.filter_type = '<div class="label label-default">' + item.filter_type.charAt(0).toUpperCase() + item.filter_type.slice(1).toLowerCase() + '</div>'
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?filter=' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/filter/' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-filter" data-api-url="delete/filter" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="filter_item" name="multi_select" value="' + item.id + '" />'
@@ -892,5 +960,6 @@ jQuery(function($){
draw_filter_table();
draw_bcc_table();
draw_recipient_map_table();
+ draw_tls_policy_table();
});
diff --git a/data/web/js/user.js b/data/web/js/user.js
index 5649d6c6..2c960e82 100644
--- a/data/web/js/user.js
+++ b/data/web/js/user.js
@@ -122,7 +122,7 @@ jQuery(function($){
item.server_w_port = escapeHtml(item.user1 + '@' + item.host1 + ':' + item.port1);
if (acl_data.syncjobs === 1) {
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?syncjob=' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="syncjob" name="multi_select" value="' + item.id + '" />';
diff --git a/data/web/json_api.php b/data/web/json_api.php
index adeb162e..d1f6a979 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -153,6 +153,9 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
case "recipient_map":
process_add_return(recipient_map('add', $attr));
break;
+ case "tls-policy-map":
+ process_add_return(tls_policy_maps('add', $attr));
+ break;
}
break;
case "get":
@@ -662,6 +665,31 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
break;
}
break;
+ case "tls-policy-map":
+ switch ($object) {
+ case "all":
+ $tls_policy_maps_items = tls_policy_maps('get');
+ if (!empty($tls_policy_maps_items)) {
+ foreach ($tls_policy_maps_items as $tls_policy_maps_item) {
+ if ($details = tls_policy_maps('details', $tls_policy_maps_item)) {
+ $data[] = $details;
+ }
+ else {
+ continue;
+ }
+ }
+ }
+ process_get_return($data);
+ break;
+ default:
+ $data = tls_policy_maps('details', $object);
+ if (!empty($data)) {
+ $data[] = $details;
+ }
+ process_get_return($data);
+ break;
+ }
+ break;
case "policy_wl_mailbox":
switch ($object) {
default:
@@ -919,6 +947,9 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
case "recipient_map":
process_delete_return(recipient_map('delete', array('id' => $items)));
break;
+ case "tls-policy-map":
+ process_delete_return(tls_policy_maps('delete', array('id' => $items)));
+ break;
case "fwdhost":
process_delete_return(fwdhost('delete', array('forwardinghost' => $items)));
break;
@@ -991,6 +1022,9 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
case "recipient_map":
process_edit_return(recipient_map('edit', array_merge(array('id' => $items), $attr)));
break;
+ case "tls-policy-map":
+ process_edit_return(tls_policy_maps('edit', array_merge(array('id' => $items), $attr)));
+ break;
case "alias":
process_edit_return(mailbox('edit', 'alias', array_merge(array('id' => $items), $attr)));
break;
diff --git a/data/web/lang/lang.de.php b/data/web/lang/lang.de.php
index 4cb2e789..9392f346 100644
--- a/data/web/lang/lang.de.php
+++ b/data/web/lang/lang.de.php
@@ -240,6 +240,17 @@ $lang['header']['mailcow_settings'] = 'Konfiguration';
$lang['header']['administration'] = 'Administration';
$lang['header']['mailboxes'] = 'Mailboxen';
$lang['header']['user_settings'] = 'Benutzereinstellungen';
+$lang['mailbox']['tls_policy_maps'] = 'TLS-Richtlinien';
+$lang['mailbox']['tls_policy_maps_long'] = 'Ausgehende TLS-Richtlinien';
+$lang['mailbox']['tls_policy_maps_info'] = 'Nachstehende Richtlinien erzwingen TLS-Transportregeln unabhängig von TLS-Richtlinieneinstellungen eines Benutzers.<br>
+ Für weitere Informationen zur Syntax sollte <a href="http://www.postfix.org/postconf.5.html#smtp_tls_policy_maps" target="_blank">die "smtp_tls_policy_maps" Dokumentation</a> konsultiert werden.';
+$lang['mailbox']['tls_enforce_in'] = 'Enforce TLS incoming';
+$lang['mailbox']['tls_enforce_out'] = 'Enforce TLS outgoing';
+$lang['mailbox']['tls_map_dest'] = 'Ziel';
+$lang['mailbox']['tls_map_dest_info'] = 'Beispiele: example.org, .example.org, [email protected], [mail.example.org]:25';
+$lang['mailbox']['tls_map_policy'] = 'Richtlinie';
+$lang['mailbox']['tls_map_parameters'] = 'Parameter';
+$lang['mailbox']['tls_map_parameters_info'] = 'Leer oder Parameter, Beispiele: protocols=!SSLv2 ciphers=medium exclude=3DES';
$lang['mailbox']['booking_0'] = 'Immer als verfügbar anzeigen';
$lang['mailbox']['booking_lt0'] = 'Unbegrenzt, jedoch anzeigen, wenn gebucht';
$lang['mailbox']['booking_custom'] = 'Benutzerdefiniertes Limit';
@@ -666,9 +677,13 @@ $lang['mailbox']['recipient_map_new_info'] = 'Der neue Empfänger muss eine E-Ma
$lang['mailbox']['recipient_map_old'] = 'Original Empfänger';
$lang['mailbox']['recipient_map_new'] = 'Neuer Empfänger';
$lang['mailbox']['add_recipient_map_entry'] = 'Empfängerumschreibung hinzufügen';
-$lang['danger']['invalid_recipient_map_new'] = 'Neuer Empfänger %s ist ungültig';
-$lang['danger']['invalid_recipient_map_old'] = 'Originaler Empfänger %s ist ungültig';
-$lang['danger']['recipient_map_entry_exists'] = 'Eine Empfängerumschreibung für %s existiert bereits';
-$lang['success']['recipient_map_entry_saved'] = 'Empfängerumschreibung für Objekt %s wurde gespeichert';
-$lang['success']['recipient_map_entry_deleted'] = 'Empfängerumschreibung für Objekt %s wurde gelöscht';
-
+$lang['danger']['invalid_recipient_map_new'] = 'Neuer Empfänger "%s" ist ungültig';
+$lang['danger']['invalid_recipient_map_old'] = 'Originaler Empfänger "%s" ist ungültig';
+$lang['danger']['recipient_map_entry_exists'] = 'Eine Empfängerumschreibung für Objekt "%s" existiert bereits';
+$lang['success']['recipient_map_entry_saved'] = 'Empfängerumschreibung für Objekt "%s" wurde gespeichert';
+$lang['success']['recipient_map_entry_deleted'] = 'Empfängerumschreibung mit der ID %s wurde gelöscht';
+$lang['danger']['tls_policy_map_entry_exists'] = 'Eine TLS-Richtlinie "%s" existiert bereits';
+$lang['success']['tls_policy_map_entry_saved'] = 'TLS-Richtlinieneintrag "%s" wurde gespeichert';
+$lang['success']['tls_policy_map_entry_deleted'] = 'TLS-Richtlinie mit der ID %s wurde gelöscht';
+$lang['mailbox']['add_tls_policy_map'] = "TLS-Richtlinieneintrag hinzufügen";
+$lang['danger']['tls_policy_map_parameter_invalid'] = "Parameter ist ungültig";
diff --git a/data/web/lang/lang.en.php b/data/web/lang/lang.en.php
index 9e5dc9ec..195bceb2 100644
--- a/data/web/lang/lang.en.php
+++ b/data/web/lang/lang.en.php
@@ -242,6 +242,17 @@ $lang['header']['mailcow_settings'] = 'Configuration';
$lang['header']['administration'] = 'Administration';
$lang['header']['mailboxes'] = 'Mailboxes';
$lang['header']['user_settings'] = 'User settings';
+$lang['mailbox']['tls_policy_maps'] = 'TLS policy maps';
+$lang['mailbox']['tls_policy_maps_long'] = 'Outgoing TLS policy map overrides';
+$lang['mailbox']['tls_policy_maps_info'] = 'This policy map overrides outgoing TLS transport rules independently of a users TLS policy settings.<br>
+ Please check <a href="http://www.postfix.org/postconf.5.html#smtp_tls_policy_maps" target="_blank">the "smtp_tls_policy_maps" docs</a> for further information.';
+$lang['mailbox']['tls_enforce_in'] = 'Enforce TLS incoming';
+$lang['mailbox']['tls_enforce_out'] = 'Enforce TLS outgoing';
+$lang['mailbox']['tls_map_dest'] = 'Destination';
+$lang['mailbox']['tls_map_dest_info'] = 'Examples: example.org, .example.org, [email protected], [mail.example.org]:25';
+$lang['mailbox']['tls_map_policy'] = 'Policy';
+$lang['mailbox']['tls_map_parameters'] = 'Parameters';
+$lang['mailbox']['tls_map_parameters_info'] = 'Empty or parameters, for example: protocols=!SSLv2 ciphers=medium exclude=3DES';
$lang['mailbox']['booking_0'] = 'Always show as free';
$lang['mailbox']['booking_lt0'] = 'Unlimited, but show as busy when booked';
$lang['mailbox']['booking_custom'] = 'Hard-limit to a custom amount of bookings';
@@ -667,6 +678,7 @@ $lang['mailbox']['bcc_maps'] = "BCC maps";
$lang['mailbox']['bcc_to_sender'] = "Switch to sender map type";
$lang['mailbox']['bcc_to_rcpt'] = "Switch to recipient map type";
$lang['mailbox']['add_bcc_entry'] = "Add BCC map";
+$lang['mailbox']['add_tls_policy_map'] = "Add TLS policy map";
$lang['mailbox']['bcc_info'] = "BCC maps are used to silently forward copies of all messages to another address. A recipient map type entry is used, when the local destination acts as recipient of a mail. Sender maps conform to the same principle.<br/>
The local destination will not be informed about a failed delivery.";
$lang['mailbox']['address_rewriting'] = 'Address rewriting';
@@ -679,10 +691,14 @@ $lang['mailbox']['recipient_map_old'] = 'Original recipient';
$lang['mailbox']['recipient_map_new'] = 'New recipient';
$lang['danger']['invalid_recipient_map_new'] = 'Invalid new recipient specified: %s';
$lang['danger']['invalid_recipient_map_old'] = 'Invalid original recipient specified: %s';
-$lang['danger']['recipient_map_entry_exists'] = 'A Recipient map entry for %s exists';
-$lang['success']['recipient_map_entry_saved'] = 'Recipient map entry for %s has been saved';
-$lang['success']['recipient_map_entry_deleted'] = 'Recipient map entry for %s has been deleted';
+$lang['danger']['recipient_map_entry_exists'] = 'A Recipient map entry "%s" exists';
+$lang['success']['recipient_map_entry_saved'] = 'Recipient map entry "%s" has been saved';
+$lang['success']['recipient_map_entry_deleted'] = 'Recipient map ID %s has been deleted';
+$lang['danger']['tls_policy_map_entry_exists'] = 'A TLS policy map entry "%s" exists';
+$lang['success']['tls_policy_map_entry_saved'] = 'TLS policy map entry "%s" has been saved';
+$lang['success']['tls_policy_map_entry_deleted'] = 'TLS policy map ID %s has been deleted';
$lang['mailbox']['add_recipient_map_entry'] = 'Add recipient map';
+$lang['danger']['tls_policy_map_parameter_invalid'] = "Policy parameter is invalid";
$lang['oauth2']['scope_ask_permission'] = 'An application asked for the following permissions';
$lang['oauth2']['profile'] = 'Profile';
diff --git a/data/web/mailbox.php b/data/web/mailbox.php
index 70d8dbb6..fd21d26d 100644
--- a/data/web/mailbox.php
+++ b/data/web/mailbox.php
@@ -22,6 +22,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
<li role="presentation"><a href="#tab-syncjobs" aria-controls="tab-syncjobs" role="tab" data-toggle="tab"><?=$lang['mailbox']['sync_jobs'];?></a></li>
<li role="presentation"><a href="#tab-filters" aria-controls="tab-filters" role="tab" data-toggle="tab"><?=$lang['mailbox']['filters'];?></a></li>
<li role="presentation"><a href="#tab-bcc" aria-controls="tab-filters" role="tab" data-toggle="tab"><?=$lang['mailbox']['address_rewriting'];?></a></li>
+ <li role="presentation"><a href="#tab-tls-policy" aria-controls="tab-tls-policy" role="tab" data-toggle="tab"><?=$lang['mailbox']['tls_policy_maps'];?></a></li>
</ul>
<div class="row">
@@ -287,6 +288,34 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
</div>
</div>
</div>
+
+ <div role="tabpanel" class="tab-pane <?=($_SESSION['mailcow_cc_role'] == "admin") ?: 'hidden';?>" id="tab-tls-policy">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <?=$lang['mailbox']['tls_policy_maps_long'];?> <span class="badge badge-info table-lines"></span>
+ <div class="btn-group pull-right">
+ <button class="btn btn-xs btn-default refresh_table" data-draw="draw_tls_policy_table" data-table="tls_policy_table"><?=$lang['admin']['refresh'];?></button>
+ </div>
+ </div>
+ <p style="margin:10px" class="help-block"><?=$lang['mailbox']['tls_policy_maps_info'];?></p>
+ <div class="table-responsive">
+ <table class="table table-striped" id="tls_policy_table"></table>
+ </div>
+ <div class="mass-actions-mailbox">
+ <div class="btn-group">
+ <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="tls-policy-map" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
+ <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+ <ul class="dropdown-menu">
+ <li><a data-action="edit_selected" data-id="tls-policy-map" data-api-url='edit/tls-policy-map' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
+ <li><a data-action="edit_selected" data-id="tls-policy-map" data-api-url='edit/tls-policy-map' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
+ <li role="separator" class="divider"></li>
+ <li><a data-action="delete_selected" data-id="tls-policy-map" data-api-url='delete/tls-policy-map' href="#"><?=$lang['mailbox']['remove'];?></a></li>
+ </ul>
+ <a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addTLSPolicyMapAdmin"><span class="glyphicon glyphicon-plus"></span> <?=$lang['mailbox']['add_tls_policy_map'];?></a>
+ </div>
+ </div>
+ </div>
+ </div>
</div> <!-- /tab-content -->
</div> <!-- /col-md-12 -->
</div> <!-- /row -->
diff --git a/data/web/modals/mailbox.php b/data/web/modals/mailbox.php
index fe99bc6d..107df71a 100644
--- a/data/web/modals/mailbox.php
+++ b/data/web/modals/mailbox.php
@@ -692,6 +692,62 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
</div>
</div>
</div><!-- add add_recipient_map modal -->
+<!-- add add_tls_policy_map modal -->
+<div class="modal fade" id="addTLSPolicyMapAdmin" tabindex="-1" role="dialog" aria-hidden="true">
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
+ <h3 class="modal-title"><?=$lang['mailbox']['tls_policy_maps'];?></h3>
+ </div>
+ <div class="modal-body">
+ <form class="form-horizontal" data-cached-form="true" role="form" data-id="add_tls_policy_map">
+ <div class="form-group">
+ <label class="control-label col-sm-2" for="dest"><?=$lang['mailbox']['tls_map_dest'];?></label>
+ <div class="col-sm-10">
+ <input type="text" class="form-control" name="dest">
+ <small><?=$lang['mailbox']['tls_map_dest_info'];?></small>
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="control-label col-sm-2" for="policy"><?=$lang['mailbox']['tls_map_policy'];?>:</label>
+ <div class="col-sm-10">
+ <select class="full-width-select" name="policy" required>
+ <option value="none">none</option>
+ <option value="may">may</option>
+ <option value="encrypt">encrypt</option>
+ <option value="dane">dane</option>
+ <option value="dane-only">dane-only</option>
+ <option value="fingerprint">fingerprint</option>
+ <option value="verify">verify</option>
+ <option value="secure">secure</option>
+ </select>
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="control-label col-sm-2" for="parameters"><?=$lang['mailbox']['tls_map_parameters'];?></label>
+ <div class="col-sm-10">
+ <input type="text" class="form-control" name="parameters">
+ <small><?=$lang['mailbox']['tls_map_parameters_info'];?></small>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-offset-2 col-sm-10">
+ <div class="checkbox">
+ <label><input type="checkbox" value="1" name="active" checked> <?=$lang['add']['active'];?></label>
+ </div>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-offset-2 col-sm-10">
+ <button class="btn btn-success" data-action="add_item" data-id="add_tls_policy_map" data-api-url='add/tls-policy-map' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+</div><!-- add add_tls_policy_map modal -->
<!-- log modal -->
<div class="modal fade" id="syncjobLogModal" tabindex="-1" role="dialog" aria-labelledby="syncjobLogModalLabel">
<div class="modal-dialog modal-lg" role="document">
diff --git a/data/web/user.php b/data/web/user.php
index 329a99c2..ebefadeb 100644
--- a/data/web/user.php
+++ b/data/web/user.php
@@ -394,7 +394,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
<div style="margin-bottom:200px;"></div>
<?php
}
-if (isset($_SESSION['mailcow_cc_role'])) {
+if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] != 'admin') {
require_once $_SERVER['DOCUMENT_ROOT'] . '/modals/user.php';
?>
<script type='text/javascript'>