From 0df9de30c9aa4d2447407878290e45352fea7d59 Mon Sep 17 00:00:00 2001
From: downtownallday <downtownallday@gmail.com>
Date: Fri, 9 Apr 2021 09:47:07 -0400
Subject: [PATCH] Manage the local Postgrey whitelist in the admin console

---
 management/daemon.py                         | 27 ++++++++++
 management/templates/index.html              |  5 ++
 management/templates/postgrey-whitelist.html | 53 ++++++++++++++++++++
 setup/mail-postfix.sh                        | 12 +++++
 4 files changed, 97 insertions(+)
 create mode 100644 management/templates/postgrey-whitelist.html

diff --git a/management/daemon.py b/management/daemon.py
index 1ccb161a..542443ce 100755
--- a/management/daemon.py
+++ b/management/daemon.py
@@ -645,6 +645,33 @@ def privacy_status_set():
 	utils.write_settings(config, env)
 	return "OK"
 
+@app.route('/system/postgrey-whitelist', methods=["GET","POST"])
+@authorized_personnel_only
+def postgrey_whitelist_handler():
+	conf_file="/etc/postgrey/whitelist_clients.local"
+	if request.method == "GET":
+		contents = ""
+		try:
+			with open(conf_file) as fp:
+				contents = fp.read()
+		except FileNotFoundError:
+			pass
+		return Response(contents, status=200, mimetype='text/plain')
+
+	elif request.method == "POST":
+		try:
+			contents = request.form["contents"]
+			with open(conf_file, "w") as fp:
+				fp.write(contents)
+			utils.shell("check_call", ["/bin/systemctl", "reload", "postgrey"])
+		except KeyError:
+			return ("Missing required parameter", 400)
+		except subprocess.CalledProcessError as e:
+			app.logger.exception(e)
+			return ("Postgrey reload failed", 500)
+
+		return "OK. Saved and Postgrey reloaded."
+
 # MUNIN
 
 @app.route('/munin/')
diff --git a/management/templates/index.html b/management/templates/index.html
index 35be0616..6ff38725 100644
--- a/management/templates/index.html
+++ b/management/templates/index.html
@@ -94,6 +94,7 @@
                 <li><a href="#custom_dns" onclick="return show_panel(this);">Custom DNS</a></li>
                 <li><a href="#external_dns" onclick="return show_panel(this);">External DNS</a></li>
                 <li><a href="/admin/munin" target="_blank">Munin Monitoring</a></li>
+                <li><a href="#postgrey_whitelist" onclick="return show_panel(this);">Postgrey whitelist</a></li>
               </ul>
             </li>
             <li class="dropdown">
@@ -135,6 +136,10 @@
       {% include "custom-dns.html" %}
       </div>
 
+      <div id="panel_postgrey_whitelist" class="admin_panel">
+      {% include "postgrey-whitelist.html" %}
+      </div>
+
       <div id="panel_mfa" class="admin_panel">
       {% include "mfa.html" %}
       </div>
diff --git a/management/templates/postgrey-whitelist.html b/management/templates/postgrey-whitelist.html
new file mode 100644
index 00000000..9b41e1f6
--- /dev/null
+++ b/management/templates/postgrey-whitelist.html
@@ -0,0 +1,53 @@
+<style>
+</style>
+
+<h2>Postgrey Whitelist</h2>
+
+<p>The text box below contains the contents of the system's Postgrey local client whitelist. It's comprised of a list of <em>hosts</em>, one per line, whose incoming email to this server should never be greylisted.</p>
+
+<p>Entries may be a fully qualified domain name, an IP address, or a regular expression. Regular expressions begin and end with the character "/".</p>
+
+<p>This file augments the whilelist provided by Postgrey.</p>
+
+<textarea style="width:100%; height:12em" id="postgrey_whitelist"></textarea>
+
+<button class="btn-success" onclick="save_postgrey_whitelist()">Save</button>
+
+<script>
+
+function show_postgrey_whitelist() {
+    get_postgrey_whitelist();
+}
+
+function get_postgrey_whitelist() {
+    api(
+        "/system/postgrey-whitelist",
+        "GET",
+        { },
+        function(whitelist) {
+            var e = document.getElementById('postgrey_whitelist');
+            e.value = whitelist
+        }
+    );
+}
+
+function save_postgrey_whitelist() {
+    var e = document.getElementById('postgrey_whitelist');
+    api(
+        "/system/postgrey-whitelist",
+        "POST",
+        {
+            contents: e.value
+        },
+        function(data) {
+            if (data == "")
+                data = "Nothing changed.";
+            else
+                data = $("<pre/>").text(data);
+            show_modal_error("Postgrey Whitelist Update", data, function() {
+                get_postgrey_whitelist();
+            });
+        });
+}
+
+</script>
diff --git a/setup/mail-postfix.sh b/setup/mail-postfix.sh
index 91dc30be..2f2385be 100755
--- a/setup/mail-postfix.sh
+++ b/setup/mail-postfix.sh
@@ -267,6 +267,18 @@ EOF
 chmod +x /etc/cron.daily/mailinabox-postgrey-whitelist
 /etc/cron.daily/mailinabox-postgrey-whitelist
 
+# keep the postgrey local client whitelist file in STORAGE_ROOT so it
+# gets backed up
+mkdir -p "$STORAGE_ROOT/mail/postgrey"
+if [ ! -L "/etc/postgrey/whitelist_clients.local" ] && [ -f "/etc/postgrey/whitelist_clients.local" ]; then
+    # regular file (non-link) exists - move it to user-data
+    cp -p "/etc/postgrey/whitelist_clients.local" \
+          "$STORAGE_ROOT/mail/postgrey/whitelist_clients.local"
+fi
+ln -sf "$STORAGE_ROOT/mail/postgrey/whitelist_clients.local" \
+       "/etc/postgrey/whitelist_clients.local"
+
+
 # Increase the message size limit from 10MB to 128MB.
 # The same limit is specified in nginx.conf for mail submitted via webmail and Z-Push.
 tools/editconf.py /etc/postfix/main.cf \