diff --git a/nixos/doc/manual/release-notes/rl-2305.section.md b/nixos/doc/manual/release-notes/rl-2305.section.md index 5bc5a8245211..d80d3556e377 100644 --- a/nixos/doc/manual/release-notes/rl-2305.section.md +++ b/nixos/doc/manual/release-notes/rl-2305.section.md @@ -65,6 +65,8 @@ In addition to numerous new and upgraded packages, this release has the followin - [photoprism](https://photoprism.app/), a AI-Powered Photos App for the Decentralized Web. Available as [services.photoprism](options.html#opt-services.photoprism.enable). +- [peroxide](https://github.com/ljanyst/peroxide), a fork of the official [ProtonMail bridge](https://github.com/ProtonMail/proton-bridge) that aims to be similar to [Hydroxide](https://github.com/emersion/hydroxide). Available as [services.peroxide](#opt-services.peroxide.enable). + - [autosuspend](https://github.com/languitar/autosuspend), a python daemon that suspends a system if certain conditions are met, or not met. - [sharing](https://github.com/parvardegr/sharing), a command-line tool to share directories and files from the CLI to iOS and Android devices without the need of an extra client app. Available as [programs.sharing](#opt-programs.sharing.enable). diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 314d67419b7f..43d30eb34c57 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -950,6 +950,7 @@ ./services/networking/owamp.nix ./services/networking/pdns-recursor.nix ./services/networking/pdnsd.nix + ./services/networking/peroxide.nix ./services/networking/pixiecore.nix ./services/networking/pleroma.nix ./services/networking/polipo.nix diff --git a/nixos/modules/services/networking/peroxide.nix b/nixos/modules/services/networking/peroxide.nix new file mode 100644 index 000000000000..6cac4bf2f89a --- /dev/null +++ b/nixos/modules/services/networking/peroxide.nix @@ -0,0 +1,131 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.peroxide; + settingsFormat = pkgs.formats.yaml { }; + stateDir = "peroxide"; +in +{ + options.services.peroxide = { + enable = mkEnableOption (lib.mdDoc "enable"); + + package = mkPackageOptionMD pkgs "peroxide" { + default = [ "peroxide" ]; + }; + + logLevel = mkOption { + # https://github.com/sirupsen/logrus#level-logging + type = types.enum [ "Panic" "Fatal" "Error" "Warning" "Info" "Debug" "Trace" ]; + default = "Warning"; + example = "Info"; + description = lib.mdDoc "Only log messages of this priority or higher."; + }; + + settings = mkOption { + type = types.submodule { + freeformType = settingsFormat.type; + + options = { + UserPortImap = mkOption { + type = types.port; + default = 1143; + description = lib.mdDoc "The port on which to listen for IMAP connections."; + }; + + UserPortSmtp = mkOption { + type = types.port; + default = 1025; + description = lib.mdDoc "The port on which to listen for SMTP connections."; + }; + + ServerAddress = mkOption { + type = types.str; + default = "[::0]"; + example = "localhost"; + description = lib.mdDoc "The address on which to listen for connections."; + }; + }; + }; + default = { }; + description = lib.mdDoc '' + Configuration for peroxide. See + [config.example.yaml](https://github.com/ljanyst/peroxide/blob/master/config.example.yaml) + for an example configuration. + ''; + }; + }; + + config = mkIf cfg.enable { + services.peroxide.settings = { + # peroxide deletes the cache directory on startup, which requires write + # permission on the parent directory, so we can't use + # /var/cache/peroxide + CacheDir = "/var/cache/peroxide/cache"; + X509Key = mkDefault "/var/lib/${stateDir}/key.pem"; + X509Cert = mkDefault "/var/lib/${stateDir}/cert.pem"; + CookieJar = "/var/lib/${stateDir}/cookies.json"; + CredentialsStore = "/var/lib/${stateDir}/credentials.json"; + }; + + users.users.peroxide = { + isSystemUser = true; + group = "peroxide"; + }; + users.groups.peroxide = { }; + + systemd.services.peroxide = { + description = "Peroxide ProtonMail bridge"; + requires = [ "network.target" ]; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + restartTriggers = [ config.environment.etc."peroxide.conf".source ]; + + serviceConfig = { + Type = "simple"; + User = "peroxide"; + LogsDirectory = "peroxide"; + LogsDirectoryMode = "0750"; + # Specify just "peroxide" so that the user has write permission, because + # peroxide deletes and recreates the cache directory on startup. + CacheDirectory = [ "peroxide" "peroxide/cache" ]; + CacheDirectoryMode = "0700"; + StateDirectory = stateDir; + StateDirectoryMode = "0700"; + ExecStart = "${cfg.package}/bin/peroxide -log-file=/var/log/peroxide/peroxide.log -log-level ${cfg.logLevel}"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + }; + + preStart = '' + # Create a self-signed certificate if no certificate exists. + if [[ ! -e "${cfg.settings.X509Key}" && ! -e "${cfg.settings.X509Cert}" ]]; then + ${cfg.package}/bin/peroxide-cfg -action gen-x509 \ + -x509-org 'N/A' \ + -x509-cn 'nixos' \ + -x509-cert "${cfg.settings.X509Cert}" \ + -x509-key "${cfg.settings.X509Key}" + fi + ''; + }; + + # https://github.com/ljanyst/peroxide/blob/master/peroxide.logrotate + services.logrotate.settings.peroxide = { + files = "/var/log/peroxide/peroxide.log"; + rotate = 31; + frequency = "daily"; + compress = true; + delaycompress = true; + missingok = true; + notifempty = true; + su = "peroxide peroxide"; + postrotate = "systemctl reload peroxide"; + }; + + environment.etc."peroxide.conf".source = settingsFormat.generate "peroxide.conf" cfg.settings; + environment.systemPackages = [ cfg.package ]; + }; + + meta.maintainers = with maintainers; [ aanderse aidalgol ]; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index ee1f6bb8059f..97be13f3bed0 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -528,6 +528,7 @@ in { peerflix = handleTest ./peerflix.nix {}; peering-manager = handleTest ./web-apps/peering-manager.nix {}; peertube = handleTestOn ["x86_64-linux"] ./web-apps/peertube.nix {}; + peroxide = handleTest ./peroxide.nix {}; pgadmin4 = handleTest ./pgadmin4.nix {}; pgjwt = handleTest ./pgjwt.nix {}; pgmanage = handleTest ./pgmanage.nix {}; diff --git a/nixos/tests/peroxide.nix b/nixos/tests/peroxide.nix new file mode 100644 index 000000000000..12e196484164 --- /dev/null +++ b/nixos/tests/peroxide.nix @@ -0,0 +1,16 @@ +import ./make-test-python.nix ({ pkgs, lib, ... }: { + name = "peroxide"; + meta.maintainers = with lib.maintainers; [ aidalgol ]; + + nodes.machine = + { config, pkgs, ... }: { + networking.hostName = "nixos"; + services.peroxide.enable = true; + }; + + testScript = '' + machine.wait_for_unit("peroxide.service") + machine.wait_for_open_port(1143) # IMAP + machine.wait_for_open_port(1025) # SMTP + ''; +})