浏览代码

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

andryyy 5 年之前
父节点
当前提交
b93371ca0a

+ 57 - 5
data/web/inc/ajax/qitem_details.php

@@ -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

+ 33 - 10
data/web/inc/functions.quarantine.inc.php

@@ -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;
   }
 }

+ 1 - 1
data/web/inc/header.inc.php

@@ -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'])) {

+ 52 - 0
data/web/js/site/qhandler.js

@@ -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);
+        });
+      }
+    }
+  });
+});

+ 2 - 1
data/web/js/site/quarantine.js

@@ -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') {

+ 1 - 1
data/web/lang/lang.ca.json

@@ -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)",

+ 1 - 1
data/web/lang/lang.cs.json

@@ -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",

+ 4 - 1
data/web/lang/lang.de.json

@@ -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",

+ 4 - 1
data/web/lang/lang.en.json

@@ -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",

+ 1 - 1
data/web/lang/lang.es.json

@@ -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",

+ 1 - 1
data/web/lang/lang.fi.json

@@ -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",

+ 1 - 1
data/web/lang/lang.lv.json

@@ -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)",

+ 1 - 1
data/web/lang/lang.nl.json

@@ -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",

+ 1 - 1
data/web/lang/lang.ro.json

@@ -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",

+ 1 - 1
data/web/lang/lang.ru.json

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

+ 1 - 1
data/web/lang/lang.sk.json

@@ -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",

+ 1 - 1
data/web/lang/lang.sv.json

@@ -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",

+ 11 - 0
data/web/modals/quarantine.php

@@ -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>

+ 51 - 2
data/web/qhandler.php

@@ -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';
 ?>