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