1{ config, pkgs, lib, ... }:
2
3with lib;
4
5let
6 dataDir = "/var/lib/matrix-appservice-discord";
7 registrationFile = "${dataDir}/discord-registration.yaml";
8 appDir = "${pkgs.matrix-appservice-discord}/${pkgs.matrix-appservice-discord.passthru.nodeAppDir}";
9 cfg = config.services.matrix-appservice-discord;
10 # TODO: switch to configGen.json once RFC42 is implemented
11 settingsFile = pkgs.writeText "matrix-appservice-discord-settings.json" (builtins.toJSON cfg.settings);
12
13in {
14 options = {
15 services.matrix-appservice-discord = {
16 enable = mkEnableOption "a bridge between Matrix and Discord";
17
18 settings = mkOption rec {
19 # TODO: switch to types.config.json as prescribed by RFC42 once it's implemented
20 type = types.attrs;
21 apply = recursiveUpdate default;
22 default = {
23 database = {
24 filename = "${dataDir}/discord.db";
25 };
26
27 # empty values necessary for registration file generation
28 # actual values defined in environmentFile
29 auth = {
30 clientID = "";
31 botToken = "";
32 };
33 };
34 example = literalExpression ''
35 {
36 bridge = {
37 domain = "public-domain.tld";
38 homeserverUrl = "http://public-domain.tld:8008";
39 };
40 }
41 '';
42 description = ''
43 <filename>config.yaml</filename> configuration as a Nix attribute set.
44 </para>
45
46 <para>
47 Configuration options should match those described in
48 <link xlink:href="https://github.com/Half-Shot/matrix-appservice-discord/blob/master/config/config.sample.yaml">
49 config.sample.yaml</link>.
50 </para>
51
52 <para>
53 <option>config.bridge.domain</option> and <option>config.bridge.homeserverUrl</option>
54 should be set to match the public host name of the Matrix homeserver for webhooks and avatars to work.
55 </para>
56
57 <para>
58 Secret tokens should be specified using <option>environmentFile</option>
59 instead of this world-readable attribute set.
60 '';
61 };
62
63 environmentFile = mkOption {
64 type = types.nullOr types.path;
65 default = null;
66 description = ''
67 File containing environment variables to be passed to the matrix-appservice-discord service,
68 in which secret tokens can be specified securely by defining values for
69 <literal>APPSERVICE_DISCORD_AUTH_CLIENT_I_D</literal> and
70 <literal>APPSERVICE_DISCORD_AUTH_BOT_TOKEN</literal>.
71 '';
72 };
73
74 url = mkOption {
75 type = types.str;
76 default = "http://localhost:${toString cfg.port}";
77 description = ''
78 The URL where the application service is listening for HS requests.
79 '';
80 };
81
82 port = mkOption {
83 type = types.port;
84 default = 9005; # from https://github.com/Half-Shot/matrix-appservice-discord/blob/master/package.json#L11
85 description = ''
86 Port number on which the bridge should listen for internal communication with the Matrix homeserver.
87 '';
88 };
89
90 localpart = mkOption {
91 type = with types; nullOr str;
92 default = null;
93 description = ''
94 The user_id localpart to assign to the AS.
95 '';
96 };
97
98 serviceDependencies = mkOption {
99 type = with types; listOf str;
100 default = optional config.services.matrix-synapse.enable "matrix-synapse.service";
101 description = ''
102 List of Systemd services to require and wait for when starting the application service,
103 such as the Matrix homeserver if it's running on the same host.
104 '';
105 };
106 };
107 };
108
109 config = mkIf cfg.enable {
110 systemd.services.matrix-appservice-discord = {
111 description = "A bridge between Matrix and Discord.";
112
113 wantedBy = [ "multi-user.target" ];
114 wants = [ "network-online.target" ] ++ cfg.serviceDependencies;
115 after = [ "network-online.target" ] ++ cfg.serviceDependencies;
116
117 preStart = ''
118 if [ ! -f '${registrationFile}' ]; then
119 ${pkgs.matrix-appservice-discord}/bin/matrix-appservice-discord \
120 --generate-registration \
121 --url=${escapeShellArg cfg.url} \
122 ${optionalString (cfg.localpart != null) "--localpart=${escapeShellArg cfg.localpart}"} \
123 --config='${settingsFile}' \
124 --file='${registrationFile}'
125 fi
126 '';
127
128 serviceConfig = {
129 Type = "simple";
130 Restart = "always";
131
132 ProtectSystem = "strict";
133 ProtectHome = true;
134 ProtectKernelTunables = true;
135 ProtectKernelModules = true;
136 ProtectControlGroups = true;
137
138 DynamicUser = true;
139 PrivateTmp = true;
140 WorkingDirectory = appDir;
141 StateDirectory = baseNameOf dataDir;
142 UMask = 0027;
143 EnvironmentFile = cfg.environmentFile;
144
145 ExecStart = ''
146 ${pkgs.matrix-appservice-discord}/bin/matrix-appservice-discord \
147 --file='${registrationFile}' \
148 --config='${settingsFile}' \
149 --port='${toString cfg.port}'
150 '';
151 };
152 };
153 };
154
155 meta.maintainers = with maintainers; [ pacien ];
156}