at 23.11-beta 6.9 kB view raw
1{ 2 lib, 3 config, 4 pkgs, 5 ... 6}: let 7 cfg = config.services.mautrix-whatsapp; 8 dataDir = "/var/lib/mautrix-whatsapp"; 9 registrationFile = "${dataDir}/whatsapp-registration.yaml"; 10 settingsFile = "${dataDir}/config.json"; 11 settingsFileUnsubstituted = settingsFormat.generate "mautrix-whatsapp-config-unsubstituted.json" cfg.settings; 12 settingsFormat = pkgs.formats.json {}; 13 appservicePort = 29318; 14 15 mkDefaults = lib.mapAttrsRecursive (n: v: lib.mkDefault v); 16 defaultConfig = { 17 homeserver.address = "http://localhost:8448"; 18 appservice = { 19 hostname = "[::]"; 20 port = appservicePort; 21 database.type = "sqlite3"; 22 database.uri = "${dataDir}/mautrix-whatsapp.db"; 23 id = "whatsapp"; 24 bot.username = "whatsappbot"; 25 bot.displayname = "WhatsApp Bridge Bot"; 26 as_token = ""; 27 hs_token = ""; 28 }; 29 bridge = { 30 username_template = "whatsapp_{{.}}"; 31 displayname_template = "{{if .BusinessName}}{{.BusinessName}}{{else if .PushName}}{{.PushName}}{{else}}{{.JID}}{{end}} (WA)"; 32 double_puppet_server_map = {}; 33 login_shared_secret_map = {}; 34 command_prefix = "!wa"; 35 permissions."*" = "relay"; 36 relay.enabled = true; 37 }; 38 logging = { 39 min_level = "info"; 40 writers = lib.singleton { 41 type = "stdout"; 42 format = "pretty-colored"; 43 time_format = " "; 44 }; 45 }; 46 }; 47 48in { 49 options.services.mautrix-whatsapp = { 50 enable = lib.mkEnableOption (lib.mdDoc "mautrix-whatsapp, a puppeting/relaybot bridge between Matrix and WhatsApp."); 51 52 settings = lib.mkOption { 53 type = settingsFormat.type; 54 default = defaultConfig; 55 description = lib.mdDoc '' 56 {file}`config.yaml` configuration as a Nix attribute set. 57 Configuration options should match those described in 58 [example-config.yaml](https://github.com/mautrix/whatsapp/blob/master/example-config.yaml). 59 Secret tokens should be specified using {option}`environmentFile` 60 instead of this world-readable attribute set. 61 ''; 62 example = { 63 appservice = { 64 database = { 65 type = "postgres"; 66 uri = "postgresql:///mautrix_whatsapp?host=/run/postgresql"; 67 }; 68 id = "whatsapp"; 69 ephemeral_events = false; 70 }; 71 bridge = { 72 history_sync = { 73 request_full_sync = true; 74 }; 75 private_chat_portal_meta = true; 76 mute_bridging = true; 77 encryption = { 78 allow = true; 79 default = true; 80 require = true; 81 }; 82 provisioning = { 83 shared_secret = "disable"; 84 }; 85 permissions = { 86 "example.com" = "user"; 87 }; 88 }; 89 }; 90 }; 91 environmentFile = lib.mkOption { 92 type = lib.types.nullOr lib.types.path; 93 default = null; 94 description = lib.mdDoc '' 95 File containing environment variables to be passed to the mautrix-whatsapp service, 96 in which secret tokens can be specified securely by optionally defining a value for 97 `MAUTRIX_WHATSAPP_BRIDGE_LOGIN_SHARED_SECRET`. 98 ''; 99 }; 100 101 serviceDependencies = lib.mkOption { 102 type = with lib.types; listOf str; 103 default = lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit; 104 defaultText = lib.literalExpression '' 105 optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnits 106 ''; 107 description = lib.mdDoc '' 108 List of Systemd services to require and wait for when starting the application service. 109 ''; 110 }; 111 }; 112 113 config = lib.mkIf cfg.enable { 114 115 users.users.mautrix-whatsapp = { 116 isSystemUser = true; 117 group = "mautrix-whatsapp"; 118 home = dataDir; 119 description = "Mautrix-WhatsApp bridge user"; 120 }; 121 122 users.groups.mautrix-whatsapp = {}; 123 124 services.mautrix-whatsapp.settings = lib.mkMerge (map mkDefaults [ 125 defaultConfig 126 # Note: this is defined here to avoid the docs depending on `config` 127 { homeserver.domain = config.services.matrix-synapse.settings.server_name; } 128 ]); 129 130 systemd.services.mautrix-whatsapp = { 131 description = "Mautrix-WhatsApp Service - A WhatsApp bridge for Matrix"; 132 133 wantedBy = ["multi-user.target"]; 134 wants = ["network-online.target"] ++ cfg.serviceDependencies; 135 after = ["network-online.target"] ++ cfg.serviceDependencies; 136 137 preStart = '' 138 # substitute the settings file by environment variables 139 # in this case read from EnvironmentFile 140 test -f '${settingsFile}' && rm -f '${settingsFile}' 141 old_umask=$(umask) 142 umask 0177 143 ${pkgs.envsubst}/bin/envsubst \ 144 -o '${settingsFile}' \ 145 -i '${settingsFileUnsubstituted}' 146 umask $old_umask 147 148 # generate the appservice's registration file if absent 149 if [ ! -f '${registrationFile}' ]; then 150 ${pkgs.mautrix-whatsapp}/bin/mautrix-whatsapp \ 151 --generate-registration \ 152 --config='${settingsFile}' \ 153 --registration='${registrationFile}' 154 fi 155 chmod 640 ${registrationFile} 156 157 umask 0177 158 ${pkgs.yq}/bin/yq -s '.[0].appservice.as_token = .[1].as_token 159 | .[0].appservice.hs_token = .[1].hs_token 160 | .[0]' '${settingsFile}' '${registrationFile}' \ 161 > '${settingsFile}.tmp' 162 mv '${settingsFile}.tmp' '${settingsFile}' 163 umask $old_umask 164 ''; 165 166 serviceConfig = { 167 User = "mautrix-whatsapp"; 168 Group = "mautrix-whatsapp"; 169 EnvironmentFile = cfg.environmentFile; 170 StateDirectory = baseNameOf dataDir; 171 WorkingDirectory = dataDir; 172 ExecStart = '' 173 ${pkgs.mautrix-whatsapp}/bin/mautrix-whatsapp \ 174 --config='${settingsFile}' \ 175 --registration='${registrationFile}' 176 ''; 177 LockPersonality = true; 178 MemoryDenyWriteExecute = true; 179 NoNewPrivileges = true; 180 PrivateDevices = true; 181 PrivateTmp = true; 182 PrivateUsers = true; 183 ProtectClock = true; 184 ProtectControlGroups = true; 185 ProtectHome = true; 186 ProtectHostname = true; 187 ProtectKernelLogs = true; 188 ProtectKernelModules = true; 189 ProtectKernelTunables = true; 190 ProtectSystem = "strict"; 191 Restart = "on-failure"; 192 RestartSec = "30s"; 193 RestrictRealtime = true; 194 RestrictSUIDSGID = true; 195 SystemCallArchitectures = "native"; 196 SystemCallErrorNumber = "EPERM"; 197 SystemCallFilter = ["@system-service"]; 198 Type = "simple"; 199 UMask = 0027; 200 }; 201 restartTriggers = [settingsFileUnsubstituted]; 202 }; 203 }; 204 meta.maintainers = with lib.maintainers; [frederictobiasc]; 205}