1{ pkgs, ... }:
2let
3
4 ca_key = mailerCerts.ca.key;
5 ca_pem = mailerCerts.ca.cert;
6
7 bundle =
8 pkgs.runCommand "bundle"
9 {
10 nativeBuildInputs = [ pkgs.minica ];
11 }
12 ''
13 minica -ca-cert ${ca_pem} -ca-key ${ca_key} \
14 -domains localhost
15 install -Dm444 -t $out localhost/{key,cert}.pem
16 '';
17
18 mailerCerts = import ../common/acme/server/snakeoil-certs.nix;
19 mailerDomain = mailerCerts.domain;
20 registrationSharedSecret = "unsecure123";
21 testUser = "alice";
22 testPassword = "alicealice";
23 testEmail = "alice@example.com";
24
25 listeners = [
26 {
27 port = 8448;
28 bind_addresses = [
29 "127.0.0.1"
30 "::1"
31 ];
32 type = "http";
33 tls = true;
34 x_forwarded = false;
35 resources = [
36 {
37 names = [
38 "client"
39 ];
40 compress = true;
41 }
42 {
43 names = [
44 "federation"
45 ];
46 compress = false;
47 }
48 ];
49 }
50 ];
51
52in
53{
54
55 name = "matrix-synapse";
56 meta = {
57 inherit (pkgs.matrix-synapse.meta) maintainers;
58 };
59
60 nodes = {
61 # Since 0.33.0, matrix-synapse doesn't allow underscores in server names
62 serverpostgres =
63 {
64 pkgs,
65 nodes,
66 config,
67 ...
68 }:
69 let
70 mailserverIP = nodes.mailserver.networking.primaryIPAddress;
71 in
72 {
73 services.matrix-synapse = {
74 enable = true;
75 settings = {
76 inherit listeners;
77 database = {
78 name = "psycopg2";
79 args.password = "synapse";
80 };
81 redis = {
82 enabled = true;
83 host = "localhost";
84 port = config.services.redis.servers.matrix-synapse.port;
85 };
86 tls_certificate_path = "${bundle}/cert.pem";
87 tls_private_key_path = "${bundle}/key.pem";
88 registration_shared_secret = registrationSharedSecret;
89 public_baseurl = "https://example.com";
90 email = {
91 smtp_host = mailerDomain;
92 smtp_port = 25;
93 require_transport_security = true;
94 notif_from = "matrix <matrix@${mailerDomain}>";
95 app_name = "Matrix";
96 };
97 };
98 };
99 services.postgresql = {
100 enable = true;
101
102 # The database name and user are configured by the following options:
103 # - services.matrix-synapse.database_name
104 # - services.matrix-synapse.database_user
105 #
106 # The values used here represent the default values of the module.
107 initialScript = pkgs.writeText "synapse-init.sql" ''
108 CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
109 CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
110 TEMPLATE template0
111 LC_COLLATE = "C"
112 LC_CTYPE = "C";
113 '';
114 };
115
116 services.redis.servers.matrix-synapse = {
117 enable = true;
118 port = 6380;
119 };
120
121 networking.extraHosts = ''
122 ${mailserverIP} ${mailerDomain}
123 '';
124
125 security.pki.certificateFiles = [
126 mailerCerts.ca.cert
127 ca_pem
128 ];
129
130 environment.systemPackages =
131 let
132 sendTestMailStarttls = pkgs.writeScriptBin "send-testmail-starttls" ''
133 #!${pkgs.python3.interpreter}
134 import smtplib
135 import ssl
136
137 ctx = ssl.create_default_context()
138
139 with smtplib.SMTP('${mailerDomain}') as smtp:
140 smtp.ehlo()
141 smtp.starttls(context=ctx)
142 smtp.ehlo()
143 smtp.sendmail('matrix@${mailerDomain}', '${testEmail}', 'Subject: Test STARTTLS\n\nTest data.')
144 smtp.quit()
145 '';
146
147 obtainTokenAndRegisterEmail =
148 let
149 # adding the email through the API is quite complicated as it involves more than one step and some
150 # client-side calculation
151 insertEmailForAlice = pkgs.writeText "alice-email.sql" ''
152 INSERT INTO user_threepids (user_id, medium, address, validated_at, added_at) VALUES ('${testUser}@serverpostgres', 'email', '${testEmail}', '1629149927271', '1629149927270');
153 '';
154 in
155 pkgs.writeScriptBin "obtain-token-and-register-email" ''
156 #!${pkgs.runtimeShell}
157 set -o errexit
158 set -o pipefail
159 set -o nounset
160 su postgres -c "psql -d matrix-synapse -f ${insertEmailForAlice}"
161 curl --fail -XPOST 'https://localhost:8448/_matrix/client/r0/account/password/email/requestToken' -d '{"email":"${testEmail}","client_secret":"foobar","send_attempt":1}' -v
162 '';
163 in
164 [
165 sendTestMailStarttls
166 pkgs.matrix-synapse
167 obtainTokenAndRegisterEmail
168 ];
169 };
170
171 # test mail delivery
172 mailserver = args: {
173 security.pki.certificateFiles = [
174 mailerCerts.ca.cert
175 ];
176
177 networking.firewall.enable = false;
178
179 services.postfix = {
180 enable = true;
181 enableSubmission = true;
182
183 # blackhole transport
184 transport = "example.com discard:silently";
185
186 settings.main = {
187 myhostname = "${mailerDomain}";
188 # open relay for subnet
189 mynetworks_style = "subnet";
190 debug_peer_level = "10";
191 smtpd_relay_restrictions = [
192 "permit_mynetworks"
193 "reject_unauth_destination"
194 ];
195
196 # disable obsolete protocols, something old versions of twisted are still using
197 smtpd_tls_protocols = "TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3";
198 smtpd_tls_mandatory_protocols = "TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3";
199 smtpd_tls_chain_files = [
200 "${mailerCerts.${mailerDomain}.key}"
201 "${mailerCerts.${mailerDomain}.cert}"
202 ];
203 };
204 };
205 };
206
207 serversqlite = args: {
208 services.matrix-synapse = {
209 enable = true;
210 settings = {
211 inherit listeners;
212 database.name = "sqlite3";
213 tls_certificate_path = "${bundle}/cert.pem";
214 tls_private_key_path = "${bundle}/key.pem";
215 };
216 };
217 };
218 };
219
220 testScript = ''
221 start_all()
222 mailserver.wait_for_unit("postfix.service")
223 serverpostgres.succeed("send-testmail-starttls")
224 serverpostgres.wait_for_unit("matrix-synapse.service")
225 serverpostgres.wait_until_succeeds(
226 "curl --fail -L --cacert ${ca_pem} https://localhost:8448/"
227 )
228 serverpostgres.wait_until_succeeds(
229 "journalctl -u matrix-synapse.service | grep -q 'Connected to redis'"
230 )
231 serverpostgres.require_unit_state("postgresql.target")
232 serverpostgres.succeed("REQUESTS_CA_BUNDLE=${ca_pem} register_new_matrix_user -u ${testUser} -p ${testPassword} -a -k ${registrationSharedSecret} https://localhost:8448/")
233 serverpostgres.succeed("obtain-token-and-register-email")
234 serversqlite.wait_for_unit("matrix-synapse.service")
235 serversqlite.wait_until_succeeds(
236 "curl --fail -L --cacert ${ca_pem} https://localhost:8448/"
237 )
238 serversqlite.succeed("[ -e /var/lib/matrix-synapse/homeserver.db ]")
239 '';
240
241}