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