1{ pkgs, ... }:
2let
3 # Set up SSL certs for Synapse to be happy.
4 runWithOpenSSL =
5 file: cmd:
6 pkgs.runCommand file {
7 buildInputs = [ pkgs.openssl ];
8 } cmd;
9
10 ca_key = runWithOpenSSL "ca-key.pem" "openssl genrsa -out $out 2048";
11 ca_pem = runWithOpenSSL "ca.pem" ''
12 openssl req \
13 -x509 -new -nodes -key ${ca_key} \
14 -days 10000 -out $out -subj "/CN=snakeoil-ca"
15 '';
16 key = runWithOpenSSL "matrix_key.pem" "openssl genrsa -out $out 2048";
17 csr = runWithOpenSSL "matrix.csr" ''
18 openssl req \
19 -new -key ${key} \
20 -out $out -subj "/CN=localhost" \
21 '';
22 cert = runWithOpenSSL "matrix_cert.pem" ''
23 openssl x509 \
24 -req -in ${csr} \
25 -CA ${ca_pem} -CAkey ${ca_key} \
26 -CAcreateserial -out $out \
27 -days 365
28 '';
29in
30{
31 name = "mjolnir";
32 meta = {
33 inherit (pkgs.mjolnir.meta) maintainers;
34 };
35
36 nodes = {
37 homeserver =
38 { pkgs, ... }:
39 {
40 services.matrix-synapse = {
41 enable = true;
42 settings = {
43 database.name = "sqlite3";
44 tls_certificate_path = "${cert}";
45 tls_private_key_path = "${key}";
46 enable_registration = true;
47 enable_registration_without_verification = true;
48 registration_shared_secret = "supersecret-registration";
49
50 listeners = [
51 {
52 # The default but tls=false
53 bind_addresses = [
54 "0.0.0.0"
55 ];
56 port = 8448;
57 resources = [
58 {
59 compress = true;
60 names = [ "client" ];
61 }
62 {
63 compress = false;
64 names = [ "federation" ];
65 }
66 ];
67 tls = false;
68 type = "http";
69 x_forwarded = false;
70 }
71 ];
72 };
73 };
74
75 networking.firewall.allowedTCPPorts = [ 8448 ];
76
77 environment.systemPackages = [
78 (pkgs.writeShellScriptBin "register_mjolnir_user" ''
79 exec ${pkgs.matrix-synapse}/bin/register_new_matrix_user \
80 -u mjolnir \
81 -p mjolnir-password \
82 --admin \
83 --shared-secret supersecret-registration \
84 http://localhost:8448
85 '')
86 (pkgs.writeShellScriptBin "register_moderator_user" ''
87 exec ${pkgs.matrix-synapse}/bin/register_new_matrix_user \
88 -u moderator \
89 -p moderator-password \
90 --no-admin \
91 --shared-secret supersecret-registration \
92 http://localhost:8448
93 '')
94 ];
95 };
96
97 mjolnir =
98 { pkgs, ... }:
99 {
100 services.mjolnir = {
101 enable = true;
102 homeserverUrl = "http://homeserver:8448";
103 pantalaimon = {
104 enable = true;
105 username = "mjolnir";
106 passwordFile = pkgs.writeText "password.txt" "mjolnir-password";
107 # otherwise mjolnir tries to connect to ::1, which is not listened by pantalaimon
108 options.listenAddress = "127.0.0.1";
109 };
110 managementRoom = "#moderators:homeserver";
111 };
112 };
113
114 client =
115 { pkgs, ... }:
116 {
117 environment.systemPackages = [
118 (pkgs.writers.writePython3Bin "create_management_room_and_invite_mjolnir"
119 {
120 libraries = with pkgs.python3Packages; [
121 (matrix-nio.override { withOlm = true; })
122 ];
123 }
124 ''
125 import asyncio
126
127 from nio import (
128 AsyncClient,
129 EnableEncryptionBuilder
130 )
131
132
133 async def main() -> None:
134 client = AsyncClient("http://homeserver:8448", "moderator")
135
136 await client.login("moderator-password")
137
138 room = await client.room_create(
139 name="Moderators",
140 alias="moderators",
141 initial_state=[EnableEncryptionBuilder().as_dict()],
142 )
143
144 await client.join(room.room_id)
145 await client.room_invite(room.room_id, "@mjolnir:homeserver")
146
147 asyncio.run(main())
148 ''
149 )
150 ];
151 };
152 };
153
154 testScript = ''
155 with subtest("start homeserver"):
156 homeserver.start()
157
158 homeserver.wait_for_unit("matrix-synapse.service")
159 homeserver.wait_until_succeeds("curl --fail -L http://localhost:8448/")
160
161 with subtest("register users"):
162 # register mjolnir user
163 homeserver.succeed("register_mjolnir_user")
164 # register moderator user
165 homeserver.succeed("register_moderator_user")
166
167 with subtest("start mjolnir"):
168 mjolnir.start()
169
170 # wait for pantalaimon to be ready
171 mjolnir.wait_for_unit("pantalaimon-mjolnir.service")
172 mjolnir.wait_for_unit("mjolnir.service")
173
174 mjolnir.wait_until_succeeds("curl --fail -L http://localhost:8009/")
175
176 with subtest("ensure mjolnir can be invited to the management room"):
177 client.start()
178
179 client.wait_until_succeeds("curl --fail -L http://homeserver:8448/")
180
181 client.succeed("create_management_room_and_invite_mjolnir")
182
183 mjolnir.wait_for_console_text("Startup complete. Now monitoring rooms")
184 '';
185}