Files
clan-core/clanServices/syncthing/shared.nix
pinpox 998aaec269 wip
2025-07-22 17:39:50 +02:00

173 lines
5.8 KiB
Nix

{
config,
pkgs,
lib,
settings,
introducerID,
...
}:
{
imports = [
{
# Syncthing ports: 8384 for remote access to GUI
# 22000 TCP and/or UDP for sync traffic
# 21027/UDP for discovery
# source: https://docs.syncthing.net/users/firewall.html
networking.firewall.interfaces."zt+".allowedTCPPorts = [
8384
22000
];
networking.firewall.allowedTCPPorts = [ 8384 ];
networking.firewall.interfaces."zt+".allowedUDPPorts = [
22000
21027
];
assertions = [
{
assertion = lib.all (
attr: builtins.hasAttr attr config.services.syncthing.settings.folders
) settings.autoShares;
message = ''
Syncthing: If you want to AutoShare a folder, you need to have it configured on the sharing device.
'';
}
];
# Activates inotify compatibility on syncthing
# use mkOverride 900 here as it otherwise would collide with the default of the
# upstream nixos xserver.nix
boot.kernel.sysctl."fs.inotify.max_user_watches" = lib.mkOverride 900 524288;
services.syncthing = {
enable = true;
overrideFolders = lib.mkDefault (if (introducerID == null) then true else false);
overrideDevices = lib.mkDefault (if (introducerID == null) then true else false);
key = lib.mkDefault config.clan.core.vars.generators.syncthing.files."key".path or null;
cert = lib.mkDefault config.clan.core.vars.generators.syncthing.files."cert".path or null;
settings = {
options = {
urAccepted = -1;
allowedNetworks = [ ];
};
devices =
{ }
// (
if (introducerID == null) then
{ }
else
{
"${introducerID}" = {
name = "introducer";
id = introducerID;
introducer = true;
autoAcceptFolders = true;
};
}
);
};
};
systemd.services.syncthing-auto-accept =
let
baseAddress = "127.0.0.1:8384";
getPendingDevices = "/rest/cluster/pending/devices";
postNewDevice = "/rest/config/devices";
SharedFolderById = "/rest/config/folders/";
apiKey = config.clan.core.vars.generators.syncthing.files."apikey".path;
in
lib.mkIf settings.autoAcceptDevices {
description = "Syncthing auto accept devices";
requisite = [ "syncthing.service" ];
after = [ "syncthing.service" ];
wantedBy = [ "multi-user.target" ];
script = ''
set -x
# query pending deviceID's
APIKEY=$(cat ${apiKey})
PENDING=$(${lib.getExe pkgs.curl} -X GET -H "X-API-Key: $APIKEY" ${baseAddress}${getPendingDevices})
PENDING=$(echo $PENDING | ${lib.getExe pkgs.jq} keys[])
# accept pending deviceID's
for ID in $PENDING;do
${lib.getExe pkgs.curl} -X POST -d "{\"deviceId\": $ID}" -H "Content-Type: application/json" -H "X-API-Key: $APIKEY" ${baseAddress}${postNewDevice}
# get all shared folders by their ID
for folder in ${builtins.toString settings.autoShares}; do
SHARED_IDS=$(${lib.getExe pkgs.curl} -X GET -H "X-API-Key: $APIKEY" ${baseAddress}${SharedFolderById}"$folder" | ${lib.getExe pkgs.jq} ."devices")
PATCHED_IDS=$(echo $SHARED_IDS | ${lib.getExe pkgs.jq} ".+= [{\"deviceID\": $ID, \"introducedBy\": \"\", \"encryptionPassword\": \"\"}]")
${lib.getExe pkgs.curl} -X PATCH -d "{\"devices\": $PATCHED_IDS}" -H "X-API-Key: $APIKEY" ${baseAddress}${SharedFolderById}"$folder"
done
done
'';
};
systemd.timers.syncthing-auto-accept = lib.mkIf settings.autoAcceptDevices {
description = "Syncthing Auto Accept";
wantedBy = [ "syncthing-auto-accept.service" ];
timerConfig = {
OnActiveSec = lib.mkDefault 60;
OnUnitActiveSec = lib.mkDefault 60;
};
};
systemd.services.syncthing-init-api-key =
let
apiKey = config.clan.core.vars.generators.syncthing.files."apikey".path;
in
lib.mkIf settings.autoAcceptDevices {
description = "Set the api key";
after = [ "syncthing-init.service" ];
wantedBy = [ "multi-user.target" ];
script = ''
# set -x
set -efu pipefail
APIKEY=$(cat ${apiKey})
${lib.getExe pkgs.gnused} -i "s/<apikey>.*<\/apikey>/<apikey>$APIKEY<\/apikey>/" ${config.services.syncthing.configDir}/config.xml
# sudo systemctl restart syncthing.service
systemctl restart syncthing.service
'';
serviceConfig = {
BindReadOnlyPaths = [ apiKey ];
Type = "oneshot";
};
};
clan.core.vars.generators.syncthing = {
files."key".group = config.services.syncthing.group;
files."key".owner = config.services.syncthing.user;
files."cert".group = config.services.syncthing.group;
files."cert".owner = config.services.syncthing.user;
files."apikey".group = config.services.syncthing.group;
files."apikey".owner = config.services.syncthing.user;
files."id".secret = false;
runtimeInputs = [
pkgs.coreutils
pkgs.gnugrep
pkgs.syncthing
];
script = ''
syncthing generate --config "$out"
mv "$out"/key.pem "$out"/key
mv "$out"/cert.pem "$out"/cert
cat "$out"/config.xml | grep -oP '(?<=<device id=")[^"]+' | uniq > "$out"/id
cat "$out"/config.xml | grep -oP '<apikey>\K[^<]+' | uniq > "$out"/apikey
'';
};
}
];
}