diff --git a/data/web/inc/ajax/qitem_details.php b/data/web/inc/ajax/qitem_details.php
index 3c82ee6a..06feb1e7 100644
--- a/data/web/inc/ajax/qitem_details.php
+++ b/data/web/inc/ajax/qitem_details.php
@@ -91,6 +91,19 @@ if (!empty($_GET['id']) && ctype_alnum($_GET['id'])) {
);
}
}
+ if (isset($_GET['eml'])) {
+ $dl_filename = str_replace('/', '_', $data['subject']);
+ header('Pragma: public');
+ header('Expires: 0');
+ header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+ header('Cache-Control: private', false);
+ header('Content-Type: message/rfc822');
+ header('Content-Disposition: attachment; filename="'. $dl_filename . '.eml";');
+ header('Content-Transfer-Encoding: binary');
+ header('Content-Length: ' . strlen($mailc['msg']));
+ echo $mailc['msg'];
+ exit;
+ }
if (isset($_GET['att'])) {
if ($_SESSION['acl']['quarantine_attachments'] == 0) {
exit(json_encode('Forbidden'));
diff --git a/data/web/json_api.php b/data/web/json_api.php
index ea4304af..d59cfe56 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -69,6 +69,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
// check for valid json
if ($action != 'get' && $requestDecoded === null) {
+ http_response_code(400);
echo json_encode(array(
'type' => 'error',
'msg' => 'Request body doesn\'t contain valid json!'
@@ -126,6 +127,15 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
$attr = (array)json_decode($_POST['attr'], true);
unset($attr['csrf_token']);
}
+ // only allow POST requests to POST API endpoints
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ http_response_code(405);
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'only POST method is allowed'
+ ));
+ exit();
+ }
switch ($category) {
case "time_limited_alias":
process_add_return(mailbox('add', 'time_limited_alias', $attr));
@@ -196,12 +206,29 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
case "tls-policy-map":
process_add_return(tls_policy_maps('add', $attr));
break;
+ // return no route found if no case is matched
+ default:
+ http_response_code(404);
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'route not found'
+ ));
+ exit();
}
break;
case "get":
function process_get_return($data) {
echo (!isset($data) || empty($data)) ? '{}' : json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
+ // only allow GET requests to GET API endpoints
+ if ($_SERVER['REQUEST_METHOD'] != 'GET') {
+ http_response_code(405);
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'only GET method is allowed'
+ ));
+ exit();
+ }
switch ($category) {
case "rspamd":
switch ($object) {
@@ -561,6 +588,14 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
}
echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
break;
+ // return no route found if no case is matched
+ default:
+ http_response_code(404);
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'route not found'
+ ));
+ exit();
}
break;
case "mailbox":
@@ -1026,9 +1061,14 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
break;
}
break;
+ // return no route found if no case is matched
default:
- echo '{}';
- break;
+ http_response_code(404);
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'route not found'
+ ));
+ exit();
}
break;
case "delete":
@@ -1055,6 +1095,15 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
else {
$items = (array)json_decode($_POST['items'], true);
}
+ // only allow POST requests to POST API endpoints
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ http_response_code(405);
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'only POST method is allowed'
+ ));
+ exit();
+ }
switch ($category) {
case "alias":
process_delete_return(mailbox('delete', 'alias', array('id' => $items)));
@@ -1135,6 +1184,14 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
case "rlhash":
echo ratelimit('delete', null, implode($items));
break;
+ // return no route found if no case is matched
+ default:
+ http_response_code(404);
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'route not found'
+ ));
+ exit();
}
break;
case "edit":
@@ -1163,6 +1220,15 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
unset($attr['csrf_token']);
$items = isset($_POST['items']) ? (array)json_decode($_POST['items'], true) : null;
}
+ // only allow POST requests to POST API endpoints
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ http_response_code(405);
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'only POST method is allowed'
+ ));
+ exit();
+ }
switch ($category) {
case "bcc":
process_edit_return(bcc('edit', array_merge(array('id' => $items), $attr)));
@@ -1271,8 +1337,29 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
process_edit_return(edit_user_account($attr));
}
break;
+ // return no route found if no case is matched
+ default:
+ http_response_code(404);
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'route not found'
+ ));
+ exit();
}
break;
+ // return no route found if no case is matched
+ default:
+ http_response_code(404);
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'route not found'
+ ));
+ exit();
+ }
+ }
+ if ($_SESSION['mailcow_cc_api'] === true) {
+ if (isset($_SESSION['mailcow_cc_api']) && $_SESSION['mailcow_cc_api'] === true) {
+ unset($_SESSION['return']);
}
}
}
diff --git a/data/web/lang/lang.de.php b/data/web/lang/lang.de.php
index 4e2ee972..71b86e0a 100644
--- a/data/web/lang/lang.de.php
+++ b/data/web/lang/lang.de.php
@@ -777,6 +777,7 @@ $lang['quarantine']['quarantine'] = "Quarantäne";
$lang['quarantine']['qinfo'] = 'Das Quarantänesystem speichert abgelehnte Nachrichten in der Datenbank. Dem Sender wird nicht signalisiert, dass seine E-Mail zugestellt wurde.
"' . $lang['quarantine']['learn_spam_delete'] . '" lernt Nachrichten nach bayesscher Statistik als Spam und erstellt Fuzzy Hashes ausgehend von der jeweiligen Nachricht, um ähnliche Inhalte zukünftig zu unterbinden.
Der Prozess des Lernens kann abhängig vom System zeitintensiv sein.';
+$lang['quarantine']['download_eml'] = "Herunterladen (.eml)";
$lang['quarantine']['release'] = "Freigeben";
$lang['quarantine']['empty'] = 'Keine Einträge';
$lang['quarantine']['toggle_all'] = 'Alle auswählen';
diff --git a/data/web/lang/lang.en.php b/data/web/lang/lang.en.php
index ad288ca7..1e6e7fd4 100644
--- a/data/web/lang/lang.en.php
+++ b/data/web/lang/lang.en.php
@@ -794,6 +794,7 @@ $lang['quarantine']['learn_spam_delete'] = "Learn as spam and delete";
$lang['quarantine']['qinfo'] = 'The quarantine system will save rejected mail to the database, while the sender will not be given the impression of a delivered mail.
"' . $lang['quarantine']['learn_spam_delete'] . '" will learn a message as spam via Bayesian theorem and also calculate fuzzy hashes to deny similar messages in the future.
Please be aware that learning multiple messages can be - depending on your system - time consuming.';
+$lang['quarantine']['download_eml'] = "Download (.eml)";
$lang['quarantine']['release'] = "Release";
$lang['quarantine']['empty'] = 'No results';
$lang['quarantine']['toggle_all'] = 'Toggle all';
diff --git a/data/web/modals/quarantine.php b/data/web/modals/quarantine.php
index 0d091163..98871fa3 100644
--- a/data/web/modals/quarantine.php
+++ b/data/web/modals/quarantine.php
@@ -46,6 +46,8 @@ if (!isset($_SESSION['mailcow_cc_role'])) {