Merge fort-nix/nix-bitcoin#425: Misc. improvements

def64a73b8 treewide: use TODO-EXTERNAL (Erik Arvstedt)
6f37bef2a3 netns-isolation: simplify firewall setup (Erik Arvstedt)
f52059ce3c docs: add doc 'Configuration and maintenance' (Erik Arvstedt)
94aee8174d usage.md: add section `Managing services` (Erik Arvstedt)
8cc7b83da1 usage.md: convert to '#' heading syntax (Erik Arvstedt)
91fbcfcc77 faq.md: reformat (Erik Arvstedt)
9e4f4d6b0f bitcoind: add option `txindex` (Erik Arvstedt)
10a744a598 rtl: add option `extraCurrency` (Erik Arvstedt)
62a2602e78 electrs: use dataDir for storing extra config (Erik Arvstedt)
9bda7305fd services: add `tor.*` options (Erik Arvstedt)
ff24e73ad7 onion-addresses: fix files not being copied (Erik Arvstedt)
c6fe017aeb netns-isolation: avoid creating service files for disabled services (Erik Arvstedt)
017e08ca10 btcpayserver: move nbxplorer options to bottom (Erik Arvstedt)
e1d869d76c modules.nix: move rtl to fix topological sorting (Erik Arvstedt)
e44cd7ecdc rtl: improve descriptions (Erik Arvstedt)
bd275d3a9a minor improvements (Erik Arvstedt)
8aa28da110 remove `recurring-donations` module (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  nixbitcoin:
    ACK def64a73b8
  jonasnick:
    ACK def64a73b8

Tree-SHA512: 13acd2a3dd73c07f9c31874c8e961f12f39accb48847cbad08479b9a8154b79a6f186819272072dfb5c4768264b81f6e058e9afa57a729db2096784e48352dfd
This commit is contained in:
Jonas Nick
2021-11-29 18:05:08 +00:00
31 changed files with 553 additions and 322 deletions

View File

@@ -157,7 +157,7 @@ let
};
proxy = mkOption {
type = types.nullOr types.str;
default = if cfg.enforceTor then config.nix-bitcoin.torClientAddressWithPort else null;
default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null;
description = "Connect through SOCKS5 proxy";
};
i2p = mkOption {
@@ -206,6 +206,11 @@ let
Value 0 disables pruning.
'';
};
txindex = mkOption {
type = types.bool;
default = false;
description = "Enable the transaction index.";
};
zmqpubrawblock = mkOption {
type = types.nullOr types.str;
default = null;
@@ -262,7 +267,7 @@ let
'';
description = "Binary to connect with the bitcoind instance.";
};
enforceTor = nbLib.enforceTor;
tor = nbLib.tor;
};
};
@@ -284,6 +289,7 @@ let
''}
${optionalString (cfg.dbCache != null) "dbcache=${toString cfg.dbCache}"}
prune=${toString cfg.prune}
${optionalString cfg.txindex "txindex=1"}
${optionalString (cfg.sysperms != null) "sysperms=${if cfg.sysperms then "1" else "0"}"}
${optionalString (cfg.disablewallet != null) "disablewallet=${if cfg.disablewallet then "1" else "0"}"}
${optionalString (cfg.assumevalid != null) "assumevalid=${cfg.assumevalid}"}
@@ -407,7 +413,7 @@ in {
Restart = "on-failure";
UMask = mkIf cfg.dataDirReadableByGroup "0027";
ReadWritePaths = cfg.dataDir;
} // nbLib.allowedIPAddresses cfg.enforceTor
} // nbLib.allowedIPAddresses cfg.tor.enforce
// optionalAttrs zmqServerEnabled nbLib.allowNetlink;
};

View File

@@ -3,45 +3,6 @@
with lib;
let
options.services = {
nbxplorer = {
package = mkOption {
type = types.package;
default = nbPkgs.nbxplorer;
description = "The package providing nbxplorer binaries.";
};
address = mkOption {
type = types.str;
default = "127.0.0.1";
description = "Address to listen on.";
};
port = mkOption {
type = types.port;
default = 24444;
description = "Port to listen on.";
};
dataDir = mkOption {
type = types.path;
default = "/var/lib/nbxplorer";
description = "The data directory for nbxplorer.";
};
user = mkOption {
type = types.str;
default = "nbxplorer";
description = "The user as which to run nbxplorer.";
};
group = mkOption {
type = types.str;
default = cfg.nbxplorer.user;
description = "The group as which to run nbxplorer.";
};
enable = mkOption {
# This option is only used by netns-isolation
internal = true;
default = cfg.btcpayserver.enable;
};
enforceTor = nbLib.enforceTor;
};
btcpayserver = {
enable = mkEnableOption "btcpayserver";
address = mkOption {
@@ -93,7 +54,49 @@ let
default = cfg.btcpayserver.user;
description = "The group as which to run btcpayserver.";
};
enforceTor = nbLib.enforceTor;
tor.enforce = nbLib.tor.enforce;
};
nbxplorer = {
enable = mkOption {
# This option is only used by netns-isolation
internal = true;
default = cfg.btcpayserver.enable;
description = ''
nbxplorer is always enabled when btcpayserver is enabled.
'';
};
package = mkOption {
type = types.package;
default = nbPkgs.nbxplorer;
description = "The package providing nbxplorer binaries.";
};
address = mkOption {
type = types.str;
default = "127.0.0.1";
description = "Address to listen on.";
};
port = mkOption {
type = types.port;
default = 24444;
description = "Port to listen on.";
};
dataDir = mkOption {
type = types.path;
default = "/var/lib/nbxplorer";
description = "The data directory for nbxplorer.";
};
user = mkOption {
type = types.str;
default = "nbxplorer";
description = "The user as which to run nbxplorer.";
};
group = mkOption {
type = types.str;
default = cfg.nbxplorer.user;
description = "The group as which to run nbxplorer.";
};
tor.enforce = nbLib.tor.enforce;
};
};
@@ -182,11 +185,11 @@ in {
RestartSec = "10s";
ReadWritePaths = cfg.nbxplorer.dataDir;
MemoryDenyWriteExecute = "false";
} // nbLib.allowedIPAddresses cfg.nbxplorer.enforceTor;
} // nbLib.allowedIPAddresses cfg.nbxplorer.tor.enforce;
};
systemd.services.btcpayserver = let
nbExplorerUrl = "http://${cfg.nbxplorer.address}:${toString cfg.nbxplorer.port}/";
nbExplorerUrl = "http://${nbLib.addressWithPort cfg.nbxplorer.address cfg.nbxplorer.port}/";
nbExplorerCookie = "${cfg.nbxplorer.dataDir}/${bitcoind.makeNetworkName "Main" "RegTest"}/.cookie";
configFile = builtins.toFile "config" (''
network=${bitcoind.network}
@@ -196,7 +199,8 @@ in {
btcexplorerurl=${nbExplorerUrl}
btcexplorercookiefile=${nbExplorerCookie}
postgres=User ID=${cfg.btcpayserver.user};Host=/run/postgresql;Database=btcpaydb
${optionalString (cfg.btcpayserver.rootpath != null) "rootpath=${cfg.btcpayserver.rootpath}"}
'' + optionalString (cfg.btcpayserver.rootpath != null) ''
rootpath=${cfg.btcpayserver.rootpath}
'' + optionalString (cfg.btcpayserver.lightningBackend == "clightning") ''
btclightning=type=clightning;server=unix:///${cfg.clightning.dataDir}/bitcoin/lightning-rpc
'' + optionalString cfg.btcpayserver.lbtc ''
@@ -234,7 +238,7 @@ in {
RestartSec = "10s";
ReadWritePaths = cfg.btcpayserver.dataDir;
MemoryDenyWriteExecute = "false";
} // nbLib.allowedIPAddresses cfg.btcpayserver.enforceTor;
} // nbLib.allowedIPAddresses cfg.btcpayserver.tor.enforce;
}; in self;
users.users.${cfg.nbxplorer.user} = {

View File

@@ -9,7 +9,9 @@ let cfg = config.services.clightning.plugins.clboss; in
type = types.ints.positive;
default = 30000;
description = ''
Specify target amount (in satoshi) that CLBOSS will leave onchain.
Target amount (in satoshi) that CLBOSS will leave on-chain.
clboss will only open new channels if this amount is smaller than
the funds in your clightning wallet.
'';
};
package = mkOption {
@@ -26,6 +28,6 @@ let cfg = config.services.clightning.plugins.clboss; in
'';
systemd.services.clightning.path = [
pkgs.dnsutils
] ++ optional config.services.clightning.enforceTor (hiPrio config.nix-bitcoin.torify);
] ++ optional config.services.clightning.tor.proxy (hiPrio config.nix-bitcoin.torify);
};
}

View File

@@ -16,14 +16,14 @@ let
};
proxy = mkOption {
type = types.nullOr types.str;
default = if cfg.enforceTor then config.nix-bitcoin.torClientAddressWithPort else null;
default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null;
description = ''
Socks proxy for connecting to Tor nodes (or for all connections if option always-use-proxy is set).
'';
};
always-use-proxy = mkOption {
type = types.bool;
default = cfg.enforceTor;
default = cfg.tor.proxy;
description = ''
Always use the proxy, even to connect to normal IP addresses.
You can still connect to Unix domain sockets manually.
@@ -43,7 +43,16 @@ let
extraConfig = mkOption {
type = types.lines;
default = "";
description = "Extra lines appended to the configuration file.";
example = ''
alias=mynode
'';
description = ''
Extra lines appended to the configuration file.
See all available options at
https://github.com/ElementsProject/lightning/blob/master/doc/lightningd-config.5.md
or by running `lightningd --help`.
'';
};
user = mkOption {
type = types.str;
@@ -70,7 +79,7 @@ let
If left empty, no address is announced.
'';
};
inherit (nbLib) enforceTor;
tor = nbLib.tor;
};
cfg = config.services.clightning;
@@ -88,6 +97,7 @@ let
bitcoin-rpcport=${toString config.services.bitcoind.rpc.port}
bitcoin-rpcuser=${config.services.bitcoind.rpc.users.public.name}
rpc-file-mode=0660
log-timestamps=false
${cfg.extraConfig}
'';
@@ -123,13 +133,14 @@ in {
preStart = ''
# The RPC socket has to be removed otherwise we might have stale sockets
rm -f ${cfg.networkDir}/lightning-rpc
install -m 640 ${configFile} '${cfg.dataDir}/config'
umask u=rw,g=r,o=
{
cat ${configFile}
echo "bitcoin-rpcpassword=$(cat ${config.nix-bitcoin.secretsDir}/bitcoin-rpcpassword-public)"
${optionalString (cfg.getPublicAddressCmd != "") ''
echo "announce-addr=$(${cfg.getPublicAddressCmd}):${toString publicPort}"
''}
} >> '${cfg.dataDir}/config'
} > '${cfg.dataDir}/config'
'';
serviceConfig = nbLib.defaultHardening // {
ExecStart = "${nbPkgs.clightning}/bin/lightningd --lightning-dir=${cfg.dataDir}";
@@ -145,7 +156,7 @@ in {
#
# Disable seccomp filtering because clightning depends on this syscall.
SystemCallFilter = [];
} // nbLib.allowedIPAddresses cfg.enforceTor;
} // nbLib.allowedIPAddresses cfg.tor.enforce;
# Wait until the rpc socket appears
postStart = ''
while [[ ! -e ${cfg.networkDir}/lightning-rpc ]]; do

View File

@@ -8,7 +8,6 @@
presets.secure-node = ./presets/secure-node.nix;
rtl = ./rtl.nix;
spark-wallet = ./spark-wallet.nix;
recurring-donations = ./recurring-donations.nix;
lnd = ./lnd.nix;
charge-lnd = ./charge-lnd.nix;
joinmarket = ./joinmarket.nix;

View File

@@ -12,7 +12,7 @@ let
port = mkOption {
type = types.port;
default = 50001;
description = "RPC port.";
description = "Port to listen for RPC connections.";
};
dataDir = mkOption {
type = types.path;
@@ -39,7 +39,7 @@ let
default = cfg.user;
description = "The group as which to run electrs.";
};
enforceTor = nbLib.enforceTor;
tor.enforce = nbLib.tor.enforce;
};
cfg = config.services.electrs;
@@ -74,10 +74,8 @@ in {
> electrs.toml
'';
serviceConfig = nbLib.defaultHardening // {
RuntimeDirectory = "electrs";
RuntimeDirectoryMode = "700";
# electrs only uses the working directory for reading electrs.toml
WorkingDirectory = "/run/electrs";
WorkingDirectory = cfg.dataDir;
ExecStart = ''
${config.nix-bitcoin.pkgs.electrs}/bin/electrs \
--log-filters=INFO \
@@ -95,7 +93,7 @@ in {
Restart = "on-failure";
RestartSec = "10s";
ReadWritePaths = cfg.dataDir;
} // nbLib.allowedIPAddresses cfg.enforceTor;
} // nbLib.allowedIPAddresses cfg.tor.enforce;
};
users.users.${cfg.user} = {

View File

@@ -29,11 +29,9 @@ let
default = cfg.user;
description = "The group as which to run JoinMarket.";
};
# This option is only used by netns-isolation
enforceTor = mkOption {
readOnly = true;
default = true;
};
# This option is only used by netns-isolation.
# Tor is always enabled.
tor.enforce = nbLib.tor.enforce;
};
cfg = config.services.joinmarket-ob-watcher;
@@ -100,7 +98,7 @@ in {
SystemCallFilter = nbLib.defaultHardening.SystemCallFilter ++ [ "mbind" ] ;
Restart = "on-failure";
RestartSec = "10s";
} // nbLib.allowTor;
} // nbLib.allowedIPAddresses cfg.tor.enforce;
};
users.users.${cfg.user} = {

View File

@@ -50,11 +50,9 @@ let
readOnly = true;
default = ircServers;
};
# This option is only used by netns-isolation
enforceTor = mkOption {
readOnly = true;
default = true;
};
# This option is only used by netns-isolation.
# Tor is always enabled.
tor.enforce = nbLib.tor.enforce;
inherit (nbLib) cliExec;
yieldgenerator = {
@@ -328,7 +326,7 @@ in {
Restart = "on-failure";
RestartSec = "10s";
ReadWritePaths = cfg.dataDir;
} // nbLib.allowTor;
} // nbLib.allowedIPAddresses cfg.tor.enforce;
};
users.users.${cfg.user} = {

View File

@@ -36,7 +36,7 @@ let
};
proxy = mkOption {
type = types.nullOr types.str;
default = if cfg.enforceTor then config.nix-bitcoin.torClientAddressWithPort else null;
default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null;
description = "host:port of SOCKS5 proxy for connnecting to the loop server.";
};
extraConfig = mkOption {
@@ -56,7 +56,7 @@ let
'';
description = "Binary to connect with the lightning-loop instance.";
};
enforceTor = nbLib.enforceTor;
tor = nbLib.tor;
};
cfg = config.services.lightning-loop;
@@ -105,7 +105,7 @@ in {
Restart = "on-failure";
RestartSec = "10s";
ReadWritePaths = cfg.dataDir;
} // nbLib.allowedIPAddresses cfg.enforceTor;
} // nbLib.allowedIPAddresses cfg.tor.enforce;
};
nix-bitcoin.secrets = {

View File

@@ -36,7 +36,7 @@ let
};
proxy = mkOption {
type = types.nullOr types.str;
default = if cfg.enforceTor then config.nix-bitcoin.torClientAddressWithPort else null;
default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null;
description = "host:port of SOCKS5 proxy for connnecting to the pool auction server.";
};
extraConfig = mkOption {
@@ -56,7 +56,7 @@ let
'';
description = "Binary to connect with the lightning-pool instance.";
};
enforceTor = nbLib.enforceTor;
tor = nbLib.tor;
};
cfg = config.services.lightning-pool;
@@ -102,7 +102,7 @@ in {
Restart = "on-failure";
RestartSec = "10s";
ReadWritePaths = cfg.dataDir;
} // (nbLib.allowedIPAddresses cfg.enforceTor)
} // (nbLib.allowedIPAddresses cfg.tor.enforce)
// nbLib.allowNetlink; # required by gRPC-Go
};
};

View File

@@ -98,7 +98,7 @@ let
};
proxy = mkOption {
type = types.nullOr types.str;
default = if cfg.enforceTor then config.nix-bitcoin.torClientAddressWithPort else null;
default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null;
description = "Connect through SOCKS5 proxy";
};
dbCache = mkOption {
@@ -156,7 +156,7 @@ let
'';
description = "Binary for managing liquid swaps.";
};
enforceTor = nbLib.enforceTor;
tor = nbLib.tor;
};
};
@@ -271,7 +271,7 @@ in {
ExecStart = "${nbPkgs.elementsd}/bin/elementsd -datadir='${cfg.dataDir}'";
Restart = "on-failure";
ReadWritePaths = cfg.dataDir;
} // nbLib.allowedIPAddresses cfg.enforceTor;
} // nbLib.allowedIPAddresses cfg.tor.enforce;
};
users.users.${cfg.user} = {

View File

@@ -46,7 +46,7 @@ let
};
tor-socks = mkOption {
type = types.nullOr types.str;
default = if cfg.enforceTor then config.nix-bitcoin.torClientAddressWithPort else null;
default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null;
description = "Socks proxy for connecting to Tor nodes";
};
macaroons = mkOption {
@@ -117,7 +117,7 @@ let
default = "${secretsDir}/lnd-cert";
description = "LND TLS certificate path.";
};
inherit (nbLib) enforceTor;
tor = nbLib.tor;
};
cfg = config.services.lnd;
@@ -143,7 +143,7 @@ let
bitcoin.active=1
bitcoin.node=bitcoind
${optionalString (cfg.enforceTor) "tor.active=true"}
${optionalString (cfg.tor.proxy) "tor.active=true"}
${optionalString (cfg.tor-socks != null) "tor.socks=${cfg.tor-socks}"}
bitcoind.rpchost=${bitcoindRpcAddress}:${toString bitcoind.rpc.port}
@@ -277,7 +277,7 @@ in {
'') (attrNames cfg.macaroons)}
'')
];
} // nbLib.allowedIPAddresses cfg.enforceTor;
} // nbLib.allowedIPAddresses cfg.tor.enforce;
};
users.users.${cfg.user} = {

View File

@@ -12,20 +12,19 @@
./bitcoind.nix
./clightning.nix
./clightning-plugins
./rtl.nix
./spark-wallet.nix
./lnd.nix
./lnd-rest-onion-service.nix # Requires onion-addresses.nix
./lightning-loop.nix
./lightning-pool.nix
./charge-lnd.nix
./rtl.nix
./electrs.nix
./liquid.nix
./btcpayserver.nix
./joinmarket.nix
./joinmarket-ob-watcher.nix
./hardware-wallets.nix
./recurring-donations.nix
# Support features
./versioning.nix

View File

@@ -70,7 +70,8 @@ let
# and
# availableNetns.clighting = [ "bitcoind" ];
#
# FIXME: Although negligible for our purposes, this calculation's runtime
# TODO-EXTERNAL:
# Although negligible for our purposes, this calculation's runtime
# is in the order of (number of connections * number of services),
# because attrsets and lists are fully copied on each update with '//' or '++'.
# This can only be improved with an update in the nix language.
@@ -156,7 +157,9 @@ in {
peer = "nb-veth-br-${toString v.id}";
inherit (v) netnsName;
nsenter = "${pkgs.utillinux}/bin/nsenter";
allowedAddresses = concatMapStringsSep "," (available: netns.${available}.address) v.availableNetns;
allowedNetnsAddresses = map (available: netns.${available}.address) v.availableNetns;
allowedAddresses = concatStringsSep ","
([ "127.0.0.1,${bridgeIp},${v.address}" ] ++ allowedNetnsAddresses);
setup = ''
${ip} netns add ${netnsName}
@@ -176,17 +179,13 @@ in {
${ip} route add default via ${bridgeIp}
${iptables} -w -P INPUT DROP
${iptables} -w -A INPUT -s 127.0.0.1,${bridgeIp},${v.address} -j ACCEPT
# allow return traffic to outgoing connections initiated by the service itself
${iptables} -w -A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT
'' + optionalString (config.services.${n}.enforceTor or false) ''
${iptables} -w -P OUTPUT DROP
${iptables} -w -A OUTPUT -d 127.0.0.1,${bridgeIp},${v.address} -j ACCEPT
'' + optionalString (v.availableNetns != []) ''
${iptables} -w -A INPUT -s ${allowedAddresses} -j ACCEPT
'' + optionalString (config.services.${n}.tor.enforce or false) ''
${iptables} -w -P OUTPUT DROP
${iptables} -w -A OUTPUT -d ${allowedAddresses} -j ACCEPT
'';
script = name: src: pkgs.writers.writeDash name ''
set -e
${src}
@@ -246,10 +245,6 @@ in {
id = 17;
# communicates with clightning over lightning-rpc socket
};
recurring-donations = {
id = 20;
# communicates with clightning over lightning-rpc socket
};
nginx = {
id = 21;
};
@@ -336,14 +331,16 @@ in {
payjoinAddress = netns.joinmarket.address;
cliExec = mkCliExec "joinmarket";
};
systemd.services.joinmarket-yieldgenerator.serviceConfig.NetworkNamespacePath = "/var/run/netns/nb-joinmarket";
systemd.services.joinmarket-yieldgenerator = mkIf config.services.joinmarket.yieldgenerator.enable {
serviceConfig.NetworkNamespacePath = "/var/run/netns/nb-joinmarket";
};
services.joinmarket-ob-watcher.address = netns.joinmarket-ob-watcher.address;
services.lightning-pool.rpcAddress = netns.lightning-pool.address;
services.rtl.address = netns.rtl.address;
systemd.services.cl-rest = {
systemd.services.cl-rest = mkIf config.services.rtl.cl-rest.enable {
serviceConfig.NetworkNamespacePath = "/var/run/netns/nb-rtl";
requires = [ "netns-rtl.service" ] ;
after = [ "netns-rtl.service" ];

View File

@@ -35,7 +35,7 @@ with lib;
runAsUserCmd = mkOption {
readOnly = true;
default = if config.security.doas.enable
# TODO: Use absolute path until https://github.com/NixOS/nixpkgs/pull/133622 is available.
# TODO-EXTERNAL: Use absolute path until https://github.com/NixOS/nixpkgs/pull/133622 is available.
then "/run/wrappers/bin/doas -u"
else "sudo -u";
};

View File

@@ -7,6 +7,16 @@ let
mkRemovedOptionModule [ "services" service "announce-tor" ] ''
Use option `nix-bitcoin.onionServices.${service}.public` instead.
'';
mkSplitEnforceTorOption = service:
(mkRemovedOptionModule [ "services" service "enforceTor" ] ''
The option has been split into options `tor.proxy` and `tor.enforce`.
Set `tor.proxy = true` to proxy outgoing connections with Tor.
Set `tor.enforce = true` to only allow connections (incoming and outgoing) through Tor.
'');
mkRenamedEnforceTorOption = service:
(mkRenamedOptionModule [ "services" service "enforceTor" ] [ "services" service "tor" "enforce" ]);
in {
imports = [
(mkRenamedOptionModule [ "services" "bitcoind" "bind" ] [ "services" "bitcoind" "address" ])
@@ -33,5 +43,20 @@ in {
bitcoin peer connections for syncing blocks. This performs well on low and high
memory systems.
'')
];
] ++
# 0.0.59
(map mkSplitEnforceTorOption [
"clightning"
"lightning-loop"
"lightning-pool"
"liquid"
"lnd"
"spark-wallet"
"bitcoind"
]) ++
(map mkRenamedEnforceTorOption [
"btcpayserver"
"rtl"
"electrs"
]);
}

View File

@@ -58,8 +58,20 @@ in {
CapabilityBoundingSet = "CAP_CHOWN CAP_FSETID CAP_SETFCAP CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_FOWNER CAP_IPC_OWNER";
};
script = ''
waitForFile() {
file=$1
for ((i=0; i<300; i++)); do
if [[ -e $file ]]; then
return;
fi
sleep 0.1
done
echo "Error: File $file did not appear after 30 sec."
exit 1
}
# Wait until tor is up
until [[ -e /var/lib/tor/state ]]; do sleep 0.1; done
waitForFile /var/lib/tor/state
cd ${cfg.dataDir}
rm -rf *
@@ -71,22 +83,20 @@ in {
${concatMapStrings
(service: ''
onionFile=/var/lib/tor/onion/${service}/hostname
if [[ -e $onionFile ]]; then
cp $onionFile ${user}/${service}
chown ${user} ${user}/${service}
fi
waitForFile $onionFile
cp $onionFile ${user}/${service}
chown ${user} ${user}/${service}
'')
cfg.access.${user}
}
}
'')
(builtins.attrNames cfg.access)
}
${concatMapStrings (service: ''
onionFile=/var/lib/tor/onion/${service}/hostname
if [[ -e $onionFile ]]; then
install -D -o ${config.systemd.services.${service}.serviceConfig.User} -m 400 $onionFile services/${service}
fi
waitForFile $onionFile
install -D -o ${config.systemd.services.${service}.serviceConfig.User} -m 400 $onionFile services/${service}
'') cfg.services}
'';
};

View File

@@ -1,27 +1,43 @@
{ lib, config, ... }:
let
defaultTrue = lib.mkDefault true;
defaultEnableTorProxy = {
tor.proxy = defaultTrue;
tor.enforce = defaultTrue;
};
defaultEnforceTor = {
tor.enforce = defaultTrue;
};
in {
services.tor = {
enable = true;
client.enable = true;
};
# Use Tor for all outgoing connections
services = {
bitcoind.enforceTor = true;
clightning.enforceTor = true;
lnd.enforceTor = true;
lightning-loop.enforceTor = true;
liquidd.enforceTor = true;
electrs.enforceTor = true;
# Use Tor as a proxy for outgoing connections
# and restrict all connections to Tor
#
bitcoind = defaultEnableTorProxy;
clightning = defaultEnableTorProxy;
lnd = defaultEnableTorProxy;
lightning-loop = defaultEnableTorProxy;
liquidd = defaultEnableTorProxy;
# TODO-EXTERNAL:
# disable Tor enforcement until btcpayserver can fetch rates over Tor
# btcpayserver.enforceTor = true;
nbxplorer.enforceTor = true;
spark-wallet.enforceTor = true;
recurring-donations.enforceTor = true;
lightning-pool.enforceTor = true;
rtl.enforceTor = true;
# btcpayserver = defaultEnableTorProxy;
spark-wallet = defaultEnableTorProxy;
lightning-pool = defaultEnableTorProxy;
# These services don't make outgoing connections
# (or use Tor by default in case of joinmarket)
# but we restrict them to Tor just to be safe.
#
electrs = defaultEnforceTor;
nbxplorer = defaultEnforceTor;
rtl = defaultEnforceTor;
joinmarket = defaultEnforceTor;
joinmarket-ob-watcher = defaultEnforceTor;
};
# Add onion services for incoming connections

View File

@@ -1,107 +0,0 @@
{ config, lib, pkgs, ... }:
with lib;
let
options.services.recurring-donations = {
enable = mkEnableOption "recurring-donations";
tallycoin = mkOption {
type = types.attrs;
default = {};
description = ''
This option is used to specify tallycoin donation receivers using an
attribute set. For example the following setting instructs the module
to repeatedly send 1000 satoshis to djbooth007.
{
"djbooth007" = 1000;
}
'';
};
interval = mkOption {
type = types.str;
default = "Mon *-*-* 00:00:00";
description = ''
Schedules the donations. Default is weekly on Mon 00:00:00. See `man
systemd.time` for further options.
'';
};
randomizedDelaySec = mkOption {
type = types.int;
default = 86400;
description = ''
Random delay to add to scheduled time for donation. Default is one day.
'';
};
enforceTor = nbLib.enforceTor;
};
cfg = config.services.recurring-donations;
nbLib = config.nix-bitcoin.lib;
recurring-donations-script = pkgs.writeScript "recurring-donations.sh" ''
LNCLI="${config.nix-bitcoin.pkgs.clightning}/bin/lightning-cli --lightning-dir=${config.services.clightning.dataDir}"
pay_tallycoin() {
NAME=$1
AMOUNT=$2
echo "Attempting to pay $AMOUNT sat to $NAME"
INVOICE=$(curl --socks5-hostname ${config.nix-bitcoin.torClientAddressWithPort} -d "satoshi_amount=$AMOUNT&payment_method=ln&id=$NAME&type=profile" -X POST https://api.tallyco.in/v1/payment/request/ | jq -r '.lightning_pay_request') 2> /dev/null
if [ -z "$INVOICE" ] || [ "$INVOICE" = "null" ]; then
echo "ERROR: did not get invoice from tallycoin"
return
fi
# Decode invoice and compare amount with requested amount
DECODED_AMOUNT=$($LNCLI decodepay "$INVOICE" | jq -r '.amount_msat' | head -c -8)
if [ -z "$DECODED_AMOUNT" ] || [ "$DECODED_AMOUNT" = "null" ]; then
echo "ERROR: did not get response from clightning"
return
fi
if [ $DECODED_AMOUNT -eq $AMOUNT ]; then
echo "Paying with invoice $INVOICE"
$LNCLI pay "$INVOICE"
else
echo "ERROR: requested amount and invoice amount do not match. $AMOUNT vs $DECODED_AMOUNT"
return
fi
}
${ builtins.foldl'
(x: receiver: x +
''
pay_tallycoin ${receiver} ${toString (builtins.getAttr receiver cfg.tallycoin)}
'')
""
(builtins.attrNames cfg.tallycoin)
}
'';
in {
inherit options;
config = mkIf cfg.enable {
services.clightning.enable = true;
systemd.services.recurring-donations = {
requires = [ "clightning.service" ];
after = [ "clightning.service" ];
path = with pkgs; [ nix-bitcoin.clightning curl jq ];
serviceConfig = nbLib.defaultHardening // {
ExecStart = "${pkgs.bash}/bin/bash ${recurring-donations-script}";
User = "recurring-donations";
Type = "oneshot";
} // nbLib.allowedIPAddresses cfg.enforceTor;
};
systemd.timers.recurring-donations = {
requires = [ "clightning.service" ];
after = [ "clightning.service" ];
timerConfig = {
Unit = "recurring-donations.service";
OnCalendar = cfg.interval;
RandomizedDelaySec = toString cfg.randomizedDelaySec;
};
wantedBy = [ "multi-user.target" ];
};
users.users.recurring-donations = {
isSystemUser = true;
group = "recurring-donations";
extraGroups = [ config.services.clightning.group ];
};
users.groups.recurring-donations = {};
};
}

View File

@@ -23,12 +23,12 @@ let
clightning = mkOption {
type = types.bool;
default = false;
description = "Add a node interface for clightning.";
description = "Enable the clightning node interface.";
};
lnd = mkOption {
type = types.bool;
default = false;
description = "Add a node interface for lnd.";
description = "Enable the lnd node interface.";
};
reverseOrder = mkOption {
type = types.bool;
@@ -49,11 +49,36 @@ let
default = false;
description = "Enable the Night UI Theme.";
};
extraCurrency = mkOption {
type = with types; nullOr str;
default = null;
example = "USD";
description = ''
Currency code (ISO 4217) of the extra currency used for displaying balances.
When set, this option enables online currency rate fetching.
Warning: Rate fetching requires outgoing clearnet connections, so option
`tor.enforce` is automatically disabled.
'';
};
user = mkOption {
type = types.str;
default = "rtl";
description = "The user as which to run RTL.";
};
group = mkOption {
type = types.str;
default = cfg.user;
description = "The group as which to run RTL.";
};
cl-rest = {
enable = mkOption {
readOnly = true;
type = types.bool;
default = cfg.nodes.clightning;
description = "Enable c-lightning-REST server.";
description = ''
Enable c-lightning-REST server. This service is required for
clightning support and is automatically enabled.
'';
};
address = mkOption {
readOnly = true;
@@ -75,17 +100,7 @@ let
description = "Swagger API documentation server port.";
};
};
user = mkOption {
type = types.str;
default = "rtl";
description = "The user as which to run RTL.";
};
group = mkOption {
type = types.str;
default = cfg.user;
description = "The group as which to run RTL.";
};
inherit (nbLib) enforceTor;
tor.enforce = nbLib.tor.enforce;
};
cfg = config.services.rtl;
@@ -114,7 +129,10 @@ let
''"channelBackupPath": "${cfg.dataDir}/backup/lnd",''
}
"logLevel": "INFO",
"fiatConversion": false,
"fiatConversion": ${if cfg.extraCurrency == null then "false" else "true"},
${optionalString (cfg.extraCurrency != null)
''"currencyUnit": "${cfg.extraCurrency}",''
}
${optionalString (isLnd && cfg.loop)
''"swapServerUrl": "https://${nbLib.addressWithPort lightning-loop.restAddress lightning-loop.restPort}",''
}
@@ -186,6 +204,8 @@ in {
"d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -"
];
services.rtl.tor.enforce = mkIf (cfg.extraCurrency != null) false;
systemd.services.rtl = rec {
wantedBy = [ "multi-user.target" ];
requires = optional cfg.nodes.clightning "cl-rest.service" ++
@@ -210,7 +230,7 @@ in {
Restart = "on-failure";
RestartSec = "10s";
ReadWritePaths = cfg.dataDir;
} // nbLib.allowedIPAddresses cfg.enforceTor
} // nbLib.allowedIPAddresses cfg.tor.enforce
// nbLib.nodejs;
};

View File

@@ -38,7 +38,7 @@ let
default = cfg.user;
description = "The group as which to run spark-wallet.";
};
inherit (nbLib) enforceTor;
tor = nbLib.tor;
};
cfg = config.services.spark-wallet;
@@ -57,7 +57,7 @@ let
--ln-path '${clightning.networkDir}' \
--host ${cfg.address} --port ${toString cfg.port} \
--config '${config.nix-bitcoin.secretsDir}/spark-wallet-login' \
${optionalString cfg.enforceTor torRateProvider} \
${optionalString cfg.tor.proxy torRateProvider} \
$publicURL \
--pairing-qr --print-key ${cfg.extraArgs}
'';
@@ -76,7 +76,7 @@ in {
User = cfg.user;
Restart = "on-failure";
RestartSec = "10s";
} // nbLib.allowedIPAddresses cfg.enforceTor
} // nbLib.allowedIPAddresses cfg.tor.enforce
// nbLib.nodejs;
};