1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 inherit (pkgs) nntp-proxy;
8
9 proxyUser = "nntp-proxy";
10
11 cfg = config.services.nntp-proxy;
12
13 configBool = b: if b then "TRUE" else "FALSE";
14
15 confFile = pkgs.writeText "nntp-proxy.conf" ''
16 nntp_server:
17 {
18 # NNTP Server host and port address
19 server = "${cfg.upstreamServer}";
20 port = ${toString cfg.upstreamPort};
21 # NNTP username
22 username = "${cfg.upstreamUser}";
23 # NNTP password in clear text
24 password = "${cfg.upstreamPassword}";
25 # Maximum number of connections allowed by the NNTP
26 max_connections = ${toString cfg.upstreamMaxConnections};
27 };
28
29 proxy:
30 {
31 # Local address and port to bind to
32 bind_ip = "${cfg.listenAddress}";
33 bind_port = ${toString cfg.port};
34
35 # SSL key and cert file
36 ssl_key = "${cfg.sslKey}";
37 ssl_cert = "${cfg.sslCert}";
38
39 # prohibit users from posting
40 prohibit_posting = ${configBool cfg.prohibitPosting};
41 # Verbose levels: ERROR, WARNING, NOTICE, INFO, DEBUG
42 verbose = "${toUpper cfg.verbosity}";
43 # Password is made with: 'mkpasswd -m sha-512 <password>'
44 users = (${concatStringsSep ",\n" (mapAttrsToList (username: userConfig:
45 ''
46 {
47 username = "${username}";
48 password = "${userConfig.passwordHash}";
49 max_connections = ${toString userConfig.maxConnections};
50 }
51 '') cfg.users)});
52 };
53 '';
54
55in
56
57{
58
59 ###### interface
60
61 options = {
62
63 services.nntp-proxy = {
64 enable = mkEnableOption "NNTP-Proxy";
65
66 upstreamServer = mkOption {
67 type = types.str;
68 default = "";
69 example = "ssl-eu.astraweb.com";
70 description = ''
71 Upstream server address
72 '';
73 };
74
75 upstreamPort = mkOption {
76 type = types.int;
77 default = 563;
78 description = ''
79 Upstream server port
80 '';
81 };
82
83 upstreamMaxConnections = mkOption {
84 type = types.int;
85 default = 20;
86 description = ''
87 Upstream server maximum allowed concurrent connections
88 '';
89 };
90
91 upstreamUser = mkOption {
92 type = types.str;
93 default = "";
94 description = ''
95 Upstream server username
96 '';
97 };
98
99 upstreamPassword = mkOption {
100 type = types.str;
101 default = "";
102 description = ''
103 Upstream server password
104 '';
105 };
106
107 listenAddress = mkOption {
108 type = types.str;
109 default = "127.0.0.1";
110 example = "[::]";
111 description = ''
112 Proxy listen address (IPv6 literal addresses need to be enclosed in "[" and "]" characters)
113 '';
114 };
115
116 port = mkOption {
117 type = types.int;
118 default = 5555;
119 description = ''
120 Proxy listen port
121 '';
122 };
123
124 sslKey = mkOption {
125 type = types.str;
126 default = "key.pem";
127 example = "/path/to/your/key.file";
128 description = ''
129 Proxy ssl key path
130 '';
131 };
132
133 sslCert = mkOption {
134 type = types.str;
135 default = "cert.pem";
136 example = "/path/to/your/cert.file";
137 description = ''
138 Proxy ssl certificate path
139 '';
140 };
141
142 prohibitPosting = mkOption {
143 type = types.bool;
144 default = true;
145 description = ''
146 Whether to prohibit posting to the upstream server
147 '';
148 };
149
150 verbosity = mkOption {
151 type = types.enum [ "error" "warning" "notice" "info" "debug" ];
152 default = "info";
153 example = "error";
154 description = ''
155 Verbosity level
156 '';
157 };
158
159 users = mkOption {
160 type = types.attrsOf (types.submodule {
161 options = {
162 username = mkOption {
163 type = types.str;
164 default = null;
165 description = ''
166 Username
167 '';
168 };
169
170 passwordHash = mkOption {
171 type = types.str;
172 default = null;
173 example = "$6$GtzE7FrpE$wwuVgFYU.TZH4Rz.Snjxk9XGua89IeVwPQ/fEUD8eujr40q5Y021yhn0aNcsQ2Ifw.BLclyzvzgegopgKcneL0";
174 description = ''
175 SHA-512 password hash (can be generated by
176 <code>mkpasswd -m sha-512 <password></code>)
177 '';
178 };
179
180 maxConnections = mkOption {
181 type = types.int;
182 default = 1;
183 description = ''
184 Maximum number of concurrent connections to the proxy for this user
185 '';
186 };
187 };
188 });
189 description = ''
190 NNTP-Proxy user configuration
191 '';
192
193 default = {};
194 example = literalExample ''
195 "user1" = {
196 passwordHash = "$6$1l0t5Kn2Dk$appzivc./9l/kjq57eg5UCsBKlcfyCr0zNWYNerKoPsI1d7eAwiT0SVsOVx/CTgaBNT/u4fi2vN.iGlPfv1ek0";
197 maxConnections = 5;
198 };
199 "anotheruser" = {
200 passwordHash = "$6$6lwEsWB.TmsS$W7m1riUx4QrA8pKJz8hvff0dnF1NwtZXgdjmGqA1Dx2MDPj07tI9GNcb0SWlMglE.2/hBgynDdAd/XqqtRqVQ0";
201 maxConnections = 7;
202 };
203 '';
204 };
205 };
206
207 };
208
209 ###### implementation
210
211 config = mkIf cfg.enable {
212
213 users.extraUsers = singleton
214 { name = proxyUser;
215 uid = config.ids.uids.nntp-proxy;
216 description = "NNTP-Proxy daemon user";
217 };
218
219 systemd.services.nntp-proxy = {
220 description = "NNTP proxy";
221 after = [ "network.target" "nss-lookup.target" ];
222 wantedBy = [ "multi-user.target" ];
223 serviceConfig = { User="${proxyUser}"; };
224 serviceConfig.ExecStart = "${nntp-proxy}/bin/nntp-proxy ${confFile}";
225 preStart = ''
226 if [ ! \( -f ${cfg.sslCert} -a -f ${cfg.sslKey} \) ]; then
227 ${pkgs.openssl.bin}/bin/openssl req -subj '/CN=AutoGeneratedCert/O=NixOS Service/C=US' \
228 -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout ${cfg.sslKey} -out ${cfg.sslCert};
229 fi
230 '';
231 };
232
233 };
234
235}