1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.namecoind;
7 dataDir = "/var/lib/namecoind";
8 useSSL = (cfg.rpc.certificate != null) && (cfg.rpc.key != null);
9 useRPC = (cfg.rpc.user != null) && (cfg.rpc.password != null);
10
11 listToConf = option: list:
12 concatMapStrings (value :"${option}=${value}\n") list;
13
14 configFile = pkgs.writeText "namecoin.conf" (''
15 server=1
16 daemon=0
17 txindex=1
18 txprevcache=1
19 walletpath=${cfg.wallet}
20 gen=${if cfg.generate then "1" else "0"}
21 ${listToConf "addnode" cfg.extraNodes}
22 ${listToConf "connect" cfg.trustedNodes}
23 '' + optionalString useRPC ''
24 rpcbind=${cfg.rpc.address}
25 rpcport=${toString cfg.rpc.port}
26 rpcuser=${cfg.rpc.user}
27 rpcpassword=${cfg.rpc.password}
28 ${listToConf "rpcallowip" cfg.rpc.allowFrom}
29 '' + optionalString useSSL ''
30 rpcssl=1
31 rpcsslcertificatechainfile=${cfg.rpc.certificate}
32 rpcsslprivatekeyfile=${cfg.rpc.key}
33 rpcsslciphers=TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH
34 '');
35
36in
37
38{
39
40 ###### interface
41
42 options = {
43
44 services.namecoind = {
45
46 enable = mkEnableOption "namecoind, Namecoin client.";
47
48 wallet = mkOption {
49 type = types.path;
50 default = "${dataDir}/wallet.dat";
51 description = ''
52 Wallet file. The ownership of the file has to be
53 namecoin:namecoin, and the permissions must be 0640.
54 '';
55 };
56
57 generate = mkOption {
58 type = types.bool;
59 default = false;
60 description = ''
61 Whether to generate (mine) Namecoins.
62 '';
63 };
64
65 extraNodes = mkOption {
66 type = types.listOf types.str;
67 default = [ ];
68 description = ''
69 List of additional peer IP addresses to connect to.
70 '';
71 };
72
73 trustedNodes = mkOption {
74 type = types.listOf types.str;
75 default = [ ];
76 description = ''
77 List of the only peer IP addresses to connect to. If specified
78 no other connection will be made.
79 '';
80 };
81
82 rpc.user = mkOption {
83 type = types.nullOr types.str;
84 default = null;
85 description = ''
86 User name for RPC connections.
87 '';
88 };
89
90 rpc.password = mkOption {
91 type = types.str;
92 default = null;
93 description = ''
94 Password for RPC connections.
95 '';
96 };
97
98 rpc.address = mkOption {
99 type = types.str;
100 default = "0.0.0.0";
101 description = ''
102 IP address the RPC server will bind to.
103 '';
104 };
105
106 rpc.port = mkOption {
107 type = types.int;
108 default = 8332;
109 description = ''
110 Port the RPC server will bind to.
111 '';
112 };
113
114 rpc.certificate = mkOption {
115 type = types.nullOr types.path;
116 default = null;
117 example = "/var/lib/namecoind/server.cert";
118 description = ''
119 Certificate file for securing RPC connections.
120 '';
121 };
122
123 rpc.key = mkOption {
124 type = types.nullOr types.path;
125 default = null;
126 example = "/var/lib/namecoind/server.pem";
127 description = ''
128 Key file for securing RPC connections.
129 '';
130 };
131
132
133 rpc.allowFrom = mkOption {
134 type = types.listOf types.str;
135 default = [ "127.0.0.1" ];
136 description = ''
137 List of IP address ranges allowed to use the RPC API.
138 Wiledcards (*) can be user to specify a range.
139 '';
140 };
141
142 };
143
144 };
145
146
147 ###### implementation
148
149 config = mkIf cfg.enable {
150
151 services.dnschain.extraConfig = ''
152 [namecoin]
153 config = ${configFile}
154 '';
155
156 users.extraUsers = singleton {
157 name = "namecoin";
158 uid = config.ids.uids.namecoin;
159 description = "Namecoin daemon user";
160 home = dataDir;
161 createHome = true;
162 };
163
164 users.extraGroups = singleton {
165 name = "namecoin";
166 gid = config.ids.gids.namecoin;
167 };
168
169 systemd.services.namecoind = {
170 description = "Namecoind daemon";
171 after = [ "network.target" ];
172 wantedBy = [ "multi-user.target" ];
173
174 serviceConfig = {
175 User = "namecoin";
176 Griup = "namecoin";
177 ExecStart = "${pkgs.altcoins.namecoind}/bin/namecoind -conf=${configFile} -datadir=${dataDir} -printtoconsole";
178 ExecStop = "${pkgs.coreutils}/bin/kill -KILL $MAINPID";
179 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
180 Nice = "10";
181 PrivateTmp = true;
182 TimeoutStopSec = "60s";
183 TimeoutStartSec = "2s";
184 Restart = "always";
185 StartLimitInterval = "120s";
186 StartLimitBurst = "5";
187 };
188
189 preStart = optionalString (cfg.wallet != "${dataDir}/wallet.dat") ''
190 # check wallet file permissions
191 if [ "$(stat --printf '%u' ${cfg.wallet})" != "${toString config.ids.uids.namecoin}" \
192 -o "$(stat --printf '%g' ${cfg.wallet})" != "${toString config.ids.gids.namecoin}" \
193 -o "$(stat --printf '%a' ${cfg.wallet})" != "640" ]; then
194 echo "ERROR: bad ownership or rights on ${cfg.wallet}" >&2
195 exit 1
196 fi
197 '';
198
199 };
200
201 };
202
203}