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