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 settingsFileUnsubstituted = settingsFormat.generate "mautrix-telegram-config-unsubstituted.json" cfg.settings;
11 settingsFile = "${dataDir}/config.json";
12
13in {
14 options = {
15 services.mautrix-telegram = {
16 enable = mkEnableOption "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 appservice = rec {
23 database = "sqlite:///${dataDir}/mautrix-telegram.db";
24 database_opts = {};
25 hostname = "0.0.0.0";
26 port = 8080;
27 address = "http://localhost:${toString port}";
28 };
29
30 bridge = {
31 permissions."*" = "relaybot";
32 relaybot.whitelist = [ ];
33 double_puppet_server_map = {};
34 login_shared_secret_map = {};
35 };
36
37 logging = {
38 version = 1;
39
40 formatters.precise.format = "[%(levelname)s@%(name)s] %(message)s";
41
42 handlers.console = {
43 class = "logging.StreamHandler";
44 formatter = "precise";
45 };
46
47 loggers = {
48 mau.level = "INFO";
49 telethon.level = "INFO";
50
51 # prevent tokens from leaking in the logs:
52 # https://github.com/tulir/mautrix-telegram/issues/351
53 aiohttp.level = "WARNING";
54 };
55
56 # log to console/systemd instead of file
57 root = {
58 level = "INFO";
59 handlers = [ "console" ];
60 };
61 };
62 };
63 example = literalExpression ''
64 {
65 homeserver = {
66 address = "http://localhost:8008";
67 domain = "public-domain.tld";
68 };
69
70 appservice.public = {
71 prefix = "/public";
72 external = "https://public-appservice-address/public";
73 };
74
75 bridge.permissions = {
76 "example.com" = "full";
77 "@admin:example.com" = "admin";
78 };
79 }
80 '';
81 description = ''
82 <filename>config.yaml</filename> configuration as a Nix attribute set.
83 Configuration options should match those described in
84 <link xlink:href="https://github.com/tulir/mautrix-telegram/blob/master/example-config.yaml">
85 example-config.yaml</link>.
86 </para>
87
88 <para>
89 Secret tokens should be specified using <option>environmentFile</option>
90 instead of this world-readable attribute set.
91 '';
92 };
93
94 environmentFile = mkOption {
95 type = types.nullOr types.path;
96 default = null;
97 description = ''
98 File containing environment variables to be passed to the mautrix-telegram service,
99 in which secret tokens can be specified securely by defining values for
100 <literal>MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN</literal>,
101 <literal>MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN</literal>,
102 <literal>MAUTRIX_TELEGRAM_TELEGRAM_API_ID</literal>,
103 <literal>MAUTRIX_TELEGRAM_TELEGRAM_API_HASH</literal> and optionally
104 <literal>MAUTRIX_TELEGRAM_TELEGRAM_BOT_TOKEN</literal>.
105 '';
106 };
107
108 serviceDependencies = mkOption {
109 type = with types; listOf str;
110 default = optional config.services.matrix-synapse.enable "matrix-synapse.service";
111 description = ''
112 List of Systemd services to require and wait for when starting the application service.
113 '';
114 };
115 };
116 };
117
118 config = mkIf cfg.enable {
119 systemd.services.mautrix-telegram = {
120 description = "Mautrix-Telegram, a Matrix-Telegram hybrid puppeting/relaybot bridge.";
121
122 wantedBy = [ "multi-user.target" ];
123 wants = [ "network-online.target" ] ++ cfg.serviceDependencies;
124 after = [ "network-online.target" ] ++ cfg.serviceDependencies;
125
126 preStart = ''
127 # Not all secrets can be passed as environment variable (yet)
128 # https://github.com/tulir/mautrix-telegram/issues/584
129 [ -f ${settingsFile} ] && rm -f ${settingsFile}
130 old_umask=$(umask)
131 umask 0177
132 ${pkgs.envsubst}/bin/envsubst \
133 -o ${settingsFile} \
134 -i ${settingsFileUnsubstituted}
135 umask $old_umask
136
137 # generate the appservice's registration file if absent
138 if [ ! -f '${registrationFile}' ]; then
139 ${pkgs.mautrix-telegram}/bin/mautrix-telegram \
140 --generate-registration \
141 --base-config='${pkgs.mautrix-telegram}/${pkgs.mautrix-telegram.pythonModule.sitePackages}/mautrix_telegram/example-config.yaml' \
142 --config='${settingsFile}' \
143 --registration='${registrationFile}'
144 fi
145
146 # run automatic database init and migration scripts
147 ${pkgs.mautrix-telegram.alembic}/bin/alembic -x config='${settingsFile}' upgrade head
148 '';
149
150 serviceConfig = {
151 Type = "simple";
152 Restart = "always";
153
154 ProtectSystem = "strict";
155 ProtectHome = true;
156 ProtectKernelTunables = true;
157 ProtectKernelModules = true;
158 ProtectControlGroups = true;
159
160 DynamicUser = true;
161 PrivateTmp = true;
162 WorkingDirectory = pkgs.mautrix-telegram; # necessary for the database migration scripts to be found
163 StateDirectory = baseNameOf dataDir;
164 UMask = 0027;
165 EnvironmentFile = cfg.environmentFile;
166
167 ExecStart = ''
168 ${pkgs.mautrix-telegram}/bin/mautrix-telegram \
169 --config='${settingsFile}'
170 '';
171 };
172
173 restartTriggers = [ settingsFileUnsubstituted ];
174 };
175 };
176
177 meta.maintainers = with maintainers; [ pacien vskilet ];
178}