nixos/hosts/astral/radicale.nix
2025-10-15 14:26:28 -07:00

100 lines
2.5 KiB
Nix

{ pkgs, config, lib, ... }:
let domain = "radicale.leaf.ninja";
in {
users.users.radicale-sync = {
isSystemUser = true;
group = "radicale-sync";
};
users.groups.radicale-sync = { };
age.secrets = {
radicale-htpasswd = {
file = ./secrets/radicale-htpasswd;
mode = "400";
owner = "radicale";
};
radicale-sync-secrets = {
file = ./secrets/radicale-sync-secrets.fish;
mode = "400";
owner = "radicale-sync";
};
};
services.radicale = {
enable = true;
settings = {
server.hosts = [ "localhost:5232" ];
auth = {
type = "htpasswd";
htpasswd_filename = config.age.secrets.radicale-htpasswd.path;
htpasswd_encryption = "plain";
};
};
rights = {
root = {
user = ".+";
collection = "";
permissions = "R";
};
principal = {
user = ".+";
collection = "{user}";
permissions = "RW";
};
calendars = {
user = ".+";
collection = "{user}/[^/]+";
permissions = "rw";
};
remote = {
user = ".+";
collection = "remote/.+";
permissions = "r";
};
};
};
services.caddy.virtualHosts.${domain}.extraConfig = ''
reverse_proxy localhost:5232
'';
systemd.timers.radicale-sync = {
wantedBy = [ "timers.target" ];
timerConfig = {
OnBootSec = "5min";
OnCalendar = "*-*-* *:0/4:00";
};
};
systemd.services.radicale-sync = let
radicaleUrl = "http://localhost:5232";
remoteCollections = [{
collection = "devhack";
url = "https://devhack.net/calendar.ics";
}];
remoteCollectionsFile = pkgs.writers.writeText "remote-collections"
(lib.concatMapStringsSep "\n"
({ collection, url }: "${collection} ${url}") remoteCollections);
syncScript = pkgs.writers.writeFish "sync.fish" ''
alias curl ${lib.getExe pkgs.curl}
source ${config.age.secrets.radicale-sync-secrets.path}
while read -l name url
set tempfile (mktemp)
curl -sf $url -o $tempfile
curl -sf -u "remote:$password" \
-X PUT "${radicaleUrl}/remote/$name" \
-H 'Content-Type: text/calendar; charset=utf-8' \
--data-binary @$tempfile
echo "Uploaded $name"
end < ${remoteCollectionsFile}
'';
in {
serviceConfig = {
Type = "oneshot";
User = "radicale-sync";
Group = "radicale-sync";
ExecStart = syncScript;
};
};
}