renormalized line endings with git config core.autocrlf true && git add --renormalize .

This commit is contained in:
Thorbjörn Jörger 2023-03-30 10:13:31 +02:00
parent ae46a877d3
commit b5f49afdba
No known key found for this signature in database
GPG Key ID: 82701519391A1DCD
59 changed files with 19210 additions and 19210 deletions

View File

@ -1,20 +1,20 @@
[supervisord] [supervisord]
nodaemon=true nodaemon=true
user=root user=root
pidfile=/var/run/supervisord.pid pidfile=/var/run/supervisord.pid
[program:syslog-ng] [program:syslog-ng]
command=/usr/sbin/syslog-ng --foreground --no-caps command=/usr/sbin/syslog-ng --foreground --no-caps
stdout_logfile=/dev/stdout stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0 stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0 stderr_logfile_maxbytes=0
autostart=true autostart=true
[program:dovecot] [program:dovecot]
command=/usr/sbin/dovecot -F command=/usr/sbin/dovecot -F
autorestart=true autorestart=true
[eventlistener:processes] [eventlistener:processes]
command=/usr/local/sbin/stop-supervisor.sh command=/usr/local/sbin/stop-supervisor.sh
events=PROCESS_STATE_STOPPED, PROCESS_STATE_EXITED, PROCESS_STATE_FATAL events=PROCESS_STATE_STOPPED, PROCESS_STATE_EXITED, PROCESS_STATE_FATAL

File diff suppressed because it is too large Load Diff

View File

@ -1,293 +1,293 @@
namespace inbox { namespace inbox {
inbox = yes inbox = yes
location = location =
separator = / separator = /
mailbox "Trash" { mailbox "Trash" {
auto = subscribe auto = subscribe
special_use = \Trash special_use = \Trash
} }
mailbox "Deleted Messages" { mailbox "Deleted Messages" {
special_use = \Trash special_use = \Trash
} }
mailbox "Deleted Items" { mailbox "Deleted Items" {
special_use = \Trash special_use = \Trash
} }
mailbox "Rubbish" { mailbox "Rubbish" {
special_use = \Trash special_use = \Trash
} }
mailbox "Gelöschte Objekte" { mailbox "Gelöschte Objekte" {
special_use = \Trash special_use = \Trash
} }
mailbox "Gelöschte Elemente" { mailbox "Gelöschte Elemente" {
special_use = \Trash special_use = \Trash
} }
mailbox "Papierkorb" { mailbox "Papierkorb" {
special_use = \Trash special_use = \Trash
} }
mailbox "Itens Excluidos" { mailbox "Itens Excluidos" {
special_use = \Trash special_use = \Trash
} }
mailbox "Itens Excluídos" { mailbox "Itens Excluídos" {
special_use = \Trash special_use = \Trash
} }
mailbox "Lixeira" { mailbox "Lixeira" {
special_use = \Trash special_use = \Trash
} }
mailbox "Prullenbak" { mailbox "Prullenbak" {
special_use = \Trash special_use = \Trash
} }
mailbox "Odstránené položky" { mailbox "Odstránené položky" {
special_use = \Trash special_use = \Trash
} }
mailbox "Koš" { mailbox "Koš" {
special_use = \Trash special_use = \Trash
} }
mailbox "Verwijderde items" { mailbox "Verwijderde items" {
special_use = \Trash special_use = \Trash
} }
mailbox "Удаленные" { mailbox "Удаленные" {
special_use = \Trash special_use = \Trash
} }
mailbox "Удаленные элементы" { mailbox "Удаленные элементы" {
special_use = \Trash special_use = \Trash
} }
mailbox "Корзина" { mailbox "Корзина" {
special_use = \Trash special_use = \Trash
} }
mailbox "Видалені" { mailbox "Видалені" {
special_use = \Trash special_use = \Trash
} }
mailbox "Видалені елементи" { mailbox "Видалені елементи" {
special_use = \Trash special_use = \Trash
} }
mailbox "Кошик" { mailbox "Кошик" {
special_use = \Trash special_use = \Trash
} }
mailbox "废件箱" { mailbox "废件箱" {
special_use = \Trash special_use = \Trash
} }
mailbox "已删除消息" { mailbox "已删除消息" {
special_use = \Trash special_use = \Trash
} }
mailbox "已删除邮件" { mailbox "已删除邮件" {
special_use = \Trash special_use = \Trash
} }
mailbox "Archive" { mailbox "Archive" {
auto = subscribe auto = subscribe
special_use = \Archive special_use = \Archive
} }
mailbox "Archiv" { mailbox "Archiv" {
special_use = \Archive special_use = \Archive
} }
mailbox "Archives" { mailbox "Archives" {
special_use = \Archive special_use = \Archive
} }
mailbox "Arquivo" { mailbox "Arquivo" {
special_use = \Archive special_use = \Archive
} }
mailbox "Arquivos" { mailbox "Arquivos" {
special_use = \Archive special_use = \Archive
} }
mailbox "Archief" { mailbox "Archief" {
special_use = \Archive special_use = \Archive
} }
mailbox "Archív" { mailbox "Archív" {
special_use = \Archive special_use = \Archive
} }
mailbox "Archivovať" { mailbox "Archivovať" {
special_use = \Archive special_use = \Archive
} }
mailbox "归档" { mailbox "归档" {
special_use = \Archive special_use = \Archive
} }
mailbox "Архив" { mailbox "Архив" {
special_use = \Archive special_use = \Archive
} }
mailbox "Архів" { mailbox "Архів" {
special_use = \Archive special_use = \Archive
} }
mailbox "Sent" { mailbox "Sent" {
auto = subscribe auto = subscribe
special_use = \Sent special_use = \Sent
} }
mailbox "Sent Messages" { mailbox "Sent Messages" {
special_use = \Sent special_use = \Sent
} }
mailbox "Sent Items" { mailbox "Sent Items" {
special_use = \Sent special_use = \Sent
} }
mailbox "已发送" { mailbox "已发送" {
special_use = \Sent special_use = \Sent
} }
mailbox "已发送消息" { mailbox "已发送消息" {
special_use = \Sent special_use = \Sent
} }
mailbox "已发送邮件" { mailbox "已发送邮件" {
special_use = \Sent special_use = \Sent
} }
mailbox "Отправленные" { mailbox "Отправленные" {
special_use = \Sent special_use = \Sent
} }
mailbox "Отправленные элементы" { mailbox "Отправленные элементы" {
special_use = \Sent special_use = \Sent
} }
mailbox "Надіслані" { mailbox "Надіслані" {
special_use = \Sent special_use = \Sent
} }
mailbox "Надіслані елементи" { mailbox "Надіслані елементи" {
special_use = \Sent special_use = \Sent
} }
mailbox "Gesendet" { mailbox "Gesendet" {
special_use = \Sent special_use = \Sent
} }
mailbox "Gesendete Objekte" { mailbox "Gesendete Objekte" {
special_use = \Sent special_use = \Sent
} }
mailbox "Gesendete Elemente" { mailbox "Gesendete Elemente" {
special_use = \Sent special_use = \Sent
} }
mailbox "Itens Enviados" { mailbox "Itens Enviados" {
special_use = \Sent special_use = \Sent
} }
mailbox "Enviados" { mailbox "Enviados" {
special_use = \Sent special_use = \Sent
} }
mailbox "Verzonden items" { mailbox "Verzonden items" {
special_use = \Sent special_use = \Sent
} }
mailbox "Verzonden" { mailbox "Verzonden" {
special_use = \Sent special_use = \Sent
} }
mailbox "Odoslaná pošta" { mailbox "Odoslaná pošta" {
special_use = \Sent special_use = \Sent
} }
mailbox "Odoslané" { mailbox "Odoslané" {
special_use = \Sent special_use = \Sent
} }
mailbox "Drafts" { mailbox "Drafts" {
auto = subscribe auto = subscribe
special_use = \Drafts special_use = \Drafts
} }
mailbox "Entwürfe" { mailbox "Entwürfe" {
special_use = \Drafts special_use = \Drafts
} }
mailbox "Rascunhos" { mailbox "Rascunhos" {
special_use = \Drafts special_use = \Drafts
} }
mailbox "Concepten" { mailbox "Concepten" {
special_use = \Drafts special_use = \Drafts
} }
mailbox "Koncepty" { mailbox "Koncepty" {
special_use = \Drafts special_use = \Drafts
} }
mailbox "草稿" { mailbox "草稿" {
special_use = \Drafts special_use = \Drafts
} }
mailbox "草稿箱" { mailbox "草稿箱" {
special_use = \Drafts special_use = \Drafts
} }
mailbox "Черновики" { mailbox "Черновики" {
special_use = \Drafts special_use = \Drafts
} }
mailbox "Чернетки" { mailbox "Чернетки" {
special_use = \Drafts special_use = \Drafts
} }
mailbox "Junk" { mailbox "Junk" {
auto = subscribe auto = subscribe
special_use = \Junk special_use = \Junk
} }
mailbox "Junk-E-Mail" { mailbox "Junk-E-Mail" {
special_use = \Junk special_use = \Junk
} }
mailbox "Junk E-Mail" { mailbox "Junk E-Mail" {
special_use = \Junk special_use = \Junk
} }
mailbox "Spam" { mailbox "Spam" {
special_use = \Junk special_use = \Junk
} }
mailbox "Lixo Eletrônico" { mailbox "Lixo Eletrônico" {
special_use = \Junk special_use = \Junk
} }
mailbox "Nevyžiadaná pošta" { mailbox "Nevyžiadaná pošta" {
special_use = \Junk special_use = \Junk
} }
mailbox "Infikované položky" { mailbox "Infikované položky" {
special_use = \Junk special_use = \Junk
} }
mailbox "Ongewenste e-mail" { mailbox "Ongewenste e-mail" {
special_use = \Junk special_use = \Junk
} }
mailbox "垃圾" { mailbox "垃圾" {
special_use = \Junk special_use = \Junk
} }
mailbox "垃圾箱" { mailbox "垃圾箱" {
special_use = \Junk special_use = \Junk
} }
mailbox "Нежелательная почта" { mailbox "Нежелательная почта" {
special_use = \Junk special_use = \Junk
} }
mailbox "Спам" { mailbox "Спам" {
special_use = \Junk special_use = \Junk
} }
mailbox "Небажана пошта" { mailbox "Небажана пошта" {
special_use = \Junk special_use = \Junk
} }
mailbox "Koncepty" { mailbox "Koncepty" {
special_use = \Drafts special_use = \Drafts
} }
mailbox "Nevyžádaná pošta" { mailbox "Nevyžádaná pošta" {
special_use = \Junk special_use = \Junk
} }
mailbox "Odstraněná pošta" { mailbox "Odstraněná pošta" {
special_use = \Trash special_use = \Trash
} }
mailbox "Odeslaná pošta" { mailbox "Odeslaná pošta" {
special_use = \Sent special_use = \Sent
} }
mailbox "Skräp" { mailbox "Skräp" {
special_use = \Trash special_use = \Trash
} }
mailbox "Borttagna Meddelanden" { mailbox "Borttagna Meddelanden" {
special_use = \Trash special_use = \Trash
} }
mailbox "Arkiv" { mailbox "Arkiv" {
special_use = \Archive special_use = \Archive
} }
mailbox "Arkeverat" { mailbox "Arkeverat" {
special_use = \Archive special_use = \Archive
} }
mailbox "Skickat" { mailbox "Skickat" {
special_use = \Sent special_use = \Sent
} }
mailbox "Skickade Meddelanden" { mailbox "Skickade Meddelanden" {
special_use = \Sent special_use = \Sent
} }
mailbox "Utkast" { mailbox "Utkast" {
special_use = \Drafts special_use = \Drafts
} }
mailbox "Skraldespand" { mailbox "Skraldespand" {
special_use = \Trash special_use = \Trash
} }
mailbox "Slettet mails" { mailbox "Slettet mails" {
special_use = \Trash special_use = \Trash
} }
mailbox "Arkiv" { mailbox "Arkiv" {
special_use = \Archive special_use = \Archive
} }
mailbox "Arkiveret mails" { mailbox "Arkiveret mails" {
special_use = \Archive special_use = \Archive
} }
mailbox "Sendt" { mailbox "Sendt" {
special_use = \Sent special_use = \Sent
} }
mailbox "Sendte mails" { mailbox "Sendte mails" {
special_use = \Sent special_use = \Sent
} }
mailbox "Udkast" { mailbox "Udkast" {
special_use = \Drafts special_use = \Drafts
} }
mailbox "Kladde" { mailbox "Kladde" {
special_use = \Drafts special_use = \Drafts
} }
prefix = prefix =
} }

View File

@ -1,174 +1,174 @@
<?php <?php
// File size is limited by Nginx site to 10M // File size is limited by Nginx site to 10M
// To speed things up, we do not include prerequisites // To speed things up, we do not include prerequisites
header('Content-Type: text/plain'); header('Content-Type: text/plain');
require_once "vars.inc.php"; require_once "vars.inc.php";
// Do not show errors, we log to using error_log // Do not show errors, we log to using error_log
ini_set('error_reporting', 0); ini_set('error_reporting', 0);
// Init database // Init database
//$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name; //$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name;
$dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name; $dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name;
$opt = [ $opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_EMULATE_PREPARES => false,
]; ];
try { try {
$pdo = new PDO($dsn, $database_user, $database_pass, $opt); $pdo = new PDO($dsn, $database_user, $database_pass, $opt);
} }
catch (PDOException $e) { catch (PDOException $e) {
error_log("ALIASEXP: " . $e . PHP_EOL); error_log("ALIASEXP: " . $e . PHP_EOL);
http_response_code(501); http_response_code(501);
exit; exit;
} }
// Init Redis // Init Redis
$redis = new Redis(); $redis = new Redis();
$redis->connect('redis-mailcow', 6379); $redis->connect('redis-mailcow', 6379);
function parse_email($email) { function parse_email($email) {
if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false; if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
$a = strrpos($email, '@'); $a = strrpos($email, '@');
return array('local' => substr($email, 0, $a), 'domain' => substr(substr($email, $a), 1)); return array('local' => substr($email, 0, $a), 'domain' => substr(substr($email, $a), 1));
} }
if (!function_exists('getallheaders')) { if (!function_exists('getallheaders')) {
function getallheaders() { function getallheaders() {
if (!is_array($_SERVER)) { if (!is_array($_SERVER)) {
return array(); return array();
} }
$headers = array(); $headers = array();
foreach ($_SERVER as $name => $value) { foreach ($_SERVER as $name => $value) {
if (substr($name, 0, 5) == 'HTTP_') { if (substr($name, 0, 5) == 'HTTP_') {
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value; $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
} }
} }
return $headers; return $headers;
} }
} }
// Read headers // Read headers
$headers = getallheaders(); $headers = getallheaders();
// Get rcpt // Get rcpt
$rcpt = $headers['Rcpt']; $rcpt = $headers['Rcpt'];
// Remove tag // Remove tag
$rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt); $rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt);
// Parse email address // Parse email address
$parsed_rcpt = parse_email($rcpt); $parsed_rcpt = parse_email($rcpt);
// Create array of final mailboxes // Create array of final mailboxes
$rcpt_final_mailboxes = array(); $rcpt_final_mailboxes = array();
// Skip if not a mailcow handled domain // Skip if not a mailcow handled domain
try { try {
if (!$redis->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) { if (!$redis->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) {
exit; exit;
} }
} }
catch (RedisException $e) { catch (RedisException $e) {
error_log("ALIASEXP: " . $e . PHP_EOL); error_log("ALIASEXP: " . $e . PHP_EOL);
http_response_code(504); http_response_code(504);
exit; exit;
} }
// Always assume rcpt is not a final mailbox but an alias for a mailbox or further aliases // Always assume rcpt is not a final mailbox but an alias for a mailbox or further aliases
// //
// rcpt // rcpt
// | // |
// mailbox <-- goto ---> alias1, alias2, mailbox2 // mailbox <-- goto ---> alias1, alias2, mailbox2
// | | // | |
// mailbox3 | // mailbox3 |
// | // |
// alias3 ---> mailbox4 // alias3 ---> mailbox4
// //
try { try {
$stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'"); $stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'");
$stmt->execute(array( $stmt->execute(array(
':rcpt' => $rcpt ':rcpt' => $rcpt
)); ));
$gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto']; $gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
if (empty($gotos)) { if (empty($gotos)) {
$stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'"); $stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'");
$stmt->execute(array( $stmt->execute(array(
':rcpt' => '@' . $parsed_rcpt['domain'] ':rcpt' => '@' . $parsed_rcpt['domain']
)); ));
$gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto']; $gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
} }
if (empty($gotos)) { if (empty($gotos)) {
$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :rcpt AND `active` = '1'"); $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :rcpt AND `active` = '1'");
$stmt->execute(array(':rcpt' => $parsed_rcpt['domain'])); $stmt->execute(array(':rcpt' => $parsed_rcpt['domain']));
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain']; $goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain'];
if ($goto_branch) { if ($goto_branch) {
$gotos = $parsed_rcpt['local'] . '@' . $goto_branch; $gotos = $parsed_rcpt['local'] . '@' . $goto_branch;
} }
} }
$gotos_array = explode(',', $gotos); $gotos_array = explode(',', $gotos);
$loop_c = 0; $loop_c = 0;
while (count($gotos_array) != 0 && $loop_c <= 20) { while (count($gotos_array) != 0 && $loop_c <= 20) {
// Loop through all found gotos // Loop through all found gotos
foreach ($gotos_array as $index => &$goto) { foreach ($gotos_array as $index => &$goto) {
error_log("ALIAS EXPANDER: http pipe: query " . $goto . " as username from mailbox" . PHP_EOL); error_log("ALIAS EXPANDER: http pipe: query " . $goto . " as username from mailbox" . PHP_EOL);
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :goto AND (`active`= '1' OR `active`= '2');"); $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :goto AND (`active`= '1' OR `active`= '2');");
$stmt->execute(array(':goto' => $goto)); $stmt->execute(array(':goto' => $goto));
$username = $stmt->fetch(PDO::FETCH_ASSOC)['username']; $username = $stmt->fetch(PDO::FETCH_ASSOC)['username'];
if (!empty($username)) { if (!empty($username)) {
error_log("ALIAS EXPANDER: http pipe: mailbox found: " . $username . PHP_EOL); error_log("ALIAS EXPANDER: http pipe: mailbox found: " . $username . PHP_EOL);
// Current goto is a mailbox, save to rcpt_final_mailboxes if not a duplicate // Current goto is a mailbox, save to rcpt_final_mailboxes if not a duplicate
if (!in_array($username, $rcpt_final_mailboxes)) { if (!in_array($username, $rcpt_final_mailboxes)) {
$rcpt_final_mailboxes[] = $username; $rcpt_final_mailboxes[] = $username;
} }
} }
else { else {
$parsed_goto = parse_email($goto); $parsed_goto = parse_email($goto);
if (!$redis->hGet('DOMAIN_MAP', $parsed_goto['domain'])) { if (!$redis->hGet('DOMAIN_MAP', $parsed_goto['domain'])) {
error_log("ALIAS EXPANDER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL); error_log("ALIAS EXPANDER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL);
} }
else { else {
$stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :goto AND `active` = '1'"); $stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :goto AND `active` = '1'");
$stmt->execute(array(':goto' => $goto)); $stmt->execute(array(':goto' => $goto));
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['goto']; $goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
if ($goto_branch) { if ($goto_branch) {
error_log("ALIAS EXPANDER: http pipe: goto address " . $goto . " is an alias branch for " . $goto_branch . PHP_EOL); error_log("ALIAS EXPANDER: http pipe: goto address " . $goto . " is an alias branch for " . $goto_branch . PHP_EOL);
$goto_branch_array = explode(',', $goto_branch); $goto_branch_array = explode(',', $goto_branch);
} else { } else {
$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain AND `active` AND '1'"); $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain AND `active` AND '1'");
$stmt->execute(array(':domain' => $parsed_goto['domain'])); $stmt->execute(array(':domain' => $parsed_goto['domain']));
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain']; $goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain'];
if ($goto_branch) { if ($goto_branch) {
error_log("ALIAS EXPANDER: http pipe: goto domain " . $parsed_goto['domain'] . " is a domain alias branch for " . $goto_branch . PHP_EOL); error_log("ALIAS EXPANDER: http pipe: goto domain " . $parsed_goto['domain'] . " is a domain alias branch for " . $goto_branch . PHP_EOL);
$goto_branch_array = array($parsed_goto['local'] . '@' . $goto_branch); $goto_branch_array = array($parsed_goto['local'] . '@' . $goto_branch);
} }
} }
} }
} }
// goto item was processed, unset // goto item was processed, unset
unset($gotos_array[$index]); unset($gotos_array[$index]);
} }
// Merge goto branch array derived from previous loop (if any), filter duplicates and unset goto branch array // Merge goto branch array derived from previous loop (if any), filter duplicates and unset goto branch array
if (!empty($goto_branch_array)) { if (!empty($goto_branch_array)) {
$gotos_array = array_unique(array_merge($gotos_array, $goto_branch_array)); $gotos_array = array_unique(array_merge($gotos_array, $goto_branch_array));
unset($goto_branch_array); unset($goto_branch_array);
} }
// Reindex array // Reindex array
$gotos_array = array_values($gotos_array); $gotos_array = array_values($gotos_array);
// Force exit if loop cannot be solved // Force exit if loop cannot be solved
// Postfix does not allow for alias loops, so this should never happen. // Postfix does not allow for alias loops, so this should never happen.
$loop_c++; $loop_c++;
error_log("ALIAS EXPANDER: http pipe: goto array count on loop #". $loop_c . " is " . count($gotos_array) . PHP_EOL); error_log("ALIAS EXPANDER: http pipe: goto array count on loop #". $loop_c . " is " . count($gotos_array) . PHP_EOL);
} }
} }
catch (PDOException $e) { catch (PDOException $e) {
error_log("ALIAS EXPANDER: " . $e->getMessage() . PHP_EOL); error_log("ALIAS EXPANDER: " . $e->getMessage() . PHP_EOL);
http_response_code(502); http_response_code(502);
exit; exit;
} }
// Does also return the mailbox name if question == answer (query == mailbox) // Does also return the mailbox name if question == answer (query == mailbox)
if (count($rcpt_final_mailboxes) == 1) { if (count($rcpt_final_mailboxes) == 1) {
error_log("ALIASEXP: direct alias " . $rcpt . " expanded to " . $rcpt_final_mailboxes[0] . PHP_EOL); error_log("ALIASEXP: direct alias " . $rcpt . " expanded to " . $rcpt_final_mailboxes[0] . PHP_EOL);
echo trim($rcpt_final_mailboxes[0]); echo trim($rcpt_final_mailboxes[0]);
} }

View File

@ -1,88 +1,88 @@
<?php <?php
// File size is limited by Nginx site to 10M // File size is limited by Nginx site to 10M
// To speed things up, we do not include prerequisites // To speed things up, we do not include prerequisites
header('Content-Type: text/plain'); header('Content-Type: text/plain');
require_once "vars.inc.php"; require_once "vars.inc.php";
// Do not show errors, we log to using error_log // Do not show errors, we log to using error_log
ini_set('error_reporting', 0); ini_set('error_reporting', 0);
// Init database // Init database
//$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name; //$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name;
$dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name; $dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name;
$opt = [ $opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_EMULATE_PREPARES => false,
]; ];
try { try {
$pdo = new PDO($dsn, $database_user, $database_pass, $opt); $pdo = new PDO($dsn, $database_user, $database_pass, $opt);
} }
catch (PDOException $e) { catch (PDOException $e) {
error_log("BCC MAP SQL ERROR: " . $e . PHP_EOL); error_log("BCC MAP SQL ERROR: " . $e . PHP_EOL);
http_response_code(501); http_response_code(501);
exit; exit;
} }
function parse_email($email) { function parse_email($email) {
if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false; if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
$a = strrpos($email, '@'); $a = strrpos($email, '@');
return array('local' => substr($email, 0, $a), 'domain' => substr(substr($email, $a), 1)); return array('local' => substr($email, 0, $a), 'domain' => substr(substr($email, $a), 1));
} }
if (!function_exists('getallheaders')) { if (!function_exists('getallheaders')) {
function getallheaders() { function getallheaders() {
if (!is_array($_SERVER)) { if (!is_array($_SERVER)) {
return array(); return array();
} }
$headers = array(); $headers = array();
foreach ($_SERVER as $name => $value) { foreach ($_SERVER as $name => $value) {
if (substr($name, 0, 5) == 'HTTP_') { if (substr($name, 0, 5) == 'HTTP_') {
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value; $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
} }
} }
return $headers; return $headers;
} }
} }
// Read headers // Read headers
$headers = getallheaders(); $headers = getallheaders();
// Get rcpt // Get rcpt
$rcpt = $headers['Rcpt']; $rcpt = $headers['Rcpt'];
// Get from // Get from
$from = $headers['From']; $from = $headers['From'];
// Remove tags // Remove tags
$rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt); $rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt);
$from = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $from); $from = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $from);
try { try {
if (!empty($rcpt)) { if (!empty($rcpt)) {
$stmt = $pdo->prepare("SELECT `bcc_dest` FROM `bcc_maps` WHERE `type` = 'rcpt' AND `local_dest` = :local_dest AND `active` = '1'"); $stmt = $pdo->prepare("SELECT `bcc_dest` FROM `bcc_maps` WHERE `type` = 'rcpt' AND `local_dest` = :local_dest AND `active` = '1'");
$stmt->execute(array( $stmt->execute(array(
':local_dest' => $rcpt ':local_dest' => $rcpt
)); ));
$bcc_dest = $stmt->fetch(PDO::FETCH_ASSOC)['bcc_dest']; $bcc_dest = $stmt->fetch(PDO::FETCH_ASSOC)['bcc_dest'];
if (!empty($bcc_dest) && filter_var($bcc_dest, FILTER_VALIDATE_EMAIL)) { if (!empty($bcc_dest) && filter_var($bcc_dest, FILTER_VALIDATE_EMAIL)) {
error_log("BCC MAP: returning ". $bcc_dest . " for " . $rcpt . PHP_EOL); error_log("BCC MAP: returning ". $bcc_dest . " for " . $rcpt . PHP_EOL);
http_response_code(201); http_response_code(201);
echo trim($bcc_dest); echo trim($bcc_dest);
exit; exit;
} }
} }
if (!empty($from)) { if (!empty($from)) {
$stmt = $pdo->prepare("SELECT `bcc_dest` FROM `bcc_maps` WHERE `type` = 'sender' AND `local_dest` = :local_dest AND `active` = '1'"); $stmt = $pdo->prepare("SELECT `bcc_dest` FROM `bcc_maps` WHERE `type` = 'sender' AND `local_dest` = :local_dest AND `active` = '1'");
$stmt->execute(array( $stmt->execute(array(
':local_dest' => $from ':local_dest' => $from
)); ));
$bcc_dest = $stmt->fetch(PDO::FETCH_ASSOC)['bcc_dest']; $bcc_dest = $stmt->fetch(PDO::FETCH_ASSOC)['bcc_dest'];
if (!empty($bcc_dest) && filter_var($bcc_dest, FILTER_VALIDATE_EMAIL)) { if (!empty($bcc_dest) && filter_var($bcc_dest, FILTER_VALIDATE_EMAIL)) {
error_log("BCC MAP: returning ". $bcc_dest . " for " . $from . PHP_EOL); error_log("BCC MAP: returning ". $bcc_dest . " for " . $from . PHP_EOL);
http_response_code(201); http_response_code(201);
echo trim($bcc_dest); echo trim($bcc_dest);
exit; exit;
} }
} }
} }
catch (PDOException $e) { catch (PDOException $e) {
error_log("BCC MAP SQL ERROR: " . $e->getMessage() . PHP_EOL); error_log("BCC MAP SQL ERROR: " . $e->getMessage() . PHP_EOL);
http_response_code(502); http_response_code(502);
exit; exit;
} }

View File

@ -1,471 +1,471 @@
<?php <?php
/* /*
The match section performs AND operation on different matches: for example, if you have from and rcpt in the same rule, The match section performs AND operation on different matches: for example, if you have from and rcpt in the same rule,
then the rule matches only when from AND rcpt match. For similar matches, the OR rule applies: if you have multiple rcpt matches, then the rule matches only when from AND rcpt match. For similar matches, the OR rule applies: if you have multiple rcpt matches,
then any of these will trigger the rule. If a rule is triggered then no more rules are matched. then any of these will trigger the rule. If a rule is triggered then no more rules are matched.
*/ */
header('Content-Type: text/plain'); header('Content-Type: text/plain');
require_once "vars.inc.php"; require_once "vars.inc.php";
// Getting headers sent by the client. // Getting headers sent by the client.
ini_set('error_reporting', 0); ini_set('error_reporting', 0);
//$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name; //$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name;
$dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name; $dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name;
$opt = [ $opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_EMULATE_PREPARES => false,
]; ];
try { try {
$pdo = new PDO($dsn, $database_user, $database_pass, $opt); $pdo = new PDO($dsn, $database_user, $database_pass, $opt);
$stmt = $pdo->query("SELECT '1' FROM `filterconf`"); $stmt = $pdo->query("SELECT '1' FROM `filterconf`");
} }
catch (PDOException $e) { catch (PDOException $e) {
echo 'settings { }'; echo 'settings { }';
exit; exit;
} }
// Check if db changed and return header // Check if db changed and return header
$stmt = $pdo->prepare("SELECT GREATEST(COALESCE(MAX(UNIX_TIMESTAMP(UPDATE_TIME)), 1), COALESCE(MAX(UNIX_TIMESTAMP(CREATE_TIME)), 1)) AS `db_update_time` FROM `information_schema`.`tables` $stmt = $pdo->prepare("SELECT GREATEST(COALESCE(MAX(UNIX_TIMESTAMP(UPDATE_TIME)), 1), COALESCE(MAX(UNIX_TIMESTAMP(CREATE_TIME)), 1)) AS `db_update_time` FROM `information_schema`.`tables`
WHERE (`TABLE_NAME` = 'filterconf' OR `TABLE_NAME` = 'settingsmap' OR `TABLE_NAME` = 'sogo_quick_contact' OR `TABLE_NAME` = 'alias') WHERE (`TABLE_NAME` = 'filterconf' OR `TABLE_NAME` = 'settingsmap' OR `TABLE_NAME` = 'sogo_quick_contact' OR `TABLE_NAME` = 'alias')
AND TABLE_SCHEMA = :dbname;"); AND TABLE_SCHEMA = :dbname;");
$stmt->execute(array( $stmt->execute(array(
':dbname' => $database_name ':dbname' => $database_name
)); ));
$db_update_time = $stmt->fetch(PDO::FETCH_ASSOC)['db_update_time']; $db_update_time = $stmt->fetch(PDO::FETCH_ASSOC)['db_update_time'];
if (empty($db_update_time)) { if (empty($db_update_time)) {
$db_update_time = 1572048000; $db_update_time = 1572048000;
} }
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && (strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $db_update_time)) { if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && (strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $db_update_time)) {
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $db_update_time).' GMT', true, 304); header('Last-Modified: '.gmdate('D, d M Y H:i:s', $db_update_time).' GMT', true, 304);
exit; exit;
} else { } else {
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $db_update_time).' GMT', true, 200); header('Last-Modified: '.gmdate('D, d M Y H:i:s', $db_update_time).' GMT', true, 200);
} }
function parse_email($email) { function parse_email($email) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) return false; if (!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
$a = strrpos($email, '@'); $a = strrpos($email, '@');
return array('local' => substr($email, 0, $a), 'domain' => substr($email, $a)); return array('local' => substr($email, 0, $a), 'domain' => substr($email, $a));
} }
function normalize_email($email) { function normalize_email($email) {
$email = strtolower(str_replace('/', '\/', $email)); $email = strtolower(str_replace('/', '\/', $email));
$gm = "@gmail.com"; $gm = "@gmail.com";
if (substr_compare($email, $gm, -strlen($gm)) == 0) { if (substr_compare($email, $gm, -strlen($gm)) == 0) {
$email = explode('@', $email); $email = explode('@', $email);
$email[0] = str_replace('.', '', $email[0]); $email[0] = str_replace('.', '', $email[0]);
$email = implode('@', $email); $email = implode('@', $email);
} }
$gm_alt = "@googlemail.com"; $gm_alt = "@googlemail.com";
if (substr_compare($email, $gm_alt, -strlen($gm_alt)) == 0) { if (substr_compare($email, $gm_alt, -strlen($gm_alt)) == 0) {
$email = explode('@', $email); $email = explode('@', $email);
$email[0] = str_replace('.', '', $email[0]); $email[0] = str_replace('.', '', $email[0]);
$email[1] = str_replace('@', '', $gm); $email[1] = str_replace('@', '', $gm);
$email = implode('@', $email); $email = implode('@', $email);
} }
if (str_contains($email, "+")) { if (str_contains($email, "+")) {
$email = explode('@', $email); $email = explode('@', $email);
$user = explode('+', $email[0]); $user = explode('+', $email[0]);
$email[0] = $user[0]; $email[0] = $user[0];
$email = implode('@', $email); $email = implode('@', $email);
} }
return $email; return $email;
} }
function wl_by_sogo() { function wl_by_sogo() {
global $pdo; global $pdo;
$rcpt = array(); $rcpt = array();
$stmt = $pdo->query("SELECT DISTINCT(`sogo_folder_info`.`c_path2`) AS `user`, GROUP_CONCAT(`sogo_quick_contact`.`c_mail`) AS `contacts` FROM `sogo_folder_info` $stmt = $pdo->query("SELECT DISTINCT(`sogo_folder_info`.`c_path2`) AS `user`, GROUP_CONCAT(`sogo_quick_contact`.`c_mail`) AS `contacts` FROM `sogo_folder_info`
INNER JOIN `sogo_quick_contact` ON `sogo_quick_contact`.`c_folder_id` = `sogo_folder_info`.`c_folder_id` INNER JOIN `sogo_quick_contact` ON `sogo_quick_contact`.`c_folder_id` = `sogo_folder_info`.`c_folder_id`
GROUP BY `c_path2`"); GROUP BY `c_path2`");
$sogo_contacts = $stmt->fetchAll(PDO::FETCH_ASSOC); $sogo_contacts = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($sogo_contacts)) { while ($row = array_shift($sogo_contacts)) {
foreach (explode(',', $row['contacts']) as $contact) { foreach (explode(',', $row['contacts']) as $contact) {
if (!filter_var($contact, FILTER_VALIDATE_EMAIL)) { if (!filter_var($contact, FILTER_VALIDATE_EMAIL)) {
continue; continue;
} }
// Explicit from, no mime_from, no regex - envelope must match // Explicit from, no mime_from, no regex - envelope must match
// mailcow white and blacklists also cover mime_from // mailcow white and blacklists also cover mime_from
$rcpt[$row['user']][] = normalize_email($contact); $rcpt[$row['user']][] = normalize_email($contact);
} }
} }
return $rcpt; return $rcpt;
} }
function ucl_rcpts($object, $type) { function ucl_rcpts($object, $type) {
global $pdo; global $pdo;
$rcpt = array(); $rcpt = array();
if ($type == 'mailbox') { if ($type == 'mailbox') {
// Standard aliases // Standard aliases
$stmt = $pdo->prepare("SELECT `address` FROM `alias` $stmt = $pdo->prepare("SELECT `address` FROM `alias`
WHERE `goto` = :object_goto WHERE `goto` = :object_goto
AND `address` NOT LIKE '@%'"); AND `address` NOT LIKE '@%'");
$stmt->execute(array( $stmt->execute(array(
':object_goto' => $object ':object_goto' => $object
)); ));
$standard_aliases = $stmt->fetchAll(PDO::FETCH_ASSOC); $standard_aliases = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($standard_aliases)) { while ($row = array_shift($standard_aliases)) {
$local = parse_email($row['address'])['local']; $local = parse_email($row['address'])['local'];
$domain = parse_email($row['address'])['domain']; $domain = parse_email($row['address'])['domain'];
if (!empty($local) && !empty($domain)) { if (!empty($local) && !empty($domain)) {
$rcpt[] = '/^' . str_replace('/', '\/', $local) . '[+].*' . str_replace('/', '\/', $domain) . '$/i'; $rcpt[] = '/^' . str_replace('/', '\/', $local) . '[+].*' . str_replace('/', '\/', $domain) . '$/i';
} }
$rcpt[] = str_replace('/', '\/', $row['address']); $rcpt[] = str_replace('/', '\/', $row['address']);
} }
// Aliases by alias domains // Aliases by alias domains
$stmt = $pdo->prepare("SELECT CONCAT(`local_part`, '@', `alias_domain`.`alias_domain`) AS `alias` FROM `mailbox` $stmt = $pdo->prepare("SELECT CONCAT(`local_part`, '@', `alias_domain`.`alias_domain`) AS `alias` FROM `mailbox`
LEFT OUTER JOIN `alias_domain` ON `mailbox`.`domain` = `alias_domain`.`target_domain` LEFT OUTER JOIN `alias_domain` ON `mailbox`.`domain` = `alias_domain`.`target_domain`
WHERE `mailbox`.`username` = :object"); WHERE `mailbox`.`username` = :object");
$stmt->execute(array( $stmt->execute(array(
':object' => $object ':object' => $object
)); ));
$by_domain_aliases = $stmt->fetchAll(PDO::FETCH_ASSOC); $by_domain_aliases = $stmt->fetchAll(PDO::FETCH_ASSOC);
array_filter($by_domain_aliases); array_filter($by_domain_aliases);
while ($row = array_shift($by_domain_aliases)) { while ($row = array_shift($by_domain_aliases)) {
if (!empty($row['alias'])) { if (!empty($row['alias'])) {
$local = parse_email($row['alias'])['local']; $local = parse_email($row['alias'])['local'];
$domain = parse_email($row['alias'])['domain']; $domain = parse_email($row['alias'])['domain'];
if (!empty($local) && !empty($domain)) { if (!empty($local) && !empty($domain)) {
$rcpt[] = '/^' . str_replace('/', '\/', $local) . '[+].*' . str_replace('/', '\/', $domain) . '$/i'; $rcpt[] = '/^' . str_replace('/', '\/', $local) . '[+].*' . str_replace('/', '\/', $domain) . '$/i';
} }
$rcpt[] = str_replace('/', '\/', $row['alias']); $rcpt[] = str_replace('/', '\/', $row['alias']);
} }
} }
} }
elseif ($type == 'domain') { elseif ($type == 'domain') {
// Domain self // Domain self
$rcpt[] = '/.*@' . $object . '/i'; $rcpt[] = '/.*@' . $object . '/i';
$stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain` $stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain`
WHERE `target_domain` = :object"); WHERE `target_domain` = :object");
$stmt->execute(array(':object' => $object)); $stmt->execute(array(':object' => $object));
$alias_domains = $stmt->fetchAll(PDO::FETCH_ASSOC); $alias_domains = $stmt->fetchAll(PDO::FETCH_ASSOC);
array_filter($alias_domains); array_filter($alias_domains);
while ($row = array_shift($alias_domains)) { while ($row = array_shift($alias_domains)) {
$rcpt[] = '/.*@' . $row['alias_domain'] . '/i'; $rcpt[] = '/.*@' . $row['alias_domain'] . '/i';
} }
} }
return $rcpt; return $rcpt;
} }
?> ?>
settings { settings {
watchdog { watchdog {
priority = 10; priority = 10;
rcpt_mime = "/null@localhost/i"; rcpt_mime = "/null@localhost/i";
from_mime = "/watchdog@localhost/i"; from_mime = "/watchdog@localhost/i";
apply "default" { apply "default" {
symbols_disabled = ["HISTORY_SAVE", "ARC", "ARC_SIGNED", "DKIM", "DKIM_SIGNED", "CLAM_VIRUS"]; symbols_disabled = ["HISTORY_SAVE", "ARC", "ARC_SIGNED", "DKIM", "DKIM_SIGNED", "CLAM_VIRUS"];
want_spam = yes; want_spam = yes;
actions { actions {
reject = 9999.0; reject = 9999.0;
greylist = 9998.0; greylist = 9998.0;
"add header" = 9997.0; "add header" = 9997.0;
} }
} }
} }
<?php <?php
/* /*
// Start custom scores for users // Start custom scores for users
*/ */
$stmt = $pdo->query("SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'highspamlevel' OR `option` = 'lowspamlevel'"); $stmt = $pdo->query("SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'highspamlevel' OR `option` = 'lowspamlevel'");
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($rows)) { while ($row = array_shift($rows)) {
$username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['object']); $username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['object']);
?> ?>
score_<?=$username_sane;?> { score_<?=$username_sane;?> {
priority = 4; priority = 4;
<?php <?php
foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) { foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) {
?> ?>
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>; rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
<?php <?php
} }
$stmt = $pdo->prepare("SELECT `option`, `value` FROM `filterconf` $stmt = $pdo->prepare("SELECT `option`, `value` FROM `filterconf`
WHERE (`option` = 'highspamlevel' OR `option` = 'lowspamlevel') WHERE (`option` = 'highspamlevel' OR `option` = 'lowspamlevel')
AND `object`= :object"); AND `object`= :object");
$stmt->execute(array(':object' => $row['object'])); $stmt->execute(array(':object' => $row['object']));
$spamscore = $stmt->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_GROUP); $spamscore = $stmt->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_GROUP);
?> ?>
apply "default" { apply "default" {
actions { actions {
reject = <?=$spamscore['highspamlevel'][0];?>; reject = <?=$spamscore['highspamlevel'][0];?>;
greylist = <?=$spamscore['lowspamlevel'][0] - 1;?>; greylist = <?=$spamscore['lowspamlevel'][0] - 1;?>;
"add header" = <?=$spamscore['lowspamlevel'][0];?>; "add header" = <?=$spamscore['lowspamlevel'][0];?>;
} }
} }
} }
<?php <?php
} }
/* /*
// Start SOGo contacts whitelist // Start SOGo contacts whitelist
// Priority 4, lower than a domain whitelist (5) and lower than a mailbox whitelist (6) // Priority 4, lower than a domain whitelist (5) and lower than a mailbox whitelist (6)
*/ */
foreach (wl_by_sogo() as $user => $contacts) { foreach (wl_by_sogo() as $user => $contacts) {
$username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $user); $username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $user);
?> ?>
whitelist_sogo_<?=$username_sane;?> { whitelist_sogo_<?=$username_sane;?> {
<?php <?php
foreach ($contacts as $contact) { foreach ($contacts as $contact) {
?> ?>
from = <?=json_encode($contact, JSON_UNESCAPED_SLASHES);?>; from = <?=json_encode($contact, JSON_UNESCAPED_SLASHES);?>;
<?php <?php
} }
?> ?>
priority = 4; priority = 4;
<?php <?php
foreach (ucl_rcpts($user, 'mailbox') as $rcpt) { foreach (ucl_rcpts($user, 'mailbox') as $rcpt) {
?> ?>
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>; rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
<?php <?php
} }
?> ?>
apply "default" { apply "default" {
SOGO_CONTACT = -99.0; SOGO_CONTACT = -99.0;
} }
symbols [ symbols [
"SOGO_CONTACT" "SOGO_CONTACT"
] ]
} }
<?php <?php
} }
/* /*
// Start whitelist // Start whitelist
*/ */
$stmt = $pdo->query("SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'whitelist_from'"); $stmt = $pdo->query("SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'whitelist_from'");
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($rows)) { while ($row = array_shift($rows)) {
$username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['object']); $username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['object']);
?> ?>
whitelist_<?=$username_sane;?> { whitelist_<?=$username_sane;?> {
<?php <?php
$list_items = array(); $list_items = array();
$stmt = $pdo->prepare("SELECT `value` FROM `filterconf` $stmt = $pdo->prepare("SELECT `value` FROM `filterconf`
WHERE `object`= :object WHERE `object`= :object
AND `option` = 'whitelist_from'"); AND `option` = 'whitelist_from'");
$stmt->execute(array(':object' => $row['object'])); $stmt->execute(array(':object' => $row['object']));
$list_items = $stmt->fetchAll(PDO::FETCH_ASSOC); $list_items = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($list_items as $item) { foreach ($list_items as $item) {
?> ?>
from = "/<?='^' . str_replace('\*', '.*', preg_quote($item['value'], '/')) . '$' ;?>/i"; from = "/<?='^' . str_replace('\*', '.*', preg_quote($item['value'], '/')) . '$' ;?>/i";
<?php <?php
} }
if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) { if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) {
?> ?>
priority = 5; priority = 5;
<?php <?php
foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) { foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) {
?> ?>
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>; rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
<?php <?php
} }
} }
else { else {
?> ?>
priority = 6; priority = 6;
<?php <?php
foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) { foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) {
?> ?>
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>; rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
<?php <?php
} }
} }
?> ?>
apply "default" { apply "default" {
MAILCOW_WHITE = -999.0; MAILCOW_WHITE = -999.0;
} }
symbols [ symbols [
"MAILCOW_WHITE" "MAILCOW_WHITE"
] ]
} }
whitelist_mime_<?=$username_sane;?> { whitelist_mime_<?=$username_sane;?> {
<?php <?php
foreach ($list_items as $item) { foreach ($list_items as $item) {
?> ?>
from_mime = "/<?='^' . str_replace('\*', '.*', preg_quote($item['value'], '/')) . '$' ;?>/i"; from_mime = "/<?='^' . str_replace('\*', '.*', preg_quote($item['value'], '/')) . '$' ;?>/i";
<?php <?php
} }
if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) { if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) {
?> ?>
priority = 5; priority = 5;
<?php <?php
foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) { foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) {
?> ?>
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>; rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
<?php <?php
} }
} }
else { else {
?> ?>
priority = 6; priority = 6;
<?php <?php
foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) { foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) {
?> ?>
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>; rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
<?php <?php
} }
} }
?> ?>
apply "default" { apply "default" {
MAILCOW_WHITE = -999.0; MAILCOW_WHITE = -999.0;
} }
symbols [ symbols [
"MAILCOW_WHITE" "MAILCOW_WHITE"
] ]
} }
<?php <?php
} }
/* /*
// Start blacklist // Start blacklist
*/ */
$stmt = $pdo->query("SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'blacklist_from'"); $stmt = $pdo->query("SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'blacklist_from'");
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($rows)) { while ($row = array_shift($rows)) {
$username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['object']); $username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['object']);
?> ?>
blacklist_<?=$username_sane;?> { blacklist_<?=$username_sane;?> {
<?php <?php
$list_items = array(); $list_items = array();
$stmt = $pdo->prepare("SELECT `value` FROM `filterconf` $stmt = $pdo->prepare("SELECT `value` FROM `filterconf`
WHERE `object`= :object WHERE `object`= :object
AND `option` = 'blacklist_from'"); AND `option` = 'blacklist_from'");
$stmt->execute(array(':object' => $row['object'])); $stmt->execute(array(':object' => $row['object']));
$list_items = $stmt->fetchAll(PDO::FETCH_ASSOC); $list_items = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($list_items as $item) { foreach ($list_items as $item) {
?> ?>
from = "/<?='^' . str_replace('\*', '.*', preg_quote($item['value'], '/')) . '$' ;?>/i"; from = "/<?='^' . str_replace('\*', '.*', preg_quote($item['value'], '/')) . '$' ;?>/i";
<?php <?php
} }
if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) { if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) {
?> ?>
priority = 5; priority = 5;
<?php <?php
foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) { foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) {
?> ?>
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>; rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
<?php <?php
} }
} }
else { else {
?> ?>
priority = 6; priority = 6;
<?php <?php
foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) { foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) {
?> ?>
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>; rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
<?php <?php
} }
} }
?> ?>
apply "default" { apply "default" {
MAILCOW_BLACK = 999.0; MAILCOW_BLACK = 999.0;
} }
symbols [ symbols [
"MAILCOW_BLACK" "MAILCOW_BLACK"
] ]
} }
blacklist_header_<?=$username_sane;?> { blacklist_header_<?=$username_sane;?> {
<?php <?php
foreach ($list_items as $item) { foreach ($list_items as $item) {
?> ?>
from_mime = "/<?='^' . str_replace('\*', '.*', preg_quote($item['value'], '/')) . '$' ;?>/i"; from_mime = "/<?='^' . str_replace('\*', '.*', preg_quote($item['value'], '/')) . '$' ;?>/i";
<?php <?php
} }
if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) { if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) {
?> ?>
priority = 5; priority = 5;
<?php <?php
foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) { foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) {
?> ?>
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>; rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
<?php <?php
} }
} }
else { else {
?> ?>
priority = 6; priority = 6;
<?php <?php
foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) { foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) {
?> ?>
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>; rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
<?php <?php
} }
} }
?> ?>
apply "default" { apply "default" {
MAILCOW_BLACK = 999.0; MAILCOW_BLACK = 999.0;
} }
symbols [ symbols [
"MAILCOW_BLACK" "MAILCOW_BLACK"
] ]
} }
<?php <?php
} }
/* /*
// Start traps // Start traps
*/ */
?> ?>
ham_trap { ham_trap {
<?php <?php
foreach (ucl_rcpts('ham@localhost', 'mailbox') as $rcpt) { foreach (ucl_rcpts('ham@localhost', 'mailbox') as $rcpt) {
?> ?>
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>; rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
<?php <?php
} }
?> ?>
priority = 9; priority = 9;
apply "default" { apply "default" {
symbols_enabled = ["HISTORY_SAVE"]; symbols_enabled = ["HISTORY_SAVE"];
} }
symbols [ symbols [
"HAM_TRAP" "HAM_TRAP"
] ]
} }
spam_trap { spam_trap {
<?php <?php
foreach (ucl_rcpts('spam@localhost', 'mailbox') as $rcpt) { foreach (ucl_rcpts('spam@localhost', 'mailbox') as $rcpt) {
?> ?>
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>; rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
<?php <?php
} }
?> ?>
priority = 9; priority = 9;
apply "default" { apply "default" {
symbols_enabled = ["HISTORY_SAVE"]; symbols_enabled = ["HISTORY_SAVE"];
} }
symbols [ symbols [
"SPAM_TRAP" "SPAM_TRAP"
] ]
} }
<?php <?php
// Start additional content // Start additional content
$stmt = $pdo->query("SELECT `id`, `content` FROM `settingsmap` WHERE `active` = '1'"); $stmt = $pdo->query("SELECT `id`, `content` FROM `settingsmap` WHERE `active` = '1'");
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($rows)) { while ($row = array_shift($rows)) {
$username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['id']); $username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['id']);
?> ?>
additional_settings_<?=intval($row['id']);?> { additional_settings_<?=intval($row['id']);?> {
<?php <?php
$content = preg_split('/\r\n|\r|\n/', $row['content']); $content = preg_split('/\r\n|\r|\n/', $row['content']);
foreach ($content as $line) { foreach ($content as $line) {
echo ' ' . $line . PHP_EOL; echo ' ' . $line . PHP_EOL;
} }
?> ?>
} }
<?php <?php
} }
?> ?>
} }

View File

@ -1,260 +1,260 @@
<?php <?php
// File size is limited by Nginx site to 10M // File size is limited by Nginx site to 10M
// To speed things up, we do not include prerequisites // To speed things up, we do not include prerequisites
header('Content-Type: text/plain'); header('Content-Type: text/plain');
require_once "vars.inc.php"; require_once "vars.inc.php";
// Do not show errors, we log to using error_log // Do not show errors, we log to using error_log
ini_set('error_reporting', 0); ini_set('error_reporting', 0);
// Init database // Init database
//$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name; //$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name;
$dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name; $dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name;
$opt = [ $opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_EMULATE_PREPARES => false,
]; ];
try { try {
$pdo = new PDO($dsn, $database_user, $database_pass, $opt); $pdo = new PDO($dsn, $database_user, $database_pass, $opt);
} }
catch (PDOException $e) { catch (PDOException $e) {
error_log("QUARANTINE: " . $e . PHP_EOL); error_log("QUARANTINE: " . $e . PHP_EOL);
http_response_code(501); http_response_code(501);
exit; exit;
} }
// Init Redis // Init Redis
$redis = new Redis(); $redis = new Redis();
$redis->connect('redis-mailcow', 6379); $redis->connect('redis-mailcow', 6379);
// Functions // Functions
function parse_email($email) { function parse_email($email) {
if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false; if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
$a = strrpos($email, '@'); $a = strrpos($email, '@');
return array('local' => substr($email, 0, $a), 'domain' => substr(substr($email, $a), 1)); return array('local' => substr($email, 0, $a), 'domain' => substr(substr($email, $a), 1));
} }
if (!function_exists('getallheaders')) { if (!function_exists('getallheaders')) {
function getallheaders() { function getallheaders() {
if (!is_array($_SERVER)) { if (!is_array($_SERVER)) {
return array(); return array();
} }
$headers = array(); $headers = array();
foreach ($_SERVER as $name => $value) { foreach ($_SERVER as $name => $value) {
if (substr($name, 0, 5) == 'HTTP_') { if (substr($name, 0, 5) == 'HTTP_') {
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value; $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
} }
} }
return $headers; return $headers;
} }
} }
$raw_data_content = file_get_contents('php://input'); $raw_data_content = file_get_contents('php://input');
$raw_data = mb_convert_encoding($raw_data_content, 'HTML-ENTITIES', "UTF-8"); $raw_data = mb_convert_encoding($raw_data_content, 'HTML-ENTITIES', "UTF-8");
$headers = getallheaders(); $headers = getallheaders();
$qid = $headers['X-Rspamd-Qid']; $qid = $headers['X-Rspamd-Qid'];
$fuzzy = $headers['X-Rspamd-Fuzzy']; $fuzzy = $headers['X-Rspamd-Fuzzy'];
$subject = $headers['X-Rspamd-Subject']; $subject = $headers['X-Rspamd-Subject'];
$score = $headers['X-Rspamd-Score']; $score = $headers['X-Rspamd-Score'];
$rcpts = $headers['X-Rspamd-Rcpt']; $rcpts = $headers['X-Rspamd-Rcpt'];
$user = $headers['X-Rspamd-User']; $user = $headers['X-Rspamd-User'];
$ip = $headers['X-Rspamd-Ip']; $ip = $headers['X-Rspamd-Ip'];
$action = $headers['X-Rspamd-Action']; $action = $headers['X-Rspamd-Action'];
$sender = $headers['X-Rspamd-From']; $sender = $headers['X-Rspamd-From'];
$symbols = $headers['X-Rspamd-Symbols']; $symbols = $headers['X-Rspamd-Symbols'];
$raw_size = (int)$_SERVER['CONTENT_LENGTH']; $raw_size = (int)$_SERVER['CONTENT_LENGTH'];
if (empty($sender)) { if (empty($sender)) {
error_log("QUARANTINE: Unknown sender, assuming empty-env-from@localhost" . PHP_EOL); error_log("QUARANTINE: Unknown sender, assuming empty-env-from@localhost" . PHP_EOL);
$sender = 'empty-env-from@localhost'; $sender = 'empty-env-from@localhost';
} }
if ($fuzzy == 'unknown') { if ($fuzzy == 'unknown') {
$fuzzy = '[]'; $fuzzy = '[]';
} }
try { try {
$max_size = (int)$redis->Get('Q_MAX_SIZE'); $max_size = (int)$redis->Get('Q_MAX_SIZE');
if (($max_size * 1048576) < $raw_size) { if (($max_size * 1048576) < $raw_size) {
error_log(sprintf("QUARANTINE: Message too large: %d b exceeds %d b", $raw_size, ($max_size * 1048576)) . PHP_EOL); error_log(sprintf("QUARANTINE: Message too large: %d b exceeds %d b", $raw_size, ($max_size * 1048576)) . PHP_EOL);
http_response_code(505); http_response_code(505);
exit; exit;
} }
if ($exclude_domains = $redis->Get('Q_EXCLUDE_DOMAINS')) { if ($exclude_domains = $redis->Get('Q_EXCLUDE_DOMAINS')) {
$exclude_domains = json_decode($exclude_domains, true); $exclude_domains = json_decode($exclude_domains, true);
} }
$retention_size = (int)$redis->Get('Q_RETENTION_SIZE'); $retention_size = (int)$redis->Get('Q_RETENTION_SIZE');
} }
catch (RedisException $e) { catch (RedisException $e) {
error_log("QUARANTINE: " . $e . PHP_EOL); error_log("QUARANTINE: " . $e . PHP_EOL);
http_response_code(504); http_response_code(504);
exit; exit;
} }
$rcpt_final_mailboxes = array(); $rcpt_final_mailboxes = array();
// Loop through all rcpts // Loop through all rcpts
foreach (json_decode($rcpts, true) as $rcpt) { foreach (json_decode($rcpts, true) as $rcpt) {
// Remove tag // Remove tag
$rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt); $rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt);
// Break rcpt into local part and domain part // Break rcpt into local part and domain part
$parsed_rcpt = parse_email($rcpt); $parsed_rcpt = parse_email($rcpt);
// Skip if not a mailcow handled domain // Skip if not a mailcow handled domain
try { try {
if (!$redis->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) { if (!$redis->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) {
continue; continue;
} }
} }
catch (RedisException $e) { catch (RedisException $e) {
error_log("QUARANTINE: " . $e . PHP_EOL); error_log("QUARANTINE: " . $e . PHP_EOL);
http_response_code(504); http_response_code(504);
exit; exit;
} }
// Skip if domain is excluded // Skip if domain is excluded
if (in_array($parsed_rcpt['domain'], $exclude_domains)) { if (in_array($parsed_rcpt['domain'], $exclude_domains)) {
error_log(sprintf("QUARANTINE: Skipped domain %s", $parsed_rcpt['domain']) . PHP_EOL); error_log(sprintf("QUARANTINE: Skipped domain %s", $parsed_rcpt['domain']) . PHP_EOL);
continue; continue;
} }
// Always assume rcpt is not a final mailbox but an alias for a mailbox or further aliases // Always assume rcpt is not a final mailbox but an alias for a mailbox or further aliases
// //
// rcpt // rcpt
// | // |
// mailbox <-- goto ---> alias1, alias2, mailbox2 // mailbox <-- goto ---> alias1, alias2, mailbox2
// | | // | |
// mailbox3 | // mailbox3 |
// | // |
// alias3 ---> mailbox4 // alias3 ---> mailbox4
// //
try { try {
$stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'"); $stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'");
$stmt->execute(array( $stmt->execute(array(
':rcpt' => $rcpt ':rcpt' => $rcpt
)); ));
$gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto']; $gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
if (empty($gotos)) { if (empty($gotos)) {
$stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'"); $stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'");
$stmt->execute(array( $stmt->execute(array(
':rcpt' => '@' . $parsed_rcpt['domain'] ':rcpt' => '@' . $parsed_rcpt['domain']
)); ));
$gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto']; $gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
} }
if (empty($gotos)) { if (empty($gotos)) {
$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :rcpt AND `active` = '1'"); $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :rcpt AND `active` = '1'");
$stmt->execute(array(':rcpt' => $parsed_rcpt['domain'])); $stmt->execute(array(':rcpt' => $parsed_rcpt['domain']));
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain']; $goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain'];
if ($goto_branch) { if ($goto_branch) {
$gotos = $parsed_rcpt['local'] . '@' . $goto_branch; $gotos = $parsed_rcpt['local'] . '@' . $goto_branch;
} }
} }
$gotos_array = explode(',', $gotos); $gotos_array = explode(',', $gotos);
$loop_c = 0; $loop_c = 0;
while (count($gotos_array) != 0 && $loop_c <= 20) { while (count($gotos_array) != 0 && $loop_c <= 20) {
// Loop through all found gotos // Loop through all found gotos
foreach ($gotos_array as $index => &$goto) { foreach ($gotos_array as $index => &$goto) {
error_log("RCPT RESOVLER: http pipe: query " . $goto . " as username from mailbox" . PHP_EOL); error_log("RCPT RESOVLER: http pipe: query " . $goto . " as username from mailbox" . PHP_EOL);
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :goto AND (`active`= '1' OR `active`= '2');"); $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :goto AND (`active`= '1' OR `active`= '2');");
$stmt->execute(array(':goto' => $goto)); $stmt->execute(array(':goto' => $goto));
$username = $stmt->fetch(PDO::FETCH_ASSOC)['username']; $username = $stmt->fetch(PDO::FETCH_ASSOC)['username'];
if (!empty($username)) { if (!empty($username)) {
error_log("RCPT RESOVLER: http pipe: mailbox found: " . $username . PHP_EOL); error_log("RCPT RESOVLER: http pipe: mailbox found: " . $username . PHP_EOL);
// Current goto is a mailbox, save to rcpt_final_mailboxes if not a duplicate // Current goto is a mailbox, save to rcpt_final_mailboxes if not a duplicate
if (!in_array($username, $rcpt_final_mailboxes)) { if (!in_array($username, $rcpt_final_mailboxes)) {
$rcpt_final_mailboxes[] = $username; $rcpt_final_mailboxes[] = $username;
} }
} }
else { else {
$parsed_goto = parse_email($goto); $parsed_goto = parse_email($goto);
if (!$redis->hGet('DOMAIN_MAP', $parsed_goto['domain'])) { if (!$redis->hGet('DOMAIN_MAP', $parsed_goto['domain'])) {
error_log("RCPT RESOVLER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL); error_log("RCPT RESOVLER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL);
} }
else { else {
$stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :goto AND `active` = '1'"); $stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :goto AND `active` = '1'");
$stmt->execute(array(':goto' => $goto)); $stmt->execute(array(':goto' => $goto));
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['goto']; $goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
if ($goto_branch) { if ($goto_branch) {
error_log("RCPT RESOVLER: http pipe: goto address " . $goto . " is an alias branch for " . $goto_branch . PHP_EOL); error_log("RCPT RESOVLER: http pipe: goto address " . $goto . " is an alias branch for " . $goto_branch . PHP_EOL);
$goto_branch_array = explode(',', $goto_branch); $goto_branch_array = explode(',', $goto_branch);
} else { } else {
$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain AND `active` AND '1'"); $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain AND `active` AND '1'");
$stmt->execute(array(':domain' => $parsed_goto['domain'])); $stmt->execute(array(':domain' => $parsed_goto['domain']));
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain']; $goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain'];
if ($goto_branch) { if ($goto_branch) {
error_log("RCPT RESOVLER: http pipe: goto domain " . $parsed_goto['domain'] . " is a domain alias branch for " . $goto_branch . PHP_EOL); error_log("RCPT RESOVLER: http pipe: goto domain " . $parsed_goto['domain'] . " is a domain alias branch for " . $goto_branch . PHP_EOL);
$goto_branch_array = array($parsed_goto['local'] . '@' . $goto_branch); $goto_branch_array = array($parsed_goto['local'] . '@' . $goto_branch);
} }
} }
} }
} }
// goto item was processed, unset // goto item was processed, unset
unset($gotos_array[$index]); unset($gotos_array[$index]);
} }
// Merge goto branch array derived from previous loop (if any), filter duplicates and unset goto branch array // Merge goto branch array derived from previous loop (if any), filter duplicates and unset goto branch array
if (!empty($goto_branch_array)) { if (!empty($goto_branch_array)) {
$gotos_array = array_unique(array_merge($gotos_array, $goto_branch_array)); $gotos_array = array_unique(array_merge($gotos_array, $goto_branch_array));
unset($goto_branch_array); unset($goto_branch_array);
} }
// Reindex array // Reindex array
$gotos_array = array_values($gotos_array); $gotos_array = array_values($gotos_array);
// Force exit if loop cannot be solved // Force exit if loop cannot be solved
// Postfix does not allow for alias loops, so this should never happen. // Postfix does not allow for alias loops, so this should never happen.
$loop_c++; $loop_c++;
error_log("RCPT RESOVLER: http pipe: goto array count on loop #". $loop_c . " is " . count($gotos_array) . PHP_EOL); error_log("RCPT RESOVLER: http pipe: goto array count on loop #". $loop_c . " is " . count($gotos_array) . PHP_EOL);
} }
} }
catch (PDOException $e) { catch (PDOException $e) {
error_log("RCPT RESOVLER: " . $e->getMessage() . PHP_EOL); error_log("RCPT RESOVLER: " . $e->getMessage() . PHP_EOL);
http_response_code(502); http_response_code(502);
exit; exit;
} }
} }
foreach ($rcpt_final_mailboxes as $rcpt_final) { foreach ($rcpt_final_mailboxes as $rcpt_final) {
error_log("QUARANTINE: quarantine pipe: processing quarantine message for rcpt " . $rcpt_final . PHP_EOL); error_log("QUARANTINE: quarantine pipe: processing quarantine message for rcpt " . $rcpt_final . PHP_EOL);
try { try {
$stmt = $pdo->prepare("INSERT INTO `quarantine` (`qid`, `subject`, `score`, `sender`, `rcpt`, `symbols`, `user`, `ip`, `msg`, `action`, `fuzzy_hashes`) $stmt = $pdo->prepare("INSERT INTO `quarantine` (`qid`, `subject`, `score`, `sender`, `rcpt`, `symbols`, `user`, `ip`, `msg`, `action`, `fuzzy_hashes`)
VALUES (:qid, :subject, :score, :sender, :rcpt, :symbols, :user, :ip, :msg, :action, :fuzzy_hashes)"); VALUES (:qid, :subject, :score, :sender, :rcpt, :symbols, :user, :ip, :msg, :action, :fuzzy_hashes)");
$stmt->execute(array( $stmt->execute(array(
':qid' => $qid, ':qid' => $qid,
':subject' => $subject, ':subject' => $subject,
':score' => $score, ':score' => $score,
':sender' => $sender, ':sender' => $sender,
':rcpt' => $rcpt_final, ':rcpt' => $rcpt_final,
':symbols' => $symbols, ':symbols' => $symbols,
':user' => $user, ':user' => $user,
':ip' => $ip, ':ip' => $ip,
':msg' => $raw_data, ':msg' => $raw_data,
':action' => $action, ':action' => $action,
':fuzzy_hashes' => $fuzzy ':fuzzy_hashes' => $fuzzy
)); ));
$stmt = $pdo->prepare('DELETE FROM `quarantine` WHERE `rcpt` = :rcpt AND `id` NOT IN ( $stmt = $pdo->prepare('DELETE FROM `quarantine` WHERE `rcpt` = :rcpt AND `id` NOT IN (
SELECT `id` SELECT `id`
FROM ( FROM (
SELECT `id` SELECT `id`
FROM `quarantine` FROM `quarantine`
WHERE `rcpt` = :rcpt2 WHERE `rcpt` = :rcpt2
ORDER BY id DESC ORDER BY id DESC
LIMIT :retention_size LIMIT :retention_size
) x ) x
);'); );');
$stmt->execute(array( $stmt->execute(array(
':rcpt' => $rcpt_final, ':rcpt' => $rcpt_final,
':rcpt2' => $rcpt_final, ':rcpt2' => $rcpt_final,
':retention_size' => $retention_size ':retention_size' => $retention_size
)); ));
} }
catch (PDOException $e) { catch (PDOException $e) {
error_log("QUARANTINE: " . $e->getMessage() . PHP_EOL); error_log("QUARANTINE: " . $e->getMessage() . PHP_EOL);
http_response_code(503); http_response_code(503);
exit; exit;
} }
} }

View File

@ -1,48 +1,48 @@
<?php <?php
// File size is limited by Nginx site to 10M // File size is limited by Nginx site to 10M
// To speed things up, we do not include prerequisites // To speed things up, we do not include prerequisites
header('Content-Type: text/plain'); header('Content-Type: text/plain');
require_once "vars.inc.php"; require_once "vars.inc.php";
// Do not show errors, we log to using error_log // Do not show errors, we log to using error_log
ini_set('error_reporting', 0); ini_set('error_reporting', 0);
// Init Redis // Init Redis
$redis = new Redis(); $redis = new Redis();
try { try {
if (!empty(getenv('REDIS_SLAVEOF_IP'))) { if (!empty(getenv('REDIS_SLAVEOF_IP'))) {
$redis->connect(getenv('REDIS_SLAVEOF_IP'), getenv('REDIS_SLAVEOF_PORT')); $redis->connect(getenv('REDIS_SLAVEOF_IP'), getenv('REDIS_SLAVEOF_PORT'));
} }
else { else {
$redis->connect('redis-mailcow', 6379); $redis->connect('redis-mailcow', 6379);
} }
} }
catch (Exception $e) { catch (Exception $e) {
exit; exit;
} }
$raw_data_content = file_get_contents('php://input'); $raw_data_content = file_get_contents('php://input');
$raw_data_decoded = json_decode($raw_data_content, true); $raw_data_decoded = json_decode($raw_data_content, true);
$data['time'] = time(); $data['time'] = time();
$data['rcpt'] = implode(', ', $raw_data_decoded['rcpt']); $data['rcpt'] = implode(', ', $raw_data_decoded['rcpt']);
$data['from'] = $raw_data_decoded['from']; $data['from'] = $raw_data_decoded['from'];
$data['user'] = $raw_data_decoded['user']; $data['user'] = $raw_data_decoded['user'];
$symbol_rl_key = array_search('RATELIMITED', array_column($raw_data_decoded['symbols'], 'name')); $symbol_rl_key = array_search('RATELIMITED', array_column($raw_data_decoded['symbols'], 'name'));
$data['rl_info'] = implode($raw_data_decoded['symbols'][$symbol_rl_key]['options']); $data['rl_info'] = implode($raw_data_decoded['symbols'][$symbol_rl_key]['options']);
preg_match('/(.+)\((.+)\)/i', $data['rl_info'], $rl_matches); preg_match('/(.+)\((.+)\)/i', $data['rl_info'], $rl_matches);
if (!empty($rl_matches[1]) && !empty($rl_matches[2])) { if (!empty($rl_matches[1]) && !empty($rl_matches[2])) {
$data['rl_name'] = $rl_matches[1]; $data['rl_name'] = $rl_matches[1];
$data['rl_hash'] = $rl_matches[2]; $data['rl_hash'] = $rl_matches[2];
} }
else { else {
$data['rl_name'] = 'err'; $data['rl_name'] = 'err';
$data['rl_hash'] = 'err'; $data['rl_hash'] = 'err';
} }
$data['qid'] = $raw_data_decoded['qid']; $data['qid'] = $raw_data_decoded['qid'];
$data['ip'] = $raw_data_decoded['ip']; $data['ip'] = $raw_data_decoded['ip'];
$data['message_id'] = $raw_data_decoded['message_id']; $data['message_id'] = $raw_data_decoded['message_id'];
$data['header_subject'] = implode(' ', $raw_data_decoded['header_subject']); $data['header_subject'] = implode(' ', $raw_data_decoded['header_subject']);
$data['header_from'] = implode(', ', $raw_data_decoded['header_from']); $data['header_from'] = implode(', ', $raw_data_decoded['header_from']);
$redis->lpush('RL_LOG', json_encode($data)); $redis->lpush('RL_LOG', json_encode($data));
exit; exit;

View File

@ -1,275 +1,275 @@
<?php <?php
// File size is limited by Nginx site to 10M // File size is limited by Nginx site to 10M
// To speed things up, we do not include prerequisites // To speed things up, we do not include prerequisites
header('Content-Type: text/plain'); header('Content-Type: text/plain');
require_once "vars.inc.php"; require_once "vars.inc.php";
// Do not show errors, we log to using error_log // Do not show errors, we log to using error_log
ini_set('error_reporting', 0); ini_set('error_reporting', 0);
// Init database // Init database
//$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name; //$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name;
$dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name; $dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name;
$opt = [ $opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_EMULATE_PREPARES => false,
]; ];
try { try {
$pdo = new PDO($dsn, $database_user, $database_pass, $opt); $pdo = new PDO($dsn, $database_user, $database_pass, $opt);
} }
catch (PDOException $e) { catch (PDOException $e) {
error_log("NOTIFY: " . $e . PHP_EOL); error_log("NOTIFY: " . $e . PHP_EOL);
http_response_code(501); http_response_code(501);
exit; exit;
} }
// Init Redis // Init Redis
$redis = new Redis(); $redis = new Redis();
$redis->connect('redis-mailcow', 6379); $redis->connect('redis-mailcow', 6379);
// Functions // Functions
function parse_email($email) { function parse_email($email) {
if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false; if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
$a = strrpos($email, '@'); $a = strrpos($email, '@');
return array('local' => substr($email, 0, $a), 'domain' => substr(substr($email, $a), 1)); return array('local' => substr($email, 0, $a), 'domain' => substr(substr($email, $a), 1));
} }
if (!function_exists('getallheaders')) { if (!function_exists('getallheaders')) {
function getallheaders() { function getallheaders() {
if (!is_array($_SERVER)) { if (!is_array($_SERVER)) {
return array(); return array();
} }
$headers = array(); $headers = array();
foreach ($_SERVER as $name => $value) { foreach ($_SERVER as $name => $value) {
if (substr($name, 0, 5) == 'HTTP_') { if (substr($name, 0, 5) == 'HTTP_') {
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value; $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
} }
} }
return $headers; return $headers;
} }
} }
$headers = getallheaders(); $headers = getallheaders();
$json_body = json_decode(file_get_contents('php://input')); $json_body = json_decode(file_get_contents('php://input'));
$qid = $headers['X-Rspamd-Qid']; $qid = $headers['X-Rspamd-Qid'];
$rcpts = $headers['X-Rspamd-Rcpt']; $rcpts = $headers['X-Rspamd-Rcpt'];
$sender = $headers['X-Rspamd-From']; $sender = $headers['X-Rspamd-From'];
$ip = $headers['X-Rspamd-Ip']; $ip = $headers['X-Rspamd-Ip'];
$subject = $headers['X-Rspamd-Subject']; $subject = $headers['X-Rspamd-Subject'];
$messageid= $json_body->message_id; $messageid= $json_body->message_id;
$priority = 0; $priority = 0;
$symbols_array = json_decode($headers['X-Rspamd-Symbols'], true); $symbols_array = json_decode($headers['X-Rspamd-Symbols'], true);
if (is_array($symbols_array)) { if (is_array($symbols_array)) {
foreach ($symbols_array as $symbol) { foreach ($symbols_array as $symbol) {
if ($symbol['name'] == 'HAS_X_PRIO_ONE') { if ($symbol['name'] == 'HAS_X_PRIO_ONE') {
$priority = 1; $priority = 1;
break; break;
} }
} }
} }
$sender_address = $json_body->header_from[0]; $sender_address = $json_body->header_from[0];
$sender_name = '-'; $sender_name = '-';
if (preg_match('/(?<name>.*?)<(?<address>.*?)>/i', $sender_address, $matches)) { if (preg_match('/(?<name>.*?)<(?<address>.*?)>/i', $sender_address, $matches)) {
$sender_address = $matches['address']; $sender_address = $matches['address'];
$sender_name = trim($matches['name'], '"\' '); $sender_name = trim($matches['name'], '"\' ');
} }
$to_address = $json_body->header_to[0]; $to_address = $json_body->header_to[0];
$to_name = '-'; $to_name = '-';
if (preg_match('/(?<name>.*?)<(?<address>.*?)>/i', $to_address, $matches)) { if (preg_match('/(?<name>.*?)<(?<address>.*?)>/i', $to_address, $matches)) {
$to_address = $matches['address']; $to_address = $matches['address'];
$to_name = trim($matches['name'], '"\' '); $to_name = trim($matches['name'], '"\' ');
} }
$rcpt_final_mailboxes = array(); $rcpt_final_mailboxes = array();
// Loop through all rcpts // Loop through all rcpts
foreach (json_decode($rcpts, true) as $rcpt) { foreach (json_decode($rcpts, true) as $rcpt) {
// Remove tag // Remove tag
$rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt); $rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt);
// Break rcpt into local part and domain part // Break rcpt into local part and domain part
$parsed_rcpt = parse_email($rcpt); $parsed_rcpt = parse_email($rcpt);
// Skip if not a mailcow handled domain // Skip if not a mailcow handled domain
try { try {
if (!$redis->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) { if (!$redis->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) {
continue; continue;
} }
} }
catch (RedisException $e) { catch (RedisException $e) {
error_log("NOTIFY: " . $e . PHP_EOL); error_log("NOTIFY: " . $e . PHP_EOL);
http_response_code(504); http_response_code(504);
exit; exit;
} }
// Always assume rcpt is not a final mailbox but an alias for a mailbox or further aliases // Always assume rcpt is not a final mailbox but an alias for a mailbox or further aliases
// //
// rcpt // rcpt
// | // |
// mailbox <-- goto ---> alias1, alias2, mailbox2 // mailbox <-- goto ---> alias1, alias2, mailbox2
// | | // | |
// mailbox3 | // mailbox3 |
// | // |
// alias3 ---> mailbox4 // alias3 ---> mailbox4
// //
try { try {
$stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'"); $stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'");
$stmt->execute(array( $stmt->execute(array(
':rcpt' => $rcpt ':rcpt' => $rcpt
)); ));
$gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto']; $gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
if (empty($gotos)) { if (empty($gotos)) {
$stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'"); $stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'");
$stmt->execute(array( $stmt->execute(array(
':rcpt' => '@' . $parsed_rcpt['domain'] ':rcpt' => '@' . $parsed_rcpt['domain']
)); ));
$gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto']; $gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
} }
if (empty($gotos)) { if (empty($gotos)) {
$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :rcpt AND `active` = '1'"); $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :rcpt AND `active` = '1'");
$stmt->execute(array(':rcpt' => $parsed_rcpt['domain'])); $stmt->execute(array(':rcpt' => $parsed_rcpt['domain']));
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain']; $goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain'];
if ($goto_branch) { if ($goto_branch) {
$gotos = $parsed_rcpt['local'] . '@' . $goto_branch; $gotos = $parsed_rcpt['local'] . '@' . $goto_branch;
} }
} }
$gotos_array = explode(',', $gotos); $gotos_array = explode(',', $gotos);
$loop_c = 0; $loop_c = 0;
while (count($gotos_array) != 0 && $loop_c <= 20) { while (count($gotos_array) != 0 && $loop_c <= 20) {
// Loop through all found gotos // Loop through all found gotos
foreach ($gotos_array as $index => &$goto) { foreach ($gotos_array as $index => &$goto) {
error_log("RCPT RESOVLER: http pipe: query " . $goto . " as username from mailbox" . PHP_EOL); error_log("RCPT RESOVLER: http pipe: query " . $goto . " as username from mailbox" . PHP_EOL);
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :goto AND (`active`= '1' OR `active`= '2');"); $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :goto AND (`active`= '1' OR `active`= '2');");
$stmt->execute(array(':goto' => $goto)); $stmt->execute(array(':goto' => $goto));
$username = $stmt->fetch(PDO::FETCH_ASSOC)['username']; $username = $stmt->fetch(PDO::FETCH_ASSOC)['username'];
if (!empty($username)) { if (!empty($username)) {
error_log("RCPT RESOVLER: http pipe: mailbox found: " . $username . PHP_EOL); error_log("RCPT RESOVLER: http pipe: mailbox found: " . $username . PHP_EOL);
// Current goto is a mailbox, save to rcpt_final_mailboxes if not a duplicate // Current goto is a mailbox, save to rcpt_final_mailboxes if not a duplicate
if (!in_array($username, $rcpt_final_mailboxes)) { if (!in_array($username, $rcpt_final_mailboxes)) {
$rcpt_final_mailboxes[] = $username; $rcpt_final_mailboxes[] = $username;
} }
} }
else { else {
$parsed_goto = parse_email($goto); $parsed_goto = parse_email($goto);
if (!$redis->hGet('DOMAIN_MAP', $parsed_goto['domain'])) { if (!$redis->hGet('DOMAIN_MAP', $parsed_goto['domain'])) {
error_log("RCPT RESOVLER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL); error_log("RCPT RESOVLER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL);
} }
else { else {
$stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :goto AND `active` = '1'"); $stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :goto AND `active` = '1'");
$stmt->execute(array(':goto' => $goto)); $stmt->execute(array(':goto' => $goto));
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['goto']; $goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
if ($goto_branch) { if ($goto_branch) {
error_log("RCPT RESOVLER: http pipe: goto address " . $goto . " is an alias branch for " . $goto_branch . PHP_EOL); error_log("RCPT RESOVLER: http pipe: goto address " . $goto . " is an alias branch for " . $goto_branch . PHP_EOL);
$goto_branch_array = explode(',', $goto_branch); $goto_branch_array = explode(',', $goto_branch);
} else { } else {
$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain AND `active` AND '1'"); $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain AND `active` AND '1'");
$stmt->execute(array(':domain' => $parsed_goto['domain'])); $stmt->execute(array(':domain' => $parsed_goto['domain']));
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain']; $goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain'];
if ($goto_branch) { if ($goto_branch) {
error_log("RCPT RESOVLER: http pipe: goto domain " . $parsed_goto['domain'] . " is a domain alias branch for " . $goto_branch . PHP_EOL); error_log("RCPT RESOVLER: http pipe: goto domain " . $parsed_goto['domain'] . " is a domain alias branch for " . $goto_branch . PHP_EOL);
$goto_branch_array = array($parsed_goto['local'] . '@' . $goto_branch); $goto_branch_array = array($parsed_goto['local'] . '@' . $goto_branch);
} }
} }
} }
} }
// goto item was processed, unset // goto item was processed, unset
unset($gotos_array[$index]); unset($gotos_array[$index]);
} }
// Merge goto branch array derived from previous loop (if any), filter duplicates and unset goto branch array // Merge goto branch array derived from previous loop (if any), filter duplicates and unset goto branch array
if (!empty($goto_branch_array)) { if (!empty($goto_branch_array)) {
$gotos_array = array_unique(array_merge($gotos_array, $goto_branch_array)); $gotos_array = array_unique(array_merge($gotos_array, $goto_branch_array));
unset($goto_branch_array); unset($goto_branch_array);
} }
// Reindex array // Reindex array
$gotos_array = array_values($gotos_array); $gotos_array = array_values($gotos_array);
// Force exit if loop cannot be solved // Force exit if loop cannot be solved
// Postfix does not allow for alias loops, so this should never happen. // Postfix does not allow for alias loops, so this should never happen.
$loop_c++; $loop_c++;
error_log("RCPT RESOVLER: http pipe: goto array count on loop #". $loop_c . " is " . count($gotos_array) . PHP_EOL); error_log("RCPT RESOVLER: http pipe: goto array count on loop #". $loop_c . " is " . count($gotos_array) . PHP_EOL);
} }
} }
catch (PDOException $e) { catch (PDOException $e) {
error_log("RCPT RESOVLER: " . $e->getMessage() . PHP_EOL); error_log("RCPT RESOVLER: " . $e->getMessage() . PHP_EOL);
http_response_code(502); http_response_code(502);
exit; exit;
} }
} }
foreach ($rcpt_final_mailboxes as $rcpt_final) { foreach ($rcpt_final_mailboxes as $rcpt_final) {
error_log("NOTIFY: pushover pipe: processing pushover message for rcpt " . $rcpt_final . PHP_EOL); error_log("NOTIFY: pushover pipe: processing pushover message for rcpt " . $rcpt_final . PHP_EOL);
$stmt = $pdo->prepare("SELECT * FROM `pushover` $stmt = $pdo->prepare("SELECT * FROM `pushover`
WHERE `username` = :username AND `active` = '1'"); WHERE `username` = :username AND `active` = '1'");
$stmt->execute(array( $stmt->execute(array(
':username' => $rcpt_final ':username' => $rcpt_final
)); ));
$api_data = $stmt->fetch(PDO::FETCH_ASSOC); $api_data = $stmt->fetch(PDO::FETCH_ASSOC);
if (isset($api_data['key']) && isset($api_data['token'])) { if (isset($api_data['key']) && isset($api_data['token'])) {
$title = (!empty($api_data['title'])) ? $api_data['title'] : 'Mail'; $title = (!empty($api_data['title'])) ? $api_data['title'] : 'Mail';
$text = (!empty($api_data['text'])) ? $api_data['text'] : 'You\'ve got mail 📧'; $text = (!empty($api_data['text'])) ? $api_data['text'] : 'You\'ve got mail 📧';
$attributes = json_decode($api_data['attributes'], true); $attributes = json_decode($api_data['attributes'], true);
$senders = explode(',', $api_data['senders']); $senders = explode(',', $api_data['senders']);
$senders = array_filter($senders); $senders = array_filter($senders);
$senders_regex = $api_data['senders_regex']; $senders_regex = $api_data['senders_regex'];
$sender_validated = false; $sender_validated = false;
if (empty($senders) && empty($senders_regex)) { if (empty($senders) && empty($senders_regex)) {
$sender_validated = true; $sender_validated = true;
} }
else { else {
if (!empty($senders)) { if (!empty($senders)) {
if (in_array($sender, $senders)) { if (in_array($sender, $senders)) {
$sender_validated = true; $sender_validated = true;
} }
} }
if (!empty($senders_regex) && $sender_validated !== true) { if (!empty($senders_regex) && $sender_validated !== true) {
if (preg_match($senders_regex, $sender)) { if (preg_match($senders_regex, $sender)) {
$sender_validated = true; $sender_validated = true;
} }
} }
} }
if ($sender_validated === false) { if ($sender_validated === false) {
error_log("NOTIFY: pushover pipe: skipping unwanted sender " . $sender); error_log("NOTIFY: pushover pipe: skipping unwanted sender " . $sender);
continue; continue;
} }
if ($attributes['only_x_prio'] == "1" && $priority == 0) { if ($attributes['only_x_prio'] == "1" && $priority == 0) {
error_log("NOTIFY: pushover pipe: mail has no X-Priority: 1 header, skipping"); error_log("NOTIFY: pushover pipe: mail has no X-Priority: 1 header, skipping");
continue; continue;
} }
$post_fields = array( $post_fields = array(
"token" => $api_data['token'], "token" => $api_data['token'],
"user" => $api_data['key'], "user" => $api_data['key'],
"title" => sprintf("%s", str_replace( "title" => sprintf("%s", str_replace(
array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO_NAME}', '{TO_ADDRESS}', '{MSG_ID}'), array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO_NAME}', '{TO_ADDRESS}', '{MSG_ID}'),
array($subject, $sender, $sender_name, $sender_address, $to_name, $to_address, $messageid), $title) array($subject, $sender, $sender_name, $sender_address, $to_name, $to_address, $messageid), $title)
), ),
"priority" => $priority, "priority" => $priority,
"message" => sprintf("%s", str_replace( "message" => sprintf("%s", str_replace(
array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO_NAME}', '{TO_ADDRESS}', '{MSG_ID}', '\n'), array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO_NAME}', '{TO_ADDRESS}', '{MSG_ID}', '\n'),
array($subject, $sender, $sender_name, $sender_address, $to_name, $to_address, $messageid, PHP_EOL), $text) array($subject, $sender, $sender_name, $sender_address, $to_name, $to_address, $messageid, PHP_EOL), $text)
), ),
"sound" => $attributes['sound'] ?? "pushover" "sound" => $attributes['sound'] ?? "pushover"
); );
if ($attributes['evaluate_x_prio'] == "1" && $priority == 1) { if ($attributes['evaluate_x_prio'] == "1" && $priority == 1) {
$post_fields['expire'] = 600; $post_fields['expire'] = 600;
$post_fields['retry'] = 120; $post_fields['retry'] = 120;
$post_fields['priority'] = 2; $post_fields['priority'] = 2;
} }
curl_setopt_array($ch = curl_init(), array( curl_setopt_array($ch = curl_init(), array(
CURLOPT_URL => "https://api.pushover.net/1/messages.json", CURLOPT_URL => "https://api.pushover.net/1/messages.json",
CURLOPT_POSTFIELDS => $post_fields, CURLOPT_POSTFIELDS => $post_fields,
CURLOPT_SAFE_UPLOAD => true, CURLOPT_SAFE_UPLOAD => true,
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
)); ));
$result = curl_exec($ch); $result = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch); curl_close($ch);
error_log("NOTIFY: result: " . $httpcode . PHP_EOL); error_log("NOTIFY: result: " . $httpcode . PHP_EOL);
} }
} }

View File

@ -1,28 +1,28 @@
<!-- <!--
<example> <example>
<key>canAuthenticate</key> <key>canAuthenticate</key>
<string>YES</string> <string>YES</string>
<key>id</key> <key>id</key>
<string>${line}_ldap</string> <string>${line}_ldap</string>
<key>isAddressBook</key> <key>isAddressBook</key>
<string>NO</string> <string>NO</string>
<key>IDFieldName</key> <key>IDFieldName</key>
<string>mail</string> <string>mail</string>
<key>UIDFieldName</key> <key>UIDFieldName</key>
<string>uid</string> <string>uid</string>
<key>bindFields</key> <key>bindFields</key>
<array> <array>
<string>mail</string> <string>mail</string>
</array> </array>
<key>type</key> <key>type</key>
<string>ldap</string> <string>ldap</string>
<key>bindDN</key> <key>bindDN</key>
<string>cn=admin,dc=example,dc=local</string> <string>cn=admin,dc=example,dc=local</string>
<key>bindPassword</key> <key>bindPassword</key>
<string>password</string> <string>password</string>
<key>baseDN</key> <key>baseDN</key>
<string>ou=People,dc=example,dc=local</string> <string>ou=People,dc=example,dc=local</string>
<key>hostname</key> <key>hostname</key>
<string>ldap://1.2.3.4:389</string> <string>ldap://1.2.3.4:389</string>
</example> </example>
--> -->

View File

@ -1,10 +1,10 @@
/*! /*!
* Bootstrap-select v1.14.0-beta2 (https://developer.snapappointments.com/bootstrap-select) * Bootstrap-select v1.14.0-beta2 (https://developer.snapappointments.com/bootstrap-select)
* *
* Copyright 2012-2021 SnapAppointments, LLC * Copyright 2012-2021 SnapAppointments, LLC
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE) * Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
*/ */
@-webkit-keyframes bs-notify-fadeOut { @-webkit-keyframes bs-notify-fadeOut {
0% { 0% {
opacity: 0.9; opacity: 0.9;

View File

@ -1,372 +1,372 @@
@font-face { @font-face {
font-family: 'Noto Sans'; font-family: 'Noto Sans';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
src: local(''), src: local(''),
url('/fonts/noto-sans-v12-latin_greek_cyrillic-regular.woff2') format('woff2'), url('/fonts/noto-sans-v12-latin_greek_cyrillic-regular.woff2') format('woff2'),
url('/fonts/noto-sans-v12-latin_greek_cyrillic-regular.woff') format('woff'); url('/fonts/noto-sans-v12-latin_greek_cyrillic-regular.woff') format('woff');
} }
@font-face { @font-face {
font-family: 'Noto Sans'; font-family: 'Noto Sans';
font-style: normal; font-style: normal;
font-weight: 700; font-weight: 700;
src: local(''), src: local(''),
url('/fonts/noto-sans-v12-latin_greek_cyrillic-700.woff2') format('woff2'), url('/fonts/noto-sans-v12-latin_greek_cyrillic-700.woff2') format('woff2'),
url('/fonts/noto-sans-v12-latin_greek_cyrillic-700.woff') format('woff'); url('/fonts/noto-sans-v12-latin_greek_cyrillic-700.woff') format('woff');
} }
@font-face { @font-face {
font-family: 'Noto Sans'; font-family: 'Noto Sans';
font-style: italic; font-style: italic;
font-weight: 400; font-weight: 400;
src: local(''), src: local(''),
url('/fonts/noto-sans-v12-latin_greek_cyrillic-italic.woff2') format('woff2'), url('/fonts/noto-sans-v12-latin_greek_cyrillic-italic.woff2') format('woff2'),
url('/fonts/noto-sans-v12-latin_greek_cyrillic-italic.woff') format('woff'); url('/fonts/noto-sans-v12-latin_greek_cyrillic-italic.woff') format('woff');
} }
@font-face { @font-face {
font-family: 'Noto Sans'; font-family: 'Noto Sans';
font-style: italic; font-style: italic;
font-weight: 700; font-weight: 700;
src: local(''), src: local(''),
url('/fonts/noto-sans-v12-latin_greek_cyrillic-700italic.woff2') format('woff2'), url('/fonts/noto-sans-v12-latin_greek_cyrillic-700italic.woff2') format('woff2'),
url('/fonts/noto-sans-v12-latin_greek_cyrillic-700italic.woff') format('woff'); url('/fonts/noto-sans-v12-latin_greek_cyrillic-700italic.woff') format('woff');
} }
#maxmsgsize { min-width: 80px; } #maxmsgsize { min-width: 80px; }
#slider1 .slider-selection { #slider1 .slider-selection {
background: #FFD700; background: #FFD700;
} }
#slider1 .slider-track-high { #slider1 .slider-track-high {
background: #FF4500; background: #FF4500;
} }
#slider1 .slider-track-low { #slider1 .slider-track-low {
background: #66CD00; background: #66CD00;
} }
.striped:nth-child(odd) { .striped:nth-child(odd) {
background-color: #fff; background-color: #fff;
} }
.striped:nth-child(even) { .striped:nth-child(even) {
background-color: #fafafa; background-color: #fafafa;
border:1px solid white; border:1px solid white;
} }
.btn { .btn {
text-transform: none; text-transform: none;
} }
.btn * { .btn * {
pointer-events: none; pointer-events: none;
} }
.textarea-code { .textarea-code {
font-family:Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace; font-family:Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace;
background:transparent !important; background:transparent !important;
} }
.navbar-nav { .navbar-nav {
margin: 0; margin: 0;
} }
.navbar-nav .nav-item { .navbar-nav .nav-item {
flex-direction: column; flex-direction: column;
display: flex; display: flex;
padding: 0 10px !important; padding: 0 10px !important;
} }
.navbar-nav .nav-link { .navbar-nav .nav-link {
height: 44px; height: 44px;
display: flex; display: flex;
align-items: center; align-items: center;
padding: 0 10px !important; padding: 0 10px !important;
} }
.navbar-fixed-bottom .navbar-collapse, .navbar-fixed-bottom .navbar-collapse,
.navbar-fixed-top .navbar-collapse { .navbar-fixed-top .navbar-collapse {
max-height: 1000px max-height: 1000px
} }
.bi { .bi {
display: inline-block; display: inline-block;
font-size: 12pt; font-size: 12pt;
} }
.btn .bi { .btn .bi {
display: inline-block; display: inline-block;
font-size: inherit; font-size: inherit;
} }
.btn-group-xs > .btn, .btn-xs { .btn-group-xs > .btn, .btn-xs {
padding: .25rem .4rem; padding: .25rem .4rem;
font-size: .875rem; font-size: .875rem;
line-height: 1rem; line-height: 1rem;
border-radius: .2rem; border-radius: .2rem;
} }
.icon-spin { .icon-spin {
animation-name: spin; animation-name: spin;
animation-duration: 2000ms; animation-duration: 2000ms;
animation-iteration-count: infinite; animation-iteration-count: infinite;
animation-timing-function: linear; animation-timing-function: linear;
-webkit-animation: spin 2000ms infinite linear; -webkit-animation: spin 2000ms infinite linear;
} }
.dropdown-menu { .dropdown-menu {
font-size: 0.9rem; font-size: 0.9rem;
} }
@-webkit-keyframes spin { @-webkit-keyframes spin {
0% { 0% {
-webkit-transform: rotate(0deg); -webkit-transform: rotate(0deg);
transform: rotate(0deg); transform: rotate(0deg);
} }
100% { 100% {
-webkit-transform: rotate(359deg); -webkit-transform: rotate(359deg);
transform: rotate(359deg); transform: rotate(359deg);
} }
} }
@keyframes spin { @keyframes spin {
0% { 0% {
-webkit-transform: rotate(0deg); -webkit-transform: rotate(0deg);
transform: rotate(0deg); transform: rotate(0deg);
} }
100% { 100% {
-webkit-transform: rotate(359deg); -webkit-transform: rotate(359deg);
transform: rotate(359deg); transform: rotate(359deg);
} }
} }
@keyframes blink { @keyframes blink {
50% { 50% {
color: transparent color: transparent
} }
} }
.loader-dot { .loader-dot {
animation: 1s blink infinite animation: 1s blink infinite
} }
.loader-dot:nth-child(2) { .loader-dot:nth-child(2) {
animation-delay: 250ms animation-delay: 250ms
} }
.loader-dot:nth-child(3) { .loader-dot:nth-child(3) {
animation-delay: 500ms animation-delay: 500ms
} }
pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;} pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;}
/* Fix modal moving content left */ /* Fix modal moving content left */
body.modal-open { body.modal-open {
overflow: inherit; overflow: inherit;
padding-right: inherit !important; padding-right: inherit !important;
} }
body { body {
font-family: "Noto Sans","Helvetica Neue",Helvetica,Arial,sans-serif; font-family: "Noto Sans","Helvetica Neue",Helvetica,Arial,sans-serif;
font-size: 10.5pt; font-size: 10.5pt;
line-height: 1.5; line-height: 1.5;
} }
html { html {
font-family: "Noto Sans","Helvetica Neue",Helvetica,Arial,sans-serif; font-family: "Noto Sans","Helvetica Neue",Helvetica,Arial,sans-serif;
font-size: 10.5pt; font-size: 10.5pt;
line-height: 1.5; line-height: 1.5;
} }
#mailcow-alert { #mailcow-alert {
position: fixed; position: fixed;
bottom: 8px; bottom: 8px;
right: 25px; right: 25px;
min-width: 350px; min-width: 350px;
max-width: 550px; max-width: 550px;
z-index: 2000; z-index: 2000;
} }
.input-group-sm .btn { margin-top: 0 !important } .input-group-sm .btn { margin-top: 0 !important }
legend { legend {
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none; -ms-user-select: none;
-o-user-select: none; -o-user-select: none;
user-select: none; user-select: none;
font-size: 1.2rem; font-size: 1.2rem;
} }
.navbar .navbar-brand { .navbar .navbar-brand {
padding-top: 5px; padding-top: 5px;
} }
.navbar .navbar-brand img { .navbar .navbar-brand img {
height: 40px; height: 40px;
} }
.mailcow-logo img { .mailcow-logo img {
max-width: 250px; max-width: 250px;
} }
.lang-link-disabled a { .lang-link-disabled a {
pointer-events: none; pointer-events: none;
} }
.lang-link-disabled { .lang-link-disabled {
cursor: not-allowed; cursor: not-allowed;
} }
.overlay { .overlay {
background: #fff; background: #fff;
position: absolute; position: absolute;
z-index: 10000; z-index: 10000;
top: 0; right: 0; bottom: 0; left: 0; top: 0; right: 0; bottom: 0; left: 0;
opacity: 0.7; opacity: 0.7;
} }
.bootstrap-select.btn-group .no-results { .bootstrap-select.btn-group .no-results {
display: none; display: none;
} }
.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary { .bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary {
color: rgb(197, 197, 197) !important; color: rgb(197, 197, 197) !important;
} }
.haveibeenpwned { .haveibeenpwned {
cursor: pointer; cursor: pointer;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none; -ms-user-select: none;
user-select: none; user-select: none;
} }
.full-width-select { .full-width-select {
width: 100%!important; width: 100%!important;
} }
.tooltip { .tooltip {
font-family: inherit; font-family: inherit;
font-size: 0.8rem; font-size: 0.8rem;
} }
.progress-bar { .progress-bar {
font-size: 0.8rem; font-size: 0.8rem;
line-height: 14px; line-height: 14px;
} }
.footer { .footer {
margin-top: 27px; margin-top: 27px;
margin-bottom: 20px; margin-bottom: 20px;
color: #959595; color: #959595;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.footer .version { .footer .version {
margin-left: auto; margin-left: auto;
margin-top: 20px; margin-top: 20px;
} }
.slave-info { .slave-info {
padding: 15px 0px 15px 15px; padding: 15px 0px 15px 15px;
font-weight: bold; font-weight: bold;
} }
.alert-hr { .alert-hr {
margin:3px 0px; margin:3px 0px;
border-bottom:1px solid #f5f5f5!important; border-bottom:1px solid #f5f5f5!important;
opacity: 0.3; opacity: 0.3;
} }
.btn-input-missing, .btn-input-missing,
.btn-input-missing:hover, .btn-input-missing:hover,
.btn-input-missing:active, .btn-input-missing:active,
.btn-input-missing:focus, .btn-input-missing:focus,
.btn-input-missing:active:hover, .btn-input-missing:active:hover,
.btn-input-missing:active:focus { .btn-input-missing:active:focus {
color: #000 !important; color: #000 !important;
background-color: #ff2f24 !important; background-color: #ff2f24 !important;
border-color: #e21207 !important; border-color: #e21207 !important;
} }
.navbar-nav > li { .navbar-nav > li {
font-size: 1rem !important; font-size: 1rem !important;
} }
.dropdown-menu > li > a { .dropdown-menu > li > a {
font-size: 1rem !important; font-size: 1rem !important;
} }
.label { .label {
font-size:inherit; font-size:inherit;
} }
[class^="bi-"]::before, [class*=" bi-"]::before { [class^="bi-"]::before, [class*=" bi-"]::before {
vertical-align: -0.2em !important; vertical-align: -0.2em !important;
} }
legend > [class^="bi-"]::before, legend > [class*=" bi-"]::before { legend > [class^="bi-"]::before, legend > [class*=" bi-"]::before {
vertical-align: 0em !important; vertical-align: 0em !important;
} }
code { code {
font-size: inherit; font-size: inherit;
} }
.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a span.check-mark { .bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a span.check-mark {
margin-top: 0px; margin-top: 0px;
} }
.flag-icon { .flag-icon {
margin-right: 5px; margin-right: 5px;
} }
.dropdown-header { .dropdown-header {
font-weight: 600; font-weight: 600;
} }
.tag-box { .tag-box {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
height: auto; height: auto;
} }
.tag-badge { .tag-badge {
transition: 200ms linear; transition: 200ms linear;
margin-top: 5px; margin-top: 5px;
margin-bottom: 5px; margin-bottom: 5px;
margin-left: 2px; margin-left: 2px;
margin-right: 2px; margin-right: 2px;
} }
.tag-badge.btn-badge { .tag-badge.btn-badge {
cursor: pointer; cursor: pointer;
} }
.tag-badge .bi { .tag-badge .bi {
font-size: 12px; font-size: 12px;
} }
.tag-badge.btn-badge:hover { .tag-badge.btn-badge:hover {
filter: brightness(0.9); filter: brightness(0.9);
} }
.tag-input { .tag-input {
margin-left: 10px; margin-left: 10px;
border: 0 !important; border: 0 !important;
flex: 1; flex: 1;
height: 24px; height: 24px;
min-width: 150px; min-width: 150px;
} }
.tag-input:focus { .tag-input:focus {
outline: none; outline: none;
} }
.tag-add { .tag-add {
padding: 0 5px 0 5px; padding: 0 5px 0 5px;
align-items: center; align-items: center;
display: inline-flex; display: inline-flex;
} }
#dnstable { #dnstable {
overflow-x: auto!important; overflow-x: auto!important;
} }
.well { .well {
border: 1px solid #dfdfdf; border: 1px solid #dfdfdf;
background-color: #f9f9f9; background-color: #f9f9f9;
padding: 10px; padding: 10px;
} }
.btn-check-label { .btn-check-label {
color: #555; color: #555;
} }
.caret { .caret {
transform: rotate(0deg); transform: rotate(0deg);
} }
a[aria-expanded='true'] > .caret, a[aria-expanded='true'] > .caret,
button[aria-expanded='true'] > .caret { button[aria-expanded='true'] > .caret {
transform: rotate(-180deg); transform: rotate(-180deg);
} }
.list-group-details { .list-group-details {
background: #fff; background: #fff;
} }
.list-group-header { .list-group-header {
background: #f7f7f7; background: #f7f7f7;
} }
.bg-primary, .alert-primary, .btn-primary { .bg-primary, .alert-primary, .btn-primary {
background-color: #0F688D !important; background-color: #0F688D !important;
border-color: #0d526d !important; border-color: #0d526d !important;
} }
.bg-info, .alert-info, .btn-info { .bg-info, .alert-info, .btn-info {
background-color: #148DBC !important; background-color: #148DBC !important;
border-color: #127ea8 !important; border-color: #127ea8 !important;
} }
.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary { .bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary {
color: rgb(137 137 137)!important; color: rgb(137 137 137)!important;
} }
.progress { .progress {
background-color: #d5d5d5; background-color: #d5d5d5;
} }
.btn-outline-secondary:hover { .btn-outline-secondary:hover {
background-color: #f0f0f0; background-color: #f0f0f0;
} }
.btn.btn-outline-secondary { .btn.btn-outline-secondary {
border-color: #cfcfcf !important; border-color: #cfcfcf !important;
} }
.btn-check:checked+.btn-outline-secondary, .btn-check:active+.btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show { .btn-check:checked+.btn-outline-secondary, .btn-check:active+.btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show {
background-color: #f0f0f0 !important; background-color: #f0f0f0 !important;
} }

View File

@ -1,86 +1,86 @@
.pagination a { .pagination a {
text-decoration: none !important; text-decoration: none !important;
} }
.panel.panel-default { .panel.panel-default {
overflow: visible !important; overflow: visible !important;
} }
.table-responsive { .table-responsive {
overflow: visible !important; overflow: visible !important;
} }
.table-responsive { .table-responsive {
overflow-x: scroll !important; overflow-x: scroll !important;
} }
body { body {
overflow-y:scroll; overflow-y:scroll;
} }
/* Fix modal moving content left */ /* Fix modal moving content left */
body.modal-open { body.modal-open {
overflow-y:scroll; overflow-y:scroll;
padding-right: inherit !important; padding-right: inherit !important;
} }
@media (min-width: 992px) { @media (min-width: 992px) {
.container { .container {
width: 80%; width: 80%;
} }
} }
.mass-actions-admin { .mass-actions-admin {
user-select: none; user-select: none;
} }
.inputMissingAttr { .inputMissingAttr {
border-color: #FF4136; border-color: #FF4136;
} }
.rotate { .rotate {
-moz-transition: all 0.3s linear; -moz-transition: all 0.3s linear;
-webkit-transition: all 0.3s linear; -webkit-transition: all 0.3s linear;
transition: all 0.3s linear; transition: all 0.3s linear;
} }
.rotate.animation { .rotate.animation {
-ms-transform:rotateX(180deg); -ms-transform:rotateX(180deg);
-moz-transform:rotateX(180deg); -moz-transform:rotateX(180deg);
-webkit-transform:rotateX(180deg); -webkit-transform:rotateX(180deg);
transform:rotateX(180deg); transform:rotateX(180deg);
} }
.anchor { .anchor {
display: block; display: block;
height: 65px; height: 65px;
margin-top: -65px; margin-top: -65px;
visibility: hidden; visibility: hidden;
} }
.thumbnail img { .thumbnail img {
min-height:100px; min-height:100px;
height:100px; height:100px;
} }
.nav-tabs>li>a { .nav-tabs>li>a {
z-index: 1; z-index: 1;
} }
.table-condensed .input-sm { .table-condensed .input-sm {
width: 100%!important; width: 100%!important;
} }
.table-condensed > thead > tr > th, .table-condensed > tbody > tr > th, .table-condensed > tfoot > tr > th, .table-condensed > thead > tr > td, .table-condensed > tbody > tr > td, .table-condensed > tfoot > tr > td { .table-condensed > thead > tr > th, .table-condensed > tbody > tr > th, .table-condensed > tfoot > tr > th, .table-condensed > thead > tr > td, .table-condensed > tbody > tr > td, .table-condensed > tfoot > tr > td {
padding: 3px; padding: 3px;
} }
table tbody tr { table tbody tr {
cursor: pointer; cursor: pointer;
} }
table tbody tr td input[type="checkbox"] { table tbody tr td input[type="checkbox"] {
cursor: pointer; cursor: pointer;
} }
#quarantine_template { #quarantine_template {
margin:20px; margin:20px;
} }
.regex-input { .regex-input {
font-family: Consolas,monaco,monospace; font-family: Consolas,monaco,monospace;
font-size: 1rem; font-size: 1rem;
} }
.label-keys { .label-keys {
font-size:100%; font-size:100%;
margin: 0px !important; margin: 0px !important;
white-space: normal !important; white-space: normal !important;
} }
.key-action { .key-action {
font-weight:bold; font-weight:bold;
color:white !important; color:white !important;
} }
.dkim-label { .dkim-label {
margin: 0 0 8px !important; margin: 0 0 8px !important;
} }

View File

@ -1,36 +1,36 @@
.pagination a { .pagination a {
text-decoration: none !important; text-decoration: none !important;
} }
.panel.panel-default { .panel.panel-default {
overflow: visible !important; overflow: visible !important;
} }
.table-responsive { .table-responsive {
overflow: visible !important; overflow: visible !important;
} }
@media screen and (max-width: 1280px) { @media screen and (max-width: 1280px) {
.table-responsive { .table-responsive {
overflow-x: scroll !important; overflow-x: scroll !important;
} }
} }
.footer-add-item { .footer-add-item {
display:block; display:block;
text-align: center; text-align: center;
font-style: italic; font-style: italic;
padding: 10px; padding: 10px;
background: #F5F5F5; background: #F5F5F5;
} }
@media (min-width: 992px) { @media (min-width: 992px) {
.container { .container {
width: 80%; width: 80%;
} }
} }
.mass-actions-debug { .mass-actions-debug {
user-select: none; user-select: none;
} }
.inputMissingAttr { .inputMissingAttr {
border-color: #FF4136; border-color: #FF4136;
} }
.table-lines { .table-lines {
vertical-align: inherit; vertical-align: inherit;
} }

View File

@ -1,42 +1,42 @@
.pagination a { .pagination a {
text-decoration: none !important; text-decoration: none !important;
} }
.panel.panel-default { .panel.panel-default {
overflow: visible !important; overflow: visible !important;
} }
.table-responsive { .table-responsive {
overflow: visible !important; overflow: visible !important;
} }
@media screen and (max-width: 767px) { @media screen and (max-width: 767px) {
.table-responsive { .table-responsive {
overflow-x: scroll !important; overflow-x: scroll !important;
} }
} }
.footer-add-item { .footer-add-item {
display:block; display:block;
text-align: center; text-align: center;
font-style: italic; font-style: italic;
padding: 10px; padding: 10px;
background: #F5F5F5; background: #F5F5F5;
} }
.mass-actions-user { .mass-actions-user {
user-select: none; user-select: none;
} }
.inputMissingAttr { .inputMissingAttr {
border-color: #FF4136; border-color: #FF4136;
} }
.rotate { .rotate {
-moz-transition: all 0.3s linear; -moz-transition: all 0.3s linear;
-webkit-transition: all 0.3s linear; -webkit-transition: all 0.3s linear;
transition: all 0.3s linear; transition: all 0.3s linear;
} }
.rotate.animation { .rotate.animation {
-ms-transform:rotateX(180deg); -ms-transform:rotateX(180deg);
-moz-transform:rotateX(180deg); -moz-transform:rotateX(180deg);
-webkit-transform:rotateX(180deg); -webkit-transform:rotateX(180deg);
transform:rotateX(180deg); transform:rotateX(180deg);
} }
#sender_acl_disabled { #sender_acl_disabled {
display:none; display:none;
margin-top:10px; margin-top:10px;
} }

View File

@ -1,8 +1,8 @@
@media (max-width: 500px) { @media (max-width: 500px) {
#top { #top {
padding-top: 15px !important; padding-top: 15px !important;
} }
} }
.ui-announcement-alert { .ui-announcement-alert {
margin: 10px 0px 10px 0px; margin: 10px 0px 10px 0px;
} }

View File

@ -1,69 +1,69 @@
.pagination a { .pagination a {
text-decoration: none !important; text-decoration: none !important;
} }
.panel.panel-default { .panel.panel-default {
overflow: visible !important; overflow: visible !important;
} }
.table-responsive { .table-responsive {
overflow: inherit !important; overflow: inherit !important;
} }
.table-responsive { .table-responsive {
overflow-x: scroll !important; overflow-x: scroll !important;
} }
.btn-group { .btn-group {
width: max-content; width: max-content;
} }
.footer-add-item { .footer-add-item {
display:block; display:block;
text-align: center; text-align: center;
font-style: italic; font-style: italic;
padding: 10px; padding: 10px;
background: #F5F5F5; background: #F5F5F5;
} }
@media (min-width: 992px) { @media (min-width: 992px) {
.container { .container {
width: 100%; width: 100%;
} }
} }
@media (min-width: 1920px) { @media (min-width: 1920px) {
.container { .container {
width: 80%; width: 80%;
} }
} }
.mass-actions-mailbox { .mass-actions-mailbox {
user-select: none; user-select: none;
} }
.inputMissingAttr { .inputMissingAttr {
border-color: #FF4136; border-color: #FF4136;
} }
.dns-found { .dns-found {
max-width: 300px; max-width: 300px;
word-break: break-all; word-break: break-all;
} }
.dns-recommended { .dns-recommended {
max-width: 150px; max-width: 150px;
word-break: break-all; word-break: break-all;
} }
.table-lines { .table-lines {
vertical-align: inherit; vertical-align: inherit;
} }
#logText { #logText {
font-family:Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace; font-family:Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace;
font-size:smaller; font-size:smaller;
} }
table tbody tr { table tbody tr {
cursor: pointer; cursor: pointer;
} }
table tbody tr td input[type="checkbox"] { table tbody tr td input[type="checkbox"] {
cursor: pointer; cursor: pointer;
} }
.label-last-login .bi { .label-last-login .bi {
font-size: 8pt !important; font-size: 8pt !important;
} }
.label-last-login { .label-last-login {
line-height: 2.2; line-height: 2.2;
color: #4a4a4a!important; color: #4a4a4a!important;
padding: .2em .4em .3em !important; padding: .2em .4em .3em !important;
background-color: #ececec!important; background-color: #ececec!important;
} }

View File

@ -1,134 +1,134 @@
.pagination a { .pagination a {
text-decoration: none !important; text-decoration: none !important;
} }
.panel.panel-default { .panel.panel-default {
overflow: visible !important; overflow: visible !important;
} }
.table-responsive { .table-responsive {
overflow: visible !important; overflow: visible !important;
} }
@media screen and (max-width: 767px) { @media screen and (max-width: 767px) {
.table-responsive { .table-responsive {
overflow-x: scroll !important; overflow-x: scroll !important;
} }
} }
.footer-add-item { .footer-add-item {
display:block; display:block;
text-align: center; text-align: center;
font-style: italic; font-style: italic;
padding: 10px; padding: 10px;
background: #F5F5F5; background: #F5F5F5;
} }
.mass-actions-user { .mass-actions-user {
user-select: none; user-select: none;
} }
.inputMissingAttr { .inputMissingAttr {
border-color: #FF4136; border-color: #FF4136;
} }
#logText { #logText {
white-space: pre-wrap; white-space: pre-wrap;
white-space: -moz-pre-wrap; white-space: -moz-pre-wrap;
white-space: -o-pre-wrap; white-space: -o-pre-wrap;
word-wrap: break-word; word-wrap: break-word;
} }
body { body {
overflow-y:scroll; overflow-y:scroll;
} }
table tbody tr { table tbody tr {
cursor: pointer; cursor: pointer;
} }
table tbody tr td input[type="checkbox"] { table tbody tr td input[type="checkbox"] {
cursor: pointer; cursor: pointer;
} }
.label-keys { .label-keys {
font-size:100%; font-size:100%;
margin: 0px !important; margin: 0px !important;
white-space: normal !important; white-space: normal !important;
} }
.key-action { .key-action {
font-weight:bold; font-weight:bold;
color:white !important; color:white !important;
} }
svg { svg {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
} }
.c-1-color, .label-ham { .c-1-color, .label-ham {
background: #28b62c; background: #28b62c;
background: -webkit-linear-gradient(to right, #28b62c, #fff233); background: -webkit-linear-gradient(to right, #28b62c, #fff233);
background: linear-gradient(to right, #28b62c, #fff233); background: linear-gradient(to right, #28b62c, #fff233);
color: #000; color: #000;
} }
.c-2-color, .label-spam { .c-2-color, .label-spam {
background: #fff233; background: #fff233;
background: -webkit-linear-gradient(to right, #fff233, #ff4136); background: -webkit-linear-gradient(to right, #fff233, #ff4136);
background: linear-gradient(to right, #fff233, #ff4136); background: linear-gradient(to right, #fff233, #ff4136);
color: #000; color: #000;
} }
.c-3-color, .label-reject{ .c-3-color, .label-reject{
background: #ff4136; background: #ff4136;
color: #fff; color: #fff;
} }
#spam_score { #spam_score {
margin-bottom: 10px; margin-bottom: 10px;
} }
.noUi-handle { .noUi-handle {
border: 1px solid #e2e2e2; border: 1px solid #e2e2e2;
border-radius: 0px; border-radius: 0px;
background: #eee; background: #eee;
cursor: default; cursor: default;
box-shadow: none; box-shadow: none;
border-top-width: 0px; border-top-width: 0px;
border-right-width: 1px; border-right-width: 1px;
border-bottom-width: 4px; border-bottom-width: 4px;
border-left-width: 1px; border-left-width: 1px;
} }
.noUi-handle:hover { .noUi-handle:hover {
background-color: #eee; background-color: #eee;
border-color: #e2e2e2; border-color: #e2e2e2;
margin-top: 1px; margin-top: 1px;
border-bottom-width: 3px; border-bottom-width: 3px;
} }
.noUi-handle::after, .noUi-handle::before { .noUi-handle::after, .noUi-handle::before {
background: #c6c6c6; background: #c6c6c6;
width: 2px; width: 2px;
} }
.noUi-target { .noUi-target {
background: transparent; background: transparent;
border-radius: 0px; border-radius: 0px;
border: 1px solid #D3D3D3; border: 1px solid #D3D3D3;
box-shadow: none; box-shadow: none;
} }
.noUi-connects { .noUi-connects {
border-radius: 0px; border-radius: 0px;
} }
.label-ham, .label-ham,
.label-spam, .label-spam,
.label-reject { .label-reject {
padding: .1em .5em .1em; padding: .1em .5em .1em;
font-size: inherit; font-size: inherit;
font-weight: 400; font-weight: 400;
} }
.clear-last-logins { .clear-last-logins {
cursor: pointer; cursor: pointer;
font-size:90%; font-size:90%;
font-style: italic; font-style: italic;
color: #158cba; color: #158cba;
user-select:none; user-select:none;
} }
.ip-location-flag { .ip-location-flag {
border-radius: 4px; border-radius: 4px;
top: 3px; top: 3px;
} }
.recent-login-success { .recent-login-success {
margin-top:2px; margin-top:2px;
margin-right:10px; margin-right:10px;
} }
.label-protocol-access { .label-protocol-access {
line-height: 2; line-height: 2;
} }
.help-block-mt-0 { .help-block-mt-0 {
margin-top: 0px; margin-top: 0px;
} }

View File

@ -1,52 +1,52 @@
<?php <?php
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
if (!isset($_SESSION['mailcow_cc_role']) || $_SESSION['mailcow_cc_role'] != 'admin') { if (!isset($_SESSION['mailcow_cc_role']) || $_SESSION['mailcow_cc_role'] != 'admin') {
exit(); exit();
} }
if (preg_match('/^[a-z\-]{0,}-mailcow/', $_GET['service'])) { if (preg_match('/^[a-z\-]{0,}-mailcow/', $_GET['service'])) {
if ($_GET['action'] == "start") { if ($_GET['action'] == "start") {
header('Content-Type: text/html; charset=utf-8'); header('Content-Type: text/html; charset=utf-8');
$retry = 0; $retry = 0;
while (docker('info', $_GET['service'])['State']['Running'] != 1 && $retry <= 3) { while (docker('info', $_GET['service'])['State']['Running'] != 1 && $retry <= 3) {
$response = docker('post', $_GET['service'], 'start'); $response = docker('post', $_GET['service'], 'start');
$response = json_decode($response, true); $response = json_decode($response, true);
$last_response = ($response['type'] == "success") ? '<b><span class="pull-right text-success">OK</span></b>' : '<b><span class="pull-right text-danger">Error: ' . $response['msg'] . '</span></b>'; $last_response = ($response['type'] == "success") ? '<b><span class="pull-right text-success">OK</span></b>' : '<b><span class="pull-right text-danger">Error: ' . $response['msg'] . '</span></b>';
if ($response['type'] == "success") { if ($response['type'] == "success") {
break; break;
} }
usleep(1500000); usleep(1500000);
$retry++; $retry++;
} }
echo (!isset($last_response)) ? '<b><span class="pull-right text-warning">Already running</span></b>' : $last_response; echo (!isset($last_response)) ? '<b><span class="pull-right text-warning">Already running</span></b>' : $last_response;
} }
if ($_GET['action'] == "stop") { if ($_GET['action'] == "stop") {
header('Content-Type: text/html; charset=utf-8'); header('Content-Type: text/html; charset=utf-8');
$retry = 0; $retry = 0;
while (docker('info', $_GET['service'])['State']['Running'] == 1 && $retry <= 3) { while (docker('info', $_GET['service'])['State']['Running'] == 1 && $retry <= 3) {
$response = docker('post', $_GET['service'], 'stop'); $response = docker('post', $_GET['service'], 'stop');
$response = json_decode($response, true); $response = json_decode($response, true);
$last_response = ($response['type'] == "success") ? '<b><span class="pull-right text-success">OK</span></b>' : '<b><span class="pull-right text-danger">Error: ' . $response['msg'] . '</span></b>'; $last_response = ($response['type'] == "success") ? '<b><span class="pull-right text-success">OK</span></b>' : '<b><span class="pull-right text-danger">Error: ' . $response['msg'] . '</span></b>';
if ($response['type'] == "success") { if ($response['type'] == "success") {
break; break;
} }
usleep(1500000); usleep(1500000);
$retry++; $retry++;
} }
echo (!isset($last_response)) ? '<b><span class="pull-right text-warning">Not running</span></b>' : $last_response; echo (!isset($last_response)) ? '<b><span class="pull-right text-warning">Not running</span></b>' : $last_response;
} }
if ($_GET['action'] == "restart") { if ($_GET['action'] == "restart") {
header('Content-Type: text/html; charset=utf-8'); header('Content-Type: text/html; charset=utf-8');
$response = docker('post', $_GET['service'], 'restart'); $response = docker('post', $_GET['service'], 'restart');
$response = json_decode($response, true); $response = json_decode($response, true);
$last_response = ($response['type'] == "success") ? '<b><span class="pull-right text-success">OK</span></b>' : '<b><span class="pull-right text-danger">Error: ' . $response['msg'] . '</span></b>'; $last_response = ($response['type'] == "success") ? '<b><span class="pull-right text-success">OK</span></b>' : '<b><span class="pull-right text-danger">Error: ' . $response['msg'] . '</span></b>';
echo (!isset($last_response)) ? '<b><span class="pull-right text-warning">Cannot restart container</span></b>' : $last_response; echo (!isset($last_response)) ? '<b><span class="pull-right text-warning">Cannot restart container</span></b>' : $last_response;
} }
if ($_GET['action'] == "logs") { if ($_GET['action'] == "logs") {
$lines = (empty($_GET['lines']) || !is_numeric($_GET['lines'])) ? 1000 : $_GET['lines']; $lines = (empty($_GET['lines']) || !is_numeric($_GET['lines'])) ? 1000 : $_GET['lines'];
header('Content-Type: text/plain; charset=utf-8'); header('Content-Type: text/plain; charset=utf-8');
print_r(preg_split('/\n/', docker('logs', $_GET['service'], $lines))); print_r(preg_split('/\n/', docker('logs', $_GET['service'], $lines)));
} }
} }
?> ?>

View File

@ -1,6 +1,6 @@
<?php <?php
session_start(); session_start();
unset($_SESSION['pending_mailcow_cc_username']); unset($_SESSION['pending_mailcow_cc_username']);
unset($_SESSION['pending_mailcow_cc_role']); unset($_SESSION['pending_mailcow_cc_role']);
unset($_SESSION['pending_tfa_methods']); unset($_SESSION['pending_tfa_methods']);
?> ?>

View File

@ -1,207 +1,207 @@
<?php <?php
header("Content-Type: application/json"); header("Content-Type: application/json");
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
function rrmdir($src) { function rrmdir($src) {
$dir = opendir($src); $dir = opendir($src);
while(false !== ( $file = readdir($dir)) ) { while(false !== ( $file = readdir($dir)) ) {
if (( $file != '.' ) && ( $file != '..' )) { if (( $file != '.' ) && ( $file != '..' )) {
$full = $src . '/' . $file; $full = $src . '/' . $file;
if ( is_dir($full) ) { if ( is_dir($full) ) {
rrmdir($full); rrmdir($full);
} }
else { else {
unlink($full); unlink($full);
} }
} }
} }
closedir($dir); closedir($dir);
rmdir($src); rmdir($src);
} }
function addAddresses(&$list, $mail, $headerName) { function addAddresses(&$list, $mail, $headerName) {
$addresses = $mail->getAddresses($headerName); $addresses = $mail->getAddresses($headerName);
foreach ($addresses as $address) { foreach ($addresses as $address) {
if (filter_var($address['address'], FILTER_VALIDATE_EMAIL)) { if (filter_var($address['address'], FILTER_VALIDATE_EMAIL)) {
$list[] = array('address' => $address['address'], 'type' => $headerName); $list[] = array('address' => $address['address'], 'type' => $headerName);
} }
} }
} }
if (!empty($_GET['hash']) && ctype_alnum($_GET['hash'])) { if (!empty($_GET['hash']) && ctype_alnum($_GET['hash'])) {
$mailc = quarantine('hash_details', $_GET['hash']); $mailc = quarantine('hash_details', $_GET['hash']);
if ($mailc === false) { if ($mailc === false) {
echo json_encode(array('error' => 'Message invalid')); echo json_encode(array('error' => 'Message invalid'));
exit; exit;
} }
if (strlen($mailc['msg']) > 10485760) { if (strlen($mailc['msg']) > 10485760) {
echo json_encode(array('error' => 'Message size exceeds 10 MiB.')); echo json_encode(array('error' => 'Message size exceeds 10 MiB.'));
exit; exit;
} }
if (!empty($mailc['msg'])) { if (!empty($mailc['msg'])) {
// Init message array // Init message array
$data = array(); $data = array();
// Init parser // Init parser
$mail_parser = new PhpMimeMailParser\Parser(); $mail_parser = new PhpMimeMailParser\Parser();
$html2text = new Html2Text\Html2Text(); $html2text = new Html2Text\Html2Text();
// Load msg to parser // Load msg to parser
$mail_parser->setText($mailc['msg']); $mail_parser->setText($mailc['msg']);
// Get mail recipients // Get mail recipients
{ {
$recipientsList = array(); $recipientsList = array();
addAddresses($recipientsList, $mail_parser, 'to'); addAddresses($recipientsList, $mail_parser, 'to');
addAddresses($recipientsList, $mail_parser, 'cc'); addAddresses($recipientsList, $mail_parser, 'cc');
addAddresses($recipientsList, $mail_parser, 'bcc'); addAddresses($recipientsList, $mail_parser, 'bcc');
$recipientsList[] = array('address' => $mailc['rcpt'], 'type' => 'smtp'); $recipientsList[] = array('address' => $mailc['rcpt'], 'type' => 'smtp');
$data['recipients'] = $recipientsList; $data['recipients'] = $recipientsList;
} }
// Get from // Get from
$data['header_from'] = $mail_parser->getHeader('from'); $data['header_from'] = $mail_parser->getHeader('from');
$data['env_from'] = $mailc['sender']; $data['env_from'] = $mailc['sender'];
// Get rspamd score // Get rspamd score
$data['score'] = $mailc['score']; $data['score'] = $mailc['score'];
// Get rspamd action // Get rspamd action
$data['action'] = $mailc['action']; $data['action'] = $mailc['action'];
// Get rspamd symbols // Get rspamd symbols
$data['symbols'] = json_decode($mailc['symbols']); $data['symbols'] = json_decode($mailc['symbols']);
// Get fuzzy hashes // Get fuzzy hashes
$data['fuzzy_hashes'] = json_decode($mailc['fuzzy_hashes']); $data['fuzzy_hashes'] = json_decode($mailc['fuzzy_hashes']);
$data['subject'] = mb_convert_encoding($mail_parser->getHeader('subject'), "UTF-8", "auto"); $data['subject'] = mb_convert_encoding($mail_parser->getHeader('subject'), "UTF-8", "auto");
(empty($data['subject'])) ? $data['subject'] = '-' : null; (empty($data['subject'])) ? $data['subject'] = '-' : null;
echo json_encode($data); echo json_encode($data);
} }
} }
elseif (!empty($_GET['id']) && ctype_alnum($_GET['id'])) { elseif (!empty($_GET['id']) && ctype_alnum($_GET['id'])) {
if (!isset($_SESSION['mailcow_cc_role'])) { if (!isset($_SESSION['mailcow_cc_role'])) {
echo json_encode(array('error' => 'Access denied')); echo json_encode(array('error' => 'Access denied'));
exit(); exit();
} }
$tmpdir = '/tmp/' . $_GET['id'] . '/'; $tmpdir = '/tmp/' . $_GET['id'] . '/';
$mailc = quarantine('details', $_GET['id']); $mailc = quarantine('details', $_GET['id']);
if ($mailc === false) { if ($mailc === false) {
echo json_encode(array('error' => 'Access denied')); echo json_encode(array('error' => 'Access denied'));
exit; exit;
} }
if (strlen($mailc['msg']) > 10485760) { if (strlen($mailc['msg']) > 10485760) {
echo json_encode(array('error' => 'Message size exceeds 10 MiB.')); echo json_encode(array('error' => 'Message size exceeds 10 MiB.'));
exit; exit;
} }
if (!empty($mailc['msg'])) { if (!empty($mailc['msg'])) {
if (isset($_GET['quick_release'])) { if (isset($_GET['quick_release'])) {
$hash = hash('sha256', $mailc['id'] . $mailc['qid']); $hash = hash('sha256', $mailc['id'] . $mailc['qid']);
header('Location: /qhandler/release/' . $hash); header('Location: /qhandler/release/' . $hash);
exit; exit;
} }
if (isset($_GET['quick_delete'])) { if (isset($_GET['quick_delete'])) {
$hash = hash('sha256', $mailc['id'] . $mailc['qid']); $hash = hash('sha256', $mailc['id'] . $mailc['qid']);
header('Location: /qhandler/delete/' . $hash); header('Location: /qhandler/delete/' . $hash);
exit; exit;
} }
// Init message array // Init message array
$data = array(); $data = array();
// Init parser // Init parser
$mail_parser = new PhpMimeMailParser\Parser(); $mail_parser = new PhpMimeMailParser\Parser();
$html2text = new Html2Text\Html2Text(); $html2text = new Html2Text\Html2Text();
// Load msg to parser // Load msg to parser
$mail_parser->setText($mailc['msg']); $mail_parser->setText($mailc['msg']);
// Get mail recipients // Get mail recipients
{ {
$recipientsList = array(); $recipientsList = array();
addAddresses($recipientsList, $mail_parser, 'to'); addAddresses($recipientsList, $mail_parser, 'to');
addAddresses($recipientsList, $mail_parser, 'cc'); addAddresses($recipientsList, $mail_parser, 'cc');
addAddresses($recipientsList, $mail_parser, 'bcc'); addAddresses($recipientsList, $mail_parser, 'bcc');
$recipientsList[] = array('address' => $mailc['rcpt'], 'type' => 'smtp'); $recipientsList[] = array('address' => $mailc['rcpt'], 'type' => 'smtp');
$data['recipients'] = $recipientsList; $data['recipients'] = $recipientsList;
} }
// Get from // Get from
$data['header_from'] = $mail_parser->getHeader('from'); $data['header_from'] = $mail_parser->getHeader('from');
$data['env_from'] = $mailc['sender']; $data['env_from'] = $mailc['sender'];
// Get rspamd score // Get rspamd score
$data['score'] = $mailc['score']; $data['score'] = $mailc['score'];
// Get rspamd action // Get rspamd action
$data['action'] = $mailc['action']; $data['action'] = $mailc['action'];
// Get rspamd symbols // Get rspamd symbols
$data['symbols'] = json_decode($mailc['symbols']); $data['symbols'] = json_decode($mailc['symbols']);
// Get fuzzy hashes // Get fuzzy hashes
$data['fuzzy_hashes'] = json_decode($mailc['fuzzy_hashes']); $data['fuzzy_hashes'] = json_decode($mailc['fuzzy_hashes']);
// Get text/plain content // Get text/plain content
$data['text_plain'] = $mail_parser->getMessageBody('text'); $data['text_plain'] = $mail_parser->getMessageBody('text');
if (!json_encode($data['text_plain'])) $data['text_plain'] = ''; if (!json_encode($data['text_plain'])) $data['text_plain'] = '';
// Get html content and convert to text // Get html content and convert to text
$data['text_html'] = $html2text->convert($mail_parser->getMessageBody('html')); $data['text_html'] = $html2text->convert($mail_parser->getMessageBody('html'));
if (empty($data['text_plain']) && empty($data['text_html'])) { if (empty($data['text_plain']) && empty($data['text_html'])) {
// Failed to parse content, try raw // Failed to parse content, try raw
$text = trim(substr($mailc['msg'], strpos($mailc['msg'], "\r\n\r\n") + 1)); $text = trim(substr($mailc['msg'], strpos($mailc['msg'], "\r\n\r\n") + 1));
// Only return html->text // Only return html->text
$data['text_plain'] = 'Parser failed, assuming HTML'; $data['text_plain'] = 'Parser failed, assuming HTML';
$data['text_html'] = $html2text->convert($text); $data['text_html'] = $html2text->convert($text);
} }
(empty($data['text_plain'])) ? $data['text_plain'] = '-' : null; (empty($data['text_plain'])) ? $data['text_plain'] = '-' : null;
// Get subject // Get subject
$data['subject'] = $mail_parser->getHeader('subject'); $data['subject'] = $mail_parser->getHeader('subject');
$data['subject'] = mb_convert_encoding($mail_parser->getHeader('subject'), "UTF-8", "auto"); $data['subject'] = mb_convert_encoding($mail_parser->getHeader('subject'), "UTF-8", "auto");
(empty($data['subject'])) ? $data['subject'] = '-' : null; (empty($data['subject'])) ? $data['subject'] = '-' : null;
// Get attachments // Get attachments
if (is_dir($tmpdir)) { if (is_dir($tmpdir)) {
rrmdir($tmpdir); rrmdir($tmpdir);
} }
mkdir('/tmp/' . $_GET['id']); mkdir('/tmp/' . $_GET['id']);
$mail_parser->saveAttachments($tmpdir, true); $mail_parser->saveAttachments($tmpdir, true);
$atts = $mail_parser->getAttachments(true); $atts = $mail_parser->getAttachments(true);
if (count($atts) > 0) { if (count($atts) > 0) {
foreach ($atts as $key => $val) { foreach ($atts as $key => $val) {
$data['attachments'][$key] = array( $data['attachments'][$key] = array(
// Index // Index
// 0 => file name // 0 => file name
// 1 => mime type // 1 => mime type
// 2 => file size // 2 => file size
// 3 => vt link by sha256 // 3 => vt link by sha256
$val->getFilename(), $val->getFilename(),
$val->getContentType(), $val->getContentType(),
filesize($tmpdir . $val->getFilename()), filesize($tmpdir . $val->getFilename()),
'https://www.virustotal.com/file/' . hash_file('SHA256', $tmpdir . $val->getFilename()) . '/analysis/' 'https://www.virustotal.com/file/' . hash_file('SHA256', $tmpdir . $val->getFilename()) . '/analysis/'
); );
} }
} }
if (isset($_GET['eml'])) { if (isset($_GET['eml'])) {
$dl_filename = filter_var($data['subject'], FILTER_SANITIZE_STRING); $dl_filename = filter_var($data['subject'], FILTER_SANITIZE_STRING);
$dl_filename = strlen($dl_filename) > 30 ? substr($dl_filename,0,30) : $dl_filename; $dl_filename = strlen($dl_filename) > 30 ? substr($dl_filename,0,30) : $dl_filename;
header('Pragma: public'); header('Pragma: public');
header('Expires: 0'); header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Cache-Control: private', false); header('Cache-Control: private', false);
header('Content-Type: message/rfc822'); header('Content-Type: message/rfc822');
header('Content-Disposition: attachment; filename="'. $dl_filename . '.eml";'); header('Content-Disposition: attachment; filename="'. $dl_filename . '.eml";');
header('Content-Transfer-Encoding: binary'); header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . strlen($mailc['msg'])); header('Content-Length: ' . strlen($mailc['msg']));
echo $mailc['msg']; echo $mailc['msg'];
exit; exit;
} }
if (isset($_GET['att'])) { if (isset($_GET['att'])) {
if ($_SESSION['acl']['quarantine_attachments'] == 0) { if ($_SESSION['acl']['quarantine_attachments'] == 0) {
exit(json_encode('Forbidden')); exit(json_encode('Forbidden'));
} }
$dl_id = intval($_GET['att']); $dl_id = intval($_GET['att']);
$dl_filename = filter_var($data['attachments'][$dl_id][0], FILTER_SANITIZE_STRING); $dl_filename = filter_var($data['attachments'][$dl_id][0], FILTER_SANITIZE_STRING);
$dl_filename_short = strlen($dl_filename) > 20 ? substr($dl_filename, 0, 20) : $dl_filename; $dl_filename_short = strlen($dl_filename) > 20 ? substr($dl_filename, 0, 20) : $dl_filename;
$dl_filename_extension = pathinfo($tmpdir . $dl_filename)['extension']; $dl_filename_extension = pathinfo($tmpdir . $dl_filename)['extension'];
$dl_filename_short = preg_replace('/\.' . $dl_filename_extension . '$/', '', $dl_filename_short); $dl_filename_short = preg_replace('/\.' . $dl_filename_extension . '$/', '', $dl_filename_short);
if (!is_dir($tmpdir . $dl_filename) && file_exists($tmpdir . $dl_filename)) { if (!is_dir($tmpdir . $dl_filename) && file_exists($tmpdir . $dl_filename)) {
header('Pragma: public'); header('Pragma: public');
header('Expires: 0'); header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Cache-Control: private', false); header('Cache-Control: private', false);
header('Content-Type: ' . $data['attachments'][$dl_id][1]); header('Content-Type: ' . $data['attachments'][$dl_id][1]);
header('Content-Disposition: attachment; filename="'. $dl_filename_short . '.' . $dl_filename_extension . '";'); header('Content-Disposition: attachment; filename="'. $dl_filename_short . '.' . $dl_filename_extension . '";');
header('Content-Transfer-Encoding: binary'); header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . $data['attachments'][$dl_id][2]); header('Content-Length: ' . $data['attachments'][$dl_id][2]);
readfile($tmpdir . $dl_filename); readfile($tmpdir . $dl_filename);
exit; exit;
} }
} }
echo json_encode($data); echo json_encode($data);
} }
} }
?> ?>

View File

@ -1,10 +1,10 @@
<?php <?php
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
header('Content-Type: text/plain'); header('Content-Type: text/plain');
if (!isset($_SESSION['mailcow_cc_role'])) { if (!isset($_SESSION['mailcow_cc_role'])) {
exit(); exit();
} }
if (isset($_GET['token']) && ctype_alnum($_GET['token'])) { if (isset($_GET['token']) && ctype_alnum($_GET['token'])) {
echo $tfa->getQRCodeImageAsDataUri($_SESSION['mailcow_cc_username'], $_GET['token']); echo $tfa->getQRCodeImageAsDataUri($_SESSION['mailcow_cc_username'], $_GET['token']);
} }
?> ?>

View File

@ -1,3 +1,3 @@
<?php <?php
session_start(); session_start();
$_SESSION['show_rspamd_global_filters'] = true; $_SESSION['show_rspamd_global_filters'] = true;

View File

@ -1,22 +1,22 @@
<?php <?php
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
header('Content-Type: application/json'); header('Content-Type: application/json');
if (!isset($_SESSION['mailcow_cc_role'])) { if (!isset($_SESSION['mailcow_cc_role'])) {
exit(); exit();
} }
if (isset($_GET['script'])) { if (isset($_GET['script'])) {
$sieve = new Sieve\SieveParser(); $sieve = new Sieve\SieveParser();
try { try {
if (empty($_GET['script'])) { if (empty($_GET['script'])) {
echo json_encode(array('type' => 'danger', 'msg' => $lang['danger']['script_empty'])); echo json_encode(array('type' => 'danger', 'msg' => $lang['danger']['script_empty']));
exit(); exit();
} }
$sieve->parse($_GET['script']); $sieve->parse($_GET['script']);
} }
catch (Exception $e) { catch (Exception $e) {
echo json_encode(array('type' => 'danger', 'msg' => $e->getMessage())); echo json_encode(array('type' => 'danger', 'msg' => $e->getMessage()));
exit(); exit();
} }
echo json_encode(array('type' => 'success', 'msg' => $lang['add']['validation_success'])); echo json_encode(array('type' => 'success', 'msg' => $lang['add']['validation_success']));
} }
?> ?>

View File

@ -1,14 +1,14 @@
<?php <?php
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
header('Content-Type: text/plain'); header('Content-Type: text/plain');
if (!isset($_SESSION['mailcow_cc_role'])) { if (!isset($_SESSION['mailcow_cc_role'])) {
exit(); exit();
} }
if (isset($_GET['id']) && is_numeric($_GET['id'])) { if (isset($_GET['id']) && is_numeric($_GET['id'])) {
if ($details = mailbox('get', 'syncjob_details', intval($_GET['id']))) { if ($details = mailbox('get', 'syncjob_details', intval($_GET['id']))) {
echo (empty($details['log'])) ? '-' : $details['log']; echo (empty($details['log'])) ? '-' : $details['log'];
} }
} }
?> ?>

View File

@ -1,149 +1,149 @@
<?php <?php
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/vars.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/vars.inc.php';
use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP; use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception; use PHPMailer\PHPMailer\Exception;
error_reporting(0); error_reporting(0);
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admin") { if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admin") {
$transport_id = intval($_GET['transport_id']); $transport_id = intval($_GET['transport_id']);
$transport_type = $_GET['transport_type']; $transport_type = $_GET['transport_type'];
if (isset($_GET['mail_from']) && filter_var($_GET['mail_from'], FILTER_VALIDATE_EMAIL)) { if (isset($_GET['mail_from']) && filter_var($_GET['mail_from'], FILTER_VALIDATE_EMAIL)) {
$mail_from = $_GET['mail_from']; $mail_from = $_GET['mail_from'];
} }
else { else {
$mail_from = "relay@example.org"; $mail_from = "relay@example.org";
} }
if (isset($_GET['mail_rcpt']) && filter_var($_GET['mail_rcpt'], FILTER_VALIDATE_EMAIL)) { if (isset($_GET['mail_rcpt']) && filter_var($_GET['mail_rcpt'], FILTER_VALIDATE_EMAIL)) {
$mail_rcpt = $_GET['mail_rcpt']; $mail_rcpt = $_GET['mail_rcpt'];
} }
else { else {
$mail_rcpt = "null@hosted.mailcow.de"; $mail_rcpt = "null@hosted.mailcow.de";
} }
if ($transport_type == 'transport-map') { if ($transport_type == 'transport-map') {
$transport_details = transport('details', $transport_id); $transport_details = transport('details', $transport_id);
$nexthop = $transport_details['nexthop']; $nexthop = $transport_details['nexthop'];
} }
elseif ($transport_type == 'sender-dependent') { elseif ($transport_type == 'sender-dependent') {
$transport_details = relayhost('details', $transport_id); $transport_details = relayhost('details', $transport_id);
$nexthop = $transport_details['hostname']; $nexthop = $transport_details['hostname'];
} }
if (!empty($transport_details)) { if (!empty($transport_details)) {
// Remove [ and ] // Remove [ and ]
$hostname_w_port = preg_replace('/\[|\]/', '', $nexthop); $hostname_w_port = preg_replace('/\[|\]/', '', $nexthop);
preg_match('/\[.+\](:.+)/', $nexthop, $hostname_port_match); preg_match('/\[.+\](:.+)/', $nexthop, $hostname_port_match);
preg_match('/\[\d\.\d\.\d\.\d\](:.+)/', $nexthop, $ipv4_port_match); preg_match('/\[\d\.\d\.\d\.\d\](:.+)/', $nexthop, $ipv4_port_match);
$has_bracket_and_port = (isset($hostname_port_match[1])) ? true : false; $has_bracket_and_port = (isset($hostname_port_match[1])) ? true : false;
$is_ipv4_and_has_port = (isset($ipv4_port_match[1])) ? true : false; $is_ipv4_and_has_port = (isset($ipv4_port_match[1])) ? true : false;
$skip_lookup_mx = strpos($nexthop, '['); $skip_lookup_mx = strpos($nexthop, '[');
// Explode to hostname and port // Explode to hostname and port
if ($has_bracket_and_port) { if ($has_bracket_and_port) {
$port = substr($hostname_w_port, strrpos($hostname_w_port, ':') + 1); $port = substr($hostname_w_port, strrpos($hostname_w_port, ':') + 1);
$hostname = preg_replace('/'. preg_quote(':' . $port, '/') . '$/', '', $hostname_w_port); $hostname = preg_replace('/'. preg_quote(':' . $port, '/') . '$/', '', $hostname_w_port);
if (filter_var($hostname, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { if (filter_var($hostname, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$hostname = '[' . $hostname . ']'; $hostname = '[' . $hostname . ']';
} }
} }
else { else {
if ($is_ipv4_and_has_port) { if ($is_ipv4_and_has_port) {
$port = substr($hostname_w_port, strrpos($hostname_w_port, ':') + 1); $port = substr($hostname_w_port, strrpos($hostname_w_port, ':') + 1);
$hostname = preg_replace('/'. preg_quote(':' . $port, '/') . '$/', '', $hostname_w_port); $hostname = preg_replace('/'. preg_quote(':' . $port, '/') . '$/', '', $hostname_w_port);
} }
if (filter_var($hostname_w_port, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { if (filter_var($hostname_w_port, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
$hostname = $hostname_w_port; $hostname = $hostname_w_port;
$port = null; $port = null;
} }
elseif (filter_var($hostname_w_port, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { elseif (filter_var($hostname_w_port, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$hostname = '[' . $hostname_w_port . ']'; $hostname = '[' . $hostname_w_port . ']';
$port = null; $port = null;
} }
else { else {
$hostname = preg_replace('/'. preg_quote(':' . $port, '/') . '$/', '', $hostname_w_port); $hostname = preg_replace('/'. preg_quote(':' . $port, '/') . '$/', '', $hostname_w_port);
$port = null; $port = null;
} }
} }
// Try to get MX if host is not [host] // Try to get MX if host is not [host]
if ($skip_lookup_mx === false) { if ($skip_lookup_mx === false) {
getmxrr($hostname, $mx_records, $mx_weight); getmxrr($hostname, $mx_records, $mx_weight);
if (!empty($mx_records)) { if (!empty($mx_records)) {
for ($i = 0; $i < count($mx_records); $i++) { for ($i = 0; $i < count($mx_records); $i++) {
$mxs[$mx_records[$i]] = $mx_weight[$i]; $mxs[$mx_records[$i]] = $mx_weight[$i];
} }
asort ($mxs); asort ($mxs);
$records = array_keys($mxs); $records = array_keys($mxs);
echo 'Using first matched primary MX for "' . $hostname . '": '; echo 'Using first matched primary MX for "' . $hostname . '": ';
$hostname = $records[0]; $hostname = $records[0];
echo $hostname . '<br>'; echo $hostname . '<br>';
} }
else { else {
echo 'No MX records for ' . $hostname . ' were found in DNS, skipping and using hostname as next-hop.<br>'; echo 'No MX records for ' . $hostname . ' were found in DNS, skipping and using hostname as next-hop.<br>';
} }
} }
// Use port 25 if no port was given // Use port 25 if no port was given
$port = (empty($port)) ? 25 : $port; $port = (empty($port)) ? 25 : $port;
$username = $transport_details['username']; $username = $transport_details['username'];
$password = $transport_details['password']; $password = $transport_details['password'];
$mail = new PHPMailer; $mail = new PHPMailer;
$mail->Timeout = 15; $mail->Timeout = 15;
$mail->SMTPOptions = array( $mail->SMTPOptions = array(
'ssl' => array( 'ssl' => array(
'verify_peer' => false, 'verify_peer' => false,
'verify_peer_name' => false, 'verify_peer_name' => false,
'allow_self_signed' => true 'allow_self_signed' => true
) )
); );
$mail->SMTPDebug = 3; $mail->SMTPDebug = 3;
// smtp: and smtp_enforced_tls: do not support wrapped tls, todo? // smtp: and smtp_enforced_tls: do not support wrapped tls, todo?
// change postfix map to detect wrapped tls or add a checkbox to toggle wrapped tls // change postfix map to detect wrapped tls or add a checkbox to toggle wrapped tls
// if ($port == 465) { // if ($port == 465) {
// $mail->SMTPSecure = "ssl"; // $mail->SMTPSecure = "ssl";
// } // }
$mail->Debugoutput = function($str, $level) { $mail->Debugoutput = function($str, $level) {
foreach(preg_split("/((\r?\n)|(\r\n?)|\n)/", $str) as $line){ foreach(preg_split("/((\r?\n)|(\r\n?)|\n)/", $str) as $line){
if (empty($line)) { continue; } if (empty($line)) { continue; }
if (preg_match("/SERVER \-\> CLIENT: 2\d\d.+/i", $line)) { if (preg_match("/SERVER \-\> CLIENT: 2\d\d.+/i", $line)) {
echo '<span style="color:darkgreen;font-weight:bold">' . htmlspecialchars($line) . '</span><br>'; echo '<span style="color:darkgreen;font-weight:bold">' . htmlspecialchars($line) . '</span><br>';
} }
elseif (preg_match("/SERVER \-\> CLIENT: 3\d\d.+/i", $line)) { elseif (preg_match("/SERVER \-\> CLIENT: 3\d\d.+/i", $line)) {
echo '<span style="color:lightgreen;font-weight:bold">' . htmlspecialchars($line) . '</span><br>'; echo '<span style="color:lightgreen;font-weight:bold">' . htmlspecialchars($line) . '</span><br>';
} }
elseif (preg_match("/SERVER \-\> CLIENT: 4\d\d.+/i", $line)) { elseif (preg_match("/SERVER \-\> CLIENT: 4\d\d.+/i", $line)) {
echo '<span style="color:yellow;font-weight:bold">' . htmlspecialchars($line) . '</span><br>'; echo '<span style="color:yellow;font-weight:bold">' . htmlspecialchars($line) . '</span><br>';
} }
elseif (preg_match("/SERVER \-\> CLIENT: 5\d\d.+/i", $line)) { elseif (preg_match("/SERVER \-\> CLIENT: 5\d\d.+/i", $line)) {
echo '<span style="color:red;font-weight:bold">' . htmlspecialchars($line) . '</span><br>'; echo '<span style="color:red;font-weight:bold">' . htmlspecialchars($line) . '</span><br>';
} }
elseif (preg_match("/CLIENT \-\> SERVER:.+/i", $line)) { elseif (preg_match("/CLIENT \-\> SERVER:.+/i", $line)) {
echo '<span style="color:#999;font-weight:bold">' . htmlspecialchars($line) . '</span><br>'; echo '<span style="color:#999;font-weight:bold">' . htmlspecialchars($line) . '</span><br>';
} }
elseif (preg_match("/^(?!SERVER|CLIENT|Connection:|\)).+$/i", $line)) { elseif (preg_match("/^(?!SERVER|CLIENT|Connection:|\)).+$/i", $line)) {
echo '<span>&nbsp;&nbsp;&nbsp;&nbsp;↪ ' . htmlspecialchars($line) . '</span><br>'; echo '<span>&nbsp;&nbsp;&nbsp;&nbsp;↪ ' . htmlspecialchars($line) . '</span><br>';
} }
else { else {
echo htmlspecialchars($line) . '<br>'; echo htmlspecialchars($line) . '<br>';
} }
} }
}; };
$mail->isSMTP(); $mail->isSMTP();
$mail->Host = $hostname; $mail->Host = $hostname;
if (!empty($username)) { if (!empty($username)) {
$mail->SMTPAuth = true; $mail->SMTPAuth = true;
$mail->Username = $username; $mail->Username = $username;
$mail->Password = $password; $mail->Password = $password;
} }
$mail->Port = $port; $mail->Port = $port;
$mail->setFrom($mail_from, 'Mailer'); $mail->setFrom($mail_from, 'Mailer');
$mail->Subject = 'A subject for a SMTP test'; $mail->Subject = 'A subject for a SMTP test';
$mail->addAddress($mail_rcpt, 'Joe Null'); $mail->addAddress($mail_rcpt, 'Joe Null');
$mail->Body = 'This is our test body'; $mail->Body = 'This is our test body';
$mail->send(); $mail->send();
} }
else { else {
echo "Unknown transport."; echo "Unknown transport.";
} }
} }
else { else {
echo "Permission denied."; echo "Permission denied.";
} }

View File

@ -1,226 +1,226 @@
<?php <?php
function acl($_action, $_scope = null, $_data = null) { function acl($_action, $_scope = null, $_data = null) {
global $pdo; global $pdo;
global $lang; global $lang;
$_data_log = $_data; $_data_log = $_data;
switch ($_action) { switch ($_action) {
case 'edit': case 'edit':
switch ($_scope) { switch ($_scope) {
case 'user': case 'user':
if (!is_array($_data['username'])) { if (!is_array($_data['username'])) {
$usernames = array(); $usernames = array();
$usernames[] = $_data['username']; $usernames[] = $_data['username'];
} }
else { else {
$usernames = $_data['username']; $usernames = $_data['username'];
} }
foreach ($usernames as $username) { foreach ($usernames as $username) {
// Cast to array for single selections // Cast to array for single selections
$acls = (array)$_data['user_acl']; $acls = (array)$_data['user_acl'];
// Create associative array from index array // Create associative array from index array
// All set items are given 1 as value // All set items are given 1 as value
foreach ($acls as $acl_key => $acl_val) { foreach ($acls as $acl_key => $acl_val) {
$acl_post[$acl_val] = 1; $acl_post[$acl_val] = 1;
} }
// Users cannot change their own ACL // Users cannot change their own ACL
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username) if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)
|| ($_SESSION['mailcow_cc_role'] != 'admin' && $_SESSION['mailcow_cc_role'] != 'domainadmin')) { || ($_SESSION['mailcow_cc_role'] != 'admin' && $_SESSION['mailcow_cc_role'] != 'domainadmin')) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
continue; continue;
} }
// Read all available acl options by calling acl(get) // Read all available acl options by calling acl(get)
// Set all available acl options we cannot find in the post data to 0, else 1 // Set all available acl options we cannot find in the post data to 0, else 1
$is_now = acl('get', 'user', $username); $is_now = acl('get', 'user', $username);
if (!empty($is_now)) { if (!empty($is_now)) {
foreach ($is_now as $acl_now_name => $acl_now_val) { foreach ($is_now as $acl_now_name => $acl_now_val) {
$set_acls[$acl_now_name] = (isset($acl_post[$acl_now_name])) ? 1 : 0; $set_acls[$acl_now_name] = (isset($acl_post[$acl_now_name])) ? 1 : 0;
} }
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'Cannot determine current ACL' 'msg' => 'Cannot determine current ACL'
); );
continue; continue;
} }
foreach ($set_acls as $set_acl_key => $set_acl_val) { foreach ($set_acls as $set_acl_key => $set_acl_val) {
$stmt = $pdo->prepare("UPDATE `user_acl` SET " . $set_acl_key . " = " . intval($set_acl_val) . " $stmt = $pdo->prepare("UPDATE `user_acl` SET " . $set_acl_key . " = " . intval($set_acl_val) . "
WHERE `username` = :username"); WHERE `username` = :username");
$stmt->execute(array( $stmt->execute(array(
':username' => $username, ':username' => $username,
)); ));
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => array('acl_saved', $username) 'msg' => array('acl_saved', $username)
); );
} }
break; break;
case 'domainadmin': case 'domainadmin':
if ($_SESSION['mailcow_cc_role'] != 'admin') { if ($_SESSION['mailcow_cc_role'] != 'admin') {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
if (!is_array($_data['username'])) { if (!is_array($_data['username'])) {
$usernames = array(); $usernames = array();
$usernames[] = $_data['username']; $usernames[] = $_data['username'];
} }
else { else {
$usernames = $_data['username']; $usernames = $_data['username'];
} }
foreach ($usernames as $username) { foreach ($usernames as $username) {
// Cast to array for single selections // Cast to array for single selections
$acls = (array)$_data['da_acl']; $acls = (array)$_data['da_acl'];
// Create associative array from index array // Create associative array from index array
// All set items are given 1 as value // All set items are given 1 as value
foreach ($acls as $acl_key => $acl_val) { foreach ($acls as $acl_key => $acl_val) {
$acl_post[$acl_val] = 1; $acl_post[$acl_val] = 1;
} }
// Users cannot change their own ACL // Users cannot change their own ACL
if ($_SESSION['mailcow_cc_role'] != 'admin') { if ($_SESSION['mailcow_cc_role'] != 'admin') {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
continue; continue;
} }
// Read all available acl options by calling acl(get) // Read all available acl options by calling acl(get)
// Set all available acl options we cannot find in the post data to 0, else 1 // Set all available acl options we cannot find in the post data to 0, else 1
$is_now = acl('get', 'domainadmin', $username); $is_now = acl('get', 'domainadmin', $username);
if (!empty($is_now)) { if (!empty($is_now)) {
foreach ($is_now as $acl_now_name => $acl_now_val) { foreach ($is_now as $acl_now_name => $acl_now_val) {
$set_acls[$acl_now_name] = (isset($acl_post[$acl_now_name])) ? 1 : 0; $set_acls[$acl_now_name] = (isset($acl_post[$acl_now_name])) ? 1 : 0;
} }
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'Cannot determine current ACL' 'msg' => 'Cannot determine current ACL'
); );
continue; continue;
} }
foreach ($set_acls as $set_acl_key => $set_acl_val) { foreach ($set_acls as $set_acl_key => $set_acl_val) {
$stmt = $pdo->prepare("UPDATE `da_acl` SET " . $set_acl_key . " = " . intval($set_acl_val) . " $stmt = $pdo->prepare("UPDATE `da_acl` SET " . $set_acl_key . " = " . intval($set_acl_val) . "
WHERE `username` = :username"); WHERE `username` = :username");
$stmt->execute(array( $stmt->execute(array(
':username' => $username, ':username' => $username,
)); ));
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => array('acl_saved', $username) 'msg' => array('acl_saved', $username)
); );
} }
break; break;
} }
break; break;
case 'get': case 'get':
switch ($_scope) { switch ($_scope) {
case 'user': case 'user':
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
return false; return false;
} }
$stmt = $pdo->prepare("SELECT * FROM `user_acl` WHERE `username` = :username"); $stmt = $pdo->prepare("SELECT * FROM `user_acl` WHERE `username` = :username");
$stmt->execute(array(':username' => $_data)); $stmt->execute(array(':username' => $_data));
$data = $stmt->fetch(PDO::FETCH_ASSOC); $data = $stmt->fetch(PDO::FETCH_ASSOC);
if ($_SESSION['mailcow_cc_role'] == 'domainadmin') { if ($_SESSION['mailcow_cc_role'] == 'domainadmin') {
// Domain admins cannot see, add or remove user ACLs they don't have access to by themselves // Domain admins cannot see, add or remove user ACLs they don't have access to by themselves
// Editing a user will use acl("get", "user") to determine granted ACLs and therefore block unallowed access escalation via form editing // Editing a user will use acl("get", "user") to determine granted ACLs and therefore block unallowed access escalation via form editing
$self_da_acl = acl('get', 'domainadmin', $_SESSION['mailcow_cc_username']); $self_da_acl = acl('get', 'domainadmin', $_SESSION['mailcow_cc_username']);
foreach ($self_da_acl as $self_da_acl_key => $self_da_acl_val) { foreach ($self_da_acl as $self_da_acl_key => $self_da_acl_val) {
if ($self_da_acl_val == 0) { if ($self_da_acl_val == 0) {
unset($data[$self_da_acl_key]); unset($data[$self_da_acl_key]);
} }
} }
} }
if (!empty($data)) { if (!empty($data)) {
unset($data['username']); unset($data['username']);
return $data; return $data;
} }
else { else {
return false; return false;
} }
break; break;
case 'domainadmin': case 'domainadmin':
if ($_SESSION['mailcow_cc_role'] != 'admin' && $_SESSION['mailcow_cc_role'] != 'domainadmin') { if ($_SESSION['mailcow_cc_role'] != 'admin' && $_SESSION['mailcow_cc_role'] != 'domainadmin') {
return false; return false;
} }
if ($_SESSION['mailcow_cc_role'] == 'domainadmin' && $_SESSION['mailcow_cc_username'] != $_data) { if ($_SESSION['mailcow_cc_role'] == 'domainadmin' && $_SESSION['mailcow_cc_username'] != $_data) {
return false; return false;
} }
$stmt = $pdo->prepare("SELECT * FROM `da_acl` WHERE `username` = :username"); $stmt = $pdo->prepare("SELECT * FROM `da_acl` WHERE `username` = :username");
$stmt->execute(array(':username' => $_data)); $stmt->execute(array(':username' => $_data));
$data = $stmt->fetch(PDO::FETCH_ASSOC); $data = $stmt->fetch(PDO::FETCH_ASSOC);
if (!empty($data)) { if (!empty($data)) {
unset($data['username']); unset($data['username']);
return $data; return $data;
} }
else { else {
return false; return false;
} }
break; break;
} }
break; break;
case 'to_session': case 'to_session':
if (!isset($_SESSION['mailcow_cc_role'])) { if (!isset($_SESSION['mailcow_cc_role'])) {
return false; return false;
} }
unset($_SESSION['acl']); unset($_SESSION['acl']);
$username = strtolower(trim($_SESSION['mailcow_cc_username'])); $username = strtolower(trim($_SESSION['mailcow_cc_username']));
// Admins get access to all modules // Admins get access to all modules
if ($_SESSION['mailcow_cc_role'] == 'admin' || if ($_SESSION['mailcow_cc_role'] == 'admin' ||
(isset($_SESSION["dual-login"]["role"]) && $_SESSION["dual-login"]["role"] == 'admin')) { (isset($_SESSION["dual-login"]["role"]) && $_SESSION["dual-login"]["role"] == 'admin')) {
$stmt = $pdo->query("SHOW COLUMNS FROM `user_acl` WHERE `Field` != 'username';"); $stmt = $pdo->query("SHOW COLUMNS FROM `user_acl` WHERE `Field` != 'username';");
$acl_all = $stmt->fetchAll(PDO::FETCH_ASSOC); $acl_all = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($acl_all)) { while ($row = array_shift($acl_all)) {
$acl['acl'][$row['Field']] = 1; $acl['acl'][$row['Field']] = 1;
} }
$stmt = $pdo->query("SHOW COLUMNS FROM `da_acl` WHERE `Field` != 'username';"); $stmt = $pdo->query("SHOW COLUMNS FROM `da_acl` WHERE `Field` != 'username';");
$acl_all = $stmt->fetchAll(PDO::FETCH_ASSOC); $acl_all = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($acl_all)) { while ($row = array_shift($acl_all)) {
$acl['acl'][$row['Field']] = 1; $acl['acl'][$row['Field']] = 1;
} }
} }
elseif ($_SESSION['mailcow_cc_role'] == 'domainadmin' || elseif ($_SESSION['mailcow_cc_role'] == 'domainadmin' ||
(isset($_SESSION["dual-login"]["role"]) && $_SESSION["dual-login"]["role"] == 'domainadmin')) { (isset($_SESSION["dual-login"]["role"]) && $_SESSION["dual-login"]["role"] == 'domainadmin')) {
// Read all exting user_acl modules and set to 1 // Read all exting user_acl modules and set to 1
$stmt = $pdo->query("SHOW COLUMNS FROM `user_acl` WHERE `Field` != 'username';"); $stmt = $pdo->query("SHOW COLUMNS FROM `user_acl` WHERE `Field` != 'username';");
$acl_all = $stmt->fetchAll(PDO::FETCH_ASSOC); $acl_all = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($acl_all)) { while ($row = array_shift($acl_all)) {
$acl['acl'][$row['Field']] = 1; $acl['acl'][$row['Field']] = 1;
} }
// Read da_acl rules for current user, OVERWRITE overlapping modules // Read da_acl rules for current user, OVERWRITE overlapping modules
// This prevents access to a users sync jobs, when a domain admins was not given access to sync jobs // This prevents access to a users sync jobs, when a domain admins was not given access to sync jobs
$stmt = $pdo->prepare("SELECT * FROM `da_acl` WHERE `username` = :username"); $stmt = $pdo->prepare("SELECT * FROM `da_acl` WHERE `username` = :username");
$stmt->execute(array(':username' => (isset($_SESSION["dual-login"]["username"])) ? $_SESSION["dual-login"]["username"] : $username)); $stmt->execute(array(':username' => (isset($_SESSION["dual-login"]["username"])) ? $_SESSION["dual-login"]["username"] : $username));
$acl_user = $stmt->fetch(PDO::FETCH_ASSOC); $acl_user = $stmt->fetch(PDO::FETCH_ASSOC);
foreach ($acl_user as $acl_user_key => $acl_user_val) { foreach ($acl_user as $acl_user_key => $acl_user_val) {
$acl['acl'][$acl_user_key] = $acl_user_val; $acl['acl'][$acl_user_key] = $acl_user_val;
} }
unset($acl['acl']['username']); unset($acl['acl']['username']);
} }
elseif ($_SESSION['mailcow_cc_role'] == 'user') { elseif ($_SESSION['mailcow_cc_role'] == 'user') {
$stmt = $pdo->prepare("SELECT * FROM `user_acl` WHERE `username` = :username"); $stmt = $pdo->prepare("SELECT * FROM `user_acl` WHERE `username` = :username");
$stmt->execute(array(':username' => $username)); $stmt->execute(array(':username' => $username));
$acl['acl'] = $stmt->fetch(PDO::FETCH_ASSOC); $acl['acl'] = $stmt->fetch(PDO::FETCH_ASSOC);
unset($acl['acl']['username']); unset($acl['acl']['username']);
} }
if (!empty($acl)) { if (!empty($acl)) {
$_SESSION = array_merge($_SESSION, $acl); $_SESSION = array_merge($_SESSION, $acl);
} }
break; break;
} }
} }

View File

@ -1,436 +1,436 @@
<?php <?php
function bcc($_action, $_data = null, $_attr = null) { function bcc($_action, $_data = null, $_attr = null) {
global $pdo; global $pdo;
global $lang; global $lang;
if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") { if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
return false; return false;
} }
switch ($_action) { switch ($_action) {
case 'add': case 'add':
if (!isset($_SESSION['acl']['bcc_maps']) || $_SESSION['acl']['bcc_maps'] != "1" ) { if (!isset($_SESSION['acl']['bcc_maps']) || $_SESSION['acl']['bcc_maps'] != "1" ) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$local_dest = strtolower(trim($_data['local_dest'])); $local_dest = strtolower(trim($_data['local_dest']));
$bcc_dest = $_data['bcc_dest']; $bcc_dest = $_data['bcc_dest'];
$active = intval($_data['active']); $active = intval($_data['active']);
$type = $_data['type']; $type = $_data['type'];
if ($type != 'sender' && $type != 'rcpt') { if ($type != 'sender' && $type != 'rcpt') {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'invalid_bcc_map_type' 'msg' => 'invalid_bcc_map_type'
); );
return false; return false;
} }
if (empty($bcc_dest)) { if (empty($bcc_dest)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'bcc_empty' 'msg' => 'bcc_empty'
); );
return false; return false;
} }
if (is_valid_domain_name($local_dest)) { if (is_valid_domain_name($local_dest)) {
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $local_dest)) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $local_dest)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$domain = idn_to_ascii($local_dest, 0, INTL_IDNA_VARIANT_UTS46); $domain = idn_to_ascii($local_dest, 0, INTL_IDNA_VARIANT_UTS46);
$local_dest_sane = '@' . idn_to_ascii($local_dest, 0, INTL_IDNA_VARIANT_UTS46); $local_dest_sane = '@' . idn_to_ascii($local_dest, 0, INTL_IDNA_VARIANT_UTS46);
} }
elseif (filter_var($local_dest, FILTER_VALIDATE_EMAIL)) { elseif (filter_var($local_dest, FILTER_VALIDATE_EMAIL)) {
$mailbox = mailbox('get', 'mailbox_details', $local_dest); $mailbox = mailbox('get', 'mailbox_details', $local_dest);
if ($mailbox === false && array_key_exists($local_dest, array_merge($direct_aliases, $shared_aliases)) === false) { if ($mailbox === false && array_key_exists($local_dest, array_merge($direct_aliases, $shared_aliases)) === false) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $local_dest) && if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $local_dest) &&
!hasAliasObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $local_dest)) { !hasAliasObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $local_dest)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$domain = idn_to_ascii(substr(strstr($local_dest, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46); $domain = idn_to_ascii(substr(strstr($local_dest, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
$local_dest_sane = $local_dest; $local_dest_sane = $local_dest;
} }
else { else {
return false; return false;
} }
if (!filter_var($bcc_dest, FILTER_VALIDATE_EMAIL)) { if (!filter_var($bcc_dest, FILTER_VALIDATE_EMAIL)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('bcc_must_be_email', htmlspecialchars($bcc_dest)) 'msg' => array('bcc_must_be_email', htmlspecialchars($bcc_dest))
); );
return false; return false;
} }
$stmt = $pdo->prepare("SELECT `id` FROM `bcc_maps` $stmt = $pdo->prepare("SELECT `id` FROM `bcc_maps`
WHERE `local_dest` = :local_dest AND `type` = :type"); WHERE `local_dest` = :local_dest AND `type` = :type");
$stmt->execute(array(':local_dest' => $local_dest_sane, ':type' => $type)); $stmt->execute(array(':local_dest' => $local_dest_sane, ':type' => $type));
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results != 0) { if ($num_results != 0) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('bcc_exists', htmlspecialchars($local_dest_sane), $type) 'msg' => array('bcc_exists', htmlspecialchars($local_dest_sane), $type)
); );
return false; return false;
} }
$stmt = $pdo->prepare("INSERT INTO `bcc_maps` (`local_dest`, `bcc_dest`, `domain`, `active`, `type`) VALUES $stmt = $pdo->prepare("INSERT INTO `bcc_maps` (`local_dest`, `bcc_dest`, `domain`, `active`, `type`) VALUES
(:local_dest, :bcc_dest, :domain, :active, :type)"); (:local_dest, :bcc_dest, :domain, :active, :type)");
$stmt->execute(array( $stmt->execute(array(
':local_dest' => $local_dest_sane, ':local_dest' => $local_dest_sane,
':bcc_dest' => $bcc_dest, ':bcc_dest' => $bcc_dest,
':domain' => $domain, ':domain' => $domain,
':active' => $active, ':active' => $active,
':type' => $type ':type' => $type
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'bcc_saved' 'msg' => 'bcc_saved'
); );
break; break;
case 'edit': case 'edit':
if (!isset($_SESSION['acl']['bcc_maps']) || $_SESSION['acl']['bcc_maps'] != "1" ) { if (!isset($_SESSION['acl']['bcc_maps']) || $_SESSION['acl']['bcc_maps'] != "1" ) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$ids = (array)$_data['id']; $ids = (array)$_data['id'];
foreach ($ids as $id) { foreach ($ids as $id) {
$is_now = bcc('details', $id); $is_now = bcc('details', $id);
if (!empty($is_now)) { if (!empty($is_now)) {
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active']; $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
$bcc_dest = (!empty($_data['bcc_dest'])) ? $_data['bcc_dest'] : $is_now['bcc_dest']; $bcc_dest = (!empty($_data['bcc_dest'])) ? $_data['bcc_dest'] : $is_now['bcc_dest'];
$local_dest = $is_now['local_dest']; $local_dest = $is_now['local_dest'];
$type = (!empty($_data['type'])) ? $_data['type'] : $is_now['type']; $type = (!empty($_data['type'])) ? $_data['type'] : $is_now['type'];
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
continue; continue;
} }
if (!filter_var($bcc_dest, FILTER_VALIDATE_EMAIL)) { if (!filter_var($bcc_dest, FILTER_VALIDATE_EMAIL)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('bcc_must_be_email', $bcc_dest) 'msg' => array('bcc_must_be_email', $bcc_dest)
); );
continue; continue;
} }
if (empty($bcc_dest)) { if (empty($bcc_dest)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('bcc_must_be_email', $bcc_dest) 'msg' => array('bcc_must_be_email', $bcc_dest)
); );
continue; continue;
} }
$stmt = $pdo->prepare("SELECT `id` FROM `bcc_maps` $stmt = $pdo->prepare("SELECT `id` FROM `bcc_maps`
WHERE `local_dest` = :local_dest AND `type` = :type"); WHERE `local_dest` = :local_dest AND `type` = :type");
$stmt->execute(array(':local_dest' => $local_dest, ':type' => $type)); $stmt->execute(array(':local_dest' => $local_dest, ':type' => $type));
$id_now = $stmt->fetch(PDO::FETCH_ASSOC)['id']; $id_now = $stmt->fetch(PDO::FETCH_ASSOC)['id'];
if (isset($id_now) && $id_now != $id) { if (isset($id_now) && $id_now != $id) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('bcc_exists', htmlspecialchars($local_dest), $type) 'msg' => array('bcc_exists', htmlspecialchars($local_dest), $type)
); );
continue; continue;
} }
$stmt = $pdo->prepare("UPDATE `bcc_maps` SET `bcc_dest` = :bcc_dest, `active` = :active, `type` = :type WHERE `id`= :id"); $stmt = $pdo->prepare("UPDATE `bcc_maps` SET `bcc_dest` = :bcc_dest, `active` = :active, `type` = :type WHERE `id`= :id");
$stmt->execute(array( $stmt->execute(array(
':bcc_dest' => $bcc_dest, ':bcc_dest' => $bcc_dest,
':active' => $active, ':active' => $active,
':type' => $type, ':type' => $type,
':id' => $id ':id' => $id
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('bcc_edited', $bcc_dest) 'msg' => array('bcc_edited', $bcc_dest)
); );
} }
break; break;
case 'details': case 'details':
$bccdata = array(); $bccdata = array();
$id = intval($_data); $id = intval($_data);
$stmt = $pdo->prepare("SELECT `id`, $stmt = $pdo->prepare("SELECT `id`,
`local_dest`, `local_dest`,
`bcc_dest`, `bcc_dest`,
`active`, `active`,
`type`, `type`,
`created`, `created`,
`domain`, `domain`,
`modified` FROM `bcc_maps` `modified` FROM `bcc_maps`
WHERE `id` = :id"); WHERE `id` = :id");
$stmt->execute(array(':id' => $id)); $stmt->execute(array(':id' => $id));
$bccdata = $stmt->fetch(PDO::FETCH_ASSOC); $bccdata = $stmt->fetch(PDO::FETCH_ASSOC);
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $bccdata['domain'])) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $bccdata['domain'])) {
$bccdata = null; $bccdata = null;
return false; return false;
} }
return $bccdata; return $bccdata;
break; break;
case 'get': case 'get':
$bccdata = array(); $bccdata = array();
$all_items = array(); $all_items = array();
$id = intval($_data); $id = intval($_data);
$stmt = $pdo->query("SELECT `id`, `domain` FROM `bcc_maps`"); $stmt = $pdo->query("SELECT `id`, `domain` FROM `bcc_maps`");
$all_items = $stmt->fetchAll(PDO::FETCH_ASSOC); $all_items = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($all_items as $i) { foreach ($all_items as $i) {
if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $i['domain'])) { if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $i['domain'])) {
$bccdata[] = $i['id']; $bccdata[] = $i['id'];
} }
} }
$all_items = null; $all_items = null;
return $bccdata; return $bccdata;
break; break;
case 'delete': case 'delete':
if (!isset($_SESSION['acl']['bcc_maps']) || $_SESSION['acl']['bcc_maps'] != "1" ) { if (!isset($_SESSION['acl']['bcc_maps']) || $_SESSION['acl']['bcc_maps'] != "1" ) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$ids = (array)$_data['id']; $ids = (array)$_data['id'];
foreach ($ids as $id) { foreach ($ids as $id) {
if (!is_numeric($id)) { if (!is_numeric($id)) {
return false; return false;
} }
$stmt = $pdo->prepare("SELECT `domain` FROM `bcc_maps` WHERE id = :id"); $stmt = $pdo->prepare("SELECT `domain` FROM `bcc_maps` WHERE id = :id");
$stmt->execute(array(':id' => $id)); $stmt->execute(array(':id' => $id));
$domain = $stmt->fetch(PDO::FETCH_ASSOC)['domain']; $domain = $stmt->fetch(PDO::FETCH_ASSOC)['domain'];
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
continue; continue;
} }
$stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `id`= :id"); $stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `id`= :id");
$stmt->execute(array(':id' => $id)); $stmt->execute(array(':id' => $id));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('bcc_deleted', $id) 'msg' => array('bcc_deleted', $id)
); );
} }
break; break;
} }
} }
function recipient_map($_action, $_data = null, $attr = null) { function recipient_map($_action, $_data = null, $attr = null) {
global $pdo; global $pdo;
global $lang; global $lang;
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
return false; return false;
} }
switch ($_action) { switch ($_action) {
case 'add': case 'add':
$old_dest = strtolower(trim($_data['recipient_map_old'])); $old_dest = strtolower(trim($_data['recipient_map_old']));
if (substr($old_dest, 0, 1) == '@') { if (substr($old_dest, 0, 1) == '@') {
$old_dest = substr($old_dest, 1); $old_dest = substr($old_dest, 1);
} }
$new_dest = strtolower(trim($_data['recipient_map_new'])); $new_dest = strtolower(trim($_data['recipient_map_new']));
$active = intval($_data['active']); $active = intval($_data['active']);
if (is_valid_domain_name($old_dest)) { if (is_valid_domain_name($old_dest)) {
$old_dest_sane = '@' . idn_to_ascii($old_dest, 0, INTL_IDNA_VARIANT_UTS46); $old_dest_sane = '@' . idn_to_ascii($old_dest, 0, INTL_IDNA_VARIANT_UTS46);
} }
elseif (filter_var($old_dest, FILTER_VALIDATE_EMAIL)) { elseif (filter_var($old_dest, FILTER_VALIDATE_EMAIL)) {
$old_dest_sane = $old_dest; $old_dest_sane = $old_dest;
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('invalid_recipient_map_old', htmlspecialchars($old_dest)) 'msg' => array('invalid_recipient_map_old', htmlspecialchars($old_dest))
); );
return false; return false;
} }
if (!filter_var($new_dest, FILTER_VALIDATE_EMAIL)) { if (!filter_var($new_dest, FILTER_VALIDATE_EMAIL)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('invalid_recipient_map_new', htmlspecialchars($new_dest)) 'msg' => array('invalid_recipient_map_new', htmlspecialchars($new_dest))
); );
return false; return false;
} }
$rmaps = recipient_map('get'); $rmaps = recipient_map('get');
foreach ($rmaps as $rmap) { foreach ($rmaps as $rmap) {
if (recipient_map('details', $rmap)['recipient_map_old'] == $old_dest_sane) { if (recipient_map('details', $rmap)['recipient_map_old'] == $old_dest_sane) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('recipient_map_entry_exists', htmlspecialchars($old_dest_sane)) 'msg' => array('recipient_map_entry_exists', htmlspecialchars($old_dest_sane))
); );
return false; return false;
} }
} }
$stmt = $pdo->prepare("INSERT INTO `recipient_maps` (`old_dest`, `new_dest`, `active`) VALUES $stmt = $pdo->prepare("INSERT INTO `recipient_maps` (`old_dest`, `new_dest`, `active`) VALUES
(:old_dest, :new_dest, :active)"); (:old_dest, :new_dest, :active)");
$stmt->execute(array( $stmt->execute(array(
':old_dest' => $old_dest_sane, ':old_dest' => $old_dest_sane,
':new_dest' => $new_dest, ':new_dest' => $new_dest,
':active' => $active ':active' => $active
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('recipient_map_entry_saved', htmlspecialchars($old_dest_sane)) 'msg' => array('recipient_map_entry_saved', htmlspecialchars($old_dest_sane))
); );
break; break;
case 'edit': case 'edit':
$ids = (array)$_data['id']; $ids = (array)$_data['id'];
foreach ($ids as $id) { foreach ($ids as $id) {
$is_now = recipient_map('details', $id); $is_now = recipient_map('details', $id);
if (!empty($is_now)) { if (!empty($is_now)) {
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active']; $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
$new_dest = (!empty($_data['recipient_map_new'])) ? $_data['recipient_map_new'] : $is_now['recipient_map_new']; $new_dest = (!empty($_data['recipient_map_new'])) ? $_data['recipient_map_new'] : $is_now['recipient_map_new'];
$old_dest = (!empty($_data['recipient_map_old'])) ? $_data['recipient_map_old'] : $is_now['recipient_map_old']; $old_dest = (!empty($_data['recipient_map_old'])) ? $_data['recipient_map_old'] : $is_now['recipient_map_old'];
if (substr($old_dest, 0, 1) == '@') { if (substr($old_dest, 0, 1) == '@') {
$old_dest = substr($old_dest, 1); $old_dest = substr($old_dest, 1);
} }
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
continue; continue;
} }
if (is_valid_domain_name($old_dest)) { if (is_valid_domain_name($old_dest)) {
$old_dest_sane = '@' . idn_to_ascii($old_dest, 0, INTL_IDNA_VARIANT_UTS46); $old_dest_sane = '@' . idn_to_ascii($old_dest, 0, INTL_IDNA_VARIANT_UTS46);
} }
elseif (filter_var($old_dest, FILTER_VALIDATE_EMAIL)) { elseif (filter_var($old_dest, FILTER_VALIDATE_EMAIL)) {
$old_dest_sane = $old_dest; $old_dest_sane = $old_dest;
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('invalid_recipient_map_old', htmlspecialchars($old_dest)) 'msg' => array('invalid_recipient_map_old', htmlspecialchars($old_dest))
); );
continue; continue;
} }
if (!filter_var($new_dest, FILTER_VALIDATE_EMAIL)) { if (!filter_var($new_dest, FILTER_VALIDATE_EMAIL)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('invalid_recipient_map_new', htmlspecialchars($new_dest)) 'msg' => array('invalid_recipient_map_new', htmlspecialchars($new_dest))
); );
continue; continue;
} }
$rmaps = recipient_map('get'); $rmaps = recipient_map('get');
foreach ($rmaps as $rmap) { foreach ($rmaps as $rmap) {
if ($rmap == $id) { continue; } if ($rmap == $id) { continue; }
if (recipient_map('details', $rmap)['recipient_map_old'] == $old_dest_sane) { if (recipient_map('details', $rmap)['recipient_map_old'] == $old_dest_sane) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('recipient_map_entry_exists', htmlspecialchars($old_dest_sane)) 'msg' => array('recipient_map_entry_exists', htmlspecialchars($old_dest_sane))
); );
return false; return false;
} }
} }
$stmt = $pdo->prepare("UPDATE `recipient_maps` SET $stmt = $pdo->prepare("UPDATE `recipient_maps` SET
`old_dest` = :old_dest, `old_dest` = :old_dest,
`new_dest` = :new_dest, `new_dest` = :new_dest,
`active` = :active `active` = :active
WHERE `id`= :id"); WHERE `id`= :id");
$stmt->execute(array( $stmt->execute(array(
':old_dest' => $old_dest_sane, ':old_dest' => $old_dest_sane,
':new_dest' => $new_dest, ':new_dest' => $new_dest,
':active' => $active, ':active' => $active,
':id' => $id ':id' => $id
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('recipient_map_entry_saved', htmlspecialchars($old_dest_sane)) 'msg' => array('recipient_map_entry_saved', htmlspecialchars($old_dest_sane))
); );
} }
break; break;
case 'details': case 'details':
$mapdata = array(); $mapdata = array();
$id = intval($_data); $id = intval($_data);
$stmt = $pdo->prepare("SELECT `id`, $stmt = $pdo->prepare("SELECT `id`,
`old_dest` AS `recipient_map_old`, `old_dest` AS `recipient_map_old`,
`new_dest` AS `recipient_map_new`, `new_dest` AS `recipient_map_new`,
`active`, `active`,
`created`, `created`,
`modified` FROM `recipient_maps` `modified` FROM `recipient_maps`
WHERE `id` = :id"); WHERE `id` = :id");
$stmt->execute(array(':id' => $id)); $stmt->execute(array(':id' => $id));
$mapdata = $stmt->fetch(PDO::FETCH_ASSOC); $mapdata = $stmt->fetch(PDO::FETCH_ASSOC);
return $mapdata; return $mapdata;
break; break;
case 'get': case 'get':
$mapdata = array(); $mapdata = array();
$all_items = array(); $all_items = array();
$id = intval($_data); $id = intval($_data);
$stmt = $pdo->query("SELECT `id` FROM `recipient_maps`"); $stmt = $pdo->query("SELECT `id` FROM `recipient_maps`");
$all_items = $stmt->fetchAll(PDO::FETCH_ASSOC); $all_items = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($all_items as $i) { foreach ($all_items as $i) {
$mapdata[] = $i['id']; $mapdata[] = $i['id'];
} }
$all_items = null; $all_items = null;
return $mapdata; return $mapdata;
break; break;
case 'delete': case 'delete':
$ids = (array)$_data['id']; $ids = (array)$_data['id'];
foreach ($ids as $id) { foreach ($ids as $id) {
if (!is_numeric($id)) { if (!is_numeric($id)) {
return false; return false;
} }
$stmt = $pdo->prepare("DELETE FROM `recipient_maps` WHERE `id`= :id"); $stmt = $pdo->prepare("DELETE FROM `recipient_maps` WHERE `id`= :id");
$stmt->execute(array(':id' => $id)); $stmt->execute(array(':id' => $id));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('recipient_map_entry_deleted', htmlspecialchars($id)) 'msg' => array('recipient_map_entry_deleted', htmlspecialchars($id))
); );
} }
break; break;
} }
} }

View File

@ -1,246 +1,246 @@
<?php <?php
function admin($_action, $_data = null) { function admin($_action, $_data = null) {
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
global $pdo; global $pdo;
global $lang; global $lang;
$_data_log = $_data; $_data_log = $_data;
!isset($_data_log['password']) ?: $_data_log['password'] = '*'; !isset($_data_log['password']) ?: $_data_log['password'] = '*';
!isset($_data_log['password2']) ?: $_data_log['password2'] = '*'; !isset($_data_log['password2']) ?: $_data_log['password2'] = '*';
switch ($_action) { switch ($_action) {
case 'add': case 'add':
$username = strtolower(trim($_data['username'])); $username = strtolower(trim($_data['username']));
$password = $_data['password']; $password = $_data['password'];
$password2 = $_data['password2']; $password2 = $_data['password2'];
$active = intval($_data['active']); $active = intval($_data['active']);
if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username)) || empty ($username) || $username == 'API') { if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username)) || empty ($username) || $username == 'API') {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('username_invalid', $username) 'msg' => array('username_invalid', $username)
); );
return false; return false;
} }
$stmt = $pdo->prepare("SELECT `username` FROM `admin` $stmt = $pdo->prepare("SELECT `username` FROM `admin`
WHERE `username` = :username"); WHERE `username` = :username");
$stmt->execute(array(':username' => $username)); $stmt->execute(array(':username' => $username));
$num_results[] = count($stmt->fetchAll(PDO::FETCH_ASSOC)); $num_results[] = count($stmt->fetchAll(PDO::FETCH_ASSOC));
$stmt = $pdo->prepare("SELECT `username` FROM `domain_admins` $stmt = $pdo->prepare("SELECT `username` FROM `domain_admins`
WHERE `username` = :username"); WHERE `username` = :username");
$stmt->execute(array(':username' => $username)); $stmt->execute(array(':username' => $username));
$num_results[] = count($stmt->fetchAll(PDO::FETCH_ASSOC)); $num_results[] = count($stmt->fetchAll(PDO::FETCH_ASSOC));
foreach ($num_results as $num_results_each) { foreach ($num_results as $num_results_each) {
if ($num_results_each != 0) { if ($num_results_each != 0) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('object_exists', htmlspecialchars($username)) 'msg' => array('object_exists', htmlspecialchars($username))
); );
return false; return false;
} }
} }
if (password_check($password, $password2) !== true) { if (password_check($password, $password2) !== true) {
return false; return false;
} }
$password_hashed = hash_password($password); $password_hashed = hash_password($password);
$stmt = $pdo->prepare("INSERT INTO `admin` (`username`, `password`, `superadmin`, `active`) $stmt = $pdo->prepare("INSERT INTO `admin` (`username`, `password`, `superadmin`, `active`)
VALUES (:username, :password_hashed, '1', :active)"); VALUES (:username, :password_hashed, '1', :active)");
$stmt->execute(array( $stmt->execute(array(
':username' => $username, ':username' => $username,
':password_hashed' => $password_hashed, ':password_hashed' => $password_hashed,
':active' => $active ':active' => $active
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('admin_added', htmlspecialchars($username)) 'msg' => array('admin_added', htmlspecialchars($username))
); );
break; break;
case 'edit': case 'edit':
if (!is_array($_data['username'])) { if (!is_array($_data['username'])) {
$usernames = array(); $usernames = array();
$usernames[] = $_data['username']; $usernames[] = $_data['username'];
} }
else { else {
$usernames = $_data['username']; $usernames = $_data['username'];
} }
foreach ($usernames as $username) { foreach ($usernames as $username) {
$is_now = admin('details', $username); $is_now = admin('details', $username);
if (!empty($is_now)) { if (!empty($is_now)) {
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active']; $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
$username_new = (!empty($_data['username_new'])) ? $_data['username_new'] : $is_now['username']; $username_new = (!empty($_data['username_new'])) ? $_data['username_new'] : $is_now['username'];
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
continue; continue;
} }
$password = $_data['password']; $password = $_data['password'];
$password2 = $_data['password2']; $password2 = $_data['password2'];
if ($active == 0) { if ($active == 0) {
$left_active = 0; $left_active = 0;
foreach (admin('get') as $admin) { foreach (admin('get') as $admin) {
$left_active = $left_active + admin('details', $admin)['active']; $left_active = $left_active + admin('details', $admin)['active'];
} }
if ($left_active == 1) { if ($left_active == 1) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'warning', 'type' => 'warning',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'no_active_admin' 'msg' => 'no_active_admin'
); );
continue; continue;
} }
} }
if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username_new))) { if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username_new))) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('username_invalid', $username_new) 'msg' => array('username_invalid', $username_new)
); );
continue; continue;
} }
if ($username_new != $username) { if ($username_new != $username) {
if (!empty(admin('details', $username_new)['username'])) { if (!empty(admin('details', $username_new)['username'])) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('username_invalid', $username_new) 'msg' => array('username_invalid', $username_new)
); );
continue; continue;
} }
} }
if (!empty($password)) { if (!empty($password)) {
if (password_check($password, $password2) !== true) { if (password_check($password, $password2) !== true) {
return false; return false;
} }
$password_hashed = hash_password($password); $password_hashed = hash_password($password);
$stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active, `password` = :password_hashed WHERE `username` = :username"); $stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active, `password` = :password_hashed WHERE `username` = :username");
$stmt->execute(array( $stmt->execute(array(
':password_hashed' => $password_hashed, ':password_hashed' => $password_hashed,
':username_new' => $username_new, ':username_new' => $username_new,
':username' => $username, ':username' => $username,
':active' => $active ':active' => $active
)); ));
if (isset($_data['disable_tfa'])) { if (isset($_data['disable_tfa'])) {
$stmt = $pdo->prepare("UPDATE `tfa` SET `active` = '0' WHERE `username` = :username"); $stmt = $pdo->prepare("UPDATE `tfa` SET `active` = '0' WHERE `username` = :username");
$stmt->execute(array(':username' => $username)); $stmt->execute(array(':username' => $username));
} }
else { else {
$stmt = $pdo->prepare("UPDATE `tfa` SET `username` = :username_new WHERE `username` = :username"); $stmt = $pdo->prepare("UPDATE `tfa` SET `username` = :username_new WHERE `username` = :username");
$stmt->execute(array(':username_new' => $username_new, ':username' => $username)); $stmt->execute(array(':username_new' => $username_new, ':username' => $username));
} }
} }
else { else {
$stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active WHERE `username` = :username"); $stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active WHERE `username` = :username");
$stmt->execute(array( $stmt->execute(array(
':username_new' => $username_new, ':username_new' => $username_new,
':username' => $username, ':username' => $username,
':active' => $active ':active' => $active
)); ));
if (isset($_data['disable_tfa'])) { if (isset($_data['disable_tfa'])) {
$stmt = $pdo->prepare("UPDATE `tfa` SET `active` = '0' WHERE `username` = :username"); $stmt = $pdo->prepare("UPDATE `tfa` SET `active` = '0' WHERE `username` = :username");
$stmt->execute(array(':username' => $username)); $stmt->execute(array(':username' => $username));
} }
else { else {
$stmt = $pdo->prepare("UPDATE `tfa` SET `username` = :username_new WHERE `username` = :username"); $stmt = $pdo->prepare("UPDATE `tfa` SET `username` = :username_new WHERE `username` = :username");
$stmt->execute(array(':username_new' => $username_new, ':username' => $username)); $stmt->execute(array(':username_new' => $username_new, ':username' => $username));
} }
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('admin_modified', htmlspecialchars($username)) 'msg' => array('admin_modified', htmlspecialchars($username))
); );
} }
return true; return true;
break; break;
case 'delete': case 'delete':
$usernames = (array)$_data['username']; $usernames = (array)$_data['username'];
foreach ($usernames as $username) { foreach ($usernames as $username) {
if ($_SESSION['mailcow_cc_username'] == $username) { if ($_SESSION['mailcow_cc_username'] == $username) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'warning', 'type' => 'warning',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'cannot_delete_self' 'msg' => 'cannot_delete_self'
); );
continue; continue;
} }
if (empty(admin('details', $username))) { if (empty(admin('details', $username))) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('username_invalid', $username) 'msg' => array('username_invalid', $username)
); );
continue; continue;
} }
$stmt = $pdo->prepare("DELETE FROM `admin` WHERE `username` = :username"); $stmt = $pdo->prepare("DELETE FROM `admin` WHERE `username` = :username");
$stmt->execute(array( $stmt->execute(array(
':username' => $username, ':username' => $username,
)); ));
$stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `username` = :username"); $stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `username` = :username");
$stmt->execute(array( $stmt->execute(array(
':username' => $username, ':username' => $username,
)); ));
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username"); $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username");
$stmt->execute(array( $stmt->execute(array(
':username' => $username, ':username' => $username,
)); ));
$stmt = $pdo->prepare("DELETE FROM `fido2` WHERE `username` = :username"); $stmt = $pdo->prepare("DELETE FROM `fido2` WHERE `username` = :username");
$stmt->execute(array( $stmt->execute(array(
':username' => $username, ':username' => $username,
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('admin_removed', htmlspecialchars($username)) 'msg' => array('admin_removed', htmlspecialchars($username))
); );
} }
break; break;
case 'get': case 'get':
$admins = array(); $admins = array();
$stmt = $pdo->query("SELECT `username` FROM `admin` WHERE `superadmin` = '1'"); $stmt = $pdo->query("SELECT `username` FROM `admin` WHERE `superadmin` = '1'");
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($rows)) { while ($row = array_shift($rows)) {
$admins[] = $row['username']; $admins[] = $row['username'];
} }
return $admins; return $admins;
break; break;
case 'details': case 'details':
$admindata = array(); $admindata = array();
$stmt = $pdo->prepare("SELECT $stmt = $pdo->prepare("SELECT
`tfa`.`active` AS `tfa_active`, `tfa`.`active` AS `tfa_active`,
`admin`.`username`, `admin`.`username`,
`admin`.`created`, `admin`.`created`,
`admin`.`active` AS `active` `admin`.`active` AS `active`
FROM `admin` FROM `admin`
LEFT OUTER JOIN `tfa` ON `tfa`.`username`=`admin`.`username` LEFT OUTER JOIN `tfa` ON `tfa`.`username`=`admin`.`username`
WHERE `admin`.`username`= :admin AND `superadmin` = '1'"); WHERE `admin`.`username`= :admin AND `superadmin` = '1'");
$stmt->execute(array( $stmt->execute(array(
':admin' => $_data ':admin' => $_data
)); ));
$row = $stmt->fetch(PDO::FETCH_ASSOC); $row = $stmt->fetch(PDO::FETCH_ASSOC);
if (empty($row)) { if (empty($row)) {
return false; return false;
} }
$admindata['username'] = $row['username']; $admindata['username'] = $row['username'];
$admindata['tfa_active'] = (is_null($row['tfa_active'])) ? 0 : $row['tfa_active']; $admindata['tfa_active'] = (is_null($row['tfa_active'])) ? 0 : $row['tfa_active'];
$admindata['tfa_active_int'] = (is_null($row['tfa_active'])) ? 0 : $row['tfa_active']; $admindata['tfa_active_int'] = (is_null($row['tfa_active'])) ? 0 : $row['tfa_active'];
$admindata['active'] = $row['active']; $admindata['active'] = $row['active'];
$admindata['active_int'] = $row['active']; $admindata['active_int'] = $row['active'];
$admindata['created'] = $row['created']; $admindata['created'] = $row['created'];
return $admindata; return $admindata;
break; break;
} }
} }

View File

@ -1,242 +1,242 @@
<?php <?php
function app_passwd($_action, $_data = null) { function app_passwd($_action, $_data = null) {
global $pdo; global $pdo;
global $lang; global $lang;
$_data_log = $_data; $_data_log = $_data;
!isset($_data_log['app_passwd']) ?: $_data_log['app_passwd'] = '*'; !isset($_data_log['app_passwd']) ?: $_data_log['app_passwd'] = '*';
!isset($_data_log['app_passwd2']) ?: $_data_log['app_passwd2'] = '*'; !isset($_data_log['app_passwd2']) ?: $_data_log['app_passwd2'] = '*';
if (isset($_data['username']) && filter_var($_data['username'], FILTER_VALIDATE_EMAIL)) { if (isset($_data['username']) && filter_var($_data['username'], FILTER_VALIDATE_EMAIL)) {
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data['username'])) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data['username'])) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
else { else {
$username = $_data['username']; $username = $_data['username'];
} }
} }
else { else {
$username = $_SESSION['mailcow_cc_username']; $username = $_SESSION['mailcow_cc_username'];
} }
switch ($_action) { switch ($_action) {
case 'add': case 'add':
$app_name = htmlspecialchars(trim($_data['app_name'])); $app_name = htmlspecialchars(trim($_data['app_name']));
$password = $_data['app_passwd']; $password = $_data['app_passwd'];
$password2 = $_data['app_passwd2']; $password2 = $_data['app_passwd2'];
$active = intval($_data['active']); $active = intval($_data['active']);
$protocols = (array)$_data['protocols']; $protocols = (array)$_data['protocols'];
$imap_access = (in_array('imap_access', $protocols)) ? 1 : 0; $imap_access = (in_array('imap_access', $protocols)) ? 1 : 0;
$dav_access = (in_array('dav_access', $protocols)) ? 1 : 0; $dav_access = (in_array('dav_access', $protocols)) ? 1 : 0;
$smtp_access = (in_array('smtp_access', $protocols)) ? 1 : 0; $smtp_access = (in_array('smtp_access', $protocols)) ? 1 : 0;
$eas_access = (in_array('eas_access', $protocols)) ? 1 : 0; $eas_access = (in_array('eas_access', $protocols)) ? 1 : 0;
$pop3_access = (in_array('pop3_access', $protocols)) ? 1 : 0; $pop3_access = (in_array('pop3_access', $protocols)) ? 1 : 0;
$sieve_access = (in_array('sieve_access', $protocols)) ? 1 : 0; $sieve_access = (in_array('sieve_access', $protocols)) ? 1 : 0;
$domain = mailbox('get', 'mailbox_details', $username)['domain']; $domain = mailbox('get', 'mailbox_details', $username)['domain'];
if (empty($domain)) { if (empty($domain)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) { if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'password_complexity' 'msg' => 'password_complexity'
); );
return false; return false;
} }
if ($password != $password2) { if ($password != $password2) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'password_mismatch' 'msg' => 'password_mismatch'
); );
return false; return false;
} }
$password_hashed = hash_password($password); $password_hashed = hash_password($password);
if (empty($app_name)) { if (empty($app_name)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'app_name_empty' 'msg' => 'app_name_empty'
); );
return false; return false;
} }
$stmt = $pdo->prepare("INSERT INTO `app_passwd` (`name`, `mailbox`, `domain`, `password`, `imap_access`, `smtp_access`, `eas_access`, `dav_access`, `pop3_access`, `sieve_access`, `active`) $stmt = $pdo->prepare("INSERT INTO `app_passwd` (`name`, `mailbox`, `domain`, `password`, `imap_access`, `smtp_access`, `eas_access`, `dav_access`, `pop3_access`, `sieve_access`, `active`)
VALUES (:app_name, :mailbox, :domain, :password, :imap_access, :smtp_access, :eas_access, :dav_access, :pop3_access, :sieve_access, :active)"); VALUES (:app_name, :mailbox, :domain, :password, :imap_access, :smtp_access, :eas_access, :dav_access, :pop3_access, :sieve_access, :active)");
$stmt->execute(array( $stmt->execute(array(
':app_name' => $app_name, ':app_name' => $app_name,
':mailbox' => $username, ':mailbox' => $username,
':domain' => $domain, ':domain' => $domain,
':password' => $password_hashed, ':password' => $password_hashed,
':imap_access' => $imap_access, ':imap_access' => $imap_access,
':smtp_access' => $smtp_access, ':smtp_access' => $smtp_access,
':eas_access' => $eas_access, ':eas_access' => $eas_access,
':dav_access' => $dav_access, ':dav_access' => $dav_access,
':pop3_access' => $pop3_access, ':pop3_access' => $pop3_access,
':sieve_access' => $sieve_access, ':sieve_access' => $sieve_access,
':active' => $active ':active' => $active
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'app_passwd_added' 'msg' => 'app_passwd_added'
); );
break; break;
case 'edit': case 'edit':
$ids = (array)$_data['id']; $ids = (array)$_data['id'];
foreach ($ids as $id) { foreach ($ids as $id) {
$is_now = app_passwd('details', $id); $is_now = app_passwd('details', $id);
if (!empty($is_now)) { if (!empty($is_now)) {
$app_name = (!empty($_data['app_name'])) ? $_data['app_name'] : $is_now['name']; $app_name = (!empty($_data['app_name'])) ? $_data['app_name'] : $is_now['name'];
$password = (!empty($_data['password'])) ? $_data['password'] : null; $password = (!empty($_data['password'])) ? $_data['password'] : null;
$password2 = (!empty($_data['password2'])) ? $_data['password2'] : null; $password2 = (!empty($_data['password2'])) ? $_data['password2'] : null;
if (isset($_data['protocols'])) { if (isset($_data['protocols'])) {
$protocols = (array)$_data['protocols']; $protocols = (array)$_data['protocols'];
$imap_access = (in_array('imap_access', $protocols)) ? 1 : 0; $imap_access = (in_array('imap_access', $protocols)) ? 1 : 0;
$dav_access = (in_array('dav_access', $protocols)) ? 1 : 0; $dav_access = (in_array('dav_access', $protocols)) ? 1 : 0;
$smtp_access = (in_array('smtp_access', $protocols)) ? 1 : 0; $smtp_access = (in_array('smtp_access', $protocols)) ? 1 : 0;
$eas_access = (in_array('eas_access', $protocols)) ? 1 : 0; $eas_access = (in_array('eas_access', $protocols)) ? 1 : 0;
$pop3_access = (in_array('pop3_access', $protocols)) ? 1 : 0; $pop3_access = (in_array('pop3_access', $protocols)) ? 1 : 0;
$sieve_access = (in_array('sieve_access', $protocols)) ? 1 : 0; $sieve_access = (in_array('sieve_access', $protocols)) ? 1 : 0;
} }
else { else {
$imap_access = $is_now['imap_access']; $imap_access = $is_now['imap_access'];
$smtp_access = $is_now['smtp_access']; $smtp_access = $is_now['smtp_access'];
$dav_access = $is_now['dav_access']; $dav_access = $is_now['dav_access'];
$eas_access = $is_now['eas_access']; $eas_access = $is_now['eas_access'];
$pop3_access = $is_now['pop3_access']; $pop3_access = $is_now['pop3_access'];
$sieve_access = $is_now['sieve_access']; $sieve_access = $is_now['sieve_access'];
} }
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active']; $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('app_passwd_id_invalid', $id) 'msg' => array('app_passwd_id_invalid', $id)
); );
continue; continue;
} }
$app_name = htmlspecialchars(trim($app_name)); $app_name = htmlspecialchars(trim($app_name));
if (!empty($password) && !empty($password2)) { if (!empty($password) && !empty($password2)) {
if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) { if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'password_complexity' 'msg' => 'password_complexity'
); );
continue; continue;
} }
if ($password != $password2) { if ($password != $password2) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'password_mismatch' 'msg' => 'password_mismatch'
); );
continue; continue;
} }
$password_hashed = hash_password($password); $password_hashed = hash_password($password);
$stmt = $pdo->prepare("UPDATE `app_passwd` SET $stmt = $pdo->prepare("UPDATE `app_passwd` SET
`password` = :password_hashed `password` = :password_hashed
WHERE `mailbox` = :username AND `id` = :id"); WHERE `mailbox` = :username AND `id` = :id");
$stmt->execute(array( $stmt->execute(array(
':password_hashed' => $password_hashed, ':password_hashed' => $password_hashed,
':username' => $username, ':username' => $username,
':id' => $id ':id' => $id
)); ));
} }
$stmt = $pdo->prepare("UPDATE `app_passwd` SET $stmt = $pdo->prepare("UPDATE `app_passwd` SET
`name` = :app_name, `name` = :app_name,
`mailbox` = :username, `mailbox` = :username,
`imap_access` = :imap_access, `imap_access` = :imap_access,
`smtp_access` = :smtp_access, `smtp_access` = :smtp_access,
`eas_access` = :eas_access, `eas_access` = :eas_access,
`dav_access` = :dav_access, `dav_access` = :dav_access,
`pop3_access` = :pop3_access, `pop3_access` = :pop3_access,
`sieve_access` = :sieve_access, `sieve_access` = :sieve_access,
`active` = :active `active` = :active
WHERE `id` = :id"); WHERE `id` = :id");
$stmt->execute(array( $stmt->execute(array(
':app_name' => $app_name, ':app_name' => $app_name,
':username' => $username, ':username' => $username,
':imap_access' => $imap_access, ':imap_access' => $imap_access,
':smtp_access' => $smtp_access, ':smtp_access' => $smtp_access,
':eas_access' => $eas_access, ':eas_access' => $eas_access,
':dav_access' => $dav_access, ':dav_access' => $dav_access,
':pop3_access' => $pop3_access, ':pop3_access' => $pop3_access,
':sieve_access' => $sieve_access, ':sieve_access' => $sieve_access,
':active' => $active, ':active' => $active,
':id' => $id ':id' => $id
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('object_modified', htmlspecialchars(implode(', ', $ids))) 'msg' => array('object_modified', htmlspecialchars(implode(', ', $ids)))
); );
} }
break; break;
case 'delete': case 'delete':
$ids = (array)$_data['id']; $ids = (array)$_data['id'];
foreach ($ids as $id) { foreach ($ids as $id) {
$stmt = $pdo->prepare("SELECT `mailbox` FROM `app_passwd` WHERE `id` = :id"); $stmt = $pdo->prepare("SELECT `mailbox` FROM `app_passwd` WHERE `id` = :id");
$stmt->execute(array(':id' => $id)); $stmt->execute(array(':id' => $id));
$mailbox = $stmt->fetch(PDO::FETCH_ASSOC)['mailbox']; $mailbox = $stmt->fetch(PDO::FETCH_ASSOC)['mailbox'];
if (empty($mailbox)) { if (empty($mailbox)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'app_passwd_id_invalid' 'msg' => 'app_passwd_id_invalid'
); );
return false; return false;
} }
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $mailbox)) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $mailbox)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$stmt = $pdo->prepare("DELETE FROM `app_passwd` WHERE `id`= :id"); $stmt = $pdo->prepare("DELETE FROM `app_passwd` WHERE `id`= :id");
$stmt->execute(array(':id' => $id)); $stmt->execute(array(':id' => $id));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('app_passwd_removed', htmlspecialchars($id)) 'msg' => array('app_passwd_removed', htmlspecialchars($id))
); );
} }
break; break;
case 'get': case 'get':
$app_passwds = array(); $app_passwds = array();
$stmt = $pdo->prepare("SELECT `id`, `name` FROM `app_passwd` WHERE `mailbox` = :username"); $stmt = $pdo->prepare("SELECT `id`, `name` FROM `app_passwd` WHERE `mailbox` = :username");
$stmt->execute(array(':username' => $username)); $stmt->execute(array(':username' => $username));
$app_passwds = $stmt->fetchAll(PDO::FETCH_ASSOC); $app_passwds = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $app_passwds; return $app_passwds;
break; break;
case 'details': case 'details':
$app_passwd_data = array(); $app_passwd_data = array();
$stmt = $pdo->prepare("SELECT * $stmt = $pdo->prepare("SELECT *
FROM `app_passwd` FROM `app_passwd`
WHERE `id` = :id"); WHERE `id` = :id");
$stmt->execute(array(':id' => $_data)); $stmt->execute(array(':id' => $_data));
$app_passwd_data = $stmt->fetch(PDO::FETCH_ASSOC); $app_passwd_data = $stmt->fetch(PDO::FETCH_ASSOC);
if (empty($app_passwd_data)) { if (empty($app_passwd_data)) {
return false; return false;
} }
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $app_passwd_data['mailbox'])) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $app_passwd_data['mailbox'])) {
$app_passwd_data = array(); $app_passwd_data = array();
return false; return false;
} }
$app_passwd_data['name'] = htmlspecialchars(trim($app_passwd_data['name'])); $app_passwd_data['name'] = htmlspecialchars(trim($app_passwd_data['name']));
return $app_passwd_data; return $app_passwd_data;
break; break;
} }
} }

View File

@ -1,315 +1,315 @@
<?php <?php
function customize($_action, $_item, $_data = null) { function customize($_action, $_item, $_data = null) {
global $redis; global $redis;
global $lang; global $lang;
switch ($_action) { switch ($_action) {
case 'add': case 'add':
// disable functionality when demo mode is enabled // disable functionality when demo mode is enabled
if ($GLOBALS["DEMO_MODE"]) { if ($GLOBALS["DEMO_MODE"]) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => 'demo_mode_enabled' 'msg' => 'demo_mode_enabled'
); );
return false; return false;
} }
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
switch ($_item) { switch ($_item) {
case 'main_logo': case 'main_logo':
if (in_array($_data['main_logo']['type'], array('image/gif', 'image/jpeg', 'image/pjpeg', 'image/x-png', 'image/png', 'image/svg+xml'))) { if (in_array($_data['main_logo']['type'], array('image/gif', 'image/jpeg', 'image/pjpeg', 'image/x-png', 'image/png', 'image/svg+xml'))) {
try { try {
if (file_exists($_data['main_logo']['tmp_name']) !== true) { if (file_exists($_data['main_logo']['tmp_name']) !== true) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => 'img_tmp_missing' 'msg' => 'img_tmp_missing'
); );
return false; return false;
} }
$image = new Imagick($_data['main_logo']['tmp_name']); $image = new Imagick($_data['main_logo']['tmp_name']);
if ($image->valid() !== true) { if ($image->valid() !== true) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => 'img_invalid' 'msg' => 'img_invalid'
); );
return false; return false;
} }
$image->destroy(); $image->destroy();
} }
catch (ImagickException $e) { catch (ImagickException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => 'img_invalid' 'msg' => 'img_invalid'
); );
return false; return false;
} }
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => 'invalid_mime_type' 'msg' => 'invalid_mime_type'
); );
return false; return false;
} }
try { try {
$redis->Set('MAIN_LOGO', 'data:' . $_data['main_logo']['type'] . ';base64,' . base64_encode(file_get_contents($_data['main_logo']['tmp_name']))); $redis->Set('MAIN_LOGO', 'data:' . $_data['main_logo']['type'] . ';base64,' . base64_encode(file_get_contents($_data['main_logo']['tmp_name'])));
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => 'upload_success' 'msg' => 'upload_success'
); );
break; break;
} }
break; break;
case 'edit': case 'edit':
// disable functionality when demo mode is enabled // disable functionality when demo mode is enabled
if ($GLOBALS["DEMO_MODE"]) { if ($GLOBALS["DEMO_MODE"]) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => 'demo_mode_enabled' 'msg' => 'demo_mode_enabled'
); );
return false; return false;
} }
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
switch ($_item) { switch ($_item) {
case 'app_links': case 'app_links':
$apps = (array)$_data['app']; $apps = (array)$_data['app'];
$links = (array)$_data['href']; $links = (array)$_data['href'];
$out = array(); $out = array();
if (count($apps) == count($links)) { if (count($apps) == count($links)) {
for ($i = 0; $i < count($apps); $i++) { for ($i = 0; $i < count($apps); $i++) {
$out[] = array($apps[$i] => $links[$i]); $out[] = array($apps[$i] => $links[$i]);
} }
try { try {
$redis->set('APP_LINKS', json_encode($out)); $redis->set('APP_LINKS', json_encode($out));
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => 'app_links' 'msg' => 'app_links'
); );
break; break;
case 'ui_texts': case 'ui_texts':
$title_name = $_data['title_name']; $title_name = $_data['title_name'];
$main_name = $_data['main_name']; $main_name = $_data['main_name'];
$apps_name = $_data['apps_name']; $apps_name = $_data['apps_name'];
$help_text = $_data['help_text']; $help_text = $_data['help_text'];
$ui_footer = $_data['ui_footer']; $ui_footer = $_data['ui_footer'];
$ui_announcement_text = $_data['ui_announcement_text']; $ui_announcement_text = $_data['ui_announcement_text'];
$ui_announcement_type = (in_array($_data['ui_announcement_type'], array('info', 'warning', 'danger'))) ? $_data['ui_announcement_type'] : false; $ui_announcement_type = (in_array($_data['ui_announcement_type'], array('info', 'warning', 'danger'))) ? $_data['ui_announcement_type'] : false;
$ui_announcement_active = (!empty($_data['ui_announcement_active']) ? 1 : 0); $ui_announcement_active = (!empty($_data['ui_announcement_active']) ? 1 : 0);
try { try {
$redis->set('TITLE_NAME', htmlspecialchars($title_name)); $redis->set('TITLE_NAME', htmlspecialchars($title_name));
$redis->set('MAIN_NAME', htmlspecialchars($main_name)); $redis->set('MAIN_NAME', htmlspecialchars($main_name));
$redis->set('APPS_NAME', htmlspecialchars($apps_name)); $redis->set('APPS_NAME', htmlspecialchars($apps_name));
$redis->set('HELP_TEXT', $help_text); $redis->set('HELP_TEXT', $help_text);
$redis->set('UI_FOOTER', $ui_footer); $redis->set('UI_FOOTER', $ui_footer);
$redis->set('UI_ANNOUNCEMENT_TEXT', $ui_announcement_text); $redis->set('UI_ANNOUNCEMENT_TEXT', $ui_announcement_text);
$redis->set('UI_ANNOUNCEMENT_TYPE', $ui_announcement_type); $redis->set('UI_ANNOUNCEMENT_TYPE', $ui_announcement_type);
$redis->set('UI_ANNOUNCEMENT_ACTIVE', $ui_announcement_active); $redis->set('UI_ANNOUNCEMENT_ACTIVE', $ui_announcement_active);
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => 'ui_texts' 'msg' => 'ui_texts'
); );
break; break;
case 'ip_check': case 'ip_check':
$ip_check = ($_data['ip_check_opt_in'] == "1") ? 1 : 0; $ip_check = ($_data['ip_check_opt_in'] == "1") ? 1 : 0;
try { try {
$redis->set('IP_CHECK', $ip_check); $redis->set('IP_CHECK', $ip_check);
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => 'ip_check_opt_in_modified' 'msg' => 'ip_check_opt_in_modified'
); );
break; break;
} }
break; break;
case 'delete': case 'delete':
// disable functionality when demo mode is enabled // disable functionality when demo mode is enabled
if ($GLOBALS["DEMO_MODE"]) { if ($GLOBALS["DEMO_MODE"]) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => 'demo_mode_enabled' 'msg' => 'demo_mode_enabled'
); );
return false; return false;
} }
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
switch ($_item) { switch ($_item) {
case 'main_logo': case 'main_logo':
try { try {
if ($redis->del('MAIN_LOGO')) { if ($redis->del('MAIN_LOGO')) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => 'reset_main_logo' 'msg' => 'reset_main_logo'
); );
return true; return true;
} }
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
break; break;
} }
break; break;
case 'get': case 'get':
switch ($_item) { switch ($_item) {
case 'app_links': case 'app_links':
try { try {
$app_links = json_decode($redis->get('APP_LINKS'), true); $app_links = json_decode($redis->get('APP_LINKS'), true);
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
return ($app_links) ? $app_links : false; return ($app_links) ? $app_links : false;
break; break;
case 'main_logo': case 'main_logo':
try { try {
return $redis->get('MAIN_LOGO'); return $redis->get('MAIN_LOGO');
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
break; break;
case 'ui_texts': case 'ui_texts':
try { try {
$data['title_name'] = ($title_name = $redis->get('TITLE_NAME')) ? $title_name : 'mailcow UI'; $data['title_name'] = ($title_name = $redis->get('TITLE_NAME')) ? $title_name : 'mailcow UI';
$data['main_name'] = ($main_name = $redis->get('MAIN_NAME')) ? $main_name : 'mailcow UI'; $data['main_name'] = ($main_name = $redis->get('MAIN_NAME')) ? $main_name : 'mailcow UI';
$data['apps_name'] = ($apps_name = $redis->get('APPS_NAME')) ? $apps_name : $lang['header']['apps']; $data['apps_name'] = ($apps_name = $redis->get('APPS_NAME')) ? $apps_name : $lang['header']['apps'];
$data['help_text'] = ($help_text = $redis->get('HELP_TEXT')) ? $help_text : false; $data['help_text'] = ($help_text = $redis->get('HELP_TEXT')) ? $help_text : false;
if (!empty($redis->get('UI_IMPRESS'))) { if (!empty($redis->get('UI_IMPRESS'))) {
$redis->set('UI_FOOTER', $redis->get('UI_IMPRESS')); $redis->set('UI_FOOTER', $redis->get('UI_IMPRESS'));
$redis->del('UI_IMPRESS'); $redis->del('UI_IMPRESS');
} }
$data['ui_footer'] = ($ui_footer = $redis->get('UI_FOOTER')) ? $ui_footer : false; $data['ui_footer'] = ($ui_footer = $redis->get('UI_FOOTER')) ? $ui_footer : false;
$data['ui_announcement_text'] = ($ui_announcement_text = $redis->get('UI_ANNOUNCEMENT_TEXT')) ? $ui_announcement_text : false; $data['ui_announcement_text'] = ($ui_announcement_text = $redis->get('UI_ANNOUNCEMENT_TEXT')) ? $ui_announcement_text : false;
$data['ui_announcement_type'] = ($ui_announcement_type = $redis->get('UI_ANNOUNCEMENT_TYPE')) ? $ui_announcement_type : false; $data['ui_announcement_type'] = ($ui_announcement_type = $redis->get('UI_ANNOUNCEMENT_TYPE')) ? $ui_announcement_type : false;
$data['ui_announcement_active'] = ($redis->get('UI_ANNOUNCEMENT_ACTIVE') == 1) ? 1 : 0; $data['ui_announcement_active'] = ($redis->get('UI_ANNOUNCEMENT_ACTIVE') == 1) ? 1 : 0;
return $data; return $data;
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
break; break;
case 'main_logo_specs': case 'main_logo_specs':
try { try {
$image = new Imagick(); $image = new Imagick();
$img_data = explode('base64,', customize('get', 'main_logo')); $img_data = explode('base64,', customize('get', 'main_logo'));
if ($img_data[1]) { if ($img_data[1]) {
$image->readImageBlob(base64_decode($img_data[1])); $image->readImageBlob(base64_decode($img_data[1]));
return $image->identifyImage(); return $image->identifyImage();
} }
return false; return false;
} }
catch (ImagickException $e) { catch (ImagickException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => 'imagick_exception' 'msg' => 'imagick_exception'
); );
return false; return false;
} }
break; break;
case 'ip_check': case 'ip_check':
try { try {
$ip_check = ($ip_check = $redis->get('IP_CHECK')) ? $ip_check : 0; $ip_check = ($ip_check = $redis->get('IP_CHECK')) ? $ip_check : 0;
return $ip_check; return $ip_check;
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data), 'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
break; break;
} }
break; break;
} }
} }

View File

@ -1,325 +1,325 @@
<?php <?php
function dkim($_action, $_data = null, $privkey = false) { function dkim($_action, $_data = null, $privkey = false) {
global $redis; global $redis;
global $lang; global $lang;
switch ($_action) { switch ($_action) {
case 'add': case 'add':
$key_length = intval($_data['key_size']); $key_length = intval($_data['key_size']);
$dkim_selector = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : 'dkim'; $dkim_selector = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : 'dkim';
$domains = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['domains'])); $domains = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['domains']));
$domains = array_filter($domains); $domains = array_filter($domains);
foreach ($domains as $domain) { foreach ($domains as $domain) {
if (!is_valid_domain_name($domain) || !is_numeric($key_length)) { if (!is_valid_domain_name($domain) || !is_numeric($key_length)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('dkim_domain_or_sel_invalid', $domain) 'msg' => array('dkim_domain_or_sel_invalid', $domain)
); );
continue; continue;
} }
if ($redis->hGet('DKIM_PUB_KEYS', $domain)) { if ($redis->hGet('DKIM_PUB_KEYS', $domain)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('dkim_domain_or_sel_invalid', $domain) 'msg' => array('dkim_domain_or_sel_invalid', $domain)
); );
continue; continue;
} }
if (!ctype_alnum(str_replace(['-', '_'], '', $dkim_selector))) { if (!ctype_alnum(str_replace(['-', '_'], '', $dkim_selector))) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('dkim_domain_or_sel_invalid', $domain) 'msg' => array('dkim_domain_or_sel_invalid', $domain)
); );
continue; continue;
} }
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('access_denied', $domain) 'msg' => array('access_denied', $domain)
); );
continue; continue;
} }
$config = array( $config = array(
"digest_alg" => "sha256", "digest_alg" => "sha256",
"private_key_bits" => $key_length, "private_key_bits" => $key_length,
"private_key_type" => OPENSSL_KEYTYPE_RSA, "private_key_type" => OPENSSL_KEYTYPE_RSA,
); );
if ($keypair_ressource = openssl_pkey_new($config)) { if ($keypair_ressource = openssl_pkey_new($config)) {
$key_details = openssl_pkey_get_details($keypair_ressource); $key_details = openssl_pkey_get_details($keypair_ressource);
$pubKey = implode(array_slice( $pubKey = implode(array_slice(
array_filter( array_filter(
explode(PHP_EOL, $key_details['key']) explode(PHP_EOL, $key_details['key'])
), 1, -1) ), 1, -1)
); );
// Save public key and selector to redis // Save public key and selector to redis
try { try {
$redis->hSet('DKIM_PUB_KEYS', $domain, $pubKey); $redis->hSet('DKIM_PUB_KEYS', $domain, $pubKey);
$redis->hSet('DKIM_SELECTORS', $domain, $dkim_selector); $redis->hSet('DKIM_SELECTORS', $domain, $dkim_selector);
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
continue; continue;
} }
// Export private key and save private key to redis // Export private key and save private key to redis
openssl_pkey_export($keypair_ressource, $privKey); openssl_pkey_export($keypair_ressource, $privKey);
if (isset($privKey) && !empty($privKey)) { if (isset($privKey) && !empty($privKey)) {
try { try {
$redis->hSet('DKIM_PRIV_KEYS', $dkim_selector . '.' . $domain, trim($privKey)); $redis->hSet('DKIM_PRIV_KEYS', $dkim_selector . '.' . $domain, trim($privKey));
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
continue; continue;
} }
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('dkim_added', $domain) 'msg' => array('dkim_added', $domain)
); );
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('dkim_domain_or_sel_invalid', $domain) 'msg' => array('dkim_domain_or_sel_invalid', $domain)
); );
continue; continue;
} }
} }
break; break;
case 'duplicate': case 'duplicate':
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$from_domain = $_data['from_domain']; $from_domain = $_data['from_domain'];
$from_domain_dkim = dkim('details', $from_domain, true); $from_domain_dkim = dkim('details', $from_domain, true);
if (empty($from_domain_dkim)) { if (empty($from_domain_dkim)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('dkim_domain_or_sel_invalid', $from_domain) 'msg' => array('dkim_domain_or_sel_invalid', $from_domain)
); );
continue; continue;
} }
$to_domains = (array)$_data['to_domain']; $to_domains = (array)$_data['to_domain'];
$to_domains = array_filter($to_domains); $to_domains = array_filter($to_domains);
foreach ($to_domains as $to_domain) { foreach ($to_domains as $to_domain) {
try { try {
$redis->hSet('DKIM_PUB_KEYS', $to_domain, $from_domain_dkim['pubkey']); $redis->hSet('DKIM_PUB_KEYS', $to_domain, $from_domain_dkim['pubkey']);
$redis->hSet('DKIM_SELECTORS', $to_domain, $from_domain_dkim['dkim_selector']); $redis->hSet('DKIM_SELECTORS', $to_domain, $from_domain_dkim['dkim_selector']);
$redis->hSet('DKIM_PRIV_KEYS', $from_domain_dkim['dkim_selector'] . '.' . $to_domain, base64_decode(trim($from_domain_dkim['privkey']))); $redis->hSet('DKIM_PRIV_KEYS', $from_domain_dkim['dkim_selector'] . '.' . $to_domain, base64_decode(trim($from_domain_dkim['privkey'])));
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
continue; continue;
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('dkim_duplicated', $from_domain, $to_domain) 'msg' => array('dkim_duplicated', $from_domain, $to_domain)
); );
} }
break; break;
case 'import': case 'import':
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$private_key_input = trim($_data['private_key_file']); $private_key_input = trim($_data['private_key_file']);
$overwrite_existing = intval($_data['overwrite_existing']); $overwrite_existing = intval($_data['overwrite_existing']);
$private_key_normalized = preg_replace('~\r\n?~', "\n", $private_key_input); $private_key_normalized = preg_replace('~\r\n?~', "\n", $private_key_input);
$private_key = openssl_pkey_get_private($private_key_normalized); $private_key = openssl_pkey_get_private($private_key_normalized);
if ($ssl_error = openssl_error_string()) { if ($ssl_error = openssl_error_string()) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('private_key_error', $ssl_error) 'msg' => array('private_key_error', $ssl_error)
); );
return false; return false;
} }
// Explode by nl // Explode by nl
$pem_public_key_array = explode(PHP_EOL, trim(openssl_pkey_get_details($private_key)['key'])); $pem_public_key_array = explode(PHP_EOL, trim(openssl_pkey_get_details($private_key)['key']));
// Remove first and last line/item // Remove first and last line/item
array_shift($pem_public_key_array); array_shift($pem_public_key_array);
array_pop($pem_public_key_array); array_pop($pem_public_key_array);
// Implode as single string // Implode as single string
$pem_public_key = implode('', (array)$pem_public_key_array); $pem_public_key = implode('', (array)$pem_public_key_array);
$dkim_selector = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : 'dkim'; $dkim_selector = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : 'dkim';
$domain = $_data['domain']; $domain = $_data['domain'];
if (!is_valid_domain_name($domain)) { if (!is_valid_domain_name($domain)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('dkim_domain_or_sel_invalid', $domain) 'msg' => array('dkim_domain_or_sel_invalid', $domain)
); );
return false; return false;
} }
if ($redis->hGet('DKIM_PUB_KEYS', $domain)) { if ($redis->hGet('DKIM_PUB_KEYS', $domain)) {
if ($overwrite_existing == 0) { if ($overwrite_existing == 0) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('dkim_domain_or_sel_exists', $domain) 'msg' => array('dkim_domain_or_sel_exists', $domain)
); );
return false; return false;
} }
} }
if (!ctype_alnum($dkim_selector)) { if (!ctype_alnum($dkim_selector)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('dkim_domain_or_sel_invalid', $domain) 'msg' => array('dkim_domain_or_sel_invalid', $domain)
); );
return false; return false;
} }
try { try {
dkim('delete', array('domains' => $domain)); dkim('delete', array('domains' => $domain));
$redis->hSet('DKIM_PUB_KEYS', $domain, $pem_public_key); $redis->hSet('DKIM_PUB_KEYS', $domain, $pem_public_key);
$redis->hSet('DKIM_SELECTORS', $domain, $dkim_selector); $redis->hSet('DKIM_SELECTORS', $domain, $dkim_selector);
$redis->hSet('DKIM_PRIV_KEYS', $dkim_selector . '.' . $domain, $private_key_normalized); $redis->hSet('DKIM_PRIV_KEYS', $dkim_selector . '.' . $domain, $private_key_normalized);
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
unset($private_key_normalized); unset($private_key_normalized);
unset($private_key); unset($private_key);
unset($private_key_input); unset($private_key_input);
try { try {
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('dkim_added', $domain) 'msg' => array('dkim_added', $domain)
); );
return true; return true;
break; break;
case 'details': case 'details':
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data) && $_SESSION['mailcow_cc_role'] != "admin") { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data) && $_SESSION['mailcow_cc_role'] != "admin") {
return false; return false;
} }
$dkimdata = array(); $dkimdata = array();
if ($redis_dkim_key_data = $redis->hGet('DKIM_PUB_KEYS', $_data)) { if ($redis_dkim_key_data = $redis->hGet('DKIM_PUB_KEYS', $_data)) {
$dkimdata['pubkey'] = $redis_dkim_key_data; $dkimdata['pubkey'] = $redis_dkim_key_data;
if (strlen($dkimdata['pubkey']) < 391) { if (strlen($dkimdata['pubkey']) < 391) {
$dkimdata['length'] = "1024"; $dkimdata['length'] = "1024";
} }
elseif (strlen($dkimdata['pubkey']) < 736) { elseif (strlen($dkimdata['pubkey']) < 736) {
$dkimdata['length'] = "2048"; $dkimdata['length'] = "2048";
} }
elseif (strlen($dkimdata['pubkey']) < 1416) { elseif (strlen($dkimdata['pubkey']) < 1416) {
$dkimdata['length'] = "4096"; $dkimdata['length'] = "4096";
} }
else { else {
$dkimdata['length'] = ">= 8192"; $dkimdata['length'] = ">= 8192";
} }
if ($GLOBALS['SPLIT_DKIM_255'] === true) { if ($GLOBALS['SPLIT_DKIM_255'] === true) {
$dkim_txt_tmp = str_split('v=DKIM1;k=rsa;t=s;s=email;p=' . $redis_dkim_key_data, 255); $dkim_txt_tmp = str_split('v=DKIM1;k=rsa;t=s;s=email;p=' . $redis_dkim_key_data, 255);
$dkimdata['dkim_txt'] = sprintf('"%s"', implode('" "', (array)$dkim_txt_tmp ) ); $dkimdata['dkim_txt'] = sprintf('"%s"', implode('" "', (array)$dkim_txt_tmp ) );
} }
else { else {
$dkimdata['dkim_txt'] = 'v=DKIM1;k=rsa;t=s;s=email;p=' . $redis_dkim_key_data; $dkimdata['dkim_txt'] = 'v=DKIM1;k=rsa;t=s;s=email;p=' . $redis_dkim_key_data;
} }
$dkimdata['dkim_selector'] = $redis->hGet('DKIM_SELECTORS', $_data); $dkimdata['dkim_selector'] = $redis->hGet('DKIM_SELECTORS', $_data);
if ($GLOBALS['SHOW_DKIM_PRIV_KEYS'] || $privkey == true) { if ($GLOBALS['SHOW_DKIM_PRIV_KEYS'] || $privkey == true) {
$dkimdata['privkey'] = base64_encode($redis->hGet('DKIM_PRIV_KEYS', $dkimdata['dkim_selector'] . '.' . $_data)); $dkimdata['privkey'] = base64_encode($redis->hGet('DKIM_PRIV_KEYS', $dkimdata['dkim_selector'] . '.' . $_data));
} }
else { else {
$dkimdata['privkey'] = ''; $dkimdata['privkey'] = '';
} }
} }
return $dkimdata; return $dkimdata;
break; break;
case 'blind': case 'blind':
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$blinddkim = array(); $blinddkim = array();
foreach ($redis->hKeys('DKIM_PUB_KEYS') as $redis_dkim_domain) { foreach ($redis->hKeys('DKIM_PUB_KEYS') as $redis_dkim_domain) {
$blinddkim[] = $redis_dkim_domain; $blinddkim[] = $redis_dkim_domain;
} }
return array_diff($blinddkim, array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'))); return array_diff($blinddkim, array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains')));
break; break;
case 'delete': case 'delete':
$domains = (array)$_data['domains']; $domains = (array)$_data['domains'];
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
foreach ($domains as $domain) { foreach ($domains as $domain) {
if (!is_valid_domain_name($domain)) { if (!is_valid_domain_name($domain)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('dkim_domain_or_sel_invalid', $domain) 'msg' => array('dkim_domain_or_sel_invalid', $domain)
); );
continue; continue;
} }
try { try {
$selector = $redis->hGet('DKIM_SELECTORS', $domain); $selector = $redis->hGet('DKIM_SELECTORS', $domain);
$redis->hDel('DKIM_PUB_KEYS', $domain); $redis->hDel('DKIM_PUB_KEYS', $domain);
$redis->hDel('DKIM_PRIV_KEYS', $selector . '.' . $domain); $redis->hDel('DKIM_PRIV_KEYS', $selector . '.' . $domain);
$redis->hDel('DKIM_SELECTORS', $domain); $redis->hDel('DKIM_SELECTORS', $domain);
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
continue; continue;
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => array('dkim_removed', htmlspecialchars($domain)) 'msg' => array('dkim_removed', htmlspecialchars($domain))
); );
} }
break; break;
} }
} }

View File

@ -1,196 +1,196 @@
<?php <?php
function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $extra_headers = null) { function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $extra_headers = null) {
global $DOCKER_TIMEOUT; global $DOCKER_TIMEOUT;
global $redis; global $redis;
$curl = curl_init(); $curl = curl_init();
curl_setopt($curl, CURLOPT_HTTPHEADER,array('Content-Type: application/json' )); curl_setopt($curl, CURLOPT_HTTPHEADER,array('Content-Type: application/json' ));
// We are using our mail certificates for dockerapi, the names will not match, the certs are trusted anyway // We are using our mail certificates for dockerapi, the names will not match, the certs are trusted anyway
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
switch($action) { switch($action) {
case 'get_id': case 'get_id':
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/json'); curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/json');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 0); curl_setopt($curl, CURLOPT_POST, 0);
curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT); curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT);
$response = curl_exec($curl); $response = curl_exec($curl);
if ($response === false) { if ($response === false) {
$err = curl_error($curl); $err = curl_error($curl);
curl_close($curl); curl_close($curl);
return $err; return $err;
} }
else { else {
curl_close($curl); curl_close($curl);
$containers = json_decode($response, true); $containers = json_decode($response, true);
if (!empty($containers)) { if (!empty($containers)) {
foreach ($containers as $container) { foreach ($containers as $container) {
if (isset($container['Config']['Labels']['com.docker.compose.service']) if (isset($container['Config']['Labels']['com.docker.compose.service'])
&& $container['Config']['Labels']['com.docker.compose.service'] == $service_name && $container['Config']['Labels']['com.docker.compose.service'] == $service_name
&& strtolower($container['Config']['Labels']['com.docker.compose.project']) == strtolower(getenv('COMPOSE_PROJECT_NAME'))) { && strtolower($container['Config']['Labels']['com.docker.compose.project']) == strtolower(getenv('COMPOSE_PROJECT_NAME'))) {
return trim($container['Id']); return trim($container['Id']);
} }
} }
} }
} }
return false; return false;
break; break;
case 'containers': case 'containers':
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/json'); curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/json');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 0); curl_setopt($curl, CURLOPT_POST, 0);
curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT); curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT);
$response = curl_exec($curl); $response = curl_exec($curl);
if ($response === false) { if ($response === false) {
$err = curl_error($curl); $err = curl_error($curl);
curl_close($curl); curl_close($curl);
return $err; return $err;
} }
else { else {
curl_close($curl); curl_close($curl);
$containers = json_decode($response, true); $containers = json_decode($response, true);
if (!empty($containers)) { if (!empty($containers)) {
foreach ($containers as $container) { foreach ($containers as $container) {
if (strtolower($container['Config']['Labels']['com.docker.compose.project']) == strtolower(getenv('COMPOSE_PROJECT_NAME'))) { if (strtolower($container['Config']['Labels']['com.docker.compose.project']) == strtolower(getenv('COMPOSE_PROJECT_NAME'))) {
$out[$container['Config']['Labels']['com.docker.compose.service']]['State'] = $container['State']; $out[$container['Config']['Labels']['com.docker.compose.service']]['State'] = $container['State'];
$out[$container['Config']['Labels']['com.docker.compose.service']]['Config'] = $container['Config']; $out[$container['Config']['Labels']['com.docker.compose.service']]['Config'] = $container['Config'];
$out[$container['Config']['Labels']['com.docker.compose.service']]['Id'] = trim($container['Id']); $out[$container['Config']['Labels']['com.docker.compose.service']]['Id'] = trim($container['Id']);
} }
} }
} }
return (!empty($out)) ? $out : false; return (!empty($out)) ? $out : false;
} }
return false; return false;
break; break;
case 'info': case 'info':
if (empty($service_name)) { if (empty($service_name)) {
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/json'); curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/json');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 0); curl_setopt($curl, CURLOPT_POST, 0);
curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT); curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT);
} }
else { else {
$container_id = docker('get_id', $service_name); $container_id = docker('get_id', $service_name);
if (ctype_xdigit($container_id)) { if (ctype_xdigit($container_id)) {
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/' . $container_id . '/json'); curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/' . $container_id . '/json');
} }
else { else {
return false; return false;
} }
} }
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 0); curl_setopt($curl, CURLOPT_POST, 0);
curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT); curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT);
$response = curl_exec($curl); $response = curl_exec($curl);
if ($response === false) { if ($response === false) {
$err = curl_error($curl); $err = curl_error($curl);
curl_close($curl); curl_close($curl);
return $err; return $err;
} }
else { else {
curl_close($curl); curl_close($curl);
$decoded_response = json_decode($response, true); $decoded_response = json_decode($response, true);
if (!empty($decoded_response)) { if (!empty($decoded_response)) {
if (empty($service_name)) { if (empty($service_name)) {
foreach ($decoded_response as $container) { foreach ($decoded_response as $container) {
if (isset($container['Config']['Labels']['com.docker.compose.project']) if (isset($container['Config']['Labels']['com.docker.compose.project'])
&& strtolower($container['Config']['Labels']['com.docker.compose.project']) == strtolower(getenv('COMPOSE_PROJECT_NAME'))) { && strtolower($container['Config']['Labels']['com.docker.compose.project']) == strtolower(getenv('COMPOSE_PROJECT_NAME'))) {
unset($container['Config']['Env']); unset($container['Config']['Env']);
$out[$container['Config']['Labels']['com.docker.compose.service']]['State'] = $container['State']; $out[$container['Config']['Labels']['com.docker.compose.service']]['State'] = $container['State'];
$out[$container['Config']['Labels']['com.docker.compose.service']]['Config'] = $container['Config']; $out[$container['Config']['Labels']['com.docker.compose.service']]['Config'] = $container['Config'];
$out[$container['Config']['Labels']['com.docker.compose.service']]['Id'] = trim($container['Id']); $out[$container['Config']['Labels']['com.docker.compose.service']]['Id'] = trim($container['Id']);
} }
} }
} }
else { else {
if (isset($decoded_response['Config']['Labels']['com.docker.compose.project']) if (isset($decoded_response['Config']['Labels']['com.docker.compose.project'])
&& strtolower($decoded_response['Config']['Labels']['com.docker.compose.project']) == strtolower(getenv('COMPOSE_PROJECT_NAME'))) { && strtolower($decoded_response['Config']['Labels']['com.docker.compose.project']) == strtolower(getenv('COMPOSE_PROJECT_NAME'))) {
unset($container['Config']['Env']); unset($container['Config']['Env']);
$out[$decoded_response['Config']['Labels']['com.docker.compose.service']]['State'] = $decoded_response['State']; $out[$decoded_response['Config']['Labels']['com.docker.compose.service']]['State'] = $decoded_response['State'];
$out[$decoded_response['Config']['Labels']['com.docker.compose.service']]['Config'] = $decoded_response['Config']; $out[$decoded_response['Config']['Labels']['com.docker.compose.service']]['Config'] = $decoded_response['Config'];
$out[$decoded_response['Config']['Labels']['com.docker.compose.service']]['Id'] = trim($decoded_response['Id']); $out[$decoded_response['Config']['Labels']['com.docker.compose.service']]['Id'] = trim($decoded_response['Id']);
} }
} }
} }
if (empty($response)) { if (empty($response)) {
return true; return true;
} }
else { else {
return (!empty($out)) ? $out : false; return (!empty($out)) ? $out : false;
} }
} }
break; break;
case 'post': case 'post':
if (!empty($attr1)) { if (!empty($attr1)) {
$container_id = docker('get_id', $service_name); $container_id = docker('get_id', $service_name);
if (ctype_xdigit($container_id) && ctype_alnum($attr1)) { if (ctype_xdigit($container_id) && ctype_alnum($attr1)) {
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/' . $container_id . '/' . $attr1); curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/' . $container_id . '/' . $attr1);
curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT); curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT);
if (!empty($attr2)) { if (!empty($attr2)) {
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($attr2)); curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($attr2));
} }
if (!empty($extra_headers) && is_array($extra_headers)) { if (!empty($extra_headers) && is_array($extra_headers)) {
curl_setopt($curl, CURLOPT_HTTPHEADER, $extra_headers); curl_setopt($curl, CURLOPT_HTTPHEADER, $extra_headers);
} }
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($curl); $response = curl_exec($curl);
if ($response === false) { if ($response === false) {
$err = curl_error($curl); $err = curl_error($curl);
curl_close($curl); curl_close($curl);
return $err; return $err;
} }
else { else {
curl_close($curl); curl_close($curl);
if (empty($response)) { if (empty($response)) {
return true; return true;
} }
else { else {
return $response; return $response;
} }
} }
} }
} }
break; break;
case 'container_stats': case 'container_stats':
if (empty($service_name)){ if (empty($service_name)){
return false; return false;
} }
$container_id = $service_name; $container_id = $service_name;
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/container/' . $container_id . '/stats/update'); curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/container/' . $container_id . '/stats/update');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT); curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT);
$response = curl_exec($curl); $response = curl_exec($curl);
if ($response === false) { if ($response === false) {
$err = curl_error($curl); $err = curl_error($curl);
curl_close($curl); curl_close($curl);
return $err; return $err;
} }
else { else {
curl_close($curl); curl_close($curl);
$stats = json_decode($response, true); $stats = json_decode($response, true);
if (!empty($stats)) return $stats; if (!empty($stats)) return $stats;
} }
return false; return false;
break; break;
case 'host_stats': case 'host_stats':
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/host/stats'); curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/host/stats');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 0); curl_setopt($curl, CURLOPT_POST, 0);
curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT); curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT);
$response = curl_exec($curl); $response = curl_exec($curl);
if ($response === false) { if ($response === false) {
$err = curl_error($curl); $err = curl_error($curl);
curl_close($curl); curl_close($curl);
return $err; return $err;
} }
else { else {
curl_close($curl); curl_close($curl);
$stats = json_decode($response, true); $stats = json_decode($response, true);
if (!empty($stats)) return $stats; if (!empty($stats)) return $stats;
} }
return false; return false;
break; break;
} }
} }

View File

@ -1,333 +1,333 @@
<?php <?php
function fail2ban($_action, $_data = null) { function fail2ban($_action, $_data = null) {
global $redis; global $redis;
$_data_log = $_data; $_data_log = $_data;
switch ($_action) { switch ($_action) {
case 'get': case 'get':
$f2b_options = array(); $f2b_options = array();
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
return false; return false;
} }
try { try {
$f2b_options = json_decode($redis->Get('F2B_OPTIONS'), true); $f2b_options = json_decode($redis->Get('F2B_OPTIONS'), true);
$f2b_options['regex'] = json_decode($redis->Get('F2B_REGEX'), true); $f2b_options['regex'] = json_decode($redis->Get('F2B_REGEX'), true);
$wl = $redis->hGetAll('F2B_WHITELIST'); $wl = $redis->hGetAll('F2B_WHITELIST');
if (is_array($wl)) { if (is_array($wl)) {
foreach ($wl as $key => $value) { foreach ($wl as $key => $value) {
$tmp_wl_data[] = $key; $tmp_wl_data[] = $key;
} }
if (isset($tmp_wl_data)) { if (isset($tmp_wl_data)) {
natsort($tmp_wl_data); natsort($tmp_wl_data);
$f2b_options['whitelist'] = implode(PHP_EOL, (array)$tmp_wl_data); $f2b_options['whitelist'] = implode(PHP_EOL, (array)$tmp_wl_data);
} }
else { else {
$f2b_options['whitelist'] = ""; $f2b_options['whitelist'] = "";
} }
} }
else { else {
$f2b_options['whitelist'] = ""; $f2b_options['whitelist'] = "";
} }
$bl = $redis->hGetAll('F2B_BLACKLIST'); $bl = $redis->hGetAll('F2B_BLACKLIST');
if (is_array($bl)) { if (is_array($bl)) {
foreach ($bl as $key => $value) { foreach ($bl as $key => $value) {
$tmp_bl_data[] = $key; $tmp_bl_data[] = $key;
} }
if (isset($tmp_bl_data)) { if (isset($tmp_bl_data)) {
natsort($tmp_bl_data); natsort($tmp_bl_data);
$f2b_options['blacklist'] = implode(PHP_EOL, (array)$tmp_bl_data); $f2b_options['blacklist'] = implode(PHP_EOL, (array)$tmp_bl_data);
} }
else { else {
$f2b_options['blacklist'] = ""; $f2b_options['blacklist'] = "";
} }
} }
else { else {
$f2b_options['blacklist'] = ""; $f2b_options['blacklist'] = "";
} }
$pb = $redis->hGetAll('F2B_PERM_BANS'); $pb = $redis->hGetAll('F2B_PERM_BANS');
if (is_array($pb)) { if (is_array($pb)) {
foreach ($pb as $key => $value) { foreach ($pb as $key => $value) {
$f2b_options['perm_bans'][] = array( $f2b_options['perm_bans'][] = array(
'network'=>$key, 'network'=>$key,
'ip' => strtok($key,'/') 'ip' => strtok($key,'/')
); );
} }
} }
else { else {
$f2b_options['perm_bans'] = ""; $f2b_options['perm_bans'] = "";
} }
$active_bans = $redis->hGetAll('F2B_ACTIVE_BANS'); $active_bans = $redis->hGetAll('F2B_ACTIVE_BANS');
$queue_unban = $redis->hGetAll('F2B_QUEUE_UNBAN'); $queue_unban = $redis->hGetAll('F2B_QUEUE_UNBAN');
if (is_array($active_bans)) { if (is_array($active_bans)) {
foreach ($active_bans as $network => $banned_until) { foreach ($active_bans as $network => $banned_until) {
$queued_for_unban = (isset($queue_unban[$network]) && $queue_unban[$network] == 1) ? 1 : 0; $queued_for_unban = (isset($queue_unban[$network]) && $queue_unban[$network] == 1) ? 1 : 0;
$difference = $banned_until - time(); $difference = $banned_until - time();
$f2b_options['active_bans'][] = array( $f2b_options['active_bans'][] = array(
'queued_for_unban' => $queued_for_unban, 'queued_for_unban' => $queued_for_unban,
'network' => $network, 'network' => $network,
'ip' => strtok($network,'/'), 'ip' => strtok($network,'/'),
'banned_until' => sprintf('%02dh %02dm %02ds', ($difference/3600), ($difference/60%60), $difference%60) 'banned_until' => sprintf('%02dh %02dm %02ds', ($difference/3600), ($difference/60%60), $difference%60)
); );
} }
} }
else { else {
$f2b_options['active_bans'] = ""; $f2b_options['active_bans'] = "";
} }
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
return $f2b_options; return $f2b_options;
break; break;
case 'edit': case 'edit':
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
// Start to read actions, if any // Start to read actions, if any
if (isset($_data['action'])) { if (isset($_data['action'])) {
// Reset regex filters // Reset regex filters
if ($_data['action'] == "reset-regex") { if ($_data['action'] == "reset-regex") {
try { try {
$redis->Del('F2B_REGEX'); $redis->Del('F2B_REGEX');
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
// Rules will also be recreated on log events, but rules may seem empty for a second in the UI // Rules will also be recreated on log events, but rules may seem empty for a second in the UI
docker('post', 'netfilter-mailcow', 'restart'); docker('post', 'netfilter-mailcow', 'restart');
$fail_count = 0; $fail_count = 0;
$regex_result = json_decode($redis->Get('F2B_REGEX'), true); $regex_result = json_decode($redis->Get('F2B_REGEX'), true);
while (empty($regex_result) && $fail_count < 10) { while (empty($regex_result) && $fail_count < 10) {
$regex_result = json_decode($redis->Get('F2B_REGEX'), true); $regex_result = json_decode($redis->Get('F2B_REGEX'), true);
$fail_count++; $fail_count++;
sleep(1); sleep(1);
} }
if ($fail_count >= 10) { if ($fail_count >= 10) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('reset_f2b_regex') 'msg' => array('reset_f2b_regex')
); );
return false; return false;
} }
} }
elseif ($_data['action'] == "edit-regex") { elseif ($_data['action'] == "edit-regex") {
if (!empty($_data['regex'])) { if (!empty($_data['regex'])) {
$rule_id = 1; $rule_id = 1;
$regex_array = array(); $regex_array = array();
foreach($_data['regex'] as $regex) { foreach($_data['regex'] as $regex) {
$regex_array[$rule_id] = $regex; $regex_array[$rule_id] = $regex;
$rule_id++; $rule_id++;
} }
if (!empty($regex_array)) { if (!empty($regex_array)) {
$redis->Set('F2B_REGEX', json_encode($regex_array, JSON_UNESCAPED_SLASHES)); $redis->Set('F2B_REGEX', json_encode($regex_array, JSON_UNESCAPED_SLASHES));
} }
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('object_modified', htmlspecialchars($network)) 'msg' => array('object_modified', htmlspecialchars($network))
); );
return true; return true;
} }
// Start actions in dependency of network // Start actions in dependency of network
if (!empty($_data['network'])) { if (!empty($_data['network'])) {
$networks = (array)$_data['network']; $networks = (array)$_data['network'];
foreach ($networks as $network) { foreach ($networks as $network) {
// Unban network // Unban network
if ($_data['action'] == "unban") { if ($_data['action'] == "unban") {
if (valid_network($network)) { if (valid_network($network)) {
try { try {
$redis->hSet('F2B_QUEUE_UNBAN', $network, 1); $redis->hSet('F2B_QUEUE_UNBAN', $network, 1);
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
continue; continue;
} }
} }
} }
// Whitelist network // Whitelist network
elseif ($_data['action'] == "whitelist") { elseif ($_data['action'] == "whitelist") {
if (empty($network)) { continue; } if (empty($network)) { continue; }
if (valid_network($network)) { if (valid_network($network)) {
try { try {
$redis->hSet('F2B_WHITELIST', $network, 1); $redis->hSet('F2B_WHITELIST', $network, 1);
$redis->hDel('F2B_BLACKLIST', $network, 1); $redis->hDel('F2B_BLACKLIST', $network, 1);
$redis->hSet('F2B_QUEUE_UNBAN', $network, 1); $redis->hSet('F2B_QUEUE_UNBAN', $network, 1);
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
continue; continue;
} }
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('network_host_invalid', $network) 'msg' => array('network_host_invalid', $network)
); );
continue; continue;
} }
} }
// Blacklist network // Blacklist network
elseif ($_data['action'] == "blacklist") { elseif ($_data['action'] == "blacklist") {
if (empty($network)) { continue; } if (empty($network)) { continue; }
if (valid_network($network) && !in_array($network, array( if (valid_network($network) && !in_array($network, array(
'0.0.0.0', '0.0.0.0',
'0.0.0.0/0', '0.0.0.0/0',
getenv('IPV4_NETWORK') . '0/24', getenv('IPV4_NETWORK') . '0/24',
getenv('IPV4_NETWORK') . '0', getenv('IPV4_NETWORK') . '0',
getenv('IPV6_NETWORK') getenv('IPV6_NETWORK')
))) { ))) {
try { try {
$redis->hSet('F2B_BLACKLIST', $network, 1); $redis->hSet('F2B_BLACKLIST', $network, 1);
$redis->hDel('F2B_WHITELIST', $network, 1); $redis->hDel('F2B_WHITELIST', $network, 1);
//$response = docker('post', 'netfilter-mailcow', 'restart'); //$response = docker('post', 'netfilter-mailcow', 'restart');
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
continue; continue;
} }
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('network_host_invalid', $network) 'msg' => array('network_host_invalid', $network)
); );
continue; continue;
} }
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('object_modified', htmlspecialchars($network)) 'msg' => array('object_modified', htmlspecialchars($network))
); );
} }
return true; return true;
} }
} }
// Start default edit without specific action // Start default edit without specific action
$is_now = fail2ban('get'); $is_now = fail2ban('get');
if (!empty($is_now)) { if (!empty($is_now)) {
$ban_time = intval((isset($_data['ban_time'])) ? $_data['ban_time'] : $is_now['ban_time']); $ban_time = intval((isset($_data['ban_time'])) ? $_data['ban_time'] : $is_now['ban_time']);
$ban_time_increment = (isset($_data['ban_time_increment']) && $_data['ban_time_increment'] == "1") ? 1 : 0; $ban_time_increment = (isset($_data['ban_time_increment']) && $_data['ban_time_increment'] == "1") ? 1 : 0;
$max_attempts = intval((isset($_data['max_attempts'])) ? $_data['max_attempts'] : $is_now['max_attempts']); $max_attempts = intval((isset($_data['max_attempts'])) ? $_data['max_attempts'] : $is_now['max_attempts']);
$max_ban_time = intval((isset($_data['max_ban_time'])) ? $_data['max_ban_time'] : $is_now['max_ban_time']); $max_ban_time = intval((isset($_data['max_ban_time'])) ? $_data['max_ban_time'] : $is_now['max_ban_time']);
$retry_window = intval((isset($_data['retry_window'])) ? $_data['retry_window'] : $is_now['retry_window']); $retry_window = intval((isset($_data['retry_window'])) ? $_data['retry_window'] : $is_now['retry_window']);
$netban_ipv4 = intval((isset($_data['netban_ipv4'])) ? $_data['netban_ipv4'] : $is_now['netban_ipv4']); $netban_ipv4 = intval((isset($_data['netban_ipv4'])) ? $_data['netban_ipv4'] : $is_now['netban_ipv4']);
$netban_ipv6 = intval((isset($_data['netban_ipv6'])) ? $_data['netban_ipv6'] : $is_now['netban_ipv6']); $netban_ipv6 = intval((isset($_data['netban_ipv6'])) ? $_data['netban_ipv6'] : $is_now['netban_ipv6']);
$wl = (isset($_data['whitelist'])) ? $_data['whitelist'] : $is_now['whitelist']; $wl = (isset($_data['whitelist'])) ? $_data['whitelist'] : $is_now['whitelist'];
$bl = (isset($_data['blacklist'])) ? $_data['blacklist'] : $is_now['blacklist']; $bl = (isset($_data['blacklist'])) ? $_data['blacklist'] : $is_now['blacklist'];
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$f2b_options = array(); $f2b_options = array();
$f2b_options['ban_time'] = ($ban_time < 60) ? 60 : $ban_time; $f2b_options['ban_time'] = ($ban_time < 60) ? 60 : $ban_time;
$f2b_options['ban_time_increment'] = ($ban_time_increment == 1) ? true : false; $f2b_options['ban_time_increment'] = ($ban_time_increment == 1) ? true : false;
$f2b_options['max_ban_time'] = ($max_ban_time < 60) ? 60 : $max_ban_time; $f2b_options['max_ban_time'] = ($max_ban_time < 60) ? 60 : $max_ban_time;
$f2b_options['netban_ipv4'] = ($netban_ipv4 < 8) ? 8 : $netban_ipv4; $f2b_options['netban_ipv4'] = ($netban_ipv4 < 8) ? 8 : $netban_ipv4;
$f2b_options['netban_ipv6'] = ($netban_ipv6 < 8) ? 8 : $netban_ipv6; $f2b_options['netban_ipv6'] = ($netban_ipv6 < 8) ? 8 : $netban_ipv6;
$f2b_options['netban_ipv4'] = ($netban_ipv4 > 32) ? 32 : $netban_ipv4; $f2b_options['netban_ipv4'] = ($netban_ipv4 > 32) ? 32 : $netban_ipv4;
$f2b_options['netban_ipv6'] = ($netban_ipv6 > 128) ? 128 : $netban_ipv6; $f2b_options['netban_ipv6'] = ($netban_ipv6 > 128) ? 128 : $netban_ipv6;
$f2b_options['max_attempts'] = ($max_attempts < 1) ? 1 : $max_attempts; $f2b_options['max_attempts'] = ($max_attempts < 1) ? 1 : $max_attempts;
$f2b_options['retry_window'] = ($retry_window < 1) ? 1 : $retry_window; $f2b_options['retry_window'] = ($retry_window < 1) ? 1 : $retry_window;
try { try {
$redis->Set('F2B_OPTIONS', json_encode($f2b_options)); $redis->Set('F2B_OPTIONS', json_encode($f2b_options));
$redis->Del('F2B_WHITELIST'); $redis->Del('F2B_WHITELIST');
$redis->Del('F2B_BLACKLIST'); $redis->Del('F2B_BLACKLIST');
if(!empty($wl)) { if(!empty($wl)) {
$wl_array = array_map('trim', preg_split( "/( |,|;|\n)/", $wl)); $wl_array = array_map('trim', preg_split( "/( |,|;|\n)/", $wl));
$wl_array = array_filter($wl_array); $wl_array = array_filter($wl_array);
if (is_array($wl_array)) { if (is_array($wl_array)) {
foreach ($wl_array as $wl_item) { foreach ($wl_array as $wl_item) {
if (valid_network($wl_item) || valid_hostname($wl_item)) { if (valid_network($wl_item) || valid_hostname($wl_item)) {
$redis->hSet('F2B_WHITELIST', $wl_item, 1); $redis->hSet('F2B_WHITELIST', $wl_item, 1);
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('network_host_invalid', $wl_item) 'msg' => array('network_host_invalid', $wl_item)
); );
continue; continue;
} }
} }
} }
} }
if(!empty($bl)) { if(!empty($bl)) {
$bl_array = array_map('trim', preg_split( "/( |,|;|\n)/", $bl)); $bl_array = array_map('trim', preg_split( "/( |,|;|\n)/", $bl));
$bl_array = array_filter($bl_array); $bl_array = array_filter($bl_array);
if (is_array($bl_array)) { if (is_array($bl_array)) {
foreach ($bl_array as $bl_item) { foreach ($bl_array as $bl_item) {
if (valid_network($bl_item) && !in_array($bl_item, array( if (valid_network($bl_item) && !in_array($bl_item, array(
'0.0.0.0', '0.0.0.0',
'0.0.0.0/0', '0.0.0.0/0',
getenv('IPV4_NETWORK') . '0/24', getenv('IPV4_NETWORK') . '0/24',
getenv('IPV4_NETWORK') . '0', getenv('IPV4_NETWORK') . '0',
getenv('IPV6_NETWORK') getenv('IPV6_NETWORK')
))) { ))) {
$redis->hSet('F2B_BLACKLIST', $bl_item, 1); $redis->hSet('F2B_BLACKLIST', $bl_item, 1);
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('network_host_invalid', $bl_item) 'msg' => array('network_host_invalid', $bl_item)
); );
continue; continue;
} }
} }
} }
} }
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'f2b_modified' 'msg' => 'f2b_modified'
); );
break; break;
} }
} }

View File

@ -1,183 +1,183 @@
<?php <?php
function fwdhost($_action, $_data = null) { function fwdhost($_action, $_data = null) {
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/spf.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/spf.inc.php';
global $redis; global $redis;
global $lang; global $lang;
$_data_log = $_data; $_data_log = $_data;
switch ($_action) { switch ($_action) {
case 'add': case 'add':
global $lang; global $lang;
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$source = $_data['hostname']; $source = $_data['hostname'];
$host = trim($_data['hostname']); $host = trim($_data['hostname']);
$filter_spam = (isset($_data['filter_spam']) && $_data['filter_spam'] == 1) ? 1 : 0; $filter_spam = (isset($_data['filter_spam']) && $_data['filter_spam'] == 1) ? 1 : 0;
if (preg_match('/^[0-9a-fA-F:\/]+$/', $host)) { // IPv6 address if (preg_match('/^[0-9a-fA-F:\/]+$/', $host)) { // IPv6 address
$hosts = array($host); $hosts = array($host);
} }
elseif (preg_match('/^[0-9\.\/]+$/', $host)) { // IPv4 address elseif (preg_match('/^[0-9\.\/]+$/', $host)) { // IPv4 address
$hosts = array($host); $hosts = array($host);
} }
else { else {
$hosts = get_outgoing_hosts_best_guess($host); $hosts = get_outgoing_hosts_best_guess($host);
} }
if (empty($hosts)) { if (empty($hosts)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('invalid_host', htmlspecialchars($host)) 'msg' => array('invalid_host', htmlspecialchars($host))
); );
return false; return false;
} }
foreach ($hosts as $host) { foreach ($hosts as $host) {
try { try {
$redis->hSet('WHITELISTED_FWD_HOST', $host, $source); $redis->hSet('WHITELISTED_FWD_HOST', $host, $source);
if ($filter_spam == 0) { if ($filter_spam == 0) {
$redis->hSet('KEEP_SPAM', $host, 1); $redis->hSet('KEEP_SPAM', $host, 1);
} }
elseif ($redis->hGet('KEEP_SPAM', $host)) { elseif ($redis->hGet('KEEP_SPAM', $host)) {
$redis->hDel('KEEP_SPAM', $host); $redis->hDel('KEEP_SPAM', $host);
} }
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('forwarding_host_added', htmlspecialchars(implode(', ', (array)$hosts))) 'msg' => array('forwarding_host_added', htmlspecialchars(implode(', ', (array)$hosts)))
); );
break; break;
case 'edit': case 'edit':
global $lang; global $lang;
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$fwdhosts = (array)$_data['fwdhost']; $fwdhosts = (array)$_data['fwdhost'];
foreach ($fwdhosts as $fwdhost) { foreach ($fwdhosts as $fwdhost) {
$is_now = fwdhost('details', $fwdhost); $is_now = fwdhost('details', $fwdhost);
if (!empty($is_now)) { if (!empty($is_now)) {
$keep_spam = (isset($_data['keep_spam'])) ? $_data['keep_spam'] : $is_now['keep_spam']; $keep_spam = (isset($_data['keep_spam'])) ? $_data['keep_spam'] : $is_now['keep_spam'];
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
continue; continue;
} }
try { try {
if ($keep_spam == 1) { if ($keep_spam == 1) {
$redis->hSet('KEEP_SPAM', $fwdhost, 1); $redis->hSet('KEEP_SPAM', $fwdhost, 1);
} }
else { else {
$redis->hDel('KEEP_SPAM', $fwdhost); $redis->hDel('KEEP_SPAM', $fwdhost);
} }
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
continue; continue;
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('object_modified', htmlspecialchars($fwdhost)) 'msg' => array('object_modified', htmlspecialchars($fwdhost))
); );
} }
break; break;
case 'delete': case 'delete':
$hosts = (array)$_data['forwardinghost']; $hosts = (array)$_data['forwardinghost'];
foreach ($hosts as $host) { foreach ($hosts as $host) {
try { try {
$redis->hDel('WHITELISTED_FWD_HOST', $host); $redis->hDel('WHITELISTED_FWD_HOST', $host);
$redis->hDel('KEEP_SPAM', $host); $redis->hDel('KEEP_SPAM', $host);
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
continue; continue;
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('forwarding_host_removed', htmlspecialchars($host)) 'msg' => array('forwarding_host_removed', htmlspecialchars($host))
); );
} }
break; break;
case 'get': case 'get':
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
return false; return false;
} }
$fwdhostsdata = array(); $fwdhostsdata = array();
try { try {
$fwd_hosts = $redis->hGetAll('WHITELISTED_FWD_HOST'); $fwd_hosts = $redis->hGetAll('WHITELISTED_FWD_HOST');
if (!empty($fwd_hosts)) { if (!empty($fwd_hosts)) {
foreach ($fwd_hosts as $fwd_host => $source) { foreach ($fwd_hosts as $fwd_host => $source) {
$keep_spam = ($redis->hGet('KEEP_SPAM', $fwd_host)) ? "yes" : "no"; $keep_spam = ($redis->hGet('KEEP_SPAM', $fwd_host)) ? "yes" : "no";
$fwdhostsdata[] = array( $fwdhostsdata[] = array(
'host' => $fwd_host, 'host' => $fwd_host,
'source' => $source, 'source' => $source,
'keep_spam' => $keep_spam 'keep_spam' => $keep_spam
); );
} }
} }
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
return $fwdhostsdata; return $fwdhostsdata;
break; break;
case 'details': case 'details':
$fwdhostdetails = array(); $fwdhostdetails = array();
if (!isset($_data) || empty($_data)) { if (!isset($_data) || empty($_data)) {
return false; return false;
} }
try { try {
if ($source = $redis->hGet('WHITELISTED_FWD_HOST', $_data)) { if ($source = $redis->hGet('WHITELISTED_FWD_HOST', $_data)) {
$fwdhostdetails['host'] = $_data; $fwdhostdetails['host'] = $_data;
$fwdhostdetails['source'] = $source; $fwdhostdetails['source'] = $source;
$fwdhostdetails['keep_spam'] = ($redis->hGet('KEEP_SPAM', $_data)) ? "yes" : "no"; $fwdhostdetails['keep_spam'] = ($redis->hGet('KEEP_SPAM', $_data)) ? "yes" : "no";
} }
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
return $fwdhostdetails; return $fwdhostdetails;
break; break;
} }
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,121 +1,121 @@
<?php <?php
function mailq($_action, $_data = null) { function mailq($_action, $_data = null) {
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
function process_mailq_output($returned_output, $_action, $_data) { function process_mailq_output($returned_output, $_action, $_data) {
if ($returned_output !== NULL) { if ($returned_output !== NULL) {
if ($_action == 'cat') { if ($_action == 'cat') {
logger(array('return' => array( logger(array('return' => array(
array( array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => 'queue_cat_success' 'msg' => 'queue_cat_success'
) )
))); )));
return $returned_output; return $returned_output;
} }
else { else {
if (isset($returned_output['type']) && $returned_output['type'] == 'danger') { if (isset($returned_output['type']) && $returned_output['type'] == 'danger') {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => 'Error: ' . $returned_output['msg'] 'msg' => 'Error: ' . $returned_output['msg']
); );
} }
if (isset($returned_output['type']) && $returned_output['type'] == 'success') { if (isset($returned_output['type']) && $returned_output['type'] == 'success') {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => 'queue_command_success' 'msg' => 'queue_command_success'
); );
} }
} }
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => 'unknown' 'msg' => 'unknown'
); );
} }
} }
if ($_action == 'get') { if ($_action == 'get') {
$mailq_lines = docker('post', 'postfix-mailcow', 'exec', array('cmd' => 'mailq', 'task' => 'list')); $mailq_lines = docker('post', 'postfix-mailcow', 'exec', array('cmd' => 'mailq', 'task' => 'list'));
$lines = 0; $lines = 0;
// Hard limit to 10000 items // Hard limit to 10000 items
foreach (preg_split("/((\r?\n)|(\r\n?))/", $mailq_lines) as $mailq_item) if ($lines++ < 10000) { foreach (preg_split("/((\r?\n)|(\r\n?))/", $mailq_lines) as $mailq_item) if ($lines++ < 10000) {
if (empty($mailq_item) || $mailq_item == '1') { if (empty($mailq_item) || $mailq_item == '1') {
continue; continue;
} }
$mq_line = json_decode($mailq_item, true); $mq_line = json_decode($mailq_item, true);
if ($mq_line !== NULL) { if ($mq_line !== NULL) {
$rcpts = array(); $rcpts = array();
foreach ($mq_line['recipients'] as $rcpt) { foreach ($mq_line['recipients'] as $rcpt) {
if (isset($rcpt['delay_reason'])) { if (isset($rcpt['delay_reason'])) {
$rcpts[] = $rcpt['address'] . ' (' . $rcpt['delay_reason'] . ')'; $rcpts[] = $rcpt['address'] . ' (' . $rcpt['delay_reason'] . ')';
} }
else { else {
$rcpts[] = $rcpt['address']; $rcpts[] = $rcpt['address'];
} }
} }
if (!empty($rcpts)) { if (!empty($rcpts)) {
$mq_line['recipients'] = $rcpts; $mq_line['recipients'] = $rcpts;
} }
$line[] = $mq_line; $line[] = $mq_line;
} }
} }
if (!isset($line) || empty($line)) { if (!isset($line) || empty($line)) {
return '[]'; return '[]';
} }
else { else {
return json_encode($line); return json_encode($line);
} }
} }
elseif ($_action == 'delete') { elseif ($_action == 'delete') {
if (!is_array($_data['qid'])) { if (!is_array($_data['qid'])) {
$qids = array(); $qids = array();
$qids[] = $_data['qid']; $qids[] = $_data['qid'];
} }
else { else {
$qids = $_data['qid']; $qids = $_data['qid'];
} }
$docker_return = docker('post', 'postfix-mailcow', 'exec', array('cmd' => 'mailq', 'task' => 'delete', 'items' => $qids)); $docker_return = docker('post', 'postfix-mailcow', 'exec', array('cmd' => 'mailq', 'task' => 'delete', 'items' => $qids));
process_mailq_output(json_decode($docker_return, true), $_action, $_data); process_mailq_output(json_decode($docker_return, true), $_action, $_data);
} }
elseif ($_action == 'cat') { elseif ($_action == 'cat') {
if (!is_array($_data['qid'])) { if (!is_array($_data['qid'])) {
$qids = array(); $qids = array();
$qids[] = $_data['qid']; $qids[] = $_data['qid'];
} }
else { else {
$qids = $_data['qid']; $qids = $_data['qid'];
} }
$docker_return = docker('post', 'postfix-mailcow', 'exec', array('cmd' => 'mailq', 'task' => 'cat', 'items' => $qids)); $docker_return = docker('post', 'postfix-mailcow', 'exec', array('cmd' => 'mailq', 'task' => 'cat', 'items' => $qids));
return process_mailq_output($docker_return, $_action, $_data); return process_mailq_output($docker_return, $_action, $_data);
} }
elseif ($_action == 'edit') { elseif ($_action == 'edit') {
if (in_array($_data['action'], array('hold', 'unhold', 'deliver'))) { if (in_array($_data['action'], array('hold', 'unhold', 'deliver'))) {
if (!is_array($_data['qid'])) { if (!is_array($_data['qid'])) {
$qids = array(); $qids = array();
$qids[] = $_data['qid']; $qids[] = $_data['qid'];
} }
else { else {
$qids = $_data['qid']; $qids = $_data['qid'];
} }
if (!empty($qids)) { if (!empty($qids)) {
$docker_return = docker('post', 'postfix-mailcow', 'exec', array('cmd' => 'mailq', 'task' => $_data['action'], 'items' => $qids)); $docker_return = docker('post', 'postfix-mailcow', 'exec', array('cmd' => 'mailq', 'task' => $_data['action'], 'items' => $qids));
process_mailq_output(json_decode($docker_return, true), $_action, $_data); process_mailq_output(json_decode($docker_return, true), $_action, $_data);
} }
} }
if (in_array($_data['action'], array('flush', 'super_delete'))) { if (in_array($_data['action'], array('flush', 'super_delete'))) {
$docker_return = docker('post', 'postfix-mailcow', 'exec', array('cmd' => 'mailq', 'task' => $_data['action'])); $docker_return = docker('post', 'postfix-mailcow', 'exec', array('cmd' => 'mailq', 'task' => $_data['action']));
process_mailq_output(json_decode($docker_return, true), $_action, $_data); process_mailq_output(json_decode($docker_return, true), $_action, $_data);
} }
} }
} }

View File

@ -1,242 +1,242 @@
<?php <?php
function oauth2($_action, $_type, $_data = null) { function oauth2($_action, $_type, $_data = null) {
global $pdo; global $pdo;
global $redis; global $redis;
global $lang; global $lang;
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data), 'log' => array(__FUNCTION__, $_action, $_type, $_data),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
switch ($_action) { switch ($_action) {
case 'add': case 'add':
switch ($_type) { switch ($_type) {
case 'client': case 'client':
$client_id = bin2hex(random_bytes(6)); $client_id = bin2hex(random_bytes(6));
$client_secret = bin2hex(random_bytes(12)); $client_secret = bin2hex(random_bytes(12));
$redirect_uri = $_data['redirect_uri']; $redirect_uri = $_data['redirect_uri'];
$scope = 'profile'; $scope = 'profile';
// For future use // For future use
// $grant_type = isset($_data['grant_type']) ? $_data['grant_type'] : 'authorization_code'; // $grant_type = isset($_data['grant_type']) ? $_data['grant_type'] : 'authorization_code';
// $scope = isset($_data['scope']) ? $_data['scope'] : 'profile'; // $scope = isset($_data['scope']) ? $_data['scope'] : 'profile';
// if ($grant_type != "authorization_code" && $grant_type != "password") { // if ($grant_type != "authorization_code" && $grant_type != "password") {
// $_SESSION['return'][] = array( // $_SESSION['return'][] = array(
// 'type' => 'danger', // 'type' => 'danger',
// 'log' => array(__FUNCTION__, $_action, $_type, $_data), // 'log' => array(__FUNCTION__, $_action, $_type, $_data),
// 'msg' => 'access_denied' // 'msg' => 'access_denied'
// ); // );
// return false; // return false;
// } // }
if ($scope != "profile") { if ($scope != "profile") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data), 'log' => array(__FUNCTION__, $_action, $_type, $_data),
'msg' => 'Invalid scope' 'msg' => 'Invalid scope'
); );
return false; return false;
} }
$stmt = $pdo->prepare("SELECT 'client' FROM `oauth_clients` $stmt = $pdo->prepare("SELECT 'client' FROM `oauth_clients`
WHERE `client_id` = :client_id"); WHERE `client_id` = :client_id");
$stmt->execute(array(':client_id' => $client_id)); $stmt->execute(array(':client_id' => $client_id));
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results != 0) { if ($num_results != 0) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data), 'log' => array(__FUNCTION__, $_action, $_type, $_data),
'msg' => 'Client ID exists' 'msg' => 'Client ID exists'
); );
return false; return false;
} }
$stmt = $pdo->prepare("INSERT INTO `oauth_clients` (`client_id`, `client_secret`, `redirect_uri`, `scope`) $stmt = $pdo->prepare("INSERT INTO `oauth_clients` (`client_id`, `client_secret`, `redirect_uri`, `scope`)
VALUES (:client_id, :client_secret, :redirect_uri, :scope)"); VALUES (:client_id, :client_secret, :redirect_uri, :scope)");
$stmt->execute(array( $stmt->execute(array(
':client_id' => $client_id, ':client_id' => $client_id,
':client_secret' => $client_secret, ':client_secret' => $client_secret,
':redirect_uri' => $redirect_uri, ':redirect_uri' => $redirect_uri,
':scope' => $scope ':scope' => $scope
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_type, $_data), 'log' => array(__FUNCTION__, $_action, $_type, $_data),
'msg' => 'Added client access' 'msg' => 'Added client access'
); );
break; break;
} }
break; break;
case 'edit': case 'edit':
switch ($_type) { switch ($_type) {
case 'client': case 'client':
$ids = (array)$_data['id']; $ids = (array)$_data['id'];
foreach ($ids as $id) { foreach ($ids as $id) {
$is_now = oauth2('details', 'client', $id); $is_now = oauth2('details', 'client', $id);
if (!empty($is_now)) { if (!empty($is_now)) {
$redirect_uri = (!empty($_data['redirect_uri'])) ? $_data['redirect_uri'] : $is_now['redirect_uri']; $redirect_uri = (!empty($_data['redirect_uri'])) ? $_data['redirect_uri'] : $is_now['redirect_uri'];
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data), 'log' => array(__FUNCTION__, $_action, $_type, $_data),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
if (isset($_data['revoke_tokens'])) { if (isset($_data['revoke_tokens'])) {
$stmt = $pdo->prepare("DELETE FROM `oauth_access_tokens` $stmt = $pdo->prepare("DELETE FROM `oauth_access_tokens`
WHERE `client_id` IN ( WHERE `client_id` IN (
SELECT `client_id` FROM `oauth_clients` WHERE `id` = :id SELECT `client_id` FROM `oauth_clients` WHERE `id` = :id
)"); )");
$stmt->execute(array( $stmt->execute(array(
':id' => $id ':id' => $id
)); ));
$stmt = $pdo->prepare("DELETE FROM `oauth_refresh_tokens` $stmt = $pdo->prepare("DELETE FROM `oauth_refresh_tokens`
WHERE `client_id` IN ( WHERE `client_id` IN (
SELECT `client_id` FROM `oauth_clients` WHERE `id` = :id SELECT `client_id` FROM `oauth_clients` WHERE `id` = :id
)"); )");
$stmt->execute(array( $stmt->execute(array(
':id' => $id ':id' => $id
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_type, $_data), 'log' => array(__FUNCTION__, $_action, $_type, $_data),
'msg' => array('object_modified', htmlspecialchars($id)) 'msg' => array('object_modified', htmlspecialchars($id))
); );
continue; continue;
} }
if (isset($_data['renew_secret'])) { if (isset($_data['renew_secret'])) {
$client_secret = bin2hex(random_bytes(12)); $client_secret = bin2hex(random_bytes(12));
$stmt = $pdo->prepare("UPDATE `oauth_clients` SET `client_secret` = :client_secret WHERE `id` = :id"); $stmt = $pdo->prepare("UPDATE `oauth_clients` SET `client_secret` = :client_secret WHERE `id` = :id");
$stmt->execute(array( $stmt->execute(array(
':client_secret' => $client_secret, ':client_secret' => $client_secret,
':id' => $id ':id' => $id
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_type, $_data), 'log' => array(__FUNCTION__, $_action, $_type, $_data),
'msg' => array('object_modified', htmlspecialchars($id)) 'msg' => array('object_modified', htmlspecialchars($id))
); );
continue; continue;
} }
if (empty($redirect_uri)) { if (empty($redirect_uri)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data), 'log' => array(__FUNCTION__, $_action, $_type, $_data),
'msg' => 'Redirect/Callback URL cannot be empty' 'msg' => 'Redirect/Callback URL cannot be empty'
); );
continue; continue;
} }
$stmt = $pdo->prepare("UPDATE `oauth_clients` SET $stmt = $pdo->prepare("UPDATE `oauth_clients` SET
`redirect_uri` = :redirect_uri `redirect_uri` = :redirect_uri
WHERE `id` = :id"); WHERE `id` = :id");
$stmt->execute(array( $stmt->execute(array(
':id' => $id, ':id' => $id,
':redirect_uri' => $redirect_uri ':redirect_uri' => $redirect_uri
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_type, $_data), 'log' => array(__FUNCTION__, $_action, $_type, $_data),
'msg' => array('object_modified', htmlspecialchars($id)) 'msg' => array('object_modified', htmlspecialchars($id))
); );
} }
break; break;
} }
break; break;
case 'delete': case 'delete':
switch ($_type) { switch ($_type) {
case 'client': case 'client':
(array)$ids = $_data['id']; (array)$ids = $_data['id'];
foreach ($ids as $id) { foreach ($ids as $id) {
if (!is_numeric($id)) { if (!is_numeric($id)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data), 'log' => array(__FUNCTION__, $_action, $_type, $_data),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
continue; continue;
} }
$stmt = $pdo->prepare("DELETE FROM `oauth_clients` $stmt = $pdo->prepare("DELETE FROM `oauth_clients`
WHERE `id` = :id"); WHERE `id` = :id");
$stmt->execute(array( $stmt->execute(array(
':id' => $id ':id' => $id
)); ));
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_type, $_data), 'log' => array(__FUNCTION__, $_action, $_type, $_data),
'msg' => array('items_deleted', htmlspecialchars($id)) 'msg' => array('items_deleted', htmlspecialchars($id))
); );
break; break;
case 'access_token': case 'access_token':
(array)$access_tokens = $_data['access_token']; (array)$access_tokens = $_data['access_token'];
foreach ($access_tokens as $access_token) { foreach ($access_tokens as $access_token) {
if (!ctype_alnum($access_token)) { if (!ctype_alnum($access_token)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data), 'log' => array(__FUNCTION__, $_action, $_type, $_data),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$stmt = $pdo->prepare("DELETE FROM `oauth_access_tokens` $stmt = $pdo->prepare("DELETE FROM `oauth_access_tokens`
WHERE `access_token` = :access_token"); WHERE `access_token` = :access_token");
$stmt->execute(array( $stmt->execute(array(
':access_token' => $access_token ':access_token' => $access_token
)); ));
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_type, $_data), 'log' => array(__FUNCTION__, $_action, $_type, $_data),
'msg' => sprintf($lang['success']['items_deleted'], implode(', ', (array)$access_tokens)) 'msg' => sprintf($lang['success']['items_deleted'], implode(', ', (array)$access_tokens))
); );
break; break;
case 'refresh_token': case 'refresh_token':
(array)$refresh_tokens = $_data['refresh_token']; (array)$refresh_tokens = $_data['refresh_token'];
foreach ($refresh_tokens as $refresh_token) { foreach ($refresh_tokens as $refresh_token) {
if (!ctype_alnum($refresh_token)) { if (!ctype_alnum($refresh_token)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data), 'log' => array(__FUNCTION__, $_action, $_type, $_data),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$stmt = $pdo->prepare("DELETE FROM `oauth_refresh_tokens` WHERE `refresh_token` = :refresh_token"); $stmt = $pdo->prepare("DELETE FROM `oauth_refresh_tokens` WHERE `refresh_token` = :refresh_token");
$stmt->execute(array( $stmt->execute(array(
':refresh_token' => $refresh_token ':refresh_token' => $refresh_token
)); ));
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_type, $_data), 'log' => array(__FUNCTION__, $_action, $_type, $_data),
'msg' => sprintf($lang['success']['items_deleted'], implode(', ', (array)$refresh_tokens)) 'msg' => sprintf($lang['success']['items_deleted'], implode(', ', (array)$refresh_tokens))
); );
break; break;
} }
break; break;
case 'get': case 'get':
switch ($_type) { switch ($_type) {
case 'clients': case 'clients':
$stmt = $pdo->query("SELECT `id` FROM `oauth_clients`"); $stmt = $pdo->query("SELECT `id` FROM `oauth_clients`");
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($rows)) { while ($row = array_shift($rows)) {
$oauth_clients[] = $row['id']; $oauth_clients[] = $row['id'];
} }
return $oauth_clients; return $oauth_clients;
break; break;
} }
break; break;
case 'details': case 'details':
switch ($_type) { switch ($_type) {
case 'client': case 'client':
$stmt = $pdo->prepare("SELECT * FROM `oauth_clients` $stmt = $pdo->prepare("SELECT * FROM `oauth_clients`
WHERE `id` = :id"); WHERE `id` = :id");
$stmt->execute(array(':id' => $_data)); $stmt->execute(array(':id' => $_data));
$oauth_client_details = $stmt->fetch(PDO::FETCH_ASSOC); $oauth_client_details = $stmt->fetch(PDO::FETCH_ASSOC);
return $oauth_client_details; return $oauth_client_details;
break; break;
} }
break; break;
} }
} }

View File

@ -1,320 +1,320 @@
<?php <?php
function policy($_action, $_scope, $_data = null) { function policy($_action, $_scope, $_data = null) {
global $pdo; global $pdo;
global $redis; global $redis;
global $lang; global $lang;
$_data_log = $_data; $_data_log = $_data;
switch ($_action) { switch ($_action) {
case 'add': case 'add':
if (!isset($_SESSION['acl']['spam_policy']) || $_SESSION['acl']['spam_policy'] != "1" ) { if (!isset($_SESSION['acl']['spam_policy']) || $_SESSION['acl']['spam_policy'] != "1" ) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
switch ($_scope) { switch ($_scope) {
case 'domain': case 'domain':
$object = $_data['domain']; $object = $_data['domain'];
if (is_valid_domain_name($object)) { if (is_valid_domain_name($object)) {
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$object = idn_to_ascii(strtolower(trim($object)), 0, INTL_IDNA_VARIANT_UTS46); $object = idn_to_ascii(strtolower(trim($object)), 0, INTL_IDNA_VARIANT_UTS46);
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
if ($_data['object_list'] == "bl") { if ($_data['object_list'] == "bl") {
$object_list = "blacklist_from"; $object_list = "blacklist_from";
} }
elseif ($_data['object_list'] == "wl") { elseif ($_data['object_list'] == "wl") {
$object_list = "whitelist_from"; $object_list = "whitelist_from";
} }
$object_from = trim(strtolower($_data['object_from'])); $object_from = trim(strtolower($_data['object_from']));
if (!ctype_alnum(str_replace(array('@', '_', '.', '-', '*'), '', $object_from))) { if (!ctype_alnum(str_replace(array('@', '_', '.', '-', '*'), '', $object_from))) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'policy_list_from_invalid' 'msg' => 'policy_list_from_invalid'
); );
return false; return false;
} }
if ($object_list != "blacklist_from" && $object_list != "whitelist_from") { if ($object_list != "blacklist_from" && $object_list != "whitelist_from") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$stmt = $pdo->prepare("SELECT `object` FROM `filterconf` $stmt = $pdo->prepare("SELECT `object` FROM `filterconf`
WHERE (`option` = 'whitelist_from' OR `option` = 'blacklist_from') WHERE (`option` = 'whitelist_from' OR `option` = 'blacklist_from')
AND `object` = :object AND `object` = :object
AND `value` = :object_from"); AND `value` = :object_from");
$stmt->execute(array(':object' => $object, ':object_from' => $object_from)); $stmt->execute(array(':object' => $object, ':object_from' => $object_from));
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results != 0) { if ($num_results != 0) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'policy_list_from_exists' 'msg' => 'policy_list_from_exists'
); );
return false; return false;
} }
$stmt = $pdo->prepare("INSERT INTO `filterconf` (`object`, `option` ,`value`) $stmt = $pdo->prepare("INSERT INTO `filterconf` (`object`, `option` ,`value`)
VALUES (:object, :object_list, :object_from)"); VALUES (:object, :object_list, :object_from)");
$stmt->execute(array( $stmt->execute(array(
':object' => $object, ':object' => $object,
':object_list' => $object_list, ':object_list' => $object_list,
':object_from' => $object_from ':object_from' => $object_from
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => array('domain_modified', $object) 'msg' => array('domain_modified', $object)
); );
break; break;
case 'mailbox': case 'mailbox':
$object = $_data['username']; $object = $_data['username'];
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
if ($_data['object_list'] == "bl") { if ($_data['object_list'] == "bl") {
$object_list = "blacklist_from"; $object_list = "blacklist_from";
} }
elseif ($_data['object_list'] == "wl") { elseif ($_data['object_list'] == "wl") {
$object_list = "whitelist_from"; $object_list = "whitelist_from";
} }
$object_from = trim(strtolower($_data['object_from'])); $object_from = trim(strtolower($_data['object_from']));
if (!ctype_alnum(str_replace(array('@', '_', '.', '-', '*'), '', $object_from))) { if (!ctype_alnum(str_replace(array('@', '_', '.', '-', '*'), '', $object_from))) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'policy_list_from_invalid' 'msg' => 'policy_list_from_invalid'
); );
return false; return false;
} }
if ($object_list != "blacklist_from" && $object_list != "whitelist_from") { if ($object_list != "blacklist_from" && $object_list != "whitelist_from") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$stmt = $pdo->prepare("SELECT `object` FROM `filterconf` $stmt = $pdo->prepare("SELECT `object` FROM `filterconf`
WHERE (`option` = 'whitelist_from' OR `option` = 'blacklist_from') WHERE (`option` = 'whitelist_from' OR `option` = 'blacklist_from')
AND `object` = :object AND `object` = :object
AND `value` = :object_from"); AND `value` = :object_from");
$stmt->execute(array(':object' => $object, ':object_from' => $object_from)); $stmt->execute(array(':object' => $object, ':object_from' => $object_from));
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results != 0) { if ($num_results != 0) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'policy_list_from_exists' 'msg' => 'policy_list_from_exists'
); );
return false; return false;
} }
$stmt = $pdo->prepare("INSERT INTO `filterconf` (`object`, `option` ,`value`) $stmt = $pdo->prepare("INSERT INTO `filterconf` (`object`, `option` ,`value`)
VALUES (:object, :object_list, :object_from)"); VALUES (:object, :object_list, :object_from)");
$stmt->execute(array( $stmt->execute(array(
':object' => $object, ':object' => $object,
':object_list' => $object_list, ':object_list' => $object_list,
':object_from' => $object_from ':object_from' => $object_from
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => array('mailbox_modified', $object) 'msg' => array('mailbox_modified', $object)
); );
break; break;
} }
break; break;
case 'delete': case 'delete':
if (!isset($_SESSION['acl']['spam_policy']) || $_SESSION['acl']['spam_policy'] != "1" ) { if (!isset($_SESSION['acl']['spam_policy']) || $_SESSION['acl']['spam_policy'] != "1" ) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
switch ($_scope) { switch ($_scope) {
case 'domain': case 'domain':
(array)$prefids = $_data['prefid']; (array)$prefids = $_data['prefid'];
foreach ($prefids as $prefid) { foreach ($prefids as $prefid) {
if (!is_numeric($prefid)) { if (!is_numeric($prefid)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
continue; continue;
} }
$stmt = $pdo->prepare("SELECT `object` FROM `filterconf` WHERE `prefid` = :prefid"); $stmt = $pdo->prepare("SELECT `object` FROM `filterconf` WHERE `prefid` = :prefid");
$stmt->execute(array(':prefid' => $prefid)); $stmt->execute(array(':prefid' => $prefid));
$object = $stmt->fetch(PDO::FETCH_ASSOC)['object']; $object = $stmt->fetch(PDO::FETCH_ASSOC)['object'];
if (is_valid_domain_name($object)) { if (is_valid_domain_name($object)) {
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
continue; continue;
} }
$object = idn_to_ascii(strtolower(trim($object)), 0, INTL_IDNA_VARIANT_UTS46); $object = idn_to_ascii(strtolower(trim($object)), 0, INTL_IDNA_VARIANT_UTS46);
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
continue; continue;
} }
try { try {
$stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :object AND `prefid` = :prefid"); $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :object AND `prefid` = :prefid");
$stmt->execute(array( $stmt->execute(array(
':object' => $object, ':object' => $object,
':prefid' => $prefid ':prefid' => $prefid
)); ));
} }
catch (PDOException $e) { catch (PDOException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => array('mysql_error', $e) 'msg' => array('mysql_error', $e)
); );
continue; continue;
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => array('item_deleted',$prefid) 'msg' => array('item_deleted',$prefid)
); );
} }
break; break;
case 'mailbox': case 'mailbox':
if (!is_array($_data['prefid'])) { if (!is_array($_data['prefid'])) {
$prefids = array(); $prefids = array();
$prefids[] = $_data['prefid']; $prefids[] = $_data['prefid'];
} }
else { else {
$prefids = $_data['prefid']; $prefids = $_data['prefid'];
} }
foreach ($prefids as $prefid) { foreach ($prefids as $prefid) {
if (!is_numeric($prefid)) { if (!is_numeric($prefid)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
continue; continue;
} }
$stmt = $pdo->prepare("SELECT `object` FROM `filterconf` WHERE `prefid` = :prefid"); $stmt = $pdo->prepare("SELECT `object` FROM `filterconf` WHERE `prefid` = :prefid");
$stmt->execute(array(':prefid' => $prefid)); $stmt->execute(array(':prefid' => $prefid));
$object = $stmt->fetch(PDO::FETCH_ASSOC)['object']; $object = $stmt->fetch(PDO::FETCH_ASSOC)['object'];
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
continue; continue;
} }
try { try {
$stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :object AND `prefid` = :prefid"); $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :object AND `prefid` = :prefid");
$stmt->execute(array( $stmt->execute(array(
':object' => $object, ':object' => $object,
':prefid' => $prefid ':prefid' => $prefid
)); ));
} }
catch (PDOException $e) { catch (PDOException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => array('mysql_error', $e) 'msg' => array('mysql_error', $e)
); );
continue; continue;
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => array('items_deleted', implode(', ', (array)$prefids)) 'msg' => array('items_deleted', implode(', ', (array)$prefids))
); );
} }
break; break;
} }
break; break;
case 'get': case 'get':
switch ($_scope) { switch ($_scope) {
case 'domain': case 'domain':
if (!is_valid_domain_name($_data)) { if (!is_valid_domain_name($_data)) {
return false; return false;
} }
else { else {
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
return false; return false;
} }
$_data = idn_to_ascii(strtolower(trim($_data)), 0, INTL_IDNA_VARIANT_UTS46); $_data = idn_to_ascii(strtolower(trim($_data)), 0, INTL_IDNA_VARIANT_UTS46);
} }
// WHITELIST // WHITELIST
$stmt = $pdo->prepare("SELECT `object`, `value`, `prefid` FROM `filterconf` WHERE `option`='whitelist_from' AND (`object` LIKE :object_mail OR `object` = :object_domain)"); $stmt = $pdo->prepare("SELECT `object`, `value`, `prefid` FROM `filterconf` WHERE `option`='whitelist_from' AND (`object` LIKE :object_mail OR `object` = :object_domain)");
$stmt->execute(array(':object_mail' => '%@' . $_data, ':object_domain' => $_data)); $stmt->execute(array(':object_mail' => '%@' . $_data, ':object_domain' => $_data));
$rows['whitelist'] = $stmt->fetchAll(PDO::FETCH_ASSOC); $rows['whitelist'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
// BLACKLIST // BLACKLIST
$stmt = $pdo->prepare("SELECT `object`, `value`, `prefid` FROM `filterconf` WHERE `option`='blacklist_from' AND (`object` LIKE :object_mail OR `object` = :object_domain)"); $stmt = $pdo->prepare("SELECT `object`, `value`, `prefid` FROM `filterconf` WHERE `option`='blacklist_from' AND (`object` LIKE :object_mail OR `object` = :object_domain)");
$stmt->execute(array(':object_mail' => '%@' . $_data, ':object_domain' => $_data)); $stmt->execute(array(':object_mail' => '%@' . $_data, ':object_domain' => $_data));
$rows['blacklist'] = $stmt->fetchAll(PDO::FETCH_ASSOC); $rows['blacklist'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $rows; return $rows;
break; break;
case 'mailbox': case 'mailbox':
if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) { if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
return false; return false;
} }
} }
else { else {
$_data = $_SESSION['mailcow_cc_username']; $_data = $_SESSION['mailcow_cc_username'];
} }
$domain = mailbox('get', 'mailbox_details', $_data)['domain']; $domain = mailbox('get', 'mailbox_details', $_data)['domain'];
if (empty($domain)) { if (empty($domain)) {
return false; return false;
} }
// WHITELIST // WHITELIST
$stmt = $pdo->prepare("SELECT `object`, `value`, `prefid` FROM `filterconf` WHERE `option`='whitelist_from' AND (`object` = :username OR `object` = :domain)"); $stmt = $pdo->prepare("SELECT `object`, `value`, `prefid` FROM `filterconf` WHERE `option`='whitelist_from' AND (`object` = :username OR `object` = :domain)");
$stmt->execute(array(':username' => $_data, ':domain' => $domain)); $stmt->execute(array(':username' => $_data, ':domain' => $domain));
$rows['whitelist'] = $stmt->fetchAll(PDO::FETCH_ASSOC); $rows['whitelist'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
// BLACKLIST // BLACKLIST
$stmt = $pdo->prepare("SELECT `object`, `value`, `prefid` FROM `filterconf` WHERE `option`='blacklist_from' AND (`object` = :username OR `object` = :domain)"); $stmt = $pdo->prepare("SELECT `object`, `value`, `prefid` FROM `filterconf` WHERE `option`='blacklist_from' AND (`object` = :username OR `object` = :domain)");
$stmt->execute(array(':username' => $_data, ':domain' => $domain)); $stmt->execute(array(':username' => $_data, ':domain' => $domain));
$rows['blacklist'] = $stmt->fetchAll(PDO::FETCH_ASSOC); $rows['blacklist'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $rows; return $rows;
break; break;
} }
break; break;
} }
} }

View File

@ -1,223 +1,223 @@
<?php <?php
function pushover($_action, $_data = null) { function pushover($_action, $_data = null) {
global $pdo; global $pdo;
switch ($_action) { switch ($_action) {
case 'edit': case 'edit':
if (!isset($_SESSION['acl']['pushover']) || $_SESSION['acl']['pushover'] != "1" ) { if (!isset($_SESSION['acl']['pushover']) || $_SESSION['acl']['pushover'] != "1" ) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
if (!is_array($_data['username'])) { if (!is_array($_data['username'])) {
$usernames = array(); $usernames = array();
$usernames[] = $_data['username']; $usernames[] = $_data['username'];
} }
else { else {
$usernames = $_data['username']; $usernames = $_data['username'];
} }
foreach ($usernames as $username) { foreach ($usernames as $username) {
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
continue; continue;
} }
$delete = $_data['delete']; $delete = $_data['delete'];
if ($delete == "true") { if ($delete == "true") {
$stmt = $pdo->prepare("DELETE FROM `pushover` WHERE `username` = :username"); $stmt = $pdo->prepare("DELETE FROM `pushover` WHERE `username` = :username");
$stmt->execute(array( $stmt->execute(array(
':username' => $username ':username' => $username
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => 'pushover_settings_edited' 'msg' => 'pushover_settings_edited'
); );
continue; continue;
} }
$is_now = pushover('get', $username); $is_now = pushover('get', $username);
if (!empty($is_now)) { if (!empty($is_now)) {
$key = (!empty($_data['key'])) ? $_data['key'] : $is_now['key']; $key = (!empty($_data['key'])) ? $_data['key'] : $is_now['key'];
$token = (!empty($_data['token'])) ? $_data['token'] : $is_now['token']; $token = (!empty($_data['token'])) ? $_data['token'] : $is_now['token'];
$senders = (isset($_data['senders'])) ? $_data['senders'] : $is_now['senders']; $senders = (isset($_data['senders'])) ? $_data['senders'] : $is_now['senders'];
$senders_regex = (isset($_data['senders_regex'])) ? $_data['senders_regex'] : $is_now['senders_regex']; $senders_regex = (isset($_data['senders_regex'])) ? $_data['senders_regex'] : $is_now['senders_regex'];
$title = (!empty($_data['title'])) ? $_data['title'] : $is_now['title']; $title = (!empty($_data['title'])) ? $_data['title'] : $is_now['title'];
$text = (!empty($_data['text'])) ? $_data['text'] : $is_now['text']; $text = (!empty($_data['text'])) ? $_data['text'] : $is_now['text'];
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active']; $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
$evaluate_x_prio = (isset($_data['evaluate_x_prio'])) ? intval($_data['evaluate_x_prio']) : $is_now['evaluate_x_prio']; $evaluate_x_prio = (isset($_data['evaluate_x_prio'])) ? intval($_data['evaluate_x_prio']) : $is_now['evaluate_x_prio'];
$only_x_prio = (isset($_data['only_x_prio'])) ? intval($_data['only_x_prio']) : $is_now['only_x_prio']; $only_x_prio = (isset($_data['only_x_prio'])) ? intval($_data['only_x_prio']) : $is_now['only_x_prio'];
$sound = (isset($_data['sound'])) ? $_data['sound'] : $is_now['sound']; $sound = (isset($_data['sound'])) ? $_data['sound'] : $is_now['sound'];
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
continue; continue;
} }
if (!empty($senders_regex) && !is_valid_regex($senders_regex)) { if (!empty($senders_regex) && !is_valid_regex($senders_regex)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => 'Invalid regex' 'msg' => 'Invalid regex'
); );
continue; continue;
} }
$senders = array_map('trim', preg_split( "/( |,|;|\n)/", $senders)); $senders = array_map('trim', preg_split( "/( |,|;|\n)/", $senders));
foreach ($senders as $i => &$sender) { foreach ($senders as $i => &$sender) {
if (empty($sender)) { if (empty($sender)) {
continue; continue;
} }
if (!filter_var($sender, FILTER_VALIDATE_EMAIL) === true) { if (!filter_var($sender, FILTER_VALIDATE_EMAIL) === true) {
unset($senders[$i]); unset($senders[$i]);
continue; continue;
} }
$senders[$i] = preg_replace('/\.(?=.*?@gmail\.com$)/', '$1', $sender); $senders[$i] = preg_replace('/\.(?=.*?@gmail\.com$)/', '$1', $sender);
} }
$senders = array_filter($senders); $senders = array_filter($senders);
if (empty($senders)) { $senders = ''; } if (empty($senders)) { $senders = ''; }
$senders = implode(",", (array)$senders); $senders = implode(",", (array)$senders);
if (!ctype_alnum($key) || strlen($key) != 30) { if (!ctype_alnum($key) || strlen($key) != 30) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_data), 'log' => array(__FUNCTION__, $_action, $_data, $_data),
'msg' => 'pushover_key' 'msg' => 'pushover_key'
); );
continue; continue;
} }
if (!ctype_alnum($token) || strlen($token) != 30) { if (!ctype_alnum($token) || strlen($token) != 30) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_data), 'log' => array(__FUNCTION__, $_action, $_data, $_data),
'msg' => 'pushover_token' 'msg' => 'pushover_token'
); );
continue; continue;
} }
$po_attributes = json_encode( $po_attributes = json_encode(
array( array(
'evaluate_x_prio' => strval(intval($evaluate_x_prio)), 'evaluate_x_prio' => strval(intval($evaluate_x_prio)),
'only_x_prio' => strval(intval($only_x_prio)), 'only_x_prio' => strval(intval($only_x_prio)),
'sound' => strval($sound) 'sound' => strval($sound)
) )
); );
$stmt = $pdo->prepare("REPLACE INTO `pushover` (`username`, `key`, `attributes`, `senders_regex`, `senders`, `token`, `title`, `text`, `active`) $stmt = $pdo->prepare("REPLACE INTO `pushover` (`username`, `key`, `attributes`, `senders_regex`, `senders`, `token`, `title`, `text`, `active`)
VALUES (:username, :key, :po_attributes, :senders_regex, :senders, :token, :title, :text, :active)"); VALUES (:username, :key, :po_attributes, :senders_regex, :senders, :token, :title, :text, :active)");
$stmt->execute(array( $stmt->execute(array(
':username' => $username, ':username' => $username,
':key' => $key, ':key' => $key,
':po_attributes' => $po_attributes, ':po_attributes' => $po_attributes,
':senders_regex' => $senders_regex, ':senders_regex' => $senders_regex,
':senders' => $senders, ':senders' => $senders,
':token' => $token, ':token' => $token,
':title' => $title, ':title' => $title,
':text' => $text, ':text' => $text,
':active' => $active ':active' => $active
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => 'pushover_settings_edited' 'msg' => 'pushover_settings_edited'
); );
} }
break; break;
case 'get': case 'get':
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$stmt = $pdo->prepare("SELECT * FROM `pushover` WHERE `username` = :username"); $stmt = $pdo->prepare("SELECT * FROM `pushover` WHERE `username` = :username");
$stmt->execute(array( $stmt->execute(array(
':username' => $_data ':username' => $_data
)); ));
$data = $stmt->fetch(PDO::FETCH_ASSOC); $data = $stmt->fetch(PDO::FETCH_ASSOC);
$data['attributes'] = json_decode($data['attributes'], true); $data['attributes'] = json_decode($data['attributes'], true);
if (empty($data)) { if (empty($data)) {
return false; return false;
} }
else { else {
return $data; return $data;
} }
break; break;
case 'test': case 'test':
if (!isset($_SESSION['acl']['pushover']) || $_SESSION['acl']['pushover'] != "1" ) { if (!isset($_SESSION['acl']['pushover']) || $_SESSION['acl']['pushover'] != "1" ) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
if (!is_array($_data['username'])) { if (!is_array($_data['username'])) {
$usernames = array(); $usernames = array();
$usernames[] = $_data['username']; $usernames[] = $_data['username'];
} }
else { else {
$usernames = $_data['username']; $usernames = $_data['username'];
} }
foreach ($usernames as $username) { foreach ($usernames as $username) {
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
continue; continue;
} }
$stmt = $pdo->prepare("SELECT * FROM `pushover` $stmt = $pdo->prepare("SELECT * FROM `pushover`
WHERE `username` = :username"); WHERE `username` = :username");
$stmt->execute(array( $stmt->execute(array(
':username' => $username ':username' => $username
)); ));
$api_data = $stmt->fetch(PDO::FETCH_ASSOC); $api_data = $stmt->fetch(PDO::FETCH_ASSOC);
if (!empty($api_data)) { if (!empty($api_data)) {
$title = (!empty($api_data['title'])) ? $api_data['title'] : 'Mail'; $title = (!empty($api_data['title'])) ? $api_data['title'] : 'Mail';
$text = (!empty($api_data['text'])) ? $api_data['text'] : 'You\'ve got mail 📧'; $text = (!empty($api_data['text'])) ? $api_data['text'] : 'You\'ve got mail 📧';
curl_setopt_array($ch = curl_init(), array( curl_setopt_array($ch = curl_init(), array(
CURLOPT_URL => "https://api.pushover.net/1/users/validate.json", CURLOPT_URL => "https://api.pushover.net/1/users/validate.json",
CURLOPT_POSTFIELDS => array( CURLOPT_POSTFIELDS => array(
"token" => $api_data['token'], "token" => $api_data['token'],
"user" => $api_data['key'] "user" => $api_data['key']
), ),
CURLOPT_SAFE_UPLOAD => true, CURLOPT_SAFE_UPLOAD => true,
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
)); ));
$result = curl_exec($ch); $result = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch); curl_close($ch);
if ($httpcode == 200) { if ($httpcode == 200) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => sprintf('Pushover API OK (%d): %s', $httpcode, $result) 'msg' => sprintf('Pushover API OK (%d): %s', $httpcode, $result)
); );
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => sprintf('Pushover API ERR (%d): %s', $httpcode, $result) 'msg' => sprintf('Pushover API ERR (%d): %s', $httpcode, $result)
); );
} }
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data), 'log' => array(__FUNCTION__, $_action, $_data),
'msg' => 'pushover_credentials_missing' 'msg' => 'pushover_credentials_missing'
); );
return false; return false;
} }
} }
break; break;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,150 +1,150 @@
<?php <?php
function quota_notification($_action, $_data = null) { function quota_notification($_action, $_data = null) {
global $redis; global $redis;
$_data_log = $_data; $_data_log = $_data;
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
switch ($_action) { switch ($_action) {
case 'edit': case 'edit':
$retention_size = $_data['retention_size']; $retention_size = $_data['retention_size'];
if ($_data['release_format'] == 'attachment' || $_data['release_format'] == 'raw') { if ($_data['release_format'] == 'attachment' || $_data['release_format'] == 'raw') {
$release_format = $_data['release_format']; $release_format = $_data['release_format'];
} }
else { else {
$release_format = 'raw'; $release_format = 'raw';
} }
$subject = $_data['subject']; $subject = $_data['subject'];
$sender = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $_data['sender']); $sender = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $_data['sender']);
if (filter_var($sender, FILTER_VALIDATE_EMAIL) === false) { if (filter_var($sender, FILTER_VALIDATE_EMAIL) === false) {
$sender = ''; $sender = '';
} }
$html = $_data['html_tmpl']; $html = $_data['html_tmpl'];
try { try {
$redis->Set('QW_SENDER', $sender); $redis->Set('QW_SENDER', $sender);
$redis->Set('QW_SUBJ', $subject); $redis->Set('QW_SUBJ', $subject);
$redis->Set('QW_HTML', $html); $redis->Set('QW_HTML', $html);
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'saved_settings' 'msg' => 'saved_settings'
); );
break; break;
case 'get': case 'get':
try { try {
$settings['subject'] = $redis->Get('QW_SUBJ'); $settings['subject'] = $redis->Get('QW_SUBJ');
$settings['sender'] = $redis->Get('QW_SENDER'); $settings['sender'] = $redis->Get('QW_SENDER');
$settings['html_tmpl'] = htmlspecialchars($redis->Get('QW_HTML')); $settings['html_tmpl'] = htmlspecialchars($redis->Get('QW_HTML'));
if (empty($settings['html_tmpl'])) { if (empty($settings['html_tmpl'])) {
$settings['html_tmpl'] = htmlspecialchars(file_get_contents("/tpls/quota.tpl")); $settings['html_tmpl'] = htmlspecialchars(file_get_contents("/tpls/quota.tpl"));
} }
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
return $settings; return $settings;
break; break;
} }
} }
function quota_notification_bcc($_action, $_data = null) { function quota_notification_bcc($_action, $_data = null) {
global $redis; global $redis;
$_data_log = $_data; $_data_log = $_data;
if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") { if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
switch ($_action) { switch ($_action) {
case 'edit': case 'edit':
$domain = $_data['domain']; $domain = $_data['domain'];
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$active = intval($_data['active']); $active = intval($_data['active']);
$bcc_rcpts = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['bcc_rcpt'])); $bcc_rcpts = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['bcc_rcpt']));
foreach ($bcc_rcpts as $i => &$rcpt) { foreach ($bcc_rcpts as $i => &$rcpt) {
$rcpt = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $rcpt); $rcpt = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $rcpt);
if (!empty($rcpt) && filter_var($rcpt, FILTER_VALIDATE_EMAIL) === false) { if (!empty($rcpt) && filter_var($rcpt, FILTER_VALIDATE_EMAIL) === false) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('goto_invalid', htmlspecialchars($rcpt)) 'msg' => array('goto_invalid', htmlspecialchars($rcpt))
); );
unset($bcc_rcpts[$i]); unset($bcc_rcpts[$i]);
continue; continue;
} }
} }
$bcc_rcpts = array_unique($bcc_rcpts); $bcc_rcpts = array_unique($bcc_rcpts);
$bcc_rcpts = array_filter($bcc_rcpts); $bcc_rcpts = array_filter($bcc_rcpts);
if (empty($bcc_rcpts)) { if (empty($bcc_rcpts)) {
$active = 0; $active = 0;
} }
try { try {
$redis->hSet('QW_BCC', $domain, json_encode(array('bcc_rcpts' => $bcc_rcpts, 'active' => $active))); $redis->hSet('QW_BCC', $domain, json_encode(array('bcc_rcpts' => $bcc_rcpts, 'active' => $active)));
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'saved_settings' 'msg' => 'saved_settings'
); );
break; break;
case 'get': case 'get':
$domain = $_data; $domain = $_data;
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
try { try {
return json_decode($redis->hGet('QW_BCC', $domain), true); return json_decode($redis->hGet('QW_BCC', $domain), true);
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
break; break;
} }
} }

View File

@ -1,242 +1,242 @@
<?php <?php
function ratelimit($_action, $_scope, $_data = null) { function ratelimit($_action, $_scope, $_data = null) {
global $redis; global $redis;
$_data_log = $_data; $_data_log = $_data;
switch ($_action) { switch ($_action) {
case 'edit': case 'edit':
if (!isset($_SESSION['acl']['ratelimit']) || $_SESSION['acl']['ratelimit'] != "1" ) { if (!isset($_SESSION['acl']['ratelimit']) || $_SESSION['acl']['ratelimit'] != "1" ) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
switch ($_scope) { switch ($_scope) {
case 'domain': case 'domain':
if (!is_array($_data['object'])) { if (!is_array($_data['object'])) {
$objects = array(); $objects = array();
$objects[] = $_data['object']; $objects[] = $_data['object'];
} }
else { else {
$objects = $_data['object']; $objects = $_data['object'];
} }
foreach ($objects as $object) { foreach ($objects as $object) {
$rl_value = intval($_data['rl_value']); $rl_value = intval($_data['rl_value']);
$rl_frame = $_data['rl_frame']; $rl_frame = $_data['rl_frame'];
if (!in_array($rl_frame, array('s', 'm', 'h', 'd'))) { if (!in_array($rl_frame, array('s', 'm', 'h', 'd'))) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'rl_timeframe' 'msg' => 'rl_timeframe'
); );
continue; continue;
} }
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
continue; continue;
} }
if (empty($rl_value)) { if (empty($rl_value)) {
try { try {
$redis->hDel('RL_VALUE', $object); $redis->hDel('RL_VALUE', $object);
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
continue; continue;
} }
} }
else { else {
try { try {
$redis->hSet('RL_VALUE', $object, $rl_value . ' / 1' . $rl_frame); $redis->hSet('RL_VALUE', $object, $rl_value . ' / 1' . $rl_frame);
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
continue; continue;
} }
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => array('rl_saved', $object) 'msg' => array('rl_saved', $object)
); );
} }
break; break;
case 'mailbox': case 'mailbox':
if (!is_array($_data['object'])) { if (!is_array($_data['object'])) {
$objects = array(); $objects = array();
$objects[] = $_data['object']; $objects[] = $_data['object'];
} }
else { else {
$objects = $_data['object']; $objects = $_data['object'];
} }
foreach ($objects as $object) { foreach ($objects as $object) {
$rl_value = intval($_data['rl_value']); $rl_value = intval($_data['rl_value']);
$rl_frame = $_data['rl_frame']; $rl_frame = $_data['rl_frame'];
if (!in_array($rl_frame, array('s', 'm', 'h', 'd'))) { if (!in_array($rl_frame, array('s', 'm', 'h', 'd'))) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'rl_timeframe' 'msg' => 'rl_timeframe'
); );
continue; continue;
} }
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object) if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)
|| ($_SESSION['mailcow_cc_role'] != 'admin' && $_SESSION['mailcow_cc_role'] != 'domainadmin')) { || ($_SESSION['mailcow_cc_role'] != 'admin' && $_SESSION['mailcow_cc_role'] != 'domainadmin')) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
continue; continue;
} }
if (empty($rl_value)) { if (empty($rl_value)) {
try { try {
$redis->hDel('RL_VALUE', $object); $redis->hDel('RL_VALUE', $object);
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
continue; continue;
} }
} }
else { else {
try { try {
$redis->hSet('RL_VALUE', $object, $rl_value . ' / 1' . $rl_frame); $redis->hSet('RL_VALUE', $object, $rl_value . ' / 1' . $rl_frame);
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
continue; continue;
} }
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => array('rl_saved', $object) 'msg' => array('rl_saved', $object)
); );
} }
break; break;
} }
break; break;
case 'get': case 'get':
switch ($_scope) { switch ($_scope) {
case 'domain': case 'domain':
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
return false; return false;
} }
try { try {
if ($rl_value = $redis->hGet('RL_VALUE', $_data)) { if ($rl_value = $redis->hGet('RL_VALUE', $_data)) {
$rl = explode(' / 1', $rl_value); $rl = explode(' / 1', $rl_value);
$data['value'] = $rl[0]; $data['value'] = $rl[0];
$data['frame'] = $rl[1]; $data['frame'] = $rl[1];
return $data; return $data;
} }
else { else {
return false; return false;
} }
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
return false; return false;
break; break;
case 'mailbox': case 'mailbox':
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data) if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)
|| ($_SESSION['mailcow_cc_role'] != 'admin' && $_SESSION['mailcow_cc_role'] != 'domainadmin')) { || ($_SESSION['mailcow_cc_role'] != 'admin' && $_SESSION['mailcow_cc_role'] != 'domainadmin')) {
return false; return false;
} }
try { try {
if ($rl_value = $redis->hGet('RL_VALUE', $_data)) { if ($rl_value = $redis->hGet('RL_VALUE', $_data)) {
$rl = explode(' / 1', $rl_value); $rl = explode(' / 1', $rl_value);
$data['value'] = $rl[0]; $data['value'] = $rl[0];
$data['frame'] = $rl[1]; $data['frame'] = $rl[1];
return $data; return $data;
} }
else { else {
return false; return false;
} }
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
return false; return false;
break; break;
} }
break; break;
case 'delete': case 'delete':
$data['hash'] = $_data; $data['hash'] = $_data;
if ($_SESSION['mailcow_cc_role'] != 'admin' || !preg_match('/^RL[0-9A-Za-z=]+$/i', trim($data['hash']))) { if ($_SESSION['mailcow_cc_role'] != 'admin' || !preg_match('/^RL[0-9A-Za-z=]+$/i', trim($data['hash']))) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
try { try {
$data_rllog = $redis->lRange('RL_LOG', 0, -1); $data_rllog = $redis->lRange('RL_LOG', 0, -1);
if ($data_rllog) { if ($data_rllog) {
foreach ($data_rllog as $json_line) { foreach ($data_rllog as $json_line) {
if (preg_match('/' . $data['hash'] . '/i', $json_line)) { if (preg_match('/' . $data['hash'] . '/i', $json_line)) {
$redis->lRem('RL_LOG', $json_line, 0); $redis->lRem('RL_LOG', $json_line, 0);
} }
} }
} }
if ($redis->type($data['hash']) == Redis::REDIS_HASH) { if ($redis->type($data['hash']) == Redis::REDIS_HASH) {
$redis->delete($data['hash']); $redis->delete($data['hash']);
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'hash_deleted' 'msg' => 'hash_deleted'
); );
return true; return true;
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'warning', 'type' => 'warning',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => 'hash_not_found' 'msg' => 'hash_not_found'
); );
return false; return false;
} }
} }
catch (RedisException $e) { catch (RedisException $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
'msg' => array('redis_error', $e) 'msg' => array('redis_error', $e)
); );
return false; return false;
} }
return false; return false;
break; break;
} }
} }

View File

@ -1,211 +1,211 @@
<?php <?php
function rsettings($_action, $_data = null) { function rsettings($_action, $_data = null) {
global $pdo; global $pdo;
global $lang; global $lang;
$_data_log = $_data; $_data_log = $_data;
switch ($_action) { switch ($_action) {
case 'add': case 'add':
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$content = $_data['content']; $content = $_data['content'];
$desc = $_data['desc']; $desc = $_data['desc'];
$active = intval($_data['active']); $active = intval($_data['active']);
if (empty($content)) { if (empty($content)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'map_content_empty' 'msg' => 'map_content_empty'
); );
return false; return false;
} }
$stmt = $pdo->prepare("INSERT INTO `settingsmap` (`content`, `desc`, `active`) $stmt = $pdo->prepare("INSERT INTO `settingsmap` (`content`, `desc`, `active`)
VALUES (:content, :desc, :active)"); VALUES (:content, :desc, :active)");
$stmt->execute(array( $stmt->execute(array(
':content' => $content, ':content' => $content,
':desc' => $desc, ':desc' => $desc,
':active' => $active ':active' => $active
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'settings_map_added' 'msg' => 'settings_map_added'
); );
break; break;
case 'edit': case 'edit':
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$ids = (array)$_data['id']; $ids = (array)$_data['id'];
foreach ($ids as $id) { foreach ($ids as $id) {
$is_now = rsettings('details', $id); $is_now = rsettings('details', $id);
if (!empty($is_now)) { if (!empty($is_now)) {
$content = (!empty($_data['content'])) ? $_data['content'] : $is_now['content']; $content = (!empty($_data['content'])) ? $_data['content'] : $is_now['content'];
$desc = (!empty($_data['desc'])) ? $_data['desc'] : $is_now['desc']; $desc = (!empty($_data['desc'])) ? $_data['desc'] : $is_now['desc'];
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active']; $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('settings_map_invalid', $id) 'msg' => array('settings_map_invalid', $id)
); );
continue; continue;
} }
$content = trim($content); $content = trim($content);
$stmt = $pdo->prepare("UPDATE `settingsmap` SET $stmt = $pdo->prepare("UPDATE `settingsmap` SET
`content` = :content, `content` = :content,
`desc` = :desc, `desc` = :desc,
`active` = :active `active` = :active
WHERE `id` = :id"); WHERE `id` = :id");
$stmt->execute(array( $stmt->execute(array(
':content' => $content, ':content' => $content,
':desc' => $desc, ':desc' => $desc,
':active' => $active, ':active' => $active,
':id' => $id ':id' => $id
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('object_modified', htmlspecialchars(implode(',', $ids))) 'msg' => array('object_modified', htmlspecialchars(implode(',', $ids)))
); );
} }
break; break;
case 'delete': case 'delete':
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$ids = (array)$_data['id']; $ids = (array)$_data['id'];
foreach ($ids as $id) { foreach ($ids as $id) {
$stmt = $pdo->prepare("DELETE FROM `settingsmap` WHERE `id`= :id"); $stmt = $pdo->prepare("DELETE FROM `settingsmap` WHERE `id`= :id");
$stmt->execute(array(':id' => $id)); $stmt->execute(array(':id' => $id));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data_log), 'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('settings_map_removed', htmlspecialchars($id)) 'msg' => array('settings_map_removed', htmlspecialchars($id))
); );
} }
break; break;
case 'get': case 'get':
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
return false; return false;
} }
$settingsmaps = array(); $settingsmaps = array();
$stmt = $pdo->query("SELECT `id`, `desc`, `active` FROM `settingsmap`"); $stmt = $pdo->query("SELECT `id`, `desc`, `active` FROM `settingsmap`");
$settingsmaps = $stmt->fetchAll(PDO::FETCH_ASSOC); $settingsmaps = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $settingsmaps; return $settingsmaps;
break; break;
case 'details': case 'details':
if ($_SESSION['mailcow_cc_role'] != "admin" || !isset($_data)) { if ($_SESSION['mailcow_cc_role'] != "admin" || !isset($_data)) {
return false; return false;
} }
$settingsmapdata = array(); $settingsmapdata = array();
$stmt = $pdo->prepare("SELECT `id`, $stmt = $pdo->prepare("SELECT `id`,
`desc`, `desc`,
`content`, `content`,
`active` `active`
FROM `settingsmap` FROM `settingsmap`
WHERE `id` = :id"); WHERE `id` = :id");
$stmt->execute(array(':id' => $_data)); $stmt->execute(array(':id' => $_data));
$settingsmapdata = $stmt->fetch(PDO::FETCH_ASSOC); $settingsmapdata = $stmt->fetch(PDO::FETCH_ASSOC);
return $settingsmapdata; return $settingsmapdata;
break; break;
} }
} }
function rspamd_maps($_action, $_data = null) { function rspamd_maps($_action, $_data = null) {
global $pdo; global $pdo;
global $lang; global $lang;
global $RSPAMD_MAPS; global $RSPAMD_MAPS;
$_data_log = $_data; $_data_log = $_data;
switch ($_action) { switch ($_action) {
case 'edit': case 'edit':
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, '-'), 'log' => array(__FUNCTION__, $_action, '-'),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
return false; return false;
} }
$maps = (array)$_data['map']; $maps = (array)$_data['map'];
foreach ($maps as $map) { foreach ($maps as $map) {
foreach ($RSPAMD_MAPS as $rspamd_map_type) { foreach ($RSPAMD_MAPS as $rspamd_map_type) {
if (!in_array($map, $rspamd_map_type)) { if (!in_array($map, $rspamd_map_type)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, '-'), 'log' => array(__FUNCTION__, $_action, '-'),
'msg' => array('global_map_invalid', $map) 'msg' => array('global_map_invalid', $map)
); );
continue; continue;
} }
} }
try { try {
if (file_exists('/rspamd_custom_maps/' . $map)) { if (file_exists('/rspamd_custom_maps/' . $map)) {
$map_content = trim($_data['rspamd_map_data']); $map_content = trim($_data['rspamd_map_data']);
$map_handle = fopen('/rspamd_custom_maps/' . $map, 'w'); $map_handle = fopen('/rspamd_custom_maps/' . $map, 'w');
if (!$map_handle) { if (!$map_handle) {
throw new Exception($lang['danger']['file_open_error']); throw new Exception($lang['danger']['file_open_error']);
} }
fwrite($map_handle, $map_content . PHP_EOL); fwrite($map_handle, $map_content . PHP_EOL);
fclose($map_handle); fclose($map_handle);
sleep(1.5); sleep(1.5);
touch('/rspamd_custom_maps/' . $map); touch('/rspamd_custom_maps/' . $map);
} }
} }
catch (Exception $e) { catch (Exception $e) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, '-'), 'log' => array(__FUNCTION__, $_action, '-'),
'msg' => array('global_map_write_error', htmlspecialchars($map), htmlspecialchars($e->getMessage())) 'msg' => array('global_map_write_error', htmlspecialchars($map), htmlspecialchars($e->getMessage()))
); );
continue; continue;
} }
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, '-'), 'log' => array(__FUNCTION__, $_action, '-'),
'msg' => array('object_modified', htmlspecialchars($map)) 'msg' => array('object_modified', htmlspecialchars($map))
); );
} }
break; break;
} }
} }
function rspamd_actions() { function rspamd_actions() {
if (isset($_SESSION["mailcow_cc_role"]) && $_SESSION["mailcow_cc_role"] == "admin") { if (isset($_SESSION["mailcow_cc_role"]) && $_SESSION["mailcow_cc_role"] == "admin") {
$curl = curl_init(); $curl = curl_init();
curl_setopt($curl, CURLOPT_UNIX_SOCKET_PATH, '/var/lib/rspamd/rspamd.sock'); curl_setopt($curl, CURLOPT_UNIX_SOCKET_PATH, '/var/lib/rspamd/rspamd.sock');
curl_setopt($curl, CURLOPT_URL,"http://rspamd/stat"); curl_setopt($curl, CURLOPT_URL,"http://rspamd/stat");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($curl); $data = curl_exec($curl);
if ($data) { if ($data) {
$return = array(); $return = array();
$stats_array = json_decode($data, true)['actions']; $stats_array = json_decode($data, true)['actions'];
$stats_array['soft reject'] = $stats_array['soft reject'] + $stats_array['greylist']; $stats_array['soft reject'] = $stats_array['soft reject'] + $stats_array['greylist'];
unset($stats_array['greylist']); unset($stats_array['greylist']);
foreach ($stats_array as $action => $count) { foreach ($stats_array as $action => $count) {
$return[] = array($action, $count); $return[] = array($action, $count);
} }
return $return; return $return;
} }
else { else {
return false; return false;
} }
} }
else { else {
return false; return false;
} }
} }

View File

@ -1,172 +1,172 @@
<?php <?php
function tls_policy_maps($_action, $_data = null, $attr = null) { function tls_policy_maps($_action, $_data = null, $attr = null) {
global $pdo; global $pdo;
global $lang; global $lang;
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
return false; return false;
} }
switch ($_action) { switch ($_action) {
case 'add': case 'add':
$dest = idn_to_ascii(trim($_data['dest']), 0, INTL_IDNA_VARIANT_UTS46); $dest = idn_to_ascii(trim($_data['dest']), 0, INTL_IDNA_VARIANT_UTS46);
$policy = strtolower(trim($_data['policy'])); $policy = strtolower(trim($_data['policy']));
$parameters = (isset($_data['parameters']) && !empty($_data['parameters'])) ? $_data['parameters'] : ''; $parameters = (isset($_data['parameters']) && !empty($_data['parameters'])) ? $_data['parameters'] : '';
if (empty($dest) || in_array($dest, array('.', '*', '@'))) { if (empty($dest) || in_array($dest, array('.', '*', '@'))) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'tls_policy_map_dest_invalid' 'msg' => 'tls_policy_map_dest_invalid'
); );
return false; return false;
} }
if (!empty($parameters)) { if (!empty($parameters)) {
foreach (explode(' ', $parameters) as $parameter) { foreach (explode(' ', $parameters) as $parameter) {
if (!preg_match('/(.+)\=(.+)/i', $parameter)) { if (!preg_match('/(.+)\=(.+)/i', $parameter)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'tls_policy_map_parameter_invalid' 'msg' => 'tls_policy_map_parameter_invalid'
); );
return false; return false;
} }
} }
} }
$active = intval($_data['active']); $active = intval($_data['active']);
$tls_policy_maps = tls_policy_maps('get'); $tls_policy_maps = tls_policy_maps('get');
foreach ($tls_policy_maps as $tls_policy_map) { foreach ($tls_policy_maps as $tls_policy_map) {
if (tls_policy_maps('details', $tls_policy_map)['dest'] == $dest) { if (tls_policy_maps('details', $tls_policy_map)['dest'] == $dest) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('tls_policy_map_entry_exists', htmlspecialchars($dest)) 'msg' => array('tls_policy_map_entry_exists', htmlspecialchars($dest))
); );
return false; return false;
} }
} }
$stmt = $pdo->prepare("INSERT INTO `tls_policy_override` (`dest`, `policy`, `parameters`, `active`) VALUES $stmt = $pdo->prepare("INSERT INTO `tls_policy_override` (`dest`, `policy`, `parameters`, `active`) VALUES
(:dest, :policy, :parameters, :active)"); (:dest, :policy, :parameters, :active)");
$stmt->execute(array( $stmt->execute(array(
':dest' => $dest, ':dest' => $dest,
':policy' => $policy, ':policy' => $policy,
':parameters' => $parameters, ':parameters' => $parameters,
':active' => $active ':active' => $active
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('tls_policy_map_entry_saved', htmlspecialchars($dest)) 'msg' => array('tls_policy_map_entry_saved', htmlspecialchars($dest))
); );
break; break;
case 'edit': case 'edit':
$ids = (array)$_data['id']; $ids = (array)$_data['id'];
foreach ($ids as $id) { foreach ($ids as $id) {
$is_now = tls_policy_maps('details', $id); $is_now = tls_policy_maps('details', $id);
if (!empty($is_now)) { if (!empty($is_now)) {
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active']; $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
$dest = (!empty($_data['dest'])) ? $_data['dest'] : $is_now['dest']; $dest = (!empty($_data['dest'])) ? $_data['dest'] : $is_now['dest'];
$policy = (!empty($_data['policy'])) ? $_data['policy'] : $is_now['policy']; $policy = (!empty($_data['policy'])) ? $_data['policy'] : $is_now['policy'];
$parameters = (isset($_data['parameters'])) ? $_data['parameters'] : $is_now['parameters']; $parameters = (isset($_data['parameters'])) ? $_data['parameters'] : $is_now['parameters'];
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'access_denied' 'msg' => 'access_denied'
); );
continue; continue;
} }
if (empty($dest) || in_array($dest, array('.', '*', '@'))) { if (empty($dest) || in_array($dest, array('.', '*', '@'))) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'tls_policy_map_dest_invalid' 'msg' => 'tls_policy_map_dest_invalid'
); );
return false; return false;
} }
if (!empty($parameters)) { if (!empty($parameters)) {
foreach (explode(' ', $parameters) as $parameter) { foreach (explode(' ', $parameters) as $parameter) {
if (!preg_match('/(.+)\=(.+)/i', $parameter)) { if (!preg_match('/(.+)\=(.+)/i', $parameter)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'tls_policy_map_parameter_invalid' 'msg' => 'tls_policy_map_parameter_invalid'
); );
return false; return false;
} }
} }
} }
$tls_policy_maps = tls_policy_maps('get'); $tls_policy_maps = tls_policy_maps('get');
foreach ($tls_policy_maps as $tls_policy_map) { foreach ($tls_policy_maps as $tls_policy_map) {
if ($tls_policy_map == $id) { continue; } if ($tls_policy_map == $id) { continue; }
if (tls_policy_maps('details', $tls_policy_map)['dest'] == $dest) { if (tls_policy_maps('details', $tls_policy_map)['dest'] == $dest) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('recipient_map_entry_exists', htmlspecialchars($dest)) 'msg' => array('recipient_map_entry_exists', htmlspecialchars($dest))
); );
return false; return false;
} }
} }
$stmt = $pdo->prepare("UPDATE `tls_policy_override` SET $stmt = $pdo->prepare("UPDATE `tls_policy_override` SET
`dest` = :dest, `dest` = :dest,
`policy` = :policy, `policy` = :policy,
`parameters` = :parameters, `parameters` = :parameters,
`active` = :active `active` = :active
WHERE `id`= :id"); WHERE `id`= :id");
$stmt->execute(array( $stmt->execute(array(
':dest' => $dest, ':dest' => $dest,
':policy' => $policy, ':policy' => $policy,
':parameters' => $parameters, ':parameters' => $parameters,
':active' => $active, ':active' => $active,
':id' => $id ':id' => $id
)); ));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('tls_policy_map_entry_saved', htmlspecialchars($dest)) 'msg' => array('tls_policy_map_entry_saved', htmlspecialchars($dest))
); );
} }
break; break;
case 'details': case 'details':
$mapdata = array(); $mapdata = array();
$id = intval($_data); $id = intval($_data);
$stmt = $pdo->prepare("SELECT `id`, $stmt = $pdo->prepare("SELECT `id`,
`dest`, `dest`,
`policy`, `policy`,
`parameters`, `parameters`,
`active` AS `active`, `active` AS `active`,
`created`, `created`,
`modified` FROM `tls_policy_override` `modified` FROM `tls_policy_override`
WHERE `id` = :id"); WHERE `id` = :id");
$stmt->execute(array(':id' => $id)); $stmt->execute(array(':id' => $id));
$mapdata = $stmt->fetch(PDO::FETCH_ASSOC); $mapdata = $stmt->fetch(PDO::FETCH_ASSOC);
return $mapdata; return $mapdata;
break; break;
case 'get': case 'get':
$mapdata = array(); $mapdata = array();
$all_items = array(); $all_items = array();
$id = intval($_data); $id = intval($_data);
$stmt = $pdo->query("SELECT `id` FROM `tls_policy_override`"); $stmt = $pdo->query("SELECT `id` FROM `tls_policy_override`");
$all_items = $stmt->fetchAll(PDO::FETCH_ASSOC); $all_items = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($all_items as $i) { foreach ($all_items as $i) {
$mapdata[] = $i['id']; $mapdata[] = $i['id'];
} }
$all_items = null; $all_items = null;
return $mapdata; return $mapdata;
break; break;
case 'delete': case 'delete':
$ids = (array)$_data['id']; $ids = (array)$_data['id'];
foreach ($ids as $id) { foreach ($ids as $id) {
if (!is_numeric($id)) { if (!is_numeric($id)) {
return false; return false;
} }
$stmt = $pdo->prepare("DELETE FROM `tls_policy_override` WHERE `id`= :id"); $stmt = $pdo->prepare("DELETE FROM `tls_policy_override` WHERE `id`= :id");
$stmt->execute(array(':id' => $id)); $stmt->execute(array(':id' => $id));
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'success', 'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data, $_attr), 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('tls_policy_map_entry_deleted', htmlspecialchars($id)) 'msg' => array('tls_policy_map_entry_deleted', htmlspecialchars($id))
); );
} }
break; break;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,31 +1,31 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIFZDCCA0ygAwIBAgIIYsLLTehAXpYwDQYJKoZIhvcNAQELBQAwUDELMAkGA1UE MIIFZDCCA0ygAwIBAgIIYsLLTehAXpYwDQYJKoZIhvcNAQELBQAwUDELMAkGA1UE
BhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEbMBkG BhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEbMBkG
A1UEAwwSSHVhd2VpIENCRyBSb290IENBMB4XDTE3MDgyMTEwNTYyN1oXDTQyMDgx A1UEAwwSSHVhd2VpIENCRyBSb290IENBMB4XDTE3MDgyMTEwNTYyN1oXDTQyMDgx
NTEwNTYyN1owUDELMAkGA1UEBhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UE NTEwNTYyN1owUDELMAkGA1UEBhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UE
CwwKSHVhd2VpIENCRzEbMBkGA1UEAwwSSHVhd2VpIENCRyBSb290IENBMIICIjAN CwwKSHVhd2VpIENCRzEbMBkGA1UEAwwSSHVhd2VpIENCRyBSb290IENBMIICIjAN
BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1OyKm3Ig/6eibB7Uz2o93UqGk2M7 BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1OyKm3Ig/6eibB7Uz2o93UqGk2M7
84WdfF8mvffvu218d61G5M3Px54E3kefUTk5Ky1ywHvw7Rp9KDuYv7ktaHkk+yr5 84WdfF8mvffvu218d61G5M3Px54E3kefUTk5Ky1ywHvw7Rp9KDuYv7ktaHkk+yr5
9Ihseu3a7iM/C6SnMSGt+LfB/Bcob9Abw95EigXQ4yQddX9hbNrin3AwZw8wMjEI 9Ihseu3a7iM/C6SnMSGt+LfB/Bcob9Abw95EigXQ4yQddX9hbNrin3AwZw8wMjEI
SYYDo5GuYDL0NbAiYg2Y5GpfYIqRzoi6GqDz+evLrsl20kJeCEPgJZN4Jg00Iq9k SYYDo5GuYDL0NbAiYg2Y5GpfYIqRzoi6GqDz+evLrsl20kJeCEPgJZN4Jg00Iq9k
++EKOZ5Jc/Zx22ZUgKpdwKABkvzshEgG6WWUPB+gosOiLv++inu/9blDpEzQZhjZ ++EKOZ5Jc/Zx22ZUgKpdwKABkvzshEgG6WWUPB+gosOiLv++inu/9blDpEzQZhjZ
9WVHpURHDK1YlCvubVAMhDpnbqNHZ0AxlPletdoyugrH/OLKl5inhMXNj3Re7Hl8 9WVHpURHDK1YlCvubVAMhDpnbqNHZ0AxlPletdoyugrH/OLKl5inhMXNj3Re7Hl8
WsBWLUKp6sXFf0dvSFzqnr2jkhicS+K2IYZnjghC9cOBRO8fnkonh0EBt0evjUIK WsBWLUKp6sXFf0dvSFzqnr2jkhicS+K2IYZnjghC9cOBRO8fnkonh0EBt0evjUIK
r5ClbCKioBX8JU+d4ldtWOpp2FlxeFTLreDJ5ZBU4//bQpTwYMt7gwMK+MO5Wtok r5ClbCKioBX8JU+d4ldtWOpp2FlxeFTLreDJ5ZBU4//bQpTwYMt7gwMK+MO5Wtok
Ux3UF98Z6GdUgbl6nBjBe82c7oIQXhHGHPnURQO7DDPgyVnNOnTPIkmiHJh/e3vk Ux3UF98Z6GdUgbl6nBjBe82c7oIQXhHGHPnURQO7DDPgyVnNOnTPIkmiHJh/e3vk
VhiZNHFCCLTip6GoJVrLxwb9i4q+d0thw4doxVJ5NB9OfDMV64/ybJgpf7m3Ld2y VhiZNHFCCLTip6GoJVrLxwb9i4q+d0thw4doxVJ5NB9OfDMV64/ybJgpf7m3Ld2y
E0gsf1prrRlDFDXjlYyqqpf1l9Y0u3ctXo7UpXMgbyDEpUQhq3a7txZQO/17luTD E0gsf1prrRlDFDXjlYyqqpf1l9Y0u3ctXo7UpXMgbyDEpUQhq3a7txZQO/17luTD
oA6Tz1ADavvBwHkCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF oA6Tz1ADavvBwHkCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
MAMBAf8wHQYDVR0OBBYEFKrE03lH6G4ja+/wqWwicz16GWmhMA0GCSqGSIb3DQEB MAMBAf8wHQYDVR0OBBYEFKrE03lH6G4ja+/wqWwicz16GWmhMA0GCSqGSIb3DQEB
CwUAA4ICAQC1d3TMB+VHZdGrWJbfaBShFNiCTN/MceSHOpzBn6JumQP4N7mxCOwd CwUAA4ICAQC1d3TMB+VHZdGrWJbfaBShFNiCTN/MceSHOpzBn6JumQP4N7mxCOwd
RSsGKQxV2NPH7LTXWNhUvUw5Sek96FWx/+Oa7jsj3WNAVtmS3zKpCQ5iGb08WIRO RSsGKQxV2NPH7LTXWNhUvUw5Sek96FWx/+Oa7jsj3WNAVtmS3zKpCQ5iGb08WIRO
cFnx3oUQ5rcO8r/lUk7Q2cN0E+rF4xsdQrH9k2cd3kAXZXBjfxfKPJTdPy1XnZR/ cFnx3oUQ5rcO8r/lUk7Q2cN0E+rF4xsdQrH9k2cd3kAXZXBjfxfKPJTdPy1XnZR/
h8H5EwEK5DWjSzK1wKd3G/Fxdm3E23pcr4FZgdYdOlFSiqW2TJ3Qe6lF4GOKOOyd h8H5EwEK5DWjSzK1wKd3G/Fxdm3E23pcr4FZgdYdOlFSiqW2TJ3Qe6lF4GOKOOyd
WHkpu54ieTsqoYcuMKnKMjT2SLNNgv9Gu5ipaG8Olz6g9C7Htp943lmK/1Vtnhgg WHkpu54ieTsqoYcuMKnKMjT2SLNNgv9Gu5ipaG8Olz6g9C7Htp943lmK/1Vtnhgg
pL3rDTsFX/+ehk7OtxuNzRMD9lXUtEfok7f8XB0dcL4ZjnEhDmp5QZqC1kMubHQt pL3rDTsFX/+ehk7OtxuNzRMD9lXUtEfok7f8XB0dcL4ZjnEhDmp5QZqC1kMubHQt
QnTauEiv0YkSGOwJAUZpK1PIff5GgxXYfaHfBC6Op4q02ppl5Q3URl7XIjYLjvs9 QnTauEiv0YkSGOwJAUZpK1PIff5GgxXYfaHfBC6Op4q02ppl5Q3URl7XIjYLjvs9
t4S9xPe8tb6416V2fe1dZ62vOXMMKHkZjVihh+IceYpJYHuyfKoYJyahLOQXZykG t4S9xPe8tb6416V2fe1dZ62vOXMMKHkZjVihh+IceYpJYHuyfKoYJyahLOQXZykG
K5iPAEEtq3HPfMVF43RKHOwfhrAH5KwelUA/0EkcR4Gzth1MKEqojdnYNemkkSy7 K5iPAEEtq3HPfMVF43RKHOwfhrAH5KwelUA/0EkcR4Gzth1MKEqojdnYNemkkSy7
aNPPT4LEm5R7sV6vG1CjwbgvQrWCgc4nMb8ngdfnVF7Ydqjqi9SAqUzIk4+Uf0ZY aNPPT4LEm5R7sV6vG1CjwbgvQrWCgc4nMb8ngdfnVF7Ydqjqi9SAqUzIk4+Uf0ZY
+6RY5IcHdCaiPaWIE1xURQ8B0DRUURsQwXdjZhgLN/DKJpCl5aCCxg== +6RY5IcHdCaiPaWIE1xURQ8B0DRUURsQwXdjZhgLN/DKJpCl5aCCxg==
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,12 +1,12 @@
A document without any HTML open/closing tags. A document without any HTML open/closing tags.
<hr> <hr>
We try and use the representation given by common browsers of the We try and use the representation given by common browsers of the
HTML document, so that it looks similar when converted to plain text. HTML document, so that it looks similar when converted to plain text.
<a href="http://foo.com">visit foo.com</a> - or <a href="http://www.foo.com">http://www.foo.com</a> <a href="http://foo.com">visit foo.com</a> - or <a href="http://www.foo.com">http://www.foo.com</a>
<a href="http://foo.com" title="a link with a title">link</a> <a href="http://foo.com" title="a link with a title">link</a>
<h2><a name="anchor">An anchor which will not appear</a></h2> <h2><a name="anchor">An anchor which will not appear</a></h2>

View File

@ -1,21 +1,21 @@
<html> <html>
<title>Ignored Title</title> <title>Ignored Title</title>
<body> <body>
<h1>Hello, World!</h1> <h1>Hello, World!</h1>
<p>This is some e-mail content. <p>This is some e-mail content.
Even though it has whitespace and newlines, the e-mail converter Even though it has whitespace and newlines, the e-mail converter
will handle it correctly. will handle it correctly.
<p>Even mismatched tags.</p> <p>Even mismatched tags.</p>
<div>A div</div> <div>A div</div>
<div>Another div</div> <div>Another div</div>
<div>A div<div>within a div</div></div> <div>A div<div>within a div</div></div>
<p>Another line<br />Yet another line</p> <p>Another line<br />Yet another line</p>
<a href="http://foo.com">A link</a> <a href="http://foo.com">A link</a>
</body> </body>
</html> </html>

View File

@ -1,53 +1,53 @@
<html> <html>
<title>Ignored Title</title> <title>Ignored Title</title>
<body> <body>
<h1>Hello, World!</h1> <h1>Hello, World!</h1>
<table> <table>
<thead> <thead>
<tr> <tr>
<th>Col A</th> <th>Col A</th>
<th>Col B</th> <th>Col B</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td> <td>
Data A1 Data A1
</td> </td>
<td> <td>
Data B1 Data B1
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
Data A2 Data A2
</td> </td>
<td> <td>
Data B2 Data B2
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
Data A3 Data A3
</td> </td>
<td> <td>
Data B4 Data B4
</td> </td>
</tr> </tr>
</tbody> </tbody>
<tfoot> <tfoot>
<tr> <tr>
<td> <td>
Total A Total A
</td> </td>
<td> <td>
Total B Total B
</td> </td>
</tr> </tr>
</tfoot> </tfoot>
</table> </table>
</body> </body>
</html> </html>

View File

@ -1,2 +1,2 @@
test one test one
test two test two

View File

@ -1,5 +1,5 @@
1 1
2 2
3 3
4 4
5 6 5 6

View File

@ -1,10 +1,10 @@
/*! /*!
* Form Cache v@VERSION * Form Cache v@VERSION
* https://github.com/fengyuanchen/formcache * https://github.com/fengyuanchen/formcache
* *
* Copyright 2014 Fengyuan Chen * Copyright 2014 Fengyuan Chen
* Released under the MIT license * Released under the MIT license
* *
* Date: @DATE * Date: @DATE
*/ */
!function(t){"function"==typeof define&&define.amd?define("formcache",["jquery"],t):t(jQuery)}(function(t){"use strict";var e=t(window),i=window.sessionStorage,s=window.localStorage,n="undefined",o=".formcache",a=/[\.\*\+\^\$\:\!\[\]#>~]+/g,c="change"+o,h="beforeunload"+o,r=function(t){return"checkbox"===t.type||"radio"===t.type},f=function(t){return parseInt(t,10)},u=function(e,i){this.form=e,this.$form=t(e),this.defaults=t.extend({},u.DEFAULTS,t.isPlainObject(i)?i:{}),this.init()};u.prototype={constructor:u,init:function(){var e=this.defaults;e.maxAge=Math.abs(e.maxAge||e.maxage),e.autoStore=Boolean(e.autoStore||e.autostore),this.initKey(),this.initStorage(),this.caches=this.storage.caches,this.index=0,this.activeIndex=0,this.storing=null,t.isArray(e.controls)||(e.controls=[]),this.$controls=this.$form.find(e.controls.join()).not(":file"),this.addListeners(),this.outputCache()},initKey:function(){var e=this.$form,i=this.defaults.key||e.data("key");i||(t("form").each(function(e){t(this).data("key",e)}),i=e.data("key")),this.key=location.pathname+"#formcache-"+i},initStorage:function(){var e,n=this.defaults,o=this.key,a=new Date,c={date:a,maxAge:n.maxAge,caches:[]};i&&(e=i.getItem(o)),!e&&s&&(e=s.getItem(o)),e="string"==typeof e?JSON.parse(e):null,t.isPlainObject(e)?"number"==typeof e.maxAge&&(a-new Date(e.date))/1e3>e.maxAge&&(e=c):e=c,this.storage=e},addListeners:function(){this.defaults.autoStore&&(this.$controls.on(c,t.proxy(this.change,this)),e.on(h,t.proxy(this.beforeunload,this)))},removeListeners:function(){this.defaults.autoStore&&(this.$controls.off(c,this.change),e.off(h,this.beforeunload))},change:function(e){var i,s,n=e.target,o=t(n),c=o.attr("name"),h=[];c&&(i=c.replace(a,""),this.$controls.filter('[name*="'+i+'"]').each(function(){r(n)?h.push(this.checked):(s=t(this).val(),s&&h.push(s))}),h.length&&(this.update(c,h),clearTimeout(this.storing),this.storing=setTimeout(t.proxy(this.store,this),1e3)))},beforeunload:function(){this.update(),this.store()},update:function(t,e){var i=this.activeIndex||this.index,s=this.getCache(i);"string"==typeof t?s[t]=e:s=this.serialize(),this.setCache(i,s)},serialize:function(){var e={};return this.$controls.each(function(){var i,s,n=t(this),o=n.attr("name");o&&(i=e[o],i=t.isArray(i)?i:[],r(this)?i.push(this.checked):(s=n.val(),s&&i.push(s)),i.length&&(e[o]=i))}),e},getCache:function(t){return this.caches[f(t)||this.index]||{}},getCaches:function(){return this.caches},setCache:function(e,i){typeof i===n&&(i=e,e=NaN),t.isPlainObject(i)&&(e=f(e)||this.index,this.caches[e]=i,this.store())},setCaches:function(e){t.isArray(e)&&(this.caches=e,this.store())},removeCache:function(t){this.caches.splice(f(t)||this.index,1),this.store()},removeCaches:function(){this.caches=[],this.store()},outputCache:function(e){var i=this.getCache(e);t.isPlainObject(i)&&(this.activeIndex=f(e)||this.index,i=t.extend(!0,{},i),this.$controls.each(function(){var e,s,n=t(this),o=n.attr("name");o&&(e=i[o],t.isArray(e)&&e.length&&(s=e.shift(),r(this)?this.checked=s:n.val(s)))}))},store:function(){var t=this.storage,e=this.key,n=this.defaults;t.date=new Date,t.maxAge=n.maxAge,t=JSON.stringify(t),n.session&&i&&i.setItem(e,t),n.local&&s&&s.setItem(e,t)},clear:function(){var t=this.key,e=this.defaults;e.session&&i&&i.removeItem(t),e.local&&s&&s.removeItem(t)},destroy:function(){this.removeListeners(),this.$form.removeData("formcache")}},u.DEFAULTS={key:"",local:!0,session:0,autoStore:!0,maxAge:void 0,controls:["select","textarea","input"]},u.setDefaults=function(e){t.extend(u.DEFAULTS,e)},u.other=t.fn.formcache,t.fn.formcache=function(e){var i,s=[].slice.call(arguments,1);return this.each(function(){var n,o=t(this),a=o.data("formcache");a||o.data("formcache",a=new u(this,e)),"string"==typeof e&&t.isFunction(n=a[e])&&(i=n.apply(a,s))}),typeof i!==n?i:this},t.fn.formcache.Constructor=u,t.fn.formcache.setDefaults=u.setDefaults,t.fn.formcache.noConflict=function(){return t.fn.formcache=u.other,this},t(function(){t('form[data-toggle="formcache"]').formcache()})}); !function(t){"function"==typeof define&&define.amd?define("formcache",["jquery"],t):t(jQuery)}(function(t){"use strict";var e=t(window),i=window.sessionStorage,s=window.localStorage,n="undefined",o=".formcache",a=/[\.\*\+\^\$\:\!\[\]#>~]+/g,c="change"+o,h="beforeunload"+o,r=function(t){return"checkbox"===t.type||"radio"===t.type},f=function(t){return parseInt(t,10)},u=function(e,i){this.form=e,this.$form=t(e),this.defaults=t.extend({},u.DEFAULTS,t.isPlainObject(i)?i:{}),this.init()};u.prototype={constructor:u,init:function(){var e=this.defaults;e.maxAge=Math.abs(e.maxAge||e.maxage),e.autoStore=Boolean(e.autoStore||e.autostore),this.initKey(),this.initStorage(),this.caches=this.storage.caches,this.index=0,this.activeIndex=0,this.storing=null,t.isArray(e.controls)||(e.controls=[]),this.$controls=this.$form.find(e.controls.join()).not(":file"),this.addListeners(),this.outputCache()},initKey:function(){var e=this.$form,i=this.defaults.key||e.data("key");i||(t("form").each(function(e){t(this).data("key",e)}),i=e.data("key")),this.key=location.pathname+"#formcache-"+i},initStorage:function(){var e,n=this.defaults,o=this.key,a=new Date,c={date:a,maxAge:n.maxAge,caches:[]};i&&(e=i.getItem(o)),!e&&s&&(e=s.getItem(o)),e="string"==typeof e?JSON.parse(e):null,t.isPlainObject(e)?"number"==typeof e.maxAge&&(a-new Date(e.date))/1e3>e.maxAge&&(e=c):e=c,this.storage=e},addListeners:function(){this.defaults.autoStore&&(this.$controls.on(c,t.proxy(this.change,this)),e.on(h,t.proxy(this.beforeunload,this)))},removeListeners:function(){this.defaults.autoStore&&(this.$controls.off(c,this.change),e.off(h,this.beforeunload))},change:function(e){var i,s,n=e.target,o=t(n),c=o.attr("name"),h=[];c&&(i=c.replace(a,""),this.$controls.filter('[name*="'+i+'"]').each(function(){r(n)?h.push(this.checked):(s=t(this).val(),s&&h.push(s))}),h.length&&(this.update(c,h),clearTimeout(this.storing),this.storing=setTimeout(t.proxy(this.store,this),1e3)))},beforeunload:function(){this.update(),this.store()},update:function(t,e){var i=this.activeIndex||this.index,s=this.getCache(i);"string"==typeof t?s[t]=e:s=this.serialize(),this.setCache(i,s)},serialize:function(){var e={};return this.$controls.each(function(){var i,s,n=t(this),o=n.attr("name");o&&(i=e[o],i=t.isArray(i)?i:[],r(this)?i.push(this.checked):(s=n.val(),s&&i.push(s)),i.length&&(e[o]=i))}),e},getCache:function(t){return this.caches[f(t)||this.index]||{}},getCaches:function(){return this.caches},setCache:function(e,i){typeof i===n&&(i=e,e=NaN),t.isPlainObject(i)&&(e=f(e)||this.index,this.caches[e]=i,this.store())},setCaches:function(e){t.isArray(e)&&(this.caches=e,this.store())},removeCache:function(t){this.caches.splice(f(t)||this.index,1),this.store()},removeCaches:function(){this.caches=[],this.store()},outputCache:function(e){var i=this.getCache(e);t.isPlainObject(i)&&(this.activeIndex=f(e)||this.index,i=t.extend(!0,{},i),this.$controls.each(function(){var e,s,n=t(this),o=n.attr("name");o&&(e=i[o],t.isArray(e)&&e.length&&(s=e.shift(),r(this)?this.checked=s:n.val(s)))}))},store:function(){var t=this.storage,e=this.key,n=this.defaults;t.date=new Date,t.maxAge=n.maxAge,t=JSON.stringify(t),n.session&&i&&i.setItem(e,t),n.local&&s&&s.setItem(e,t)},clear:function(){var t=this.key,e=this.defaults;e.session&&i&&i.removeItem(t),e.local&&s&&s.removeItem(t)},destroy:function(){this.removeListeners(),this.$form.removeData("formcache")}},u.DEFAULTS={key:"",local:!0,session:0,autoStore:!0,maxAge:void 0,controls:["select","textarea","input"]},u.setDefaults=function(e){t.extend(u.DEFAULTS,e)},u.other=t.fn.formcache,t.fn.formcache=function(e){var i,s=[].slice.call(arguments,1);return this.each(function(){var n,o=t(this),a=o.data("formcache");a||o.data("formcache",a=new u(this,e)),"string"==typeof e&&t.isFunction(n=a[e])&&(i=n.apply(a,s))}),typeof i!==n?i:this},t.fn.formcache.Constructor=u,t.fn.formcache.setDefaults=u.setDefaults,t.fn.formcache.noConflict=function(){return t.fn.formcache=u.other,this},t(function(){t('form[data-toggle="formcache"]').formcache()})});

View File

@ -1 +1 @@
!function(e){function t(t,n){var a=e('<div class="numberedtextarea-wrapper"></div>').insertAfter(t);e(t).detach().appendTo(a)}function n(t,n){(t=e(t)).parents(".numberedtextarea-wrapper");var i=parseFloat(t.css("padding-left")),o=parseFloat(t.css("padding-top")),s=(parseFloat(t.css("padding-bottom")),e('<div class="numberedtextarea-line-numbers"></div>').insertAfter(t));t.css({paddingLeft:i+s.width()+"px"}).on("input propertychange change keyup paste",function(){a(t,n)}).on("scroll",function(){r(t,n)}),s.css({paddingLeft:i+"px",paddingTop:o+"px",lineHeight:t.css("line-height"),fontFamily:t.css("font-family"),width:s.width()-i+"px"}),t.trigger("change")}function a(t,n){var a=(t=e(t)).parent().find(".numberedtextarea-line-numbers"),r=t.val().split("\n").length,o=parseFloat(t.css("padding-bottom"));for(a.find(".numberedtextarea-number").remove(),i=1;i<=r;i++){var s=e('<div class="numberedtextarea-number numberedtextarea-number-'+i+'">'+i+"</div>").appendTo(a);i===r&&s.css("margin-bottom",o+"px")}}function r(t,n){(t=e(t)).parent().find(".numberedtextarea-line-numbers").scrollTop(t.scrollTop())}function o(e,t){if(e.focus(),"number"==typeof e.selectionStart){var n=e.value,a=e.selectionStart;e.value=n.slice(0,a)+t+n.slice(e.selectionEnd),e.selectionEnd=e.selectionStart=a+t.length}else if(void 0!==document.selection){var i=document.selection.createRange();i.text=t,i.collapse(!1),i.select()}}function s(t){e(t).keydown(function(e){if(9==e.which)return o(this,"\t"),!1}),e(t).keypress(function(e){if(9==e.which)return!1})}e.fn.numberedtextarea=function(a){var i=e.extend({color:null,borderColor:null,class:null,allowTabChar:!1},a);return this.each(function(){if("textarea"!==this.nodeName.toLowerCase())return console.log("This is not a <textarea>, so no way Jose..."),!1;t(this,i),n(this,i),i.allowTabChar&&e(this).allowTabChar()}),this},e.fn.allowTabChar=function(){return this.jquery&&this.each(function(){if(1==this.nodeType){var e=this.nodeName.toLowerCase();("textarea"==e||"input"==e&&"text"==this.type)&&s(this)}}),this}}(jQuery); !function(e){function t(t,n){var a=e('<div class="numberedtextarea-wrapper"></div>').insertAfter(t);e(t).detach().appendTo(a)}function n(t,n){(t=e(t)).parents(".numberedtextarea-wrapper");var i=parseFloat(t.css("padding-left")),o=parseFloat(t.css("padding-top")),s=(parseFloat(t.css("padding-bottom")),e('<div class="numberedtextarea-line-numbers"></div>').insertAfter(t));t.css({paddingLeft:i+s.width()+"px"}).on("input propertychange change keyup paste",function(){a(t,n)}).on("scroll",function(){r(t,n)}),s.css({paddingLeft:i+"px",paddingTop:o+"px",lineHeight:t.css("line-height"),fontFamily:t.css("font-family"),width:s.width()-i+"px"}),t.trigger("change")}function a(t,n){var a=(t=e(t)).parent().find(".numberedtextarea-line-numbers"),r=t.val().split("\n").length,o=parseFloat(t.css("padding-bottom"));for(a.find(".numberedtextarea-number").remove(),i=1;i<=r;i++){var s=e('<div class="numberedtextarea-number numberedtextarea-number-'+i+'">'+i+"</div>").appendTo(a);i===r&&s.css("margin-bottom",o+"px")}}function r(t,n){(t=e(t)).parent().find(".numberedtextarea-line-numbers").scrollTop(t.scrollTop())}function o(e,t){if(e.focus(),"number"==typeof e.selectionStart){var n=e.value,a=e.selectionStart;e.value=n.slice(0,a)+t+n.slice(e.selectionEnd),e.selectionEnd=e.selectionStart=a+t.length}else if(void 0!==document.selection){var i=document.selection.createRange();i.text=t,i.collapse(!1),i.select()}}function s(t){e(t).keydown(function(e){if(9==e.which)return o(this,"\t"),!1}),e(t).keypress(function(e){if(9==e.which)return!1})}e.fn.numberedtextarea=function(a){var i=e.extend({color:null,borderColor:null,class:null,allowTabChar:!1},a);return this.each(function(){if("textarea"!==this.nodeName.toLowerCase())return console.log("This is not a <textarea>, so no way Jose..."),!1;t(this,i),n(this,i),i.allowTabChar&&e(this).allowTabChar()}),this},e.fn.allowTabChar=function(){return this.jquery&&this.each(function(){if(1==this.nodeType){var e=this.nodeName.toLowerCase();("textarea"==e||"input"==e&&"text"==this.type)&&s(this)}}),this}}(jQuery);

View File

@ -1,397 +1,397 @@
$(document).ready(function() { $(document).ready(function() {
mass_action = false; mass_action = false;
function validateEmail(email) { function validateEmail(email) {
var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email); return re.test(email);
} }
function validateRegex(e){var t=e.split("/"),n=e,r="";t.length>1&&(n=t[1],r=t[2]);try{return new RegExp(n,r),!0}catch(e){return!1}} function validateRegex(e){var t=e.split("/"),n=e,r="";t.length>1&&(n=t[1],r=t[2]);try{return new RegExp(n,r),!0}catch(e){return!1}}
function is_active(elem) { function is_active(elem) {
if ($(elem).data('submitted') == '1') { if ($(elem).data('submitted') == '1') {
return true; return true;
} else { } else {
var parent_btn_grp = $(elem).parentsUntil(".btn-group").parent(); var parent_btn_grp = $(elem).parentsUntil(".btn-group").parent();
if (parent_btn_grp.hasClass('btn-group')) { if (parent_btn_grp.hasClass('btn-group')) {
parent_btn_grp.replaceWith('<button class="btn btn-secondary btn-sm" disabled>' + lang_footer.loading + '</a>'); parent_btn_grp.replaceWith('<button class="btn btn-secondary btn-sm" disabled>' + lang_footer.loading + '</a>');
} }
$(elem).text(lang_footer.loading); $(elem).text(lang_footer.loading);
$(elem).attr('data-submitted', '1'); $(elem).attr('data-submitted', '1');
function disableF5(e) { if ((e.which || e.keyCode) == 116 || (e.which || e.keyCode) == 82) e.preventDefault(); }; function disableF5(e) { if ((e.which || e.keyCode) == 116 || (e.which || e.keyCode) == 82) e.preventDefault(); };
$(document).on("keydown", disableF5); $(document).on("keydown", disableF5);
return false; return false;
} }
} }
$.fn.serializeObject = function() { $.fn.serializeObject = function() {
var o = {}; var o = {};
var a = this.serializeArray(); var a = this.serializeArray();
$.each(a, function() { $.each(a, function() {
if (o[this.name]) { if (o[this.name]) {
if (!o[this.name].push) { if (!o[this.name].push) {
o[this.name] = [o[this.name]]; o[this.name] = [o[this.name]];
} }
o[this.name].push(this.value || ''); o[this.name].push(this.value || '');
} else { } else {
o[this.name] = this.value || ''; o[this.name] = this.value || '';
} }
}); });
return o; return o;
}; };
// Collect values of input fields with name "multi_select" and same data-id to js array multi_data[data-id] // Collect values of input fields with name "multi_select" and same data-id to js array multi_data[data-id]
var multi_data = []; var multi_data = [];
$(document).on('change', 'input[name=multi_select]:checkbox', function(e) { $(document).on('change', 'input[name=multi_select]:checkbox', function(e) {
if(mass_action === true) { if(mass_action === true) {
multi_data = []; multi_data = [];
mass_action = false; mass_action = false;
} }
if ($(this).is(':checked') && $(this).data('id')) { if ($(this).is(':checked') && $(this).data('id')) {
var id = $(this).data('id'); var id = $(this).data('id');
if (typeof multi_data[id] == "undefined") { if (typeof multi_data[id] == "undefined") {
multi_data[id] = []; multi_data[id] = [];
} }
multi_data[id].push($(this).val()); multi_data[id].push($(this).val());
} }
else { else {
var id = $(this).data('id'); var id = $(this).data('id');
if (typeof multi_data[id] !== "undefined") { if (typeof multi_data[id] !== "undefined") {
multi_data[id].splice($.inArray($(this).val(), multi_data[id]),1); multi_data[id].splice($.inArray($(this).val(), multi_data[id]),1);
} }
} }
}); });
// Select checkbox by click on parent tr // Select checkbox by click on parent tr
$(document).on('click', 'tbody>tr', function(e) { $(document).on('click', 'tbody>tr', function(e) {
if(e.target.tagName.toLowerCase() === 'button') { if(e.target.tagName.toLowerCase() === 'button') {
e.stopPropagation(); e.stopPropagation();
} }
else if(e.target.tagName.toLowerCase() === 'a') { else if(e.target.tagName.toLowerCase() === 'a') {
e.stopPropagation(); e.stopPropagation();
} }
else if (e.target.type == "checkbox") { else if (e.target.type == "checkbox") {
e.stopPropagation(); e.stopPropagation();
} }
else { else {
var checkbox = $(this).find(':checkbox'); var checkbox = $(this).find(':checkbox');
checkbox.trigger('click'); checkbox.trigger('click');
} }
}); });
// Select or deselect all checkboxes with same data-id // Select or deselect all checkboxes with same data-id
$(document).on('click', '#toggle_multi_select_all', function(e) { $(document).on('click', '#toggle_multi_select_all', function(e) {
mass_action = true mass_action = true
e.preventDefault(); e.preventDefault();
id = $(this).data("id"); id = $(this).data("id");
var all_checkboxes = $("input[data-id=" + id + "]:enabled"); var all_checkboxes = $("input[data-id=" + id + "]:enabled");
all_checkboxes.prop("checked", !all_checkboxes.prop("checked")).change(); all_checkboxes.prop("checked", !all_checkboxes.prop("checked")).change();
}); });
// General API edit actions // General API edit actions
$(document).on('click', "[data-action='edit_selected']", function(e) { $(document).on('click', "[data-action='edit_selected']", function(e) {
e.preventDefault(); e.preventDefault();
var id = $(this).data('id'); var id = $(this).data('id');
var api_url = $(this).data('api-url'); var api_url = $(this).data('api-url');
var api_attr = $(this).data('api-attr'); var api_attr = $(this).data('api-attr');
if (typeof $(this).data('api-reload-window') !== 'undefined') { if (typeof $(this).data('api-reload-window') !== 'undefined') {
api_reload_window = $(this).data('api-reload-window'); api_reload_window = $(this).data('api-reload-window');
} else { } else {
api_reload_window = true; api_reload_window = true;
} }
if (typeof $(this).data('api-reload-location') !== 'undefined') { if (typeof $(this).data('api-reload-location') !== 'undefined') {
api_reload_location = $(this).data('api-reload-location'); api_reload_location = $(this).data('api-reload-location');
} else { } else {
api_reload_location = '#'; api_reload_location = '#';
} }
// If clicked element #edit_selected is in a form with the same data-id as the button, // If clicked element #edit_selected is in a form with the same data-id as the button,
// we merge all input fields by {"name":"value"} into api-attr // we merge all input fields by {"name":"value"} into api-attr
if ($(this).closest("form").data('id') == id) { if ($(this).closest("form").data('id') == id) {
var invalid = false; var invalid = false;
$(this).closest("form").find('select, textarea, input').each(function() { $(this).closest("form").find('select, textarea, input').each(function() {
if ($(this).prop('required')) { if ($(this).prop('required')) {
if (!$(this).val() && $(this).prop('disabled') === false) { if (!$(this).val() && $(this).prop('disabled') === false) {
invalid = true; invalid = true;
if ($(this).is("select")) { if ($(this).is("select")) {
$(this).selectpicker('setStyle', 'btn-input-missing', 'add'); $(this).selectpicker('setStyle', 'btn-input-missing', 'add');
} }
$(this).addClass('inputMissingAttr'); $(this).addClass('inputMissingAttr');
} else { } else {
if ($(this).is("select")) { if ($(this).is("select")) {
$(this).selectpicker('setStyle', 'btn-input-missing', 'remove'); $(this).selectpicker('setStyle', 'btn-input-missing', 'remove');
} }
$(this).removeClass('inputMissingAttr'); $(this).removeClass('inputMissingAttr');
} }
} }
if ($(this).val() && $(this).attr("type") == 'email') { if ($(this).val() && $(this).attr("type") == 'email') {
if (!validateEmail($(this).val())) { if (!validateEmail($(this).val())) {
invalid = true; invalid = true;
$(this).addClass('inputMissingAttr'); $(this).addClass('inputMissingAttr');
} else { } else {
$(this).removeClass('inputMissingAttr'); $(this).removeClass('inputMissingAttr');
} }
} }
if ($(this).attr("max")) { if ($(this).attr("max")) {
if (Number($(this).val()) > Number($(this).attr("max"))) { if (Number($(this).val()) > Number($(this).attr("max"))) {
invalid = true; invalid = true;
$(this).addClass('inputMissingAttr'); $(this).addClass('inputMissingAttr');
} else { } else {
if ($(this).attr("min")) { if ($(this).attr("min")) {
if (Number($(this).val()) < Number($(this).attr("min"))) { if (Number($(this).val()) < Number($(this).attr("min"))) {
invalid = true; invalid = true;
$(this).addClass('inputMissingAttr'); $(this).addClass('inputMissingAttr');
} else { } else {
$(this).removeClass('inputMissingAttr'); $(this).removeClass('inputMissingAttr');
} }
} }
} }
} }
if ($(this).val() && $(this).attr("regex")) { if ($(this).val() && $(this).attr("regex")) {
var regex_content = $(this).val(); var regex_content = $(this).val();
$(this).removeClass('inputMissingAttr'); $(this).removeClass('inputMissingAttr');
if(!validateRegex(regex_content)) { if(!validateRegex(regex_content)) {
invalid = true; invalid = true;
$(this).addClass('inputMissingAttr'); $(this).addClass('inputMissingAttr');
} }
if(!regex_content.startsWith('/') || !/\/[ims]?$/.test(regex_content)){ if(!regex_content.startsWith('/') || !/\/[ims]?$/.test(regex_content)){
invalid = true; invalid = true;
$(this).addClass('inputMissingAttr'); $(this).addClass('inputMissingAttr');
} }
} }
}); });
if (!invalid) { if (!invalid) {
var attr_to_merge = $(this).closest("form").serializeObject(); var attr_to_merge = $(this).closest("form").serializeObject();
// parse possible JSON Strings // parse possible JSON Strings
for (var [key, value] of Object.entries(attr_to_merge)) { for (var [key, value] of Object.entries(attr_to_merge)) {
try { try {
attr_to_merge[key] = JSON.parse(attr_to_merge[key]); attr_to_merge[key] = JSON.parse(attr_to_merge[key]);
} catch {} } catch {}
} }
var api_attr = $.extend(api_attr, attr_to_merge) var api_attr = $.extend(api_attr, attr_to_merge)
} else { } else {
return false; return false;
} }
} }
// alert(JSON.stringify(api_attr)); // alert(JSON.stringify(api_attr));
// If clicked element #edit_selected has data-item attribute, it is added to "items" // If clicked element #edit_selected has data-item attribute, it is added to "items"
if (typeof $(this).data('item') !== 'undefined') { if (typeof $(this).data('item') !== 'undefined') {
var id = $(this).data('id'); var id = $(this).data('id');
if (typeof multi_data[id] == "undefined") { if (typeof multi_data[id] == "undefined") {
multi_data[id] = []; multi_data[id] = [];
} }
multi_data[id].splice($.inArray($(this).data('item'), multi_data[id]), 1); multi_data[id].splice($.inArray($(this).data('item'), multi_data[id]), 1);
multi_data[id].push($(this).data('item')); multi_data[id].push($(this).data('item'));
} }
if (typeof multi_data[id] == "undefined") return; if (typeof multi_data[id] == "undefined") return;
api_items = multi_data[id]; api_items = multi_data[id];
for (var i in api_items) { for (var i in api_items) {
api_items[i] = decodeURIComponent(api_items[i]); api_items[i] = decodeURIComponent(api_items[i]);
} }
// alert(JSON.stringify(api_attr)); // alert(JSON.stringify(api_attr));
if (Object.keys(api_items).length !== 0) { if (Object.keys(api_items).length !== 0) {
if (is_active($(this))) { return false; } if (is_active($(this))) { return false; }
$.ajax({ $.ajax({
type: "POST", type: "POST",
dataType: "json", dataType: "json",
data: { data: {
"items": JSON.stringify(api_items), "items": JSON.stringify(api_items),
"attr": JSON.stringify(api_attr), "attr": JSON.stringify(api_attr),
"csrf_token": csrf_token "csrf_token": csrf_token
}, },
url: '/api/v1/' + api_url, url: '/api/v1/' + api_url,
jsonp: false, jsonp: false,
complete: function(data) { complete: function(data) {
var response = (data.responseText); var response = (data.responseText);
if (typeof response !== 'undefined' && response.length !== 0) { if (typeof response !== 'undefined' && response.length !== 0) {
response_obj = JSON.parse(response); response_obj = JSON.parse(response);
} }
if (api_reload_window === true) { if (api_reload_window === true) {
if (api_reload_location != '#') { if (api_reload_location != '#') {
window.location.replace(api_reload_location) window.location.replace(api_reload_location)
} else { } else {
window.location = window.location.href.split("#")[0]; window.location = window.location.href.split("#")[0];
} }
} }
} }
}); });
} }
}); });
// General API add actions // General API add actions
$(document).on('click', "[data-action='add_item']", function(e) { $(document).on('click', "[data-action='add_item']", function(e) {
e.preventDefault(); e.preventDefault();
var id = $(this).data('id'); var id = $(this).data('id');
var api_url = $(this).data('api-url'); var api_url = $(this).data('api-url');
var api_attr = $(this).data('api-attr'); var api_attr = $(this).data('api-attr');
if (typeof $(this).data('api-reload-window') !== 'undefined') { if (typeof $(this).data('api-reload-window') !== 'undefined') {
api_reload_window = $(this).data('api-reload-window'); api_reload_window = $(this).data('api-reload-window');
} else { } else {
api_reload_window = true; api_reload_window = true;
} }
// If clicked button is in a form with the same data-id as the button, // If clicked button is in a form with the same data-id as the button,
// we merge all input fields by {"name":"value"} into api-attr // we merge all input fields by {"name":"value"} into api-attr
if ($(this).closest("form").data('id') == id) { if ($(this).closest("form").data('id') == id) {
var invalid = false; var invalid = false;
$(this).closest("form").find('select, textarea, input').each(function() { $(this).closest("form").find('select, textarea, input').each(function() {
if ($(this).prop('required')) { if ($(this).prop('required')) {
if (!$(this).val() && $(this).prop('disabled') === false) { if (!$(this).val() && $(this).prop('disabled') === false) {
invalid = true; invalid = true;
if ($(this).is("select")) { if ($(this).is("select")) {
$(this).selectpicker('setStyle', 'btn-input-missing', 'add'); $(this).selectpicker('setStyle', 'btn-input-missing', 'add');
} }
$(this).addClass('inputMissingAttr'); $(this).addClass('inputMissingAttr');
} else { } else {
if ($(this).is("select")) { if ($(this).is("select")) {
$(this).selectpicker('setStyle', 'btn-input-missing', 'remove'); $(this).selectpicker('setStyle', 'btn-input-missing', 'remove');
} }
$(this).removeClass('inputMissingAttr'); $(this).removeClass('inputMissingAttr');
} }
} }
if ($(this).attr("type") == 'email') { if ($(this).attr("type") == 'email') {
var emailReg = /^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/; var emailReg = /^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/;
if (!emailReg.test($(this).val())) { if (!emailReg.test($(this).val())) {
invalid = true; invalid = true;
$(this).addClass('inputMissingAttr'); $(this).addClass('inputMissingAttr');
} else { } else {
$(this).removeClass('inputMissingAttr'); $(this).removeClass('inputMissingAttr');
} }
} }
if ($(this).attr("max")) { if ($(this).attr("max")) {
if (Number($(this).val()) > Number($(this).attr("max"))) { if (Number($(this).val()) > Number($(this).attr("max"))) {
invalid = true; invalid = true;
$(this).addClass('inputMissingAttr'); $(this).addClass('inputMissingAttr');
} else { } else {
if ($(this).attr("min")) { if ($(this).attr("min")) {
if (Number($(this).val()) < Number($(this).attr("min"))) { if (Number($(this).val()) < Number($(this).attr("min"))) {
invalid = true; invalid = true;
$(this).addClass('inputMissingAttr'); $(this).addClass('inputMissingAttr');
} else { } else {
$(this).removeClass('inputMissingAttr'); $(this).removeClass('inputMissingAttr');
} }
} }
} }
} }
}); });
if (!invalid) { if (!invalid) {
var attr_to_merge = $(this).closest("form").serializeObject(); var attr_to_merge = $(this).closest("form").serializeObject();
// parse possible JSON Strings // parse possible JSON Strings
for (var [key, value] of Object.entries(attr_to_merge)) { for (var [key, value] of Object.entries(attr_to_merge)) {
try { try {
attr_to_merge[key] = JSON.parse(attr_to_merge[key]); attr_to_merge[key] = JSON.parse(attr_to_merge[key]);
} catch {} } catch {}
} }
var api_attr = $.extend(api_attr, attr_to_merge) var api_attr = $.extend(api_attr, attr_to_merge)
} else { } else {
return false; return false;
} }
} }
if (is_active($(this))) { return false; } if (is_active($(this))) { return false; }
// alert(JSON.stringify(api_attr)); // alert(JSON.stringify(api_attr));
$.ajax({ $.ajax({
type: "POST", type: "POST",
dataType: "json", dataType: "json",
data: { data: {
"attr": JSON.stringify(api_attr), "attr": JSON.stringify(api_attr),
"csrf_token": csrf_token "csrf_token": csrf_token
}, },
url: '/api/v1/' + api_url, url: '/api/v1/' + api_url,
jsonp: false, jsonp: false,
complete: function(data) { complete: function(data) {
var response = (data.responseText); var response = (data.responseText);
if (typeof response !== 'undefined' && response.length !== 0) { if (typeof response !== 'undefined' && response.length !== 0) {
response_obj = JSON.parse(response); response_obj = JSON.parse(response);
unset = true; unset = true;
$.each(response_obj, function(i, v) { $.each(response_obj, function(i, v) {
if (v.type == "danger") { if (v.type == "danger") {
unset = false; unset = false;
} }
}); });
if (unset === true) { if (unset === true) {
unset = null; unset = null;
// Keep form data for sync jobs // Keep form data for sync jobs
if (id != "add_syncjob") { if (id != "add_syncjob") {
$('form').formcache('clear'); $('form').formcache('clear');
$('form').formcache('destroy'); $('form').formcache('destroy');
var i = localStorage.length; var i = localStorage.length;
while(i--) { while(i--) {
var key = localStorage.key(i); var key = localStorage.key(i);
if(/formcache/.test(key)) { if(/formcache/.test(key)) {
localStorage.removeItem(key); localStorage.removeItem(key);
} }
} }
} }
} }
else { else {
var add_modal = $('.modal.in').attr('id'); var add_modal = $('.modal.in').attr('id');
localStorage.setItem("add_modal", add_modal); localStorage.setItem("add_modal", add_modal);
} }
} }
if (api_reload_window === true) { if (api_reload_window === true) {
window.location = window.location.href.split("#")[0]; window.location = window.location.href.split("#")[0];
} }
} }
}); });
}); });
// General API delete actions // General API delete actions
$(document).on('click', "[data-action='delete_selected']", function(e) { $(document).on('click', "[data-action='delete_selected']", function(e) {
e.preventDefault(); e.preventDefault();
var id = $(this).data('id'); var id = $(this).data('id');
// If clicked element #delete_selected has data-item attribute, it is added to "items" // If clicked element #delete_selected has data-item attribute, it is added to "items"
if (typeof $(this).data('item') !== 'undefined') { if (typeof $(this).data('item') !== 'undefined') {
var id = $(this).data('id'); var id = $(this).data('id');
if (typeof multi_data[id] == "undefined") { if (typeof multi_data[id] == "undefined") {
multi_data[id] = []; multi_data[id] = [];
} }
multi_data[id].splice($.inArray($(this).data('item'), multi_data[id]), 1); multi_data[id].splice($.inArray($(this).data('item'), multi_data[id]), 1);
multi_data[id].push($(this).data('item')); multi_data[id].push($(this).data('item'));
} }
if (typeof $(this).data('text') !== 'undefined') { if (typeof $(this).data('text') !== 'undefined') {
$("#DeleteText").empty(); $("#DeleteText").empty();
$("#DeleteText").text($(this).data('text')); $("#DeleteText").text($(this).data('text'));
} }
if (typeof multi_data[id] == "undefined" || multi_data[id] == "") return; if (typeof multi_data[id] == "undefined" || multi_data[id] == "") return;
data_array = multi_data[id]; data_array = multi_data[id];
api_url = $(this).data('api-url'); api_url = $(this).data('api-url');
$(document).on('show.bs.modal', '#ConfirmDeleteModal', function() { $(document).on('show.bs.modal', '#ConfirmDeleteModal', function() {
$("#ItemsToDelete").empty(); $("#ItemsToDelete").empty();
for (var i in data_array) { for (var i in data_array) {
data_array[i] = decodeURIComponent(data_array[i]); data_array[i] = decodeURIComponent(data_array[i]);
$("#ItemsToDelete").append("<li>" + escapeHtml(data_array[i]) + "</li>"); $("#ItemsToDelete").append("<li>" + escapeHtml(data_array[i]) + "</li>");
} }
}) })
$('#ConfirmDeleteModal').modal('show') $('#ConfirmDeleteModal').modal('show')
.one('click', '#IsConfirmed', function(e) { .one('click', '#IsConfirmed', function(e) {
if (is_active($('#IsConfirmed'))) { return false; } if (is_active($('#IsConfirmed'))) { return false; }
$.ajax({ $.ajax({
type: "POST", type: "POST",
dataType: "json", dataType: "json",
cache: false, cache: false,
data: { data: {
"items": JSON.stringify(data_array), "items": JSON.stringify(data_array),
"csrf_token": csrf_token "csrf_token": csrf_token
}, },
url: '/api/v1/' + api_url, url: '/api/v1/' + api_url,
jsonp: false, jsonp: false,
complete: function(data) { complete: function(data) {
window.location = window.location.href.split("#")[0]; window.location = window.location.href.split("#")[0];
} }
}); });
}) })
.one('click', '#isCanceled', function(e) { .one('click', '#isCanceled', function(e) {
// Remove event handler to allow to close modal and restart dialog without multiple submits // Remove event handler to allow to close modal and restart dialog without multiple submits
$('#ConfirmDeleteModal').off(); $('#ConfirmDeleteModal').off();
$('#ConfirmDeleteModal').modal('hide'); $('#ConfirmDeleteModal').modal('hide');
}); });
}); });
// toggle jquery datatables child rows // toggle jquery datatables child rows
$('button[data-datatables-expand], a[data-datatables-expand]').on('click', function (e) { $('button[data-datatables-expand], a[data-datatables-expand]').on('click', function (e) {
e.preventDefault(); e.preventDefault();
var tableId = e.target.getAttribute("data-datatables-expand"); var tableId = e.target.getAttribute("data-datatables-expand");
var table = $("#" + tableId).DataTable(); var table = $("#" + tableId).DataTable();
table.rows(':not(.parent)').nodes().to$().find('td:first-child').trigger('click'); table.rows(':not(.parent)').nodes().to$().find('td:first-child').trigger('click');
}); });
$('button[data-datatables-collapse], a[data-datatables-collapse]').on('click', function (e) { $('button[data-datatables-collapse], a[data-datatables-collapse]').on('click', function (e) {
e.preventDefault(); e.preventDefault();
var tableId = e.target.getAttribute("data-datatables-collapse"); var tableId = e.target.getAttribute("data-datatables-collapse");
var table = $("#" + tableId).DataTable(); var table = $("#" + tableId).DataTable();
table.rows('.parent').nodes().to$().find('td:first-child').trigger('click'); table.rows('.parent').nodes().to$().find('td:first-child').trigger('click');
}); });
}); });

File diff suppressed because it is too large Load Diff

View File

@ -1,32 +1,32 @@
<?php <?php
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
if (!$oauth2_server->verifyResourceRequest(OAuth2\Request::createFromGlobals())) { if (!$oauth2_server->verifyResourceRequest(OAuth2\Request::createFromGlobals())) {
$oauth2_server->getResponse()->send(); $oauth2_server->getResponse()->send();
die; die;
} }
$token = $oauth2_server->getAccessTokenData(OAuth2\Request::createFromGlobals()); $token = $oauth2_server->getAccessTokenData(OAuth2\Request::createFromGlobals());
$stmt = $pdo->prepare("SELECT * FROM `mailbox` WHERE `username` = :username AND `active` = '1'"); $stmt = $pdo->prepare("SELECT * FROM `mailbox` WHERE `username` = :username AND `active` = '1'");
$stmt->execute(array(':username' => $token['user_id'])); $stmt->execute(array(':username' => $token['user_id']));
$mailbox = $stmt->fetch(PDO::FETCH_ASSOC); $mailbox = $stmt->fetch(PDO::FETCH_ASSOC);
if (!empty($mailbox)) { if (!empty($mailbox)) {
if ($token['scope'] == 'profile') { if ($token['scope'] == 'profile') {
header('Content-Type: application/json'); header('Content-Type: application/json');
echo json_encode(array( echo json_encode(array(
'success' => true, 'success' => true,
'username' => $token['user_id'], 'username' => $token['user_id'],
'id' => $token['user_id'], 'id' => $token['user_id'],
'identifier' => $token['user_id'], 'identifier' => $token['user_id'],
'email' => (!empty($mailbox['username']) ? $mailbox['username'] : ''), 'email' => (!empty($mailbox['username']) ? $mailbox['username'] : ''),
'full_name' => (!empty($mailbox['name']) ? $mailbox['name'] : 'mailcow administrative user'), 'full_name' => (!empty($mailbox['name']) ? $mailbox['name'] : 'mailcow administrative user'),
'displayName' => (!empty($mailbox['name']) ? $mailbox['name'] : 'mailcow administrative user'), 'displayName' => (!empty($mailbox['name']) ? $mailbox['name'] : 'mailcow administrative user'),
'created' => (!empty($mailbox['created']) ? $mailbox['created'] : ''), 'created' => (!empty($mailbox['created']) ? $mailbox['created'] : ''),
'modified' => (!empty($mailbox['modified']) ? $mailbox['modified'] : ''), 'modified' => (!empty($mailbox['modified']) ? $mailbox['modified'] : ''),
'active' => (!empty($mailbox['active']) ? $mailbox['active'] : ''), 'active' => (!empty($mailbox['active']) ? $mailbox['active'] : ''),
)); ));
exit; exit;
} }
} }
echo json_encode(array( echo json_encode(array(
'success' => false 'success' => false
)); ));

View File

@ -1,4 +1,4 @@
<?php <?php
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
$request = OAuth2\Request::createFromGlobals(); $request = OAuth2\Request::createFromGlobals();
$oauth2_server->handleTokenRequest($request)->send(); $oauth2_server->handleTokenRequest($request)->send();