at 24.11-pre 4.2 kB view raw
1{ config, lib, pkgs, ... }: 2 3let 4 inherit (lib) getExe mkIf mkOption mkEnableOption optionals types; 5 6 cfg = config.services.mollysocket; 7 configuration = format.generate "mollysocket.conf" cfg.settings; 8 format = pkgs.formats.toml { }; 9 package = pkgs.writeShellScriptBin "mollysocket" '' 10 MOLLY_CONF=${configuration} exec ${getExe pkgs.mollysocket} "$@" 11 ''; 12in { 13 options.services.mollysocket = { 14 enable = mkEnableOption '' 15 [MollySocket](https://github.com/mollyim/mollysocket) for getting Signal 16 notifications via UnifiedPush 17 ''; 18 19 settings = mkOption { 20 default = { }; 21 description = '' 22 Configuration for MollySocket. Available options are listed 23 [here](https://github.com/mollyim/mollysocket#configuration). 24 ''; 25 type = types.submodule { 26 freeformType = format.type; 27 options = { 28 host = mkOption { 29 default = "127.0.0.1"; 30 description = "Listening address of the web server"; 31 type = types.str; 32 }; 33 34 port = mkOption { 35 default = 8020; 36 description = "Listening port of the web server"; 37 type = types.port; 38 }; 39 40 allowed_endpoints = mkOption { 41 default = [ "*" ]; 42 description = "List of UnifiedPush servers"; 43 example = [ "https://ntfy.sh" ]; 44 type = with types; listOf str; 45 }; 46 47 allowed_uuids = mkOption { 48 default = [ "*" ]; 49 description = "UUIDs of Signal accounts that may use this server"; 50 example = [ "abcdef-12345-tuxyz-67890" ]; 51 type = with types; listOf str; 52 }; 53 }; 54 }; 55 }; 56 57 environmentFile = mkOption { 58 default = null; 59 description = '' 60 Environment file (see {manpage}`systemd.exec(5)` "EnvironmentFile=" 61 section for the syntax) passed to the service. This option can be 62 used to safely include secrets in the configuration. 63 ''; 64 example = "/run/secrets/mollysocket"; 65 type = with types; nullOr path; 66 }; 67 68 logLevel = mkOption { 69 default = "info"; 70 description = "Set the {env}`RUST_LOG` environment variable"; 71 example = "debug"; 72 type = types.str; 73 }; 74 }; 75 76 config = mkIf cfg.enable { 77 environment.systemPackages = [ 78 package 79 ]; 80 81 # see https://github.com/mollyim/mollysocket/blob/main/mollysocket.service 82 systemd.services.mollysocket = { 83 description = "MollySocket"; 84 wantedBy = [ "multi-user.target" ]; 85 after = [ "network-online.target" ]; 86 wants = [ "network-online.target" ]; 87 environment.RUST_LOG = cfg.logLevel; 88 serviceConfig = let 89 capabilities = [ "" ] ++ optionals (cfg.settings.port < 1024) [ "CAP_NET_BIND_SERVICE" ]; 90 in { 91 EnvironmentFile = cfg.environmentFile; 92 ExecStart = "${getExe package} server"; 93 KillSignal = "SIGINT"; 94 Restart = "on-failure"; 95 StateDirectory = "mollysocket"; 96 TimeoutStopSec = 5; 97 WorkingDirectory = "/var/lib/mollysocket"; 98 99 # hardening 100 AmbientCapabilities = capabilities; 101 CapabilityBoundingSet = capabilities; 102 DevicePolicy = "closed"; 103 DynamicUser = true; 104 LockPersonality = true; 105 MemoryDenyWriteExecute = true; 106 NoNewPrivileges = true; 107 PrivateDevices = true; 108 PrivateTmp = true; 109 PrivateUsers = true; 110 ProcSubset = "pid"; 111 ProtectClock = true; 112 ProtectControlGroups = true; 113 ProtectHome = true; 114 ProtectHostname = true; 115 ProtectKernelLogs = true; 116 ProtectKernelModules = true; 117 ProtectKernelTunables = true; 118 ProtectProc = "invisible"; 119 ProtectSystem = "strict"; 120 RemoveIPC = true; 121 RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; 122 RestrictNamespaces = true; 123 RestrictRealtime = true; 124 RestrictSUIDSGID = true; 125 SystemCallArchitectures = "native"; 126 SystemCallFilter = [ "@system-service" "~@resources" "~@privileged" ]; 127 UMask = "0077"; 128 }; 129 }; 130 }; 131 132 meta.maintainers = with lib.maintainers; [ dotlambda ]; 133}