From f1f2043fbaf8ef6c3990ea81ca4a80f2c2541050 Mon Sep 17 00:00:00 2001 From: Nettika Date: Wed, 15 Oct 2025 14:26:28 -0700 Subject: [PATCH] WIP --- hosts/astral/default.nix | 6 ++ hosts/astral/links.nix | 18 ++-- hosts/astral/radicale.nix | 100 ++++++++++++++++++ hosts/astral/secrets/radicale-htpasswd | 7 ++ .../astral/secrets/radicale-sync-secrets.fish | 7 ++ secrets.nix | 3 + 6 files changed, 132 insertions(+), 9 deletions(-) create mode 100644 hosts/astral/radicale.nix create mode 100644 hosts/astral/secrets/radicale-htpasswd create mode 100644 hosts/astral/secrets/radicale-sync-secrets.fish diff --git a/hosts/astral/default.nix b/hosts/astral/default.nix index cc03584..c600557 100644 --- a/hosts/astral/default.nix +++ b/hosts/astral/default.nix @@ -7,6 +7,7 @@ agenix.nixosModules.default ./forgejo.nix ./links.nix + ./radicale.nix ./vaultwarden.nix ]; @@ -35,6 +36,11 @@ services.caddy = { enable = true; + package = pkgs.caddy.withPlugins { + plugins = + [ "github.com/abiosoft/caddy-exec@v0.0.0-20240914124740-521d8736cb4d" ]; + hash = "sha256-ef6/x7wjKk0axjX6MfAzTTwPM2FTOTSSyI9zLLrczV0="; + }; virtualHosts = { "astral.leaf.ninja".extraConfig = '' respond "astral is online" diff --git a/hosts/astral/links.nix b/hosts/astral/links.nix index eb70571..bbf7a7e 100644 --- a/hosts/astral/links.nix +++ b/hosts/astral/links.nix @@ -22,15 +22,15 @@ let httpd.serve_forever() ''; in { - systemd.services.links-webhook = { - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - serviceConfig = { - Type = "simple"; - ExecStart = "${pkgs.python3}/bin/python3 ${webhookHandler}"; - Restart = "always"; - }; - }; + # systemd.services.links-webhook = { + # wantedBy = [ "multi-user.target" ]; + # after = [ "network.target" ]; + # serviceConfig = { + # Type = "simple"; + # ExecStart = "${pkgs.python3}/bin/python3 ${webhookHandler}"; + # Restart = "always"; + # }; + # }; services.caddy.virtualHosts.${domain}.extraConfig = '' root * ${root} diff --git a/hosts/astral/radicale.nix b/hosts/astral/radicale.nix new file mode 100644 index 0000000..79527b7 --- /dev/null +++ b/hosts/astral/radicale.nix @@ -0,0 +1,100 @@ +{ 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; + }; + }; +} diff --git a/hosts/astral/secrets/radicale-htpasswd b/hosts/astral/secrets/radicale-htpasswd new file mode 100644 index 0000000..c2a396c --- /dev/null +++ b/hosts/astral/secrets/radicale-htpasswd @@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 f+PJrQ iGtaCi4amFijPCydakWm6qo6eYPiRHp5Rrr7TpnRLxo +MiFAmPkU9gDBYdNqGA9CdYike2n780nQ7o8nAZ0GGtE +-> ssh-ed25519 nz/vnw FiTGU3HNakVR1VNVyUPdiu+WhEMf9t/ONBgoQRILExA +TjDSkxA6z1ovqu2mA0G1UY1k29f35HFHDZQWA90XSzM +--- WK1KjkiLaqH1jN3zIgetSHEe5xEddBYjlt3Qu5Z/Bcg +Ϲ%slma@Oԧ> K<(Co6hӖLɠ(_hR2Ȋ"znp/MW}LNe%C̺7?#j3ҋG?ÁX{V%Ym lf \ No newline at end of file diff --git a/hosts/astral/secrets/radicale-sync-secrets.fish b/hosts/astral/secrets/radicale-sync-secrets.fish new file mode 100644 index 0000000..3cc4d6d --- /dev/null +++ b/hosts/astral/secrets/radicale-sync-secrets.fish @@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 f+PJrQ f+4sexgdKNmdc7DQe3h6v8CveCiHN+dLFX0vdMzBOBQ +/nSP3nPNdxKjOUIn0xzH/ht4QC68aMxCLplP8kIeKr4 +-> ssh-ed25519 nz/vnw ejIzeXNfCDxPhho7426oR6WQWlJxDprp1j90lgCGnmM +yaq9bU726x5xtHhK7ZQc1Onlg681cSQsSxSCRU/GBAU +--- UT7B9uDmsNJwTLroGj+JQdKbsOHhgSnnlhMru4tY7/M +uK Ti,M`S4~6ϒjҫ9$H0d?pXV%IJؘ "ҾdWO \ No newline at end of file diff --git a/secrets.nix b/secrets.nix index 58ceb27..7956f39 100644 --- a/secrets.nix +++ b/secrets.nix @@ -13,4 +13,7 @@ in { "hosts/astral/secrets/vaultwarden-env.age".publicKeys = [ marauder astral ]; "hosts/astral/secrets/forgejo-mailer-password.age".publicKeys = [ marauder astral ]; + "hosts/astral/secrets/radicale-htpasswd".publicKeys = [ marauder astral ]; + "hosts/astral/secrets/radicale-sync-secrets.fish".publicKeys = + [ marauder astral ]; }