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