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