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