summaryrefslogtreecommitdiff
path: root/hosts/surtr/email
diff options
context:
space:
mode:
Diffstat (limited to 'hosts/surtr/email')
-rw-r--r--hosts/surtr/email/ccert-policy-server/.envrc4
-rw-r--r--hosts/surtr/email/ccert-policy-server/.gitignore2
-rw-r--r--hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py17
-rw-r--r--hosts/surtr/email/ccert-policy-server/poetry.lock169
-rw-r--r--hosts/surtr/email/ccert-policy-server/pyproject.toml36
-rw-r--r--hosts/surtr/email/ccert-policy-server/uv.lock130
-rw-r--r--hosts/surtr/email/default.nix255
7 files changed, 300 insertions, 313 deletions
diff --git a/hosts/surtr/email/ccert-policy-server/.envrc b/hosts/surtr/email/ccert-policy-server/.envrc
new file mode 100644
index 00000000..2c909235
--- /dev/null
+++ b/hosts/surtr/email/ccert-policy-server/.envrc
@@ -0,0 +1,4 @@
1use flake
2
3[[ -d ".venv" ]] || ( uv venv && uv sync )
4. .venv/bin/activate
diff --git a/hosts/surtr/email/ccert-policy-server/.gitignore b/hosts/surtr/email/ccert-policy-server/.gitignore
new file mode 100644
index 00000000..4ccfae70
--- /dev/null
+++ b/hosts/surtr/email/ccert-policy-server/.gitignore
@@ -0,0 +1,2 @@
1.venv
2**/__pycache__
diff --git a/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py b/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py
index 7117eb63..45619fb0 100644
--- a/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py
+++ b/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py
@@ -28,12 +28,14 @@ class PolicyHandler(StreamRequestHandler):
28 28
29 allowed = False 29 allowed = False
30 user = None 30 user = None
31 relay_eligible = False
31 if self.args['sasl_username']: 32 if self.args['sasl_username']:
32 user = self.args['sasl_username'] 33 user = self.args['sasl_username']
33 if self.args['ccert_subject']: 34 if self.args['ccert_subject']:
34 user = self.args['ccert_subject'] 35 user = self.args['ccert_subject']
36 relay_eligible = True
35 37
36 if user: 38 if user and '@' in self.args['sender']:
37 with self.server.db_pool.connection() as conn: 39 with self.server.db_pool.connection() as conn:
38 local, domain = self.args['sender'].split(sep='@', maxsplit=1) 40 local, domain = self.args['sender'].split(sep='@', maxsplit=1)
39 extension = None 41 extension = None
@@ -44,9 +46,16 @@ class PolicyHandler(StreamRequestHandler):
44 46
45 with conn.cursor() as cur: 47 with conn.cursor() as cur:
46 cur.row_factory = namedtuple_row 48 cur.row_factory = namedtuple_row
47 cur.execute('SELECT EXISTS(SELECT true FROM "mailbox" INNER JOIN "mailbox_mapping" ON "mailbox".id = "mailbox_mapping"."mailbox" WHERE "mailbox"."mailbox" = %(user)s AND ("local" = %(local)s OR "local" IS NULL) AND ("extension" = %(extension)s OR "extension" IS NULL) AND "domain" = %(domain)s) as "exists"', params = {'user': user, 'local': local, 'extension': extension if extension is not None else '', 'domain': domain}, prepare=True) 49
48 if (row := cur.fetchone()) is not None: 50 if relay_eligible:
49 allowed = row.exists 51 cur.execute('SELECT EXISTS(SELECT true FROM "mailbox" INNER JOIN "relay_access" ON "mailbox".id = "relay_access"."mailbox" WHERE "mailbox"."mailbox" = %(user)s AND ("domain" = %(domain)s OR %(domain)s ilike CONCAT(\'%%_.\', "domain"))) as "exists"', params = {'user': user, 'domain': domain})
52 if (row := cur.fetchone()) is not None:
53 allowed = row.exists
54
55 if not allowed:
56 cur.execute('SELECT EXISTS(SELECT true FROM "mailbox" INNER JOIN "mailbox_mapping" ON "mailbox".id = "mailbox_mapping"."mailbox" WHERE "mailbox"."mailbox" = %(user)s AND ("local" = %(local)s OR "local" IS NULL) AND ("extension" = %(extension)s OR "extension" IS NULL) AND "domain" = %(domain)s) as "exists"', params = {'user': user, 'local': local, 'extension': extension if extension is not None else '', 'domain': domain}, prepare=True)
57 if (row := cur.fetchone()) is not None:
58 allowed = row.exists
50 59
51 action = '550 5.7.0 Sender address not authorized for current user' 60 action = '550 5.7.0 Sender address not authorized for current user'
52 if allowed: 61 if allowed:
diff --git a/hosts/surtr/email/ccert-policy-server/poetry.lock b/hosts/surtr/email/ccert-policy-server/poetry.lock
deleted file mode 100644
index acd354e8..00000000
--- a/hosts/surtr/email/ccert-policy-server/poetry.lock
+++ /dev/null
@@ -1,169 +0,0 @@
1# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand.
2
3[[package]]
4name = "psycopg"
5version = "3.1.8"
6description = "PostgreSQL database adapter for Python"
7category = "main"
8optional = false
9python-versions = ">=3.7"
10files = [
11 {file = "psycopg-3.1.8-py3-none-any.whl", hash = "sha256:b1500c42063abaa01d30b056f0b300826b8dd8d586900586029a294ce74af327"},
12 {file = "psycopg-3.1.8.tar.gz", hash = "sha256:59b4a71536b146925513c0234dfd1dc42b81e65d56ce5335dff4813434dbc113"},
13]
14
15[package.dependencies]
16typing-extensions = ">=4.1"
17tzdata = {version = "*", markers = "sys_platform == \"win32\""}
18
19[package.extras]
20binary = ["psycopg-binary (>=3.1.6,<=3.1.8)"]
21c = ["psycopg-c (>=3.1.6,<=3.1.8)"]
22dev = ["black (>=22.3.0)", "dnspython (>=2.1)", "flake8 (>=4.0)", "mypy (>=0.990)", "types-setuptools (>=57.4)", "wheel (>=0.37)"]
23docs = ["Sphinx (>=5.0)", "furo (==2022.6.21)", "sphinx-autobuild (>=2021.3.14)", "sphinx-autodoc-typehints (>=1.12)"]
24pool = ["psycopg-pool"]
25test = ["mypy (>=0.990)", "pproxy (>=2.7)", "pytest (>=6.2.5)", "pytest-asyncio (>=0.17)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.5)"]
26
27[[package]]
28name = "psycopg-binary"
29version = "3.1.8"
30description = "PostgreSQL database adapter for Python -- C optimisation distribution"
31category = "main"
32optional = false
33python-versions = ">=3.7"
34files = [
35 {file = "psycopg_binary-3.1.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f32684b4fc3863190c4b9c141342b2cbdb81632731b9c68e6946d772ba0560f2"},
36 {file = "psycopg_binary-3.1.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37212244817b3cc7193ee4b5d60765c020ead5e53589c935d249bfb96452878b"},
37 {file = "psycopg_binary-3.1.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32f2563db6e44372f593a76c94452ce476306e0fb508e092f3fab4d9091a9974"},
38 {file = "psycopg_binary-3.1.8-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b36fcc67d8b23935ee871a6331c9631ecfdb11452a64f34b8ecb9642de43aec8"},
39 {file = "psycopg_binary-3.1.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8bb9f577a09e799322008e574a1671c5b2645e990f954be2b7dae669e3779750"},
40 {file = "psycopg_binary-3.1.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ac81e68262b03163ca977f34448b4cadbc49db929146406b4706fe2141d76d1"},
41 {file = "psycopg_binary-3.1.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fbfc9ae4edfb76c14d09bd70d6f399eb935008bbb3bc4cd6a4ab76645ba3443e"},
42 {file = "psycopg_binary-3.1.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8602836138bc209aa5f9821c8e8439466f151c3ec4fcdbc740697e49cff1b920"},
43 {file = "psycopg_binary-3.1.8-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:9cf94411f5a9064cf4ab1066976a7bce44f970f9603a01585c1040465eb312f9"},
44 {file = "psycopg_binary-3.1.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a8fee8d846f9614331bd764850b4c1363730d36e88e14aa28ec4639318fd2093"},
45 {file = "psycopg_binary-3.1.8-cp310-cp310-win_amd64.whl", hash = "sha256:2d5ae85c6037e45862e304d39ec24a24ddebc7d2b5b3601155dddc07c19c0cdc"},
46 {file = "psycopg_binary-3.1.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17d187743d8ca63d24fa724bfee76e50b6473f1fef998cebcd35348b0d5936de"},
47 {file = "psycopg_binary-3.1.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3762e73b6743139c5258d8b3a294edb309c691ba4f172c9f272315501390e7c2"},
48 {file = "psycopg_binary-3.1.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87973d064a72bc2716309381b713f49f57c48100fb1f046943b780a04bc011f6"},
49 {file = "psycopg_binary-3.1.8-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f8400d400f64f659a897d1ef67212012524cc44882bd24387515df9bb723364"},
50 {file = "psycopg_binary-3.1.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f45766ce8e74eb456d8672116e936391e67290c50fd0cc1b41876b61261869b6"},
51 {file = "psycopg_binary-3.1.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33ecf37c6348232073ea62b0630655479021f855635f72b4170693032993cdaf"},
52 {file = "psycopg_binary-3.1.8-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:10b8f1f96f5e8f02a60ba76dab315d3e71cb76c18ff49aa18bbf48a8089c3202"},
53 {file = "psycopg_binary-3.1.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:58cb0d007768dbccb67783baacf1c4016c7be8a494339a514321edee3d3b787a"},
54 {file = "psycopg_binary-3.1.8-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:59d8dbea1bc3dbbc819c0320cb2b641dc362389b096098c62172f49605f58284"},
55 {file = "psycopg_binary-3.1.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4325cee1641c25719bcf063f7683e909cb8cc9932ace3f8bf20ce112e47ce743"},
56 {file = "psycopg_binary-3.1.8-cp311-cp311-win_amd64.whl", hash = "sha256:064502d191d7bc32a48670cc605ce49abcdb5e01e2697ee3fe546cff330fb8ae"},
57 {file = "psycopg_binary-3.1.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5fd8492931865cc7181169b2dbf472377a5b5808f001e73f5c25b05bb61e9622"},
58 {file = "psycopg_binary-3.1.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4d1a4ea2ca20f0bc944bc28e4addb80e6a22ac60a85fc7035e57c88e96f3a18"},
59 {file = "psycopg_binary-3.1.8-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c27be5ddf4a05146ae7fb8429e9367dad0dc278a7d0e2f5094dd533195c4f8a1"},
60 {file = "psycopg_binary-3.1.8-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa8ca48a35be0f9880ed2093c213f07d318fa9389a2b9194196c239e41a77841"},
61 {file = "psycopg_binary-3.1.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf59e1d06f420930fc4c16a42ed6476c60c83976c82e53012dbca45f009d5978"},
62 {file = "psycopg_binary-3.1.8-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:cb3013b76cbab4a903f3b9c87f4518335627cb05fd89f9e04520c1743c2b919b"},
63 {file = "psycopg_binary-3.1.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:db84eaa9e2d13e37a97dcd39d2fe78e0a3052c9aa67b5f0b4f3d346a155f4d21"},
64 {file = "psycopg_binary-3.1.8-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:2c3d268cf2dbb79e52a555c2e7b26c6df2d014f3fb918d512ffc25ecc9c54582"},
65 {file = "psycopg_binary-3.1.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0fe6205af5f63ee6e4816b267bf06add5934a259cddcf7dfdfc8ed738f5127b2"},
66 {file = "psycopg_binary-3.1.8-cp37-cp37m-win_amd64.whl", hash = "sha256:f99806a5b9a5ba5cb5f46a0fa0440cd721556e0af09a7cadcc39e27ae9b1807e"},
67 {file = "psycopg_binary-3.1.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0cc5d5a9b0acbf38e0b4de1c701d235f0cb750ef3de528dedfdbab1a367f2396"},
68 {file = "psycopg_binary-3.1.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:478ecbb774398e5df6ee365a4d0a77f382a65f140e76720909804255c7801d4a"},
69 {file = "psycopg_binary-3.1.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b40b56c5b3ffa8481f7bebb08473602ddb8e2e86ba25bf9261ba428eb7887175"},
70 {file = "psycopg_binary-3.1.8-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:37df8714837d2c701ba4c54462a189b95d1a4439d4d147fb71018560e9a60547"},
71 {file = "psycopg_binary-3.1.8-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29a38b48cbec8484d83efea4d1d0707e49a3c51a2273cfbaa3d9ba280d3df7d9"},
72 {file = "psycopg_binary-3.1.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1a2209ef4df25f4ed8d91924bd4d9c7028d254e61216366c4b894c8a6ea4f88"},
73 {file = "psycopg_binary-3.1.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:858a794c2d5e984627503581f03cc68cef97ee080993b7b6a0b7b30cb4fac107"},
74 {file = "psycopg_binary-3.1.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:574c8b7b51e8d5c06f27125fc218d1328c018c0c1ad8f1202033aa6897b8ee99"},
75 {file = "psycopg_binary-3.1.8-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:e3dc783eedde10f966039ecc5f96f7df25c288ea4f6795d28b990f312c33ff09"},
76 {file = "psycopg_binary-3.1.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:94f9e7ccbfdba1c4f5de80b615187eb47a351ab64a9123d87aea4bf347c1e1d8"},
77 {file = "psycopg_binary-3.1.8-cp38-cp38-win_amd64.whl", hash = "sha256:1425c2cc4cfd4778d9dee578541f11546a93fc2f5c558a0411c94026a1cf94c7"},
78 {file = "psycopg_binary-3.1.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e68e8b8077cd45dd2683fcd9a384e7672b400e26c0c7d04dac0cf0763c12be78"},
79 {file = "psycopg_binary-3.1.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:60b22dd46e4e4f678379cf3388468171c2ecea74e90b1332d173ffa8cd83315f"},
80 {file = "psycopg_binary-3.1.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61a1ccef7e0bf6128a7818c9d22cc850cf7649cee9541e82e4a8c080a734024d"},
81 {file = "psycopg_binary-3.1.8-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e7a7b41eba96c7b9648efee57298f1aa0d96e081dea76489f52113536981712"},
82 {file = "psycopg_binary-3.1.8-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a161785b1c8e26cd8e8d5436fa39ba2a8af590c17f1741aae11f8076a08485e6"},
83 {file = "psycopg_binary-3.1.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a978d2bea09265eb6ebcd1b8a3aa05ea4118aa4013cb9669e12a8656975385cd"},
84 {file = "psycopg_binary-3.1.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:251d2e6dca112dd359c029f422a025d75e78f2f2af4a2aceff506fdc5120f5f9"},
85 {file = "psycopg_binary-3.1.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a1f052642a54eda53786fa8b72fca2e48ceaf0fc2f3e8709c87694fd7c45ac50"},
86 {file = "psycopg_binary-3.1.8-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:73747e6a5dfb05500ff3857f9b9ee50e4f4f663250454d773b98d818545f10fa"},
87 {file = "psycopg_binary-3.1.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:811d870ca9e97875db92f9b346492c4fa7a9edd74dce3604015dd13389fef46a"},
88 {file = "psycopg_binary-3.1.8-cp39-cp39-win_amd64.whl", hash = "sha256:8a0f425171e95379f1fe93b41d67c6dfe85b6b635944facf07ca26ff7fa8ab1d"},
89]
90
91[[package]]
92name = "psycopg-pool"
93version = "3.1.7"
94description = "Connection Pool for Psycopg"
95category = "main"
96optional = false
97python-versions = ">=3.7"
98files = [
99 {file = "psycopg-pool-3.1.7.tar.gz", hash = "sha256:d02741dc48303495f4021900630442af87d6b1c3bfd1a3ece54cc11aa43d7dde"},
100 {file = "psycopg_pool-3.1.7-py3-none-any.whl", hash = "sha256:ca1f2c366b5910acd400e16e812912827c57836af638c1717ba495111d22073b"},
101]
102
103[package.dependencies]
104typing-extensions = ">=3.10"
105
106[[package]]
107name = "sdnotify"
108version = "0.3.2"
109description = "A pure Python implementation of systemd's service notification protocol (sd_notify)"
110category = "main"
111optional = false
112python-versions = "*"
113files = [
114 {file = "sdnotify-0.3.2.tar.gz", hash = "sha256:73977fc746b36cc41184dd43c3fe81323e7b8b06c2bb0826c4f59a20c56bb9f1"},
115]
116
117[[package]]
118name = "systemd-python"
119version = "235"
120description = "Python interface for libsystemd"
121category = "main"
122optional = false
123python-versions = "*"
124files = [
125 {file = "systemd-python-235.tar.gz", hash = "sha256:4e57f39797fd5d9e2d22b8806a252d7c0106c936039d1e71c8c6b8008e695c0a"},
126]
127
128[[package]]
129name = "systemd-socketserver"
130version = "1.0"
131description = "Socket server implementation that works with systemd socket activation"
132category = "main"
133optional = false
134python-versions = ">=3"
135files = [
136 {file = "systemd_socketserver-1.0-py3-none-any.whl", hash = "sha256:987a8bfbf28d959e7c2966c742ad7bad482f05e121077defcf95bb38267db9a8"},
137]
138
139[package.dependencies]
140systemd-python = "*"
141
142[[package]]
143name = "typing-extensions"
144version = "4.5.0"
145description = "Backported and Experimental Type Hints for Python 3.7+"
146category = "main"
147optional = false
148python-versions = ">=3.7"
149files = [
150 {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"},
151 {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"},
152]
153
154[[package]]
155name = "tzdata"
156version = "2023.3"
157description = "Provider of IANA time zone data"
158category = "main"
159optional = false
160python-versions = ">=2"
161files = [
162 {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"},
163 {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"},
164]
165
166[metadata]
167lock-version = "2.0"
168python-versions = "^3.9"
169content-hash = "caba2a43081cb7820a3d1243e0c4aae70e0604405fbe1601cea99bd93a2f1429"
diff --git a/hosts/surtr/email/ccert-policy-server/pyproject.toml b/hosts/surtr/email/ccert-policy-server/pyproject.toml
index 97a18c65..518bd4f9 100644
--- a/hosts/surtr/email/ccert-policy-server/pyproject.toml
+++ b/hosts/surtr/email/ccert-policy-server/pyproject.toml
@@ -1,20 +1,30 @@
1[tool.poetry] 1[project]
2name = "ccert_policy_server" 2name = "ccert_policy_server"
3version = "0.0.0" 3version = "0.0.0"
4authors = ["Gregor Kleen <gkleen@yggdrasil.li>"]
5description = "" 4description = ""
5authors = [{ name = "Gregor Kleen", email = "gkleen@yggdrasil.li" }]
6requires-python = ">=3.12,<4"
7classifiers = [
8 "Programming Language :: Python :: 3",
9 "Programming Language :: Python :: 3.12",
10 "Programming Language :: Python :: 3.13",
11 "Programming Language :: Python :: 3.14",
12]
13dependencies = [
14 "sdnotify>=0.3.2,<0.4",
15 "systemd-socketserver>=1.0,<2",
16 "psycopg>=3.3,<4",
17 "psycopg-pool>=3.3,<4",
18 "psycopg-binary>=3.3.3,<4",
19]
6 20
7[tool.poetry.scripts] 21[project.scripts]
8ccert-policy-server = "ccert_policy_server.__main__:main" 22ccert-policy-server = "ccert_policy_server.__main__:main"
9 23
10[tool.poetry.dependencies]
11python = "^3.9"
12sdnotify = "^0.3.2"
13systemd-socketserver = "^1.0"
14psycopg = "^3.1.8"
15psycopg-pool = "^3.1.7"
16psycopg-binary = "^3.1.8"
17
18[build-system] 24[build-system]
19requires = ["poetry-core>=1.0.0"] 25requires = ["uv_build>=0.10.9,<0.11.0"]
20build-backend = "poetry.core.masonry.api" \ No newline at end of file 26build-backend = "uv_build"
27
28[tool.uv.build-backend]
29module-root = "."
30module-name = ["ccert_policy_server"]
diff --git a/hosts/surtr/email/ccert-policy-server/uv.lock b/hosts/surtr/email/ccert-policy-server/uv.lock
new file mode 100644
index 00000000..0024400b
--- /dev/null
+++ b/hosts/surtr/email/ccert-policy-server/uv.lock
@@ -0,0 +1,130 @@
1version = 1
2revision = 3
3requires-python = ">=3.12, <4"
4
5[[package]]
6name = "ccert-policy-server"
7version = "0.0.0"
8source = { editable = "." }
9dependencies = [
10 { name = "psycopg" },
11 { name = "psycopg-binary" },
12 { name = "psycopg-pool" },
13 { name = "sdnotify" },
14 { name = "systemd-socketserver" },
15]
16
17[package.metadata]
18requires-dist = [
19 { name = "psycopg", specifier = ">=3.3,<4" },
20 { name = "psycopg-binary", specifier = ">=3.3.3,<4" },
21 { name = "psycopg-pool", specifier = ">=3.3,<4" },
22 { name = "sdnotify", specifier = ">=0.3.2,<0.4" },
23 { name = "systemd-socketserver", specifier = ">=1.0,<2" },
24]
25
26[[package]]
27name = "psycopg"
28version = "3.3.3"
29source = { registry = "https://pypi.org/simple" }
30dependencies = [
31 { name = "typing-extensions", marker = "python_full_version < '3.13'" },
32 { name = "tzdata", marker = "sys_platform == 'win32'" },
33]
34sdist = { url = "https://files.pythonhosted.org/packages/d3/b6/379d0a960f8f435ec78720462fd94c4863e7a31237cf81bf76d0af5883bf/psycopg-3.3.3.tar.gz", hash = "sha256:5e9a47458b3c1583326513b2556a2a9473a1001a56c9efe9e587245b43148dd9", size = 165624, upload-time = "2026-02-18T16:52:16.546Z" }
35wheels = [
36 { url = "https://files.pythonhosted.org/packages/c8/5b/181e2e3becb7672b502f0ed7f16ed7352aca7c109cfb94cf3878a9186db9/psycopg-3.3.3-py3-none-any.whl", hash = "sha256:f96525a72bcfade6584ab17e89de415ff360748c766f0106959144dcbb38c698", size = 212768, upload-time = "2026-02-18T16:46:27.365Z" },
37]
38
39[[package]]
40name = "psycopg-binary"
41version = "3.3.3"
42source = { registry = "https://pypi.org/simple" }
43wheels = [
44 { url = "https://files.pythonhosted.org/packages/90/15/021be5c0cbc5b7c1ab46e91cc3434eb42569f79a0592e67b8d25e66d844d/psycopg_binary-3.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6698dbab5bcef8fdb570fc9d35fd9ac52041771bfcfe6fd0fc5f5c4e36f1e99d", size = 4591170, upload-time = "2026-02-18T16:48:55.594Z" },
45 { url = "https://files.pythonhosted.org/packages/f1/54/a60211c346c9a2f8c6b272b5f2bbe21f6e11800ce7f61e99ba75cf8b63e1/psycopg_binary-3.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:329ff393441e75f10b673ae99ab45276887993d49e65f141da20d915c05aafd8", size = 4670009, upload-time = "2026-02-18T16:49:03.608Z" },
46 { url = "https://files.pythonhosted.org/packages/c1/53/ac7c18671347c553362aadbf65f92786eef9540676ca24114cc02f5be405/psycopg_binary-3.3.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:eb072949b8ebf4082ae24289a2b0fd724da9adc8f22743409d6fd718ddb379df", size = 5469735, upload-time = "2026-02-18T16:49:10.128Z" },
47 { url = "https://files.pythonhosted.org/packages/7f/c3/4f4e040902b82a344eff1c736cde2f2720f127fe939c7e7565706f96dd44/psycopg_binary-3.3.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:263a24f39f26e19ed7fc982d7859a36f17841b05bebad3eb47bb9cd2dd785351", size = 5152919, upload-time = "2026-02-18T16:49:16.335Z" },
48 { url = "https://files.pythonhosted.org/packages/0c/e7/d929679c6a5c212bcf738806c7c89f5b3d0919f2e1685a0e08d6ff877945/psycopg_binary-3.3.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5152d50798c2fa5bd9b68ec68eb68a1b71b95126c1d70adaa1a08cd5eefdc23d", size = 6738785, upload-time = "2026-02-18T16:49:22.687Z" },
49 { url = "https://files.pythonhosted.org/packages/69/b0/09703aeb69a9443d232d7b5318d58742e8ca51ff79f90ffe6b88f1db45e7/psycopg_binary-3.3.3-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9d6a1e56dd267848edb824dbeb08cf5bac649e02ee0b03ba883ba3f4f0bd54f2", size = 4979008, upload-time = "2026-02-18T16:49:27.313Z" },
50 { url = "https://files.pythonhosted.org/packages/cc/a6/e662558b793c6e13a7473b970fee327d635270e41eded3090ef14045a6a5/psycopg_binary-3.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73eaaf4bb04709f545606c1db2f65f4000e8a04cdbf3e00d165a23004692093e", size = 4508255, upload-time = "2026-02-18T16:49:31.575Z" },
51 { url = "https://files.pythonhosted.org/packages/5f/7f/0f8b2e1d5e0093921b6f324a948a5c740c1447fbb45e97acaf50241d0f39/psycopg_binary-3.3.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:162e5675efb4704192411eaf8e00d07f7960b679cd3306e7efb120bb8d9456cc", size = 4189166, upload-time = "2026-02-18T16:49:35.801Z" },
52 { url = "https://files.pythonhosted.org/packages/92/ec/ce2e91c33bc8d10b00c87e2f6b0fb570641a6a60042d6a9ae35658a3a797/psycopg_binary-3.3.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:fab6b5e37715885c69f5d091f6ff229be71e235f272ebaa35158d5a46fd548a0", size = 3924544, upload-time = "2026-02-18T16:49:41.129Z" },
53 { url = "https://files.pythonhosted.org/packages/c5/2f/7718141485f73a924205af60041c392938852aa447a94c8cbd222ff389a1/psycopg_binary-3.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a4aab31bd6d1057f287c96c0effca3a25584eb9cc702f282ecb96ded7814e830", size = 4235297, upload-time = "2026-02-18T16:49:46.726Z" },
54 { url = "https://files.pythonhosted.org/packages/57/f9/1add717e2643a003bbde31b1b220172e64fbc0cb09f06429820c9173f7fc/psycopg_binary-3.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:59aa31fe11a0e1d1bcc2ce37ed35fe2ac84cd65bb9036d049b1a1c39064d0f14", size = 3547659, upload-time = "2026-02-18T16:49:52.999Z" },
55 { url = "https://files.pythonhosted.org/packages/03/0a/cac9fdf1df16a269ba0e5f0f06cac61f826c94cadb39df028cdfe19d3a33/psycopg_binary-3.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05f32239aec25c5fb15f7948cffdc2dc0dac098e48b80a140e4ba32b572a2e7d", size = 4590414, upload-time = "2026-02-18T16:50:01.441Z" },
56 { url = "https://files.pythonhosted.org/packages/9c/c0/d8f8508fbf440edbc0099b1abff33003cd80c9e66eb3a1e78834e3fb4fb9/psycopg_binary-3.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7c84f9d214f2d1de2fafebc17fa68ac3f6561a59e291553dfc45ad299f4898c1", size = 4669021, upload-time = "2026-02-18T16:50:08.803Z" },
57 { url = "https://files.pythonhosted.org/packages/04/05/097016b77e343b4568feddf12c72171fc513acef9a4214d21b9478569068/psycopg_binary-3.3.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e77957d2ba17cada11be09a5066d93026cdb61ada7c8893101d7fe1c6e1f3925", size = 5467453, upload-time = "2026-02-18T16:50:14.985Z" },
58 { url = "https://files.pythonhosted.org/packages/91/23/73244e5feb55b5ca109cede6e97f32ef45189f0fdac4c80d75c99862729d/psycopg_binary-3.3.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:42961609ac07c232a427da7c87a468d3c82fee6762c220f38e37cfdacb2b178d", size = 5151135, upload-time = "2026-02-18T16:50:24.82Z" },
59 { url = "https://files.pythonhosted.org/packages/11/49/5309473b9803b207682095201d8708bbc7842ddf3f192488a69204e36455/psycopg_binary-3.3.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae07a3114313dd91fce686cab2f4c44af094398519af0e0f854bc707e1aeedf1", size = 6737315, upload-time = "2026-02-18T16:50:35.106Z" },
60 { url = "https://files.pythonhosted.org/packages/d4/5d/03abe74ef34d460b33c4d9662bf6ec1dd38888324323c1a1752133c10377/psycopg_binary-3.3.3-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d257c58d7b36a621dcce1d01476ad8b60f12d80eb1406aee4cf796f88b2ae482", size = 4979783, upload-time = "2026-02-18T16:50:42.067Z" },
61 { url = "https://files.pythonhosted.org/packages/f0/6c/3fbf8e604e15f2f3752900434046c00c90bb8764305a1b81112bff30ba24/psycopg_binary-3.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:07c7211f9327d522c9c47560cae00a4ecf6687f4e02d779d035dd3177b41cb12", size = 4509023, upload-time = "2026-02-18T16:50:50.116Z" },
62 { url = "https://files.pythonhosted.org/packages/9c/6b/1a06b43b7c7af756c80b67eac8bfaa51d77e68635a8a8d246e4f0bb7604a/psycopg_binary-3.3.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:8e7e9eca9b363dbedeceeadd8be97149d2499081f3c52d141d7cd1f395a91f83", size = 4185874, upload-time = "2026-02-18T16:50:55.97Z" },
63 { url = "https://files.pythonhosted.org/packages/2b/d3/bf49e3dcaadba510170c8d111e5e69e5ae3f981c1554c5bb71c75ce354bb/psycopg_binary-3.3.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:cb85b1d5702877c16f28d7b92ba030c1f49ebcc9b87d03d8c10bf45a2f1c7508", size = 3925668, upload-time = "2026-02-18T16:51:03.299Z" },
64 { url = "https://files.pythonhosted.org/packages/f8/92/0aac830ed6a944fe334404e1687a074e4215630725753f0e3e9a9a595b62/psycopg_binary-3.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4d4606c84d04b80f9138d72f1e28c6c02dc5ae0c7b8f3f8aaf89c681ce1cd1b1", size = 4234973, upload-time = "2026-02-18T16:51:09.097Z" },
65 { url = "https://files.pythonhosted.org/packages/2e/96/102244653ee5a143ece5afe33f00f52fe64e389dfce8dbc87580c6d70d3d/psycopg_binary-3.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:74eae563166ebf74e8d950ff359be037b85723d99ca83f57d9b244a871d6c13b", size = 3551342, upload-time = "2026-02-18T16:51:13.892Z" },
66 { url = "https://files.pythonhosted.org/packages/a2/71/7a57e5b12275fe7e7d84d54113f0226080423a869118419c9106c083a21c/psycopg_binary-3.3.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:497852c5eaf1f0c2d88ab74a64a8097c099deac0c71de1cbcf18659a8a04a4b2", size = 4607368, upload-time = "2026-02-18T16:51:19.295Z" },
67 { url = "https://files.pythonhosted.org/packages/c7/04/cb834f120f2b2c10d4003515ef9ca9d688115b9431735e3936ae48549af8/psycopg_binary-3.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:258d1ea53464d29768bf25930f43291949f4c7becc706f6e220c515a63a24edd", size = 4687047, upload-time = "2026-02-18T16:51:23.84Z" },
68 { url = "https://files.pythonhosted.org/packages/40/e9/47a69692d3da9704468041aa5ed3ad6fc7f6bb1a5ae788d261a26bbca6c7/psycopg_binary-3.3.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:111c59897a452196116db12e7f608da472fbff000693a21040e35fc978b23430", size = 5487096, upload-time = "2026-02-18T16:51:29.645Z" },
69 { url = "https://files.pythonhosted.org/packages/0b/b6/0e0dd6a2f802864a4ae3dbadf4ec620f05e3904c7842b326aafc43e5f464/psycopg_binary-3.3.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:17bb6600e2455993946385249a3c3d0af52cd70c1c1cdbf712e9d696d0b0bf1b", size = 5168720, upload-time = "2026-02-18T16:51:36.499Z" },
70 { url = "https://files.pythonhosted.org/packages/6f/0d/977af38ac19a6b55d22dff508bd743fd7c1901e1b73657e7937c7cccb0a3/psycopg_binary-3.3.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:642050398583d61c9856210568eb09a8e4f2fe8224bf3be21b67a370e677eead", size = 6762076, upload-time = "2026-02-18T16:51:43.167Z" },
71 { url = "https://files.pythonhosted.org/packages/34/40/912a39d48322cf86895c0eaf2d5b95cb899402443faefd4b09abbba6b6e1/psycopg_binary-3.3.3-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:533efe6dc3a7cba5e2a84e38970786bb966306863e45f3db152007e9f48638a6", size = 4997623, upload-time = "2026-02-18T16:51:47.707Z" },
72 { url = "https://files.pythonhosted.org/packages/98/0c/c14d0e259c65dc7be854d926993f151077887391d5a081118907a9d89603/psycopg_binary-3.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5958dbf28b77ce2033482f6cb9ef04d43f5d8f4b7636e6963d5626f000efb23e", size = 4532096, upload-time = "2026-02-18T16:51:51.421Z" },
73 { url = "https://files.pythonhosted.org/packages/39/21/8b7c50a194cfca6ea0fd4d1f276158307785775426e90700ab2eba5cd623/psycopg_binary-3.3.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:a6af77b6626ce92b5817bf294b4d45ec1a6161dba80fc2d82cdffdd6814fd023", size = 4208884, upload-time = "2026-02-18T16:51:57.336Z" },
74 { url = "https://files.pythonhosted.org/packages/c7/2c/a4981bf42cf30ebba0424971d7ce70a222ae9b82594c42fc3f2105d7b525/psycopg_binary-3.3.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:47f06fcbe8542b4d96d7392c476a74ada521c5aebdb41c3c0155f6595fc14c8d", size = 3944542, upload-time = "2026-02-18T16:52:04.266Z" },
75 { url = "https://files.pythonhosted.org/packages/60/e9/b7c29b56aa0b85a4e0c4d89db691c1ceef08f46a356369144430c155a2f5/psycopg_binary-3.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e7800e6c6b5dc4b0ca7cc7370f770f53ac83886b76afda0848065a674231e856", size = 4254339, upload-time = "2026-02-18T16:52:10.444Z" },
76 { url = "https://files.pythonhosted.org/packages/98/5a/291d89f44d3820fffb7a04ebc8f3ef5dda4f542f44a5daea0c55a84abf45/psycopg_binary-3.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:165f22ab5a9513a3d7425ffb7fcc7955ed8ccaeef6d37e369d6cc1dff1582383", size = 3652796, upload-time = "2026-02-18T16:52:14.02Z" },
77]
78
79[[package]]
80name = "psycopg-pool"
81version = "3.3.0"
82source = { registry = "https://pypi.org/simple" }
83dependencies = [
84 { name = "typing-extensions" },
85]
86sdist = { url = "https://files.pythonhosted.org/packages/56/9a/9470d013d0d50af0da9c4251614aeb3c1823635cab3edc211e3839db0bcf/psycopg_pool-3.3.0.tar.gz", hash = "sha256:fa115eb2860bd88fce1717d75611f41490dec6135efb619611142b24da3f6db5", size = 31606, upload-time = "2025-12-01T11:34:33.11Z" }
87wheels = [
88 { url = "https://files.pythonhosted.org/packages/e7/c3/26b8a0908a9db249de3b4169692e1c7c19048a9bc41a4d3209cee7dbb758/psycopg_pool-3.3.0-py3-none-any.whl", hash = "sha256:2e44329155c410b5e8666372db44276a8b1ebd8c90f1c3026ebba40d4bc81063", size = 39995, upload-time = "2025-12-01T11:34:29.761Z" },
89]
90
91[[package]]
92name = "sdnotify"
93version = "0.3.2"
94source = { registry = "https://pypi.org/simple" }
95sdist = { url = "https://files.pythonhosted.org/packages/ce/d8/9fdc36b2a912bf78106de4b3f0de3891ff8f369e7a6f80be842b8b0b6bd5/sdnotify-0.3.2.tar.gz", hash = "sha256:73977fc746b36cc41184dd43c3fe81323e7b8b06c2bb0826c4f59a20c56bb9f1", size = 2459, upload-time = "2017-08-02T20:03:44.395Z" }
96
97[[package]]
98name = "systemd-python"
99version = "235"
100source = { registry = "https://pypi.org/simple" }
101sdist = { url = "https://files.pythonhosted.org/packages/10/9e/ab4458e00367223bda2dd7ccf0849a72235ee3e29b36dce732685d9b7ad9/systemd-python-235.tar.gz", hash = "sha256:4e57f39797fd5d9e2d22b8806a252d7c0106c936039d1e71c8c6b8008e695c0a", size = 61677, upload-time = "2023-02-11T13:42:16.588Z" }
102
103[[package]]
104name = "systemd-socketserver"
105version = "1.0"
106source = { registry = "https://pypi.org/simple" }
107dependencies = [
108 { name = "systemd-python" },
109]
110wheels = [
111 { url = "https://files.pythonhosted.org/packages/d8/4f/b28b7f08880120a26669b080ca74487c8c67e8b54dcb0467a8f0c9f38ed6/systemd_socketserver-1.0-py3-none-any.whl", hash = "sha256:987a8bfbf28d959e7c2966c742ad7bad482f05e121077defcf95bb38267db9a8", size = 3248, upload-time = "2020-04-26T05:26:40.661Z" },
112]
113
114[[package]]
115name = "typing-extensions"
116version = "4.15.0"
117source = { registry = "https://pypi.org/simple" }
118sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
119wheels = [
120 { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
121]
122
123[[package]]
124name = "tzdata"
125version = "2025.3"
126source = { registry = "https://pypi.org/simple" }
127sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" }
128wheels = [
129 { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" },
130]
diff --git a/hosts/surtr/email/default.nix b/hosts/surtr/email/default.nix
index c6253e4c..4243366c 100644
--- a/hosts/surtr/email/default.nix
+++ b/hosts/surtr/email/default.nix
@@ -21,18 +21,21 @@ let
21 }; 21 };
22 22
23 ccert-policy-server = 23 ccert-policy-server =
24 with pkgs.poetry2nix; 24 let
25 mkPoetryApplication { 25 workspace = flakeInputs.uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./ccert-policy-server; };
26 python = pkgs.python311; 26 pythonSet = flake.lib.pythonSet {
27 27 inherit pkgs;
28 projectDir = cleanPythonSources { src = ./ccert-policy-server; }; 28 python = pkgs.python312;
29 29 overlay = workspace.mkPyprojectOverlay {
30 overrides = overrides.withDefaults (self: super: { 30 sourcePreference = "wheel";
31 systemd-python = super.systemd-python.overridePythonAttrs (oldAttrs: { 31 };
32 buildInputs = (oldAttrs.buildInputs or []) ++ [ super.setuptools ]; 32 };
33 }); 33 virtualEnv = pythonSet.mkVirtualEnv "ccert-policy-server-env" workspace.deps.default;
34 }); 34 in virtualEnv.overrideAttrs (oldAttrs: {
35 }; 35 meta = (oldAttrs.meta or {}) // {
36 mainProgram = "ccert-policy-server";
37 };
38 });
36 internal-policy-server = 39 internal-policy-server =
37 let 40 let
38 workspace = flakeInputs.uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./internal-policy-server; }; 41 workspace = flakeInputs.uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./internal-policy-server; };
@@ -124,22 +127,20 @@ in {
124 services.postfix = { 127 services.postfix = {
125 enable = true; 128 enable = true;
126 enableSmtp = false; 129 enableSmtp = false;
127 hostname = "surtr.yggdrasil.li";
128 recipientDelimiter = "";
129 setSendmail = true; 130 setSendmail = true;
130 postmasterAlias = ""; rootAlias = ""; extraAliases = ""; 131 postmasterAlias = ""; rootAlias = ""; extraAliases = "";
131 destination = []; 132 settings.main = {
132 sslCert = "/run/credentials/postfix.service/surtr.yggdrasil.li.pem"; 133 recpipient_delimiter = "";
133 sslKey = "/run/credentials/postfix.service/surtr.yggdrasil.li.key.pem"; 134 mydestination = [];
134 networks = []; 135 mynetworks = [];
135 config = let 136 myhostname = "surtr.yggdrasil.li";
136 relay_ccert = "texthash:${pkgs.writeText "relay_ccert" ""}"; 137
137 in {
138 smtpd_tls_security_level = "may"; 138 smtpd_tls_security_level = "may";
139 139
140 #the dh params 140 smtpd_tls_chain_files = [
141 smtpd_tls_dh1024_param_file = toString config.security.dhparams.params."postfix-1024".path; 141 "/run/credentials/postfix.service/surtr.yggdrasil.li.full.pem"
142 smtpd_tls_dh512_param_file = toString config.security.dhparams.params."postfix-512".path; 142 ];
143
143 #enable ECDH 144 #enable ECDH
144 smtpd_tls_eecdh_grade = "strong"; 145 smtpd_tls_eecdh_grade = "strong";
145 #enabled SSL protocols, don't allow SSLv2 and SSLv3 146 #enabled SSL protocols, don't allow SSLv2 and SSLv3
@@ -171,21 +172,14 @@ in {
171 172
172 smtp_tls_connection_reuse = true; 173 smtp_tls_connection_reuse = true;
173 174
174 tls_server_sni_maps = ''texthash:${pkgs.writeText "sni" ( 175 tls_server_sni_maps = "inline:{${concatMapStringsSep ", " (domain: "{ ${domain} = /run/credentials/postfix.service/${removePrefix "." domain}.full.pem }") (concatMap (domain: [domain "mailin.${domain}" "mailsub.${domain}" ".${domain}"]) emailDomains)}}";
175 concatMapStringsSep "\n\n" (domain:
176 concatMapStringsSep "\n" (subdomain: "${subdomain} /run/credentials/postfix.service/${removePrefix "." subdomain}.full.pem")
177 [domain "mailin.${domain}" "mailsub.${domain}" ".${domain}"]
178 ) emailDomains
179 )}'';
180 176
181 smtp_tls_policy_maps = "socketmap:unix:${config.services.postfix-mta-sts-resolver.settings.path}:postfix"; 177 smtp_tls_policy_maps = "socketmap:unix:${config.services.postfix-mta-sts-resolver.settings.path}:postfix";
182 178
183 local_recipient_maps = ""; 179 local_recipient_maps = "";
184 180
185 # 10 GiB 181 message_size_limit = 10 * 1024 * 1024 * 1024;
186 message_size_limit = "10737418240"; 182 mailbox_size_limit = 10 * 1024 * 1024 * 1024;
187 # 10 GiB
188 mailbox_size_limit = "10737418240";
189 183
190 smtpd_delay_reject = true; 184 smtpd_delay_reject = true;
191 smtpd_helo_required = true; 185 smtpd_helo_required = true;
@@ -200,7 +194,6 @@ in {
200 dbname = email 194 dbname = email
201 query = SELECT action FROM virtual_mailbox_access WHERE lookup = '%s' 195 query = SELECT action FROM virtual_mailbox_access WHERE lookup = '%s'
202 ''}" 196 ''}"
203 "check_ccert_access ${relay_ccert}"
204 "reject_non_fqdn_helo_hostname" 197 "reject_non_fqdn_helo_hostname"
205 "reject_invalid_helo_hostname" 198 "reject_invalid_helo_hostname"
206 "reject_unauth_destination" 199 "reject_unauth_destination"
@@ -221,7 +214,6 @@ in {
221 address_verify_sender_ttl = "30045s"; 214 address_verify_sender_ttl = "30045s";
222 215
223 smtpd_relay_restrictions = [ 216 smtpd_relay_restrictions = [
224 "check_ccert_access ${relay_ccert}"
225 "reject_unauth_destination" 217 "reject_unauth_destination"
226 ]; 218 ];
227 219
@@ -232,8 +224,8 @@ in {
232 smtpd_client_event_limit_exceptions = ""; 224 smtpd_client_event_limit_exceptions = "";
233 225
234 milter_default_action = "accept"; 226 milter_default_action = "accept";
235 smtpd_milters = [config.services.opendkim.socket "local:/run/rspamd/rspamd-milter.sock" "local:/run/postsrsd/postsrsd-milter.sock"]; 227 smtpd_milters = ["local:/run/rspamd/rspamd-milter.sock" "local:/run/postsrsd/postsrsd-milter.sock"];
236 non_smtpd_milters = [config.services.opendkim.socket "local:/run/rspamd/rspamd-milter.sock"]; 228 non_smtpd_milters = ["local:/run/rspamd/rspamd-milter.sock"];
237 229
238 alias_maps = ""; 230 alias_maps = "";
239 231
@@ -244,6 +236,37 @@ in {
244 bounce_queue_lifetime = "20m"; 236 bounce_queue_lifetime = "20m";
245 delay_warning_time = "10m"; 237 delay_warning_time = "10m";
246 238
239 failure_template_file = toString (pkgs.writeText "failure.cf" ''
240 Charset: us-ascii
241 From: Mail Delivery System <MAILER-DAEMON>
242 Subject: Undelivered Mail Returned to Sender
243 Postmaster-Subject: Postmaster Copy: Undelivered Mail
244
245 This is the mail system at host $myhostname.
246
247 I'm sorry to have to inform you that your message could not
248 be delivered to one or more recipients. It's attached below.
249
250 The mail system
251 '');
252 delay_template_file = toString (pkgs.writeText "delay.cf" ''
253 Charset: us-ascii
254 From: Mail Delivery System <MAILER-DAEMON>
255 Subject: Delayed Mail (still being retried)
256 Postmaster-Subject: Postmaster Warning: Delayed Mail
257
258 This is the mail system at host $myhostname.
259
260 ####################################################################
261 # THIS IS A WARNING ONLY. YOU DO NOT NEED TO RESEND YOUR MESSAGE. #
262 ####################################################################
263
264 Your message could not be delivered for more than $delay_warning_time_minutes minute(s).
265 It will be retried until it is $maximal_queue_lifetime_minutes minute(s) old.
266
267 The mail system
268 '');
269
247 smtpd_discard_ehlo_keyword_address_maps = "cidr:${pkgs.writeText "esmtp_access" '' 270 smtpd_discard_ehlo_keyword_address_maps = "cidr:${pkgs.writeText "esmtp_access" ''
248 # Allow DSN requests from local subnet only 271 # Allow DSN requests from local subnet only
249 192.168.0.0/16 silent-discard 272 192.168.0.0/16 silent-discard
@@ -268,13 +291,26 @@ in {
268 virtual_transport = "dvlmtp:unix:/run/dovecot-lmtp"; 291 virtual_transport = "dvlmtp:unix:/run/dovecot-lmtp";
269 smtputf8_enable = false; 292 smtputf8_enable = false;
270 293
271 authorized_submit_users = "inline:{ root= postfwd= dovecot2= }"; 294 authorized_submit_users = "inline:{ root= postfwd= ${config.services.dovecot2.user}= }";
295 authorized_flush_users = "inline:{ root= }";
296 authorized_mailq_users = "inline:{ root= }";
272 297
273 postscreen_access_list = ""; 298 postscreen_access_list = "";
274 postscreen_denylist_action = "drop"; 299 postscreen_denylist_action = "drop";
275 postscreen_greet_action = "enforce"; 300 postscreen_greet_action = "enforce";
301
302 sender_bcc_maps = ''pgsql:${pkgs.writeText "sender_bcc_maps.cf" ''
303 hosts = postgresql:///email
304 dbname = email
305 query = SELECT value FROM sender_bcc_maps WHERE key = '%s'
306 ''}'';
307 recipient_bcc_maps = ''pgsql:${pkgs.writeText "recipient_bcc_maps.cf" ''
308 hosts = postgresql:///email
309 dbname = email
310 query = SELECT value FROM recipient_bcc_maps WHERE key = '%s'
311 ''}'';
276 }; 312 };
277 masterConfig = { 313 settings.master = {
278 "465" = { 314 "465" = {
279 type = "inet"; 315 type = "inet";
280 private = false; 316 private = false;
@@ -303,7 +339,6 @@ in {
303 "-o" "unverified_sender_reject_code=550" 339 "-o" "unverified_sender_reject_code=550"
304 "-o" "unverified_sender_reject_reason={Sender address rejected: undeliverable address}" 340 "-o" "unverified_sender_reject_reason={Sender address rejected: undeliverable address}"
305 "-o" "milter_macro_daemon_name=surtr.yggdrasil.li" 341 "-o" "milter_macro_daemon_name=surtr.yggdrasil.li"
306 "-o" ''smtpd_milters=${config.services.opendkim.socket}''
307 ]; 342 ];
308 }; 343 };
309 "466" = { 344 "466" = {
@@ -333,7 +368,6 @@ in {
333 "-o" "unverified_sender_reject_code=550" 368 "-o" "unverified_sender_reject_code=550"
334 "-o" "unverified_sender_reject_reason={Sender address rejected: undeliverable address}" 369 "-o" "unverified_sender_reject_reason={Sender address rejected: undeliverable address}"
335 "-o" "milter_macro_daemon_name=surtr.yggdrasil.li" 370 "-o" "milter_macro_daemon_name=surtr.yggdrasil.li"
336 "-o" ''smtpd_milters=${config.services.opendkim.socket}''
337 ]; 371 ];
338 }; 372 };
339 subcleanup = { 373 subcleanup = {
@@ -342,7 +376,10 @@ in {
342 maxproc = 0; 376 maxproc = 0;
343 args = [ 377 args = [
344 "-o" "header_checks=pcre:${pkgs.writeText "header_checks_submission" '' 378 "-o" "header_checks=pcre:${pkgs.writeText "header_checks_submission" ''
379 if /^Received: /
380 !/by surtr\.yggdrasil\.li/ STRIP
345 /^Received: from [^ ]+ \([^ ]+ [^ ]+\)\s+(.*)$/ REPLACE Received: $1 381 /^Received: from [^ ]+ \([^ ]+ [^ ]+\)\s+(.*)$/ REPLACE Received: $1
382 endif
346 ''}" 383 ''}"
347 ]; 384 ];
348 }; 385 };
@@ -386,20 +423,6 @@ in {
386 ''; 423 '';
387 }; 424 };
388 425
389 services.opendkim = {
390 enable = true;
391 user = "postfix"; group = "postfix";
392 socket = "local:/run/opendkim/opendkim.sock";
393 domains = ''csl:${concatStringsSep "," (["surtr.yggdrasil.li"] ++ emailDomains)}'';
394 selector = "surtr";
395 configFile = builtins.toFile "opendkim.conf" ''
396 Syslog true
397 MTA surtr.yggdrasil.li
398 MTACommand ${config.security.wrapperDir}/sendmail
399 LogResults true
400 '';
401 };
402
403 services.rspamd = { 426 services.rspamd = {
404 enable = true; 427 enable = true;
405 workers = { 428 workers = {
@@ -431,6 +454,8 @@ in {
431 milter = yes; 454 milter = yes;
432 timeout = 120s; 455 timeout = 120s;
433 456
457 client_ca_name = "yggdrasil.li";
458
434 upstream "local" { 459 upstream "local" {
435 default = yes; 460 default = yes;
436 self_scan = yes; 461 self_scan = yes;
@@ -467,7 +492,13 @@ in {
467 "redis.conf".text = '' 492 "redis.conf".text = ''
468 servers = "${config.services.redis.servers.rspamd.unixSocket}"; 493 servers = "${config.services.redis.servers.rspamd.unixSocket}";
469 ''; 494 '';
470 "dkim_signing.conf".text = "enabled = false;"; 495 "dkim_signing.conf".text = ''
496 enabled = true;
497 allow_username_mismatch = true;
498
499 path = "/var/lib/rspamd/dkim/$domain.key";
500 selector = "mail";
501 '';
471 "neural.conf".text = "enabled = false;"; 502 "neural.conf".text = "enabled = false;";
472 "classifier-bayes.conf".text = '' 503 "classifier-bayes.conf".text = ''
473 enable = true; 504 enable = true;
@@ -488,55 +519,58 @@ in {
488 spam = true; 519 spam = true;
489 } 520 }
490 ''; 521 '';
522 "logging.inc".text = ''
523 debug_modules = ["milter", "dkim_signing"];
524 '';
491 # "redirectors.inc".text = '' 525 # "redirectors.inc".text = ''
492 # visit.creeper.host 526 # visit.creeper.host
493 # ''; 527 # '';
494 }; 528 };
495 }; 529 };
496 530
497 users.groups.${config.services.rspamd.group}.members = [ config.services.postfix.user "dovecot2" ]; 531 users.groups.${config.services.rspamd.group}.members = [ config.services.postfix.user config.services.dovecot2.user ];
498 532
499 services.redis.servers.rspamd.enable = true; 533 services.redis.servers.rspamd.enable = true;
500 534
501 users.groups.${config.services.redis.servers.rspamd.user}.members = [ config.services.rspamd.user ]; 535 users.groups.${config.services.redis.servers.rspamd.user}.members = [ config.services.rspamd.user ];
502 536
503 environment.systemPackages = with pkgs; [ dovecot_pigeonhole dovecot_fts_xapian ]; 537 environment.systemPackages = with pkgs; [ dovecot_pigeonhole dovecot-fts-flatcurve ];
504 services.dovecot2 = { 538 services.dovecot2 = {
505 enable = true; 539 enable = true;
506 enablePAM = false; 540 enablePAM = false;
507 sslServerCert = "/run/credentials/dovecot2.service/surtr.yggdrasil.li.pem"; 541 sslServerCert = "/run/credentials/dovecot.service/surtr.yggdrasil.li.pem";
508 sslServerKey = "/run/credentials/dovecot2.service/surtr.yggdrasil.li.key.pem"; 542 sslServerKey = "/run/credentials/dovecot.service/surtr.yggdrasil.li.key.pem";
509 sslCACert = toString ./ca/ca.crt; 543 sslCACert = toString ./ca/ca.crt;
510 mailLocation = "maildir:/var/lib/mail/%u/maildir:UTF-8:INDEX=/var/lib/dovecot/indices/%u"; 544 mailLocation = "maildir:/var/lib/mail/%u/maildir:UTF-8:INDEX=/var/lib/dovecot/indices/%u";
511 mailPlugins.globally.enable = [ "fts" "fts_xapian" ]; 545 mailPlugins.globally.enable = [ "fts" "fts_flatcurve" ];
512 protocols = [ "lmtp" "sieve" ]; 546 protocols = [ "lmtp" "sieve" ];
513 sieve = { 547 sieve = {
514 extensions = ["copy" "imapsieve" "variables" "imap4flags" "vacation"]; 548 extensions = ["copy" "imapsieve" "variables" "imap4flags" "vacation" "vacation-seconds" "vnd.dovecot.debug"];
515 globalExtensions = ["copy" "imapsieve" "variables" "imap4flags" "vacation"]; 549 globalExtensions = ["copy" "imapsieve" "variables" "imap4flags" "vacation" "vacation-seconds" "vnd.dovecot.debug"];
516 }; 550 };
517 extraConfig = let 551 extraConfig = let
518 dovecotSqlConf = pkgs.writeText "dovecot-sql.conf" '' 552 dovecotSqlConf = pkgs.writeText "dovecot-sql.conf" ''
519 driver = pgsql 553 driver = pgsql
520 connect = dbname=email 554 connect = dbname=email
521 password_query = SELECT (CASE WHEN '%k' = 'valid' AND '%m' = 'EXTERNAL' THEN NULL ELSE "password" END) as password, (CASE WHEN '%k' = 'valid' AND '%m' = 'EXTERNAL' THEN true WHEN password IS NULL THEN true ELSE NULL END) as nopassword, "user", quota_rule, 'dovecot2' as uid, 'dovecot2' as gid FROM imap_user WHERE "user" = '%n' 555 password_query = SELECT (CASE WHEN '%k' = 'valid' AND '%m' = 'EXTERNAL' THEN NULL ELSE "password" END) as password, (CASE WHEN '%k' = 'valid' AND '%m' = 'EXTERNAL' THEN true WHEN password IS NULL THEN true ELSE NULL END) as nopassword, "user", quota_rule, '${config.services.dovecot2.user}' as uid, '${config.services.dovecot2.group}' as gid FROM imap_user WHERE "user" = '%n'
522 user_query = SELECT "user", quota_rule, 'dovecot2' as uid, 'dovecot2' as gid FROM imap_user WHERE "user" = '%n' 556 user_query = SELECT "user", quota_rule, '${config.services.dovecot2.user}' as uid, 'dovecot2' as gid FROM imap_user WHERE "user" = '%n'
523 iterate_query = SELECT "user" FROM imap_user 557 iterate_query = SELECT "user" FROM imap_user
524 ''; 558 '';
525 in '' 559 in ''
526 mail_home = /var/lib/mail/%u 560 mail_home = /var/lib/mail/%u
527 561
528 mail_plugins = $mail_plugins quota 562 mail_plugins = $mail_plugins quota fts fts_flatcurve
529 563
530 first_valid_uid = ${toString config.users.users.dovecot2.uid} 564 first_valid_uid = ${toString config.users.users.${config.services.dovecot2.user}.uid}
531 last_valid_uid = ${toString config.users.users.dovecot2.uid} 565 last_valid_uid = ${toString config.users.users.${config.services.dovecot2.user}.uid}
532 first_valid_gid = ${toString config.users.groups.dovecot2.gid} 566 first_valid_gid = ${toString config.users.groups.${config.services.dovecot2.group}.gid}
533 last_valid_gid = ${toString config.users.groups.dovecot2.gid} 567 last_valid_gid = ${toString config.users.groups.${config.services.dovecot2.group}.gid}
534 568
535 ${concatMapStringsSep "\n\n" (domain: 569 ${concatMapStringsSep "\n\n" (domain:
536 concatMapStringsSep "\n" (subdomain: '' 570 concatMapStringsSep "\n" (subdomain: ''
537 local_name ${subdomain} { 571 local_name ${subdomain} {
538 ssl_cert = </run/credentials/dovecot2.service/${subdomain}.pem 572 ssl_cert = </run/credentials/dovecot.service/${subdomain}.pem
539 ssl_key = </run/credentials/dovecot2.service/${subdomain}.key.pem 573 ssl_key = </run/credentials/dovecot.service/${subdomain}.key.pem
540 } 574 }
541 '') ["imap.${domain}" domain] 575 '') ["imap.${domain}" domain]
542 ) emailDomains} 576 ) emailDomains}
@@ -557,10 +591,10 @@ in {
557 auth_debug = yes 591 auth_debug = yes
558 592
559 service auth { 593 service auth {
560 user = dovecot2 594 user = ${config.services.dovecot2.user}
561 } 595 }
562 service auth-worker { 596 service auth-worker {
563 user = dovecot2 597 user = ${config.services.dovecot2.user}
564 } 598 }
565 599
566 userdb { 600 userdb {
@@ -581,7 +615,7 @@ in {
581 args = ${pkgs.writeText "dovecot-sql.conf" '' 615 args = ${pkgs.writeText "dovecot-sql.conf" ''
582 driver = pgsql 616 driver = pgsql
583 connect = dbname=email 617 connect = dbname=email
584 user_query = SELECT DISTINCT ON (extension IS NULL, local IS NULL) "user", quota_rule, 'dovecot2' as uid, 'dovecot2' as gid FROM lmtp_mapping WHERE CASE WHEN extension IS NOT NULL AND local IS NOT NULL THEN ('%n' :: citext) = local || '+' || extension AND domain = ('%d' :: citext) WHEN local IS NOT NULL THEN (local = ('%n' :: citext) OR ('%n' :: citext) ILIKE local || '+%%') AND domain = ('%d' :: citext) WHEN extension IS NOT NULL THEN ('%n' :: citext) ILIKE '%%+' || extension AND domain = ('%d' :: citext) ELSE domain = ('%d' :: citext) END ORDER BY (extension IS NULL) ASC, (local IS NULL) ASC 618 user_query = SELECT DISTINCT ON (extension IS NULL, local IS NULL) "user", quota_rule, '${config.services.dovecot2.user}' as uid, '${config.services.dovecot2.group}' as gid FROM lmtp_mapping WHERE CASE WHEN extension IS NOT NULL AND local IS NOT NULL THEN ('%n' :: citext) = local || '+' || extension AND domain = ('%d' :: citext) WHEN local IS NOT NULL THEN (local = ('%n' :: citext) OR ('%n' :: citext) ILIKE local || '+%%') AND domain = ('%d' :: citext) WHEN extension IS NOT NULL THEN ('%n' :: citext) ILIKE '%%+' || extension AND domain = ('%d' :: citext) ELSE domain = ('%d' :: citext) END ORDER BY (extension IS NULL) ASC, (local IS NULL) ASC
585 ''} 619 ''}
586 620
587 skip = never 621 skip = never
@@ -651,7 +685,7 @@ in {
651 quota_status_success = DUNNO 685 quota_status_success = DUNNO
652 quota_status_nouser = DUNNO 686 quota_status_nouser = DUNNO
653 quota_grace = 10%% 687 quota_grace = 10%%
654 quota_max_mail_size = ${config.services.postfix.config.message_size_limit} 688 quota_max_mail_size = ${toString config.services.postfix.settings.main.message_size_limit}
655 quota_vsizes = yes 689 quota_vsizes = yes
656 } 690 }
657 691
@@ -687,13 +721,16 @@ in {
687 } 721 }
688 722
689 plugin { 723 plugin {
690 plugin = fts fts_xapian 724 fts = flatcurve
691 fts = xapian 725
692 fts_xapian = partial=3 full=20 attachments=1 verbose=1 726 fts_languages = en de
727 fts_tokenizers = generic email-address
693 728
694 fts_autoindex = yes 729 fts_tokenizer_email_address = maxlen=100
730 fts_tokenizer_generic = algorithm=simple maxlen=30
695 731
696 fts_enforced = no 732 fts_filters = normalizer-icu snowball stopwords
733 fts_filters_en = lowercase snowball stopwords
697 } 734 }
698 735
699 service indexer-worker { 736 service indexer-worker {
@@ -702,30 +739,6 @@ in {
702 ''; 739 '';
703 }; 740 };
704 741
705 systemd.services.dovecot-fts-xapian-optimize = {
706 description = "Optimize dovecot indices for fts_xapian";
707 requisite = [ "dovecot2.service" ];
708 after = [ "dovecot2.service" ];
709 startAt = "*-*-* 22:00:00 Europe/Berlin";
710 serviceConfig = {
711 Type = "oneshot";
712 ExecStart = "${getExe' pkgs.dovecot "doveadm"} fts optimize -A";
713 PrivateDevices = true;
714 PrivateNetwork = true;
715 ProtectKernelTunables = true;
716 ProtectKernelModules = true;
717 ProtectControlGroups = true;
718 ProtectHome = true;
719 ProtectSystem = true;
720 PrivateTmp = true;
721 };
722 };
723 systemd.timers.dovecot-fts-xapian-optimize = {
724 timerConfig = {
725 RandomizedDelaySec = 4 * 3600;
726 };
727 };
728
729 environment.etc = { 742 environment.etc = {
730 "dovecot/sieve_before.d/tag-junk.sieve".text = '' 743 "dovecot/sieve_before.d/tag-junk.sieve".text = ''
731 require ["imap4flags"]; 744 require ["imap4flags"];
@@ -758,40 +771,28 @@ in {
758 ''; 771 '';
759 }; 772 };
760 773
761 security.dhparams = {
762 params = {
763 "postfix-512".bits = 512;
764 "postfix-1024".bits = 2048;
765
766 "postfix-smtps-512".bits = 512;
767 "postfix-smtps-1024".bits = 2048;
768 };
769 };
770
771 security.acme.rfc2136Domains = { 774 security.acme.rfc2136Domains = {
772 "surtr.yggdrasil.li" = { 775 "surtr.yggdrasil.li" = {
773 restartUnits = [ "postfix.service" "dovecot2.service" ]; 776 restartUnits = [ "postfix.service" "dovecot.service" ];
774 }; 777 };
775 } // listToAttrs (map (domain: nameValuePair "spm.${domain}" { restartUnits = ["nginx.service"]; }) spmDomains) 778 } // listToAttrs (map (domain: nameValuePair "spm.${domain}" { restartUnits = ["nginx.service"]; }) spmDomains)
776 // listToAttrs (concatMap (domain: [ 779 // listToAttrs (concatMap (domain: [
777 (nameValuePair domain { restartUnits = ["postfix.service" "dovecot2.service"]; }) 780 (nameValuePair domain { restartUnits = ["postfix.service" "dovecot.service"]; })
778 (nameValuePair "mailin.${domain}" { restartUnits = ["postfix.service"]; }) 781 (nameValuePair "mailin.${domain}" { restartUnits = ["postfix.service"]; })
779 (nameValuePair "mailsub.${domain}" { restartUnits = ["postfix.service"]; }) 782 (nameValuePair "mailsub.${domain}" { restartUnits = ["postfix.service"]; })
780 (nameValuePair "imap.${domain}" { restartUnits = ["dovecot2.service"]; }) 783 (nameValuePair "imap.${domain}" { restartUnits = ["dovecot.service"]; })
781 (nameValuePair "mta-sts.${domain}" { restartUnits = ["nginx.service"]; }) 784 (nameValuePair "mta-sts.${domain}" { restartUnits = ["nginx.service"]; })
782 ]) emailDomains); 785 ]) emailDomains);
783 786
784 systemd.services.postfix = { 787 systemd.services.postfix = {
785 serviceConfig.LoadCredential = [ 788 serviceConfig.LoadCredential = let
786 "surtr.yggdrasil.li.key.pem:${config.security.acme.certs."surtr.yggdrasil.li".directory}/key.pem" 789 tlsCredential = domain: "${domain}.full.pem:${config.security.acme.certs.${domain}.directory}/full.pem";
787 "surtr.yggdrasil.li.pem:${config.security.acme.certs."surtr.yggdrasil.li".directory}/fullchain.pem" 790 in [
788 ] ++ concatMap (domain: 791 (tlsCredential "surtr.yggdrasil.li")
789 map (subdomain: "${subdomain}.full.pem:${config.security.acme.certs.${subdomain}.directory}/full.pem") 792 ] ++ concatMap (domain: map tlsCredential [domain "mailin.${domain}" "mailsub.${domain}"]) emailDomains;
790 [domain "mailin.${domain}" "mailsub.${domain}"]
791 ) emailDomains;
792 }; 793 };
793 794
794 systemd.services.dovecot2 = { 795 systemd.services.dovecot = {
795 preStart = '' 796 preStart = ''
796 for f in /etc/dovecot/sieve_flag.d/*.sieve /etc/dovecot/sieve_before.d/*.sieve; do 797 for f in /etc/dovecot/sieve_flag.d/*.sieve /etc/dovecot/sieve_before.d/*.sieve; do
797 ${getExe' pkgs.dovecot_pigeonhole "sievec"} $f 798 ${getExe' pkgs.dovecot_pigeonhole "sievec"} $f