dotfiles/os/syncthing/default.nix

162 lines
5 KiB
Nix

{
pkgs,
lib,
config,
...
}:
let
cfg = config.services.syncthing;
service = "syncthing";
secretsDir = "/etc/secrets/${service}";
password = {
path = "syncthing/${config.frogeye.name}";
selector = "@";
generator = ''(t="$(mktemp -d)" && ${lib.getExe pkgs.syncthing} generate --home="$t" &> /dev/null && cat "$t"/{cert,key}.pem && rm -rf "$t")'';
};
capitalizeFirstLetter =
str:
(lib.strings.toUpper (builtins.substring 0 1 str))
+ (builtins.substring 1 (builtins.stringLength str) str);
nixosDevices = builtins.map (system: system.config.frogeye) (
builtins.attrValues config.frogeye.toplevel.nixosConfigurations
);
allDevices = nixosDevices;
syncingDevices = builtins.filter (device: device.syncthing.id != null) allDevices;
peerDevices = builtins.filter (
device: device.syncthing.id != config.frogeye.syncthing.id
) syncingDevices;
# Can't use the module's folders enable option, as it still requests things somehow
allFolders = builtins.attrValues config.frogeye.folders;
syncedFolders = builtins.filter (folder: folder.syncthing.enable) allFolders;
folderShouldSyncWith =
folder: device:
(lib.hasAttrByPath [ folder.name ] device.folders)
&& device.folders.${folder.name}.syncthing.enable;
enable = (builtins.length syncedFolders) > 0;
in
{
config = {
# Allow to export configuration to other systems
system.build.syncthingConfig = {
folders = lib.trivial.pipe syncedFolders [
(builtins.map (folder: {
name = folder.name;
value = folder;
}))
builtins.listToAttrs
(lib.attrsets.mapAttrs (
folderName: folder:
(lib.attrsets.filterAttrs (
k: v:
builtins.elem k [
"label"
"path"
"syncthing"
"user"
]
))
folder
))
];
devices = lib.trivial.pipe syncingDevices [
(builtins.map (device: {
name = device.name;
value = device;
}))
builtins.listToAttrs
(lib.attrsets.mapAttrs (
deviceName: device:
{
folders = lib.trivial.pipe device.folders [
(lib.attrsets.filterAttrs (folderName: folder: folder.syncthing.enable))
(lib.attrsets.mapAttrs (folderName: folder: { syncthing.enable = true; }))
];
}
//
(lib.attrsets.filterAttrs (
k: v:
builtins.elem k [
"syncthing"
]
))
device
))
];
};
services.${service} = {
inherit enable;
openDefaultPorts = true;
configDir = "/var/lib/${service}";
databaseDir = "/var/cache/${service}";
dataDir = cfg.databaseDir; # Don't really care
key = "${secretsDir}/key.pem";
cert = "${secretsDir}/cert.pem";
settings = {
devices = builtins.listToAttrs (
builtins.map (device: {
inherit (device) name;
value = device.syncthing;
}) syncingDevices
);
folders = builtins.listToAttrs (
builtins.map (folder: {
inherit (folder) name;
value = {
label = "${capitalizeFirstLetter folder.user} ${folder.label}";
path = "${config.users.users.${folder.user}.home}/${folder.path}";
devices = builtins.map (device: device.name) (
builtins.filter (folderShouldSyncWith folder) peerDevices
);
versioning =
if (config.frogeye.storageSize == "big" && folder.versionsMaxDays != null) then
{
type = "staggered";
params.maxAge = builtins.toString (folder.versionsMaxDays * 24 * 3600);
# TODO Increase cleanupIntervalS to 1 day or so
}
else
null;
rescanIntervalS = 10 * 3600; # Using watcher, should be good enough
copyRangeMethod = "all"; # Prevents duplication
copyOwnershipFromParent = true;
} // folder.syncthing;
}) syncedFolders
);
options = rec {
urAccepted = 3;
urSeen = urAccepted;
};
};
};
systemd.services.${service}.serviceConfig = {
ExecStartPre = [
"+${pkgs.writeShellScript "syncthing-create-folders" ''
install -Dm700 -o ${cfg.user} -g ${cfg.group} -d ${cfg.configDir}
install -Dm700 -o ${cfg.user} -g ${cfg.group} -d ${cfg.databaseDir}
''}"
];
PrivateUsers = lib.mkForce false;
AmbientCapabilities = [
"CAP_CHOWN"
"CAP_DAC_OVERRIDE"
"CAP_FOWNER"
];
};
vivarium.passwordFiles = {
${cfg.key}.password = password // {
transform = "${lib.getExe pkgs.openssl} pkey";
};
${cfg.cert}.password = password // {
transform = "${lib.getExe pkgs.openssl} x509";
};
};
};
}