grafana-alloy: don't build the frontend twice
[NixPkgs.git] / nixos / modules / services / mail / postgrey.nix
blob7c206e3725e6b2fbf46a41fd65769e5083b1b831
1 { config, lib, pkgs, ... }:
3 with lib; let
5   cfg = config.services.postgrey;
7   natural = with types; addCheck int (x: x >= 0);
8   natural' = with types; addCheck int (x: x > 0);
10   socket = with types; addCheck (either (submodule unixSocket) (submodule inetSocket)) (x: x ? path || x ? port);
12   inetSocket = with types; {
13     options = {
14       addr = mkOption {
15         type = nullOr str;
16         default = null;
17         example = "127.0.0.1";
18         description = "The address to bind to. Localhost if null";
19       };
20       port = mkOption {
21         type = natural';
22         default = 10030;
23         description = "Tcp port to bind to";
24       };
25     };
26   };
28   unixSocket = with types; {
29     options = {
30       path = mkOption {
31         type = path;
32         default = "/run/postgrey.sock";
33         description = "Path of the unix socket";
34       };
36       mode = mkOption {
37         type = str;
38         default = "0777";
39         description = "Mode of the unix socket";
40       };
41     };
42   };
44 in {
45   imports = [
46     (mkMergedOptionModule [ [ "services" "postgrey" "inetAddr" ] [ "services" "postgrey" "inetPort" ] ] [ "services" "postgrey" "socket" ] (config: let
47         value = p: getAttrFromPath p config;
48         inetAddr = [ "services" "postgrey" "inetAddr" ];
49         inetPort = [ "services" "postgrey" "inetPort" ];
50       in
51         if value inetAddr == null
52         then { path = "/run/postgrey.sock"; }
53         else { addr = value inetAddr; port = value inetPort; }
54     ))
55   ];
57   options = {
58     services.postgrey = with types; {
59       enable = mkOption {
60         type = bool;
61         default = false;
62         description = "Whether to run the Postgrey daemon";
63       };
64       socket = mkOption {
65         type = socket;
66         default = {
67           path = "/run/postgrey.sock";
68           mode = "0777";
69         };
70         example = {
71           addr = "127.0.0.1";
72           port = 10030;
73         };
74         description = "Socket to bind to";
75       };
76       greylistText = mkOption {
77         type = str;
78         default = "Greylisted for %%s seconds";
79         description = "Response status text for greylisted messages; use %%s for seconds left until greylisting is over and %%r for mail domain of recipient";
80       };
81       greylistAction = mkOption {
82         type = str;
83         default = "DEFER_IF_PERMIT";
84         description = "Response status for greylisted messages (see access(5))";
85       };
86       greylistHeader = mkOption {
87         type = str;
88         default = "X-Greylist: delayed %%t seconds by postgrey-%%v at %%h; %%d";
89         description = "Prepend header to greylisted mails; use %%t for seconds delayed due to greylisting, %%v for the version of postgrey, %%d for the date, and %%h for the host";
90       };
91       delay = mkOption {
92         type = natural;
93         default = 300;
94         description = "Greylist for N seconds";
95       };
96       maxAge = mkOption {
97         type = natural;
98         default = 35;
99         description = "Delete entries from whitelist if they haven't been seen for N days";
100       };
101       retryWindow = mkOption {
102         type = either str natural;
103         default = 2;
104         example = "12h";
105         description = "Allow N days for the first retry. Use string with appended 'h' to specify time in hours";
106       };
107       lookupBySubnet = mkOption {
108         type = bool;
109         default = true;
110         description = "Strip the last N bits from IP addresses, determined by IPv4CIDR and IPv6CIDR";
111       };
112       IPv4CIDR = mkOption {
113         type = natural;
114         default = 24;
115         description = "Strip N bits from IPv4 addresses if lookupBySubnet is true";
116       };
117       IPv6CIDR = mkOption {
118         type = natural;
119         default = 64;
120         description = "Strip N bits from IPv6 addresses if lookupBySubnet is true";
121       };
122       privacy = mkOption {
123         type = bool;
124         default = true;
125         description = "Store data using one-way hash functions (SHA1)";
126       };
127       autoWhitelist = mkOption {
128         type = nullOr natural';
129         default = 5;
130         description = "Whitelist clients after successful delivery of N messages";
131       };
132       whitelistClients = mkOption {
133         type = listOf path;
134         default = [];
135         description = "Client address whitelist files (see postgrey(8))";
136       };
137       whitelistRecipients = mkOption {
138         type = listOf path;
139         default = [];
140         description = "Recipient address whitelist files (see postgrey(8))";
141       };
142     };
143   };
145   config = mkIf cfg.enable {
147     environment.systemPackages = [ pkgs.postgrey ];
149     users = {
150       users = {
151         postgrey = {
152           description = "Postgrey Daemon";
153           uid = config.ids.uids.postgrey;
154           group = "postgrey";
155         };
156       };
157       groups = {
158         postgrey = {
159           gid = config.ids.gids.postgrey;
160         };
161       };
162     };
164     systemd.services.postgrey = let
165       bind-flag = if cfg.socket ? path then
166         "--unix=${cfg.socket.path} --socketmode=${cfg.socket.mode}"
167       else
168         ''--inet=${optionalString (cfg.socket.addr != null) (cfg.socket.addr + ":")}${toString cfg.socket.port}'';
169     in {
170       description = "Postfix Greylisting Service";
171       wantedBy = [ "multi-user.target" ];
172       before = [ "postfix.service" ];
173       preStart = ''
174         mkdir -p /var/postgrey
175         chown postgrey:postgrey /var/postgrey
176         chmod 0770 /var/postgrey
177       '';
178       serviceConfig = {
179         Type = "simple";
180         ExecStart = ''${pkgs.postgrey}/bin/postgrey \
181           ${bind-flag} \
182           --group=postgrey --user=postgrey \
183           --dbdir=/var/postgrey \
184           --delay=${toString cfg.delay} \
185           --max-age=${toString cfg.maxAge} \
186           --retry-window=${toString cfg.retryWindow} \
187           ${if cfg.lookupBySubnet then "--lookup-by-subnet" else "--lookup-by-host"} \
188           --ipv4cidr=${toString cfg.IPv4CIDR} --ipv6cidr=${toString cfg.IPv6CIDR} \
189           ${optionalString cfg.privacy "--privacy"} \
190           --auto-whitelist-clients=${toString (if cfg.autoWhitelist == null then 0 else cfg.autoWhitelist)} \
191           --greylist-action=${cfg.greylistAction} \
192           --greylist-text="${cfg.greylistText}" \
193           --x-greylist-header="${cfg.greylistHeader}" \
194           ${concatMapStringsSep " " (x: "--whitelist-clients=" + x) cfg.whitelistClients} \
195           ${concatMapStringsSep " " (x: "--whitelist-recipients=" + x) cfg.whitelistRecipients}
196         '';
197         Restart = "always";
198         RestartSec = 5;
199         TimeoutSec = 10;
200       };
201     };
203   };