1{
2 config,
3 pkgs,
4 lib,
5 ...
6}:
7let
8 cfg = config.services.schleuder;
9 settingsFormat = pkgs.formats.yaml { };
10 postfixMap =
11 entries: lib.concatStringsSep "\n" (lib.mapAttrsToList (name: value: "${name} ${value}") entries);
12 writePostfixMap = name: entries: pkgs.writeText name (postfixMap entries);
13 configScript = pkgs.writeScript "schleuder-cfg" ''
14 #!${pkgs.runtimeShell}
15 set -exuo pipefail
16 umask 0077
17 ${pkgs.yq}/bin/yq \
18 --slurpfile overrides <(${pkgs.yq}/bin/yq . <${lib.escapeShellArg cfg.extraSettingsFile}) \
19 < ${settingsFormat.generate "schleuder.yml" cfg.settings} \
20 '. * $overrides[0]' \
21 > /etc/schleuder/schleuder.yml
22 chown schleuder: /etc/schleuder/schleuder.yml
23 '';
24in
25{
26 options.services.schleuder = {
27 enable = lib.mkEnableOption "Schleuder secure remailer";
28 enablePostfix = lib.mkEnableOption "automatic postfix integration" // {
29 default = true;
30 };
31 lists = lib.mkOption {
32 description = ''
33 List of list addresses that should be handled by Schleuder.
34
35 Note that this is only handled by the postfix integration, and
36 the setup of the lists, their members and their keys has to be
37 performed separately via schleuder's API, using a tool such as
38 schleuder-cli.
39 '';
40 type = lib.types.listOf lib.types.str;
41 default = [ ];
42 example = [
43 "widget-team@example.com"
44 "security@example.com"
45 ];
46 };
47 /*
48 maybe one day....
49 domains = lib.mkOption {
50 description = "Domains for which all mail should be handled by Schleuder.";
51 type = lib.types.listOf lib.types.str;
52 default = [];
53 example = ["securelists.example.com"];
54 };
55 */
56 settings = lib.mkOption {
57 description = ''
58 Settings for schleuder.yml.
59
60 Check the [example configuration](https://0xacab.org/schleuder/schleuder/blob/master/etc/schleuder.yml) for possible values.
61 '';
62 type = lib.types.submodule {
63 freeformType = settingsFormat.type;
64 options.keyserver = lib.mkOption {
65 type = lib.types.str;
66 description = ''
67 Key server from which to fetch and update keys.
68
69 Note that NixOS uses a different default from upstream, since the upstream default sks-keyservers.net is deprecated.
70 '';
71 default = "keys.openpgp.org";
72 };
73 };
74 default = { };
75 };
76 extraSettingsFile = lib.mkOption {
77 description = "YAML file to merge into the schleuder config at runtime. This can be used for secrets such as API keys.";
78 type = lib.types.nullOr lib.types.path;
79 default = null;
80 };
81 listDefaults = lib.mkOption {
82 description = ''
83 Default settings for lists (list-defaults.yml).
84
85 Check the [example configuration](https://0xacab.org/schleuder/schleuder/-/blob/master/etc/list-defaults.yml) for possible values.
86 '';
87 type = settingsFormat.type;
88 default = { };
89 };
90 };
91 config = lib.mkIf cfg.enable {
92 assertions = [
93 {
94 assertion = !(cfg.settings.api ? valid_api_keys);
95 message = ''
96 services.schleuder.settings.api.valid_api_keys is set. Defining API keys via NixOS config results in them being copied to the world-readable Nix store. Please use the extraSettingsFile option to store API keys in a non-public location.
97 '';
98 }
99 {
100 assertion = !(lib.any (db: db ? password) (lib.attrValues cfg.settings.database or { }));
101 message = ''
102 A password is defined for at least one database in services.schleuder.settings.database. Defining passwords via NixOS config results in them being copied to the world-readable Nix store. Please use the extraSettingsFile option to store database passwords in a non-public location.
103 '';
104 }
105 ];
106 users.users.schleuder.isSystemUser = true;
107 users.users.schleuder.group = "schleuder";
108 users.groups.schleuder = { };
109 environment.systemPackages = [
110 pkgs.schleuder-cli
111 ];
112 services.postfix = lib.mkIf cfg.enablePostfix {
113 extraMasterConf = ''
114 schleuder unix - n n - - pipe
115 flags=DRhu user=schleuder argv=/${pkgs.schleuder}/bin/schleuder work ''${recipient}
116 '';
117 transport = lib.mkIf (cfg.lists != [ ]) (postfixMap (lib.genAttrs cfg.lists (_: "schleuder:")));
118 extraConfig = ''
119 schleuder_destination_recipient_limit = 1
120 '';
121 # review: does this make sense?
122 localRecipients = lib.mkIf (cfg.lists != [ ]) cfg.lists;
123 };
124 systemd.services =
125 let
126 commonServiceConfig = {
127 # We would have liked to use DynamicUser, but since the default
128 # database is SQLite and lives in StateDirectory, and that same
129 # database needs to be readable from the postfix service, this
130 # isn't trivial to do.
131 User = "schleuder";
132 StateDirectory = "schleuder";
133 StateDirectoryMode = "0700";
134 };
135 in
136 {
137 schleuder-init = {
138 serviceConfig = commonServiceConfig // {
139 ExecStartPre = lib.mkIf (cfg.extraSettingsFile != null) [
140 "+${configScript}"
141 ];
142 ExecStart = [ "${pkgs.schleuder}/bin/schleuder install" ];
143 Type = "oneshot";
144 };
145 };
146 schleuder-api-daemon = {
147 after = [
148 "local-fs.target"
149 "network.target"
150 "schleuder-init.service"
151 ];
152 wantedBy = [ "multi-user.target" ];
153 requires = [ "schleuder-init.service" ];
154 serviceConfig = commonServiceConfig // {
155 ExecStart = [ "${pkgs.schleuder}/bin/schleuder-api-daemon" ];
156 };
157 };
158 schleuder-weekly-key-maintenance = {
159 after = [
160 "local-fs.target"
161 "network.target"
162 ];
163 startAt = "weekly";
164 serviceConfig = commonServiceConfig // {
165 ExecStart = [
166 "${pkgs.schleuder}/bin/schleuder refresh_keys"
167 "${pkgs.schleuder}/bin/schleuder check_keys"
168 ];
169 };
170 };
171 };
172
173 environment.etc."schleuder/schleuder.yml" = lib.mkIf (cfg.extraSettingsFile == null) {
174 source = settingsFormat.generate "schleuder.yml" cfg.settings;
175 };
176 environment.etc."schleuder/list-defaults.yml".source =
177 settingsFormat.generate "list-defaults.yml" cfg.listDefaults;
178
179 services.schleuder = {
180 #lists_dir = "/var/lib/schleuder.lists";
181 settings.filters_dir = lib.mkDefault "/var/lib/schleuder/filters";
182 settings.keyword_handlers_dir = lib.mkDefault "/var/lib/schleuder/keyword_handlers";
183 };
184 };
185}