From 06261f5f31252a0171cbabe4036a4af8d9d42904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9B=A7-440729=20=5Bsophie=5D?= Date: Fri, 22 Nov 2024 19:08:45 +0100 Subject: [PATCH] nixos/mjolnir: add configuration options for native encryption --- nixos/modules/services/matrix/mjolnir.md | 33 +++++++-- nixos/modules/services/matrix/mjolnir.nix | 82 ++++++++++++++++------- 2 files changed, 85 insertions(+), 30 deletions(-) diff --git a/nixos/modules/services/matrix/mjolnir.md b/nixos/modules/services/matrix/mjolnir.md index 2594f05ce27bb..2401a2c9a863b 100644 --- a/nixos/modules/services/matrix/mjolnir.md +++ b/nixos/modules/services/matrix/mjolnir.md @@ -37,10 +37,31 @@ you'll need to make the Mjolnir user a Matrix server admin. Now invite the Mjolnir user to the management room. -It is recommended to use [Pantalaimon](https://github.com/matrix-org/pantalaimon), -so your management room can be encrypted. This also applies if you are looking to moderate an encrypted room. +It is recommended to enable encryption so your management room can be encrypted. This also applies +if you are looking to moderate an encrypted room. This can be done by enabling +[services.mjolnir.encryption](#opt-services.mjolnir.encryption.enable) and configuring a password +in [services.mjolnir.passwordFile](#opt-services.mjolnir.passwordFile). -To enable the Pantalaimon E2E Proxy for mjolnir, enable +```nix +{ + services.mjolnir = { + enable = true; + homeserverUrl = "https://matrix.domain.tld"; + passwordFile = "/run/secrets/mjolnir-password"; + encryption = { + enable = true; + username = "mjolnir"; + }; + protectedRooms = [ + "https://matrix.to/#/!xxx:domain.tld" + ]; + managementRoom = "!yyy:domain.tld"; + }; +} +``` + +Alternatively, using [Pantalaimon](https://github.com/matrix-org/pantalaimon) for encryption is +still supported, but deprecated. To enable the Pantalaimon E2E Proxy for mjolnir, enable [services.mjolnir.pantalaimon](#opt-services.mjolnir.pantalaimon.enable). This will autoconfigure a new Pantalaimon instance, which will connect to the homeserver set in [services.mjolnir.homeserverUrl](#opt-services.mjolnir.homeserverUrl) and Mjolnir itself @@ -51,10 +72,10 @@ will be configured to connect to the new Pantalaimon instance. services.mjolnir = { enable = true; homeserverUrl = "https://matrix.domain.tld"; + passwordFile = "/run/secrets/mjolnir-password"; pantalaimon = { - enable = true; - username = "mjolnir"; - passwordFile = "/run/secrets/mjolnir-password"; + enable = true; + username = "mjolnir"; }; protectedRooms = [ "https://matrix.to/#/!xxx:domain.tld" diff --git a/nixos/modules/services/matrix/mjolnir.nix b/nixos/modules/services/matrix/mjolnir.nix index 085f38e522e6e..c562180e79b14 100644 --- a/nixos/modules/services/matrix/mjolnir.nix +++ b/nixos/modules/services/matrix/mjolnir.nix @@ -15,10 +15,17 @@ let rawHomeserverUrl = cfg.homeserverUrl; pantalaimon = { + use = cfg.pantalaimon.enable; + } // lib.optionalAttrs cfg.pantalaimon.enable { inherit (cfg.pantalaimon) username; + password = "@MJOLNIR_PASSWORD@"; # will be replaced in "generateConfig" + }; - use = cfg.pantalaimon.enable; - password = "@PANTALAIMON_PASSWORD@"; # will be replaced in "generateConfig" + encryption = { + use = cfg.encryption.enable; + } // lib.optionalAttrs cfg.encryption.enable { + inherit (cfg.encryption) username; + password = "@MJOLNIR_PASSWORD@"; # will be replaced in "generateConfig" }; }; @@ -55,8 +62,8 @@ let ${lib.optionalString (cfg.accessTokenFile != null) '' ${pkgs.replace-secret}/bin/replace-secret '@ACCESS_TOKEN@' '${cfg.accessTokenFile}' ${cfg.dataPath}/config/default.yaml ''} - ${lib.optionalString (cfg.pantalaimon.passwordFile != null) '' - ${pkgs.replace-secret}/bin/replace-secret '@PANTALAIMON_PASSWORD@' '${cfg.pantalaimon.passwordFile}' ${cfg.dataPath}/config/default.yaml + ${lib.optionalString (cfg.passwordFile != null) '' + ${pkgs.replace-secret}/bin/replace-secret '@MJOLNIR_PASSWORD@' '${cfg.passwordFile}' ${cfg.dataPath}/config/default.yaml ''} '' ); @@ -81,6 +88,17 @@ in default = null; description = '' File containing the matrix access token for the `mjolnir` user. + + Required when neither encryption or pantalaimon is enabled. + ''; + }; + passwordFile = lib.mkOption { + type = with lib.types; nullOr path; + default = null; + description = '' + File containing the matrix password for the `mjolnir` user. + + Required when encryption or pantalaimon is enabled. ''; }; @@ -89,13 +107,15 @@ in `pantalaimon` options (enables E2E Encryption support). This will create a `pantalaimon` instance with the name "mjolnir". + + Mutually exclusive with setting `config.services.mjolnir.encryption.enable`. ''; default = { }; type = lib.types.submodule { options = { enable = lib.mkEnableOption '' - ignoring the accessToken. If true, accessToken is ignored and the username/password below will be - used instead. The access token of the bot will be stored in the dataPath + Ignoring the accessToken. If true, accessToken is ignored and username/password will be + used instead. The access token of the bot will be stored in the dataPath. ''; username = lib.mkOption { @@ -103,14 +123,6 @@ in description = "The username to login with."; }; - passwordFile = lib.mkOption { - type = with lib.types; nullOr path; - default = null; - description = '' - File containing the matrix password for the `mjolnir` user. - ''; - }; - options = lib.mkOption { type = lib.types.submodule (import ./pantalaimon-options.nix); default = { }; @@ -122,6 +134,28 @@ in }; }; + encryption = lib.mkOption { + description = '' + `encryption` options (enables native E2E Encryption support without using pantalaimon as proxy). + + Mutually exclusive with setting `config.services.mjolnir.pantalaimon.enable`. + ''; + default = { }; + type = lib.types.submodule { + options = { + enable = lib.mkEnableOption '' + Ignoring the accessToken. If true, accessToken is ignored and username/password will be + used instead. The access token of the bot will be stored in the dataPath. + ''; + + username = lib.mkOption { + type = lib.types.str; + description = "The username to login with."; + }; + }; + }; + }; + dataPath = lib.mkOption { type = lib.types.path; default = "/var/lib/mjolnir"; @@ -173,23 +207,23 @@ in config = lib.mkIf config.services.mjolnir.enable { assertions = [ { - assertion = !(cfg.pantalaimon.enable && cfg.pantalaimon.passwordFile == null); - message = "Specify pantalaimon.passwordFile"; + assertion = (cfg.pantalaimon.enable || cfg.encryption.enable) -> cfg.passwordFile != null; + message = "Enabling pantalaimon or encryption requires setting config.services.mjolnir.passwordFile"; + } + { + assertion = (cfg.pantalaimon.enable || cfg.encryption.enable) -> cfg.accessTokenFile == null; + message = "Do not specify accessTokenFile when enabling pantalaimon or encryption"; } { - assertion = !(cfg.pantalaimon.enable && cfg.accessTokenFile != null); - message = "Do not specify accessTokenFile when using pantalaimon"; + assertion = !(cfg.pantalaimon.enable && cfg.encryption.enable); + message = "Only one of encryption or pantalaimon may be enabled, not both"; } { - assertion = !(!cfg.pantalaimon.enable && cfg.accessTokenFile == null); - message = "Specify accessTokenFile when not using pantalaimon"; + assertion = !(cfg.pantalaimon.enable || cfg.encryption.enable) -> cfg.accessTokenFile != null; + message = "Specify accessTokenFile when not using pantalaimon or encryption"; } ]; - # This defaults to true in the application, - # which breaks older configs using pantalaimon or access tokens - services.mjolnir.settings.encryption.use = lib.mkDefault false; - services.pantalaimon-headless.instances."mjolnir" = lib.mkIf cfg.pantalaimon.enable { homeserver = cfg.homeserverUrl;