at 25.11-pre 9.0 kB view raw
1{ 2 config, 3 pkgs, 4 lib, 5 ... 6}: 7let 8 dataDir = "/var/lib/mautrix-telegram"; 9 registrationFile = "${dataDir}/telegram-registration.yaml"; 10 cfg = config.services.mautrix-telegram; 11 settingsFormat = pkgs.formats.json { }; 12 settingsFileUnsubstituted = settingsFormat.generate "mautrix-telegram-config.json" cfg.settings; 13 settingsFile = "${dataDir}/config.json"; 14 15in 16{ 17 options = { 18 services.mautrix-telegram = { 19 enable = lib.mkEnableOption "Mautrix-Telegram, a Matrix-Telegram hybrid puppeting/relaybot bridge"; 20 21 package = lib.mkPackageOption pkgs "mautrix-telegram" { }; 22 23 settings = lib.mkOption rec { 24 apply = lib.recursiveUpdate default; 25 inherit (settingsFormat) type; 26 default = { 27 homeserver = { 28 software = "standard"; 29 }; 30 31 appservice = rec { 32 database = "sqlite:///${dataDir}/mautrix-telegram.db"; 33 database_opts = { }; 34 hostname = "0.0.0.0"; 35 port = 8080; 36 address = "http://localhost:${toString port}"; 37 }; 38 39 bridge = { 40 permissions."*" = "relaybot"; 41 relaybot.whitelist = [ ]; 42 double_puppet_server_map = { }; 43 login_shared_secret_map = { }; 44 }; 45 46 logging = { 47 version = 1; 48 49 formatters.precise.format = "[%(levelname)s@%(name)s] %(message)s"; 50 51 handlers.console = { 52 class = "logging.StreamHandler"; 53 formatter = "precise"; 54 }; 55 56 loggers = { 57 mau.level = "INFO"; 58 telethon.level = "INFO"; 59 60 # prevent tokens from leaking in the logs: 61 # https://github.com/tulir/mautrix-telegram/issues/351 62 aiohttp.level = "WARNING"; 63 }; 64 65 # log to console/systemd instead of file 66 root = { 67 level = "INFO"; 68 handlers = [ "console" ]; 69 }; 70 }; 71 }; 72 example = lib.literalExpression '' 73 { 74 homeserver = { 75 address = "http://localhost:8008"; 76 domain = "public-domain.tld"; 77 }; 78 79 appservice.public = { 80 prefix = "/public"; 81 external = "https://public-appservice-address/public"; 82 }; 83 84 bridge.permissions = { 85 "example.com" = "full"; 86 "@admin:example.com" = "admin"; 87 }; 88 telegram = { 89 connection.use_ipv6 = true; 90 }; 91 } 92 ''; 93 description = '' 94 {file}`config.yaml` configuration as a Nix attribute set. 95 Configuration options should match those described in 96 [example-config.yaml](https://github.com/mautrix/telegram/blob/master/mautrix_telegram/example-config.yaml). 97 98 Secret tokens should be specified using {option}`environmentFile` 99 instead of this world-readable attribute set. 100 ''; 101 }; 102 103 environmentFile = lib.mkOption { 104 type = lib.types.nullOr lib.types.path; 105 default = null; 106 description = '' 107 File containing environment variables to be passed to the mautrix-telegram service, 108 in which secret tokens can be specified securely by defining values for e.g. 109 `MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN`, 110 `MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN`, 111 `MAUTRIX_TELEGRAM_TELEGRAM_API_ID`, 112 `MAUTRIX_TELEGRAM_TELEGRAM_API_HASH` and optionally 113 `MAUTRIX_TELEGRAM_TELEGRAM_BOT_TOKEN`. 114 115 These environment variables can also be used to set other options by 116 replacing hierarchy levels by `.`, converting the name to uppercase 117 and prepending `MAUTRIX_TELEGRAM_`. 118 For example, the first value above maps to 119 {option}`settings.appservice.as_token`. 120 121 The environment variable values can be prefixed with `json::` to have 122 them be parsed as JSON. For example, `login_shared_secret_map` can be 123 set as follows: 124 `MAUTRIX_TELEGRAM_BRIDGE_LOGIN_SHARED_SECRET_MAP=json::{"example.com":"secret"}`. 125 ''; 126 }; 127 128 serviceDependencies = lib.mkOption { 129 type = with lib.types; listOf str; 130 default = lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit; 131 defaultText = lib.literalExpression '' 132 lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit 133 ''; 134 description = '' 135 List of Systemd services to require and wait for when starting the application service. 136 ''; 137 }; 138 139 registerToSynapse = lib.mkOption { 140 type = lib.types.bool; 141 default = config.services.matrix-synapse.enable; 142 defaultText = lib.literalExpression "config.services.matrix-synapse.enable"; 143 description = '' 144 Whether to add the bridge's app service registration file to 145 `services.matrix-synapse.settings.app_service_config_files`. 146 ''; 147 }; 148 }; 149 }; 150 151 config = lib.mkIf cfg.enable { 152 153 users.users.mautrix-telegram = { 154 isSystemUser = true; 155 group = "mautrix-telegram"; 156 home = dataDir; 157 description = "Mautrix-Telegram bridge user"; 158 }; 159 160 users.groups.mautrix-telegram = { }; 161 162 services.matrix-synapse = lib.mkIf cfg.registerToSynapse { 163 settings.app_service_config_files = [ registrationFile ]; 164 }; 165 systemd.services.matrix-synapse = lib.mkIf cfg.registerToSynapse { 166 serviceConfig.SupplementaryGroups = [ "mautrix-telegram" ]; 167 }; 168 169 systemd.services.mautrix-telegram = { 170 description = "Mautrix-Telegram, a Matrix-Telegram hybrid puppeting/relaybot bridge."; 171 172 wantedBy = [ "multi-user.target" ]; 173 wants = [ "network-online.target" ] ++ cfg.serviceDependencies; 174 after = [ "network-online.target" ] ++ cfg.serviceDependencies; 175 path = [ 176 pkgs.lottieconverter 177 pkgs.ffmpeg-headless 178 ]; 179 180 # mautrix-telegram tries to generate a dotfile in the home directory of 181 # the running user if using a postgresql database: 182 # 183 # File "python3.10/site-packages/asyncpg/connect_utils.py", line 257, in _dot_postgre> 184 # return (pathlib.Path.home() / '.postgresql' / filename).resolve() 185 # File "python3.10/pathlib.py", line 1000, in home 186 # return cls("~").expanduser() 187 # File "python3.10/pathlib.py", line 1440, in expanduser 188 # raise RuntimeError("Could not determine home directory.") 189 # RuntimeError: Could not determine home directory. 190 environment.HOME = dataDir; 191 192 preStart = 193 '' 194 # substitute the settings file by environment variables 195 # in this case read from EnvironmentFile 196 test -f '${settingsFile}' && rm -f '${settingsFile}' 197 old_umask=$(umask) 198 umask 0177 199 ${pkgs.envsubst}/bin/envsubst \ 200 -o '${settingsFile}' \ 201 -i '${settingsFileUnsubstituted}' 202 umask $old_umask 203 204 # generate the appservice's registration file if absent 205 if [ ! -f '${registrationFile}' ]; then 206 ${cfg.package}/bin/mautrix-telegram \ 207 --generate-registration \ 208 --config='${settingsFile}' \ 209 --registration='${registrationFile}' 210 fi 211 212 old_umask=$(umask) 213 umask 0177 214 # 1. Overwrite registration tokens in config 215 # is set, set it as the login shared secret value for the configured 216 # homeserver domain. 217 ${pkgs.yq}/bin/yq -s '.[0].appservice.as_token = .[1].as_token 218 | .[0].appservice.hs_token = .[1].hs_token 219 | .[0]' \ 220 '${settingsFile}' '${registrationFile}' > '${settingsFile}.tmp' 221 mv '${settingsFile}.tmp' '${settingsFile}' 222 223 umask $old_umask 224 '' 225 + lib.optionalString (cfg.package ? alembic) '' 226 # run automatic database init and migration scripts 227 ${cfg.package.alembic}/bin/alembic -x config='${settingsFile}' upgrade head 228 ''; 229 230 serviceConfig = { 231 User = "mautrix-telegram"; 232 Group = "mautrix-telegram"; 233 Type = "simple"; 234 Restart = "always"; 235 236 ProtectSystem = "strict"; 237 ProtectHome = true; 238 ProtectKernelTunables = true; 239 ProtectKernelModules = true; 240 ProtectControlGroups = true; 241 242 PrivateTmp = true; 243 WorkingDirectory = cfg.package; # necessary for the database migration scripts to be found 244 StateDirectory = baseNameOf dataDir; 245 UMask = "0027"; 246 EnvironmentFile = cfg.environmentFile; 247 248 ExecStart = '' 249 ${cfg.package}/bin/mautrix-telegram \ 250 --config='${settingsFile}' 251 ''; 252 }; 253 }; 254 }; 255 256 meta.maintainers = with lib.maintainers; [ 257 euxane 258 vskilet 259 ]; 260}