[Web] Add smtp and header from to quarantine items, add more info to qhandler, allow to open qhandler links from qitem details

master
andryyy 2020-06-06 13:25:32 +02:00
parent f9b8d386bc
commit b93371ca0a
No known key found for this signature in database
GPG Key ID: 8EC34FF2794E25EF
19 changed files with 225 additions and 31 deletions

View File

@ -2,9 +2,6 @@
session_start();
header("Content-Type: application/json");
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
if (!isset($_SESSION['mailcow_cc_role'])) {
exit();
}
function rrmdir($src) {
$dir = opendir($src);
@ -22,6 +19,7 @@ function rrmdir($src) {
closedir($dir);
rmdir($src);
}
function addAddresses(&$list, $mail, $headerName) {
$addresses = $mail->getAddresses($headerName);
foreach ($addresses as $address) {
@ -29,7 +27,49 @@ function addAddresses(&$list, $mail, $headerName) {
}
}
if (!empty($_GET['id']) && ctype_alnum($_GET['id'])) {
if (!empty($_GET['hash']) && ctype_alnum($_GET['hash'])) {
$mailc = quarantine('hash_details', $_GET['hash']);
if ($mailc === false) {
echo json_encode(array('error' => 'Message invalid'));
exit;
}
if (strlen($mailc['msg']) > 10485760) {
echo json_encode(array('error' => 'Message size exceeds 10 MiB.'));
exit;
}
if (!empty($mailc['msg'])) {
// Init message array
$data = array();
// Init parser
$mail_parser = new PhpMimeMailParser\Parser();
$html2text = new Html2Text\Html2Text();
// Load msg to parser
$mail_parser->setText($mailc['msg']);
// Get mail recipients
{
$recipientsList = array();
addAddresses($recipientsList, $mail_parser, 'to');
addAddresses($recipientsList, $mail_parser, 'cc');
addAddresses($recipientsList, $mail_parser, 'bcc');
$data['recipients'] = $recipientsList;
}
// Get from
$data['header_from'] = $mail_parser->getHeader('from');
$data['env_from'] = $mailc['sender'];
// Get rspamd score
$data['score'] = $mailc['score'];
// Get rspamd symbols
$data['symbols'] = json_decode($mailc['symbols']);
$data['subject'] = $mail_parser->getHeader('subject');
(empty($data['subject'])) ? $data['subject'] = '-' : null;
echo json_encode($data);
}
}
elseif (!empty($_GET['id']) && ctype_alnum($_GET['id'])) {
if (!isset($_SESSION['mailcow_cc_role'])) {
echo json_encode(array('error' => 'Access denied'));
exit();
}
$tmpdir = '/tmp/' . $_GET['id'] . '/';
$mailc = quarantine('details', $_GET['id']);
if (strlen($mailc['msg']) > 10485760) {
@ -37,6 +77,16 @@ if (!empty($_GET['id']) && ctype_alnum($_GET['id'])) {
exit;
}
if (!empty($mailc['msg'])) {
if (isset($_GET['quick_release'])) {
$hash = hash('sha256', $mailc['id'] . $mailc['qid']);
header('Location: /qhandler/release/' . $hash);
exit;
}
if (isset($_GET['quick_delete'])) {
$hash = hash('sha256', $mailc['id'] . $mailc['qid']);
header('Location: /qhandler/delete/' . $hash);
exit;
}
// Init message array
$data = array();
// Init parser
@ -53,7 +103,9 @@ if (!empty($_GET['id']) && ctype_alnum($_GET['id'])) {
addAddresses($recipientsList, $mail_parser, 'bcc');
$data['recipients'] = $recipientsList;
}
// Get from
$data['header_from'] = $mail_parser->getHeader('from');
$data['env_from'] = $mailc['sender'];
// Get rspamd score
$data['score'] = $mailc['score'];
// Get rspamd symbols

View File

@ -16,7 +16,7 @@ function quarantine($_action, $_data = null) {
'msg' => 'access_denied'
)
)));
return;
return false;
}
$stmt = $pdo->prepare('SELECT `id` FROM `quarantine` LEFT OUTER JOIN `user_acl` ON `user_acl`.`username` = `rcpt`
WHERE SHA2(CONCAT(`id`, `qid`), 256) = :hash
@ -32,7 +32,7 @@ function quarantine($_action, $_data = null) {
'msg' => 'access_denied'
)
)));
return;
return false;
}
else {
$stmt = $pdo->prepare("DELETE FROM `quarantine` WHERE id = :id");
@ -59,7 +59,7 @@ function quarantine($_action, $_data = null) {
'msg' => 'access_denied'
)
)));
return;
return false;
}
$stmt = $pdo->prepare('SELECT `id` FROM `quarantine` LEFT OUTER JOIN `user_acl` ON `user_acl`.`username` = `rcpt`
WHERE SHA2(CONCAT(`id`, `qid`), 256) = :hash
@ -75,7 +75,7 @@ function quarantine($_action, $_data = null) {
'msg' => 'access_denied'
)
)));
return;
return false;
}
else {
$stmt = $pdo->prepare('SELECT `msg`, `qid`, `sender`, `rcpt` FROM `quarantine` WHERE `id` = :id');
@ -96,7 +96,7 @@ function quarantine($_action, $_data = null) {
'msg' => array('release_send_failed', 'Cannot determine Postfix host')
)
)));
return;
return false;
}
try {
$release_format = $redis->Get('Q_RELEASE_FORMAT');
@ -109,7 +109,7 @@ function quarantine($_action, $_data = null) {
'msg' => array('redis_error', $e)
)
)));
return;
return false;
}
if ($release_format == 'attachment') {
try {
@ -137,7 +137,7 @@ function quarantine($_action, $_data = null) {
'msg' => array('release_send_failed', 'Cannot determine Postfix host')
)
)));
return;
return false;
}
$mail->Host = $postfix;
$mail->Port = 590;
@ -162,7 +162,7 @@ function quarantine($_action, $_data = null) {
'msg' => array('release_send_failed', $e->errorMessage())
)
)));
return;
return false;
}
}
elseif ($release_format == 'raw') {
@ -199,7 +199,7 @@ function quarantine($_action, $_data = null) {
'msg' => 'Postfix returned SMTP code ' . $smtp_resource . ', expected ' . $postfix_talk[$i][0]
)
)));
return;
return false;
}
if ($postfix_talk[$i][1] !== '') {
fputs($smtp_connection, $postfix_talk[$i][1]);
@ -809,13 +809,36 @@ function quarantine($_action, $_data = null) {
if (!is_numeric($_data) || empty($_data)) {
return false;
}
$stmt = $pdo->prepare('SELECT `rcpt`, `score`, `symbols`, `msg`, `domain` FROM `quarantine` WHERE `id`= :id');
$stmt = $pdo->prepare('SELECT * FROM `quarantine` WHERE `id`= :id');
$stmt->execute(array(':id' => $_data));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row['rcpt'])) {
return $row;
}
logger(array('return' => array(
array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied'
)
)));
return false;
break;
case 'hash_details':
$hash = trim($_data);
if (preg_match("/^([a-f0-9]{64})$/", $hash) === false) {
logger(array('return' => array(
array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied'
)
)));
return false;
}
$stmt = $pdo->prepare('SELECT * FROM `quarantine` WHERE SHA2(CONCAT(`id`, `qid`), 256) = :hash');
$stmt->execute(array(':hash' => $hash));
return $stmt->fetch(PDO::FETCH_ASSOC);
break;
}
}

View File

@ -20,7 +20,7 @@
if (preg_match("/edit/i", $_SERVER['REQUEST_URI'])) {
$css_minifier->add('/web/css/site/edit.css');
}
if (preg_match("/quarantine/i", $_SERVER['REQUEST_URI'])) {
if (preg_match("/(quarantine|qhandler)/i", $_SERVER['REQUEST_URI'])) {
$css_minifier->add('/web/css/site/quarantine.css');
}
if (preg_match("/debug/i", $_SERVER['REQUEST_URI'])) {

View File

@ -0,0 +1,52 @@
jQuery(function($){
var qitem = $('legend').data('hash');
var qError = $("#qid_error");
$.ajax({
url: '/inc/ajax/qitem_details.php',
data: { hash: qitem },
dataType: 'json',
success: function(data){
if (typeof data.error !== 'undefined') {
qError.text(data.error);
qError.show();
}
$('[data-id="qitems_single"]').each(function(index) {
$(this).attr("data-item", qitem);
});
$('#qid_detail_subj').text(data.subject);
$('#qid_detail_hfrom').text(data.header_from);
$('#qid_detail_efrom').text(data.env_from);
$('#qid_detail_score').text(data.score);
$('#qid_detail_symbols').html('');
if (typeof data.symbols !== 'undefined') {
data.symbols.sort(function (a, b) {
if (a.score === 0) return 1
if (b.score === 0) return -1
if (b.score < 0 && a.score < 0) {
return a.score - b.score
}
if (b.score > 0 && a.score > 0) {
return b.score - a.score
}
return b.score - a.score
})
$.each(data.symbols, function (index, value) {
var highlightClass = ''
if (value.score > 0) highlightClass = 'negative'
else if (value.score < 0) highlightClass = 'positive'
else highlightClass = 'neutral'
$('#qid_detail_symbols').append('<span data-toggle="tooltip" class="rspamd-symbol ' + highlightClass + '" title="' + (value.options ? value.options.join(', ') : '') + '">' + value.name + ' (<span class="score">' + value.score + '</span>)</span>');
});
$('[data-toggle="tooltip"]').tooltip()
}
$('#qid_detail_recipients').html('');
if (typeof data.recipients !== 'undefined') {
$.each(data.recipients, function(index, value) {
var elem = $('<span class="mail-address-item"></span>');
elem.text(value.address + (value.type != 'to' ? (' (' + value.type.toUpperCase() + ')') : ''));
$('#qid_detail_recipients').append(elem);
});
}
}
});
});

View File

@ -144,7 +144,8 @@ jQuery(function($){
$('#qid_detail_subj').text(data.subject);
$('#qid_detail_text').text(data.text_plain);
$('#qid_detail_text_from_html').text(data.text_html);
$('#qid_detail_hfrom').text(data.header_from);
$('#qid_detail_efrom').text(data.env_from);
$('#qid_detail_score').text(data.score);
$('#qid_detail_symbols').html('');
if (typeof data.symbols !== 'undefined') {

View File

@ -387,7 +387,7 @@
"release_body": "Hem adjuntat el teu missatge com a eml en aquest missatge.",
"release_subject": "Element potencialment perillós %s en quarantena",
"remove": "Esborrar",
"sender": "Emissor",
"sender": "Emissor (SMTP)",
"show_item": "Mostrar",
"subj": "Assumpte",
"text_from_html_content": "Contingut (a partir del HTML)",

View File

@ -676,7 +676,7 @@
"release_subject": "Potenciálně škodlivá položka v karanténě %s",
"remove": "Smazat",
"rspamd_result": "Skóre Rspamd",
"sender": "Odesílatel",
"sender": "Odesílatel (SMTP)",
"show_item": "Zobrazit položku",
"spam_score": "Skóre",
"subj": "Předmět",

View File

@ -758,7 +758,10 @@
"release_subject": "Potentiell schädliche Nachricht aus Quarantäne: %s",
"remove": "Entfernen",
"rspamd_result": "Rspamd Ergebnis",
"sender": "Sender",
"quick_release_link": "Quick-Release Link öffnen",
"quick_delete_link": "Quick-Delete Link öffnen",
"sender": "Sender (SMTP)",
"sender_header": "Sender (From-Header)",
"show_item": "Details",
"spam_score": "Bewertung",
"subj": "Betreff",

View File

@ -757,7 +757,10 @@
"release_subject": "Potentially damaging quarantine item %s",
"remove": "Remove",
"rspamd_result": "Rspamd result",
"sender": "Sender",
"sender": "Sender (SMTP)",
"sender_header": "Sender (From header)",
"quick_release_link": "Open quick release link",
"quick_delete_link": "Open quick delete link",
"show_item": "Show item",
"spam_score": "Score",
"subj": "Subject",

View File

@ -602,7 +602,7 @@
"release_body": "Adjuntamos el mensaje en formato eml a este correo.",
"release_subject": "Mensaje de cuarentena potencialmente dañino %s",
"remove": "Remover",
"sender": "Remitente",
"sender": "Remitente (SMTP)",
"show_item": "Mostrar item",
"spam_score": "Puntaje",
"subj": "Asunto",

View File

@ -677,7 +677,7 @@
"release_subject": "Mahdollisesti vahingoittava karanteeni aihe %s",
"remove": "Poista",
"rspamd_result": "Rspamd-tulos",
"sender": "Lähettäjä",
"sender": "Lähettäjä (SMTP)",
"show_item": "Näytä tuote",
"spam_score": "Pisteet",
"subj": "Aihe",

View File

@ -388,7 +388,7 @@
"release_body": "Šim ziņojumam mēs esam pievienojuši jūsu ziņojumu kā eml failu.",
"release_subject": "Potenciāli kaitīgs karantīnas vienums %s",
"remove": "Noņemt",
"sender": "Sūtītājs",
"sender": "Sūtītājs (SMTP)",
"show_item": "Parādīt vienumus",
"subj": "Priekšmets",
"text_from_html_content": "Saturs (konvertēts html)",

View File

@ -753,7 +753,7 @@
"release_subject": "Mogelijk schadelijk quarantaine-item %s",
"remove": "Verwijder",
"rspamd_result": "Rspamd-resultaat",
"sender": "Afzender",
"sender": "Afzender (SMTP)",
"show_item": "Toon item",
"spam_score": "Score",
"subj": "Onderwerp",

View File

@ -757,7 +757,7 @@
"release_subject": "Element în carantină potențial dăunător %s",
"remove": "Elimină",
"rspamd_result": "Rezultat Rspamd",
"sender": "Expeditor",
"sender": "Expeditor (SMTP)",
"show_item": "Afișează elementul",
"spam_score": "Scor",
"subj": "Subiect",

View File

@ -759,7 +759,7 @@
"release_subject": "Потенциально опасное письмо %s",
"remove": "Удалить",
"rspamd_result": "Результат Rspamd",
"sender": "Отправитель",
"sender": "Отправитель (SMTP)",
"show_item": "Показать",
"spam_score": "Оценка",
"subj": "Тема письма",

View File

@ -750,7 +750,7 @@
"release_subject": "Potenciálne nebezpečná položka v karanténne %s",
"remove": "Odstrániť",
"rspamd_result": "Rspamd výsledok",
"sender": "Odosielateľ",
"sender": "Odosielateľ (SMTP)",
"show_item": "Ukázať súbor",
"spam_score": "Výsledok",
"subj": "Predmet",

View File

@ -757,7 +757,7 @@
"release_subject": "Potentiellt skadlig karantänsmeddelande %s",
"remove": "Ta bort",
"rspamd_result": "Rspamd resultat",
"sender": "Avsändare",
"sender": "Avsändare (SMTP)",
"show_item": "Visa objekt",
"spam_score": "Betyg",
"subj": "Ämne",

View File

@ -26,6 +26,14 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
<label for="qid_detail_recipients"><h4><?=$lang['quarantine']['recipients'];?>:</h4></label>
<p id="qid_detail_recipients"></p>
</div>
<div class="form-group">
<label for="qid_detail_hfrom"><h4><?=$lang['quarantine']['sender_header'];?>:</h4></label>
<p><span class="mail-address-item" id="qid_detail_hfrom"></span></p>
</div>
<div class="form-group">
<label for="qid_detail_efrom"><h4><?=$lang['quarantine']['sender'];?>:</h4></label>
<p><span class="mail-address-item" id="qid_detail_efrom"></span></p>
</div>
<div class="form-group">
<label for="qid_detail_text"><h4><?=$lang['quarantine']['text_plain_content'];?>:</h4></label>
<pre id="qid_detail_text"></pre>
@ -53,6 +61,9 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
<li role="separator" class="divider"></li>
<li><a data-id="qitems_single" data-item="" onclick="window.open('/inc/ajax/qitem_details.php?id=' + $(this).data('item') + '&eml', '_blank')" href="#"><?=$lang['quarantine']['download_eml'];?></a></li>
<li role="separator" class="divider"></li>
<li><a data-id="qitems_single" data-item="" onclick="window.open('/inc/ajax/qitem_details.php?id=' + $(this).data('item') + '&quick_release', '_blank')" href="#"><?=$lang['quarantine']['quick_release_link'];?></a></li>
<li><a data-id="qitems_single" data-item="" onclick="window.open('/inc/ajax/qitem_details.php?id=' + $(this).data('item') + '&quick_delete', '_blank')" href="#"><?=$lang['quarantine']['quick_delete_link'];?></a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="qitems_single" data-item="" data-api-url='delete/qitem' href="#"><?=$lang['quarantine']['remove'];?></a></li>
</ul>
</div>

View File

@ -1,6 +1,10 @@
<?php
session_start();
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
if (quarantine('hash_details', $_GET['hash']) === false) {
header('Location: /admin');
exit();
}
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/header.inc.php';
if (preg_match("/^([a-f0-9]{64})$/", $_POST['quick_release']) || preg_match("/^([a-f0-9]{64})$/", $_POST['quick_delete'])) {
?>
@ -29,7 +33,29 @@ elseif (in_array($_GET['action'], array('release', 'delete'))) {
<div class="panel panel-default">
<div class="panel-heading"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> <?= $lang['header']['quarantine']; ?></div>
<div class="panel-body">
<legend><?=$lang['quarantine']['release'];?></legend>
<legend data-hash="<?=$_GET['hash'];?>"><?=$lang['quarantine']['release'];?></legend>
<div id="qid_error" style="display:none" class="alert alert-danger"></div>
<div class="form-group">
<label for="qid_detail_symbols"><h4><?=$lang['quarantine']['rspamd_result'];?>:</h4></label>
<p><?=$lang['quarantine']['spam_score'];?>: <span id="qid_detail_score"></span></p>
<p id="qid_detail_symbols"></p>
</div>
<div class="form-group">
<label for="qid_detail_subj"><h4><?=$lang['quarantine']['subj'];?>:</h4></label>
<p id="qid_detail_subj"></p>
</div>
<div class="form-group">
<label for="qid_detail_hfrom"><h4><?=$lang['quarantine']['sender_header'];?>:</h4></label>
<p><span class="mail-address-item" id="qid_detail_hfrom"></span></p>
</div>
<div class="form-group">
<label for="qid_detail_efrom"><h4><?=$lang['quarantine']['sender'];?>:</h4></label>
<p><span class="mail-address-item" id="qid_detail_efrom"></span></p>
</div>
<div class="form-group">
<label for="qid_detail_recipients"><h4><?=$lang['quarantine']['recipients'];?>:</h4></label>
<p id="qid_detail_recipients"></p>
</div>
<form method="post" autofill="off">
<div class="form-group">
<button type="submit" class="btn btn-success" name="quick_release" value="<?=$_GET['hash'];?>"><?= $lang['tfa']['confirm']; ?></button>
@ -49,7 +75,29 @@ elseif (in_array($_GET['action'], array('release', 'delete'))) {
<div class="panel panel-default">
<div class="panel-heading"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> <?= $lang['header']['quarantine']; ?></div>
<div class="panel-body">
<legend><?=$lang['quarantine']['remove'];?></legend>
<legend data-hash="<?=$_GET['hash'];?>"><?=$lang['quarantine']['remove'];?></legend>
<div id="qid_error" style="display:none" class="alert alert-danger"></div>
<div class="form-group">
<label for="qid_detail_symbols"><h4><?=$lang['quarantine']['rspamd_result'];?>:</h4></label>
<p><?=$lang['quarantine']['spam_score'];?>: <span id="qid_detail_score"></span></p>
<p id="qid_detail_symbols"></p>
</div>
<div class="form-group">
<label for="qid_detail_subj"><h4><?=$lang['quarantine']['subj'];?>:</h4></label>
<p id="qid_detail_subj"></p>
</div>
<div class="form-group">
<label for="qid_detail_hfrom"><h4><?=$lang['quarantine']['sender_header'];?>:</h4></label>
<p><span class="mail-address-item" id="qid_detail_hfrom"></span></p>
</div>
<div class="form-group">
<label for="qid_detail_efrom"><h4><?=$lang['quarantine']['sender'];?>:</h4></label>
<p><span class="mail-address-item" id="qid_detail_efrom"></span></p>
</div>
<div class="form-group">
<label for="qid_detail_recipients"><h4><?=$lang['quarantine']['recipients'];?>:</h4></label>
<p id="qid_detail_recipients"></p>
</div>
<form method="post" autofill="off">
<div class="form-group">
<button type="submit" class="btn btn-success" name="quick_delete" value="<?=$_GET['hash'];?>"><?= $lang['tfa']['confirm']; ?></button>
@ -64,5 +112,6 @@ elseif (in_array($_GET['action'], array('release', 'delete'))) {
endif;
}
}
$js_minifier->add('/web/js/site/qhandler.js');
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';
?>