[Web] Feature: Allow app passwords for imap/smtp, allow to set acl permission for app passwords (domain admin [when logged in as user] and user)
parent
0e6dfdd0fe
commit
653c058e33
|
@ -45,12 +45,25 @@ recipient_delimiter = +
|
||||||
auth_master_user_separator = *
|
auth_master_user_separator = *
|
||||||
mail_shared_explicit_inbox = yes
|
mail_shared_explicit_inbox = yes
|
||||||
mail_prefetch_count = 30
|
mail_prefetch_count = 30
|
||||||
|
# try a master passwd
|
||||||
passdb {
|
passdb {
|
||||||
driver = passwd-file
|
driver = passwd-file
|
||||||
args = /etc/dovecot/dovecot-master.passwd
|
args = /etc/dovecot/dovecot-master.passwd
|
||||||
master = yes
|
master = yes
|
||||||
pass = yes
|
pass = yes
|
||||||
|
result_failure = continue
|
||||||
|
result_internalfail = continue
|
||||||
}
|
}
|
||||||
|
# try an app passwd
|
||||||
|
passdb {
|
||||||
|
args = /etc/dovecot/sql/dovecot-dict-sql-app-passdb.conf
|
||||||
|
driver = sql
|
||||||
|
pass = yes
|
||||||
|
result_failure = continue
|
||||||
|
result_internalfail = continue
|
||||||
|
}
|
||||||
|
# check for regular password - if empty (e.g. force-passwd-reset), previous pass=yes passdbs also fail
|
||||||
|
# a return of the following passdb is mandatory
|
||||||
passdb {
|
passdb {
|
||||||
args = /etc/dovecot/sql/dovecot-dict-sql-passdb.conf
|
args = /etc/dovecot/sql/dovecot-dict-sql-passdb.conf
|
||||||
driver = sql
|
driver = sql
|
||||||
|
|
|
@ -98,6 +98,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||||
<p class="help-block">
|
<p class="help-block">
|
||||||
<?=$lang['admin']['customer_id'];?>: <?=(isset($_SESSION['gal']['c'])) ? $_SESSION['gal']['c'] : '?';?> -
|
<?=$lang['admin']['customer_id'];?>: <?=(isset($_SESSION['gal']['c'])) ? $_SESSION['gal']['c'] : '?';?> -
|
||||||
<?=$lang['admin']['service_id'];?>: <?=(isset($_SESSION['gal']['s'])) ? $_SESSION['gal']['s'] : '?';?>
|
<?=$lang['admin']['service_id'];?>: <?=(isset($_SESSION['gal']['s'])) ? $_SESSION['gal']['s'] : '?';?>
|
||||||
|
<?=$lang['admin']['sal_level'];?>: <?=(isset($_SESSION['gal']['m'])) ? $_SESSION['gal']['m'] : '?';?>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1314,6 +1314,54 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
elseif (isset($_GET['app-passwd']) &&
|
||||||
|
is_numeric($_GET['app-passwd'])) {
|
||||||
|
$id = $_GET["app-passwd"];
|
||||||
|
$result = app_passwd('details', $id);
|
||||||
|
if (!empty($result)) {
|
||||||
|
?>
|
||||||
|
<h4>App</h4>
|
||||||
|
<form class="form-horizontal" data-id="editapp" role="form" method="post">
|
||||||
|
<input type="hidden" value="0" name="active">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2" for="name">App</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" class="form-control" name="name" id="name" value="<?=htmlspecialchars($result['name'], ENT_QUOTES, 'UTF-8');?>" required maxlength="255">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2" for="password"><?=$lang['edit']['password'];?></label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="password" data-hibp="true" class="form-control" name="password" placeholder="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2" for="password2"><?=$lang['edit']['password_repeat'];?></label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="password" class="form-control" name="password2">
|
||||||
|
</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" <?=($result['active_int']=="1") ? "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="editapp" data-item="<?=htmlspecialchars($result['id']);?>" data-api-url='edit/app-passwd' 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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -0,0 +1,210 @@
|
||||||
|
<?php
|
||||||
|
function app_passwd($_action, $_data = null) {
|
||||||
|
global $pdo;
|
||||||
|
global $lang;
|
||||||
|
$_data_log = $_data;
|
||||||
|
if (isset($_data['username']) && filter_var($_data['username'], FILTER_VALIDATE_EMAIL)) {
|
||||||
|
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data['username'])) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
|
'msg' => 'access_denied'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$username = $_data['username'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$username = $_SESSION['mailcow_cc_username'];
|
||||||
|
}
|
||||||
|
switch ($_action) {
|
||||||
|
case 'add':
|
||||||
|
$name = trim($_data['name']);
|
||||||
|
$password = $_data['password'];
|
||||||
|
$password2 = $_data['password2'];
|
||||||
|
$active = intval($_data['active']);
|
||||||
|
$domain = mailbox('get', 'mailbox_details', $username)['domain'];
|
||||||
|
if (empty($domain)) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
|
'msg' => 'access_denied'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!empty($password) && !empty($password2)) {
|
||||||
|
if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
|
'msg' => 'password_complexity'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($password != $password2) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
|
'msg' => 'password_mismatch'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$password_hashed = hash_password($password);
|
||||||
|
}
|
||||||
|
if (empty($name)) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
|
'msg' => 'app_name_empty'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `app_passwd` (`name`, `mailbox`, `domain`, `password`, `active`)
|
||||||
|
VALUES (:name, :mailbox, :domain, :password, :active)");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':name' => $name,
|
||||||
|
':mailbox' => $mailbox,
|
||||||
|
':domain' => $domain,
|
||||||
|
':password' => $password,
|
||||||
|
':active' => $active
|
||||||
|
));
|
||||||
|
}
|
||||||
|
catch (PDOException $e) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
|
'msg' => array('mysql_error', $e)
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
|
'msg' => 'app_passwd_added'
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'edit':
|
||||||
|
$ids = (array)$_data['id'];
|
||||||
|
foreach ($ids as $id) {
|
||||||
|
$is_now = app_passwd('details', $id);
|
||||||
|
if (!empty($is_now)) {
|
||||||
|
$name = (!empty($_data['name'])) ? $_data['name'] : $is_now['name'];
|
||||||
|
$password = (!empty($_data['password'])) ? $_data['password'] : null;
|
||||||
|
$password2 = (!empty($_data['password2'])) ? $_data['password2'] : null;
|
||||||
|
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active_int'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
|
'msg' => array('settings_map_invalid', $id)
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$name = trim($name);
|
||||||
|
if (!empty($password) && !empty($password2)) {
|
||||||
|
if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => 'password_complexity'
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($password != $password2) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => 'password_mismatch'
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$password_hashed = hash_password($password);
|
||||||
|
$stmt = $pdo->prepare("UPDATE `app_passwd` SET
|
||||||
|
`password` = :password_hashed
|
||||||
|
WHERE `mailbox` = :username AND `id` = :id");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':password_hashed' => $password_hashed,
|
||||||
|
':username' => $username,
|
||||||
|
':id' => $id
|
||||||
|
));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("UPDATE `app_passwd` SET
|
||||||
|
`name` = :name,
|
||||||
|
`mailbox` = :username,
|
||||||
|
`active` = :active
|
||||||
|
WHERE `id` = :id");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':name' => $name,
|
||||||
|
':username' => $username,
|
||||||
|
':active' => $active,
|
||||||
|
':id' => $id
|
||||||
|
));
|
||||||
|
}
|
||||||
|
catch (PDOException $e) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
|
'msg' => array('mysql_error', $e)
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
|
'msg' => array('object_modified', htmlspecialchars($ids))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
$ids = (array)$_data['id'];
|
||||||
|
foreach ($ids as $id) {
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM `app_passwd` WHERE `id`= :id AND `mailbox`= :username");
|
||||||
|
$stmt->execute(array(':id' => $id, ':username' => $username));
|
||||||
|
}
|
||||||
|
catch (PDOException $e) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
|
'msg' => array('mysql_error', $e)
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
|
'msg' => array('app_passwd_removed', htmlspecialchars($id))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'get':
|
||||||
|
$app_passwds = array();
|
||||||
|
$stmt = $pdo->prepare("SELECT `id`, `name` FROM `app_passwd` WHERE `mailbox` = :username");
|
||||||
|
$stmt->execute(array(':username' => $username));
|
||||||
|
$app_passwds = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
return $app_passwds;
|
||||||
|
break;
|
||||||
|
case 'details':
|
||||||
|
$app_passwd_data = array();
|
||||||
|
$stmt = $pdo->prepare("SELECT `id`,
|
||||||
|
`name`,
|
||||||
|
`mailbox`,
|
||||||
|
`domain`,
|
||||||
|
`created`,
|
||||||
|
`modified`,
|
||||||
|
`active` AS `active_int`,
|
||||||
|
CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`
|
||||||
|
FROM `app_passwd`
|
||||||
|
WHERE `id` = :id
|
||||||
|
AND `mailbox` = :username");
|
||||||
|
$stmt->execute(array(':id' => $_data, ':username' => $username));
|
||||||
|
$app_passwd_data = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
return $app_passwd_data;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1260,17 +1260,20 @@ function license($action, $data = null) {
|
||||||
$_SESSION['gal']['valid'] = "true";
|
$_SESSION['gal']['valid'] = "true";
|
||||||
$_SESSION['gal']['c'] = $json_return['c'];
|
$_SESSION['gal']['c'] = $json_return['c'];
|
||||||
$_SESSION['gal']['s'] = $json_return['s'];
|
$_SESSION['gal']['s'] = $json_return['s'];
|
||||||
}
|
$_SESSION['gal']['m'] = str_repeat('🐄', substr_count($json_return['m'], 'o'));
|
||||||
|
}
|
||||||
elseif ($json_return['response'] === "invalid") {
|
elseif ($json_return['response'] === "invalid") {
|
||||||
$_SESSION['gal']['valid'] = "false";
|
$_SESSION['gal']['valid'] = "false";
|
||||||
$_SESSION['gal']['c'] = $lang['mailbox']['no'];
|
$_SESSION['gal']['c'] = $lang['mailbox']['no'];
|
||||||
$_SESSION['gal']['s'] = $lang['mailbox']['no'];
|
$_SESSION['gal']['s'] = $lang['mailbox']['no'];
|
||||||
|
$_SESSION['gal']['m'] = $lang['mailbox']['no'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$_SESSION['gal']['valid'] = "false";
|
$_SESSION['gal']['valid'] = "false";
|
||||||
$_SESSION['gal']['c'] = $lang['danger']['temp_error'];
|
$_SESSION['gal']['c'] = $lang['danger']['temp_error'];
|
||||||
$_SESSION['gal']['s'] = $lang['danger']['temp_error'];
|
$_SESSION['gal']['s'] = $lang['danger']['temp_error'];
|
||||||
|
$_SESSION['gal']['m'] = $lang['danger']['temp_error'];
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// json_encode needs "true"/"false" instead of true/false, to not encode it to 0 or 1
|
// json_encode needs "true"/"false" instead of true/false, to not encode it to 0 or 1
|
||||||
|
|
|
@ -3,7 +3,7 @@ function init_db_schema() {
|
||||||
try {
|
try {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
|
|
||||||
$db_version = "06112019_1840";
|
$db_version = "01122019_0755";
|
||||||
|
|
||||||
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
||||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||||
|
@ -321,6 +321,37 @@ function init_db_schema() {
|
||||||
),
|
),
|
||||||
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
||||||
),
|
),
|
||||||
|
"app_passwd" => array(
|
||||||
|
"cols" => array(
|
||||||
|
"id" => "INT NOT NULL AUTO_INCREMENT",
|
||||||
|
"name" => "VARCHAR(255) NOT NULL",
|
||||||
|
"mailbox" => "VARCHAR(255) NOT NULL",
|
||||||
|
"domain" => "VARCHAR(255) NOT NULL",
|
||||||
|
"password" => "VARCHAR(255) NOT NULL",
|
||||||
|
"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")
|
||||||
|
),
|
||||||
|
"key" => array(
|
||||||
|
"mailbox" => array("mailbox"),
|
||||||
|
"password" => array("password"),
|
||||||
|
"domain" => array("domain"),
|
||||||
|
),
|
||||||
|
"fkey" => array(
|
||||||
|
"fk_username_app_passwd" => array(
|
||||||
|
"col" => "mailbox",
|
||||||
|
"ref" => "mailbox.username",
|
||||||
|
"delete" => "CASCADE",
|
||||||
|
"update" => "NO ACTION"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
||||||
|
),
|
||||||
"user_acl" => array(
|
"user_acl" => array(
|
||||||
"cols" => array(
|
"cols" => array(
|
||||||
"username" => "VARCHAR(255) NOT NULL",
|
"username" => "VARCHAR(255) NOT NULL",
|
||||||
|
@ -335,6 +366,7 @@ function init_db_schema() {
|
||||||
"quarantine" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
"quarantine" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||||
"quarantine_attachments" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
"quarantine_attachments" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||||
"quarantine_notification" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
"quarantine_notification" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||||
|
"app_passwds" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||||
),
|
),
|
||||||
"keys" => array(
|
"keys" => array(
|
||||||
"primary" => array(
|
"primary" => array(
|
||||||
|
@ -475,6 +507,7 @@ function init_db_schema() {
|
||||||
"quarantine" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
"quarantine" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||||
"login_as" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
"login_as" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||||
"sogo_access" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
"sogo_access" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||||
|
"app_passwds" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||||
"bcc_maps" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
"bcc_maps" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||||
"filters" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
"filters" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||||
"ratelimit" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
"ratelimit" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||||
|
|
|
@ -205,6 +205,7 @@ if(file_exists($langFile)) {
|
||||||
|
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.inc.php';
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.acl.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.acl.inc.php';
|
||||||
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.app_passwd.inc.php';
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.mailbox.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.mailbox.inc.php';
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.customize.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.customize.inc.php';
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.address_rewriting.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.address_rewriting.inc.php';
|
||||||
|
|
|
@ -156,6 +156,51 @@ jQuery(function($){
|
||||||
"toggleSelector": "table tbody span.footable-toggle"
|
"toggleSelector": "table tbody span.footable-toggle"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function draw_app_passwd_table() {
|
||||||
|
ft_apppasswd_table = FooTable.init('#app_passwd_table', {
|
||||||
|
"columns": [
|
||||||
|
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
|
||||||
|
{"sorted": true,"name":"id","title":"ID","style":{"maxWidth":"60px","width":"60px","text-align":"center"}},
|
||||||
|
{"name":"name","title":lang.app_name},
|
||||||
|
{"name":"active","filterable": false,"style":{"maxWidth":"70px","width":"70px"},"title":lang.active},
|
||||||
|
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
|
||||||
|
],
|
||||||
|
"empty": lang.empty,
|
||||||
|
"rows": $.ajax({
|
||||||
|
dataType: 'json',
|
||||||
|
url: '/api/v1/get/app-passwd/all',
|
||||||
|
jsonp: false,
|
||||||
|
error: function () {
|
||||||
|
console.log('Cannot draw app passwd table');
|
||||||
|
},
|
||||||
|
success: function (data) {
|
||||||
|
$.each(data, function (i, item) {
|
||||||
|
if (acl_data.app_passwds === 1) {
|
||||||
|
item.action = '<div class="btn-group">' +
|
||||||
|
'<a href="/edit/app-passwd/' + 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-apppasswd" data-api-url="delete/app-passwd" 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="apppasswd" name="multi_select" value="' + item.id + '" />';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item.action = '<span>-</span>';
|
||||||
|
item.chkbox = '<input type="checkbox" disabled />';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
"paging": {
|
||||||
|
"enabled": true,
|
||||||
|
"limit": 5,
|
||||||
|
"size": pagination_size
|
||||||
|
},
|
||||||
|
"state": {"enabled": true},
|
||||||
|
"sorting": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"toggleSelector": "table tbody span.footable-toggle"
|
||||||
|
});
|
||||||
|
}
|
||||||
function draw_wl_policy_mailbox_table() {
|
function draw_wl_policy_mailbox_table() {
|
||||||
ft_wl_policy_mailbox_table = FooTable.init('#wl_policy_mailbox_table', {
|
ft_wl_policy_mailbox_table = FooTable.init('#wl_policy_mailbox_table', {
|
||||||
"columns": [
|
"columns": [
|
||||||
|
@ -244,6 +289,7 @@ jQuery(function($){
|
||||||
})
|
})
|
||||||
|
|
||||||
draw_sync_job_table();
|
draw_sync_job_table();
|
||||||
|
draw_app_passwd_table();
|
||||||
draw_tla_table();
|
draw_tla_table();
|
||||||
draw_wl_policy_mailbox_table();
|
draw_wl_policy_mailbox_table();
|
||||||
draw_bl_policy_mailbox_table();
|
draw_bl_policy_mailbox_table();
|
||||||
|
|
|
@ -206,6 +206,9 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
|
||||||
case "tls-policy-map":
|
case "tls-policy-map":
|
||||||
process_add_return(tls_policy_maps('add', $attr));
|
process_add_return(tls_policy_maps('add', $attr));
|
||||||
break;
|
break;
|
||||||
|
case "app-passwd":
|
||||||
|
process_add_return(app_passwd('add', $attr));
|
||||||
|
break;
|
||||||
// return no route found if no case is matched
|
// return no route found if no case is matched
|
||||||
default:
|
default:
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
|
@ -282,6 +285,33 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "app-passwd":
|
||||||
|
switch ($object) {
|
||||||
|
case "all":
|
||||||
|
$app_passwds = app_passwd('get');
|
||||||
|
if (!empty($app_passwds)) {
|
||||||
|
foreach ($app_passwds as $app_passwd) {
|
||||||
|
if ($details = app_passwd('details', $app_passwd['id'])) {
|
||||||
|
$data[] = $details;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
process_get_return($data);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
echo '{}';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$data = app_passwd('details', $object);
|
||||||
|
process_get_return($data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case "mailq":
|
case "mailq":
|
||||||
switch ($object) {
|
switch ($object) {
|
||||||
case "all":
|
case "all":
|
||||||
|
@ -1121,6 +1151,9 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
|
||||||
case "oauth2-client":
|
case "oauth2-client":
|
||||||
process_delete_return(oauth2('delete', 'client', array('id' => $items)));
|
process_delete_return(oauth2('delete', 'client', array('id' => $items)));
|
||||||
break;
|
break;
|
||||||
|
case "app-passwd":
|
||||||
|
process_delete_return(app_passwd('delete', array('id' => $items)));
|
||||||
|
break;
|
||||||
case "relayhost":
|
case "relayhost":
|
||||||
process_delete_return(relayhost('delete', array('id' => $items)));
|
process_delete_return(relayhost('delete', array('id' => $items)));
|
||||||
break;
|
break;
|
||||||
|
@ -1249,6 +1282,9 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
|
||||||
case "recipient_map":
|
case "recipient_map":
|
||||||
process_edit_return(recipient_map('edit', array_merge(array('id' => $items), $attr)));
|
process_edit_return(recipient_map('edit', array_merge(array('id' => $items), $attr)));
|
||||||
break;
|
break;
|
||||||
|
case "app-passwd":
|
||||||
|
process_edit_return(app_passwd('edit', array_merge(array('id' => $items), $attr)));
|
||||||
|
break;
|
||||||
case "tls-policy-map":
|
case "tls-policy-map":
|
||||||
process_edit_return(tls_policy_maps('edit', array_merge(array('id' => $items), $attr)));
|
process_edit_return(tls_policy_maps('edit', array_merge(array('id' => $items), $attr)));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -56,7 +56,9 @@
|
||||||
"bcc_exists": "Ein BCC Map Eintrag %s existiert bereits als Typ %s",
|
"bcc_exists": "Ein BCC Map Eintrag %s existiert bereits als Typ %s",
|
||||||
"private_key_error": "Schlüsselfehler: %s",
|
"private_key_error": "Schlüsselfehler: %s",
|
||||||
"map_content_empty": "Inhalt darf nicht leer sein",
|
"map_content_empty": "Inhalt darf nicht leer sein",
|
||||||
|
"app_name_empty": "App Name darf nicht leer sein",
|
||||||
"settings_map_invalid": "Regel ID %s ist ungültig",
|
"settings_map_invalid": "Regel ID %s ist ungültig",
|
||||||
|
"app_passwd_id_invalid": "App Passwort ID %s ist ungültig",
|
||||||
"global_map_invalid": "Rspamd Map %s ist ungültig",
|
"global_map_invalid": "Rspamd Map %s ist ungültig",
|
||||||
"global_map_write_error": "Kann globale Map ID %s nicht schreiben: %s",
|
"global_map_write_error": "Kann globale Map ID %s nicht schreiben: %s",
|
||||||
"invalid_host": "Ungültiger Host: %s",
|
"invalid_host": "Ungültiger Host: %s",
|
||||||
|
@ -144,7 +146,9 @@
|
||||||
"bcc_edited": "BCC Map Eintrag %s wurde geändert",
|
"bcc_edited": "BCC Map Eintrag %s wurde geändert",
|
||||||
"bcc_deleted": "BCC Map Einträge gelöscht: %s",
|
"bcc_deleted": "BCC Map Einträge gelöscht: %s",
|
||||||
"settings_map_added": "Regel wurde gespeichert",
|
"settings_map_added": "Regel wurde gespeichert",
|
||||||
|
"app_passwd_added": "App Password wurde gespeichert",
|
||||||
"settings_map_removed": "Regeln wurden entfernt: %s",
|
"settings_map_removed": "Regeln wurden entfernt: %s",
|
||||||
|
"app_passwd_removed": "App Passwort ID %s wurde entfernt",
|
||||||
"saved_settings": "Regel wurde gespeichert",
|
"saved_settings": "Regel wurde gespeichert",
|
||||||
"dkim_removed": "DKIM-Key %s wurde entfernt",
|
"dkim_removed": "DKIM-Key %s wurde entfernt",
|
||||||
"dkim_added": "DKIM-Key %s wurde hinzugefügt",
|
"dkim_added": "DKIM-Key %s wurde hinzugefügt",
|
||||||
|
@ -212,6 +216,10 @@
|
||||||
"session_ua": "Formular-Token ungültig: User-Agent-Validierungsfehler"
|
"session_ua": "Formular-Token ungültig: User-Agent-Validierungsfehler"
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
|
"create_app_passwd": "Erstelle App Passwort",
|
||||||
|
"app_passwds": "App Passwörter",
|
||||||
|
"app_name": "App Name",
|
||||||
|
"app_hint": "App Passwörter sind alternative Passwörter für den <b>IMAP und SMTP</b> Login am Mailserver. Der Benutzername bleibt unverändert.<br>SOGo (und damit ActiveSync) ist mit diesem Kennwort nicht verwendbar.",
|
||||||
"loading": "Lade...",
|
"loading": "Lade...",
|
||||||
"force_pw_update": "Das Passwort für diesen Benutzer <b>muss</b> geändert werden, damit die Zugriffssperre auf die Groupwarekomponenten wieder freigeschaltet wird.",
|
"force_pw_update": "Das Passwort für diesen Benutzer <b>muss</b> geändert werden, damit die Zugriffssperre auf die Groupwarekomponenten wieder freigeschaltet wird.",
|
||||||
"active_sieve": "Aktiver Filter",
|
"active_sieve": "Aktiver Filter",
|
||||||
|
@ -224,8 +232,10 @@
|
||||||
"change_password": "Passwort ändern",
|
"change_password": "Passwort ändern",
|
||||||
"client_configuration": "Konfigurationsanleitungen für E-Mail-Programme und Smartphones anzeigen",
|
"client_configuration": "Konfigurationsanleitungen für E-Mail-Programme und Smartphones anzeigen",
|
||||||
"new_password": "Neues Passwort",
|
"new_password": "Neues Passwort",
|
||||||
|
"password": "Passwort",
|
||||||
"save_changes": "Änderungen speichern",
|
"save_changes": "Änderungen speichern",
|
||||||
"password_now": "Aktuelles Passwort (Änderungen bestätigen)",
|
"password_now": "Aktuelles Passwort (Änderungen bestätigen)",
|
||||||
|
"password_repeat": "Passwort (Wiederholung)",
|
||||||
"new_password_repeat": "Neues Passwort (Wiederholung)",
|
"new_password_repeat": "Neues Passwort (Wiederholung)",
|
||||||
"new_password_description": "Mindestanforderung: 6 Zeichen lang, Buchstaben und Zahlen.",
|
"new_password_description": "Mindestanforderung: 6 Zeichen lang, Buchstaben und Zahlen.",
|
||||||
"spam_aliases": "Temporäre E-Mail Aliasse",
|
"spam_aliases": "Temporäre E-Mail Aliasse",
|
||||||
|
@ -475,6 +485,7 @@
|
||||||
"validate_license_now": "GUID erneut verifizieren",
|
"validate_license_now": "GUID erneut verifizieren",
|
||||||
"customer_id": "Kunde",
|
"customer_id": "Kunde",
|
||||||
"service_id": "Service",
|
"service_id": "Service",
|
||||||
|
"sal_level": "Moo-Level",
|
||||||
"lookup_mx": "Ziel gegen MX prüfen (etwa .outlook.com, um alle Ziele mit MX *.outlook.com zu routen)",
|
"lookup_mx": "Ziel gegen MX prüfen (etwa .outlook.com, um alle Ziele mit MX *.outlook.com zu routen)",
|
||||||
"transport_dest_format": "Syntax: example.org, .example.org, *, box@example.org (mehrere Werte getrennt durch Komma einzugeben)",
|
"transport_dest_format": "Syntax: example.org, .example.org, *, box@example.org (mehrere Werte getrennt durch Komma einzugeben)",
|
||||||
"rspamd_global_filters_agree": "Ich werde vorsichtig sein!",
|
"rspamd_global_filters_agree": "Ich werde vorsichtig sein!",
|
||||||
|
@ -745,6 +756,8 @@
|
||||||
"generate": "generieren",
|
"generate": "generieren",
|
||||||
"syncjob": "Syncjob hinzufügen",
|
"syncjob": "Syncjob hinzufügen",
|
||||||
"syncjob_hint": "Passwörter werden unverschlüsselt abgelegt!",
|
"syncjob_hint": "Passwörter werden unverschlüsselt abgelegt!",
|
||||||
|
"app_password": "App Passwort hinzufügen",
|
||||||
|
"app_name": "App Name",
|
||||||
"hostname": "Host",
|
"hostname": "Host",
|
||||||
"destination": "Ziel",
|
"destination": "Ziel",
|
||||||
"nexthop": "Next Hop",
|
"nexthop": "Next Hop",
|
||||||
|
@ -824,7 +837,8 @@
|
||||||
"unlimited_quota": "Unendliche Quota für Mailboxen",
|
"unlimited_quota": "Unendliche Quota für Mailboxen",
|
||||||
"extend_sender_acl": "Eingabe externer Absenderadressen erlauben",
|
"extend_sender_acl": "Eingabe externer Absenderadressen erlauben",
|
||||||
"prohibited": "Untersagt durch Richtlinie",
|
"prohibited": "Untersagt durch Richtlinie",
|
||||||
"sogo_access": "Verwalten des SOGo Zugriffsrechts erlauben"
|
"sogo_access": "Verwalten des SOGo Zugriffsrechts erlauben",
|
||||||
|
"app_passwds": "App Passwörter verwalten"
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"username": "Benutzername",
|
"username": "Benutzername",
|
||||||
|
|
|
@ -56,7 +56,9 @@
|
||||||
"bcc_exists": "A BCC map %s exists for type %s",
|
"bcc_exists": "A BCC map %s exists for type %s",
|
||||||
"private_key_error": "Private key error: %s",
|
"private_key_error": "Private key error: %s",
|
||||||
"map_content_empty": "Map content cannot be empty",
|
"map_content_empty": "Map content cannot be empty",
|
||||||
|
"app_name_empty": "App name cannot be empty",
|
||||||
"settings_map_invalid": "Settings map ID %s invalid",
|
"settings_map_invalid": "Settings map ID %s invalid",
|
||||||
|
"app_passwd_id_invalid": "App password ID %s invalid",
|
||||||
"global_map_invalid": "Global map ID %s invalid",
|
"global_map_invalid": "Global map ID %s invalid",
|
||||||
"global_map_write_error": "Could not write global map ID %s: %s",
|
"global_map_write_error": "Could not write global map ID %s: %s",
|
||||||
"invalid_host": "Invalid host specified: %s",
|
"invalid_host": "Invalid host specified: %s",
|
||||||
|
@ -144,7 +146,9 @@
|
||||||
"bcc_edited": "BCC map entry %s edited",
|
"bcc_edited": "BCC map entry %s edited",
|
||||||
"bcc_deleted": "BCC map entries deleted: %s",
|
"bcc_deleted": "BCC map entries deleted: %s",
|
||||||
"settings_map_added": "Added settings map entry",
|
"settings_map_added": "Added settings map entry",
|
||||||
|
"app_passwd_added": "Added new app password",
|
||||||
"settings_map_removed": "Removed settings map ID %s",
|
"settings_map_removed": "Removed settings map ID %s",
|
||||||
|
"app_passwd_removed": "Removed app password ID %s",
|
||||||
"saved_settings": "Saved settings",
|
"saved_settings": "Saved settings",
|
||||||
"db_init_complete": "Database initialization completed",
|
"db_init_complete": "Database initialization completed",
|
||||||
"dkim_removed": "DKIM key %s has been removed",
|
"dkim_removed": "DKIM key %s has been removed",
|
||||||
|
@ -212,6 +216,10 @@
|
||||||
"ip_invalid": "Skipped invalid IP: %s"
|
"ip_invalid": "Skipped invalid IP: %s"
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
|
"create_app_passwd": "Create app password",
|
||||||
|
"app_passwds": "App passwords",
|
||||||
|
"app_name": "App name",
|
||||||
|
"app_hint": "App passwords are alternative passwords for your <b>IMAP and SMTP</b> login. The username remains unchanged.<br>SOGo (including ActiveSync) is not available through app passwords.",
|
||||||
"loading": "Loading...",
|
"loading": "Loading...",
|
||||||
"force_pw_update": "You <b>must</b> set a new password to be able to access groupware related services.",
|
"force_pw_update": "You <b>must</b> set a new password to be able to access groupware related services.",
|
||||||
"active_sieve": "Active filter",
|
"active_sieve": "Active filter",
|
||||||
|
@ -224,9 +232,11 @@
|
||||||
"change_password": "Change password",
|
"change_password": "Change password",
|
||||||
"client_configuration": "Show configuration guides for email clients and smartphones",
|
"client_configuration": "Show configuration guides for email clients and smartphones",
|
||||||
"new_password": "New password",
|
"new_password": "New password",
|
||||||
|
"password": "password",
|
||||||
"save_changes": "Save changes",
|
"save_changes": "Save changes",
|
||||||
"password_now": "Current password (confirm changes)",
|
"password_now": "Current password (confirm changes)",
|
||||||
"new_password_repeat": "Confirmation password (repeat)",
|
"new_password_repeat": "Confirmation password (repeat)",
|
||||||
|
"password_repeat": "Password (repeat)",
|
||||||
"new_password_description": "Requirement: 6 characters long, letters and numbers.",
|
"new_password_description": "Requirement: 6 characters long, letters and numbers.",
|
||||||
"spam_aliases": "Temporary email aliases",
|
"spam_aliases": "Temporary email aliases",
|
||||||
"alias": "Alias",
|
"alias": "Alias",
|
||||||
|
@ -487,6 +497,7 @@
|
||||||
"validate_license_now": "Validate GUID against license server",
|
"validate_license_now": "Validate GUID against license server",
|
||||||
"customer_id": "Customer ID",
|
"customer_id": "Customer ID",
|
||||||
"service_id": "Service ID",
|
"service_id": "Service ID",
|
||||||
|
"sal_level": "Moo level",
|
||||||
"lookup_mx": "Match destination against MX (.outlook.com to route all mail targeted to a MX *.outlook.com over this hop)",
|
"lookup_mx": "Match destination against MX (.outlook.com to route all mail targeted to a MX *.outlook.com over this hop)",
|
||||||
"transport_dest_format": "Syntax: example.org, .example.org, *, box@example.org (multiple values can be comma-separated)",
|
"transport_dest_format": "Syntax: example.org, .example.org, *, box@example.org (multiple values can be comma-separated)",
|
||||||
"rspamd_global_filters_agree": "I will be careful!",
|
"rspamd_global_filters_agree": "I will be careful!",
|
||||||
|
@ -748,6 +759,8 @@
|
||||||
"destination": "Destination",
|
"destination": "Destination",
|
||||||
"nexthop": "Next hop",
|
"nexthop": "Next hop",
|
||||||
"port": "Port",
|
"port": "Port",
|
||||||
|
"app_name": "App name",
|
||||||
|
"app_password": "Add app password",
|
||||||
"username": "Username",
|
"username": "Username",
|
||||||
"enc_method": "Encryption method",
|
"enc_method": "Encryption method",
|
||||||
"mins_interval": "Polling interval (minutes)",
|
"mins_interval": "Polling interval (minutes)",
|
||||||
|
@ -824,6 +837,7 @@
|
||||||
"extend_sender_acl": "Allow to extend sender ACL by external addresses",
|
"extend_sender_acl": "Allow to extend sender ACL by external addresses",
|
||||||
"prohibited": "Prohibited by ACL",
|
"prohibited": "Prohibited by ACL",
|
||||||
"sogo_access": "Allow management of SOGo access"
|
"sogo_access": "Allow management of SOGo access"
|
||||||
|
"app_passwds": "Manage app passwords"
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"username": "Username",
|
"username": "Username",
|
||||||
|
|
|
@ -162,6 +162,52 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div><!-- add sync job modal -->
|
</div><!-- add sync job modal -->
|
||||||
|
<!-- app passwd modal -->
|
||||||
|
<div class="modal fade" id="addAppPasswdModal" 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['add']['app_password'];?></h3>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form class="form-horizontal" data-cached-form="true" role="form" data-id="add_syncjob">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2" for="app_name"><?=$lang['add']['app_name'];?></label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" class="form-control" name="app_name" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2" for="app_passwd"><?=$lang['user']['password'];?></label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="password" data-hibp="true" class="form-control" name="app_passwd" autocomplete="off" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2" for="app_passwd2"><?=$lang['user']['password_repeat'];?></label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="password" class="form-control" name="app_passwd2" autocomplete="off" required>
|
||||||
|
<p class="help-block"><?=$lang['user']['new_password_description'];?></p>
|
||||||
|
</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-default" data-action="add_item" data-id="add_syncjob" data-api-url='add/syncjob' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!-- add app passwd modal -->
|
||||||
<!-- log modal -->
|
<!-- log modal -->
|
||||||
<div class="modal fade" id="syncjobLogModal" tabindex="-1" role="dialog" aria-labelledby="syncjobLogModalLabel">
|
<div class="modal fade" id="syncjobLogModal" tabindex="-1" role="dialog" aria-labelledby="syncjobLogModalLabel">
|
||||||
<div class="modal-dialog modal-lg" role="document">
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
|
|
|
@ -100,6 +100,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
|
||||||
<li role="presentation"><a href="#SpamAliases" aria-controls="SpamAliases" role="tab" data-toggle="tab"><?=$lang['user']['spam_aliases'];?></a></li>
|
<li role="presentation"><a href="#SpamAliases" aria-controls="SpamAliases" role="tab" data-toggle="tab"><?=$lang['user']['spam_aliases'];?></a></li>
|
||||||
<li role="presentation"><a href="#Spamfilter" aria-controls="Spamfilter" role="tab" data-toggle="tab"><?=$lang['user']['spamfilter'];?></a></li>
|
<li role="presentation"><a href="#Spamfilter" aria-controls="Spamfilter" role="tab" data-toggle="tab"><?=$lang['user']['spamfilter'];?></a></li>
|
||||||
<li role="presentation"><a href="#Syncjobs" aria-controls="Syncjobs" role="tab" data-toggle="tab"><?=$lang['user']['sync_jobs'];?></a></li>
|
<li role="presentation"><a href="#Syncjobs" aria-controls="Syncjobs" role="tab" data-toggle="tab"><?=$lang['user']['sync_jobs'];?></a></li>
|
||||||
|
<li role="presentation"><a href="#AppPasswds" aria-controls="AppPasswds" role="tab" data-toggle="tab"><?=$lang['user']['app_passwds'];?></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
|
@ -459,7 +460,28 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
|
||||||
<a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addSyncJobModal"><span class="glyphicon glyphicon-plus"></span> <?=$lang['user']['create_syncjob'];?></a>
|
<a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addSyncJobModal"><span class="glyphicon glyphicon-plus"></span> <?=$lang['user']['create_syncjob'];?></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div role="tabpanel" class="tab-pane" id="AppPasswds">
|
||||||
|
<p><?=$lang['user']['app_hint'];?></p>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped" id="app_passwd_table"></table>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mass-actions-user">
|
||||||
|
<div class="btn-group" data-acl="<?=$_SESSION['acl']['app_passwds'];?>">
|
||||||
|
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="apppasswd" 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="apppasswd" data-api-url='edit/app-passwd' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
|
||||||
|
<li><a data-action="edit_selected" data-id="apppasswd" data-api-url='edit/app-passwd' 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="apppasswd" data-api-url='delete/app-passwd' href="#"><?=$lang['mailbox']['remove'];?></a></li>
|
||||||
|
</ul>
|
||||||
|
<a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addAppPasswdModal"><span class="glyphicon glyphicon-plus"></span> <?=$lang['user']['create_app_passwd'];?></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div><!-- /container -->
|
</div><!-- /container -->
|
||||||
|
|
Loading…
Reference in New Issue