at 25.11-pre 7.4 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8let 9 cfg = config.services.umurmur; 10 dumpAttrset = 11 x: top_level: 12 (lib.optionalString (!top_level) "{") 13 + (lib.concatLines (lib.mapAttrsToList (name: value: "${name} = ${toConfigValue value false};") x)) 14 + (lib.optionalString (!top_level) "}"); 15 dumpList = x: top_level: "(${lib.concatStringsSep ",\n" (map (y: "${toConfigValue y false}") x)})"; 16 17 toConfigValue = 18 x: top_level: 19 if builtins.isList x then 20 dumpList x top_level 21 else if builtins.isAttrs x then 22 dumpAttrset x top_level 23 else 24 builtins.toJSON x; 25 dumpCfg = x: toConfigValue x true; 26 configAttrs = lib.filterAttrsRecursive (name: value: value != null) cfg.settings; 27 configFile = pkgs.writeTextFile { 28 name = "umurmur.conf"; 29 checkPhase = '' 30 ${lib.getExe cfg.package} -t -c "$target" 31 ''; 32 text = "\n" + (dumpCfg configAttrs) + "\n"; 33 }; 34in 35{ 36 options = { 37 services.umurmur = { 38 enable = lib.mkEnableOption "uMurmur Mumble server"; 39 40 package = lib.mkPackageOption pkgs "umurmur" { }; 41 42 openFirewall = lib.mkOption { 43 type = lib.types.bool; 44 default = false; 45 description = '' 46 Open ports in the firewall for the uMurmur Mumble server. 47 ''; 48 }; 49 50 settings = lib.mkOption { 51 type = lib.types.submodule { 52 freeformType = 53 let 54 valueType = 55 with lib.types; 56 oneOf [ 57 bool 58 int 59 float 60 str 61 path 62 (listOf (attrsOf valueType)) 63 ] 64 // { 65 description = "uMurmur config value"; 66 }; 67 in 68 valueType; 69 options = { 70 welcometext = lib.mkOption { 71 type = lib.types.nullOr lib.types.str; 72 default = "Welcome to uMurmur!"; 73 description = "Welcome message for connected clients."; 74 }; 75 76 bindaddr = lib.mkOption { 77 type = lib.types.str; 78 default = "0.0.0.0"; 79 description = "IPv4 address to bind to. Defaults binding on all addresses."; 80 }; 81 82 bindaddr6 = lib.mkOption { 83 type = lib.types.str; 84 default = "::"; 85 description = "IPv6 address to bind to. Defaults binding on all addresses."; 86 }; 87 88 bindport = lib.mkOption { 89 type = lib.types.port; 90 default = 64739; 91 description = "Port to bind to (UDP and TCP)."; 92 }; 93 94 password = lib.mkOption { 95 type = lib.types.nullOr lib.types.str; 96 default = null; 97 description = "Required password to join server, if specified."; 98 }; 99 100 max_bandwidth = lib.mkOption { 101 type = lib.types.int; 102 default = 48000; 103 description = '' 104 Maximum bandwidth (in bits per second) that clients may send 105 speech at. 106 ''; 107 }; 108 109 max_users = lib.mkOption { 110 type = lib.types.int; 111 default = 10; 112 description = "Maximum number of concurrent clients allowed."; 113 }; 114 115 certificate = lib.mkOption { 116 type = lib.types.str; 117 default = "/var/lib/private/umurmur/cert.crt"; 118 description = "Path to your SSL certificate. Generates self-signed automatically if not exists."; 119 }; 120 121 private_key = lib.mkOption { 122 type = lib.types.str; 123 default = "/var/lib/private/umurmur/key.key"; 124 description = "Path to your SSL key. Generates self-signed automatically if not exists."; 125 }; 126 127 ca_path = lib.mkOption { 128 type = lib.types.nullOr lib.types.str; 129 default = null; 130 description = "Path to your SSL CA certificate."; 131 }; 132 133 channels = lib.mkOption { 134 type = lib.types.listOf lib.types.attrs; 135 default = [ 136 { 137 name = "root"; 138 parent = ""; 139 description = "Root channel."; 140 noenter = false; 141 } 142 ]; 143 description = "Channel tree definitions."; 144 }; 145 146 channel_links = lib.mkOption { 147 type = lib.types.listOf lib.types.attrs; 148 default = [ ]; 149 example = [ 150 { 151 source = "Lobby"; 152 destination = "Red team"; 153 } 154 ]; 155 description = "Channel tree definitions."; 156 }; 157 158 default_channel = lib.mkOption { 159 type = lib.types.str; 160 default = "root"; 161 description = "The channel in which users will appear in when connecting."; 162 }; 163 164 }; 165 }; 166 default = { }; 167 description = "Settings of uMurmur. For reference see https://github.com/umurmur/umurmur/blob/master/umurmur.conf.example"; 168 }; 169 170 configFile = lib.mkOption rec { 171 type = lib.types.path; 172 default = configFile; 173 description = "Configuration file, default is generated from config.service.umurmur.settings"; 174 defaultText = description; 175 }; 176 }; 177 }; 178 179 config = lib.mkIf cfg.enable { 180 networking.firewall = lib.mkIf cfg.openFirewall { 181 allowedTCPPorts = [ cfg.settings.bindport ]; 182 allowedUDPPorts = [ cfg.settings.bindport ]; 183 }; 184 185 systemd.services.umurmur = { 186 description = "uMurmur Mumble Server"; 187 wants = [ "network.target" ]; 188 after = [ "network.target" ]; 189 wantedBy = [ "multi-user.target" ]; 190 serviceConfig = { 191 Type = "exec"; 192 ExecStart = "${lib.getExe cfg.package} -d -c ${cfg.configFile}"; 193 Restart = "on-failure"; 194 DynamicUser = true; 195 StateDirectory = "umurmur"; 196 ReadWritePaths = "/dev/shm"; 197 198 # hardening 199 UMask = 27; 200 MemoryDenyWriteExecute = true; 201 AmbientCapabilities = [ "" ]; 202 CapabilityBoundingSet = [ "" ]; 203 DevicePolicy = "closed"; 204 LockPersonality = true; 205 NoNewPrivileges = true; 206 PrivateDevices = true; 207 PrivateTmp = true; 208 PrivateUsers = true; 209 ProtectSystem = "full"; 210 ProtectClock = true; 211 ProtectControlGroups = true; 212 ProtectHome = true; 213 ProtectHostname = true; 214 ProtectKernelLogs = true; 215 ProtectKernelModules = true; 216 ProtectKernelTunables = true; 217 ProcSubset = "pid"; 218 ProtectProc = "invisible"; 219 RemoveIPC = true; 220 RestrictAddressFamilies = [ 221 "AF_UNIX" 222 "AF_INET" 223 "AF_INET6" 224 ]; 225 RestrictNamespaces = true; 226 RestrictRealtime = true; 227 RestrictSUIDSGID = true; 228 SystemCallArchitectures = "native"; 229 SystemCallFilter = [ 230 "@system-service" 231 "~@cpu-emulation" 232 "~@debug" 233 "~@mount" 234 "~@obsolete" 235 "~@privileged" 236 "~@resources" 237 ]; 238 }; 239 }; 240 }; 241 242 meta.maintainers = with lib.maintainers; [ _3JlOy-PYCCKUi ]; 243 meta.doc = ./umurmur.md; 244}