From 72f8c0a5bdad505b91f87ed608efb5f1ed6e82d0 Mon Sep 17 00:00:00 2001
From: ntimo <git@nowitzki.me>
Date: Thu, 3 Oct 2019 12:48:19 +0200
Subject: [PATCH 01/18] [API] Added proper status codes to API

---
 data/web/json_api.php | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/data/web/json_api.php b/data/web/json_api.php
index ea4304af..9e38cbec 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!'
@@ -112,9 +113,11 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
             'msg' => 'Task completed'
           ));
           if ($return === false) {
+            http_response_code(200);
             echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_failure;
           }
           else {
+            http_response_code(200);
             echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_success;
           }
         }
@@ -202,6 +205,14 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
         function process_get_return($data) {
           echo (!isset($data) || empty($data)) ? '{}' : json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
         }
+        if ($action != 'get' ) {
+          http_response_code(400);
+          echo json_encode(array(
+              'type' => 'error',
+              'msg' => 'Only GET method is allowed!'
+          ));
+          exit
+        }
         switch ($category) {
           case "rspamd":
             switch ($object) {
@@ -1042,9 +1053,11 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
             'msg' => 'Task completed'
           ));
           if ($return === false) {
+            http_response_code(200);
             echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_failure;
           }
           else {
+            http_response_code(200);
             echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_success;
           }
         }
@@ -1148,9 +1161,11 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
             'msg' => 'Task completed'
           ));
           if ($return === false) {
+            http_response_code(200);
             echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_failure;
           }
           else {
+            http_response_code(200);
             echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_success;
           }
         }
@@ -1273,6 +1288,14 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
           break;
         }
       break;
+      default;
+        http_response_code(404);
+        echo json_encode(array(
+          'type' => 'error',
+          'msg' => 'route not found'
+        ));
+        unset($_POST);
+        die();
     }
   }
 }

From 796853cae5eab2920da550a1c52e6b35bcda0c24 Mon Sep 17 00:00:00 2001
From: ntimo <git@nowitzki.me>
Date: Thu, 3 Oct 2019 12:50:58 +0200
Subject: [PATCH 02/18] [API] Replace exit with die();

---
 data/web/json_api.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/data/web/json_api.php b/data/web/json_api.php
index 9e38cbec..66a839b1 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -211,7 +211,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               'type' => 'error',
               'msg' => 'Only GET method is allowed!'
           ));
-          exit
+          die();
         }
         switch ($category) {
           case "rspamd":

From c67e86756ff0b2e738d96b4223992912108752b5 Mon Sep 17 00:00:00 2001
From: ntimo <git@nowitzki.me>
Date: Thu, 3 Oct 2019 12:54:06 +0200
Subject: [PATCH 03/18] [API] Better check for GET method

---
 data/web/json_api.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/data/web/json_api.php b/data/web/json_api.php
index 66a839b1..90dce751 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -205,7 +205,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
         function process_get_return($data) {
           echo (!isset($data) || empty($data)) ? '{}' : json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
         }
-        if ($action != 'get' ) {
+        if ($_SERVER['REQUEST_METHOD'] === 'GET') {
           http_response_code(400);
           echo json_encode(array(
               'type' => 'error',

From 948137b4b4bbe0500af14d063cd5ab1648d27952 Mon Sep 17 00:00:00 2001
From: ntimo <git@nowitzki.me>
Date: Thu, 3 Oct 2019 12:56:01 +0200
Subject: [PATCH 04/18] [API] Fixed only allow GET logic

---
 data/web/json_api.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/data/web/json_api.php b/data/web/json_api.php
index 90dce751..852c2dec 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -205,7 +205,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
         function process_get_return($data) {
           echo (!isset($data) || empty($data)) ? '{}' : json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
         }
-        if ($_SERVER['REQUEST_METHOD'] === 'GET') {
+        if ($_SERVER['REQUEST_METHOD'] != 'GET') {
           http_response_code(400);
           echo json_encode(array(
               'type' => 'error',

From f3930492736f67b469e97b89890de9523d86ef77 Mon Sep 17 00:00:00 2001
From: ntimo <git@nowitzki.me>
Date: Thu, 3 Oct 2019 14:36:10 +0200
Subject: [PATCH 05/18] [API] Make add and delete routes POST only

---
 data/web/json_api.php | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/data/web/json_api.php b/data/web/json_api.php
index 852c2dec..5f3b0ea5 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -129,6 +129,12 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
           $attr = (array)json_decode($_POST['attr'], true);
           unset($attr['csrf_token']);
         }
+        if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+          http_response_code(405);
+          echo json_encode(array(
+              'type' => 'error',
+              'msg' => 'Only POST method is allowed!'
+          ));
         switch ($category) {
           case "time_limited_alias":
             process_add_return(mailbox('add', 'time_limited_alias', $attr));
@@ -206,7 +212,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
           echo (!isset($data) || empty($data)) ? '{}' : json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
         }
         if ($_SERVER['REQUEST_METHOD'] != 'GET') {
-          http_response_code(400);
+          http_response_code(405);
           echo json_encode(array(
               'type' => 'error',
               'msg' => 'Only GET method is allowed!'
@@ -1068,6 +1074,12 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
         else {
           $items = (array)json_decode($_POST['items'], true);
         }
+        if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+          http_response_code(405);
+          echo json_encode(array(
+              'type' => 'error',
+              'msg' => 'Only POST method is allowed!'
+          ));
         switch ($category) {
           case "alias":
             process_delete_return(mailbox('delete', 'alias', array('id' => $items)));

From c4c9d2a3b4d3f5e5789a04c593f133a697b5601c Mon Sep 17 00:00:00 2001
From: ntimo <git@nowitzki.me>
Date: Thu, 3 Oct 2019 14:39:38 +0200
Subject: [PATCH 06/18] [API] Fixed broken if

---
 data/web/json_api.php | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/data/web/json_api.php b/data/web/json_api.php
index 5f3b0ea5..e5643dc5 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -135,6 +135,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               'type' => 'error',
               'msg' => 'Only POST method is allowed!'
           ));
+        }
         switch ($category) {
           case "time_limited_alias":
             process_add_return(mailbox('add', 'time_limited_alias', $attr));
@@ -1080,6 +1081,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               'type' => 'error',
               'msg' => 'Only POST method is allowed!'
           ));
+        }
         switch ($category) {
           case "alias":
             process_delete_return(mailbox('delete', 'alias', array('id' => $items)));

From 877c48db58696cc2ba3a9890a7d18dd0ed58f606 Mon Sep 17 00:00:00 2001
From: ntimo <git@nowitzki.me>
Date: Thu, 3 Oct 2019 14:42:30 +0200
Subject: [PATCH 07/18] [API] Added missing die()

---
 data/web/json_api.php | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/data/web/json_api.php b/data/web/json_api.php
index e5643dc5..d358a619 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -135,6 +135,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               'type' => 'error',
               'msg' => 'Only POST method is allowed!'
           ));
+          die();
         }
         switch ($category) {
           case "time_limited_alias":
@@ -1081,6 +1082,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               'type' => 'error',
               'msg' => 'Only POST method is allowed!'
           ));
+          die();
         }
         switch ($category) {
           case "alias":

From ab298741e3ad2a12297096b13403f9df846ef4f3 Mon Sep 17 00:00:00 2001
From: ntimo <git@nowitzki.me>
Date: Thu, 3 Oct 2019 15:04:25 +0200
Subject: [PATCH 08/18] [API] Added comments

---
 data/web/json_api.php | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/data/web/json_api.php b/data/web/json_api.php
index d358a619..2be9dbdb 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -129,11 +129,12 @@ 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!'
+              'msg' => 'only POST method is allowed'
           ));
           die();
         }
@@ -213,11 +214,12 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
         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!'
+              'msg' => 'only GET method is allowed'
           ));
           die();
         }
@@ -1076,11 +1078,12 @@ 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!'
+              'msg' => 'only POST method is allowed'
           ));
           die();
         }
@@ -1304,6 +1307,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
           break;
         }
       break;
+      // return no route found if no case is matched
       default;
         http_response_code(404);
         echo json_encode(array(

From 416d5a12f8e55cef0c83b0a959dc407af250c0fb Mon Sep 17 00:00:00 2001
From: ntimo <git@nowitzki.me>
Date: Thu, 3 Oct 2019 15:06:08 +0200
Subject: [PATCH 09/18] [API] Unset POST when only GET is allowed

---
 data/web/json_api.php | 1 +
 1 file changed, 1 insertion(+)

diff --git a/data/web/json_api.php b/data/web/json_api.php
index 2be9dbdb..64d6304b 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -221,6 +221,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               'type' => 'error',
               'msg' => 'only GET method is allowed'
           ));
+          unset($_POST);
           die();
         }
         switch ($category) {

From 5fa456770f054f9312163f002e42457ad372bd25 Mon Sep 17 00:00:00 2001
From: ntimo <git@nowitzki.me>
Date: Thu, 3 Oct 2019 17:25:56 +0200
Subject: [PATCH 10/18] [API] Removed hard coded status code 200

---
 data/web/json_api.php | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/data/web/json_api.php b/data/web/json_api.php
index 64d6304b..46e65519 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -113,11 +113,9 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
             'msg' => 'Task completed'
           ));
           if ($return === false) {
-            http_response_code(200);
             echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_failure;
           }
           else {
-            http_response_code(200);
             echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_success;
           }
         }
@@ -1064,11 +1062,9 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
             'msg' => 'Task completed'
           ));
           if ($return === false) {
-            http_response_code(200);
             echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_failure;
           }
           else {
-            http_response_code(200);
             echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_success;
           }
         }
@@ -1181,11 +1177,9 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
             'msg' => 'Task completed'
           ));
           if ($return === false) {
-            http_response_code(200);
             echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_failure;
           }
           else {
-            http_response_code(200);
             echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_success;
           }
         }

From b9c244b746f79b148d919174cc5c6f8d4b857f97 Mon Sep 17 00:00:00 2001
From: ntimo <git@nowitzki.me>
Date: Thu, 3 Oct 2019 18:14:27 +0200
Subject: [PATCH 11/18] [API] Only allow POST method for edit apis

---
 data/web/json_api.php | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/data/web/json_api.php b/data/web/json_api.php
index 46e65519..88fa3fdb 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -1192,6 +1192,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'
+          ));
+          die();
+        }
         switch ($category) {
           case "bcc":
             process_edit_return(bcc('edit', array_merge(array('id' => $items), $attr)));

From 2da55296b5eaed48bf4264b0a94fbfa6de6251c2 Mon Sep 17 00:00:00 2001
From: ntimo <git@nowitzki.me>
Date: Thu, 3 Oct 2019 20:52:09 +0200
Subject: [PATCH 12/18] [API] Catch more cases where no api route exists

---
 data/web/json_api.php | 34 +++++++++++++++++++++++++++++++---
 1 file changed, 31 insertions(+), 3 deletions(-)

diff --git a/data/web/json_api.php b/data/web/json_api.php
index 88fa3fdb..63da426c 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -206,6 +206,14 @@ 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;
+          default:
+            http_response_code(404);
+            echo json_encode(array(
+              'type' => 'error',
+              'msg' => 'route not found'
+            ));
+            unset($_POST);
+            die();
         }
       break;
       case "get":
@@ -1047,8 +1055,12 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
             }
           break;
           default:
-            echo '{}';
-          break;
+            http_response_code(404);
+            echo json_encode(array(
+              'type' => 'error',
+              'msg' => 'route not found'
+            ));
+            die();
         }
       break;
       case "delete":
@@ -1164,6 +1176,14 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
           case "rlhash":
             echo ratelimit('delete', null, implode($items));
           break;
+          default:
+            http_response_code(404);
+            echo json_encode(array(
+              'type' => 'error',
+              'msg' => 'route not found'
+            ));
+            unset($_POST);
+            die();
         }
       break;
       case "edit":
@@ -1309,10 +1329,18 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               process_edit_return(edit_user_account($attr));
             }
           break;
+          default:
+            http_response_code(404);
+            echo json_encode(array(
+              'type' => 'error',
+              'msg' => 'route not found'
+            ));
+            unset($_POST);
+            die();
         }
       break;
       // return no route found if no case is matched
-      default;
+      default:
         http_response_code(404);
         echo json_encode(array(
           'type' => 'error',

From 08350d9a95ffa9c3d8ac445c275bca6a1c581fba Mon Sep 17 00:00:00 2001
From: ntimo <git@nowitzki.me>
Date: Thu, 3 Oct 2019 20:58:56 +0200
Subject: [PATCH 13/18] [API] Added missing route not found error for
 /get/logs/

---
 data/web/json_api.php | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/data/web/json_api.php b/data/web/json_api.php
index 63da426c..7dd7feaa 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -589,6 +589,13 @@ 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;
+              default:
+                http_response_code(404);
+                echo json_encode(array(
+                  'type' => 'error',
+                  'msg' => 'route not found'
+                ));
+                die();
             }
           break;
           case "mailbox":

From 6372df21feb51d783cdbd9bf0aff6f1f645e85b6 Mon Sep 17 00:00:00 2001
From: ntimo <git@nowitzki.me>
Date: Fri, 4 Oct 2019 08:37:30 +0200
Subject: [PATCH 14/18] [API] Replaced die(); with exit(); due to code
 conventions

---
 data/web/json_api.php | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/data/web/json_api.php b/data/web/json_api.php
index 7dd7feaa..0753c74a 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -134,7 +134,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               'type' => 'error',
               'msg' => 'only POST method is allowed'
           ));
-          die();
+          exit();
         }
         switch ($category) {
           case "time_limited_alias":
@@ -213,7 +213,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               'msg' => 'route not found'
             ));
             unset($_POST);
-            die();
+            exit();
         }
       break;
       case "get":
@@ -228,7 +228,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               'msg' => 'only GET method is allowed'
           ));
           unset($_POST);
-          die();
+          exit();
         }
         switch ($category) {
           case "rspamd":
@@ -595,7 +595,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
                   'type' => 'error',
                   'msg' => 'route not found'
                 ));
-                die();
+                exit();
             }
           break;
           case "mailbox":
@@ -1067,7 +1067,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               'type' => 'error',
               'msg' => 'route not found'
             ));
-            die();
+            exit();
         }
       break;
       case "delete":
@@ -1101,7 +1101,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               'type' => 'error',
               'msg' => 'only POST method is allowed'
           ));
-          die();
+          exit();
         }
         switch ($category) {
           case "alias":
@@ -1190,7 +1190,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               'msg' => 'route not found'
             ));
             unset($_POST);
-            die();
+            exit();
         }
       break;
       case "edit":
@@ -1226,7 +1226,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               'type' => 'error',
               'msg' => 'only POST method is allowed'
           ));
-          die();
+          exit();
         }
         switch ($category) {
           case "bcc":
@@ -1343,7 +1343,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               'msg' => 'route not found'
             ));
             unset($_POST);
-            die();
+            exit();
         }
       break;
       // return no route found if no case is matched
@@ -1354,7 +1354,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
           'msg' => 'route not found'
         ));
         unset($_POST);
-        die();
+        exit();
     }
   }
 }

From 2c7e9f49d5a8a153107e7c311f17258dd4407e63 Mon Sep 17 00:00:00 2001
From: ntimo <git@nowitzki.me>
Date: Fri, 4 Oct 2019 09:01:31 +0200
Subject: [PATCH 15/18] [API] Added comments to defaults

---
 data/web/json_api.php | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/data/web/json_api.php b/data/web/json_api.php
index 0753c74a..0efc0bcd 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -206,6 +206,7 @@ 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(
@@ -589,6 +590,7 @@ 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(
@@ -1061,6 +1063,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
                   break;
             }
           break;
+          // return no route found if no case is matched
           default:
             http_response_code(404);
             echo json_encode(array(
@@ -1183,6 +1186,7 @@ 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(
@@ -1336,6 +1340,7 @@ 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(

From 8a87dd4254a0e6694041a307d6edd35d80c6700b Mon Sep 17 00:00:00 2001
From: ntimo <git@nowitzki.me>
Date: Sat, 5 Oct 2019 18:14:36 +0200
Subject: [PATCH 16/18] [API] Removed unsets that are not needed

---
 data/web/json_api.php | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/data/web/json_api.php b/data/web/json_api.php
index 0efc0bcd..4c490c0d 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -213,7 +213,6 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               'type' => 'error',
               'msg' => 'route not found'
             ));
-            unset($_POST);
             exit();
         }
       break;
@@ -228,7 +227,6 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               'type' => 'error',
               'msg' => 'only GET method is allowed'
           ));
-          unset($_POST);
           exit();
         }
         switch ($category) {
@@ -1193,7 +1191,6 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               'type' => 'error',
               'msg' => 'route not found'
             ));
-            unset($_POST);
             exit();
         }
       break;
@@ -1347,7 +1344,6 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               'type' => 'error',
               'msg' => 'route not found'
             ));
-            unset($_POST);
             exit();
         }
       break;
@@ -1358,7 +1354,6 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
           'type' => 'error',
           'msg' => 'route not found'
         ));
-        unset($_POST);
         exit();
     }
   }

From af13ae455cdc62a6f64e9a493768f7a81e8885c6 Mon Sep 17 00:00:00 2001
From: ntimo <git@nowitzki.me>
Date: Tue, 8 Oct 2019 19:30:01 +0200
Subject: [PATCH 17/18] [API] Invalidate session after api call is done

---
 data/web/json_api.php | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/data/web/json_api.php b/data/web/json_api.php
index 4c490c0d..d59cfe56 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -1357,4 +1357,9 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
         exit();
     }
   }
+  if ($_SESSION['mailcow_cc_api'] === true) {
+    if (isset($_SESSION['mailcow_cc_api']) && $_SESSION['mailcow_cc_api'] === true) {
+      unset($_SESSION['return']);
+    }
+  }
 }

From 6fc32e8e526f33a386420604378490dce0d79ec5 Mon Sep 17 00:00:00 2001
From: friedPotat0 <5374007+friedPotat0@users.noreply.github.com>
Date: Wed, 9 Oct 2019 20:18:21 +0200
Subject: [PATCH 18/18] Add option to download quarantine item as eml

---
 data/web/inc/ajax/qitem_details.php | 13 +++++++++++++
 data/web/lang/lang.de.php           |  1 +
 data/web/lang/lang.en.php           |  1 +
 data/web/modals/quarantine.php      |  2 ++
 4 files changed, 17 insertions(+)

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/lang/lang.de.php b/data/web/lang/lang.de.php
index dadfb8de..1ba5c45e 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 <em>nicht</em> signalisiert, dass seine E-Mail zugestellt wurde.
   <br>"' . $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.
   <br>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 efdb80ee..eaa51333 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 <em>not</em> be given the impression of a delivered mail.
   <br>"' . $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.
   <br>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'])) {
             <li role="separator" class="divider"></li>
             <li><a data-action="edit_selected" data-id="qitems_single" data-item="" data-api-url='edit/qitem' data-api-attr='{"action":"learnspam"}' href="#"><?=$lang['quarantine']['learn_spam_delete'];?></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') + '&eml', '_blank')" href="#"><?=$lang['quarantine']['download_eml'];?></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>