diff options
Diffstat (limited to 'nixpkgs/nixos/tests/matrix')
-rw-r--r-- | nixpkgs/nixos/tests/matrix/appservice-irc.nix | 225 | ||||
-rw-r--r-- | nixpkgs/nixos/tests/matrix/conduit.nix | 97 | ||||
-rw-r--r-- | nixpkgs/nixos/tests/matrix/dendrite.nix | 101 | ||||
-rw-r--r-- | nixpkgs/nixos/tests/matrix/mjolnir.nix | 176 | ||||
-rw-r--r-- | nixpkgs/nixos/tests/matrix/pantalaimon.nix | 88 | ||||
-rw-r--r-- | nixpkgs/nixos/tests/matrix/synapse-workers.nix | 50 | ||||
-rw-r--r-- | nixpkgs/nixos/tests/matrix/synapse.nix | 218 |
7 files changed, 955 insertions, 0 deletions
diff --git a/nixpkgs/nixos/tests/matrix/appservice-irc.nix b/nixpkgs/nixos/tests/matrix/appservice-irc.nix new file mode 100644 index 000000000000..78c53024ca6c --- /dev/null +++ b/nixpkgs/nixos/tests/matrix/appservice-irc.nix @@ -0,0 +1,225 @@ +import ../make-test-python.nix ({ pkgs, ... }: + let + homeserverUrl = "http://homeserver:8008"; + in + { + name = "matrix-appservice-irc"; + meta = { + maintainers = pkgs.matrix-appservice-irc.meta.maintainers; + }; + + nodes = { + homeserver = { pkgs, ... }: { + # We'll switch to this once the config is copied into place + specialisation.running.configuration = { + services.matrix-synapse = { + enable = true; + settings = { + database.name = "sqlite3"; + app_service_config_files = [ "/registration.yml" ]; + + enable_registration = true; + + # don't use this in production, always use some form of verification + enable_registration_without_verification = true; + + listeners = [ { + # The default but tls=false + bind_addresses = [ + "0.0.0.0" + ]; + port = 8008; + resources = [ { + "compress" = true; + "names" = [ "client" ]; + } { + "compress" = false; + "names" = [ "federation" ]; + } ]; + tls = false; + type = "http"; + } ]; + }; + }; + + networking.firewall.allowedTCPPorts = [ 8008 ]; + }; + }; + + ircd = { pkgs, ... }: { + services.ngircd = { + enable = true; + config = '' + [Global] + Name = ircd.ircd + Info = Server Info Text + AdminInfo1 = _ + + [Channel] + Name = #test + Topic = a cool place + + [Options] + PAM = no + ''; + }; + networking.firewall.allowedTCPPorts = [ 6667 ]; + }; + + appservice = { pkgs, ... }: { + services.matrix-appservice-irc = { + enable = true; + registrationUrl = "http://appservice:8009"; + + settings = { + homeserver.url = homeserverUrl; + homeserver.domain = "homeserver"; + + ircService.servers."ircd" = { + name = "IRCd"; + port = 6667; + dynamicChannels = { + enabled = true; + aliasTemplate = "#irc_$CHANNEL"; + }; + }; + }; + }; + + networking.firewall.allowedTCPPorts = [ 8009 ]; + }; + + client = { pkgs, ... }: { + environment.systemPackages = [ + (pkgs.writers.writePython3Bin "do_test" + { + libraries = [ pkgs.python3Packages.matrix-nio ]; + flakeIgnore = [ + # We don't live in the dark ages anymore. + # Languages like Python that are whitespace heavy will overrun + # 79 characters.. + "E501" + ]; + } '' + import sys + import socket + import functools + from time import sleep + import asyncio + + from nio import AsyncClient, RoomMessageText, JoinResponse + + + async def matrix_room_message_text_callback(matrix: AsyncClient, msg: str, _r, e): + print("Received matrix text message: ", e) + if msg in e.body: + print("Received hi from IRC") + await matrix.close() + exit(0) # Actual exit point + + + class IRC: + def __init__(self): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect(("ircd", 6667)) + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + sock.send(b"USER bob bob bob :bob\n") + sock.send(b"NICK bob\n") + self.sock = sock + + def join(self, room: str): + self.sock.send(f"JOIN {room}\n".encode()) + + def privmsg(self, room: str, msg: str): + self.sock.send(f"PRIVMSG {room} :{msg}\n".encode()) + + def expect_msg(self, body: str): + buffer = "" + while True: + buf = self.sock.recv(1024).decode() + buffer += buf + if body in buffer: + return + + + async def run(homeserver: str): + irc = IRC() + + matrix = AsyncClient(homeserver) + response = await matrix.register("alice", "foobar") + print("Matrix register response: ", response) + + response = await matrix.join("#irc_#test:homeserver") + print("Matrix join room response:", response) + assert isinstance(response, JoinResponse) + room_id = response.room_id + + irc.join("#test") + # FIXME: what are we waiting on here? Matrix? IRC? Both? + # 10s seem bad for busy hydra machines. + sleep(10) + + # Exchange messages + print("Sending text message to matrix room") + response = await matrix.room_send( + room_id=room_id, + message_type="m.room.message", + content={"msgtype": "m.text", "body": "hi from matrix"}, + ) + print("Matrix room send response: ", response) + irc.privmsg("#test", "hi from irc") + + print("Waiting for the matrix message to appear on the IRC side...") + irc.expect_msg("hi from matrix") + + callback = functools.partial( + matrix_room_message_text_callback, matrix, "hi from irc" + ) + matrix.add_event_callback(callback, RoomMessageText) + + print("Waiting for matrix message...") + await matrix.sync_forever() + + exit(1) # Unreachable + + + if __name__ == "__main__": + asyncio.run(run(sys.argv[1])) + '' + ) + ]; + }; + }; + + testScript = '' + import pathlib + import os + + start_all() + + ircd.wait_for_unit("ngircd.service") + ircd.wait_for_open_port(6667) + + with subtest("start the appservice"): + appservice.wait_for_unit("matrix-appservice-irc.service") + appservice.wait_for_open_port(8009) + + with subtest("copy the registration file"): + appservice.copy_from_vm("/var/lib/matrix-appservice-irc/registration.yml") + homeserver.copy_from_host( + str(pathlib.Path(os.environ.get("out", os.getcwd())) / "registration.yml"), "/" + ) + homeserver.succeed("chmod 444 /registration.yml") + + with subtest("start the homeserver"): + homeserver.succeed( + "/run/current-system/specialisation/running/bin/switch-to-configuration test >&2" + ) + + homeserver.wait_for_unit("matrix-synapse.service") + homeserver.wait_for_open_port(8008) + + with subtest("ensure messages can be exchanged"): + client.succeed("do_test ${homeserverUrl} >&2") + ''; + }) diff --git a/nixpkgs/nixos/tests/matrix/conduit.nix b/nixpkgs/nixos/tests/matrix/conduit.nix new file mode 100644 index 000000000000..2b81c23598eb --- /dev/null +++ b/nixpkgs/nixos/tests/matrix/conduit.nix @@ -0,0 +1,97 @@ +import ../make-test-python.nix ({ pkgs, ... }: + let + name = "conduit"; + in + { + name = "matrix-conduit"; + + nodes = { + conduit = args: { + services.matrix-conduit = { + enable = true; + settings.global.server_name = name; + settings.global.allow_registration = true; + extraEnvironment.RUST_BACKTRACE = "yes"; + }; + services.nginx = { + enable = true; + virtualHosts.${name} = { + enableACME = false; + forceSSL = false; + enableSSL = false; + + locations."/_matrix" = { + proxyPass = "http://[::1]:6167"; + }; + }; + }; + networking.firewall.allowedTCPPorts = [ 80 ]; + }; + client = { pkgs, ... }: { + environment.systemPackages = [ + ( + pkgs.writers.writePython3Bin "do_test" + { libraries = [ pkgs.python3Packages.matrix-nio ]; } '' + import asyncio + + from nio import AsyncClient + + + async def main() -> None: + # Connect to conduit + client = AsyncClient("http://conduit:80", "alice") + + # Register as user alice + response = await client.register("alice", "my-secret-password") + + # Log in as user alice + response = await client.login("my-secret-password") + + # Create a new room + response = await client.room_create(federate=False) + room_id = response.room_id + + # Join the room + response = await client.join(room_id) + + # Send a message to the room + response = await client.room_send( + room_id=room_id, + message_type="m.room.message", + content={ + "msgtype": "m.text", + "body": "Hello conduit!" + } + ) + + # Sync responses + response = await client.sync(timeout=30000) + + # Check the message was received by conduit + last_message = response.rooms.join[room_id].timeline.events[-1].body + assert last_message == "Hello conduit!" + + # Leave the room + response = await client.room_leave(room_id) + + # Close the client + await client.close() + + asyncio.get_event_loop().run_until_complete(main()) + '' + ) + ]; + }; + }; + + testScript = '' + start_all() + + with subtest("start conduit"): + conduit.wait_for_unit("conduit.service") + conduit.wait_for_open_port(80) + + with subtest("ensure messages can be exchanged"): + client.succeed("do_test") + ''; + }) diff --git a/nixpkgs/nixos/tests/matrix/dendrite.nix b/nixpkgs/nixos/tests/matrix/dendrite.nix new file mode 100644 index 000000000000..82e71d912130 --- /dev/null +++ b/nixpkgs/nixos/tests/matrix/dendrite.nix @@ -0,0 +1,101 @@ +import ../make-test-python.nix ( + { pkgs, ... }: + let + homeserverUrl = "http://homeserver:8008"; + + private_key = pkgs.runCommand "matrix_key.pem" { + buildInputs = [ pkgs.dendrite ]; + } "generate-keys --private-key $out"; + in + { + name = "dendrite"; + meta = with pkgs.lib; { + maintainers = teams.matrix.members; + }; + + nodes = { + homeserver = { pkgs, ... }: { + services.dendrite = { + enable = true; + loadCredential = [ "test_private_key:${private_key}" ]; + openRegistration = true; + settings = { + global.server_name = "test-dendrite-server.com"; + global.private_key = "$CREDENTIALS_DIRECTORY/test_private_key"; + client_api.registration_disabled = false; + }; + }; + + networking.firewall.allowedTCPPorts = [ 8008 ]; + }; + + client = { pkgs, ... }: { + environment.systemPackages = [ + ( + pkgs.writers.writePython3Bin "do_test" + { libraries = [ pkgs.python3Packages.matrix-nio ]; } '' + import asyncio + + from nio import AsyncClient + + + async def main() -> None: + # Connect to dendrite + client = AsyncClient("http://homeserver:8008", "alice") + + # Register as user alice + response = await client.register("alice", "my-secret-password") + + # Log in as user alice + response = await client.login("my-secret-password") + + # Create a new room + response = await client.room_create(federate=False) + room_id = response.room_id + + # Join the room + response = await client.join(room_id) + + # Send a message to the room + response = await client.room_send( + room_id=room_id, + message_type="m.room.message", + content={ + "msgtype": "m.text", + "body": "Hello world!" + } + ) + + # Sync responses + response = await client.sync(timeout=30000) + + # Check the message was received by dendrite + last_message = response.rooms.join[room_id].timeline.events[-1].body + assert last_message == "Hello world!" + + # Leave the room + response = await client.room_leave(room_id) + + # Close the client + await client.close() + + asyncio.get_event_loop().run_until_complete(main()) + '' + ) + ]; + }; + }; + + testScript = '' + start_all() + + with subtest("start the homeserver"): + homeserver.wait_for_unit("dendrite.service") + homeserver.wait_for_open_port(8008) + + with subtest("ensure messages can be exchanged"): + client.succeed("do_test") + ''; + + } +) diff --git a/nixpkgs/nixos/tests/matrix/mjolnir.nix b/nixpkgs/nixos/tests/matrix/mjolnir.nix new file mode 100644 index 000000000000..8a888b17a3d7 --- /dev/null +++ b/nixpkgs/nixos/tests/matrix/mjolnir.nix @@ -0,0 +1,176 @@ +import ../make-test-python.nix ( + { pkgs, ... }: + let + # Set up SSL certs for Synapse to be happy. + runWithOpenSSL = file: cmd: pkgs.runCommand file + { + buildInputs = [ pkgs.openssl ]; + } + cmd; + + ca_key = runWithOpenSSL "ca-key.pem" "openssl genrsa -out $out 2048"; + ca_pem = runWithOpenSSL "ca.pem" '' + openssl req \ + -x509 -new -nodes -key ${ca_key} \ + -days 10000 -out $out -subj "/CN=snakeoil-ca" + ''; + key = runWithOpenSSL "matrix_key.pem" "openssl genrsa -out $out 2048"; + csr = runWithOpenSSL "matrix.csr" '' + openssl req \ + -new -key ${key} \ + -out $out -subj "/CN=localhost" \ + ''; + cert = runWithOpenSSL "matrix_cert.pem" '' + openssl x509 \ + -req -in ${csr} \ + -CA ${ca_pem} -CAkey ${ca_key} \ + -CAcreateserial -out $out \ + -days 365 + ''; + in + { + name = "mjolnir"; + meta = with pkgs.lib; { + maintainers = teams.matrix.members; + }; + + nodes = { + homeserver = { pkgs, ... }: { + services.matrix-synapse = { + enable = true; + settings = { + database.name = "sqlite3"; + tls_certificate_path = "${cert}"; + tls_private_key_path = "${key}"; + enable_registration = true; + enable_registration_without_verification = true; + registration_shared_secret = "supersecret-registration"; + + listeners = [ { + # The default but tls=false + bind_addresses = [ + "0.0.0.0" + ]; + port = 8448; + resources = [ { + compress = true; + names = [ "client" ]; + } { + compress = false; + names = [ "federation" ]; + } ]; + tls = false; + type = "http"; + x_forwarded = false; + } ]; + }; + }; + + networking.firewall.allowedTCPPorts = [ 8448 ]; + + environment.systemPackages = [ + (pkgs.writeShellScriptBin "register_mjolnir_user" '' + exec ${pkgs.matrix-synapse}/bin/register_new_matrix_user \ + -u mjolnir \ + -p mjolnir-password \ + --admin \ + --shared-secret supersecret-registration \ + http://localhost:8448 + '' + ) + (pkgs.writeShellScriptBin "register_moderator_user" '' + exec ${pkgs.matrix-synapse}/bin/register_new_matrix_user \ + -u moderator \ + -p moderator-password \ + --no-admin \ + --shared-secret supersecret-registration \ + http://localhost:8448 + '' + ) + ]; + }; + + mjolnir = { pkgs, ... }: { + services.mjolnir = { + enable = true; + homeserverUrl = "http://homeserver:8448"; + pantalaimon = { + enable = true; + username = "mjolnir"; + passwordFile = pkgs.writeText "password.txt" "mjolnir-password"; + # otherwise mjolnir tries to connect to ::1, which is not listened by pantalaimon + options.listenAddress = "127.0.0.1"; + }; + managementRoom = "#moderators:homeserver"; + }; + }; + + client = { pkgs, ... }: { + environment.systemPackages = [ + (pkgs.writers.writePython3Bin "create_management_room_and_invite_mjolnir" + { libraries = with pkgs.python3Packages; [ + matrix-nio + ] ++ matrix-nio.optional-dependencies.e2e; + } '' + import asyncio + + from nio import ( + AsyncClient, + EnableEncryptionBuilder + ) + + + async def main() -> None: + client = AsyncClient("http://homeserver:8448", "moderator") + + await client.login("moderator-password") + + room = await client.room_create( + name="Moderators", + alias="moderators", + initial_state=[EnableEncryptionBuilder().as_dict()], + ) + + await client.join(room.room_id) + await client.room_invite(room.room_id, "@mjolnir:homeserver") + + asyncio.run(main()) + '' + ) + ]; + }; + }; + + testScript = '' + with subtest("start homeserver"): + homeserver.start() + + homeserver.wait_for_unit("matrix-synapse.service") + homeserver.wait_until_succeeds("curl --fail -L http://localhost:8448/") + + with subtest("register users"): + # register mjolnir user + homeserver.succeed("register_mjolnir_user") + # register moderator user + homeserver.succeed("register_moderator_user") + + with subtest("start mjolnir"): + mjolnir.start() + + # wait for pantalaimon to be ready + mjolnir.wait_for_unit("pantalaimon-mjolnir.service") + mjolnir.wait_for_unit("mjolnir.service") + + mjolnir.wait_until_succeeds("curl --fail -L http://localhost:8009/") + + with subtest("ensure mjolnir can be invited to the management room"): + client.start() + + client.wait_until_succeeds("curl --fail -L http://homeserver:8448/") + + client.succeed("create_management_room_and_invite_mjolnir") + + mjolnir.wait_for_console_text("Startup complete. Now monitoring rooms") + ''; + } +) diff --git a/nixpkgs/nixos/tests/matrix/pantalaimon.nix b/nixpkgs/nixos/tests/matrix/pantalaimon.nix new file mode 100644 index 000000000000..b5d649e6517a --- /dev/null +++ b/nixpkgs/nixos/tests/matrix/pantalaimon.nix @@ -0,0 +1,88 @@ +import ../make-test-python.nix ( + { pkgs, ... }: + let + pantalaimonInstanceName = "testing"; + + # Set up SSL certs for Synapse to be happy. + runWithOpenSSL = file: cmd: pkgs.runCommand file + { + buildInputs = [ pkgs.openssl ]; + } + cmd; + + ca_key = runWithOpenSSL "ca-key.pem" "openssl genrsa -out $out 2048"; + ca_pem = runWithOpenSSL "ca.pem" '' + openssl req \ + -x509 -new -nodes -key ${ca_key} \ + -days 10000 -out $out -subj "/CN=snakeoil-ca" + ''; + key = runWithOpenSSL "matrix_key.pem" "openssl genrsa -out $out 2048"; + csr = runWithOpenSSL "matrix.csr" '' + openssl req \ + -new -key ${key} \ + -out $out -subj "/CN=localhost" \ + ''; + cert = runWithOpenSSL "matrix_cert.pem" '' + openssl x509 \ + -req -in ${csr} \ + -CA ${ca_pem} -CAkey ${ca_key} \ + -CAcreateserial -out $out \ + -days 365 + ''; + in + { + name = "pantalaimon"; + meta = with pkgs.lib; { + maintainers = teams.matrix.members; + }; + + nodes.machine = { pkgs, ... }: { + services.pantalaimon-headless.instances.${pantalaimonInstanceName} = { + homeserver = "https://localhost:8448"; + listenAddress = "0.0.0.0"; + listenPort = 8888; + logLevel = "debug"; + ssl = false; + }; + + services.matrix-synapse = { + enable = true; + settings = { + listeners = [ { + port = 8448; + bind_addresses = [ + "127.0.0.1" + "::1" + ]; + type = "http"; + tls = true; + x_forwarded = false; + resources = [ { + names = [ + "client" + ]; + compress = true; + } { + names = [ + "federation" + ]; + compress = false; + } ]; + } ]; + database.name = "sqlite3"; + tls_certificate_path = "${cert}"; + tls_private_key_path = "${key}"; + }; + }; + }; + + testScript = '' + start_all() + machine.wait_for_unit("pantalaimon-${pantalaimonInstanceName}.service") + machine.wait_for_unit("matrix-synapse.service") + machine.wait_until_succeeds( + "curl --fail -L http://localhost:8888/" + ) + ''; + } +) diff --git a/nixpkgs/nixos/tests/matrix/synapse-workers.nix b/nixpkgs/nixos/tests/matrix/synapse-workers.nix new file mode 100644 index 000000000000..e90301aeae9e --- /dev/null +++ b/nixpkgs/nixos/tests/matrix/synapse-workers.nix @@ -0,0 +1,50 @@ +import ../make-test-python.nix ({ pkgs, ... }: { + name = "matrix-synapse-workers"; + meta = with pkgs.lib; { + maintainers = teams.matrix.members; + }; + + nodes = { + homeserver = + { pkgs + , nodes + , ... + }: { + services.postgresql = { + enable = true; + initialScript = pkgs.writeText "synapse-init.sql" '' + CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse'; + CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse" + TEMPLATE template0 + LC_COLLATE = "C" + LC_CTYPE = "C"; + ''; + }; + + services.matrix-synapse = { + enable = true; + settings = { + database = { + name = "psycopg2"; + args.password = "synapse"; + }; + enable_registration = true; + enable_registration_without_verification = true; + + federation_sender_instances = [ "federation_sender" ]; + }; + configureRedisLocally = true; + workers = { + "federation_sender" = { }; + }; + }; + }; + }; + + testScript = '' + start_all() + + homeserver.wait_for_unit("matrix-synapse.service"); + homeserver.wait_for_unit("matrix-synapse-worker-federation_sender.service"); + ''; +}) diff --git a/nixpkgs/nixos/tests/matrix/synapse.nix b/nixpkgs/nixos/tests/matrix/synapse.nix new file mode 100644 index 000000000000..8c10a575ffbd --- /dev/null +++ b/nixpkgs/nixos/tests/matrix/synapse.nix @@ -0,0 +1,218 @@ +import ../make-test-python.nix ({ pkgs, ... } : let + + ca_key = mailerCerts.ca.key; + ca_pem = mailerCerts.ca.cert; + + bundle = pkgs.runCommand "bundle" { + nativeBuildInputs = [ pkgs.minica ]; + } '' + minica -ca-cert ${ca_pem} -ca-key ${ca_key} \ + -domains localhost + install -Dm444 -t $out localhost/{key,cert}.pem + ''; + + mailerCerts = import ../common/acme/server/snakeoil-certs.nix; + mailerDomain = mailerCerts.domain; + registrationSharedSecret = "unsecure123"; + testUser = "alice"; + testPassword = "alicealice"; + testEmail = "alice@example.com"; + + listeners = [ { + port = 8448; + bind_addresses = [ + "127.0.0.1" + "::1" + ]; + type = "http"; + tls = true; + x_forwarded = false; + resources = [ { + names = [ + "client" + ]; + compress = true; + } { + names = [ + "federation" + ]; + compress = false; + } ]; + } ]; + +in { + + name = "matrix-synapse"; + meta = with pkgs.lib; { + maintainers = teams.matrix.members; + }; + + nodes = { + # Since 0.33.0, matrix-synapse doesn't allow underscores in server names + serverpostgres = { pkgs, nodes, config, ... }: let + mailserverIP = nodes.mailserver.config.networking.primaryIPAddress; + in + { + services.matrix-synapse = { + enable = true; + settings = { + inherit listeners; + database = { + name = "psycopg2"; + args.password = "synapse"; + }; + redis = { + enabled = true; + host = "localhost"; + port = config.services.redis.servers.matrix-synapse.port; + }; + tls_certificate_path = "${bundle}/cert.pem"; + tls_private_key_path = "${bundle}/key.pem"; + registration_shared_secret = registrationSharedSecret; + public_baseurl = "https://example.com"; + email = { + smtp_host = mailerDomain; + smtp_port = 25; + require_transport_security = true; + notif_from = "matrix <matrix@${mailerDomain}>"; + app_name = "Matrix"; + }; + }; + }; + services.postgresql = { + enable = true; + + # The database name and user are configured by the following options: + # - services.matrix-synapse.database_name + # - services.matrix-synapse.database_user + # + # The values used here represent the default values of the module. + initialScript = pkgs.writeText "synapse-init.sql" '' + CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse'; + CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse" + TEMPLATE template0 + LC_COLLATE = "C" + LC_CTYPE = "C"; + ''; + }; + + services.redis.servers.matrix-synapse = { + enable = true; + port = 6380; + }; + + networking.extraHosts = '' + ${mailserverIP} ${mailerDomain} + ''; + + security.pki.certificateFiles = [ + mailerCerts.ca.cert ca_pem + ]; + + environment.systemPackages = let + sendTestMailStarttls = pkgs.writeScriptBin "send-testmail-starttls" '' + #!${pkgs.python3.interpreter} + import smtplib + import ssl + + ctx = ssl.create_default_context() + + with smtplib.SMTP('${mailerDomain}') as smtp: + smtp.ehlo() + smtp.starttls(context=ctx) + smtp.ehlo() + smtp.sendmail('matrix@${mailerDomain}', '${testEmail}', 'Subject: Test STARTTLS\n\nTest data.') + smtp.quit() + ''; + + obtainTokenAndRegisterEmail = let + # adding the email through the API is quite complicated as it involves more than one step and some + # client-side calculation + insertEmailForAlice = pkgs.writeText "alice-email.sql" '' + INSERT INTO user_threepids (user_id, medium, address, validated_at, added_at) VALUES ('${testUser}@serverpostgres', 'email', '${testEmail}', '1629149927271', '1629149927270'); + ''; + in + pkgs.writeScriptBin "obtain-token-and-register-email" '' + #!${pkgs.runtimeShell} + set -o errexit + set -o pipefail + set -o nounset + su postgres -c "psql -d matrix-synapse -f ${insertEmailForAlice}" + curl --fail -XPOST 'https://localhost:8448/_matrix/client/r0/account/password/email/requestToken' -d '{"email":"${testEmail}","client_secret":"foobar","send_attempt":1}' -v + ''; + in [ sendTestMailStarttls pkgs.matrix-synapse obtainTokenAndRegisterEmail ]; + }; + + # test mail delivery + mailserver = args: let + in + { + security.pki.certificateFiles = [ + mailerCerts.ca.cert + ]; + + networking.firewall.enable = false; + + services.postfix = { + enable = true; + hostname = "${mailerDomain}"; + # open relay for subnet + networksStyle = "subnet"; + enableSubmission = true; + tlsTrustedAuthorities = "${mailerCerts.ca.cert}"; + sslCert = "${mailerCerts.${mailerDomain}.cert}"; + sslKey = "${mailerCerts.${mailerDomain}.key}"; + + # blackhole transport + transport = "example.com discard:silently"; + + config = { + debug_peer_level = "10"; + smtpd_relay_restrictions = [ + "permit_mynetworks" "reject_unauth_destination" + ]; + + # disable obsolete protocols, something old versions of twisted are still using + smtpd_tls_protocols = "TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3"; + smtp_tls_protocols = "TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3"; + smtpd_tls_mandatory_protocols = "TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3"; + smtp_tls_mandatory_protocols = "TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3"; + }; + }; + }; + + serversqlite = args: { + services.matrix-synapse = { + enable = true; + settings = { + inherit listeners; + database.name = "sqlite3"; + tls_certificate_path = "${bundle}/cert.pem"; + tls_private_key_path = "${bundle}/key.pem"; + }; + }; + }; + }; + + testScript = '' + start_all() + mailserver.wait_for_unit("postfix.service") + serverpostgres.succeed("send-testmail-starttls") + serverpostgres.wait_for_unit("matrix-synapse.service") + serverpostgres.wait_until_succeeds( + "curl --fail -L --cacert ${ca_pem} https://localhost:8448/" + ) + serverpostgres.wait_until_succeeds( + "journalctl -u matrix-synapse.service | grep -q 'Connected to redis'" + ) + serverpostgres.require_unit_state("postgresql.service") + serverpostgres.succeed("REQUESTS_CA_BUNDLE=${ca_pem} register_new_matrix_user -u ${testUser} -p ${testPassword} -a -k ${registrationSharedSecret} https://localhost:8448/") + serverpostgres.succeed("obtain-token-and-register-email") + serversqlite.wait_for_unit("matrix-synapse.service") + serversqlite.wait_until_succeeds( + "curl --fail -L --cacert ${ca_pem} https://localhost:8448/" + ) + serversqlite.succeed("[ -e /var/lib/matrix-synapse/homeserver.db ]") + ''; + +}) |