From aef71f548a08c4cc192c626124f95105833ce364 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 13 Apr 2024 04:34:53 +0200
Subject: [PATCH 01/67] WIP: authelia: Add SSO

---
 configuration/default.nix                  |  1 +
 configuration/services/auth.nix            | 95 +++++++++++++++++++++
 configuration/services/metrics/grafana.nix |  1 +
 configuration/services/postgres.nix        | 11 ++-
 keys/production.yaml                       |  8 +-
 keys/staging.yaml                          |  9 +-
 modules/nginxExtensions.nix                | 99 ++++++++++++++++++++++
 7 files changed, 217 insertions(+), 7 deletions(-)
 create mode 100644 configuration/services/auth.nix

diff --git a/configuration/default.nix b/configuration/default.nix
index 3b580eb..556d81e 100644
--- a/configuration/default.nix
+++ b/configuration/default.nix
@@ -15,6 +15,7 @@
     (import ../modules)
 
     ./services/afvalcalendar.nix
+    ./services/auth.nix
     ./services/backups.nix
     ./services/battery-manager.nix
     ./services/conduit.nix
diff --git a/configuration/services/auth.nix b/configuration/services/auth.nix
new file mode 100644
index 0000000..cd78111
--- /dev/null
+++ b/configuration/services/auth.nix
@@ -0,0 +1,95 @@
+{
+  pkgs,
+  config,
+  ...
+}: let
+  user = config.services.authelia.instances.main.user;
+  domain = "auth.${config.services.nginx.domain}";
+in {
+  services.authelia.instances.main = {
+    enable = true;
+    settings = {
+      theme = "auto";
+
+      access_control.default_policy = "one_factor";
+
+      authentication_backend = {
+        password_reset.disable = true;
+        file.path = "/var/lib/authelia-main/users.yml";
+      };
+
+      notifier.filesystem.filename = "/var/lib/authelia-main/notification.txt";
+
+      session = {
+        domain = config.services.nginx.domain;
+        redis.host = config.services.redis.servers.authelia.unixSocket;
+      };
+
+      storage.postgres = {
+        host = "/run/postgresql";
+        port = 5432;
+        database = user;
+        username = user;
+
+        password = "unnecessary";
+      };
+    };
+
+    secrets = {
+      storageEncryptionKeyFile = config.sops.secrets."authelia/storageEncryptionKey".path; # Database
+      sessionSecretFile = config.sops.secrets."authelia/sessionSecret".path; # Redis
+      jwtSecretFile = config.sops.secrets."authelia/jwtSecret".path;
+    };
+  };
+
+  systemd.services.authelia-main.after = ["postgresql.service"];
+
+  services.nginx = {
+    # TODO(tlater): Possibly remove on next authelia release
+    additionalModules = with pkgs.nginxModules; [
+      develkit
+      set-misc
+    ];
+
+    virtualHosts."${domain}" = {
+      forceSSL = true;
+      enableACME = true;
+      enableHSTS = true;
+
+      locations = {
+        "/" = {
+          proxyPass = "http://127.0.0.1:9091";
+          recommendedProxySettings = false;
+          enableAutheliaProxy = true;
+        };
+
+        "/api/verify" = {
+          proxyPass = "http://127.0.0.1:9091";
+          recommendedProxySettings = false;
+        };
+      };
+    };
+  };
+
+  services.redis.servers.authelia = {
+    inherit user;
+    enable = true;
+  };
+
+  sops.secrets = {
+    "authelia/storageEncryptionKey" = {
+      owner = user;
+      group = user;
+    };
+
+    "authelia/sessionSecret" = {
+      owner = user;
+      group = user;
+    };
+
+    "authelia/jwtSecret" = {
+      owner = user;
+      group = user;
+    };
+  };
+}
diff --git a/configuration/services/metrics/grafana.nix b/configuration/services/metrics/grafana.nix
index eb5106e..1136a17 100644
--- a/configuration/services/metrics/grafana.nix
+++ b/configuration/services/metrics/grafana.nix
@@ -40,6 +40,7 @@ in {
     forceSSL = true;
     useACMEHost = "tlater.net";
     enableHSTS = true;
+    enableAuthorization = true;
     locations."/".proxyPass = "http://localhost:${toString config.services.grafana.settings.server.http_port}";
   };
 }
diff --git a/configuration/services/postgres.nix b/configuration/services/postgres.nix
index 018dc6e..4ec1e83 100644
--- a/configuration/services/postgres.nix
+++ b/configuration/services/postgres.nix
@@ -1,4 +1,8 @@
-{pkgs, ...}: {
+{
+  config,
+  pkgs,
+  ...
+}: {
   services.postgresql = {
     package = pkgs.postgresql_14;
     enable = true;
@@ -24,11 +28,16 @@
         name = "nextcloud";
         ensureDBOwnership = true;
       }
+      {
+        name = config.services.authelia.instances.main.user;
+        ensureDBOwnership = true;
+      }
     ];
 
     ensureDatabases = [
       "grafana"
       "nextcloud"
+      config.services.authelia.instances.main.user
     ];
   };
 }
diff --git a/keys/production.yaml b/keys/production.yaml
index da90860..43b3578 100644
--- a/keys/production.yaml
+++ b/keys/production.yaml
@@ -1,4 +1,6 @@
-hetzner-api: ENC[AES256_GCM,data:OsUfo86AzcBe/OELkfB5brEfsZ4gkbeehxwIVUBwQgE=,iv:Bt/cjlZ6oZEVUOQjWMDL7/mfL3HWLFAw1tEGeLMgeKg=,tag:TMU2XiHlMgP4aes10mIQYQ==,type:str]
+authelia:
+    storageEncryptionKey: ENC[AES256_GCM,data:OUCC+6Gcr6U7Mub1+DaIyswTV6da1wd1u0WGEm4wpJ8L0mi7WSpEmVjH79YyRhp7AmiZhdFFDXFeEYthBb2AZl+xoS9gqs6rWyfU4ezaCbXBiS/dIhsA5foPg13wq5A33qJWtPTy7DJEgqHaIonnaBuVJIBwH3wzPTHc3bDvBo4=,iv:intiZzngz5cMTtjEI9rTKMW0Xv3KB3ZEgtYN3amwKCE=,tag:AKxfbeZlPs54esHCsVnNCg==,type:str]
+    sessionSecret: ENC[AES256_GCM,data:GEMWhBltOIOs0g9FsWk3OQGs6dMcbwz3ZuhlyBFYROylsIZb4xTXWLgNwIpHwQukQU3TgvIxbCW/fGRWiALPanE2koSVAHNx0UU0hj1mVNRFQGK4H3EL10tPp7l4PofrcdeCbLPrOwM/xLOuPt+52sKlcbL2Awz5/MmpUVpCKXc=,iv:kWX2ptOpTgW3obBgri0MvVv6gCEPR3o77sldOXFQeks=,tag:je4pqLcEOhuBTQkoZHYNCw==,type:str]
 battery-manager:
     email: ENC[AES256_GCM,data:rYLUACXR/n+bLBmZ,iv:sUBEkh2+7qGjHZ5R23e/hoCiyTA7GTL4bJvXmxjZ5Sw=,tag:fdPMllaQQfRgX0WZKIre4g==,type:str]
     password: ENC[AES256_GCM,data:7cokZa6Q6ahSeiFPz+cV,iv:vz405P0IcG9FsAQXlY7mi78GuushQUKJm2irG6buGzc=,tag:JLHG2jTkJDGbinAq9dXRsQ==,type:str]
@@ -32,8 +34,8 @@ sops:
     azure_kv: []
     hc_vault: []
     age: []
-    lastmodified: "2024-04-15T23:13:18Z"
-    mac: ENC[AES256_GCM,data:3/v+WgSWJ+VcBSBe1Wkis3z+tMmSjbKzLFqBB8xugc6DvgQG8J+1HRrPucLnpNNtEdmpyoTa72U6fPm6JnyUsuj5pLEghLprOJkqQNdRI06fllhw+9d3e3twx6D4oIIsVH6/io4ElXrGsGQTsfNbYhgn+987wa3WP5N25fBac3U=,iv:FL3tzPutOMN6IPkQfXIu/JOZT+OzUSqpMSQrUeXZQHE=,tag:jL1BTsYTA9XjrsjFszxZhA==,type:str]
+    lastmodified: "2024-04-11T23:38:56Z"
+    mac: ENC[AES256_GCM,data:GjIB0EbWsh4o+QoFSyIXgGYnNhRlvfSmue1LyTt6oUlIjNgODhdIB8px8LnRo0rmm/f1YHbDq2MFOxlgdm3PTNaqm/MoKyW3r/wuAeWADsYayQszLNxyhTMXcjWtfm6zCRIuc/+YyM44pXRfVrOZRAin9B6pmJZsRJwBAZpogbU=,iv:r/ZQZvrP0E9dOW5fhBH2I21Z0uv2e3njdEGmadxEALg=,tag:iZvbGTvRJFo80n8aoKSSmQ==,type:str]
     pgp:
         - created_at: "2024-03-18T04:02:00Z"
           enc: |-
diff --git a/keys/staging.yaml b/keys/staging.yaml
index 17e7875..ebdd628 100644
--- a/keys/staging.yaml
+++ b/keys/staging.yaml
@@ -1,4 +1,7 @@
-hetzner-api: ENC[AES256_GCM,data:1Zjp003j60g=,iv:+vDcyiqYm4A9CMIrW4oGZKdZiczatBcvfL4qYYhKwCg=,tag:Xeu8JuRm+b+5RO+wFR2M8w==,type:str]
+authelia:
+    storageEncryptionKey: ENC[AES256_GCM,data:8X6Zvq7ct1MkMH+lc5kTTHXOo6rGyhSzc3aWxGRA5tnBet+TGcENo0RYTYmactsPGVpTIUGGplaG7B7dqRPhkdDHhbCCZCm2nLaYjpVJ241DrpUNKHn8lvg/bMxUQ/Dvw76ByYuWN6bREr3XRaBztBSPzld8zTSYx71I0CKY7vk=,iv:cJSwfuVWO39qqKCGt2Mvw7pN8+hD6kRH9v4c/u4hLuk=,tag:YhdlXuX2ETxjb443RI8MsA==,type:str]
+    sessionSecret: ENC[AES256_GCM,data:dnoWmc4HND62w3jMXL+akncAEb61c/I70DgRytx55Wxcn4rMiswp6zCkRdsP4CkouTQ1lyAcQrubp5I8M9Kyow/KBMYz9dPkr4+2xJ9w0SEmAVhyPe2DFvYos3x0Uvx5S0B3o1mXoXqbg78e4w5yEIbALiJT8VPGrWK8Cl4nVPo=,iv:FHDXUW2DWUmEZzWUYkYduogdVOtvMlRH4/fVg05cZaI=,tag:u282WQnHpBsZGYJH7mFFKA==,type:str]
+    jwtSecret: ENC[AES256_GCM,data:0M3AyoMp+orrljl5NsxmthzrHMmu0REcz7+9fpFKbwwqV6KqlpgGddjYZIsTpHEWEq9zhZ2YWLJkMxKdDgROVHUFZGKut28JPSAjjY+1V0wxNBnfSCnxEv5BUw2+cCxcpCwYQyNfRK6SotTt8aqpxvda4oRXpzxV6SW7ogDjc6E=,iv:D57SynZkW2JuFyX6bpZYkxpR2KtkOmKaySg1Bxim0r8=,tag:JCPGZaumdHrtgcH16A7b+g==,type:str]
 battery-manager:
     email: ENC[AES256_GCM,data:LM/EGzWHfVQ=,iv:jFaoUQuUfuGoOyj/GFpdI8TerH/c8D9fjvio+IEt2Tc=,tag:IWLiN011JEnHRLIXWQgfmA==,type:str]
     password: ENC[AES256_GCM,data:SUxjqS7SJHM=,iv:LvdKk88S+nSImh6/ZezbFGLCUBu1Lpdu+neF2xyHdBg=,tag:rcMyZuW4FVNbcbz00wQKBg==,type:str]
@@ -32,8 +35,8 @@ sops:
     azure_kv: []
     hc_vault: []
     age: []
-    lastmodified: "2024-04-15T23:13:27Z"
-    mac: ENC[AES256_GCM,data:JhEVrKF2Jsqpdztcr3g5lMrgEFeLXfBRQTwQJ6PmLSNyDORcTU09TJPNWTPDnR5okDrvIU/wlzi5DZ8A0ebNhrKf6l0tNFBT9LSvQFHU5SBxqY/m8uEJKSrEC4IL5lugOOISDka2KSvYXVCXrumMHE5FnmOS/CgOZaZk6LUjPYA=,iv:ygygnSedcTo2Vsc56s2qrz1qkWchvSgvoiMTebRxQQ8=,tag:vf6z8rxsXmqzwpDy9Avifw==,type:str]
+    lastmodified: "2024-04-12T01:00:31Z"
+    mac: ENC[AES256_GCM,data:fVnMwfvGi7vtP1Fg4NLrhGvLF2PcIgZPOcwk4Ssm4iw5iSj0K1npOX3pd5BWzyszqchfYYRHY99GllAump0bZmprVAld9rf70B2HZIVvowBPuUXfc9Cz/5q0z+s8bQ5vCdElW1Bh7h8W/POePdc8cFGAyBS4i1ZVNheIDOHdDjI=,iv:Bi6rekXOx3/dwwPRryF3CoAoQi3D06ABysRF1oBeG5A=,tag:0TCra+AkhBDczj4uvAzKMw==,type:str]
     pgp:
         - created_at: "2023-12-29T15:25:27Z"
           enc: |
diff --git a/modules/nginxExtensions.nix b/modules/nginxExtensions.nix
index 9fe489a..8c19cc0 100644
--- a/modules/nginxExtensions.nix
+++ b/modules/nginxExtensions.nix
@@ -11,12 +11,72 @@
     };
 
     services.nginx.virtualHosts = let
+      autheliaDomain = "auth.${config.services.nginx.domain}";
+      extraLocationOptions = {config, ...}: {
+        options = {
+          enableAutheliaProxy = lib.mkEnableOption "Enable recommended authelia proxy settings";
+          enableAuthorization = lib.mkEnableOption "Enable authorization via authelia";
+        };
+
+        config = {
+          recommendedProxySettings = lib.mkIf config.enableAutheliaProxy false;
+
+          extraConfig = lib.concatStringsSep "\n" [
+            (lib.optionalString config.enableAutheliaProxy ''
+              proxy_set_header Host $host;
+              proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
+              proxy_set_header X-Forwarded-Proto $scheme;
+              proxy_set_header X-Forwarded-Host $http_host;
+              proxy_set_header X-Forwarded-URI $request_uri;
+              proxy_set_header X-Forwarded-Ssl on;
+              proxy_set_header X-Forwarded-For $remote_addr;
+              proxy_set_header X-Real-IP $remote_addr;
+              proxy_set_header Connection "";
+
+              client_body_buffer_size 128k;
+              proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
+              proxy_redirect http:// $scheme://;
+              proxy_http_version 1.1;
+              proxy_cache_bypass $cookie_session;
+              proxy_no_cache $cookie_session;
+              proxy_buffers 64 256k;
+
+              real_ip_header X-Forwarded-For;
+              real_ip_recursive on;
+
+              send_timeout 5m;
+              proxy_read_timeout 360;
+              proxy_send_timeout 360;
+              proxy_connect_timeout 360;
+            '')
+            (lib.optionalString config.enableAuthorization ''
+              auth_request /authelia;
+
+              set_escape_uri $target_url $scheme://$http_host$request_uri;
+
+              auth_request_set $user $upstream_http_remote_user;
+              auth_request_set $groups $upstream_http_remote_groups;
+              auth_request_set $name $upstream_http_remote_name;
+              auth_request_set $email $upstream_http_remote_email;
+
+              proxy_set_header Remote-User $user;
+              proxy_set_header Remote-Groups $groups;
+              proxy_set_header Remote-Email $email;
+              proxy_set_header Remote-Name $name;
+
+              error_page 401 =302 https://${autheliaDomain}/?rd=$target_url;
+            '')
+          ];
+        };
+      };
+
       extraVirtualHostOptions = {
         name,
         config,
         ...
       }: {
         options = {
+          enableAuthorization = lib.mkEnableOption "Enable authorization via authelia";
           enableHSTS = lib.mkEnableOption "Enable HSTS";
 
           addAccessLog = lib.mkOption {
@@ -26,6 +86,10 @@
               Add special logging to `/var/log/nginx/''${serverName}`
             '';
           };
+
+          locations = lib.mkOption {
+            type = lib.types.attrsOf (lib.types.submodule extraLocationOptions);
+          };
         };
 
         config = {
@@ -37,6 +101,41 @@
               access_log /var/log/nginx/${name}/access.log upstream_time;
             '')
           ];
+
+          locations = lib.mkIf config.enableAuthorization {
+            "/".enableAuthorization = true;
+            "/authelia" = {
+              proxyPass = "http://127.0.0.1:9091/api/verify";
+              recommendedProxySettings = false;
+              extraConfig = ''
+                internal;
+
+                proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
+                proxy_set_header X-Original-Method $request_method;
+                proxy_set_header X-Forwarded-Method $request_method;
+                proxy_set_header X-Forwarded-Proto $scheme;
+                proxy_set_header X-Forwarded-Host $http_host;
+                proxy_set_header X-Forwarded-Uri $request_uri;
+                proxy_set_header X-Forwarded-For $remote_addr;
+                proxy_set_header Content-Length "";
+                proxy_set_header Connection "";
+
+                proxy_pass_request_body off;
+                proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
+                proxy_redirect http:// $scheme://;
+                proxy_http_version 1.1;
+                proxy_cache_bypass $cookie_session;
+                proxy_no_cache $cookie_session;
+                proxy_buffers 4 32k;
+                client_body_buffer_size 128k;
+
+                send_timeout 5m;
+                proxy_read_timeout 240;
+                proxy_send_timeout 240;
+                proxy_connect_timeout 240;
+              '';
+            };
+          };
         };
       };
     in

From fd138d45e6a2cad89fead6e9f246ba282070d6b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 28 Jun 2024 20:12:55 +0200
Subject: [PATCH 02/67] treewide: Start using nixpkgs-fmt formatting

---
 configuration/default.nix                     |  29 +-
 .../hardware-specific/hetzner/default.nix     |   2 +-
 .../hardware-specific/hetzner/disko.nix       | 132 +++++-----
 configuration/hardware-specific/vm.nix        |   4 +-
 configuration/nginx.nix                       |  45 ++--
 configuration/services/afvalcalendar.nix      |  17 +-
 configuration/services/backups.nix            | 152 +++++------
 configuration/services/battery-manager.nix    |   7 +-
 configuration/services/conduit.nix            | 199 +++++++-------
 configuration/services/fail2ban.nix           |   6 +-
 configuration/services/foundryvtt.nix         |  43 +--
 configuration/services/gitea.nix              |  71 ++---
 configuration/services/metrics/exporters.nix  | 100 +++----
 configuration/services/metrics/grafana.nix    |   6 +-
 configuration/services/metrics/options.nix    | 249 +++++++++---------
 .../services/metrics/victoriametrics.nix      |   6 +-
 configuration/services/nextcloud.nix          |  15 +-
 configuration/services/postgres.nix           |   2 +-
 configuration/services/starbound.nix          |  19 +-
 configuration/services/webserver.nix          |  26 +-
 configuration/services/wireguard.nix          |   6 +-
 configuration/sops.nix                        |   8 +-
 flake.nix                                     | 240 ++++++++---------
 modules/nginxExtensions.nix                   |  84 +++---
 pkgs/afvalcalendar/default.nix                |   7 +-
 pkgs/default.nix                              |  37 +--
 pkgs/mkNextcloudApp.nix                       |   6 +-
 pkgs/prometheus/fail2ban-exporter.nix         |   6 +-
 pkgs/starbound/default.nix                    |  55 ++--
 29 files changed, 812 insertions(+), 767 deletions(-)

diff --git a/configuration/default.nix b/configuration/default.nix
index 3b580eb..b933d19 100644
--- a/configuration/default.nix
+++ b/configuration/default.nix
@@ -1,10 +1,9 @@
-{
-  config,
-  pkgs,
-  lib,
-  modulesPath,
-  flake-inputs,
-  ...
+{ config
+, pkgs
+, lib
+, modulesPath
+, flake-inputs
+, ...
 }: {
   imports = [
     flake-inputs.disko.nixosModules.disko
@@ -47,15 +46,15 @@
     '';
 
     # Enable remote builds from tlater
-    settings.trusted-users = ["@wheel"];
+    settings.trusted-users = [ "@wheel" ];
   };
 
   nixpkgs.config.allowUnfreePredicate = pkg:
-    builtins.elem (lib.getName pkg) ["steam-original" "steam-runtime" "steam-run" "steamcmd"];
+    builtins.elem (lib.getName pkg) [ "steam-original" "steam-runtime" "steam-run" "steamcmd" ];
 
   # Optimization for minecraft servers, see:
   # https://bugs.mojang.com/browse/MC-183518
-  boot.kernelParams = ["highres=off" "nohz=off"];
+  boot.kernelParams = [ "highres=off" "nohz=off" ];
 
   networking = {
     usePredictableInterfaceNames = false;
@@ -106,15 +105,15 @@
 
   users.users.tlater = {
     isNormalUser = true;
-    extraGroups = ["wheel"];
-    openssh.authorizedKeys.keyFiles = [../keys/tlater.pub];
+    extraGroups = [ "wheel" ];
+    openssh.authorizedKeys.keyFiles = [ ../keys/tlater.pub ];
   };
 
   services = {
     openssh = {
       enable = true;
       allowSFTP = false;
-      ports = [2222];
+      ports = [ 2222 ];
       startWhenNeeded = true;
 
       settings = {
@@ -133,14 +132,14 @@
     pam = {
       sshAgentAuth = {
         enable = true;
-        authorizedKeysFiles = ["/etc/ssh/authorized_keys.d/%u"];
+        authorizedKeysFiles = [ "/etc/ssh/authorized_keys.d/%u" ];
       };
       services.sudo.sshAgentAuth = true;
     };
   };
 
   # Remove some unneeded packages
-  environment.defaultPackages = [];
+  environment.defaultPackages = [ ];
 
   system.stateVersion = "20.09";
 }
diff --git a/configuration/hardware-specific/hetzner/default.nix b/configuration/hardware-specific/hetzner/default.nix
index 5ecf63a..3106f19 100644
--- a/configuration/hardware-specific/hetzner/default.nix
+++ b/configuration/hardware-specific/hetzner/default.nix
@@ -8,7 +8,7 @@
   # disables it by default.
   #
   # TODO(tlater): See if would be useful for anything?
-  boot.kernelParams = ["nosgx"];
+  boot.kernelParams = [ "nosgx" ];
 
   networking.hostName = "hetzner-1";
   services.nginx.domain = "tlater.net";
diff --git a/configuration/hardware-specific/hetzner/disko.nix b/configuration/hardware-specific/hetzner/disko.nix
index e404688..a2ea764 100644
--- a/configuration/hardware-specific/hetzner/disko.nix
+++ b/configuration/hardware-specific/hetzner/disko.nix
@@ -1,82 +1,84 @@
 {
-  disko.devices.disk = let
-    bootPartition = {
-      size = "1M";
-      type = "EF02";
-    };
-
-    swapPartition = {
-      # 8G is apparently recommended for this much RAM, but we set up
-      # 4G on both disks for mirroring purposes.
-      #
-      # That'll still be 8G during normal operation, and it's probably
-      # not too bad to have slightly less swap if a disk dies.
-      size = "4G";
-      content = {
-        type = "swap";
-        randomEncryption = true;
+  disko.devices.disk =
+    let
+      bootPartition = {
+        size = "1M";
+        type = "EF02";
       };
-    };
 
-    mountOptions = ["compress=zstd" "noatime"];
-  in {
-    sda = {
-      type = "disk";
-      device = "/dev/sda";
-      content = {
-        type = "gpt";
-        partitions = {
-          boot = bootPartition;
-          swap = swapPartition;
+      swapPartition = {
+        # 8G is apparently recommended for this much RAM, but we set up
+        # 4G on both disks for mirroring purposes.
+        #
+        # That'll still be 8G during normal operation, and it's probably
+        # not too bad to have slightly less swap if a disk dies.
+        size = "4G";
+        content = {
+          type = "swap";
+          randomEncryption = true;
+        };
+      };
 
-          disk1 = {
-            size = "100%";
-            # Empty partition to combine in RAID0 with the other disk
+      mountOptions = [ "compress=zstd" "noatime" ];
+    in
+    {
+      sda = {
+        type = "disk";
+        device = "/dev/sda";
+        content = {
+          type = "gpt";
+          partitions = {
+            boot = bootPartition;
+            swap = swapPartition;
+
+            disk1 = {
+              size = "100%";
+              # Empty partition to combine in RAID0 with the other disk
+            };
           };
         };
       };
-    };
 
-    sdb = {
-      type = "disk";
-      device = "/dev/sdb";
-      content = {
-        type = "gpt";
-        partitions = {
-          boot = bootPartition;
-          swap = swapPartition;
+      sdb = {
+        type = "disk";
+        device = "/dev/sdb";
+        content = {
+          type = "gpt";
+          partitions = {
+            boot = bootPartition;
+            swap = swapPartition;
 
-          disk2 = {
-            size = "100%";
-            content = {
-              type = "btrfs";
-              # Hack to get multi-device btrfs going
-              # See https://github.com/nix-community/disko/issues/99
-              extraArgs = ["-d" "raid1" "-m" "raid1" "--runtime-features" "quota" "/dev/sda3"];
-              subvolumes = {
-                "/volume" = {};
-                "/volume/root" = {
-                  inherit mountOptions;
-                  mountpoint = "/";
+            disk2 = {
+              size = "100%";
+              content = {
+                type = "btrfs";
+                # Hack to get multi-device btrfs going
+                # See https://github.com/nix-community/disko/issues/99
+                extraArgs = [ "-d" "raid1" "-m" "raid1" "--runtime-features" "quota" "/dev/sda3" ];
+                subvolumes = {
+                  "/volume" = { };
+                  "/volume/root" = {
+                    inherit mountOptions;
+                    mountpoint = "/";
+                  };
+                  "/volume/home" = {
+                    inherit mountOptions;
+                    mountpoint = "/home";
+                  };
+                  "/volume/var" = {
+                    inherit mountOptions;
+                    mountpoint = "/var";
+                  };
+                  "/volume/nix-store" = {
+                    inherit mountOptions;
+                    mountpoint = "/nix";
+                  };
+                  "/snapshots" = { };
                 };
-                "/volume/home" = {
-                  inherit mountOptions;
-                  mountpoint = "/home";
-                };
-                "/volume/var" = {
-                  inherit mountOptions;
-                  mountpoint = "/var";
-                };
-                "/volume/nix-store" = {
-                  inherit mountOptions;
-                  mountpoint = "/nix";
-                };
-                "/snapshots" = {};
               };
             };
           };
         };
       };
     };
-  };
 }
diff --git a/configuration/hardware-specific/vm.nix b/configuration/hardware-specific/vm.nix
index 7f1fcf1..86fcaed 100644
--- a/configuration/hardware-specific/vm.nix
+++ b/configuration/hardware-specific/vm.nix
@@ -1,8 +1,8 @@
-{lib, ...}: {
+{ lib, ... }: {
   users.users.tlater.password = "insecure";
 
   # Disable graphical tty so -curses works
-  boot.kernelParams = ["nomodeset"];
+  boot.kernelParams = [ "nomodeset" ];
 
   networking.hostName = "testvm";
   # Sets the base domain for nginx to a local domain so that we can
diff --git a/configuration/nginx.nix b/configuration/nginx.nix
index 82baab0..d696bba 100644
--- a/configuration/nginx.nix
+++ b/configuration/nginx.nix
@@ -1,7 +1,6 @@
-{
-  config,
-  lib,
-  ...
+{ config
+, lib
+, ...
 }: {
   services.nginx = {
     enable = true;
@@ -27,31 +26,33 @@
       # Override the default, just keep fewer logs
       nginx.rotate = 6;
     }
-    // lib.mapAttrs' (virtualHost: _:
-      lib.nameValuePair "/var/log/nginx/${virtualHost}/access.log" {
-        frequency = "daily";
-        rotate = 2;
-        compress = true;
-        delaycompress = true;
-        su = "${config.services.nginx.user} ${config.services.nginx.group}";
-        postrotate = "[ ! -f /var/run/nginx/nginx.pid ] || kill -USR1 `cat /var/run/nginx/nginx.pid`";
-      })
-    config.services.nginx.virtualHosts;
+    // lib.mapAttrs'
+      (virtualHost: _:
+        lib.nameValuePair "/var/log/nginx/${virtualHost}/access.log" {
+          frequency = "daily";
+          rotate = 2;
+          compress = true;
+          delaycompress = true;
+          su = "${config.services.nginx.user} ${config.services.nginx.group}";
+          postrotate = "[ ! -f /var/run/nginx/nginx.pid ] || kill -USR1 `cat /var/run/nginx/nginx.pid`";
+        })
+      config.services.nginx.virtualHosts;
 
   systemd.tmpfiles.rules =
-    lib.mapAttrsToList (
-      virtualHost: _:
-      #
-      "d /var/log/nginx/${virtualHost} 0750 ${config.services.nginx.user} ${config.services.nginx.group}"
-    )
-    config.services.nginx.virtualHosts;
+    lib.mapAttrsToList
+      (
+        virtualHost: _:
+          #
+          "d /var/log/nginx/${virtualHost} 0750 ${config.services.nginx.user} ${config.services.nginx.group}"
+      )
+      config.services.nginx.virtualHosts;
 
   security.acme = {
     defaults.email = "tm@tlater.net";
     acceptTerms = true;
 
     certs."tlater.net" = {
-      extraDomainNames = ["*.tlater.net"];
+      extraDomainNames = [ "*.tlater.net" ];
       dnsProvider = "hetzner";
       group = "nginx";
       credentialFiles."HETZNER_API_KEY_FILE" = config.sops.secrets."hetzner-api".path;
@@ -62,6 +63,6 @@
     user = "acme";
     paths =
       lib.mapAttrsToList (virtualHost: _: "/var/lib/acme/${virtualHost}")
-      config.services.nginx.virtualHosts;
+        config.services.nginx.virtualHosts;
   };
 }
diff --git a/configuration/services/afvalcalendar.nix b/configuration/services/afvalcalendar.nix
index e27ba62..28e3a75 100644
--- a/configuration/services/afvalcalendar.nix
+++ b/configuration/services/afvalcalendar.nix
@@ -1,12 +1,11 @@
-{
-  pkgs,
-  config,
-  ...
+{ pkgs
+, config
+, ...
 }: {
   systemd.services.afvalcalendar = {
     description = "Enschede afvalcalendar -> ical converter";
-    wantedBy = ["multi-user.target"];
-    after = ["network.target"];
+    wantedBy = [ "multi-user.target" ];
+    after = [ "network.target" ];
 
     script = ''
       ${pkgs.local.afvalcalendar}/bin/afvalcalendar > /srv/afvalcalendar/afvalcalendar.ical
@@ -26,14 +25,14 @@
       ProtectKernelModules = true;
       ProtectKernelLogs = true;
       ProtectControlGroups = true;
-      RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"];
+      RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
       RestrictNamespaces = true;
       LockPersonality = true;
       MemoryDenyWriteExecute = true;
       RestrictRealtime = true;
       RestrictSUIDSGID = true;
       SystemCallArchitectures = "native";
-      SystemCallFilter = ["@system-service" "~@privileged @resources @setuid @keyring"];
+      SystemCallFilter = [ "@system-service" "~@privileged @resources @setuid @keyring" ];
 
       Umask = 0002;
       SupplementaryGroups = "afvalcalendar-hosting";
@@ -50,7 +49,7 @@
     root = "/srv/afvalcalendar";
   };
 
-  users.groups.afvalcalendar-hosting = {};
+  users.groups.afvalcalendar-hosting = { };
   systemd.tmpfiles.settings."10-afvalcalendar" = {
     "/srv/afvalcalendar".d = {
       user = "nginx";
diff --git a/configuration/services/backups.nix b/configuration/services/backups.nix
index 98aa473..7c77399 100644
--- a/configuration/services/backups.nix
+++ b/configuration/services/backups.nix
@@ -1,9 +1,9 @@
-{
-  config,
-  pkgs,
-  lib,
-  ...
-}: let
+{ config
+, pkgs
+, lib
+, ...
+}:
+let
   inherit (lib) types optional singleton;
   mkShutdownScript = service:
     pkgs.writeShellScript "backup-${service}-shutdown" ''
@@ -42,17 +42,17 @@
     RESTIC_REPOSITORY = "rclone:storagebox:backups";
     RCLONE_CONFIG = rcloneConfig;
   };
-in {
+in
+{
   options = {
     services.backups = lib.mkOption {
       description = lib.mdDoc ''
         Configure restic backups with a specific tag.
       '';
-      type = types.attrsOf (types.submodule ({
-        config,
-        name,
-        ...
-      }: {
+      type = types.attrsOf (types.submodule ({ config
+                                             , name
+                                             , ...
+                                             }: {
         options = {
           user = lib.mkOption {
             type = types.str;
@@ -76,7 +76,7 @@ in {
           preparation = {
             packages = lib.mkOption {
               type = types.listOf types.package;
-              default = [];
+              default = [ ];
               description = ''
                 The list of packages to make available in the
                 preparation script.
@@ -97,7 +97,7 @@ in {
           cleanup = {
             packages = lib.mkOption {
               type = types.listOf types.package;
-              default = [];
+              default = [ ];
               description = ''
                 The list of packages to make available in the
                 cleanup script.
@@ -116,7 +116,7 @@ in {
           };
           pauseServices = lib.mkOption {
             type = types.listOf types.str;
-            default = [];
+            default = [ ];
             description = ''
               The systemd services that need to be shut down before
               the backup can run. Services will be restarted after the
@@ -131,7 +131,7 @@ in {
     };
   };
 
-  config = lib.mkIf (config.services.backups != {}) {
+  config = lib.mkIf (config.services.backups != { }) {
     systemd.services =
       {
         restic-prune = {
@@ -164,79 +164,81 @@ in {
           };
         };
       }
-      // lib.mapAttrs' (name: backup:
-        lib.nameValuePair "backup-${name}" {
-          # Don't want to restart mid-backup
-          restartIfChanged = false;
+      // lib.mapAttrs'
+        (name: backup:
+          lib.nameValuePair "backup-${name}" {
+            # Don't want to restart mid-backup
+            restartIfChanged = false;
 
-          environment =
-            resticEnv
-            // {
-              RESTIC_CACHE_DIR = "%C/backup-${name}";
-            };
+            environment =
+              resticEnv
+              // {
+                RESTIC_CACHE_DIR = "%C/backup-${name}";
+              };
 
-          path = with pkgs; [
-            coreutils
-            openssh
-            rclone
-            restic
-          ];
-
-          # TODO(tlater): If I ever add more than one repo, service
-          # shutdown/restarting will potentially break if multiple
-          # backups for the same service overlap. A more clever
-          # sentinel file with reference counts would probably solve
-          # this.
-          serviceConfig = {
-            User = backup.user;
-            Group = "backup";
-            RuntimeDirectory = "backup-${name}";
-            CacheDirectory = "backup-${name}";
-            CacheDirectoryMode = "0700";
-            PrivateTmp = true;
-
-            ExecStart = [
-              (lib.concatStringsSep " " (["${pkgs.restic}/bin/restic" "backup" "--tag" name] ++ backup.paths))
+            path = with pkgs; [
+              coreutils
+              openssh
+              rclone
+              restic
             ];
 
-            ExecStartPre =
-              map (service: "+${mkShutdownScript service}") backup.pauseServices
-              ++ singleton (writeScript "backup-${name}-repo-init" [] ''
-                restic snapshots || restic init
-              '')
-              ++ optional (backup.preparation.text != null)
-              (writeScript "backup-${name}-prepare" backup.preparation.packages backup.preparation.text);
+            # TODO(tlater): If I ever add more than one repo, service
+            # shutdown/restarting will potentially break if multiple
+            # backups for the same service overlap. A more clever
+            # sentinel file with reference counts would probably solve
+            # this.
+            serviceConfig = {
+              User = backup.user;
+              Group = "backup";
+              RuntimeDirectory = "backup-${name}";
+              CacheDirectory = "backup-${name}";
+              CacheDirectoryMode = "0700";
+              PrivateTmp = true;
 
-            # TODO(tlater): Add repo pruning/checking
-            ExecStopPost =
-              map (service: "+${mkRestartScript service}") backup.pauseServices
-              ++ optional (backup.cleanup.text != null)
-              (writeScript "backup-${name}-cleanup" backup.cleanup.packages backup.cleanup.text);
-          };
-        })
-      config.services.backups;
+              ExecStart = [
+                (lib.concatStringsSep " " ([ "${pkgs.restic}/bin/restic" "backup" "--tag" name ] ++ backup.paths))
+              ];
+
+              ExecStartPre =
+                map (service: "+${mkShutdownScript service}") backup.pauseServices
+                ++ singleton (writeScript "backup-${name}-repo-init" [ ] ''
+                  restic snapshots || restic init
+                '')
+                ++ optional (backup.preparation.text != null)
+                  (writeScript "backup-${name}-prepare" backup.preparation.packages backup.preparation.text);
+
+              # TODO(tlater): Add repo pruning/checking
+              ExecStopPost =
+                map (service: "+${mkRestartScript service}") backup.pauseServices
+                ++ optional (backup.cleanup.text != null)
+                  (writeScript "backup-${name}-cleanup" backup.cleanup.packages backup.cleanup.text);
+            };
+          })
+        config.services.backups;
 
     systemd.timers =
       {
         restic-prune = {
-          wantedBy = ["timers.target"];
+          wantedBy = [ "timers.target" ];
           timerConfig.OnCalendar = "Thursday 03:00:00 UTC";
           # Don't make this persistent, in case the server was offline
           # for a while. This job cannot run at the same time as any
           # of the backup jobs.
         };
       }
-      // lib.mapAttrs' (name: backup:
-        lib.nameValuePair "backup-${name}" {
-          wantedBy = ["timers.target"];
-          timerConfig = {
-            OnCalendar = "Wednesday 02:30:00 UTC";
-            RandomizedDelaySec = "1h";
-            FixedRandomDelay = true;
-            Persistent = true;
-          };
-        })
-      config.services.backups;
+      // lib.mapAttrs'
+        (name: backup:
+          lib.nameValuePair "backup-${name}" {
+            wantedBy = [ "timers.target" ];
+            timerConfig = {
+              OnCalendar = "Wednesday 02:30:00 UTC";
+              RandomizedDelaySec = "1h";
+              FixedRandomDelay = true;
+              Persistent = true;
+            };
+          })
+        config.services.backups;
 
     users = {
       # This user is only used to own the ssh key, because apparently
@@ -245,7 +247,7 @@ in {
         group = "backup";
         isSystemUser = true;
       };
-      groups.backup = {};
+      groups.backup = { };
     };
   };
 }
diff --git a/configuration/services/battery-manager.nix b/configuration/services/battery-manager.nix
index 7f27931..7783a3b 100644
--- a/configuration/services/battery-manager.nix
+++ b/configuration/services/battery-manager.nix
@@ -1,7 +1,6 @@
-{
-  config,
-  flake-inputs,
-  ...
+{ config
+, flake-inputs
+, ...
 }: {
   imports = [
     flake-inputs.sonnenshift.nixosModules.default
diff --git a/configuration/services/conduit.nix b/configuration/services/conduit.nix
index 2462d9b..950165c 100644
--- a/configuration/services/conduit.nix
+++ b/configuration/services/conduit.nix
@@ -1,15 +1,16 @@
-{
-  pkgs,
-  config,
-  lib,
-  ...
-}: let
+{ pkgs
+, config
+, lib
+, ...
+}:
+let
   inherit (lib.strings) concatMapStringsSep;
 
   cfg = config.services.matrix-conduit;
   domain = "matrix.${config.services.nginx.domain}";
   turn-realm = "turn.${config.services.nginx.domain}";
-in {
+in
+{
   services.matrix-conduit = {
     enable = true;
     settings.global = {
@@ -17,99 +18,103 @@ in {
       server_name = domain;
       database_backend = "rocksdb";
 
-      turn_uris = let
-        address = "${config.services.coturn.realm}:${toString config.services.coturn.listening-port}";
-        tls-address = "${config.services.coturn.realm}:${toString config.services.coturn.tls-listening-port}";
-      in [
-        "turn:${address}?transport=udp"
-        "turn:${address}?transport=tcp"
-        "turns:${tls-address}?transport=udp"
-        "turns:${tls-address}?transport=tcp"
-      ];
-    };
-  };
-
-  systemd.services.heisenbridge = let
-    replaceSecretBin = "${pkgs.replace-secret}/bin/replace-secret";
-    registrationFile = builtins.toFile "heisenbridge-registration.yaml" (builtins.toJSON {
-      id = "heisenbridge";
-      url = "http://127.0.0.1:9898";
-      as_token = "@AS_TOKEN@";
-      hs_token = "@HS_TOKEN@";
-      rate_limited = false;
-      sender_localpart = "heisenbridge";
-      namespaces = {
-        users = [
-          {
-            regex = "@irc_.*";
-            exclusive = true;
-          }
-          {
-            regex = "@heisenbridge:.*";
-            exclusive = true;
-          }
+      turn_uris =
+        let
+          address = "${config.services.coturn.realm}:${toString config.services.coturn.listening-port}";
+          tls-address = "${config.services.coturn.realm}:${toString config.services.coturn.tls-listening-port}";
+        in
+        [
+          "turn:${address}?transport=udp"
+          "turn:${address}?transport=tcp"
+          "turns:${tls-address}?transport=udp"
+          "turns:${tls-address}?transport=tcp"
         ];
-        aliases = [];
-        rooms = [];
-      };
-    });
-
-    # TODO(tlater): Starting with systemd 253 it will become possible
-    # to do the credential setup as part of ExecStartPre/preStart
-    # instead.
-    #
-    # This will also make it possible to actually set caps on the
-    # heisenbridge process using systemd, so that we can run the
-    # identd process.
-    execScript = pkgs.writeShellScript "heisenbridge" ''
-      cp ${registrationFile} "$RUNTIME_DIRECTORY/heisenbridge-registration.yaml"
-      chmod 600 $RUNTIME_DIRECTORY/heisenbridge-registration.yaml
-      ${replaceSecretBin} '@AS_TOKEN@' "$CREDENTIALS_DIRECTORY/heisenbridge_as-token" "$RUNTIME_DIRECTORY/heisenbridge-registration.yaml"
-      ${replaceSecretBin} '@HS_TOKEN@' "$CREDENTIALS_DIRECTORY/heisenbridge_hs-token" "$RUNTIME_DIRECTORY/heisenbridge-registration.yaml"
-      chmod 400 $RUNTIME_DIRECTORY/heisenbridge-registration.yaml
-
-      ${pkgs.heisenbridge}/bin/heisenbridge \
-          --config $RUNTIME_DIRECTORY/heisenbridge-registration.yaml \
-          --owner @tlater:matrix.tlater.net \
-          'http://localhost:${toString cfg.settings.global.port}'
-    '';
-  in {
-    description = "Matrix<->IRC bridge";
-    wantedBy = ["multi-user.target"];
-    after = ["conduit.service"];
-
-    serviceConfig = {
-      Type = "simple";
-
-      LoadCredential = "heisenbridge:/run/secrets/heisenbridge";
-
-      ExecStart = execScript;
-
-      DynamicUser = true;
-      RuntimeDirectory = "heisenbridge";
-      RuntimeDirectoryMode = "0700";
-
-      RestrictNamespaces = true;
-      PrivateUsers = true;
-      ProtectHostname = true;
-      ProtectClock = true;
-      ProtectKernelTunables = true;
-      ProtectKernelModules = true;
-      ProtectKernelLogs = true;
-      ProtectControlGroups = true;
-      RestrictAddressFamilies = ["AF_INET AF_INET6"];
-      LockPersonality = true;
-      RestrictRealtime = true;
-      ProtectProc = "invisible";
-      ProcSubset = "pid";
-      UMask = 0077;
-
-      # For the identd port
-      # CapabilityBoundingSet = ["CAP_NET_BIND_SERVICE"];
-      # AmbientCapabilities = ["CAP_NET_BIND_SERVICE"];
     };
   };
 
+  systemd.services.heisenbridge =
+    let
+      replaceSecretBin = "${pkgs.replace-secret}/bin/replace-secret";
+      registrationFile = builtins.toFile "heisenbridge-registration.yaml" (builtins.toJSON {
+        id = "heisenbridge";
+        url = "http://127.0.0.1:9898";
+        as_token = "@AS_TOKEN@";
+        hs_token = "@HS_TOKEN@";
+        rate_limited = false;
+        sender_localpart = "heisenbridge";
+        namespaces = {
+          users = [
+            {
+              regex = "@irc_.*";
+              exclusive = true;
+            }
+            {
+              regex = "@heisenbridge:.*";
+              exclusive = true;
+            }
+          ];
+          aliases = [ ];
+          rooms = [ ];
+        };
+      });
+
+      # TODO(tlater): Starting with systemd 253 it will become possible
+      # to do the credential setup as part of ExecStartPre/preStart
+      # instead.
+      #
+      # This will also make it possible to actually set caps on the
+      # heisenbridge process using systemd, so that we can run the
+      # identd process.
+      execScript = pkgs.writeShellScript "heisenbridge" ''
+        cp ${registrationFile} "$RUNTIME_DIRECTORY/heisenbridge-registration.yaml"
+        chmod 600 $RUNTIME_DIRECTORY/heisenbridge-registration.yaml
+        ${replaceSecretBin} '@AS_TOKEN@' "$CREDENTIALS_DIRECTORY/heisenbridge_as-token" "$RUNTIME_DIRECTORY/heisenbridge-registration.yaml"
+        ${replaceSecretBin} '@HS_TOKEN@' "$CREDENTIALS_DIRECTORY/heisenbridge_hs-token" "$RUNTIME_DIRECTORY/heisenbridge-registration.yaml"
+        chmod 400 $RUNTIME_DIRECTORY/heisenbridge-registration.yaml
+
+        ${pkgs.heisenbridge}/bin/heisenbridge \
+            --config $RUNTIME_DIRECTORY/heisenbridge-registration.yaml \
+            --owner @tlater:matrix.tlater.net \
+            'http://localhost:${toString cfg.settings.global.port}'
+      '';
+    in
+    {
+      description = "Matrix<->IRC bridge";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "conduit.service" ];
+
+      serviceConfig = {
+        Type = "simple";
+
+        LoadCredential = "heisenbridge:/run/secrets/heisenbridge";
+
+        ExecStart = execScript;
+
+        DynamicUser = true;
+        RuntimeDirectory = "heisenbridge";
+        RuntimeDirectoryMode = "0700";
+
+        RestrictNamespaces = true;
+        PrivateUsers = true;
+        ProtectHostname = true;
+        ProtectClock = true;
+        ProtectKernelTunables = true;
+        ProtectKernelModules = true;
+        ProtectKernelLogs = true;
+        ProtectControlGroups = true;
+        RestrictAddressFamilies = [ "AF_INET AF_INET6" ];
+        LockPersonality = true;
+        RestrictRealtime = true;
+        ProtectProc = "invisible";
+        ProcSubset = "pid";
+        UMask = 0077;
+
+        # For the identd port
+        # CapabilityBoundingSet = ["CAP_NET_BIND_SERVICE"];
+        # AmbientCapabilities = ["CAP_NET_BIND_SERVICE"];
+      };
+    };
+
   # Pass in the TURN secret via EnvironmentFile, not supported by
   # upstream module currently.
   #
@@ -249,6 +254,6 @@ in {
     ];
     # Other services store their data in conduit, so no other services
     # need to be shut down currently.
-    pauseServices = ["conduit.service"];
+    pauseServices = [ "conduit.service" ];
   };
 }
diff --git a/configuration/services/fail2ban.nix b/configuration/services/fail2ban.nix
index ace3219..1811046 100644
--- a/configuration/services/fail2ban.nix
+++ b/configuration/services/fail2ban.nix
@@ -1,7 +1,7 @@
-{pkgs, ...}: {
+{ pkgs, ... }: {
   services.fail2ban = {
     enable = true;
-    extraPackages = [pkgs.ipset];
+    extraPackages = [ pkgs.ipset ];
     banaction = "iptables-ipset-proto6-allports";
     bantime-increment.enable = true;
 
@@ -21,7 +21,7 @@
   };
 
   # Allow metrics services to connect to the socket as well
-  users.groups.fail2ban = {};
+  users.groups.fail2ban = { };
   systemd.services.fail2ban.serviceConfig = {
     ExecStartPost =
       "+"
diff --git a/configuration/services/foundryvtt.nix b/configuration/services/foundryvtt.nix
index ac206fc..e69d2dd 100644
--- a/configuration/services/foundryvtt.nix
+++ b/configuration/services/foundryvtt.nix
@@ -1,12 +1,13 @@
-{
-  lib,
-  config,
-  flake-inputs,
-  ...
-}: let
+{ lib
+, config
+, flake-inputs
+, ...
+}:
+let
   domain = "foundryvtt.${config.services.nginx.domain}";
-in {
-  imports = [flake-inputs.foundryvtt.nixosModules.foundryvtt];
+in
+{
+  imports = [ flake-inputs.foundryvtt.nixosModules.foundryvtt ];
 
   services.foundryvtt = {
     enable = true;
@@ -18,26 +19,28 @@ in {
 
   # Want to start it manually when I need it, not have it constantly
   # running
-  systemd.services.foundryvtt.wantedBy = lib.mkForce [];
+  systemd.services.foundryvtt.wantedBy = lib.mkForce [ ];
 
-  services.nginx.virtualHosts."${domain}" = let
-    inherit (config.services.foundryvtt) port;
-  in {
-    forceSSL = true;
-    useACMEHost = "tlater.net";
-    enableHSTS = true;
+  services.nginx.virtualHosts."${domain}" =
+    let
+      inherit (config.services.foundryvtt) port;
+    in
+    {
+      forceSSL = true;
+      useACMEHost = "tlater.net";
+      enableHSTS = true;
 
-    locations."/" = {
-      proxyWebsockets = true;
-      proxyPass = "http://localhost:${toString port}";
+      locations."/" = {
+        proxyWebsockets = true;
+        proxyPass = "http://localhost:${toString port}";
+      };
     };
-  };
 
   services.backups.foundryvtt = {
     user = "foundryvtt";
     paths = [
       config.services.foundryvtt.dataDir
     ];
-    pauseServices = ["foundryvtt.service"];
+    pauseServices = [ "foundryvtt.service" ];
   };
 }
diff --git a/configuration/services/gitea.nix b/configuration/services/gitea.nix
index 26fe2f8..4ef6238 100644
--- a/configuration/services/gitea.nix
+++ b/configuration/services/gitea.nix
@@ -1,11 +1,12 @@
-{
-  pkgs,
-  config,
-  lib,
-  ...
-}: let
+{ pkgs
+, config
+, lib
+, ...
+}:
+let
   domain = "gitea.${config.services.nginx.domain}";
-in {
+in
+{
   services.forgejo = {
     enable = true;
     database.type = "postgres";
@@ -27,33 +28,37 @@ in {
     };
   };
 
-  systemd.services.forgejo.serviceConfig.ExecStartPre = let
-    replaceSecretBin = "${pkgs.replace-secret}/bin/replace-secret";
-    secretPath = config.sops.secrets."forgejo/metrics-token".path;
-    runConfig = "${config.services.forgejo.customDir}/conf/app.ini";
-  in [
-    "+${replaceSecretBin} '#metricstoken#' '${secretPath}' '${runConfig}'"
-  ];
+  systemd.services.forgejo.serviceConfig.ExecStartPre =
+    let
+      replaceSecretBin = "${pkgs.replace-secret}/bin/replace-secret";
+      secretPath = config.sops.secrets."forgejo/metrics-token".path;
+      runConfig = "${config.services.forgejo.customDir}/conf/app.ini";
+    in
+    [
+      "+${replaceSecretBin} '#metricstoken#' '${secretPath}' '${runConfig}'"
+    ];
 
   # Set up SSL
-  services.nginx.virtualHosts."${domain}" = let
-    httpAddress = config.services.forgejo.settings.server.HTTP_ADDR;
-    httpPort = config.services.forgejo.settings.server.HTTP_PORT;
-  in {
-    forceSSL = true;
-    useACMEHost = "tlater.net";
-    enableHSTS = true;
+  services.nginx.virtualHosts."${domain}" =
+    let
+      httpAddress = config.services.forgejo.settings.server.HTTP_ADDR;
+      httpPort = config.services.forgejo.settings.server.HTTP_PORT;
+    in
+    {
+      forceSSL = true;
+      useACMEHost = "tlater.net";
+      enableHSTS = true;
 
-    locations."/".proxyPass = "http://${httpAddress}:${toString httpPort}";
-    locations."/metrics" = {
-      extraConfig = ''
-        access_log off;
-        allow 127.0.0.1;
-        ${lib.optionalString config.networking.enableIPv6 "allow ::1;"}
-        deny all;
-      '';
+      locations."/".proxyPass = "http://${httpAddress}:${toString httpPort}";
+      locations."/metrics" = {
+        extraConfig = ''
+          access_log off;
+          allow 127.0.0.1;
+          ${lib.optionalString config.networking.enableIPv6 "allow ::1;"}
+          deny all;
+        '';
+      };
     };
-  };
 
   # Block repeated failed login attempts
   #
@@ -83,13 +88,13 @@ in {
       # Conf is backed up via nix
     ];
     preparation = {
-      packages = [config.services.postgresql.package];
+      packages = [ config.services.postgresql.package ];
       text = "pg_dump ${config.services.forgejo.database.name} --file=/var/lib/forgejo/forgejo-db.sql";
     };
     cleanup = {
-      packages = [pkgs.coreutils];
+      packages = [ pkgs.coreutils ];
       text = "rm /var/lib/forgejo/forgejo-db.sql";
     };
-    pauseServices = ["forgejo.service"];
+    pauseServices = [ "forgejo.service" ];
   };
 }
diff --git a/configuration/services/metrics/exporters.nix b/configuration/services/metrics/exporters.nix
index f3054db..e17be8e 100644
--- a/configuration/services/metrics/exporters.nix
+++ b/configuration/services/metrics/exporters.nix
@@ -1,25 +1,28 @@
+{ config
+, pkgs
+, lib
+, ...
+}:
+let
+  yaml = pkgs.formats.yaml { };
+in
 {
-  config,
-  pkgs,
-  lib,
-  ...
-}: let
-  yaml = pkgs.formats.yaml {};
-in {
   services.prometheus = {
     exporters = {
       # Periodically check domain registration status
       domain = {
         enable = true;
         listenAddress = "127.0.0.1";
-        extraFlags = let
-          conf.domains = [
-            "tlater.net"
-            "tlater.com"
+        extraFlags =
+          let
+            conf.domains = [
+              "tlater.net"
+              "tlater.com"
+            ];
+          in
+          [
+            "--config=${yaml.generate "domains.yml" conf}"
           ];
-        in [
-          "--config=${yaml.generate "domains.yml" conf}"
-        ];
       };
 
       # System statistics
@@ -49,47 +52,50 @@ in {
         group = "nginx";
 
         settings.namespaces =
-          lib.mapAttrsToList (name: virtualHost: {
-            inherit name;
-            metrics_override.prefix = "nginxlog";
-            namespace_label = "vhost";
+          lib.mapAttrsToList
+            (name: virtualHost: {
+              inherit name;
+              metrics_override.prefix = "nginxlog";
+              namespace_label = "vhost";
 
-            format = lib.concatStringsSep " " [
-              "$remote_addr - $remote_user [$time_local]"
-              ''"$request" $status $body_bytes_sent''
-              ''"$http_referer" "$http_user_agent"''
-              ''rt=$request_time uct="$upstream_connect_time"''
-              ''uht="$upstream_header_time" urt="$upstream_response_time"''
-            ];
+              format = lib.concatStringsSep " " [
+                "$remote_addr - $remote_user [$time_local]"
+                ''"$request" $status $body_bytes_sent''
+                ''"$http_referer" "$http_user_agent"''
+                ''rt=$request_time uct="$upstream_connect_time"''
+                ''uht="$upstream_header_time" urt="$upstream_response_time"''
+              ];
 
-            source.files = [
-              "/var/log/nginx/${name}/access.log"
-            ];
-          })
-          config.services.nginx.virtualHosts;
+              source.files = [
+                "/var/log/nginx/${name}/access.log"
+              ];
+            })
+            config.services.nginx.virtualHosts;
       };
     };
 
     extraExporters = {
-      fail2ban = let
-        cfg = config.services.prometheus.extraExporters.fail2ban;
-      in {
-        port = 9191;
-        serviceOpts = {
-          after = ["fail2ban.service"];
-          requires = ["fail2ban.service"];
-          serviceConfig = {
-            Group = "fail2ban";
-            RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"];
-            ExecStart = lib.concatStringsSep " " [
-              "${pkgs.local.prometheus-fail2ban-exporter}/bin/fail2ban-prometheus-exporter"
-              "--collector.f2b.socket=/var/run/fail2ban/fail2ban.sock"
-              "--web.listen-address='${cfg.listenAddress}:${toString cfg.port}'"
-              "--collector.f2b.exit-on-socket-connection-error=true"
-            ];
+      fail2ban =
+        let
+          cfg = config.services.prometheus.extraExporters.fail2ban;
+        in
+        {
+          port = 9191;
+          serviceOpts = {
+            after = [ "fail2ban.service" ];
+            requires = [ "fail2ban.service" ];
+            serviceConfig = {
+              Group = "fail2ban";
+              RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
+              ExecStart = lib.concatStringsSep " " [
+                "${pkgs.local.prometheus-fail2ban-exporter}/bin/fail2ban-prometheus-exporter"
+                "--collector.f2b.socket=/var/run/fail2ban/fail2ban.sock"
+                "--web.listen-address='${cfg.listenAddress}:${toString cfg.port}'"
+                "--collector.f2b.exit-on-socket-connection-error=true"
+              ];
+            };
           };
         };
-      };
     };
 
     # TODO(tlater):
diff --git a/configuration/services/metrics/grafana.nix b/configuration/services/metrics/grafana.nix
index eb5106e..d13fe7b 100644
--- a/configuration/services/metrics/grafana.nix
+++ b/configuration/services/metrics/grafana.nix
@@ -1,6 +1,8 @@
-{config, ...}: let
+{ config, ... }:
+let
   domain = "metrics.${config.services.nginx.domain}";
-in {
+in
+{
   services.grafana = {
     enable = true;
     settings = {
diff --git a/configuration/services/metrics/options.nix b/configuration/services/metrics/options.nix
index 81f0865..552aec8 100644
--- a/configuration/services/metrics/options.nix
+++ b/configuration/services/metrics/options.nix
@@ -1,12 +1,13 @@
-{
-  pkgs,
-  config,
-  lib,
-  ...
-}: let
+{ pkgs
+, config
+, lib
+, ...
+}:
+let
   inherit (lib) types mkOption mkDefault;
-  yaml = pkgs.formats.yaml {};
-in {
+  yaml = pkgs.formats.yaml { };
+in
+{
   options = {
     services.prometheus = {
       extraExporters = mkOption {
@@ -31,11 +32,10 @@ in {
     };
 
     services.victoriametrics.scrapeConfigs = mkOption {
-      type = types.attrsOf (types.submodule ({
-        name,
-        self,
-        ...
-      }: {
+      type = types.attrsOf (types.submodule ({ name
+                                             , self
+                                             , ...
+                                             }: {
         options = {
           job_name = mkOption {
             type = types.str;
@@ -47,7 +47,7 @@ in {
             description = ''
               Other settings to set for this scrape config.
             '';
-            default = {};
+            default = { };
           };
 
           targets = mkOption {
@@ -57,11 +57,11 @@ in {
 
               Shortcut for `static_configs = lib.singleton {targets = [<targets>];}`
             '';
-            default = [];
+            default = [ ];
           };
 
           static_configs = mkOption {
-            default = [];
+            default = [ ];
             type = types.listOf (types.submodule {
               options = {
                 targets = mkOption {
@@ -77,7 +77,7 @@ in {
                   description = lib.mdDoc ''
                     Labels to apply to all targets defined for this static config.
                   '';
-                  default = {};
+                  default = { };
                 };
               };
             });
@@ -89,116 +89,125 @@ in {
 
   config = {
     systemd.services = lib.mkMerge [
-      (lib.mapAttrs' (name: exporter:
-        lib.nameValuePair "prometheus-${name}-exporter" (lib.mkMerge [
-          {
-            # Shamelessly copied from upstream because the upstream
-            # module is an intractable mess
-            wantedBy = ["multi-user.target"];
-            after = ["network.target"];
-            serviceConfig.Restart = mkDefault "always";
-            serviceConfig.PrivateTmp = mkDefault true;
-            serviceConfig.WorkingDirectory = mkDefault /tmp;
-            serviceConfig.DynamicUser = mkDefault true;
-            # Hardening
-            serviceConfig.CapabilityBoundingSet = mkDefault [""];
-            serviceConfig.DeviceAllow = [""];
-            serviceConfig.LockPersonality = true;
-            serviceConfig.MemoryDenyWriteExecute = true;
-            serviceConfig.NoNewPrivileges = true;
-            serviceConfig.PrivateDevices = mkDefault true;
-            serviceConfig.ProtectClock = mkDefault true;
-            serviceConfig.ProtectControlGroups = true;
-            serviceConfig.ProtectHome = true;
-            serviceConfig.ProtectHostname = true;
-            serviceConfig.ProtectKernelLogs = true;
-            serviceConfig.ProtectKernelModules = true;
-            serviceConfig.ProtectKernelTunables = true;
-            serviceConfig.ProtectSystem = mkDefault "strict";
-            serviceConfig.RemoveIPC = true;
-            serviceConfig.RestrictAddressFamilies = ["AF_INET" "AF_INET6"];
-            serviceConfig.RestrictNamespaces = true;
-            serviceConfig.RestrictRealtime = true;
-            serviceConfig.RestrictSUIDSGID = true;
-            serviceConfig.SystemCallArchitectures = "native";
-            serviceConfig.UMask = "0077";
-          }
-          exporter.serviceOpts
-        ]))
-      config.services.prometheus.extraExporters)
+      (lib.mapAttrs'
+        (name: exporter:
+          lib.nameValuePair "prometheus-${name}-exporter" (lib.mkMerge [
+            {
+              # Shamelessly copied from upstream because the upstream
+              # module is an intractable mess
+              wantedBy = [ "multi-user.target" ];
+              after = [ "network.target" ];
+              serviceConfig.Restart = mkDefault "always";
+              serviceConfig.PrivateTmp = mkDefault true;
+              serviceConfig.WorkingDirectory = mkDefault /tmp;
+              serviceConfig.DynamicUser = mkDefault true;
+              # Hardening
+              serviceConfig.CapabilityBoundingSet = mkDefault [ "" ];
+              serviceConfig.DeviceAllow = [ "" ];
+              serviceConfig.LockPersonality = true;
+              serviceConfig.MemoryDenyWriteExecute = true;
+              serviceConfig.NoNewPrivileges = true;
+              serviceConfig.PrivateDevices = mkDefault true;
+              serviceConfig.ProtectClock = mkDefault true;
+              serviceConfig.ProtectControlGroups = true;
+              serviceConfig.ProtectHome = true;
+              serviceConfig.ProtectHostname = true;
+              serviceConfig.ProtectKernelLogs = true;
+              serviceConfig.ProtectKernelModules = true;
+              serviceConfig.ProtectKernelTunables = true;
+              serviceConfig.ProtectSystem = mkDefault "strict";
+              serviceConfig.RemoveIPC = true;
+              serviceConfig.RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+              serviceConfig.RestrictNamespaces = true;
+              serviceConfig.RestrictRealtime = true;
+              serviceConfig.RestrictSUIDSGID = true;
+              serviceConfig.SystemCallArchitectures = "native";
+              serviceConfig.UMask = "0077";
+            }
+            exporter.serviceOpts
+          ]))
+        config.services.prometheus.extraExporters)
 
       {
-        vmagent-scrape-exporters = let
-          listenAddress = config.services.victoriametrics.listenAddress;
-          vmAddr = (lib.optionalString (lib.hasPrefix ":" listenAddress) "127.0.0.1") + listenAddress;
-          promscrape = yaml.generate "prometheus.yml" {
-            scrape_configs = lib.mapAttrsToList (_: scrape:
-              lib.recursiveUpdate {
-                inherit (scrape) job_name;
-                static_configs =
-                  scrape.static_configs
-                  ++ lib.optional (scrape.targets != []) {targets = scrape.targets;};
-              }
-              scrape.extraSettings)
-            config.services.victoriametrics.scrapeConfigs;
-          };
-        in {
-          enable = true;
-          path = [pkgs.victoriametrics];
-          wantedBy = ["multi-user.target"];
-          after = ["network.target" "victoriametrics.service"];
-          serviceConfig = {
-            ExecStart = [
-              (lib.concatStringsSep " " [
-                "${pkgs.victoriametrics}/bin/vmagent"
-                "-promscrape.config=${promscrape}"
-                "-remoteWrite.url=http://${vmAddr}/api/v1/write"
-                "-remoteWrite.tmpDataPath=%t/vmagent"
-              ])
-            ];
-            SupplementaryGroups = "metrics";
+        vmagent-scrape-exporters =
+          let
+            listenAddress = config.services.victoriametrics.listenAddress;
+            vmAddr = (lib.optionalString (lib.hasPrefix ":" listenAddress) "127.0.0.1") + listenAddress;
+            promscrape = yaml.generate "prometheus.yml" {
+              scrape_configs = lib.mapAttrsToList
+                (_: scrape:
+                  lib.recursiveUpdate
+                    {
+                      inherit (scrape) job_name;
+                      static_configs =
+                        scrape.static_configs
+                        ++ lib.optional (scrape.targets != [ ]) { targets = scrape.targets; };
+                    }
+                    scrape.extraSettings)
+                config.services.victoriametrics.scrapeConfigs;
+            };
+          in
+          {
+            enable = true;
+            path = [ pkgs.victoriametrics ];
+            wantedBy = [ "multi-user.target" ];
+            after = [ "network.target" "victoriametrics.service" ];
+            serviceConfig = {
+              ExecStart = [
+                (lib.concatStringsSep " " [
+                  "${pkgs.victoriametrics}/bin/vmagent"
+                  "-promscrape.config=${promscrape}"
+                  "-remoteWrite.url=http://${vmAddr}/api/v1/write"
+                  "-remoteWrite.tmpDataPath=%t/vmagent"
+                ])
+              ];
+              SupplementaryGroups = "metrics";
 
-            DynamicUser = true;
-            RuntimeDirectory = "vmagent";
-            CapabilityBoundingSet = [""];
-            DeviceAllow = [""];
-            LockPersonality = true;
-            MemoryDenyWriteExecute = true;
-            NoNewPrivileges = true;
-            PrivateDevices = true;
-            ProtectClock = true;
-            ProtectControlGroups = true;
-            ProtectHome = true;
-            ProtectHostname = true;
-            ProtectKernelLogs = true;
-            ProtectKernelModules = true;
-            ProtectKernelTunables = true;
-            ProtectSystem = "strict";
-            RemoveIPC = true;
-            RestrictAddressFamilies = ["AF_INET" "AF_INET6"];
-            RestrictNamespaces = true;
-            RestrictRealtime = true;
-            RestrictSUIDSGID = true;
-            SystemCallArchitectures = "native";
-            UMask = "0077";
+              DynamicUser = true;
+              RuntimeDirectory = "vmagent";
+              CapabilityBoundingSet = [ "" ];
+              DeviceAllow = [ "" ];
+              LockPersonality = true;
+              MemoryDenyWriteExecute = true;
+              NoNewPrivileges = true;
+              PrivateDevices = true;
+              ProtectClock = true;
+              ProtectControlGroups = true;
+              ProtectHome = true;
+              ProtectHostname = true;
+              ProtectKernelLogs = true;
+              ProtectKernelModules = true;
+              ProtectKernelTunables = true;
+              ProtectSystem = "strict";
+              RemoveIPC = true;
+              RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+              RestrictNamespaces = true;
+              RestrictRealtime = true;
+              RestrictSUIDSGID = true;
+              SystemCallArchitectures = "native";
+              UMask = "0077";
+            };
           };
-        };
       }
     ];
 
-    users.groups.metrics = {};
+    users.groups.metrics = { };
 
-    services.victoriametrics.scrapeConfigs = let
-      allExporters =
-        lib.mapAttrs (name: exporter: {
-          inherit (exporter) listenAddress port;
-        }) ((lib.filterAttrs (_: exporter: builtins.isAttrs exporter && exporter.enable)
-          config.services.prometheus.exporters)
-        // config.services.prometheus.extraExporters);
-    in
-      lib.mapAttrs (_: exporter: {
-        targets = ["${exporter.listenAddress}:${toString exporter.port}"];
-      })
-      allExporters;
+    services.victoriametrics.scrapeConfigs =
+      let
+        allExporters =
+          lib.mapAttrs
+            (name: exporter: {
+              inherit (exporter) listenAddress port;
+            })
+            ((lib.filterAttrs (_: exporter: builtins.isAttrs exporter && exporter.enable)
+              config.services.prometheus.exporters)
+            // config.services.prometheus.extraExporters);
+      in
+      lib.mapAttrs
+        (_: exporter: {
+          targets = [ "${exporter.listenAddress}:${toString exporter.port}" ];
+        })
+        allExporters;
   };
 }
diff --git a/configuration/services/metrics/victoriametrics.nix b/configuration/services/metrics/victoriametrics.nix
index daf3f94..695b89e 100644
--- a/configuration/services/metrics/victoriametrics.nix
+++ b/configuration/services/metrics/victoriametrics.nix
@@ -1,4 +1,4 @@
-{config, ...}: {
+{ config, ... }: {
   config.services.victoriametrics = {
     enable = true;
     extraOptions = [
@@ -7,10 +7,10 @@
 
     scrapeConfigs = {
       forgejo = {
-        targets = ["127.0.0.1:${toString config.services.forgejo.settings.server.HTTP_PORT}"];
+        targets = [ "127.0.0.1:${toString config.services.forgejo.settings.server.HTTP_PORT}" ];
         extraSettings.authorization.credentials_file = config.sops.secrets."forgejo/metrics-token".path;
       };
-      coturn.targets = ["127.0.0.1:9641"];
+      coturn.targets = [ "127.0.0.1:9641" ];
     };
   };
 }
diff --git a/configuration/services/nextcloud.nix b/configuration/services/nextcloud.nix
index 2c7fe4f..7c4fcf4 100644
--- a/configuration/services/nextcloud.nix
+++ b/configuration/services/nextcloud.nix
@@ -1,14 +1,15 @@
-{
-  pkgs,
-  config,
-  ...
-}: let
+{ pkgs
+, config
+, ...
+}:
+let
   # Update pending on rewrite of nextcloud news, though there is an
   # alpha to switch to if it becomes necessary:
   # https://github.com/nextcloud/news/issues/2610
   nextcloud = pkgs.nextcloud27;
   hostName = "nextcloud.${config.services.nginx.domain}";
-in {
+in
+{
   services.nextcloud = {
     inherit hostName;
 
@@ -42,7 +43,7 @@ in {
   };
 
   # Ensure that this service doesn't start before postgres is ready
-  systemd.services.nextcloud-setup.after = ["postgresql.service"];
+  systemd.services.nextcloud-setup.after = [ "postgresql.service" ];
 
   # Set up SSL
   services.nginx.virtualHosts."${hostName}" = {
diff --git a/configuration/services/postgres.nix b/configuration/services/postgres.nix
index 018dc6e..62dfb01 100644
--- a/configuration/services/postgres.nix
+++ b/configuration/services/postgres.nix
@@ -1,4 +1,4 @@
-{pkgs, ...}: {
+{ pkgs, ... }: {
   services.postgresql = {
     package = pkgs.postgresql_14;
     enable = true;
diff --git a/configuration/services/starbound.nix b/configuration/services/starbound.nix
index 6da890e..3b54ee9 100644
--- a/configuration/services/starbound.nix
+++ b/configuration/services/starbound.nix
@@ -1,16 +1,17 @@
-{
-  pkgs,
-  lib,
-  ...
-}: let
+{ pkgs
+, lib
+, ...
+}:
+let
   inherit (lib) concatStringsSep;
-in {
+in
+{
   # Sadly, steam-run requires some X libs
   environment.noXlibs = false;
 
   systemd.services.starbound = {
     description = "Starbound";
-    after = ["network.target"];
+    after = [ "network.target" ];
 
     serviceConfig = {
       ExecStart = "${pkgs.local.starbound}/bin/launch-starbound ${./configs/starbound.json}";
@@ -67,7 +68,7 @@ in {
       # Game servers shouldn't use cgroups themselves either
       ProtectControlGroups = true;
       # Most game servers will never need other socket types
-      RestrictAddressFamilies = ["AF_UNIX AF_INET AF_INET6"];
+      RestrictAddressFamilies = [ "AF_UNIX AF_INET AF_INET6" ];
       # Also a no-brainer, no game server should ever need this
       LockPersonality = true;
       # Some game servers will probably try to set this, but they
@@ -116,6 +117,6 @@ in {
     paths = [
       "/var/lib/private/starbound/storage/universe/"
     ];
-    pauseServices = ["starbound.service"];
+    pauseServices = [ "starbound.service" ];
   };
 }
diff --git a/configuration/services/webserver.nix b/configuration/services/webserver.nix
index 387df57..e6b49b3 100644
--- a/configuration/services/webserver.nix
+++ b/configuration/services/webserver.nix
@@ -1,6 +1,8 @@
-{config, ...}: let
+{ config, ... }:
+let
   domain = config.services.nginx.domain;
-in {
+in
+{
   services.tlaternet-webserver = {
     enable = true;
     listen = {
@@ -10,15 +12,17 @@ in {
   };
 
   # Set up SSL
-  services.nginx.virtualHosts."${domain}" = let
-    inherit (config.services.tlaternet-webserver.listen) addr port;
-  in {
-    serverAliases = ["www.${domain}"];
+  services.nginx.virtualHosts."${domain}" =
+    let
+      inherit (config.services.tlaternet-webserver.listen) addr port;
+    in
+    {
+      serverAliases = [ "www.${domain}" ];
 
-    forceSSL = true;
-    useACMEHost = "tlater.net";
-    enableHSTS = true;
+      forceSSL = true;
+      useACMEHost = "tlater.net";
+      enableHSTS = true;
 
-    locations."/".proxyPass = "http://${addr}:${toString port}";
-  };
+      locations."/".proxyPass = "http://${addr}:${toString port}";
+    };
 }
diff --git a/configuration/services/wireguard.nix b/configuration/services/wireguard.nix
index 1ae6aac..057a2e9 100644
--- a/configuration/services/wireguard.nix
+++ b/configuration/services/wireguard.nix
@@ -1,4 +1,4 @@
-{config, ...}: {
+{ config, ... }: {
   # iptables needs to permit forwarding from wg0 to wg0
   networking.firewall.extraCommands = ''
     iptables -A FORWARD -i wg0 -o wg0 -j ACCEPT
@@ -26,7 +26,7 @@
           {
             # yui
             wireguardPeerConfig = {
-              AllowedIPs = ["10.45.249.2/32"];
+              AllowedIPs = [ "10.45.249.2/32" ];
               PublicKey = "5mlnqEVJWks5OqgeFA2bLIrvST9TlCE81Btl+j4myz0=";
             };
           }
@@ -34,7 +34,7 @@
           {
             # yuanyuan
             wireguardPeerConfig = {
-              AllowedIPs = ["10.45.249.10/32"];
+              AllowedIPs = [ "10.45.249.10/32" ];
               PublicKey = "0UsFE2atz/O5P3OKQ8UHyyyGQNJbp1MeIWUJLuoerwE=";
             };
           }
diff --git a/configuration/sops.nix b/configuration/sops.nix
index 0746133..bc21834 100644
--- a/configuration/sops.nix
+++ b/configuration/sops.nix
@@ -31,8 +31,8 @@
       };
 
       # Heisenbridge
-      "heisenbridge/as-token" = {};
-      "heisenbridge/hs-token" = {};
+      "heisenbridge/as-token" = { };
+      "heisenbridge/hs-token" = { };
 
       "hetzner-api" = {
         owner = "acme";
@@ -62,10 +62,10 @@
       };
 
       # Steam
-      "steam/tlater" = {};
+      "steam/tlater" = { };
 
       # Turn
-      "turn/env" = {};
+      "turn/env" = { };
       "turn/secret" = {
         owner = "turnserver";
       };
diff --git a/flake.nix b/flake.nix
index 09a74ac..afdc668 100644
--- a/flake.nix
+++ b/flake.nix
@@ -32,126 +32,130 @@
     };
   };
 
-  outputs = {
-    self,
-    nixpkgs,
-    sops-nix,
-    nvfetcher,
-    deploy-rs,
-    ...
-  } @ inputs: let
-    system = "x86_64-linux";
-    pkgs = nixpkgs.legacyPackages.${system};
-  in {
-    ##################
-    # Configurations #
-    ##################
-    nixosConfigurations = {
-      # The actual system definition
-      hetzner-1 = nixpkgs.lib.nixosSystem {
-        inherit system;
-        specialArgs.flake-inputs = inputs;
+  outputs =
+    { self
+    , nixpkgs
+    , sops-nix
+    , nvfetcher
+    , deploy-rs
+    , ...
+    } @ inputs:
+    let
+      system = "x86_64-linux";
+      pkgs = nixpkgs.legacyPackages.${system};
+    in
+    {
+      ##################
+      # Configurations #
+      ##################
+      nixosConfigurations = {
+        # The actual system definition
+        hetzner-1 = nixpkgs.lib.nixosSystem {
+          inherit system;
+          specialArgs.flake-inputs = inputs;
 
-        modules = [
-          ./configuration
-          ./configuration/hardware-specific/hetzner
+          modules = [
+            ./configuration
+            ./configuration/hardware-specific/hetzner
+          ];
+        };
+      };
+
+      ############################
+      # Deployment configuration #
+      ############################
+      deploy.nodes = {
+        hetzner-1 = {
+          hostname = "116.202.158.55";
+
+          profiles.system = {
+            user = "root";
+            path = deploy-rs.lib.${system}.activate.nixos self.nixosConfigurations.hetzner-1;
+          };
+
+          sshUser = "tlater";
+          sshOpts = [ "-p" "2222" "-o" "ForwardAgent=yes" ];
+        };
+      };
+
+      #########
+      # Tests #
+      #########
+      checks = builtins.mapAttrs (system: deployLib: deployLib.deployChecks self.deploy) deploy-rs.lib;
+
+      ###################
+      # Utility scripts #
+      ###################
+      apps.${system} = {
+        default = self.apps.${system}.run-vm;
+
+        run-vm = {
+          type = "app";
+          program =
+            let
+              vm = nixpkgs.lib.nixosSystem {
+                inherit system;
+                specialArgs.flake-inputs = inputs;
+
+                modules = [
+                  ./configuration
+                  ./configuration/hardware-specific/vm.nix
+                ];
+              };
+            in
+            (pkgs.writeShellScript "" ''
+              ${vm.config.system.build.vm.outPath}/bin/run-testvm-vm
+            '').outPath;
+        };
+
+        update-pkgs = {
+          type = "app";
+          program =
+            let
+              nvfetcher-bin = "${nvfetcher.packages.${system}.default}/bin/nvfetcher";
+            in
+            (pkgs.writeShellScript "update-pkgs" ''
+              cd "$(git rev-parse --show-toplevel)/pkgs"
+              ${nvfetcher-bin} -o _sources_pkgs -c nvfetcher.toml
+            '').outPath;
+        };
+
+        update-nextcloud-apps = {
+          type = "app";
+          program =
+            let
+              nvfetcher-bin = "${nvfetcher.packages.${system}.default}/bin/nvfetcher";
+            in
+            (pkgs.writeShellScript "update-nextcloud-apps" ''
+              cd "$(git rev-parse --show-toplevel)/pkgs"
+              ${nvfetcher-bin} -o _sources_nextcloud -c nextcloud-apps.toml
+            '').outPath;
+        };
+      };
+
+      ###########################
+      # Development environment #
+      ###########################
+      devShells.${system}.default = nixpkgs.legacyPackages.${system}.mkShell {
+        sopsPGPKeyDirs = [ "./keys/hosts/" "./keys/users/" ];
+        nativeBuildInputs = [
+          sops-nix.packages.${system}.sops-import-keys-hook
+        ];
+
+        packages = with pkgs; [
+          sops-nix.packages.${system}.sops-init-gpg-key
+          deploy-rs.packages.${system}.default
+
+          nixpkgs-fmt
+
+          cargo
+          clippy
+          rustc
+          rustfmt
+          rust-analyzer
+          pkg-config
+          openssl
         ];
       };
     };
-
-    ############################
-    # Deployment configuration #
-    ############################
-    deploy.nodes = {
-      hetzner-1 = {
-        hostname = "116.202.158.55";
-
-        profiles.system = {
-          user = "root";
-          path = deploy-rs.lib.${system}.activate.nixos self.nixosConfigurations.hetzner-1;
-        };
-
-        sshUser = "tlater";
-        sshOpts = ["-p" "2222" "-o" "ForwardAgent=yes"];
-      };
-    };
-
-    #########
-    # Tests #
-    #########
-    checks = builtins.mapAttrs (system: deployLib: deployLib.deployChecks self.deploy) deploy-rs.lib;
-
-    ###################
-    # Utility scripts #
-    ###################
-    apps.${system} = {
-      default = self.apps.${system}.run-vm;
-
-      run-vm = {
-        type = "app";
-        program = let
-          vm = nixpkgs.lib.nixosSystem {
-            inherit system;
-            specialArgs.flake-inputs = inputs;
-
-            modules = [
-              ./configuration
-              ./configuration/hardware-specific/vm.nix
-            ];
-          };
-        in
-          (pkgs.writeShellScript "" ''
-            ${vm.config.system.build.vm.outPath}/bin/run-testvm-vm
-          '')
-          .outPath;
-      };
-
-      update-pkgs = {
-        type = "app";
-        program = let
-          nvfetcher-bin = "${nvfetcher.packages.${system}.default}/bin/nvfetcher";
-        in
-          (pkgs.writeShellScript "update-pkgs" ''
-            cd "$(git rev-parse --show-toplevel)/pkgs"
-            ${nvfetcher-bin} -o _sources_pkgs -c nvfetcher.toml
-          '')
-          .outPath;
-      };
-
-      update-nextcloud-apps = {
-        type = "app";
-        program = let
-          nvfetcher-bin = "${nvfetcher.packages.${system}.default}/bin/nvfetcher";
-        in
-          (pkgs.writeShellScript "update-nextcloud-apps" ''
-            cd "$(git rev-parse --show-toplevel)/pkgs"
-            ${nvfetcher-bin} -o _sources_nextcloud -c nextcloud-apps.toml
-          '')
-          .outPath;
-      };
-    };
-
-    ###########################
-    # Development environment #
-    ###########################
-    devShells.${system}.default = nixpkgs.legacyPackages.${system}.mkShell {
-      sopsPGPKeyDirs = ["./keys/hosts/" "./keys/users/"];
-      nativeBuildInputs = [
-        sops-nix.packages.${system}.sops-import-keys-hook
-      ];
-
-      packages = with pkgs; [
-        sops-nix.packages.${system}.sops-init-gpg-key
-        deploy-rs.packages.${system}.default
-
-        cargo
-        clippy
-        rustc
-        rustfmt
-        rust-analyzer
-        pkg-config
-        openssl
-      ];
-    };
-  };
 }
diff --git a/modules/nginxExtensions.nix b/modules/nginxExtensions.nix
index 9fe489a..3603756 100644
--- a/modules/nginxExtensions.nix
+++ b/modules/nginxExtensions.nix
@@ -1,8 +1,7 @@
-{
-  config,
-  pkgs,
-  lib,
-  ...
+{ config
+, pkgs
+, lib
+, ...
 }: {
   options = {
     services.nginx.domain = lib.mkOption {
@@ -10,36 +9,37 @@
       description = "The base domain name to append to virtual domain names";
     };
 
-    services.nginx.virtualHosts = let
-      extraVirtualHostOptions = {
-        name,
-        config,
-        ...
-      }: {
-        options = {
-          enableHSTS = lib.mkEnableOption "Enable HSTS";
+    services.nginx.virtualHosts =
+      let
+        extraVirtualHostOptions =
+          { name
+          , config
+          , ...
+          }: {
+            options = {
+              enableHSTS = lib.mkEnableOption "Enable HSTS";
 
-          addAccessLog = lib.mkOption {
-            type = lib.types.bool;
-            default = true;
-            description = ''
-              Add special logging to `/var/log/nginx/''${serverName}`
-            '';
+              addAccessLog = lib.mkOption {
+                type = lib.types.bool;
+                default = true;
+                description = ''
+                  Add special logging to `/var/log/nginx/''${serverName}`
+                '';
+              };
+            };
+
+            config = {
+              extraConfig = lib.concatStringsSep "\n" [
+                (lib.optionalString config.enableHSTS ''
+                  add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
+                '')
+                (lib.optionalString config.addAccessLog ''
+                  access_log /var/log/nginx/${name}/access.log upstream_time;
+                '')
+              ];
+            };
           };
-        };
-
-        config = {
-          extraConfig = lib.concatStringsSep "\n" [
-            (lib.optionalString config.enableHSTS ''
-              add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
-            '')
-            (lib.optionalString config.addAccessLog ''
-              access_log /var/log/nginx/${name}/access.log upstream_time;
-            '')
-          ];
-        };
-      };
-    in
+      in
       lib.mkOption {
         type = lib.types.attrsOf (lib.types.submodule extraVirtualHostOptions);
       };
@@ -47,13 +47,15 @@
 
   config = {
     # Don't attempt to run acme if the domain name is not tlater.net
-    systemd.services = let
-      confirm = ''[[ "tlater.net" = ${config.services.nginx.domain} ]]'';
-    in
-      lib.mapAttrs' (cert: _:
-        lib.nameValuePair "acme-${cert}" {
-          serviceConfig.ExecCondition = ''${pkgs.runtimeShell} -c '${confirm}' '';
-        })
-      config.security.acme.certs;
+    systemd.services =
+      let
+        confirm = ''[[ "tlater.net" = ${config.services.nginx.domain} ]]'';
+      in
+      lib.mapAttrs'
+        (cert: _:
+          lib.nameValuePair "acme-${cert}" {
+            serviceConfig.ExecCondition = ''${pkgs.runtimeShell} -c '${confirm}' '';
+          })
+        config.security.acme.certs;
   };
 }
diff --git a/pkgs/afvalcalendar/default.nix b/pkgs/afvalcalendar/default.nix
index 12e2af5..12b868c 100644
--- a/pkgs/afvalcalendar/default.nix
+++ b/pkgs/afvalcalendar/default.nix
@@ -1,7 +1,6 @@
-{
-  pkgs,
-  rustPlatform,
-  ...
+{ pkgs
+, rustPlatform
+, ...
 }:
 rustPlatform.buildRustPackage {
   pname = "afvalcalendar";
diff --git a/pkgs/default.nix b/pkgs/default.nix
index 3162787..132d0f5 100644
--- a/pkgs/default.nix
+++ b/pkgs/default.nix
@@ -1,22 +1,23 @@
-{
-  pkgs,
-  lib,
-}: let
+{ pkgs
+, lib
+,
+}:
+let
   inherit (builtins) fromJSON mapAttrs readFile;
   inherit (pkgs) callPackage;
 in
-  {
-    starbound = callPackage ./starbound {};
-    prometheus-fail2ban-exporter = callPackage ./prometheus/fail2ban-exporter.nix {
-      sources = pkgs.callPackage ./_sources_pkgs/generated.nix {};
-    };
-    afvalcalendar = callPackage ./afvalcalendar {};
-  }
+{
+  starbound = callPackage ./starbound { };
+  prometheus-fail2ban-exporter = callPackage ./prometheus/fail2ban-exporter.nix {
+    sources = pkgs.callPackage ./_sources_pkgs/generated.nix { };
+  };
+  afvalcalendar = callPackage ./afvalcalendar { };
+}
   // (
-    # Add nextcloud apps
-    let
-      mkNextcloudApp = pkgs.callPackage ./mkNextcloudApp.nix {};
-      sources = fromJSON (readFile ./_sources_nextcloud/generated.json);
-    in
-      mapAttrs (_: source: mkNextcloudApp source) sources
-  )
+  # Add nextcloud apps
+  let
+    mkNextcloudApp = pkgs.callPackage ./mkNextcloudApp.nix { };
+    sources = fromJSON (readFile ./_sources_nextcloud/generated.json);
+  in
+  mapAttrs (_: source: mkNextcloudApp source) sources
+)
diff --git a/pkgs/mkNextcloudApp.nix b/pkgs/mkNextcloudApp.nix
index 9bf6b26..7453f44 100644
--- a/pkgs/mkNextcloudApp.nix
+++ b/pkgs/mkNextcloudApp.nix
@@ -1,6 +1,6 @@
-{
-  fetchNextcloudApp,
-  lib,
+{ fetchNextcloudApp
+, lib
+,
 }: source:
 fetchNextcloudApp {
   url = source.src.url;
diff --git a/pkgs/prometheus/fail2ban-exporter.nix b/pkgs/prometheus/fail2ban-exporter.nix
index b2c6a25..b74e35d 100644
--- a/pkgs/prometheus/fail2ban-exporter.nix
+++ b/pkgs/prometheus/fail2ban-exporter.nix
@@ -1,6 +1,6 @@
-{
-  buildGoModule,
-  sources,
+{ buildGoModule
+, sources
+,
 }:
 buildGoModule {
   inherit (sources.prometheus-fail2ban-exporter) pname src version;
diff --git a/pkgs/starbound/default.nix b/pkgs/starbound/default.nix
index 304f0f3..a8689f3 100644
--- a/pkgs/starbound/default.nix
+++ b/pkgs/starbound/default.nix
@@ -1,34 +1,35 @@
-{
-  stdenv,
-  lib,
-  makeWrapper,
-  patchelf,
-  steamPackages,
-  replace-secret,
-}: let
+{ stdenv
+, lib
+, makeWrapper
+, patchelf
+, steamPackages
+, replace-secret
+,
+}:
+let
   # Use the directory in which starbound is installed so steamcmd
   # doesn't have to be reinstalled constantly (we're using DynamicUser
   # with StateDirectory to persist this).
   steamcmd = steamPackages.steamcmd.override {
     steamRoot = "/var/lib/starbound/.steamcmd";
   };
-  wrapperPath = lib.makeBinPath [patchelf steamcmd replace-secret];
+  wrapperPath = lib.makeBinPath [ patchelf steamcmd replace-secret ];
 in
-  stdenv.mkDerivation {
-    name = "starbound-update-script";
-    nativeBuildInputs = [makeWrapper];
-    dontUnpack = true;
-    patchPhase = ''
-      interpreter="$(cat $NIX_CC/nix-support/dynamic-linker)"
-      substitute ${./launch-starbound.sh} launch-starbound --subst-var interpreter
-    '';
-    installPhase = ''
-      mkdir -p $out/bin
-      cp launch-starbound $out/bin/launch-starbound
-      chmod +x $out/bin/launch-starbound
-    '';
-    postFixup = ''
-      wrapProgram $out/bin/launch-starbound \
-          --prefix PATH : "${wrapperPath}"
-    '';
-  }
+stdenv.mkDerivation {
+  name = "starbound-update-script";
+  nativeBuildInputs = [ makeWrapper ];
+  dontUnpack = true;
+  patchPhase = ''
+    interpreter="$(cat $NIX_CC/nix-support/dynamic-linker)"
+    substitute ${./launch-starbound.sh} launch-starbound --subst-var interpreter
+  '';
+  installPhase = ''
+    mkdir -p $out/bin
+    cp launch-starbound $out/bin/launch-starbound
+    chmod +x $out/bin/launch-starbound
+  '';
+  postFixup = ''
+    wrapProgram $out/bin/launch-starbound \
+        --prefix PATH : "${wrapperPath}"
+  '';
+}

From 038a7974274e3e0a169516968cb935d4231e85e5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 28 Jun 2024 20:15:11 +0200
Subject: [PATCH 03/67] git: Blame-ignore nixpkgs-fmt commit

---
 .git-blame-ignore-revs | 8 ++++++++
 1 file changed, 8 insertions(+)
 create mode 100644 .git-blame-ignore-revs

diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 0000000..cee878d
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,8 @@
+# Run this command to always ignore formatting commits in `git blame`
+# git config blame.ignoreRevsFile .git-blame-ignore-revs
+
+# Switch to nixpkgs-fmt formatting
+fd138d45e6a2cad89fead6e9f246ba282070d6b7
+
+# Switch to alejandra formatting
+046a88905ddfa7f9edc3291c310dbb985dee34f9

From 9654d599e90e46cd42fe02b852235cb44c380c79 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 28 Jun 2024 20:28:15 +0200
Subject: [PATCH 04/67] flake.lock: Update
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Flake lock file updates:

• Updated input 'deploy-rs':
    'github:serokell/deploy-rs/88b3059b020da69cbe16526b8d639bd5e0b51c8b' (2024-04-01)
  → 'github:serokell/deploy-rs/3867348fa92bc892eba5d9ddb2d7a97b9e127a8a' (2024-06-12)
• Updated input 'disko':
    'github:nix-community/disko/285e26465a0bae510897ca04da26ce6307c652b4' (2024-04-26)
  → 'github:nix-community/disko/115311bc395f24c1b553338fec4b3aa28cbf5ae2' (2024-06-28)
• Updated input 'foundryvtt':
    'github:reckenrode/nix-foundryvtt/6025615b431170558c3c13f16b549fc0126425e1' (2024-04-09)
  → 'github:reckenrode/nix-foundryvtt/1176cc325e5e1d46c7a018663a8e02e699e838ec' (2024-06-28)
• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/cc54fb41d13736e92229c21627ea4f22199fee6b' (2024-06-12)
  → 'github:nixos/nixpkgs/89c49874fb15f4124bf71ca5f42a04f2ee5825fd' (2024-06-26)
• Updated input 'nixpkgs-unstable':
    'github:nixos/nixpkgs/58a1abdbae3217ca6b702f03d3b35125d88a2994' (2024-04-27)
  → 'github:nixos/nixpkgs/2893f56de08021cffd9b6b6dfc70fd9ccd51eb60' (2024-06-24)
• Updated input 'nvfetcher':
    'github:berberman/nvfetcher/2a824322dc6a755ffda83a13b948d42304521e4d' (2024-04-17)
  → 'github:berberman/nvfetcher/fa7609950023462c6f91c425de7610c0bb6b86ba' (2024-06-13)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/f1b0adc27265274e3b0c9b872a8f476a098679bd' (2024-04-23)
  → 'github:Mic92/sops-nix/c2ea1186c0cbfa4d06d406ae50f3e4b085ddc9b3' (2024-06-24)
• Updated input 'sops-nix/nixpkgs-stable':
    'github:NixOS/nixpkgs/74574c38577914733b4f7a775dd77d24245081dd' (2024-04-20)
  → 'github:NixOS/nixpkgs/5e8e3b89adbd0be63192f6e645e0a54080004924' (2024-06-22)
---
 flake.lock | 84 +++++++++++++++++++++++++++---------------------------
 flake.nix  |  4 +--
 2 files changed, 44 insertions(+), 44 deletions(-)

diff --git a/flake.lock b/flake.lock
index 3f8dcb9..dab6ebf 100644
--- a/flake.lock
+++ b/flake.lock
@@ -7,11 +7,11 @@
         "utils": "utils"
       },
       "locked": {
-        "lastModified": 1711973905,
-        "narHash": "sha256-UFKME/N1pbUtn+2Aqnk+agUt8CekbpuqwzljivfIme8=",
+        "lastModified": 1718194053,
+        "narHash": "sha256-FaGrf7qwZ99ehPJCAwgvNY5sLCqQ3GDiE/6uLhxxwSY=",
         "owner": "serokell",
         "repo": "deploy-rs",
-        "rev": "88b3059b020da69cbe16526b8d639bd5e0b51c8b",
+        "rev": "3867348fa92bc892eba5d9ddb2d7a97b9e127a8a",
         "type": "github"
       },
       "original": {
@@ -27,11 +27,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1714103775,
-        "narHash": "sha256-kcBiIrmqzt3bNTr2GMBfAyA+on8BEKO1iKzzDFQZkjI=",
+        "lastModified": 1719733833,
+        "narHash": "sha256-6h2EqZU9bL9rHlXE+2LCBgnDImejzbS+4dYsNDDFlkY=",
         "owner": "nix-community",
         "repo": "disko",
-        "rev": "285e26465a0bae510897ca04da26ce6307c652b4",
+        "rev": "d185770ea261fb5cf81aa5ad1791b93a7834d12c",
         "type": "github"
       },
       "original": {
@@ -47,11 +47,11 @@
         "pyproject-nix": "pyproject-nix"
       },
       "locked": {
-        "lastModified": 1702457430,
-        "narHash": "sha256-8NQiXtYCOiC7XFayy6GPGDudCBrPROry3mfWjpdVj5g=",
+        "lastModified": 1719685993,
+        "narHash": "sha256-04gy1icwnGO3ZXF6r96yBm/C0PNPzeLxA/8xzzq0dBI=",
         "owner": "nix-community",
         "repo": "dream2nix",
-        "rev": "262198033e23e9ee832f0cc8133d38f07598f555",
+        "rev": "1b5e01219a32324c8f6889fe1f4db933ec7932f6",
         "type": "github"
       },
       "original": {
@@ -69,11 +69,11 @@
         "rust-analyzer-src": "rust-analyzer-src"
       },
       "locked": {
-        "lastModified": 1704003651,
-        "narHash": "sha256-bA3d4E1CX5G7TVbKwJOm9jZfVOGOPp6u5CKEUzNsE8E=",
+        "lastModified": 1719815435,
+        "narHash": "sha256-K2xFp142onP35jcx7li10xUxNVEVRWjAdY8DSuR7Naw=",
         "owner": "nix-community",
         "repo": "fenix",
-        "rev": "c6d82e087ac96f24b90c5787a17e29a72566c2b4",
+        "rev": "ebfe2c639111d7e82972a12711206afaeeda2450",
         "type": "github"
       },
       "original": {
@@ -157,11 +157,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1712623723,
-        "narHash": "sha256-jPD5+M+QPyMRk52zfFMIeHdv7yXYJ/yNGqwS0PhYF+E=",
+        "lastModified": 1719541573,
+        "narHash": "sha256-9j8Rtv5UWsD4A3jAh8MpopNGmftSAoI8htssmXLu8jU=",
         "owner": "reckenrode",
         "repo": "nix-foundryvtt",
-        "rev": "6025615b431170558c3c13f16b549fc0126425e1",
+        "rev": "1176cc325e5e1d46c7a018663a8e02e699e838ec",
         "type": "github"
       },
       "original": {
@@ -210,11 +210,11 @@
     },
     "nixpkgs-stable": {
       "locked": {
-        "lastModified": 1713638189,
-        "narHash": "sha256-q7APLfB6FmmSMI1Su5ihW9IwntBsk2hWNXh8XtSdSIk=",
+        "lastModified": 1719663039,
+        "narHash": "sha256-tXlrgAQygNIy49LDVFuPXlWD2zTQV9/F8pfoqwwPJyo=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "74574c38577914733b4f7a775dd77d24245081dd",
+        "rev": "4a1e673523344f6ccc84b37f4413ad74ea19a119",
         "type": "github"
       },
       "original": {
@@ -226,43 +226,43 @@
     },
     "nixpkgs-unstable": {
       "locked": {
-        "lastModified": 1714253743,
-        "narHash": "sha256-mdTQw2XlariysyScCv2tTE45QSU9v/ezLcHJ22f0Nxc=",
+        "lastModified": 1719824438,
+        "narHash": "sha256-pY0wosAgcr9W4vmGML0T3BVhQiGuKoozCbs2t+Je1zc=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "58a1abdbae3217ca6b702f03d3b35125d88a2994",
+        "rev": "7f993cdf26ccef564eabf31fdb40d140821e12bc",
         "type": "github"
       },
       "original": {
         "owner": "nixos",
-        "ref": "nixos-unstable",
+        "ref": "nixos-unstable-small",
         "repo": "nixpkgs",
         "type": "github"
       }
     },
     "nixpkgs_2": {
       "locked": {
-        "lastModified": 1718208800,
-        "narHash": "sha256-US1tAChvPxT52RV8GksWZS415tTS7PV42KTc2PNDBmc=",
+        "lastModified": 1719825363,
+        "narHash": "sha256-2ASBatUTQWNIiTeBZRuxROu27MyOavVnzeCv7h40QNw=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "cc54fb41d13736e92229c21627ea4f22199fee6b",
+        "rev": "10c832d0548e9e3a6df7eb51e68c2783212a303e",
         "type": "github"
       },
       "original": {
         "owner": "nixos",
-        "ref": "nixos-24.05",
+        "ref": "nixos-24.05-small",
         "repo": "nixpkgs",
         "type": "github"
       }
     },
     "nixpkgs_3": {
       "locked": {
-        "lastModified": 1702272962,
-        "narHash": "sha256-D+zHwkwPc6oYQ4G3A1HuadopqRwUY/JkMwHz1YF7j4Q=",
+        "lastModified": 1719468428,
+        "narHash": "sha256-vN5xJAZ4UGREEglh3lfbbkIj+MPEYMuqewMn4atZFaQ=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "e97b3e4186bcadf0ef1b6be22b8558eab1cdeb5d",
+        "rev": "1e3deb3d8a86a870d925760db1a5adecc64d329d",
         "type": "github"
       },
       "original": {
@@ -281,11 +281,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1713333471,
-        "narHash": "sha256-sIVQKOXzruxtTYiBRHZa8UQH+CSIa9K5MZlY6vavYfA=",
+        "lastModified": 1718252448,
+        "narHash": "sha256-xZZBdKqe1ByITzvx65pVgGQ5jeb73MybjgrcfI84lEo=",
         "owner": "berberman",
         "repo": "nvfetcher",
-        "rev": "2a824322dc6a755ffda83a13b948d42304521e4d",
+        "rev": "fa7609950023462c6f91c425de7610c0bb6b86ba",
         "type": "github"
       },
       "original": {
@@ -375,11 +375,11 @@
     "rust-analyzer-src": {
       "flake": false,
       "locked": {
-        "lastModified": 1703965384,
-        "narHash": "sha256-3iyouqkBvhh/E48TkBlt4JmmcIEyfQwY7pokKBx9WNg=",
+        "lastModified": 1719760370,
+        "narHash": "sha256-fsxAuW6RxKZYjAP3biUC6C4vaYFhDfWv8lp1Tmx3ZCY=",
         "owner": "rust-lang",
         "repo": "rust-analyzer",
-        "rev": "e872f5085cf5b0e44558442365c1c033d486eff2",
+        "rev": "ea7fdada6a0940b239ddbde2048a4d7dac1efe1e",
         "type": "github"
       },
       "original": {
@@ -442,11 +442,11 @@
         "nixpkgs-stable": "nixpkgs-stable"
       },
       "locked": {
-        "lastModified": 1713892811,
-        "narHash": "sha256-uIGmA2xq41vVFETCF1WW4fFWFT2tqBln+aXnWrvjGRE=",
+        "lastModified": 1719716556,
+        "narHash": "sha256-KA9gy2Wkv76s4A8eLnOcdKVTygewbw3xsB8+awNMyqs=",
         "owner": "Mic92",
         "repo": "sops-nix",
-        "rev": "f1b0adc27265274e3b0c9b872a8f476a098679bd",
+        "rev": "b5974d4331fb6c893e808977a2e1a6d34b3162d6",
         "type": "github"
       },
       "original": {
@@ -523,11 +523,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1704840002,
-        "narHash": "sha256-ik2LeuRjcnRXwBLoRSOyGEMXscE+coO8G79IFhZhdJk=",
+        "lastModified": 1719851829,
+        "narHash": "sha256-M5miiIbiwP4uArTyeIr/RKA857rP14AEJUe11AZsKAc=",
         "ref": "refs/heads/master",
-        "rev": "d14f50c8dcc8ab30a5e5fa907b392ac0df6c7b52",
-        "revCount": 73,
+        "rev": "4a099f27a27f4107ceb14969e2158eaabebcf1d4",
+        "revCount": 74,
         "type": "git",
         "url": "https://gitea.tlater.net/tlaternet/tlaternet.git"
       },
diff --git a/flake.nix b/flake.nix
index afdc668..e3ff531 100644
--- a/flake.nix
+++ b/flake.nix
@@ -2,8 +2,8 @@
   description = "tlater.net host configuration";
 
   inputs = {
-    nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05";
-    nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
+    nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05-small";
+    nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable-small";
     disko = {
       url = "github:nix-community/disko";
       inputs.nixpkgs.follows = "nixpkgs";

From 21cb4eab9cbaeee6dab27ee9dc0c03b42269839c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Mon, 1 Jul 2024 18:34:23 +0200
Subject: [PATCH 05/67] foundryvtt: Set foundry version explicitly

---
 configuration/services/foundryvtt.nix | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/configuration/services/foundryvtt.nix b/configuration/services/foundryvtt.nix
index e69d2dd..3383ab3 100644
--- a/configuration/services/foundryvtt.nix
+++ b/configuration/services/foundryvtt.nix
@@ -1,6 +1,7 @@
 { lib
 , config
 , flake-inputs
+, pkgs
 , ...
 }:
 let
@@ -15,6 +16,7 @@ in
     minifyStaticFiles = true;
     proxySSL = true;
     proxyPort = 443;
+    package = flake-inputs.foundryvtt.packages.${pkgs.system}.foundryvtt_11;
   };
 
   # Want to start it manually when I need it, not have it constantly

From 32f4cabfa35bad8da8ef2a06e1f08dece6a9a6e1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Mon, 1 Jul 2024 18:35:53 +0200
Subject: [PATCH 06/67] nextcloud: Update to 28 since 27 is EOL

We were waiting for nextcloud news to update, but we can't wait any
longer.
---
 configuration/services/nextcloud.nix   |  2 +-
 pkgs/_sources_nextcloud/generated.json | 24 ++++++++++++------------
 pkgs/_sources_nextcloud/generated.nix  | 24 ++++++++++++------------
 pkgs/nextcloud-apps.toml               | 13 +++++--------
 4 files changed, 30 insertions(+), 33 deletions(-)

diff --git a/configuration/services/nextcloud.nix b/configuration/services/nextcloud.nix
index 7c4fcf4..0d22e6c 100644
--- a/configuration/services/nextcloud.nix
+++ b/configuration/services/nextcloud.nix
@@ -6,7 +6,7 @@ let
   # Update pending on rewrite of nextcloud news, though there is an
   # alpha to switch to if it becomes necessary:
   # https://github.com/nextcloud/news/issues/2610
-  nextcloud = pkgs.nextcloud27;
+  nextcloud = pkgs.nextcloud28;
   hostName = "nextcloud.${config.services.nginx.domain}";
 in
 {
diff --git a/pkgs/_sources_nextcloud/generated.json b/pkgs/_sources_nextcloud/generated.json
index ce9ac04..c216c8d 100644
--- a/pkgs/_sources_nextcloud/generated.json
+++ b/pkgs/_sources_nextcloud/generated.json
@@ -7,11 +7,11 @@
         "passthru": null,
         "pinned": false,
         "src": {
-            "sha256": "sha256-JXNQNnWXoii71QhtKktuEBEIqzmONVetULBhpSjM9xo=",
+            "sha256": "sha256-wUeXcbxNCRA2brzdCHKwl0zbhmDucKv1ZCkF3KlQ8O4=",
             "type": "tarball",
-            "url": "https://github.com/nextcloud/bookmarks/releases/download/v13.1.3/bookmarks-13.1.3.tar.gz"
+            "url": "https://github.com/nextcloud/bookmarks/releases/download/v14.2.2/bookmarks-14.2.2.tar.gz"
         },
-        "version": "13.1.3"
+        "version": "14.2.2"
     },
     "calendar": {
         "cargoLocks": null,
@@ -21,11 +21,11 @@
         "passthru": null,
         "pinned": false,
         "src": {
-            "sha256": "sha256-hZfjWAMi/0qs5xMMgOlcoSXG6kcZ2aeDaez+NqSZFKI=",
+            "sha256": "sha256-cuAqJz1cZ+VfxttAKjWIe11DFwWGLdSSvcNJKQKidgk=",
             "type": "tarball",
-            "url": "https://github.com/nextcloud-releases/calendar/releases/download/v4.6.7/calendar-v4.6.7.tar.gz"
+            "url": "https://github.com/nextcloud-releases/calendar/releases/download/v4.7.8/calendar-v4.7.8.tar.gz"
         },
-        "version": "v4.6.7"
+        "version": "v4.7.8"
     },
     "contacts": {
         "cargoLocks": null,
@@ -49,11 +49,11 @@
         "passthru": null,
         "pinned": false,
         "src": {
-            "sha256": "sha256-TE/w8SgyIPaGl5wZUAsG234nxoPj25QoRPF3zjbMoRk=",
+            "sha256": "sha256-a8ekMnEzudHGiqHF53jPtgsVTOTc2QLuPg6YtTw5h68=",
             "type": "tarball",
-            "url": "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v0.10.5/Cookbook-0.10.5.tar.gz"
+            "url": "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v0.11.1/Cookbook-0.11.1.tar.gz"
         },
-        "version": "0.10.5"
+        "version": "0.11.1"
     },
     "news": {
         "cargoLocks": null,
@@ -63,11 +63,11 @@
         "passthru": null,
         "pinned": false,
         "src": {
-            "sha256": "sha256-cfJkKRNSz15L4E3w1tnEb+t4MrVwVzb8lb6vCOA4cK4=",
+            "sha256": "sha256-XNGjf7SWgJYFdVNOh3ED0jxSG0GJwWImVQq4cJT1Lo4=",
             "type": "tarball",
-            "url": "https://github.com/nextcloud/news/releases/download/24.0.0/news.tar.gz"
+            "url": "https://github.com/nextcloud/news/releases/download/25.0.0-alpha7/news.tar.gz"
         },
-        "version": "24.0.0"
+        "version": "25.0.0-alpha7"
     },
     "notes": {
         "cargoLocks": null,
diff --git a/pkgs/_sources_nextcloud/generated.nix b/pkgs/_sources_nextcloud/generated.nix
index c77aa9c..3075206 100644
--- a/pkgs/_sources_nextcloud/generated.nix
+++ b/pkgs/_sources_nextcloud/generated.nix
@@ -3,18 +3,18 @@
 {
   bookmarks = {
     pname = "bookmarks";
-    version = "13.1.3";
+    version = "14.2.2";
     src = fetchTarball {
-      url = "https://github.com/nextcloud/bookmarks/releases/download/v13.1.3/bookmarks-13.1.3.tar.gz";
-      sha256 = "sha256-JXNQNnWXoii71QhtKktuEBEIqzmONVetULBhpSjM9xo=";
+      url = "https://github.com/nextcloud/bookmarks/releases/download/v14.2.2/bookmarks-14.2.2.tar.gz";
+      sha256 = "sha256-wUeXcbxNCRA2brzdCHKwl0zbhmDucKv1ZCkF3KlQ8O4=";
     };
   };
   calendar = {
     pname = "calendar";
-    version = "v4.6.7";
+    version = "v4.7.8";
     src = fetchTarball {
-      url = "https://github.com/nextcloud-releases/calendar/releases/download/v4.6.7/calendar-v4.6.7.tar.gz";
-      sha256 = "sha256-hZfjWAMi/0qs5xMMgOlcoSXG6kcZ2aeDaez+NqSZFKI=";
+      url = "https://github.com/nextcloud-releases/calendar/releases/download/v4.7.8/calendar-v4.7.8.tar.gz";
+      sha256 = "sha256-cuAqJz1cZ+VfxttAKjWIe11DFwWGLdSSvcNJKQKidgk=";
     };
   };
   contacts = {
@@ -27,18 +27,18 @@
   };
   cookbook = {
     pname = "cookbook";
-    version = "0.10.5";
+    version = "0.11.1";
     src = fetchTarball {
-      url = "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v0.10.5/Cookbook-0.10.5.tar.gz";
-      sha256 = "sha256-TE/w8SgyIPaGl5wZUAsG234nxoPj25QoRPF3zjbMoRk=";
+      url = "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v0.11.1/Cookbook-0.11.1.tar.gz";
+      sha256 = "sha256-a8ekMnEzudHGiqHF53jPtgsVTOTc2QLuPg6YtTw5h68=";
     };
   };
   news = {
     pname = "news";
-    version = "24.0.0";
+    version = "25.0.0-alpha7";
     src = fetchTarball {
-      url = "https://github.com/nextcloud/news/releases/download/24.0.0/news.tar.gz";
-      sha256 = "sha256-cfJkKRNSz15L4E3w1tnEb+t4MrVwVzb8lb6vCOA4cK4=";
+      url = "https://github.com/nextcloud/news/releases/download/25.0.0-alpha7/news.tar.gz";
+      sha256 = "sha256-XNGjf7SWgJYFdVNOh3ED0jxSG0GJwWImVQq4cJT1Lo4=";
     };
   };
   notes = {
diff --git a/pkgs/nextcloud-apps.toml b/pkgs/nextcloud-apps.toml
index 36566db..9023dd3 100644
--- a/pkgs/nextcloud-apps.toml
+++ b/pkgs/nextcloud-apps.toml
@@ -1,12 +1,10 @@
 [bookmarks]
-# src.github = "nextcloud/bookmarks"
+src.github = "nextcloud/bookmarks"
 src.prefix = "v"
-src.manual = "v13.1.3"
 fetch.tarball = "https://github.com/nextcloud/bookmarks/releases/download/v$ver/bookmarks-$ver.tar.gz"
 
 [calendar]
-# src.github = "nextcloud-releases/calendar"
-src.manual = "v4.6.7"
+src.github = "nextcloud-releases/calendar"
 fetch.tarball = "https://github.com/nextcloud-releases/calendar/releases/download/$ver/calendar-$ver.tar.gz"
 
 [contacts]
@@ -15,15 +13,14 @@ src.manual = "v5.5.3"
 fetch.tarball = "https://github.com/nextcloud-releases/contacts/releases/download/$ver/contacts-$ver.tar.gz"
 
 [cookbook]
-# src.github = "christianlupus-nextcloud/cookbook-releases"
+src.github = "christianlupus-nextcloud/cookbook-releases"
 src.prefix = "v"
-src.manual = "0.10.5"
 fetch.tarball = "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v$ver/Cookbook-$ver.tar.gz"
 
 [news]
+# Update manually until angular rewrite is done
 # src.github = "nextcloud/news"
-# Update to 25 when angular rewrite is done/the alpha when I need to switch to nextcloud 28+
-src.manual = "24.0.0"
+src.manual = "25.0.0-alpha7"
 fetch.tarball = "https://github.com/nextcloud/news/releases/download/$ver/news.tar.gz"
 
 [notes]

From 222829d82a7ffe2887ceaaefa13ed3a2e4b8963a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Mon, 1 Jul 2024 18:39:42 +0200
Subject: [PATCH 07/67] starbound: Don't build service for now

This includes the really huge steam-run closure, which is just a PITA
to keep up with if we're never using it.
---
 configuration/default.nix | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/configuration/default.nix b/configuration/default.nix
index b933d19..792a4c9 100644
--- a/configuration/default.nix
+++ b/configuration/default.nix
@@ -24,7 +24,7 @@
     ./services/nextcloud.nix
     ./services/webserver.nix
     ./services/wireguard.nix
-    ./services/starbound.nix
+    # ./services/starbound.nix -- Not currently used
     ./services/postgres.nix
     ./nginx.nix
     ./sops.nix
@@ -49,9 +49,6 @@
     settings.trusted-users = [ "@wheel" ];
   };
 
-  nixpkgs.config.allowUnfreePredicate = pkg:
-    builtins.elem (lib.getName pkg) [ "steam-original" "steam-runtime" "steam-run" "steamcmd" ];
-
   # Optimization for minecraft servers, see:
   # https://bugs.mojang.com/browse/MC-183518
   boot.kernelParams = [ "highres=off" "nohz=off" ];

From d568436d83126c7e92a1402e1551aa7235412481 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Mon, 1 Jul 2024 19:18:34 +0200
Subject: [PATCH 08/67] conduit: Use new upstream delegation support

---
 configuration/services/conduit.nix | 22 +++++++++-------------
 1 file changed, 9 insertions(+), 13 deletions(-)

diff --git a/configuration/services/conduit.nix b/configuration/services/conduit.nix
index 950165c..8734785 100644
--- a/configuration/services/conduit.nix
+++ b/configuration/services/conduit.nix
@@ -18,6 +18,13 @@ in
       server_name = domain;
       database_backend = "rocksdb";
 
+      # Set up delegation: https://docs.conduit.rs/delegation.html#automatic-recommended
+      # This is primarily to make sliding sync work
+      well_known = {
+        client = "https://${domain}";
+        server = "${domain}:443";
+      };
+
       turn_uris =
         let
           address = "${config.services.coturn.realm}:${toString config.services.coturn.listening-port}";
@@ -230,19 +237,8 @@ in
           proxy_buffering off;
         '';
       };
-
-      # Add Element X support
-      # TODO(tlater): Remove when no longer required: https://github.com/vector-im/element-x-android/issues/1085
-      "=/.well-known/matrix/client" = {
-        alias = pkgs.writeText "well-known-matrix-client" (builtins.toJSON {
-          "m.homeserver".base_url = "https://${domain}";
-          "org.matrix.msc3575.proxy".url = "https://${domain}";
-        });
-
-        extraConfig = ''
-          default_type application/json;
-          add_header Access-Control-Allow-Origin "*";
-        '';
+      "/.well-known/matrix" = {
+        proxyPass = "http://${cfg.settings.global.address}:${toString cfg.settings.global.port}";
       };
     };
   };

From 21b9112f76675cc23201433186d7ca25cb38ebf6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Mon, 1 Jul 2024 19:18:59 +0200
Subject: [PATCH 09/67] fail2ban-exporter: Bump generated source json/nix

---
 pkgs/_sources_pkgs/generated.json | 1 +
 pkgs/_sources_pkgs/generated.nix  | 1 +
 2 files changed, 2 insertions(+)

diff --git a/pkgs/_sources_pkgs/generated.json b/pkgs/_sources_pkgs/generated.json
index fc6c343..cec5a92 100644
--- a/pkgs/_sources_pkgs/generated.json
+++ b/pkgs/_sources_pkgs/generated.json
@@ -13,6 +13,7 @@
             "name": null,
             "rev": "v0.10.1",
             "sha256": "sha256-zGEhDy3uXIbvx4agSA8Mx7bRtiZZtoDZGbNbHc9L+yI=",
+            "sparseCheckout": [],
             "type": "git",
             "url": "https://gitlab.com/hectorjsmith/fail2ban-prometheus-exporter"
         },
diff --git a/pkgs/_sources_pkgs/generated.nix b/pkgs/_sources_pkgs/generated.nix
index 39dc6d0..95fd75e 100644
--- a/pkgs/_sources_pkgs/generated.nix
+++ b/pkgs/_sources_pkgs/generated.nix
@@ -10,6 +10,7 @@
       fetchSubmodules = false;
       deepClone = false;
       leaveDotGit = false;
+      sparseCheckout = [ ];
       sha256 = "sha256-zGEhDy3uXIbvx4agSA8Mx7bRtiZZtoDZGbNbHc9L+yI=";
     };
   };

From 306b69f6b543e785f929919a83c8169e281f25c8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Wed, 3 Jul 2024 01:28:23 +0200
Subject: [PATCH 10/67] nextcloud: Use the system postgres version

---
 configuration/services/nextcloud.nix | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/configuration/services/nextcloud.nix b/configuration/services/nextcloud.nix
index 0d22e6c..30adf6e 100644
--- a/configuration/services/nextcloud.nix
+++ b/configuration/services/nextcloud.nix
@@ -1,5 +1,6 @@
 { pkgs
 , config
+, lib
 , ...
 }:
 let
@@ -14,6 +15,19 @@ in
     inherit hostName;
 
     package = nextcloud;
+    phpPackage = lib.mkForce
+      (pkgs.php.override {
+        packageOverrides = final: prev: {
+          extensions = prev.extensions // {
+            pgsql = prev.extensions.pgsql.overrideAttrs (old: {
+              configureFlags = [ "--with-pgsql=${config.services.postgresql.package}" ];
+            });
+            pdo_pgsql = prev.extensions.pdo_pgsql.overrideAttrs (old: {
+              configureFlags = [ "--with-pdo-pgsql=${config.services.postgresql.package}" ];
+            });
+          };
+        };
+      });
     enable = true;
     maxUploadSize = "2G";
     https = true;

From d426e783cda4725e6b3e1bba2d726215676a502f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Wed, 3 Jul 2024 02:56:23 +0200
Subject: [PATCH 11/67] grafana: Properly proxy websocket connections

Fixes #115
---
 configuration/services/metrics/grafana.nix | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/configuration/services/metrics/grafana.nix b/configuration/services/metrics/grafana.nix
index d13fe7b..5c779f2 100644
--- a/configuration/services/metrics/grafana.nix
+++ b/configuration/services/metrics/grafana.nix
@@ -42,6 +42,12 @@ in
     forceSSL = true;
     useACMEHost = "tlater.net";
     enableHSTS = true;
-    locations."/".proxyPass = "http://localhost:${toString config.services.grafana.settings.server.http_port}";
+    locations = {
+      "/".proxyPass = "http://localhost:${toString config.services.grafana.settings.server.http_port}";
+      "/api/live" = {
+        proxyWebsockets = true;
+        proxyPass = "http://localhost:${toString config.services.grafana.settings.server.http_port}";
+      };
+    };
   };
 }

From 0047b585a38526f237615afa6e776d80c10d51c0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Mon, 5 Aug 2024 19:38:04 +0200
Subject: [PATCH 12/67] flake.lock: Update
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Flake lock file updates:

• Updated input 'disko':
    'github:nix-community/disko/d185770ea261fb5cf81aa5ad1791b93a7834d12c' (2024-06-30)
  → 'github:nix-community/disko/0257e44f4ad472b54f19a6dd1615aee7fa48ed49' (2024-08-05)
• Updated input 'foundryvtt':
    'github:reckenrode/nix-foundryvtt/1176cc325e5e1d46c7a018663a8e02e699e838ec' (2024-06-28)
  → 'github:reckenrode/nix-foundryvtt/699a175398410688214615a9d977354e9ef98d2d' (2024-08-03)
• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/10c832d0548e9e3a6df7eb51e68c2783212a303e' (2024-07-01)
  → 'github:nixos/nixpkgs/0ab9c4c1e0cab782fcde00ec2b32436abfd2a6d4' (2024-08-05)
• Updated input 'nixpkgs-unstable':
    'github:nixos/nixpkgs/7f993cdf26ccef564eabf31fdb40d140821e12bc' (2024-07-01)
  → 'github:nixos/nixpkgs/41d21a82c38e226e234e16f4ff213b3fcf85e6e9' (2024-08-05)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/b5974d4331fb6c893e808977a2e1a6d34b3162d6' (2024-06-30)
  → 'github:Mic92/sops-nix/eb34eb588132d653e4c4925d862f1e5a227cc2ab' (2024-07-27)
• Updated input 'sops-nix/nixpkgs-stable':
    'github:NixOS/nixpkgs/4a1e673523344f6ccc84b37f4413ad74ea19a119' (2024-06-29)
  → 'github:NixOS/nixpkgs/556533a23879fc7e5f98dd2e0b31a6911a213171' (2024-07-21)
---
 flake.lock | 38 +++++++++++++++++++-------------------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/flake.lock b/flake.lock
index dab6ebf..c541444 100644
--- a/flake.lock
+++ b/flake.lock
@@ -27,11 +27,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1719733833,
-        "narHash": "sha256-6h2EqZU9bL9rHlXE+2LCBgnDImejzbS+4dYsNDDFlkY=",
+        "lastModified": 1722821805,
+        "narHash": "sha256-FGrUPUD+LMDwJsYyNSxNIzFMldtCm8wXiQuyL2PHSrM=",
         "owner": "nix-community",
         "repo": "disko",
-        "rev": "d185770ea261fb5cf81aa5ad1791b93a7834d12c",
+        "rev": "0257e44f4ad472b54f19a6dd1615aee7fa48ed49",
         "type": "github"
       },
       "original": {
@@ -157,11 +157,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1719541573,
-        "narHash": "sha256-9j8Rtv5UWsD4A3jAh8MpopNGmftSAoI8htssmXLu8jU=",
+        "lastModified": 1722661736,
+        "narHash": "sha256-0lujsK40JV/2PlqCjhZMGpHKL4vDKzJcnkFJYnG1WZA=",
         "owner": "reckenrode",
         "repo": "nix-foundryvtt",
-        "rev": "1176cc325e5e1d46c7a018663a8e02e699e838ec",
+        "rev": "699a175398410688214615a9d977354e9ef98d2d",
         "type": "github"
       },
       "original": {
@@ -210,27 +210,27 @@
     },
     "nixpkgs-stable": {
       "locked": {
-        "lastModified": 1719663039,
-        "narHash": "sha256-tXlrgAQygNIy49LDVFuPXlWD2zTQV9/F8pfoqwwPJyo=",
+        "lastModified": 1721524707,
+        "narHash": "sha256-5NctRsoE54N86nWd0psae70YSLfrOek3Kv1e8KoXe/0=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "4a1e673523344f6ccc84b37f4413ad74ea19a119",
+        "rev": "556533a23879fc7e5f98dd2e0b31a6911a213171",
         "type": "github"
       },
       "original": {
         "owner": "NixOS",
-        "ref": "release-23.11",
+        "ref": "release-24.05",
         "repo": "nixpkgs",
         "type": "github"
       }
     },
     "nixpkgs-unstable": {
       "locked": {
-        "lastModified": 1719824438,
-        "narHash": "sha256-pY0wosAgcr9W4vmGML0T3BVhQiGuKoozCbs2t+Je1zc=",
+        "lastModified": 1722849152,
+        "narHash": "sha256-Es/syckEivSAJWxVF6vRYAFMAgXhJpIPdxMwN70NYxo=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "7f993cdf26ccef564eabf31fdb40d140821e12bc",
+        "rev": "41d21a82c38e226e234e16f4ff213b3fcf85e6e9",
         "type": "github"
       },
       "original": {
@@ -242,11 +242,11 @@
     },
     "nixpkgs_2": {
       "locked": {
-        "lastModified": 1719825363,
-        "narHash": "sha256-2ASBatUTQWNIiTeBZRuxROu27MyOavVnzeCv7h40QNw=",
+        "lastModified": 1722821716,
+        "narHash": "sha256-VZMyGaYBuuQ+PCF4iRNeqJ/lbowOMQnnVF2Vg0tR3Dk=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "10c832d0548e9e3a6df7eb51e68c2783212a303e",
+        "rev": "0ab9c4c1e0cab782fcde00ec2b32436abfd2a6d4",
         "type": "github"
       },
       "original": {
@@ -442,11 +442,11 @@
         "nixpkgs-stable": "nixpkgs-stable"
       },
       "locked": {
-        "lastModified": 1719716556,
-        "narHash": "sha256-KA9gy2Wkv76s4A8eLnOcdKVTygewbw3xsB8+awNMyqs=",
+        "lastModified": 1722114803,
+        "narHash": "sha256-s6YhI8UHwQvO4cIFLwl1wZ1eS5Cuuw7ld2VzUchdFP0=",
         "owner": "Mic92",
         "repo": "sops-nix",
-        "rev": "b5974d4331fb6c893e808977a2e1a6d34b3162d6",
+        "rev": "eb34eb588132d653e4c4925d862f1e5a227cc2ab",
         "type": "github"
       },
       "original": {

From e1bd183cdda6a61930cffa4061e688a5a5bfc981 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Mon, 5 Aug 2024 19:42:55 +0200
Subject: [PATCH 13/67] pkgs: Update sources

---
 pkgs/_sources_nextcloud/generated.json | 24 ++++++++++++------------
 pkgs/_sources_nextcloud/generated.nix  | 24 ++++++++++++------------
 pkgs/nextcloud-apps.toml               |  6 +++---
 3 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/pkgs/_sources_nextcloud/generated.json b/pkgs/_sources_nextcloud/generated.json
index c216c8d..73a69ea 100644
--- a/pkgs/_sources_nextcloud/generated.json
+++ b/pkgs/_sources_nextcloud/generated.json
@@ -7,11 +7,11 @@
         "passthru": null,
         "pinned": false,
         "src": {
-            "sha256": "sha256-wUeXcbxNCRA2brzdCHKwl0zbhmDucKv1ZCkF3KlQ8O4=",
+            "sha256": "sha256-32xlI+cQNlJT255F3lmx04FkeZdzd93YzSA3wPcETlQ=",
             "type": "tarball",
-            "url": "https://github.com/nextcloud/bookmarks/releases/download/v14.2.2/bookmarks-14.2.2.tar.gz"
+            "url": "https://github.com/nextcloud/bookmarks/releases/download/v14.2.3/bookmarks-14.2.3.tar.gz"
         },
-        "version": "14.2.2"
+        "version": "14.2.3"
     },
     "calendar": {
         "cargoLocks": null,
@@ -21,11 +21,11 @@
         "passthru": null,
         "pinned": false,
         "src": {
-            "sha256": "sha256-cuAqJz1cZ+VfxttAKjWIe11DFwWGLdSSvcNJKQKidgk=",
+            "sha256": "sha256-k73g1SpepMz0kBWX67dLahE/vE1AgTzTV+Sq6UBNPuU=",
             "type": "tarball",
-            "url": "https://github.com/nextcloud-releases/calendar/releases/download/v4.7.8/calendar-v4.7.8.tar.gz"
+            "url": "https://github.com/nextcloud-releases/calendar/releases/download/v4.7.14/calendar-v4.7.14.tar.gz"
         },
-        "version": "v4.7.8"
+        "version": "v4.7.14"
     },
     "contacts": {
         "cargoLocks": null,
@@ -63,11 +63,11 @@
         "passthru": null,
         "pinned": false,
         "src": {
-            "sha256": "sha256-XNGjf7SWgJYFdVNOh3ED0jxSG0GJwWImVQq4cJT1Lo4=",
+            "sha256": "sha256-AhTZGQCLeNgsRBF5w3+Lf9JtNN4D1QncB5t+odU+XUc=",
             "type": "tarball",
-            "url": "https://github.com/nextcloud/news/releases/download/25.0.0-alpha7/news.tar.gz"
+            "url": "https://github.com/nextcloud/news/releases/download/25.0.0-alpha8/news.tar.gz"
         },
-        "version": "25.0.0-alpha7"
+        "version": "25.0.0-alpha8"
     },
     "notes": {
         "cargoLocks": null,
@@ -77,10 +77,10 @@
         "passthru": null,
         "pinned": false,
         "src": {
-            "sha256": "sha256-ydpxatwuZUz7XIgK8FMklZlxNQklpsP8Uqpxvt3iK0k=",
+            "sha256": "sha256-A3QNWGWeC2OcZngMrh9NpYbU5qp5x9xiDcRfB9cRXBo=",
             "type": "tarball",
-            "url": "https://github.com/nextcloud/notes/releases/download/v4.10.0/notes.tar.gz"
+            "url": "https://github.com/nextcloud-releases/notes/releases/download/v4.10.1/notes-v4.10.1.tar.gz"
         },
-        "version": "v4.10.0"
+        "version": "v4.10.1"
     }
 }
\ No newline at end of file
diff --git a/pkgs/_sources_nextcloud/generated.nix b/pkgs/_sources_nextcloud/generated.nix
index 3075206..918c8d2 100644
--- a/pkgs/_sources_nextcloud/generated.nix
+++ b/pkgs/_sources_nextcloud/generated.nix
@@ -3,18 +3,18 @@
 {
   bookmarks = {
     pname = "bookmarks";
-    version = "14.2.2";
+    version = "14.2.3";
     src = fetchTarball {
-      url = "https://github.com/nextcloud/bookmarks/releases/download/v14.2.2/bookmarks-14.2.2.tar.gz";
-      sha256 = "sha256-wUeXcbxNCRA2brzdCHKwl0zbhmDucKv1ZCkF3KlQ8O4=";
+      url = "https://github.com/nextcloud/bookmarks/releases/download/v14.2.3/bookmarks-14.2.3.tar.gz";
+      sha256 = "sha256-32xlI+cQNlJT255F3lmx04FkeZdzd93YzSA3wPcETlQ=";
     };
   };
   calendar = {
     pname = "calendar";
-    version = "v4.7.8";
+    version = "v4.7.14";
     src = fetchTarball {
-      url = "https://github.com/nextcloud-releases/calendar/releases/download/v4.7.8/calendar-v4.7.8.tar.gz";
-      sha256 = "sha256-cuAqJz1cZ+VfxttAKjWIe11DFwWGLdSSvcNJKQKidgk=";
+      url = "https://github.com/nextcloud-releases/calendar/releases/download/v4.7.14/calendar-v4.7.14.tar.gz";
+      sha256 = "sha256-k73g1SpepMz0kBWX67dLahE/vE1AgTzTV+Sq6UBNPuU=";
     };
   };
   contacts = {
@@ -35,18 +35,18 @@
   };
   news = {
     pname = "news";
-    version = "25.0.0-alpha7";
+    version = "25.0.0-alpha8";
     src = fetchTarball {
-      url = "https://github.com/nextcloud/news/releases/download/25.0.0-alpha7/news.tar.gz";
-      sha256 = "sha256-XNGjf7SWgJYFdVNOh3ED0jxSG0GJwWImVQq4cJT1Lo4=";
+      url = "https://github.com/nextcloud/news/releases/download/25.0.0-alpha8/news.tar.gz";
+      sha256 = "sha256-AhTZGQCLeNgsRBF5w3+Lf9JtNN4D1QncB5t+odU+XUc=";
     };
   };
   notes = {
     pname = "notes";
-    version = "v4.10.0";
+    version = "v4.10.1";
     src = fetchTarball {
-      url = "https://github.com/nextcloud/notes/releases/download/v4.10.0/notes.tar.gz";
-      sha256 = "sha256-ydpxatwuZUz7XIgK8FMklZlxNQklpsP8Uqpxvt3iK0k=";
+      url = "https://github.com/nextcloud-releases/notes/releases/download/v4.10.1/notes-v4.10.1.tar.gz";
+      sha256 = "sha256-A3QNWGWeC2OcZngMrh9NpYbU5qp5x9xiDcRfB9cRXBo=";
     };
   };
 }
diff --git a/pkgs/nextcloud-apps.toml b/pkgs/nextcloud-apps.toml
index 9023dd3..89dccb4 100644
--- a/pkgs/nextcloud-apps.toml
+++ b/pkgs/nextcloud-apps.toml
@@ -20,9 +20,9 @@ fetch.tarball = "https://github.com/christianlupus-nextcloud/cookbook-releases/r
 [news]
 # Update manually until angular rewrite is done
 # src.github = "nextcloud/news"
-src.manual = "25.0.0-alpha7"
+src.manual = "25.0.0-alpha8"
 fetch.tarball = "https://github.com/nextcloud/news/releases/download/$ver/news.tar.gz"
 
 [notes]
-src.github = "nextcloud/notes"
-fetch.tarball = "https://github.com/nextcloud/notes/releases/download/$ver/notes.tar.gz"
+src.github = "nextcloud-releases/notes"
+fetch.tarball = "https://github.com/nextcloud-releases/notes/releases/download/$ver/notes-$ver.tar.gz"

From 521190297bc2fa7380383df26ba559053ab246d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sun, 18 Aug 2024 17:24:45 +0200
Subject: [PATCH 14/67] flake.lock: Update
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Flake lock file updates:

• Updated input 'disko':
    'github:nix-community/disko/0257e44f4ad472b54f19a6dd1615aee7fa48ed49' (2024-08-05)
  → 'github:nix-community/disko/276a0d055a720691912c6a34abb724e395c8e38a' (2024-08-15)
• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/0ab9c4c1e0cab782fcde00ec2b32436abfd2a6d4' (2024-08-05)
  → 'github:nixos/nixpkgs/1cbd3d585263dc620c483e138d352a39b9f0e3ec' (2024-08-17)
• Updated input 'nixpkgs-unstable':
    'github:nixos/nixpkgs/41d21a82c38e226e234e16f4ff213b3fcf85e6e9' (2024-08-05)
  → 'github:nixos/nixpkgs/abcef4da4ebb72240bddc370a27263627e64877f' (2024-08-18)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/eb34eb588132d653e4c4925d862f1e5a227cc2ab' (2024-07-27)
  → 'github:Mic92/sops-nix/be0eec2d27563590194a9206f551a6f73d52fa34' (2024-08-12)
---
 flake.lock | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/flake.lock b/flake.lock
index c541444..78327bf 100644
--- a/flake.lock
+++ b/flake.lock
@@ -27,11 +27,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1722821805,
-        "narHash": "sha256-FGrUPUD+LMDwJsYyNSxNIzFMldtCm8wXiQuyL2PHSrM=",
+        "lastModified": 1723685519,
+        "narHash": "sha256-GkXQIoZmW2zCPp1YFtAYGg/xHNyFH/Mgm79lcs81rq0=",
         "owner": "nix-community",
         "repo": "disko",
-        "rev": "0257e44f4ad472b54f19a6dd1615aee7fa48ed49",
+        "rev": "276a0d055a720691912c6a34abb724e395c8e38a",
         "type": "github"
       },
       "original": {
@@ -226,11 +226,11 @@
     },
     "nixpkgs-unstable": {
       "locked": {
-        "lastModified": 1722849152,
-        "narHash": "sha256-Es/syckEivSAJWxVF6vRYAFMAgXhJpIPdxMwN70NYxo=",
+        "lastModified": 1723957280,
+        "narHash": "sha256-J08Yqf2IJ73y7myI69qEKsQ048ibweG6FeJeCxbIdB4=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "41d21a82c38e226e234e16f4ff213b3fcf85e6e9",
+        "rev": "abcef4da4ebb72240bddc370a27263627e64877f",
         "type": "github"
       },
       "original": {
@@ -242,11 +242,11 @@
     },
     "nixpkgs_2": {
       "locked": {
-        "lastModified": 1722821716,
-        "narHash": "sha256-VZMyGaYBuuQ+PCF4iRNeqJ/lbowOMQnnVF2Vg0tR3Dk=",
+        "lastModified": 1723920526,
+        "narHash": "sha256-USs6A60raDKZ/8BEpqja1XjZIsRzADX+NtWKH6wIxIw=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "0ab9c4c1e0cab782fcde00ec2b32436abfd2a6d4",
+        "rev": "1cbd3d585263dc620c483e138d352a39b9f0e3ec",
         "type": "github"
       },
       "original": {
@@ -442,11 +442,11 @@
         "nixpkgs-stable": "nixpkgs-stable"
       },
       "locked": {
-        "lastModified": 1722114803,
-        "narHash": "sha256-s6YhI8UHwQvO4cIFLwl1wZ1eS5Cuuw7ld2VzUchdFP0=",
+        "lastModified": 1723501126,
+        "narHash": "sha256-N9IcHgj/p1+2Pvk8P4Zc1bfrMwld5PcosVA0nL6IGdE=",
         "owner": "Mic92",
         "repo": "sops-nix",
-        "rev": "eb34eb588132d653e4c4925d862f1e5a227cc2ab",
+        "rev": "be0eec2d27563590194a9206f551a6f73d52fa34",
         "type": "github"
       },
       "original": {

From 0ad265f6aa269c953c76cbc998550a864ec72653 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sun, 18 Aug 2024 18:51:16 +0200
Subject: [PATCH 15/67] pkgs/sources: Update package sources

---
 pkgs/_sources_nextcloud/generated.json | 12 ++++++------
 pkgs/_sources_nextcloud/generated.nix  | 12 ++++++------
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/pkgs/_sources_nextcloud/generated.json b/pkgs/_sources_nextcloud/generated.json
index 73a69ea..4071726 100644
--- a/pkgs/_sources_nextcloud/generated.json
+++ b/pkgs/_sources_nextcloud/generated.json
@@ -7,11 +7,11 @@
         "passthru": null,
         "pinned": false,
         "src": {
-            "sha256": "sha256-32xlI+cQNlJT255F3lmx04FkeZdzd93YzSA3wPcETlQ=",
+            "sha256": "sha256-V4zZsAwPn8QiCXEDqOgNFHaXqMOcHMpMbJ1Oz3Db0pc=",
             "type": "tarball",
-            "url": "https://github.com/nextcloud/bookmarks/releases/download/v14.2.3/bookmarks-14.2.3.tar.gz"
+            "url": "https://github.com/nextcloud/bookmarks/releases/download/v14.2.4/bookmarks-14.2.4.tar.gz"
         },
-        "version": "14.2.3"
+        "version": "14.2.4"
     },
     "calendar": {
         "cargoLocks": null,
@@ -21,11 +21,11 @@
         "passthru": null,
         "pinned": false,
         "src": {
-            "sha256": "sha256-k73g1SpepMz0kBWX67dLahE/vE1AgTzTV+Sq6UBNPuU=",
+            "sha256": "sha256-sipXeyOL4OhENz7V2beFeSYBAoFZdCWtqftIy0lsqEY=",
             "type": "tarball",
-            "url": "https://github.com/nextcloud-releases/calendar/releases/download/v4.7.14/calendar-v4.7.14.tar.gz"
+            "url": "https://github.com/nextcloud-releases/calendar/releases/download/v4.7.15/calendar-v4.7.15.tar.gz"
         },
-        "version": "v4.7.14"
+        "version": "v4.7.15"
     },
     "contacts": {
         "cargoLocks": null,
diff --git a/pkgs/_sources_nextcloud/generated.nix b/pkgs/_sources_nextcloud/generated.nix
index 918c8d2..53e26d1 100644
--- a/pkgs/_sources_nextcloud/generated.nix
+++ b/pkgs/_sources_nextcloud/generated.nix
@@ -3,18 +3,18 @@
 {
   bookmarks = {
     pname = "bookmarks";
-    version = "14.2.3";
+    version = "14.2.4";
     src = fetchTarball {
-      url = "https://github.com/nextcloud/bookmarks/releases/download/v14.2.3/bookmarks-14.2.3.tar.gz";
-      sha256 = "sha256-32xlI+cQNlJT255F3lmx04FkeZdzd93YzSA3wPcETlQ=";
+      url = "https://github.com/nextcloud/bookmarks/releases/download/v14.2.4/bookmarks-14.2.4.tar.gz";
+      sha256 = "sha256-V4zZsAwPn8QiCXEDqOgNFHaXqMOcHMpMbJ1Oz3Db0pc=";
     };
   };
   calendar = {
     pname = "calendar";
-    version = "v4.7.14";
+    version = "v4.7.15";
     src = fetchTarball {
-      url = "https://github.com/nextcloud-releases/calendar/releases/download/v4.7.14/calendar-v4.7.14.tar.gz";
-      sha256 = "sha256-k73g1SpepMz0kBWX67dLahE/vE1AgTzTV+Sq6UBNPuU=";
+      url = "https://github.com/nextcloud-releases/calendar/releases/download/v4.7.15/calendar-v4.7.15.tar.gz";
+      sha256 = "sha256-sipXeyOL4OhENz7V2beFeSYBAoFZdCWtqftIy0lsqEY=";
     };
   };
   contacts = {

From 3a591863b01d275a472ae6706bb58ed4794b305e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sun, 18 Aug 2024 17:36:45 +0200
Subject: [PATCH 16/67] flake.nix: Add default package to allow easily creating
 gc root

---
 flake.nix | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/flake.nix b/flake.nix
index e3ff531..56f3972 100644
--- a/flake.nix
+++ b/flake.nix
@@ -43,6 +43,16 @@
     let
       system = "x86_64-linux";
       pkgs = nixpkgs.legacyPackages.${system};
+
+      vm = nixpkgs.lib.nixosSystem {
+        inherit system;
+        specialArgs.flake-inputs = inputs;
+
+        modules = [
+          ./configuration
+          ./configuration/hardware-specific/vm.nix
+        ];
+      };
     in
     {
       ##################
@@ -83,6 +93,12 @@
       #########
       checks = builtins.mapAttrs (system: deployLib: deployLib.deployChecks self.deploy) deploy-rs.lib;
 
+      ###########################
+      # Garbage collection root #
+      ###########################
+
+      packages.${system}.default = vm.config.system.build.vm;
+
       ###################
       # Utility scripts #
       ###################
@@ -93,15 +109,6 @@
           type = "app";
           program =
             let
-              vm = nixpkgs.lib.nixosSystem {
-                inherit system;
-                specialArgs.flake-inputs = inputs;
-
-                modules = [
-                  ./configuration
-                  ./configuration/hardware-specific/vm.nix
-                ];
-              };
             in
             (pkgs.writeShellScript "" ''
               ${vm.config.system.build.vm.outPath}/bin/run-testvm-vm

From 04f7a7ef1d38906163afc9cddfa8ce2b0ebf3b45 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sun, 18 Aug 2024 20:41:20 +0200
Subject: [PATCH 17/67] treewide: Use nixfmt for formatting

---
 configuration/default.nix                     |  21 +-
 .../hardware-specific/hetzner/default.nix     |   4 +-
 .../hardware-specific/hetzner/disko.nix       |  15 +-
 configuration/hardware-specific/vm.nix        |   3 +-
 configuration/nginx.nix                       |  47 ++-
 configuration/services/afvalcalendar.nix      |  19 +-
 configuration/services/backups.nix            | 308 +++++++++---------
 configuration/services/battery-manager.nix    |  10 +-
 configuration/services/conduit.nix            |  65 ++--
 configuration/services/fail2ban.nix           |   3 +-
 configuration/services/foundryvtt.nix         |  15 +-
 configuration/services/gitea.nix              |  13 +-
 configuration/services/metrics/exporters.nix  |  50 ++-
 configuration/services/metrics/options.nix    | 218 +++++++------
 .../services/metrics/victoriametrics.nix      |   7 +-
 configuration/services/nextcloud.nix          |  25 +-
 configuration/services/postgres.nix           |   3 +-
 configuration/services/starbound.nix          |   9 +-
 configuration/services/wireguard.nix          |   3 +-
 flake.nix                                     |  29 +-
 modules/default.nix                           |   6 +-
 modules/nginxExtensions.nix                   |  34 +-
 pkgs/afvalcalendar/default.nix                |  13 +-
 pkgs/default.nix                              |   7 +-
 pkgs/mkNextcloudApp.nix                       |   6 +-
 pkgs/prometheus/fail2ban-exporter.nix         |   5 +-
 pkgs/starbound/default.nix                    |  24 +-
 27 files changed, 496 insertions(+), 466 deletions(-)

diff --git a/configuration/default.nix b/configuration/default.nix
index 792a4c9..333488b 100644
--- a/configuration/default.nix
+++ b/configuration/default.nix
@@ -1,10 +1,12 @@
-{ config
-, pkgs
-, lib
-, modulesPath
-, flake-inputs
-, ...
-}: {
+{
+  config,
+  pkgs,
+  lib,
+  modulesPath,
+  flake-inputs,
+  ...
+}:
+{
   imports = [
     flake-inputs.disko.nixosModules.disko
     flake-inputs.sops-nix.nixosModules.sops
@@ -51,7 +53,10 @@
 
   # Optimization for minecraft servers, see:
   # https://bugs.mojang.com/browse/MC-183518
-  boot.kernelParams = [ "highres=off" "nohz=off" ];
+  boot.kernelParams = [
+    "highres=off"
+    "nohz=off"
+  ];
 
   networking = {
     usePredictableInterfaceNames = false;
diff --git a/configuration/hardware-specific/hetzner/default.nix b/configuration/hardware-specific/hetzner/default.nix
index 3106f19..6795377 100644
--- a/configuration/hardware-specific/hetzner/default.nix
+++ b/configuration/hardware-specific/hetzner/default.nix
@@ -25,9 +25,7 @@
         };
       }
       # IPv6
-      {
-        addressConfig.Address = "2a01:4f8:10b:3c85::2/64";
-      }
+      { addressConfig.Address = "2a01:4f8:10b:3c85::2/64"; }
     ];
 
     networkConfig = {
diff --git a/configuration/hardware-specific/hetzner/disko.nix b/configuration/hardware-specific/hetzner/disko.nix
index a2ea764..cc15471 100644
--- a/configuration/hardware-specific/hetzner/disko.nix
+++ b/configuration/hardware-specific/hetzner/disko.nix
@@ -19,7 +19,10 @@
         };
       };
 
-      mountOptions = [ "compress=zstd" "noatime" ];
+      mountOptions = [
+        "compress=zstd"
+        "noatime"
+      ];
     in
     {
       sda = {
@@ -54,7 +57,15 @@
                 type = "btrfs";
                 # Hack to get multi-device btrfs going
                 # See https://github.com/nix-community/disko/issues/99
-                extraArgs = [ "-d" "raid1" "-m" "raid1" "--runtime-features" "quota" "/dev/sda3" ];
+                extraArgs = [
+                  "-d"
+                  "raid1"
+                  "-m"
+                  "raid1"
+                  "--runtime-features"
+                  "quota"
+                  "/dev/sda3"
+                ];
                 subvolumes = {
                   "/volume" = { };
                   "/volume/root" = {
diff --git a/configuration/hardware-specific/vm.nix b/configuration/hardware-specific/vm.nix
index 86fcaed..1783956 100644
--- a/configuration/hardware-specific/vm.nix
+++ b/configuration/hardware-specific/vm.nix
@@ -1,4 +1,5 @@
-{ lib, ... }: {
+{ lib, ... }:
+{
   users.users.tlater.password = "insecure";
 
   # Disable graphical tty so -curses works
diff --git a/configuration/nginx.nix b/configuration/nginx.nix
index d696bba..b38118b 100644
--- a/configuration/nginx.nix
+++ b/configuration/nginx.nix
@@ -1,7 +1,5 @@
-{ config
-, lib
-, ...
-}: {
+{ config, lib, ... }:
+{
   services.nginx = {
     enable = true;
     recommendedTlsSettings = true;
@@ -26,26 +24,23 @@
       # Override the default, just keep fewer logs
       nginx.rotate = 6;
     }
-    // lib.mapAttrs'
-      (virtualHost: _:
-        lib.nameValuePair "/var/log/nginx/${virtualHost}/access.log" {
-          frequency = "daily";
-          rotate = 2;
-          compress = true;
-          delaycompress = true;
-          su = "${config.services.nginx.user} ${config.services.nginx.group}";
-          postrotate = "[ ! -f /var/run/nginx/nginx.pid ] || kill -USR1 `cat /var/run/nginx/nginx.pid`";
-        })
-      config.services.nginx.virtualHosts;
+    // lib.mapAttrs' (
+      virtualHost: _:
+      lib.nameValuePair "/var/log/nginx/${virtualHost}/access.log" {
+        frequency = "daily";
+        rotate = 2;
+        compress = true;
+        delaycompress = true;
+        su = "${config.services.nginx.user} ${config.services.nginx.group}";
+        postrotate = "[ ! -f /var/run/nginx/nginx.pid ] || kill -USR1 `cat /var/run/nginx/nginx.pid`";
+      }
+    ) config.services.nginx.virtualHosts;
 
-  systemd.tmpfiles.rules =
-    lib.mapAttrsToList
-      (
-        virtualHost: _:
-          #
-          "d /var/log/nginx/${virtualHost} 0750 ${config.services.nginx.user} ${config.services.nginx.group}"
-      )
-      config.services.nginx.virtualHosts;
+  systemd.tmpfiles.rules = lib.mapAttrsToList (
+    virtualHost: _:
+    #
+    "d /var/log/nginx/${virtualHost} 0750 ${config.services.nginx.user} ${config.services.nginx.group}"
+  ) config.services.nginx.virtualHosts;
 
   security.acme = {
     defaults.email = "tm@tlater.net";
@@ -61,8 +56,8 @@
 
   services.backups.acme = {
     user = "acme";
-    paths =
-      lib.mapAttrsToList (virtualHost: _: "/var/lib/acme/${virtualHost}")
-        config.services.nginx.virtualHosts;
+    paths = lib.mapAttrsToList (
+      virtualHost: _: "/var/lib/acme/${virtualHost}"
+    ) config.services.nginx.virtualHosts;
   };
 }
diff --git a/configuration/services/afvalcalendar.nix b/configuration/services/afvalcalendar.nix
index 28e3a75..ec7d9f7 100644
--- a/configuration/services/afvalcalendar.nix
+++ b/configuration/services/afvalcalendar.nix
@@ -1,7 +1,5 @@
-{ pkgs
-, config
-, ...
-}: {
+{ pkgs, config, ... }:
+{
   systemd.services.afvalcalendar = {
     description = "Enschede afvalcalendar -> ical converter";
     wantedBy = [ "multi-user.target" ];
@@ -25,16 +23,23 @@
       ProtectKernelModules = true;
       ProtectKernelLogs = true;
       ProtectControlGroups = true;
-      RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
+      RestrictAddressFamilies = [
+        "AF_UNIX"
+        "AF_INET"
+        "AF_INET6"
+      ];
       RestrictNamespaces = true;
       LockPersonality = true;
       MemoryDenyWriteExecute = true;
       RestrictRealtime = true;
       RestrictSUIDSGID = true;
       SystemCallArchitectures = "native";
-      SystemCallFilter = [ "@system-service" "~@privileged @resources @setuid @keyring" ];
+      SystemCallFilter = [
+        "@system-service"
+        "~@privileged @resources @setuid @keyring"
+      ];
 
-      Umask = 0002;
+      Umask = 2;
       SupplementaryGroups = "afvalcalendar-hosting";
 
       ReadWritePaths = "/srv/afvalcalendar";
diff --git a/configuration/services/backups.nix b/configuration/services/backups.nix
index 7c77399..81e3554 100644
--- a/configuration/services/backups.nix
+++ b/configuration/services/backups.nix
@@ -1,29 +1,35 @@
-{ config
-, pkgs
-, lib
-, ...
+{
+  config,
+  pkgs,
+  lib,
+  ...
 }:
 let
   inherit (lib) types optional singleton;
-  mkShutdownScript = service:
+  mkShutdownScript =
+    service:
     pkgs.writeShellScript "backup-${service}-shutdown" ''
       if systemctl is-active --quiet '${service}'; then
         touch '/tmp/${service}-was-active'
         systemctl stop '${service}'
       fi
     '';
-  mkRestartScript = service:
+  mkRestartScript =
+    service:
     pkgs.writeShellScript "backup-${service}-restart" ''
       if [ -f '/tmp/${service}-was-active' ]; then
         rm '/tmp/${service}-was-active'
         systemctl start '${service}'
       fi
     '';
-  writeScript = name: packages: text:
-    lib.getExe (pkgs.writeShellApplication {
-      inherit name text;
-      runtimeInputs = packages;
-    });
+  writeScript =
+    name: packages: text:
+    lib.getExe (
+      pkgs.writeShellApplication {
+        inherit name text;
+        runtimeInputs = packages;
+      }
+    );
 
   # *NOT* a TOML file, for some reason quotes are interpreted
   # *literally
@@ -49,85 +55,87 @@ in
       description = lib.mdDoc ''
         Configure restic backups with a specific tag.
       '';
-      type = types.attrsOf (types.submodule ({ config
-                                             , name
-                                             , ...
-                                             }: {
-        options = {
-          user = lib.mkOption {
-            type = types.str;
-            description = ''
-              The user as which to run the backup.
-            '';
-          };
-          paths = lib.mkOption {
-            type = types.listOf types.str;
-            description = ''
-              The paths to back up.
-            '';
-          };
-          tag = lib.mkOption {
-            type = types.str;
-            description = ''
-              The restic tag to mark the backup with.
-            '';
-            default = name;
-          };
-          preparation = {
-            packages = lib.mkOption {
-              type = types.listOf types.package;
-              default = [ ];
-              description = ''
-                The list of packages to make available in the
-                preparation script.
-              '';
-            };
-            text = lib.mkOption {
-              type = types.nullOr types.str;
-              default = null;
-              description = ''
-                The preparation script to run before the backup.
+      type = types.attrsOf (
+        types.submodule (
+          { config, name, ... }:
+          {
+            options = {
+              user = lib.mkOption {
+                type = types.str;
+                description = ''
+                  The user as which to run the backup.
+                '';
+              };
+              paths = lib.mkOption {
+                type = types.listOf types.str;
+                description = ''
+                  The paths to back up.
+                '';
+              };
+              tag = lib.mkOption {
+                type = types.str;
+                description = ''
+                  The restic tag to mark the backup with.
+                '';
+                default = name;
+              };
+              preparation = {
+                packages = lib.mkOption {
+                  type = types.listOf types.package;
+                  default = [ ];
+                  description = ''
+                    The list of packages to make available in the
+                    preparation script.
+                  '';
+                };
+                text = lib.mkOption {
+                  type = types.nullOr types.str;
+                  default = null;
+                  description = ''
+                    The preparation script to run before the backup.
 
-                This should include things like database dumps and
-                enabling maintenance modes. If a service needs to be
-                shut down for backups, use `pauseServices` instead.
-              '';
-            };
-          };
-          cleanup = {
-            packages = lib.mkOption {
-              type = types.listOf types.package;
-              default = [ ];
-              description = ''
-                The list of packages to make available in the
-                cleanup script.
-              '';
-            };
-            text = lib.mkOption {
-              type = types.nullOr types.str;
-              default = null;
-              description = ''
-                The cleanup script to run after the backup.
+                    This should include things like database dumps and
+                    enabling maintenance modes. If a service needs to be
+                    shut down for backups, use `pauseServices` instead.
+                  '';
+                };
+              };
+              cleanup = {
+                packages = lib.mkOption {
+                  type = types.listOf types.package;
+                  default = [ ];
+                  description = ''
+                    The list of packages to make available in the
+                    cleanup script.
+                  '';
+                };
+                text = lib.mkOption {
+                  type = types.nullOr types.str;
+                  default = null;
+                  description = ''
+                    The cleanup script to run after the backup.
 
-                This should do things like cleaning up database dumps
-                and disabling maintenance modes.
-              '';
-            };
-          };
-          pauseServices = lib.mkOption {
-            type = types.listOf types.str;
-            default = [ ];
-            description = ''
-              The systemd services that need to be shut down before
-              the backup can run. Services will be restarted after the
-              backup is complete.
+                    This should do things like cleaning up database dumps
+                    and disabling maintenance modes.
+                  '';
+                };
+              };
+              pauseServices = lib.mkOption {
+                type = types.listOf types.str;
+                default = [ ];
+                description = ''
+                  The systemd services that need to be shut down before
+                  the backup can run. Services will be restarted after the
+                  backup is complete.
 
-              This is intended to be used for services that do not
-              support hot backups.
-            '';
-          };
-        };
-      }));
+                  This is intended to be used for services that do not
+                  support hot backups.
+                '';
+              };
+            };
+          }
+        )
+      );
     };
   };
 
@@ -164,58 +172,68 @@ in
           };
         };
       }
-      // lib.mapAttrs'
-        (name: backup:
-          lib.nameValuePair "backup-${name}" {
-            # Don't want to restart mid-backup
-            restartIfChanged = false;
+      // lib.mapAttrs' (
+        name: backup:
+        lib.nameValuePair "backup-${name}" {
+          # Don't want to restart mid-backup
+          restartIfChanged = false;
 
-            environment =
-              resticEnv
-              // {
-                RESTIC_CACHE_DIR = "%C/backup-${name}";
-              };
+          environment = resticEnv // {
+            RESTIC_CACHE_DIR = "%C/backup-${name}";
+          };
 
-            path = with pkgs; [
-              coreutils
-              openssh
-              rclone
-              restic
+          path = with pkgs; [
+            coreutils
+            openssh
+            rclone
+            restic
+          ];
+
+          # TODO(tlater): If I ever add more than one repo, service
+          # shutdown/restarting will potentially break if multiple
+          # backups for the same service overlap. A more clever
+          # sentinel file with reference counts would probably solve
+          # this.
+          serviceConfig = {
+            User = backup.user;
+            Group = "backup";
+            RuntimeDirectory = "backup-${name}";
+            CacheDirectory = "backup-${name}";
+            CacheDirectoryMode = "0700";
+            PrivateTmp = true;
+
+            ExecStart = [
+              (lib.concatStringsSep " " (
+                [
+                  "${pkgs.restic}/bin/restic"
+                  "backup"
+                  "--tag"
+                  name
+                ]
+                ++ backup.paths
+              ))
             ];
 
-            # TODO(tlater): If I ever add more than one repo, service
-            # shutdown/restarting will potentially break if multiple
-            # backups for the same service overlap. A more clever
-            # sentinel file with reference counts would probably solve
-            # this.
-            serviceConfig = {
-              User = backup.user;
-              Group = "backup";
-              RuntimeDirectory = "backup-${name}";
-              CacheDirectory = "backup-${name}";
-              CacheDirectoryMode = "0700";
-              PrivateTmp = true;
-
-              ExecStart = [
-                (lib.concatStringsSep " " ([ "${pkgs.restic}/bin/restic" "backup" "--tag" name ] ++ backup.paths))
-              ];
-
-              ExecStartPre =
-                map (service: "+${mkShutdownScript service}") backup.pauseServices
-                ++ singleton (writeScript "backup-${name}-repo-init" [ ] ''
+            ExecStartPre =
+              map (service: "+${mkShutdownScript service}") backup.pauseServices
+              ++ singleton (
+                writeScript "backup-${name}-repo-init" [ ] ''
                   restic snapshots || restic init
-                '')
-                ++ optional (backup.preparation.text != null)
-                  (writeScript "backup-${name}-prepare" backup.preparation.packages backup.preparation.text);
+                ''
+              )
+              ++ optional (backup.preparation.text != null) (
+                writeScript "backup-${name}-prepare" backup.preparation.packages backup.preparation.text
+              );
 
-              # TODO(tlater): Add repo pruning/checking
-              ExecStopPost =
-                map (service: "+${mkRestartScript service}") backup.pauseServices
-                ++ optional (backup.cleanup.text != null)
-                  (writeScript "backup-${name}-cleanup" backup.cleanup.packages backup.cleanup.text);
-            };
-          })
-        config.services.backups;
+            # TODO(tlater): Add repo pruning/checking
+            ExecStopPost =
+              map (service: "+${mkRestartScript service}") backup.pauseServices
+              ++ optional (backup.cleanup.text != null) (
+                writeScript "backup-${name}-cleanup" backup.cleanup.packages backup.cleanup.text
+              );
+          };
+        }
+      ) config.services.backups;
 
     systemd.timers =
       {
@@ -227,18 +245,18 @@ in
           # of the backup jobs.
         };
       }
-      // lib.mapAttrs'
-        (name: backup:
-          lib.nameValuePair "backup-${name}" {
-            wantedBy = [ "timers.target" ];
-            timerConfig = {
-              OnCalendar = "Wednesday 02:30:00 UTC";
-              RandomizedDelaySec = "1h";
-              FixedRandomDelay = true;
-              Persistent = true;
-            };
-          })
-        config.services.backups;
+      // lib.mapAttrs' (
+        name: backup:
+        lib.nameValuePair "backup-${name}" {
+          wantedBy = [ "timers.target" ];
+          timerConfig = {
+            OnCalendar = "Wednesday 02:30:00 UTC";
+            RandomizedDelaySec = "1h";
+            FixedRandomDelay = true;
+            Persistent = true;
+          };
+        }
+      ) config.services.backups;
 
     users = {
       # This user is only used to own the ssh key, because apparently
diff --git a/configuration/services/battery-manager.nix b/configuration/services/battery-manager.nix
index 7783a3b..a16cca1 100644
--- a/configuration/services/battery-manager.nix
+++ b/configuration/services/battery-manager.nix
@@ -1,10 +1,6 @@
-{ config
-, flake-inputs
-, ...
-}: {
-  imports = [
-    flake-inputs.sonnenshift.nixosModules.default
-  ];
+{ config, flake-inputs, ... }:
+{
+  imports = [ flake-inputs.sonnenshift.nixosModules.default ];
 
   services.batteryManager = {
     enable = true;
diff --git a/configuration/services/conduit.nix b/configuration/services/conduit.nix
index 8734785..4e53241 100644
--- a/configuration/services/conduit.nix
+++ b/configuration/services/conduit.nix
@@ -1,7 +1,8 @@
-{ pkgs
-, config
-, lib
-, ...
+{
+  pkgs,
+  config,
+  lib,
+  ...
 }:
 let
   inherit (lib.strings) concatMapStringsSep;
@@ -42,28 +43,30 @@ in
   systemd.services.heisenbridge =
     let
       replaceSecretBin = "${pkgs.replace-secret}/bin/replace-secret";
-      registrationFile = builtins.toFile "heisenbridge-registration.yaml" (builtins.toJSON {
-        id = "heisenbridge";
-        url = "http://127.0.0.1:9898";
-        as_token = "@AS_TOKEN@";
-        hs_token = "@HS_TOKEN@";
-        rate_limited = false;
-        sender_localpart = "heisenbridge";
-        namespaces = {
-          users = [
-            {
-              regex = "@irc_.*";
-              exclusive = true;
-            }
-            {
-              regex = "@heisenbridge:.*";
-              exclusive = true;
-            }
-          ];
-          aliases = [ ];
-          rooms = [ ];
-        };
-      });
+      registrationFile = builtins.toFile "heisenbridge-registration.yaml" (
+        builtins.toJSON {
+          id = "heisenbridge";
+          url = "http://127.0.0.1:9898";
+          as_token = "@AS_TOKEN@";
+          hs_token = "@HS_TOKEN@";
+          rate_limited = false;
+          sender_localpart = "heisenbridge";
+          namespaces = {
+            users = [
+              {
+                regex = "@irc_.*";
+                exclusive = true;
+              }
+              {
+                regex = "@heisenbridge:.*";
+                exclusive = true;
+              }
+            ];
+            aliases = [ ];
+            rooms = [ ];
+          };
+        }
+      );
 
       # TODO(tlater): Starting with systemd 253 it will become possible
       # to do the credential setup as part of ExecStartPre/preStart
@@ -114,7 +117,7 @@ in
         RestrictRealtime = true;
         ProtectProc = "invisible";
         ProcSubset = "pid";
-        UMask = 0077;
+        UMask = 77;
 
         # For the identd port
         # CapabilityBoundingSet = ["CAP_NET_BIND_SERVICE"];
@@ -134,9 +137,7 @@ in
     use-auth-secret = true;
     static-auth-secret-file = config.sops.secrets."turn/secret".path;
     realm = turn-realm;
-    relay-ips = [
-      "116.202.158.55"
-    ];
+    relay-ips = [ "116.202.158.55" ];
 
     # SSL config
     #
@@ -245,9 +246,7 @@ in
 
   services.backups.conduit = {
     user = "root";
-    paths = [
-      "/var/lib/private/matrix-conduit/"
-    ];
+    paths = [ "/var/lib/private/matrix-conduit/" ];
     # Other services store their data in conduit, so no other services
     # need to be shut down currently.
     pauseServices = [ "conduit.service" ];
diff --git a/configuration/services/fail2ban.nix b/configuration/services/fail2ban.nix
index 1811046..f09668c 100644
--- a/configuration/services/fail2ban.nix
+++ b/configuration/services/fail2ban.nix
@@ -1,4 +1,5 @@
-{ pkgs, ... }: {
+{ pkgs, ... }:
+{
   services.fail2ban = {
     enable = true;
     extraPackages = [ pkgs.ipset ];
diff --git a/configuration/services/foundryvtt.nix b/configuration/services/foundryvtt.nix
index 3383ab3..614b818 100644
--- a/configuration/services/foundryvtt.nix
+++ b/configuration/services/foundryvtt.nix
@@ -1,8 +1,9 @@
-{ lib
-, config
-, flake-inputs
-, pkgs
-, ...
+{
+  lib,
+  config,
+  flake-inputs,
+  pkgs,
+  ...
 }:
 let
   domain = "foundryvtt.${config.services.nginx.domain}";
@@ -40,9 +41,7 @@ in
 
   services.backups.foundryvtt = {
     user = "foundryvtt";
-    paths = [
-      config.services.foundryvtt.dataDir
-    ];
+    paths = [ config.services.foundryvtt.dataDir ];
     pauseServices = [ "foundryvtt.service" ];
   };
 }
diff --git a/configuration/services/gitea.nix b/configuration/services/gitea.nix
index 4ef6238..c88dd01 100644
--- a/configuration/services/gitea.nix
+++ b/configuration/services/gitea.nix
@@ -1,7 +1,8 @@
-{ pkgs
-, config
-, lib
-, ...
+{
+  pkgs,
+  config,
+  lib,
+  ...
 }:
 let
   domain = "gitea.${config.services.nginx.domain}";
@@ -34,9 +35,7 @@ in
       secretPath = config.sops.secrets."forgejo/metrics-token".path;
       runConfig = "${config.services.forgejo.customDir}/conf/app.ini";
     in
-    [
-      "+${replaceSecretBin} '#metricstoken#' '${secretPath}' '${runConfig}'"
-    ];
+    [ "+${replaceSecretBin} '#metricstoken#' '${secretPath}' '${runConfig}'" ];
 
   # Set up SSL
   services.nginx.virtualHosts."${domain}" =
diff --git a/configuration/services/metrics/exporters.nix b/configuration/services/metrics/exporters.nix
index e17be8e..e16b945 100644
--- a/configuration/services/metrics/exporters.nix
+++ b/configuration/services/metrics/exporters.nix
@@ -1,7 +1,8 @@
-{ config
-, pkgs
-, lib
-, ...
+{
+  config,
+  pkgs,
+  lib,
+  ...
 }:
 let
   yaml = pkgs.formats.yaml { };
@@ -20,9 +21,7 @@ in
               "tlater.com"
             ];
           in
-          [
-            "--config=${yaml.generate "domains.yml" conf}"
-          ];
+          [ "--config=${yaml.generate "domains.yml" conf}" ];
       };
 
       # System statistics
@@ -51,26 +50,21 @@ in
         listenAddress = "127.0.0.1";
         group = "nginx";
 
-        settings.namespaces =
-          lib.mapAttrsToList
-            (name: virtualHost: {
-              inherit name;
-              metrics_override.prefix = "nginxlog";
-              namespace_label = "vhost";
+        settings.namespaces = lib.mapAttrsToList (name: virtualHost: {
+          inherit name;
+          metrics_override.prefix = "nginxlog";
+          namespace_label = "vhost";
 
-              format = lib.concatStringsSep " " [
-                "$remote_addr - $remote_user [$time_local]"
-                ''"$request" $status $body_bytes_sent''
-                ''"$http_referer" "$http_user_agent"''
-                ''rt=$request_time uct="$upstream_connect_time"''
-                ''uht="$upstream_header_time" urt="$upstream_response_time"''
-              ];
+          format = lib.concatStringsSep " " [
+            "$remote_addr - $remote_user [$time_local]"
+            ''"$request" $status $body_bytes_sent''
+            ''"$http_referer" "$http_user_agent"''
+            ''rt=$request_time uct="$upstream_connect_time"''
+            ''uht="$upstream_header_time" urt="$upstream_response_time"''
+          ];
 
-              source.files = [
-                "/var/log/nginx/${name}/access.log"
-              ];
-            })
-            config.services.nginx.virtualHosts;
+          source.files = [ "/var/log/nginx/${name}/access.log" ];
+        }) config.services.nginx.virtualHosts;
       };
     };
 
@@ -86,7 +80,11 @@ in
             requires = [ "fail2ban.service" ];
             serviceConfig = {
               Group = "fail2ban";
-              RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
+              RestrictAddressFamilies = [
+                "AF_UNIX"
+                "AF_INET"
+                "AF_INET6"
+              ];
               ExecStart = lib.concatStringsSep " " [
                 "${pkgs.local.prometheus-fail2ban-exporter}/bin/fail2ban-prometheus-exporter"
                 "--collector.f2b.socket=/var/run/fail2ban/fail2ban.sock"
diff --git a/configuration/services/metrics/options.nix b/configuration/services/metrics/options.nix
index 552aec8..5dd17a3 100644
--- a/configuration/services/metrics/options.nix
+++ b/configuration/services/metrics/options.nix
@@ -1,7 +1,8 @@
-{ pkgs
-, config
-, lib
-, ...
+{
+  pkgs,
+  config,
+  lib,
+  ...
 }:
 let
   inherit (lib) types mkOption mkDefault;
@@ -11,87 +12,94 @@ in
   options = {
     services.prometheus = {
       extraExporters = mkOption {
-        type = types.attrsOf (types.submodule {
-          options = {
-            port = mkOption {
-              type = types.int;
-              description = "The port on which this exporter listens.";
+        type = types.attrsOf (
+          types.submodule {
+            options = {
+              port = mkOption {
+                type = types.int;
+                description = "The port on which this exporter listens.";
+              };
+              listenAddress = mkOption {
+                type = types.str;
+                default = "127.0.0.1";
+                description = "Address to listen on.";
+              };
+              serviceOpts = mkOption {
+                type = types.attrs;
+                description = "An attrset to be merged with the exporter's systemd service.";
+              };
             };
-            listenAddress = mkOption {
-              type = types.str;
-              default = "127.0.0.1";
-              description = "Address to listen on.";
-            };
-            serviceOpts = mkOption {
-              type = types.attrs;
-              description = "An attrset to be merged with the exporter's systemd service.";
-            };
-          };
-        });
+          }
+        );
       };
     };
 
     services.victoriametrics.scrapeConfigs = mkOption {
-      type = types.attrsOf (types.submodule ({ name
-                                             , self
-                                             , ...
-                                             }: {
-        options = {
-          job_name = mkOption {
-            type = types.str;
-            default = name;
-          };
-
-          extraSettings = mkOption {
-            type = types.anything;
-            description = ''
-              Other settings to set for this scrape config.
-            '';
-            default = { };
-          };
-
-          targets = mkOption {
-            type = types.listOf types.str;
-            description = lib.mdDoc ''
-              Addresses scrape targets for this config listen on.
-
-              Shortcut for `static_configs = lib.singleton {targets = [<targets>];}`
-            '';
-            default = [ ];
-          };
-
-          static_configs = mkOption {
-            default = [ ];
-            type = types.listOf (types.submodule {
-              options = {
-                targets = mkOption {
-                  type = types.listOf types.str;
-                  description = lib.mdDoc ''
-                    The addresses scrape targets for this config listen on.
-
-                    Must in `listenAddress:port` format.
-                  '';
-                };
-                labels = mkOption {
-                  type = types.attrsOf types.str;
-                  description = lib.mdDoc ''
-                    Labels to apply to all targets defined for this static config.
-                  '';
-                  default = { };
-                };
+      type = types.attrsOf (
+        types.submodule (
+          { name, self, ... }:
+          {
+            options = {
+              job_name = mkOption {
+                type = types.str;
+                default = name;
               };
-            });
-          };
-        };
-      }));
+
+              extraSettings = mkOption {
+                type = types.anything;
+                description = ''
+                  Other settings to set for this scrape config.
+                '';
+                default = { };
+              };
+
+              targets = mkOption {
+                type = types.listOf types.str;
+                description = lib.mdDoc ''
+                  Addresses scrape targets for this config listen on.
+
+                  Shortcut for `static_configs = lib.singleton {targets = [<targets>];}`
+                '';
+                default = [ ];
+              };
+
+              static_configs = mkOption {
+                default = [ ];
+                type = types.listOf (
+                  types.submodule {
+                    options = {
+                      targets = mkOption {
+                        type = types.listOf types.str;
+                        description = lib.mdDoc ''
+                          The addresses scrape targets for this config listen on.
+
+                          Must in `listenAddress:port` format.
+                        '';
+                      };
+                      labels = mkOption {
+                        type = types.attrsOf types.str;
+                        description = lib.mdDoc ''
+                          Labels to apply to all targets defined for this static config.
+                        '';
+                        default = { };
+                      };
+                    };
+                  }
+                );
+              };
+            };
+          }
+        )
+      );
     };
   };
 
   config = {
     systemd.services = lib.mkMerge [
-      (lib.mapAttrs'
-        (name: exporter:
-          lib.nameValuePair "prometheus-${name}-exporter" (lib.mkMerge [
+      (lib.mapAttrs' (
+        name: exporter:
+        lib.nameValuePair "prometheus-${name}-exporter" (
+          lib.mkMerge [
             {
               # Shamelessly copied from upstream because the upstream
               # module is an intractable mess
@@ -117,7 +125,10 @@ in
               serviceConfig.ProtectKernelTunables = true;
               serviceConfig.ProtectSystem = mkDefault "strict";
               serviceConfig.RemoveIPC = true;
-              serviceConfig.RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+              serviceConfig.RestrictAddressFamilies = [
+                "AF_INET"
+                "AF_INET6"
+              ];
               serviceConfig.RestrictNamespaces = true;
               serviceConfig.RestrictRealtime = true;
               serviceConfig.RestrictSUIDSGID = true;
@@ -125,8 +136,9 @@ in
               serviceConfig.UMask = "0077";
             }
             exporter.serviceOpts
-          ]))
-        config.services.prometheus.extraExporters)
+          ]
+        )
+      ) config.services.prometheus.extraExporters)
 
       {
         vmagent-scrape-exporters =
@@ -134,24 +146,25 @@ in
             listenAddress = config.services.victoriametrics.listenAddress;
             vmAddr = (lib.optionalString (lib.hasPrefix ":" listenAddress) "127.0.0.1") + listenAddress;
             promscrape = yaml.generate "prometheus.yml" {
-              scrape_configs = lib.mapAttrsToList
-                (_: scrape:
-                  lib.recursiveUpdate
-                    {
-                      inherit (scrape) job_name;
-                      static_configs =
-                        scrape.static_configs
-                        ++ lib.optional (scrape.targets != [ ]) { targets = scrape.targets; };
-                    }
-                    scrape.extraSettings)
-                config.services.victoriametrics.scrapeConfigs;
+              scrape_configs = lib.mapAttrsToList (
+                _: scrape:
+                lib.recursiveUpdate {
+                  inherit (scrape) job_name;
+                  static_configs =
+                    scrape.static_configs
+                    ++ lib.optional (scrape.targets != [ ]) { targets = scrape.targets; };
+                } scrape.extraSettings
+              ) config.services.victoriametrics.scrapeConfigs;
             };
           in
           {
             enable = true;
             path = [ pkgs.victoriametrics ];
             wantedBy = [ "multi-user.target" ];
-            after = [ "network.target" "victoriametrics.service" ];
+            after = [
+              "network.target"
+              "victoriametrics.service"
+            ];
             serviceConfig = {
               ExecStart = [
                 (lib.concatStringsSep " " [
@@ -180,7 +193,10 @@ in
               ProtectKernelTunables = true;
               ProtectSystem = "strict";
               RemoveIPC = true;
-              RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+              RestrictAddressFamilies = [
+                "AF_INET"
+                "AF_INET6"
+              ];
               RestrictNamespaces = true;
               RestrictRealtime = true;
               RestrictSUIDSGID = true;
@@ -195,19 +211,15 @@ in
 
     services.victoriametrics.scrapeConfigs =
       let
-        allExporters =
-          lib.mapAttrs
-            (name: exporter: {
-              inherit (exporter) listenAddress port;
-            })
-            ((lib.filterAttrs (_: exporter: builtins.isAttrs exporter && exporter.enable)
-              config.services.prometheus.exporters)
-            // config.services.prometheus.extraExporters);
+        allExporters = lib.mapAttrs (name: exporter: { inherit (exporter) listenAddress port; }) (
+          (lib.filterAttrs (
+            _: exporter: builtins.isAttrs exporter && exporter.enable
+          ) config.services.prometheus.exporters)
+          // config.services.prometheus.extraExporters
+        );
       in
-      lib.mapAttrs
-        (_: exporter: {
-          targets = [ "${exporter.listenAddress}:${toString exporter.port}" ];
-        })
-        allExporters;
+      lib.mapAttrs (_: exporter: {
+        targets = [ "${exporter.listenAddress}:${toString exporter.port}" ];
+      }) allExporters;
   };
 }
diff --git a/configuration/services/metrics/victoriametrics.nix b/configuration/services/metrics/victoriametrics.nix
index 695b89e..710cf70 100644
--- a/configuration/services/metrics/victoriametrics.nix
+++ b/configuration/services/metrics/victoriametrics.nix
@@ -1,9 +1,8 @@
-{ config, ... }: {
+{ config, ... }:
+{
   config.services.victoriametrics = {
     enable = true;
-    extraOptions = [
-      "-storage.minFreeDiskSpaceBytes=5GB"
-    ];
+    extraOptions = [ "-storage.minFreeDiskSpaceBytes=5GB" ];
 
     scrapeConfigs = {
       forgejo = {
diff --git a/configuration/services/nextcloud.nix b/configuration/services/nextcloud.nix
index 30adf6e..63c7446 100644
--- a/configuration/services/nextcloud.nix
+++ b/configuration/services/nextcloud.nix
@@ -1,7 +1,8 @@
-{ pkgs
-, config
-, lib
-, ...
+{
+  pkgs,
+  config,
+  lib,
+  ...
 }:
 let
   # Update pending on rewrite of nextcloud news, though there is an
@@ -15,8 +16,8 @@ in
     inherit hostName;
 
     package = nextcloud;
-    phpPackage = lib.mkForce
-      (pkgs.php.override {
+    phpPackage = lib.mkForce (
+      pkgs.php.override {
         packageOverrides = final: prev: {
           extensions = prev.extensions // {
             pgsql = prev.extensions.pgsql.overrideAttrs (old: {
@@ -27,7 +28,8 @@ in
             });
           };
         };
-      });
+      }
+    );
     enable = true;
     maxUploadSize = "2G";
     https = true;
@@ -52,7 +54,14 @@ in
     };
 
     extraApps = {
-      inherit (pkgs.local) bookmarks calendar contacts cookbook news notes;
+      inherit (pkgs.local)
+        bookmarks
+        calendar
+        contacts
+        cookbook
+        news
+        notes
+        ;
     };
   };
 
diff --git a/configuration/services/postgres.nix b/configuration/services/postgres.nix
index 62dfb01..85a6843 100644
--- a/configuration/services/postgres.nix
+++ b/configuration/services/postgres.nix
@@ -1,4 +1,5 @@
-{ pkgs, ... }: {
+{ pkgs, ... }:
+{
   services.postgresql = {
     package = pkgs.postgresql_14;
     enable = true;
diff --git a/configuration/services/starbound.nix b/configuration/services/starbound.nix
index 3b54ee9..f5b23c3 100644
--- a/configuration/services/starbound.nix
+++ b/configuration/services/starbound.nix
@@ -1,7 +1,4 @@
-{ pkgs
-, lib
-, ...
-}:
+{ pkgs, lib, ... }:
 let
   inherit (lib) concatStringsSep;
 in
@@ -114,9 +111,7 @@ in
 
   services.backups.starbound = {
     user = "root";
-    paths = [
-      "/var/lib/private/starbound/storage/universe/"
-    ];
+    paths = [ "/var/lib/private/starbound/storage/universe/" ];
     pauseServices = [ "starbound.service" ];
   };
 }
diff --git a/configuration/services/wireguard.nix b/configuration/services/wireguard.nix
index 057a2e9..6f8f6a2 100644
--- a/configuration/services/wireguard.nix
+++ b/configuration/services/wireguard.nix
@@ -1,4 +1,5 @@
-{ config, ... }: {
+{ config, ... }:
+{
   # iptables needs to permit forwarding from wg0 to wg0
   networking.firewall.extraCommands = ''
     iptables -A FORWARD -i wg0 -o wg0 -j ACCEPT
diff --git a/flake.nix b/flake.nix
index 56f3972..6dbbaa5 100644
--- a/flake.nix
+++ b/flake.nix
@@ -33,13 +33,14 @@
   };
 
   outputs =
-    { self
-    , nixpkgs
-    , sops-nix
-    , nvfetcher
-    , deploy-rs
-    , ...
-    } @ inputs:
+    {
+      self,
+      nixpkgs,
+      sops-nix,
+      nvfetcher,
+      deploy-rs,
+      ...
+    }@inputs:
     let
       system = "x86_64-linux";
       pkgs = nixpkgs.legacyPackages.${system};
@@ -84,7 +85,12 @@
           };
 
           sshUser = "tlater";
-          sshOpts = [ "-p" "2222" "-o" "ForwardAgent=yes" ];
+          sshOpts = [
+            "-p"
+            "2222"
+            "-o"
+            "ForwardAgent=yes"
+          ];
         };
       };
 
@@ -144,10 +150,11 @@
       # Development environment #
       ###########################
       devShells.${system}.default = nixpkgs.legacyPackages.${system}.mkShell {
-        sopsPGPKeyDirs = [ "./keys/hosts/" "./keys/users/" ];
-        nativeBuildInputs = [
-          sops-nix.packages.${system}.sops-import-keys-hook
+        sopsPGPKeyDirs = [
+          "./keys/hosts/"
+          "./keys/users/"
         ];
+        nativeBuildInputs = [ sops-nix.packages.${system}.sops-import-keys-hook ];
 
         packages = with pkgs; [
           sops-nix.packages.${system}.sops-init-gpg-key
diff --git a/modules/default.nix b/modules/default.nix
index 9341a5a..e1db4cc 100644
--- a/modules/default.nix
+++ b/modules/default.nix
@@ -1,5 +1 @@
-{
-  imports = [
-    ./nginxExtensions.nix
-  ];
-}
+{ imports = [ ./nginxExtensions.nix ]; }
diff --git a/modules/nginxExtensions.nix b/modules/nginxExtensions.nix
index 3603756..bd505d3 100644
--- a/modules/nginxExtensions.nix
+++ b/modules/nginxExtensions.nix
@@ -1,8 +1,10 @@
-{ config
-, pkgs
-, lib
-, ...
-}: {
+{
+  config,
+  pkgs,
+  lib,
+  ...
+}:
+{
   options = {
     services.nginx.domain = lib.mkOption {
       type = lib.types.str;
@@ -12,10 +14,8 @@
     services.nginx.virtualHosts =
       let
         extraVirtualHostOptions =
-          { name
-          , config
-          , ...
-          }: {
+          { name, config, ... }:
+          {
             options = {
               enableHSTS = lib.mkEnableOption "Enable HSTS";
 
@@ -40,9 +40,7 @@
             };
           };
       in
-      lib.mkOption {
-        type = lib.types.attrsOf (lib.types.submodule extraVirtualHostOptions);
-      };
+      lib.mkOption { type = lib.types.attrsOf (lib.types.submodule extraVirtualHostOptions); };
   };
 
   config = {
@@ -51,11 +49,11 @@
       let
         confirm = ''[[ "tlater.net" = ${config.services.nginx.domain} ]]'';
       in
-      lib.mapAttrs'
-        (cert: _:
-          lib.nameValuePair "acme-${cert}" {
-            serviceConfig.ExecCondition = ''${pkgs.runtimeShell} -c '${confirm}' '';
-          })
-        config.security.acme.certs;
+      lib.mapAttrs' (
+        cert: _:
+        lib.nameValuePair "acme-${cert}" {
+          serviceConfig.ExecCondition = ''${pkgs.runtimeShell} -c '${confirm}' '';
+        }
+      ) config.security.acme.certs;
   };
 }
diff --git a/pkgs/afvalcalendar/default.nix b/pkgs/afvalcalendar/default.nix
index 12b868c..6392220 100644
--- a/pkgs/afvalcalendar/default.nix
+++ b/pkgs/afvalcalendar/default.nix
@@ -1,19 +1,12 @@
-{ pkgs
-, rustPlatform
-, ...
-}:
+{ pkgs, rustPlatform, ... }:
 rustPlatform.buildRustPackage {
   pname = "afvalcalendar";
   version = "0.1.0";
   src = ./.;
 
-  nativeBuildInputs = with pkgs; [
-    pkg-config
-  ];
+  nativeBuildInputs = with pkgs; [ pkg-config ];
 
-  buildInputs = with pkgs; [
-    openssl
-  ];
+  buildInputs = with pkgs; [ openssl ];
 
   cargoHash = "sha256-JXx6aUKdKbUTBCwlBw5i1hZy8ofCfSrhLCwFzqdA8cI=";
 }
diff --git a/pkgs/default.nix b/pkgs/default.nix
index 132d0f5..a9d7aa1 100644
--- a/pkgs/default.nix
+++ b/pkgs/default.nix
@@ -1,7 +1,4 @@
-{ pkgs
-, lib
-,
-}:
+{ pkgs, lib }:
 let
   inherit (builtins) fromJSON mapAttrs readFile;
   inherit (pkgs) callPackage;
@@ -13,7 +10,7 @@ in
   };
   afvalcalendar = callPackage ./afvalcalendar { };
 }
-  // (
+// (
   # Add nextcloud apps
   let
     mkNextcloudApp = pkgs.callPackage ./mkNextcloudApp.nix { };
diff --git a/pkgs/mkNextcloudApp.nix b/pkgs/mkNextcloudApp.nix
index 7453f44..095b0e8 100644
--- a/pkgs/mkNextcloudApp.nix
+++ b/pkgs/mkNextcloudApp.nix
@@ -1,7 +1,5 @@
-{ fetchNextcloudApp
-, lib
-,
-}: source:
+{ fetchNextcloudApp, lib }:
+source:
 fetchNextcloudApp {
   url = source.src.url;
   sha256 = source.src.sha256;
diff --git a/pkgs/prometheus/fail2ban-exporter.nix b/pkgs/prometheus/fail2ban-exporter.nix
index b74e35d..dc22b6c 100644
--- a/pkgs/prometheus/fail2ban-exporter.nix
+++ b/pkgs/prometheus/fail2ban-exporter.nix
@@ -1,7 +1,4 @@
-{ buildGoModule
-, sources
-,
-}:
+{ buildGoModule, sources }:
 buildGoModule {
   inherit (sources.prometheus-fail2ban-exporter) pname src version;
   vendorHash = "sha256-5o8p5p0U/c0WAIV5dACnWA3ThzSh2tt5LIFMb59i9GY=";
diff --git a/pkgs/starbound/default.nix b/pkgs/starbound/default.nix
index a8689f3..26f2184 100644
--- a/pkgs/starbound/default.nix
+++ b/pkgs/starbound/default.nix
@@ -1,19 +1,21 @@
-{ stdenv
-, lib
-, makeWrapper
-, patchelf
-, steamPackages
-, replace-secret
-,
+{
+  stdenv,
+  lib,
+  makeWrapper,
+  patchelf,
+  steamPackages,
+  replace-secret,
 }:
 let
   # Use the directory in which starbound is installed so steamcmd
   # doesn't have to be reinstalled constantly (we're using DynamicUser
   # with StateDirectory to persist this).
-  steamcmd = steamPackages.steamcmd.override {
-    steamRoot = "/var/lib/starbound/.steamcmd";
-  };
-  wrapperPath = lib.makeBinPath [ patchelf steamcmd replace-secret ];
+  steamcmd = steamPackages.steamcmd.override { steamRoot = "/var/lib/starbound/.steamcmd"; };
+  wrapperPath = lib.makeBinPath [
+    patchelf
+    steamcmd
+    replace-secret
+  ];
 in
 stdenv.mkDerivation {
   name = "starbound-update-script";

From d56fad518b0cfd0c2013f0ad50d69a36348d910a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sun, 18 Aug 2024 20:41:58 +0200
Subject: [PATCH 18/67] git: Blame-ignore nixfmt commit

---
 .git-blame-ignore-revs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index cee878d..df9d62b 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -1,6 +1,9 @@
 # Run this command to always ignore formatting commits in `git blame`
 # git config blame.ignoreRevsFile .git-blame-ignore-revs
 
+# Switch to nixfmt formatting
+04f7a7ef1d38906163afc9cddfa8ce2b0ebf3b45
+
 # Switch to nixpkgs-fmt formatting
 fd138d45e6a2cad89fead6e9f246ba282070d6b7
 

From c4ec382de9fed4afe99d425254d05ae8f7f586e1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Thu, 24 Oct 2024 23:02:57 +0200
Subject: [PATCH 19/67] flake.lock: Update
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Flake lock file updates:

• Updated input 'deploy-rs':
    'github:serokell/deploy-rs/3867348fa92bc892eba5d9ddb2d7a97b9e127a8a' (2024-06-12)
  → 'github:serokell/deploy-rs/aa07eb05537d4cd025e2310397a6adcedfe72c76' (2024-09-27)
• Updated input 'disko':
    'github:nix-community/disko/276a0d055a720691912c6a34abb724e395c8e38a' (2024-08-15)
  → 'github:nix-community/disko/09a776702b004fdf9c41a024e1299d575ee18a7d' (2024-10-23)
• Updated input 'foundryvtt':
    'github:reckenrode/nix-foundryvtt/699a175398410688214615a9d977354e9ef98d2d' (2024-08-03)
  → 'github:reckenrode/nix-foundryvtt/bf07f9dd916a97a091f8ab83358c2f295bea9ec9' (2024-09-18)
• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/1cbd3d585263dc620c483e138d352a39b9f0e3ec' (2024-08-17)
  → 'github:nixos/nixpkgs/00c24c17345ba867086a807a7869b12e05955c81' (2024-10-24)
• Updated input 'nixpkgs-unstable':
    'github:nixos/nixpkgs/abcef4da4ebb72240bddc370a27263627e64877f' (2024-08-18)
  → 'github:nixos/nixpkgs/8b052aac04356e25b6ec1058c86de8792440362d' (2024-10-24)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/be0eec2d27563590194a9206f551a6f73d52fa34' (2024-08-12)
  → 'github:Mic92/sops-nix/78a0e634fc8981d6b564f08b6715c69a755c4c7d' (2024-10-24)
• Updated input 'sops-nix/nixpkgs-stable':
    'github:NixOS/nixpkgs/556533a23879fc7e5f98dd2e0b31a6911a213171' (2024-07-21)
  → 'github:NixOS/nixpkgs/bb8c2cf7ea0dd2e18a52746b2c3a5b0c73b93c22' (2024-10-19)
---
 flake.lock | 42 +++++++++++++++++++++---------------------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/flake.lock b/flake.lock
index 78327bf..61d58f4 100644
--- a/flake.lock
+++ b/flake.lock
@@ -7,11 +7,11 @@
         "utils": "utils"
       },
       "locked": {
-        "lastModified": 1718194053,
-        "narHash": "sha256-FaGrf7qwZ99ehPJCAwgvNY5sLCqQ3GDiE/6uLhxxwSY=",
+        "lastModified": 1727447169,
+        "narHash": "sha256-3KyjMPUKHkiWhwR91J1YchF6zb6gvckCAY1jOE+ne0U=",
         "owner": "serokell",
         "repo": "deploy-rs",
-        "rev": "3867348fa92bc892eba5d9ddb2d7a97b9e127a8a",
+        "rev": "aa07eb05537d4cd025e2310397a6adcedfe72c76",
         "type": "github"
       },
       "original": {
@@ -27,11 +27,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1723685519,
-        "narHash": "sha256-GkXQIoZmW2zCPp1YFtAYGg/xHNyFH/Mgm79lcs81rq0=",
+        "lastModified": 1729712798,
+        "narHash": "sha256-a+Aakkb+amHw4biOZ0iMo8xYl37uUL48YEXIC5PYJ/8=",
         "owner": "nix-community",
         "repo": "disko",
-        "rev": "276a0d055a720691912c6a34abb724e395c8e38a",
+        "rev": "09a776702b004fdf9c41a024e1299d575ee18a7d",
         "type": "github"
       },
       "original": {
@@ -157,11 +157,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1722661736,
-        "narHash": "sha256-0lujsK40JV/2PlqCjhZMGpHKL4vDKzJcnkFJYnG1WZA=",
+        "lastModified": 1726638033,
+        "narHash": "sha256-+hcgXKG5t/9wibv+8T9WASWItBAWb0tsmcZXH+VIYdw=",
         "owner": "reckenrode",
         "repo": "nix-foundryvtt",
-        "rev": "699a175398410688214615a9d977354e9ef98d2d",
+        "rev": "bf07f9dd916a97a091f8ab83358c2f295bea9ec9",
         "type": "github"
       },
       "original": {
@@ -210,11 +210,11 @@
     },
     "nixpkgs-stable": {
       "locked": {
-        "lastModified": 1721524707,
-        "narHash": "sha256-5NctRsoE54N86nWd0psae70YSLfrOek3Kv1e8KoXe/0=",
+        "lastModified": 1729357638,
+        "narHash": "sha256-66RHecx+zohbZwJVEPF7uuwHeqf8rykZTMCTqIrOew4=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "556533a23879fc7e5f98dd2e0b31a6911a213171",
+        "rev": "bb8c2cf7ea0dd2e18a52746b2c3a5b0c73b93c22",
         "type": "github"
       },
       "original": {
@@ -226,11 +226,11 @@
     },
     "nixpkgs-unstable": {
       "locked": {
-        "lastModified": 1723957280,
-        "narHash": "sha256-J08Yqf2IJ73y7myI69qEKsQ048ibweG6FeJeCxbIdB4=",
+        "lastModified": 1729766066,
+        "narHash": "sha256-QLeNRaGsoIFfv2Kfd4rw2l1TTDb1i4gQzvClSmrk1l4=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "abcef4da4ebb72240bddc370a27263627e64877f",
+        "rev": "8b052aac04356e25b6ec1058c86de8792440362d",
         "type": "github"
       },
       "original": {
@@ -242,11 +242,11 @@
     },
     "nixpkgs_2": {
       "locked": {
-        "lastModified": 1723920526,
-        "narHash": "sha256-USs6A60raDKZ/8BEpqja1XjZIsRzADX+NtWKH6wIxIw=",
+        "lastModified": 1729762315,
+        "narHash": "sha256-l0HyBdB2drPowQm044HDWqMLWwf818G38flxL0bhwqU=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "1cbd3d585263dc620c483e138d352a39b9f0e3ec",
+        "rev": "00c24c17345ba867086a807a7869b12e05955c81",
         "type": "github"
       },
       "original": {
@@ -442,11 +442,11 @@
         "nixpkgs-stable": "nixpkgs-stable"
       },
       "locked": {
-        "lastModified": 1723501126,
-        "narHash": "sha256-N9IcHgj/p1+2Pvk8P4Zc1bfrMwld5PcosVA0nL6IGdE=",
+        "lastModified": 1729775275,
+        "narHash": "sha256-J2vtHq9sw1wWm0aTMXpEEAzsVCUMZDTEe5kiBYccpLE=",
         "owner": "Mic92",
         "repo": "sops-nix",
-        "rev": "be0eec2d27563590194a9206f551a6f73d52fa34",
+        "rev": "78a0e634fc8981d6b564f08b6715c69a755c4c7d",
         "type": "github"
       },
       "original": {

From cbbe555f075ddace197e563c40628c8a32cd50d3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 25 Oct 2024 00:17:29 +0200
Subject: [PATCH 20/67] bump: Update nextcloud

---
 configuration/services/nextcloud.nix   |  5 +----
 pkgs/_sources_nextcloud/generated.json | 30 +++++++++++++-------------
 pkgs/_sources_nextcloud/generated.nix  | 30 +++++++++++++-------------
 pkgs/nextcloud-apps.toml               | 10 +++++----
 4 files changed, 37 insertions(+), 38 deletions(-)

diff --git a/configuration/services/nextcloud.nix b/configuration/services/nextcloud.nix
index 63c7446..205d702 100644
--- a/configuration/services/nextcloud.nix
+++ b/configuration/services/nextcloud.nix
@@ -5,10 +5,7 @@
   ...
 }:
 let
-  # Update pending on rewrite of nextcloud news, though there is an
-  # alpha to switch to if it becomes necessary:
-  # https://github.com/nextcloud/news/issues/2610
-  nextcloud = pkgs.nextcloud28;
+  nextcloud = pkgs.nextcloud29;
   hostName = "nextcloud.${config.services.nginx.domain}";
 in
 {
diff --git a/pkgs/_sources_nextcloud/generated.json b/pkgs/_sources_nextcloud/generated.json
index 4071726..1c553ce 100644
--- a/pkgs/_sources_nextcloud/generated.json
+++ b/pkgs/_sources_nextcloud/generated.json
@@ -7,11 +7,11 @@
         "passthru": null,
         "pinned": false,
         "src": {
-            "sha256": "sha256-V4zZsAwPn8QiCXEDqOgNFHaXqMOcHMpMbJ1Oz3Db0pc=",
+            "sha256": "sha256-7BTNFsNcqmDACpj5PMEiS71xtr50v7Sqo3qeCL+3J9s=",
             "type": "tarball",
-            "url": "https://github.com/nextcloud/bookmarks/releases/download/v14.2.4/bookmarks-14.2.4.tar.gz"
+            "url": "https://github.com/nextcloud/bookmarks/releases/download/v14.2.6/bookmarks-14.2.6.tar.gz"
         },
-        "version": "14.2.4"
+        "version": "14.2.6"
     },
     "calendar": {
         "cargoLocks": null,
@@ -21,11 +21,11 @@
         "passthru": null,
         "pinned": false,
         "src": {
-            "sha256": "sha256-sipXeyOL4OhENz7V2beFeSYBAoFZdCWtqftIy0lsqEY=",
+            "sha256": "sha256-X2XcH7HpxgizCEJVrazGtzNQTBihFxvTq/ybK939cxo=",
             "type": "tarball",
-            "url": "https://github.com/nextcloud-releases/calendar/releases/download/v4.7.15/calendar-v4.7.15.tar.gz"
+            "url": "https://github.com/nextcloud-releases/calendar/releases/download/v4.7.16/calendar-v4.7.16.tar.gz"
         },
-        "version": "v4.7.15"
+        "version": "v4.7.16"
     },
     "contacts": {
         "cargoLocks": null,
@@ -49,11 +49,11 @@
         "passthru": null,
         "pinned": false,
         "src": {
-            "sha256": "sha256-a8ekMnEzudHGiqHF53jPtgsVTOTc2QLuPg6YtTw5h68=",
+            "sha256": "sha256-Pfa+Xbopg20os+pnGgg+wpEX1MI5fz5JMb0K4a8rBhs=",
             "type": "tarball",
-            "url": "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v0.11.1/Cookbook-0.11.1.tar.gz"
+            "url": "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v0.11.2/Cookbook-0.11.2.tar.gz"
         },
-        "version": "0.11.1"
+        "version": "0.11.2"
     },
     "news": {
         "cargoLocks": null,
@@ -63,11 +63,11 @@
         "passthru": null,
         "pinned": false,
         "src": {
-            "sha256": "sha256-AhTZGQCLeNgsRBF5w3+Lf9JtNN4D1QncB5t+odU+XUc=",
+            "sha256": "sha256-pnvyMZQ+NYMgH0Unfh5S19HdZSjnghgoUDAoi2KIXNI=",
             "type": "tarball",
-            "url": "https://github.com/nextcloud/news/releases/download/25.0.0-alpha8/news.tar.gz"
+            "url": "https://github.com/nextcloud/news/releases/download/25.0.0-alpha12/news.tar.gz"
         },
-        "version": "25.0.0-alpha8"
+        "version": "25.0.0-alpha12"
     },
     "notes": {
         "cargoLocks": null,
@@ -77,10 +77,10 @@
         "passthru": null,
         "pinned": false,
         "src": {
-            "sha256": "sha256-A3QNWGWeC2OcZngMrh9NpYbU5qp5x9xiDcRfB9cRXBo=",
+            "sha256": "sha256-Cu73H0hJREbkskLbj56M8qUF1Tp4EazORlCF9rpPL90=",
             "type": "tarball",
-            "url": "https://github.com/nextcloud-releases/notes/releases/download/v4.10.1/notes-v4.10.1.tar.gz"
+            "url": "https://github.com/nextcloud-releases/notes/releases/download/v4.11.0/notes-v4.11.0.tar.gz"
         },
-        "version": "v4.10.1"
+        "version": "v4.11.0"
     }
 }
\ No newline at end of file
diff --git a/pkgs/_sources_nextcloud/generated.nix b/pkgs/_sources_nextcloud/generated.nix
index 53e26d1..da275cc 100644
--- a/pkgs/_sources_nextcloud/generated.nix
+++ b/pkgs/_sources_nextcloud/generated.nix
@@ -3,18 +3,18 @@
 {
   bookmarks = {
     pname = "bookmarks";
-    version = "14.2.4";
+    version = "14.2.6";
     src = fetchTarball {
-      url = "https://github.com/nextcloud/bookmarks/releases/download/v14.2.4/bookmarks-14.2.4.tar.gz";
-      sha256 = "sha256-V4zZsAwPn8QiCXEDqOgNFHaXqMOcHMpMbJ1Oz3Db0pc=";
+      url = "https://github.com/nextcloud/bookmarks/releases/download/v14.2.6/bookmarks-14.2.6.tar.gz";
+      sha256 = "sha256-7BTNFsNcqmDACpj5PMEiS71xtr50v7Sqo3qeCL+3J9s=";
     };
   };
   calendar = {
     pname = "calendar";
-    version = "v4.7.15";
+    version = "v4.7.16";
     src = fetchTarball {
-      url = "https://github.com/nextcloud-releases/calendar/releases/download/v4.7.15/calendar-v4.7.15.tar.gz";
-      sha256 = "sha256-sipXeyOL4OhENz7V2beFeSYBAoFZdCWtqftIy0lsqEY=";
+      url = "https://github.com/nextcloud-releases/calendar/releases/download/v4.7.16/calendar-v4.7.16.tar.gz";
+      sha256 = "sha256-X2XcH7HpxgizCEJVrazGtzNQTBihFxvTq/ybK939cxo=";
     };
   };
   contacts = {
@@ -27,26 +27,26 @@
   };
   cookbook = {
     pname = "cookbook";
-    version = "0.11.1";
+    version = "0.11.2";
     src = fetchTarball {
-      url = "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v0.11.1/Cookbook-0.11.1.tar.gz";
-      sha256 = "sha256-a8ekMnEzudHGiqHF53jPtgsVTOTc2QLuPg6YtTw5h68=";
+      url = "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v0.11.2/Cookbook-0.11.2.tar.gz";
+      sha256 = "sha256-Pfa+Xbopg20os+pnGgg+wpEX1MI5fz5JMb0K4a8rBhs=";
     };
   };
   news = {
     pname = "news";
-    version = "25.0.0-alpha8";
+    version = "25.0.0-alpha12";
     src = fetchTarball {
-      url = "https://github.com/nextcloud/news/releases/download/25.0.0-alpha8/news.tar.gz";
-      sha256 = "sha256-AhTZGQCLeNgsRBF5w3+Lf9JtNN4D1QncB5t+odU+XUc=";
+      url = "https://github.com/nextcloud/news/releases/download/25.0.0-alpha12/news.tar.gz";
+      sha256 = "sha256-pnvyMZQ+NYMgH0Unfh5S19HdZSjnghgoUDAoi2KIXNI=";
     };
   };
   notes = {
     pname = "notes";
-    version = "v4.10.1";
+    version = "v4.11.0";
     src = fetchTarball {
-      url = "https://github.com/nextcloud-releases/notes/releases/download/v4.10.1/notes-v4.10.1.tar.gz";
-      sha256 = "sha256-A3QNWGWeC2OcZngMrh9NpYbU5qp5x9xiDcRfB9cRXBo=";
+      url = "https://github.com/nextcloud-releases/notes/releases/download/v4.11.0/notes-v4.11.0.tar.gz";
+      sha256 = "sha256-Cu73H0hJREbkskLbj56M8qUF1Tp4EazORlCF9rpPL90=";
     };
   };
 }
diff --git a/pkgs/nextcloud-apps.toml b/pkgs/nextcloud-apps.toml
index 89dccb4..4e6e0b2 100644
--- a/pkgs/nextcloud-apps.toml
+++ b/pkgs/nextcloud-apps.toml
@@ -1,10 +1,12 @@
 [bookmarks]
-src.github = "nextcloud/bookmarks"
-src.prefix = "v"
+# src.github = "nextcloud/bookmarks"
+# src.prefix = "v"
+src.manual = "14.2.6"
 fetch.tarball = "https://github.com/nextcloud/bookmarks/releases/download/v$ver/bookmarks-$ver.tar.gz"
 
 [calendar]
-src.github = "nextcloud-releases/calendar"
+# src.github = "nextcloud-releases/calendar"
+src.manual = "v4.7.16"
 fetch.tarball = "https://github.com/nextcloud-releases/calendar/releases/download/$ver/calendar-$ver.tar.gz"
 
 [contacts]
@@ -20,7 +22,7 @@ fetch.tarball = "https://github.com/christianlupus-nextcloud/cookbook-releases/r
 [news]
 # Update manually until angular rewrite is done
 # src.github = "nextcloud/news"
-src.manual = "25.0.0-alpha8"
+src.manual = "25.0.0-alpha12"
 fetch.tarball = "https://github.com/nextcloud/news/releases/download/$ver/news.tar.gz"
 
 [notes]

From 2d977f4f13ef75c86699b6147e1426165b3b38e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Thu, 28 Nov 2024 00:56:31 +0100
Subject: [PATCH 21/67] Update battery-manager

---
 flake.lock | 35 +++++++++++++++++------------------
 flake.nix  |  2 +-
 2 files changed, 18 insertions(+), 19 deletions(-)

diff --git a/flake.lock b/flake.lock
index 61d58f4..a2017c6 100644
--- a/flake.lock
+++ b/flake.lock
@@ -137,11 +137,11 @@
         "systems": "systems_3"
       },
       "locked": {
-        "lastModified": 1705309234,
-        "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
+        "lastModified": 1726560853,
+        "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
         "owner": "numtide",
         "repo": "flake-utils",
-        "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
+        "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
         "type": "github"
       },
       "original": {
@@ -179,11 +179,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1703863825,
-        "narHash": "sha256-rXwqjtwiGKJheXB43ybM8NwWB8rO2dSRrEqes0S7F5Y=",
+        "lastModified": 1729742964,
+        "narHash": "sha256-B4mzTcQ0FZHdpeWcpDYPERtyjJd/NIuaQ9+BV1h+MpA=",
         "owner": "nix-community",
         "repo": "nix-github-actions",
-        "rev": "5163432afc817cf8bd1f031418d1869e4c9d5547",
+        "rev": "e04df33f62cdcf93d73e9a04142464753a16db67",
         "type": "github"
       },
       "original": {
@@ -306,11 +306,11 @@
         "treefmt-nix": "treefmt-nix"
       },
       "locked": {
-        "lastModified": 1708589824,
-        "narHash": "sha256-2GOiFTkvs5MtVF65sC78KNVxQSmsxtk0WmV1wJ9V2ck=",
+        "lastModified": 1731205797,
+        "narHash": "sha256-F7N1mxH1VrkVNHR3JGNMRvp9+98KYO4b832KS8Gl2xI=",
         "owner": "nix-community",
         "repo": "poetry2nix",
-        "rev": "3c92540611f42d3fb2d0d084a6c694cd6544b609",
+        "rev": "f554d27c1544d9c56e5f1f8e2b8aff399803674e",
         "type": "github"
       },
       "original": {
@@ -420,16 +420,15 @@
         "poetry2nixi": "poetry2nixi"
       },
       "locked": {
-        "lastModified": 1712437610,
-        "narHash": "sha256-U0xIqSupo6yBVWQcHIcLPDKg5ShQIkV/0Ay+Xg3GIlk=",
-        "ref": "tlater/implement-nix-module",
-        "rev": "43c4f591328f194ca989b86cea49773104f75549",
-        "revCount": 7,
+        "lastModified": 1733296058,
+        "narHash": "sha256-2tYgb4TbvoLk+zsRdCPaglP0s9GCG5HOR9Jm9rsSiHU=",
+        "ref": "refs/heads/main",
+        "rev": "5f01c17df4dbe841bb6ccd85993c0d9b7368af72",
+        "revCount": 13,
         "type": "git",
         "url": "ssh://git@github.com/sonnenshift/battery-manager"
       },
       "original": {
-        "ref": "tlater/implement-nix-module",
         "type": "git",
         "url": "ssh://git@github.com/sonnenshift/battery-manager"
       }
@@ -545,11 +544,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1708335038,
-        "narHash": "sha256-ETLZNFBVCabo7lJrpjD6cAbnE11eDOjaQnznmg/6hAE=",
+        "lastModified": 1730120726,
+        "narHash": "sha256-LqHYIxMrl/1p3/kvm2ir925tZ8DkI0KA10djk8wecSk=",
         "owner": "numtide",
         "repo": "treefmt-nix",
-        "rev": "e504621290a1fd896631ddbc5e9c16f4366c9f65",
+        "rev": "9ef337e492a5555d8e17a51c911ff1f02635be15",
         "type": "github"
       },
       "original": {
diff --git a/flake.nix b/flake.nix
index 6dbbaa5..ea27f2d 100644
--- a/flake.nix
+++ b/flake.nix
@@ -27,7 +27,7 @@
     };
 
     sonnenshift = {
-      url = "git+ssh://git@github.com/sonnenshift/battery-manager?ref=tlater/implement-nix-module";
+      url = "git+ssh://git@github.com/sonnenshift/battery-manager";
       inputs.nixpkgs.follows = "nixpkgs";
     };
   };

From 7ebb2ca6d8d7f3d18a3ae6c88a6c565c28ed9406 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 18 Jan 2025 22:55:57 +0800
Subject: [PATCH 22/67] flake.lock: Update
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Flake lock file updates:

• Updated input 'disko':
    'github:nix-community/disko/09a776702b004fdf9c41a024e1299d575ee18a7d?narHash=sha256-a%2BAakkb%2BamHw4biOZ0iMo8xYl37uUL48YEXIC5PYJ/8%3D' (2024-10-23)
  → 'github:nix-community/disko/bf0abfde48f469c256f2b0f481c6281ff04a5db2?narHash=sha256-rMEuiK69MDhjz1JgbaeQ9mBDXMJ2/P8vmOYRbFndXsk%3D' (2025-01-16)
• Updated input 'foundryvtt':
    'github:reckenrode/nix-foundryvtt/bf07f9dd916a97a091f8ab83358c2f295bea9ec9?narHash=sha256-%2BhcgXKG5t/9wibv%2B8T9WASWItBAWb0tsmcZXH%2BVIYdw%3D' (2024-09-18)
  → 'github:reckenrode/nix-foundryvtt/0a72a4bf64224c6584fd1b9e9f0012dd09af979a?narHash=sha256-vM9C1gFiQGa3nTYqmTBI8MoiUfprkQdepUBbxV7ECMQ%3D' (2025-01-17)
• Updated input 'nixpkgs-unstable':
    'github:nixos/nixpkgs/8b052aac04356e25b6ec1058c86de8792440362d?narHash=sha256-QLeNRaGsoIFfv2Kfd4rw2l1TTDb1i4gQzvClSmrk1l4%3D' (2024-10-24)
  → 'github:nixos/nixpkgs/09c71b16e6efc9e90edae7eb8b63348702ff9a85?narHash=sha256-jtucJjcdryEZQw1g0RThPSPxCdWNHF42sLp8pmMMGDs%3D' (2025-01-18)
• Updated input 'nvfetcher':
    'github:berberman/nvfetcher/fa7609950023462c6f91c425de7610c0bb6b86ba?narHash=sha256-xZZBdKqe1ByITzvx65pVgGQ5jeb73MybjgrcfI84lEo%3D' (2024-06-13)
  → 'github:berberman/nvfetcher/bdb14eab6fe9cefc29efe01e60c3a3f616d6b62a?narHash=sha256-Z0BpHelaGQsE5VD9hBsBHsvMU9h%2BXt0kfkDJyFivZOU%3D' (2024-11-25)
• Updated input 'nvfetcher/flake-utils':
    'github:numtide/flake-utils/b1d9ab70662946ef0850d488da1c9019f3a9752a?narHash=sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ%3D' (2024-03-11)
  → 'github:numtide/flake-utils/11707dc2f618dd54ca8739b309ec4fc024de578b?narHash=sha256-l0KFg5HjrsfsO/JpG%2Br7fRrqm12kzFHyUHqHCVpMMbI%3D' (2024-11-13)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/78a0e634fc8981d6b564f08b6715c69a755c4c7d?narHash=sha256-J2vtHq9sw1wWm0aTMXpEEAzsVCUMZDTEe5kiBYccpLE%3D' (2024-10-24)
  → 'github:Mic92/sops-nix/4c4fb93f18b9072c6fa1986221f9a3d7bf1fe4b6?narHash=sha256-GXUE9%2BFgxoZU8v0p6ilBJ8NH7k8nKmZjp/7dmMrCv3o%3D' (2025-01-17)
• Removed input 'sops-nix/nixpkgs-stable'
---
 flake.lock | 63 ++++++++++++++++++++----------------------------------
 1 file changed, 23 insertions(+), 40 deletions(-)

diff --git a/flake.lock b/flake.lock
index a2017c6..9aff775 100644
--- a/flake.lock
+++ b/flake.lock
@@ -27,11 +27,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1729712798,
-        "narHash": "sha256-a+Aakkb+amHw4biOZ0iMo8xYl37uUL48YEXIC5PYJ/8=",
+        "lastModified": 1737038063,
+        "narHash": "sha256-rMEuiK69MDhjz1JgbaeQ9mBDXMJ2/P8vmOYRbFndXsk=",
         "owner": "nix-community",
         "repo": "disko",
-        "rev": "09a776702b004fdf9c41a024e1299d575ee18a7d",
+        "rev": "bf0abfde48f469c256f2b0f481c6281ff04a5db2",
         "type": "github"
       },
       "original": {
@@ -119,11 +119,11 @@
         "systems": "systems_2"
       },
       "locked": {
-        "lastModified": 1710146030,
-        "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
+        "lastModified": 1731533236,
+        "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
         "owner": "numtide",
         "repo": "flake-utils",
-        "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
+        "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
         "type": "github"
       },
       "original": {
@@ -157,11 +157,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1726638033,
-        "narHash": "sha256-+hcgXKG5t/9wibv+8T9WASWItBAWb0tsmcZXH+VIYdw=",
+        "lastModified": 1737076827,
+        "narHash": "sha256-vM9C1gFiQGa3nTYqmTBI8MoiUfprkQdepUBbxV7ECMQ=",
         "owner": "reckenrode",
         "repo": "nix-foundryvtt",
-        "rev": "bf07f9dd916a97a091f8ab83358c2f295bea9ec9",
+        "rev": "0a72a4bf64224c6584fd1b9e9f0012dd09af979a",
         "type": "github"
       },
       "original": {
@@ -208,29 +208,13 @@
         "type": "github"
       }
     },
-    "nixpkgs-stable": {
-      "locked": {
-        "lastModified": 1729357638,
-        "narHash": "sha256-66RHecx+zohbZwJVEPF7uuwHeqf8rykZTMCTqIrOew4=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "bb8c2cf7ea0dd2e18a52746b2c3a5b0c73b93c22",
-        "type": "github"
-      },
-      "original": {
-        "owner": "NixOS",
-        "ref": "release-24.05",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
     "nixpkgs-unstable": {
       "locked": {
-        "lastModified": 1729766066,
-        "narHash": "sha256-QLeNRaGsoIFfv2Kfd4rw2l1TTDb1i4gQzvClSmrk1l4=",
+        "lastModified": 1737192615,
+        "narHash": "sha256-jtucJjcdryEZQw1g0RThPSPxCdWNHF42sLp8pmMMGDs=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "8b052aac04356e25b6ec1058c86de8792440362d",
+        "rev": "09c71b16e6efc9e90edae7eb8b63348702ff9a85",
         "type": "github"
       },
       "original": {
@@ -242,16 +226,16 @@
     },
     "nixpkgs_2": {
       "locked": {
-        "lastModified": 1729762315,
-        "narHash": "sha256-l0HyBdB2drPowQm044HDWqMLWwf818G38flxL0bhwqU=",
+        "lastModified": 1737171713,
+        "narHash": "sha256-9mWmMXCto7e8U9hM8ZFozElv4dgOMTe308SSc7rEEFs=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "00c24c17345ba867086a807a7869b12e05955c81",
+        "rev": "8773174492fc61571b578f34a59953baba46471a",
         "type": "github"
       },
       "original": {
         "owner": "nixos",
-        "ref": "nixos-24.05-small",
+        "ref": "nixos-24.11-small",
         "repo": "nixpkgs",
         "type": "github"
       }
@@ -281,11 +265,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1718252448,
-        "narHash": "sha256-xZZBdKqe1ByITzvx65pVgGQ5jeb73MybjgrcfI84lEo=",
+        "lastModified": 1732501185,
+        "narHash": "sha256-Z0BpHelaGQsE5VD9hBsBHsvMU9h+Xt0kfkDJyFivZOU=",
         "owner": "berberman",
         "repo": "nvfetcher",
-        "rev": "fa7609950023462c6f91c425de7610c0bb6b86ba",
+        "rev": "bdb14eab6fe9cefc29efe01e60c3a3f616d6b62a",
         "type": "github"
       },
       "original": {
@@ -437,15 +421,14 @@
       "inputs": {
         "nixpkgs": [
           "nixpkgs"
-        ],
-        "nixpkgs-stable": "nixpkgs-stable"
+        ]
       },
       "locked": {
-        "lastModified": 1729775275,
-        "narHash": "sha256-J2vtHq9sw1wWm0aTMXpEEAzsVCUMZDTEe5kiBYccpLE=",
+        "lastModified": 1737107480,
+        "narHash": "sha256-GXUE9+FgxoZU8v0p6ilBJ8NH7k8nKmZjp/7dmMrCv3o=",
         "owner": "Mic92",
         "repo": "sops-nix",
-        "rev": "78a0e634fc8981d6b564f08b6715c69a755c4c7d",
+        "rev": "4c4fb93f18b9072c6fa1986221f9a3d7bf1fe4b6",
         "type": "github"
       },
       "original": {

From 84759f564a0687bd849dfbc5a51abf06e0dd44b3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 18 Jan 2025 23:35:12 +0800
Subject: [PATCH 23/67] Sigh...

---
 configuration/services/wireguard.nix | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/configuration/services/wireguard.nix b/configuration/services/wireguard.nix
index 6f8f6a2..a5185c5 100644
--- a/configuration/services/wireguard.nix
+++ b/configuration/services/wireguard.nix
@@ -31,14 +31,6 @@
               PublicKey = "5mlnqEVJWks5OqgeFA2bLIrvST9TlCE81Btl+j4myz0=";
             };
           }
-
-          {
-            # yuanyuan
-            wireguardPeerConfig = {
-              AllowedIPs = [ "10.45.249.10/32" ];
-              PublicKey = "0UsFE2atz/O5P3OKQ8UHyyyGQNJbp1MeIWUJLuoerwE=";
-            };
-          }
         ];
       };
     };

From 34f88ee8d5e5b664251f309a2defe0be58f863a6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sun, 19 Jan 2025 00:11:22 +0800
Subject: [PATCH 24/67] chore: Remove afvalcalendar

---
 configuration/default.nix                |    1 -
 configuration/services/afvalcalendar.nix |   71 --
 pkgs/afvalcalendar/Cargo.lock            | 1430 ----------------------
 pkgs/afvalcalendar/Cargo.toml            |   16 -
 pkgs/afvalcalendar/default.nix           |   12 -
 pkgs/afvalcalendar/src/calendar.rs       |   43 -
 pkgs/afvalcalendar/src/main.rs           |   15 -
 pkgs/afvalcalendar/src/trash.rs          |   59 -
 pkgs/afvalcalendar/test.rest             |    4 -
 pkgs/default.nix                         |    1 -
 10 files changed, 1652 deletions(-)
 delete mode 100644 configuration/services/afvalcalendar.nix
 delete mode 100644 pkgs/afvalcalendar/Cargo.lock
 delete mode 100644 pkgs/afvalcalendar/Cargo.toml
 delete mode 100644 pkgs/afvalcalendar/default.nix
 delete mode 100644 pkgs/afvalcalendar/src/calendar.rs
 delete mode 100644 pkgs/afvalcalendar/src/main.rs
 delete mode 100644 pkgs/afvalcalendar/src/trash.rs
 delete mode 100644 pkgs/afvalcalendar/test.rest

diff --git a/configuration/default.nix b/configuration/default.nix
index 333488b..48ee8c4 100644
--- a/configuration/default.nix
+++ b/configuration/default.nix
@@ -15,7 +15,6 @@
     "${modulesPath}/profiles/minimal.nix"
     (import ../modules)
 
-    ./services/afvalcalendar.nix
     ./services/backups.nix
     ./services/battery-manager.nix
     ./services/conduit.nix
diff --git a/configuration/services/afvalcalendar.nix b/configuration/services/afvalcalendar.nix
deleted file mode 100644
index ec7d9f7..0000000
--- a/configuration/services/afvalcalendar.nix
+++ /dev/null
@@ -1,71 +0,0 @@
-{ pkgs, config, ... }:
-{
-  systemd.services.afvalcalendar = {
-    description = "Enschede afvalcalendar -> ical converter";
-    wantedBy = [ "multi-user.target" ];
-    after = [ "network.target" ];
-
-    script = ''
-      ${pkgs.local.afvalcalendar}/bin/afvalcalendar > /srv/afvalcalendar/afvalcalendar.ical
-    '';
-
-    startAt = "daily";
-
-    serviceConfig = {
-      DynamicUser = true;
-      ProtectHome = true; # Override the default (read-only)
-      PrivateDevices = true;
-      PrivateIPC = true;
-      PrivateUsers = true;
-      ProtectHostname = true;
-      ProtectClock = true;
-      ProtectKernelTunables = true;
-      ProtectKernelModules = true;
-      ProtectKernelLogs = true;
-      ProtectControlGroups = true;
-      RestrictAddressFamilies = [
-        "AF_UNIX"
-        "AF_INET"
-        "AF_INET6"
-      ];
-      RestrictNamespaces = true;
-      LockPersonality = true;
-      MemoryDenyWriteExecute = true;
-      RestrictRealtime = true;
-      RestrictSUIDSGID = true;
-      SystemCallArchitectures = "native";
-      SystemCallFilter = [
-        "@system-service"
-        "~@privileged @resources @setuid @keyring"
-      ];
-
-      Umask = 2;
-      SupplementaryGroups = "afvalcalendar-hosting";
-
-      ReadWritePaths = "/srv/afvalcalendar";
-    };
-  };
-
-  services.nginx.virtualHosts."afvalcalendar.${config.services.nginx.domain}" = {
-    forceSSL = true;
-    useACMEHost = "tlater.net";
-    enableHSTS = true;
-
-    root = "/srv/afvalcalendar";
-  };
-
-  users.groups.afvalcalendar-hosting = { };
-  systemd.tmpfiles.settings."10-afvalcalendar" = {
-    "/srv/afvalcalendar".d = {
-      user = "nginx";
-      group = "afvalcalendar-hosting";
-      mode = "0775";
-    };
-
-    "/srv/afvalcalendar/afvalcalendar.ical".f = {
-      user = "nginx";
-      group = "afvalcalendar-hosting";
-      mode = "0775";
-    };
-  };
-}
diff --git a/pkgs/afvalcalendar/Cargo.lock b/pkgs/afvalcalendar/Cargo.lock
deleted file mode 100644
index 24cace4..0000000
--- a/pkgs/afvalcalendar/Cargo.lock
+++ /dev/null
@@ -1,1430 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "addr2line"
-version = "0.21.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
-dependencies = [
- "gimli",
-]
-
-[[package]]
-name = "adler"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
-
-[[package]]
-name = "afvalcalendar"
-version = "0.1.0"
-dependencies = [
- "chrono",
- "hostname",
- "icalendar",
- "reqwest",
- "serde",
- "serde_json",
- "serde_repr",
- "tokio",
-]
-
-[[package]]
-name = "android-tzdata"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
-
-[[package]]
-name = "android_system_properties"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "autocfg"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
-
-[[package]]
-name = "backtrace"
-version = "0.3.69"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
-dependencies = [
- "addr2line",
- "cc",
- "cfg-if",
- "libc",
- "miniz_oxide",
- "object",
- "rustc-demangle",
-]
-
-[[package]]
-name = "base64"
-version = "0.21.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
-
-[[package]]
-name = "bitflags"
-version = "1.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
-
-[[package]]
-name = "bitflags"
-version = "2.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
-
-[[package]]
-name = "bumpalo"
-version = "3.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d32a994c2b3ca201d9b263612a374263f05e7adde37c4707f693dcd375076d1f"
-
-[[package]]
-name = "bytes"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
-
-[[package]]
-name = "cc"
-version = "1.0.83"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-
-[[package]]
-name = "chrono"
-version = "0.4.34"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b"
-dependencies = [
- "android-tzdata",
- "iana-time-zone",
- "js-sys",
- "num-traits",
- "serde",
- "wasm-bindgen",
- "windows-targets 0.52.0",
-]
-
-[[package]]
-name = "cookie"
-version = "0.17.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24"
-dependencies = [
- "percent-encoding",
- "time",
- "version_check",
-]
-
-[[package]]
-name = "cookie_store"
-version = "0.20.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "387461abbc748185c3a6e1673d826918b450b87ff22639429c694619a83b6cf6"
-dependencies = [
- "cookie",
- "idna 0.3.0",
- "log",
- "publicsuffix",
- "serde",
- "serde_derive",
- "serde_json",
- "time",
- "url",
-]
-
-[[package]]
-name = "core-foundation"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
-name = "core-foundation-sys"
-version = "0.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
-
-[[package]]
-name = "deranged"
-version = "0.3.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
-dependencies = [
- "powerfmt",
-]
-
-[[package]]
-name = "encoding_rs"
-version = "0.8.33"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "equivalent"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
-
-[[package]]
-name = "errno"
-version = "0.3.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
-dependencies = [
- "libc",
- "windows-sys 0.52.0",
-]
-
-[[package]]
-name = "fastrand"
-version = "2.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
-
-[[package]]
-name = "fnv"
-version = "1.0.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
-
-[[package]]
-name = "foreign-types"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
-dependencies = [
- "foreign-types-shared",
-]
-
-[[package]]
-name = "foreign-types-shared"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
-
-[[package]]
-name = "form_urlencoded"
-version = "1.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
-dependencies = [
- "percent-encoding",
-]
-
-[[package]]
-name = "futures-channel"
-version = "0.3.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
-dependencies = [
- "futures-core",
-]
-
-[[package]]
-name = "futures-core"
-version = "0.3.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
-
-[[package]]
-name = "futures-sink"
-version = "0.3.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
-
-[[package]]
-name = "futures-task"
-version = "0.3.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
-
-[[package]]
-name = "futures-util"
-version = "0.3.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
-dependencies = [
- "futures-core",
- "futures-task",
- "pin-project-lite",
- "pin-utils",
-]
-
-[[package]]
-name = "getrandom"
-version = "0.2.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
-dependencies = [
- "cfg-if",
- "js-sys",
- "libc",
- "wasi",
- "wasm-bindgen",
-]
-
-[[package]]
-name = "gimli"
-version = "0.28.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
-
-[[package]]
-name = "h2"
-version = "0.3.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9"
-dependencies = [
- "bytes",
- "fnv",
- "futures-core",
- "futures-sink",
- "futures-util",
- "http",
- "indexmap",
- "slab",
- "tokio",
- "tokio-util",
- "tracing",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.14.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
-
-[[package]]
-name = "hermit-abi"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd"
-
-[[package]]
-name = "hostname"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
-dependencies = [
- "libc",
- "match_cfg",
- "winapi",
-]
-
-[[package]]
-name = "http"
-version = "0.2.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb"
-dependencies = [
- "bytes",
- "fnv",
- "itoa",
-]
-
-[[package]]
-name = "http-body"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
-dependencies = [
- "bytes",
- "http",
- "pin-project-lite",
-]
-
-[[package]]
-name = "httparse"
-version = "1.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
-
-[[package]]
-name = "httpdate"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
-
-[[package]]
-name = "hyper"
-version = "0.14.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80"
-dependencies = [
- "bytes",
- "futures-channel",
- "futures-core",
- "futures-util",
- "h2",
- "http",
- "http-body",
- "httparse",
- "httpdate",
- "itoa",
- "pin-project-lite",
- "socket2",
- "tokio",
- "tower-service",
- "tracing",
- "want",
-]
-
-[[package]]
-name = "hyper-tls"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
-dependencies = [
- "bytes",
- "hyper",
- "native-tls",
- "tokio",
- "tokio-native-tls",
-]
-
-[[package]]
-name = "iana-time-zone"
-version = "0.1.60"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
-dependencies = [
- "android_system_properties",
- "core-foundation-sys",
- "iana-time-zone-haiku",
- "js-sys",
- "wasm-bindgen",
- "windows-core",
-]
-
-[[package]]
-name = "iana-time-zone-haiku"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
-dependencies = [
- "cc",
-]
-
-[[package]]
-name = "icalendar"
-version = "0.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa4ffbcf3325ae94554c5259ce0b8907d37133c066cb3d424a2fa96aa1f10088"
-dependencies = [
- "chrono",
- "iso8601",
- "nom",
- "uuid",
-]
-
-[[package]]
-name = "idna"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
-dependencies = [
- "unicode-bidi",
- "unicode-normalization",
-]
-
-[[package]]
-name = "idna"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
-dependencies = [
- "unicode-bidi",
- "unicode-normalization",
-]
-
-[[package]]
-name = "indexmap"
-version = "2.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177"
-dependencies = [
- "equivalent",
- "hashbrown",
-]
-
-[[package]]
-name = "ipnet"
-version = "2.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
-
-[[package]]
-name = "iso8601"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "924e5d73ea28f59011fec52a0d12185d496a9b075d360657aed2a5707f701153"
-dependencies = [
- "nom",
-]
-
-[[package]]
-name = "itoa"
-version = "1.0.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
-
-[[package]]
-name = "js-sys"
-version = "0.3.68"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee"
-dependencies = [
- "wasm-bindgen",
-]
-
-[[package]]
-name = "lazy_static"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-
-[[package]]
-name = "libc"
-version = "0.2.153"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
-
-[[package]]
-name = "linux-raw-sys"
-version = "0.4.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
-
-[[package]]
-name = "log"
-version = "0.4.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
-
-[[package]]
-name = "match_cfg"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
-
-[[package]]
-name = "memchr"
-version = "2.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
-
-[[package]]
-name = "mime"
-version = "0.3.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
-
-[[package]]
-name = "minimal-lexical"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
-
-[[package]]
-name = "miniz_oxide"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
-dependencies = [
- "adler",
-]
-
-[[package]]
-name = "mio"
-version = "0.8.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
-dependencies = [
- "libc",
- "wasi",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "native-tls"
-version = "0.2.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
-dependencies = [
- "lazy_static",
- "libc",
- "log",
- "openssl",
- "openssl-probe",
- "openssl-sys",
- "schannel",
- "security-framework",
- "security-framework-sys",
- "tempfile",
-]
-
-[[package]]
-name = "nom"
-version = "7.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
-dependencies = [
- "memchr",
- "minimal-lexical",
-]
-
-[[package]]
-name = "num-conv"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
-
-[[package]]
-name = "num-traits"
-version = "0.2.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "num_cpus"
-version = "1.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
-dependencies = [
- "hermit-abi",
- "libc",
-]
-
-[[package]]
-name = "object"
-version = "0.32.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "once_cell"
-version = "1.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
-
-[[package]]
-name = "openssl"
-version = "0.10.64"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f"
-dependencies = [
- "bitflags 2.4.2",
- "cfg-if",
- "foreign-types",
- "libc",
- "once_cell",
- "openssl-macros",
- "openssl-sys",
-]
-
-[[package]]
-name = "openssl-macros"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "openssl-probe"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
-
-[[package]]
-name = "openssl-sys"
-version = "0.9.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae94056a791d0e1217d18b6cbdccb02c61e3054fc69893607f4067e3bb0b1fd1"
-dependencies = [
- "cc",
- "libc",
- "pkg-config",
- "vcpkg",
-]
-
-[[package]]
-name = "percent-encoding"
-version = "2.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
-
-[[package]]
-name = "pin-project-lite"
-version = "0.2.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
-
-[[package]]
-name = "pin-utils"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
-
-[[package]]
-name = "pkg-config"
-version = "0.3.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
-
-[[package]]
-name = "powerfmt"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.78"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "psl-types"
-version = "2.0.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac"
-
-[[package]]
-name = "publicsuffix"
-version = "2.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457"
-dependencies = [
- "idna 0.3.0",
- "psl-types",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.35"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "reqwest"
-version = "0.11.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251"
-dependencies = [
- "base64",
- "bytes",
- "cookie",
- "cookie_store",
- "encoding_rs",
- "futures-core",
- "futures-util",
- "h2",
- "http",
- "http-body",
- "hyper",
- "hyper-tls",
- "ipnet",
- "js-sys",
- "log",
- "mime",
- "native-tls",
- "once_cell",
- "percent-encoding",
- "pin-project-lite",
- "rustls-pemfile",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "sync_wrapper",
- "system-configuration",
- "tokio",
- "tokio-native-tls",
- "tower-service",
- "url",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
- "winreg",
-]
-
-[[package]]
-name = "rustc-demangle"
-version = "0.1.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
-
-[[package]]
-name = "rustix"
-version = "0.38.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
-dependencies = [
- "bitflags 2.4.2",
- "errno",
- "libc",
- "linux-raw-sys",
- "windows-sys 0.52.0",
-]
-
-[[package]]
-name = "rustls-pemfile"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
-dependencies = [
- "base64",
-]
-
-[[package]]
-name = "ryu"
-version = "1.0.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
-
-[[package]]
-name = "schannel"
-version = "0.1.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534"
-dependencies = [
- "windows-sys 0.52.0",
-]
-
-[[package]]
-name = "security-framework"
-version = "2.9.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
-dependencies = [
- "bitflags 1.3.2",
- "core-foundation",
- "core-foundation-sys",
- "libc",
- "security-framework-sys",
-]
-
-[[package]]
-name = "security-framework-sys"
-version = "2.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
-name = "serde"
-version = "1.0.196"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32"
-dependencies = [
- "serde_derive",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.196"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "serde_json"
-version = "1.0.114"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
-dependencies = [
- "itoa",
- "ryu",
- "serde",
-]
-
-[[package]]
-name = "serde_repr"
-version = "0.1.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "serde_urlencoded"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
-dependencies = [
- "form_urlencoded",
- "itoa",
- "ryu",
- "serde",
-]
-
-[[package]]
-name = "slab"
-version = "0.4.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "socket2"
-version = "0.5.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
-dependencies = [
- "libc",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.49"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "sync_wrapper"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
-
-[[package]]
-name = "system-configuration"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
-dependencies = [
- "bitflags 1.3.2",
- "core-foundation",
- "system-configuration-sys",
-]
-
-[[package]]
-name = "system-configuration-sys"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
-name = "tempfile"
-version = "3.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67"
-dependencies = [
- "cfg-if",
- "fastrand",
- "rustix",
- "windows-sys 0.52.0",
-]
-
-[[package]]
-name = "time"
-version = "0.3.34"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
-dependencies = [
- "deranged",
- "itoa",
- "num-conv",
- "powerfmt",
- "serde",
- "time-core",
- "time-macros",
-]
-
-[[package]]
-name = "time-core"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
-
-[[package]]
-name = "time-macros"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774"
-dependencies = [
- "num-conv",
- "time-core",
-]
-
-[[package]]
-name = "tinyvec"
-version = "1.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
-dependencies = [
- "tinyvec_macros",
-]
-
-[[package]]
-name = "tinyvec_macros"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
-
-[[package]]
-name = "tokio"
-version = "1.36.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
-dependencies = [
- "backtrace",
- "bytes",
- "libc",
- "mio",
- "num_cpus",
- "pin-project-lite",
- "socket2",
- "tokio-macros",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "tokio-macros"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "tokio-native-tls"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
-dependencies = [
- "native-tls",
- "tokio",
-]
-
-[[package]]
-name = "tokio-util"
-version = "0.7.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15"
-dependencies = [
- "bytes",
- "futures-core",
- "futures-sink",
- "pin-project-lite",
- "tokio",
- "tracing",
-]
-
-[[package]]
-name = "tower-service"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
-
-[[package]]
-name = "tracing"
-version = "0.1.40"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
-dependencies = [
- "pin-project-lite",
- "tracing-core",
-]
-
-[[package]]
-name = "tracing-core"
-version = "0.1.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
-dependencies = [
- "once_cell",
-]
-
-[[package]]
-name = "try-lock"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
-
-[[package]]
-name = "unicode-bidi"
-version = "0.3.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
-
-[[package]]
-name = "unicode-normalization"
-version = "0.1.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
-dependencies = [
- "tinyvec",
-]
-
-[[package]]
-name = "url"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
-dependencies = [
- "form_urlencoded",
- "idna 0.5.0",
- "percent-encoding",
-]
-
-[[package]]
-name = "uuid"
-version = "1.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a"
-dependencies = [
- "getrandom",
- "wasm-bindgen",
-]
-
-[[package]]
-name = "vcpkg"
-version = "0.2.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
-
-[[package]]
-name = "version_check"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
-
-[[package]]
-name = "want"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
-dependencies = [
- "try-lock",
-]
-
-[[package]]
-name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
-
-[[package]]
-name = "wasm-bindgen"
-version = "0.2.91"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f"
-dependencies = [
- "cfg-if",
- "wasm-bindgen-macro",
-]
-
-[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.91"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b"
-dependencies = [
- "bumpalo",
- "log",
- "once_cell",
- "proc-macro2",
- "quote",
- "syn",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-futures"
-version = "0.4.41"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97"
-dependencies = [
- "cfg-if",
- "js-sys",
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "wasm-bindgen-macro"
-version = "0.2.91"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed"
-dependencies = [
- "quote",
- "wasm-bindgen-macro-support",
-]
-
-[[package]]
-name = "wasm-bindgen-macro-support"
-version = "0.2.91"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "wasm-bindgen-backend",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-shared"
-version = "0.2.91"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
-
-[[package]]
-name = "web-sys"
-version = "0.3.68"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446"
-dependencies = [
- "js-sys",
- "wasm-bindgen",
-]
-
-[[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-
-[[package]]
-name = "windows-core"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
-dependencies = [
- "windows-targets 0.52.0",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
-dependencies = [
- "windows-targets 0.48.5",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
-dependencies = [
- "windows-targets 0.52.0",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
-dependencies = [
- "windows_aarch64_gnullvm 0.48.5",
- "windows_aarch64_msvc 0.48.5",
- "windows_i686_gnu 0.48.5",
- "windows_i686_msvc 0.48.5",
- "windows_x86_64_gnu 0.48.5",
- "windows_x86_64_gnullvm 0.48.5",
- "windows_x86_64_msvc 0.48.5",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
-dependencies = [
- "windows_aarch64_gnullvm 0.52.0",
- "windows_aarch64_msvc 0.52.0",
- "windows_i686_gnu 0.52.0",
- "windows_i686_msvc 0.52.0",
- "windows_x86_64_gnu 0.52.0",
- "windows_x86_64_gnullvm 0.52.0",
- "windows_x86_64_msvc 0.52.0",
-]
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
-
-[[package]]
-name = "winreg"
-version = "0.50.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
-dependencies = [
- "cfg-if",
- "windows-sys 0.48.0",
-]
diff --git a/pkgs/afvalcalendar/Cargo.toml b/pkgs/afvalcalendar/Cargo.toml
deleted file mode 100644
index f37dff1..0000000
--- a/pkgs/afvalcalendar/Cargo.toml
+++ /dev/null
@@ -1,16 +0,0 @@
-[package]
-name = "afvalcalendar"
-version = "0.1.0"
-edition = "2021"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-icalendar = "0.16.0"
-serde = { version = "1.0.195", features = ["derive"] }
-tokio = { version = "1.35.1", features = ["macros", "rt-multi-thread"] }
-reqwest = { version = "0.11", features = ["cookies", "json"] }
-chrono = { version = "0.4.34", features = ["serde"] }
-serde_json = "1.0.114"
-serde_repr = "0.1.18"
-hostname = "0.3.1"
diff --git a/pkgs/afvalcalendar/default.nix b/pkgs/afvalcalendar/default.nix
deleted file mode 100644
index 6392220..0000000
--- a/pkgs/afvalcalendar/default.nix
+++ /dev/null
@@ -1,12 +0,0 @@
-{ pkgs, rustPlatform, ... }:
-rustPlatform.buildRustPackage {
-  pname = "afvalcalendar";
-  version = "0.1.0";
-  src = ./.;
-
-  nativeBuildInputs = with pkgs; [ pkg-config ];
-
-  buildInputs = with pkgs; [ openssl ];
-
-  cargoHash = "sha256-JXx6aUKdKbUTBCwlBw5i1hZy8ofCfSrhLCwFzqdA8cI=";
-}
diff --git a/pkgs/afvalcalendar/src/calendar.rs b/pkgs/afvalcalendar/src/calendar.rs
deleted file mode 100644
index 2c76d7f..0000000
--- a/pkgs/afvalcalendar/src/calendar.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-use chrono::{Duration, NaiveDate};
-use icalendar::{Alarm, Calendar, Component, Event, EventLike, Property};
-
-use crate::trash::TrashType;
-
-pub(crate) fn calendar_from_pickup_dates(dates: Vec<(TrashType, NaiveDate)>) -> Calendar {
-    let mut ical = Calendar::new();
-    ical.name("Twente Milieu Afvalkalender");
-
-    let events = dates.iter().map(|date| {
-        let description = match date.0 {
-            TrashType::Grey => "Restafval wordt opgehaald",
-            TrashType::Green => "GFT wordt opgehaald",
-            TrashType::Paper => "Papier wordt opgehaald",
-            TrashType::Packages => "Verpakkingen worden opgehaald",
-        };
-
-        let color = Property::new(
-            "COLOR",
-            match date.0 {
-                TrashType::Grey => "darkgray",
-                TrashType::Green => "darkgreen",
-                TrashType::Paper => "royalblue",
-                TrashType::Packages => "darkorange",
-            },
-        );
-
-        let reminder = Alarm::display(description, -Duration::hours(5));
-
-        Event::new()
-            .all_day(date.1)
-            .summary(description)
-            .append_property(color)
-            .alarm(reminder)
-            .done()
-    });
-
-    for event in events {
-        ical.push(event);
-    }
-
-    ical.done()
-}
diff --git a/pkgs/afvalcalendar/src/main.rs b/pkgs/afvalcalendar/src/main.rs
deleted file mode 100644
index e8023f7..0000000
--- a/pkgs/afvalcalendar/src/main.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-mod calendar;
-mod trash;
-
-#[tokio::main]
-async fn main() {
-    match trash::get_pickup_dates().await {
-        Ok(dates) => {
-            let calendar = calendar::calendar_from_pickup_dates(dates);
-            calendar.print().unwrap();
-        }
-        Err(error) => {
-            eprintln!("{}", error);
-        }
-    }
-}
diff --git a/pkgs/afvalcalendar/src/trash.rs b/pkgs/afvalcalendar/src/trash.rs
deleted file mode 100644
index 89a84d0..0000000
--- a/pkgs/afvalcalendar/src/trash.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-use chrono::{Months, NaiveDate, NaiveDateTime, Utc};
-use serde::Deserialize;
-use serde_repr::Deserialize_repr;
-
-#[derive(Deserialize, Debug)]
-#[serde(rename_all = "camelCase")]
-struct CalendarAPIDatum {
-    pickup_dates: Vec<NaiveDateTime>,
-    pickup_type: TrashType,
-}
-
-#[derive(Deserialize, Debug)]
-#[serde(rename_all = "camelCase")]
-struct CalendarAPIResponse {
-    data_list: Vec<CalendarAPIDatum>,
-}
-
-#[derive(Copy, Clone, Deserialize_repr, Debug)]
-#[repr(u8)]
-pub(crate) enum TrashType {
-    Grey = 0,
-    Green = 1,
-    Paper = 2,
-    Packages = 10,
-}
-
-pub(crate) async fn get_pickup_dates() -> Result<Vec<(TrashType, NaiveDate)>, reqwest::Error> {
-    let today = Utc::now().date_naive();
-    let next_month = (today + Months::new(1)).to_string();
-    let today = today.to_string();
-
-    let client = reqwest::Client::new();
-
-    let params = [
-        ("companyCode", "8d97bb56-5afd-4cbc-a651-b4f7314264b4"),
-        ("uniqueAddressID", "1300002485"),
-        ("startDate", &today),
-        ("endDate", &next_month),
-    ];
-
-    let calendar = client
-        .post("https://twentemilieuapi.ximmio.com/api/GetCalendar")
-        .form(&params)
-        .send()
-        .await?
-        .json::<CalendarAPIResponse>()
-        .await?;
-
-    Ok(calendar
-        .data_list
-        .iter()
-        .flat_map(|datum| {
-            datum
-                .pickup_dates
-                .iter()
-                .map(|date| (datum.pickup_type, NaiveDate::from(*date)))
-        })
-        .collect::<Vec<(TrashType, NaiveDate)>>())
-}
diff --git a/pkgs/afvalcalendar/test.rest b/pkgs/afvalcalendar/test.rest
deleted file mode 100644
index d2d409e..0000000
--- a/pkgs/afvalcalendar/test.rest
+++ /dev/null
@@ -1,4 +0,0 @@
-POST https://twentemilieuapi.ximmio.com/api/GetCalendar
-Content-Type: application/x-www-form-urlencoded
-
-companyCode=8d97bb56-5afd-4cbc-a651-b4f7314264b4&uniqueAddressID=1300002485&startDate=2024-02-01&endDate=2024-02-29
diff --git a/pkgs/default.nix b/pkgs/default.nix
index a9d7aa1..24ade6f 100644
--- a/pkgs/default.nix
+++ b/pkgs/default.nix
@@ -8,7 +8,6 @@ in
   prometheus-fail2ban-exporter = callPackage ./prometheus/fail2ban-exporter.nix {
     sources = pkgs.callPackage ./_sources_pkgs/generated.nix { };
   };
-  afvalcalendar = callPackage ./afvalcalendar { };
 }
 // (
   # Add nextcloud apps

From b3be7bd88fc70c7d0262798fe241dc297352eaaa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sun, 19 Jan 2025 00:09:40 +0800
Subject: [PATCH 25/67] bump: Update to NixOS 24.11

---
 configuration/default.nix                     |  2 -
 .../hardware-specific/hetzner/default.nix     |  8 +-
 configuration/services/metrics/options.nix    | 10 ++-
 configuration/services/nextcloud.nix          |  6 +-
 configuration/services/wireguard.nix          | 22 +++--
 flake.lock                                    | 61 ++++++++-----
 flake.nix                                     | 14 +--
 pkgs/_sources_nextcloud/generated.json        | 86 -------------------
 pkgs/_sources_nextcloud/generated.nix         | 52 -----------
 pkgs/default.nix                              | 11 +--
 pkgs/mkNextcloudApp.nix                       |  7 --
 pkgs/nextcloud-apps.toml                      | 30 -------
 12 files changed, 66 insertions(+), 243 deletions(-)
 delete mode 100644 pkgs/_sources_nextcloud/generated.json
 delete mode 100644 pkgs/_sources_nextcloud/generated.nix
 delete mode 100644 pkgs/mkNextcloudApp.nix
 delete mode 100644 pkgs/nextcloud-apps.toml

diff --git a/configuration/default.nix b/configuration/default.nix
index 48ee8c4..18d124e 100644
--- a/configuration/default.nix
+++ b/configuration/default.nix
@@ -35,13 +35,11 @@
     (final: prev: {
       local = import ../pkgs {
         pkgs = prev;
-        lib = prev.lib;
       };
     })
   ];
 
   nix = {
-    package = pkgs.nixFlakes;
     extraOptions = ''
       experimental-features = nix-command flakes
     '';
diff --git a/configuration/hardware-specific/hetzner/default.nix b/configuration/hardware-specific/hetzner/default.nix
index 6795377..3e35eb0 100644
--- a/configuration/hardware-specific/hetzner/default.nix
+++ b/configuration/hardware-specific/hetzner/default.nix
@@ -19,13 +19,11 @@
     addresses = [
       # IPv4
       {
-        addressConfig = {
-          Address = "116.202.158.55/32";
-          Peer = "116.202.158.1/32"; # Gateway
-        };
+        Address = "116.202.158.55/32";
+        Peer = "116.202.158.1/32"; # Gateway
       }
       # IPv6
-      { addressConfig.Address = "2a01:4f8:10b:3c85::2/64"; }
+      { Address = "2a01:4f8:10b:3c85::2/64"; }
     ];
 
     networkConfig = {
diff --git a/configuration/services/metrics/options.nix b/configuration/services/metrics/options.nix
index 5dd17a3..69cbd6b 100644
--- a/configuration/services/metrics/options.nix
+++ b/configuration/services/metrics/options.nix
@@ -213,7 +213,15 @@ in
       let
         allExporters = lib.mapAttrs (name: exporter: { inherit (exporter) listenAddress port; }) (
           (lib.filterAttrs (
-            _: exporter: builtins.isAttrs exporter && exporter.enable
+            name: exporter:
+            # A bunch of deprecated exporters that need to be ignored
+            !(builtins.elem name [
+              "minio"
+              "tor"
+              "unifi-poller"
+            ])
+            && builtins.isAttrs exporter
+            && exporter.enable
           ) config.services.prometheus.exporters)
           // config.services.prometheus.extraExporters
         );
diff --git a/configuration/services/nextcloud.nix b/configuration/services/nextcloud.nix
index 205d702..45cfe80 100644
--- a/configuration/services/nextcloud.nix
+++ b/configuration/services/nextcloud.nix
@@ -18,10 +18,10 @@ in
         packageOverrides = final: prev: {
           extensions = prev.extensions // {
             pgsql = prev.extensions.pgsql.overrideAttrs (old: {
-              configureFlags = [ "--with-pgsql=${config.services.postgresql.package}" ];
+              configureFlags = [ "--with-pgsql=${lib.getDev config.services.postgresql.package}" ];
             });
             pdo_pgsql = prev.extensions.pdo_pgsql.overrideAttrs (old: {
-              configureFlags = [ "--with-pdo-pgsql=${config.services.postgresql.package}" ];
+              configureFlags = [ "--with-pdo-pgsql=${lib.getDev config.services.postgresql.package}" ];
             });
           };
         };
@@ -51,7 +51,7 @@ in
     };
 
     extraApps = {
-      inherit (pkgs.local)
+      inherit (config.services.nextcloud.package.packages.apps)
         bookmarks
         calendar
         contacts
diff --git a/configuration/services/wireguard.nix b/configuration/services/wireguard.nix
index a5185c5..bbab22e 100644
--- a/configuration/services/wireguard.nix
+++ b/configuration/services/wireguard.nix
@@ -24,12 +24,10 @@
         };
 
         wireguardPeers = [
+          # yui
           {
-            # yui
-            wireguardPeerConfig = {
-              AllowedIPs = [ "10.45.249.2/32" ];
-              PublicKey = "5mlnqEVJWks5OqgeFA2bLIrvST9TlCE81Btl+j4myz0=";
-            };
+            AllowedIPs = [ "10.45.249.2/32" ];
+            PublicKey = "5mlnqEVJWks5OqgeFA2bLIrvST9TlCE81Btl+j4myz0=";
           }
         ];
       };
@@ -40,23 +38,23 @@
         matchConfig.Name = "wg0";
 
         networkConfig = {
+          Description = "VLAN";
+
           Address = [
             "10.45.249.1/32"
             # TODO(tlater): Add IPv6 whenever that becomes relevant
           ];
 
-          IPForward = "yes";
+          IPv4Forwarding = "yes";
           IPv4ProxyARP = "yes";
         };
 
         routes = [
           {
-            routeConfig = {
-              Source = "10.45.249.0/24";
-              Destination = "10.45.249.0/24";
-              Gateway = "10.45.249.1";
-              GatewayOnLink = "no";
-            };
+            Source = "10.45.249.0/24";
+            Destination = "10.45.249.0/24";
+            Gateway = "10.45.249.1";
+            GatewayOnLink = "no";
           }
         ];
 
diff --git a/flake.lock b/flake.lock
index 9aff775..d349bea 100644
--- a/flake.lock
+++ b/flake.lock
@@ -47,11 +47,11 @@
         "pyproject-nix": "pyproject-nix"
       },
       "locked": {
-        "lastModified": 1719685993,
-        "narHash": "sha256-04gy1icwnGO3ZXF6r96yBm/C0PNPzeLxA/8xzzq0dBI=",
+        "lastModified": 1735160684,
+        "narHash": "sha256-n5CwhmqKxifuD4Sq4WuRP/h5LO6f23cGnSAuJemnd/4=",
         "owner": "nix-community",
         "repo": "dream2nix",
-        "rev": "1b5e01219a32324c8f6889fe1f4db933ec7932f6",
+        "rev": "8ce6284ff58208ed8961681276f82c2f8f978ef4",
         "type": "github"
       },
       "original": {
@@ -69,11 +69,11 @@
         "rust-analyzer-src": "rust-analyzer-src"
       },
       "locked": {
-        "lastModified": 1719815435,
-        "narHash": "sha256-K2xFp142onP35jcx7li10xUxNVEVRWjAdY8DSuR7Naw=",
+        "lastModified": 1737181903,
+        "narHash": "sha256-lvp77MhGzSN+ICd0MugppCjQR6cmlM2iAC5cjy2ZsaA=",
         "owner": "nix-community",
         "repo": "fenix",
-        "rev": "ebfe2c639111d7e82972a12711206afaeeda2450",
+        "rev": "ac79bb490b8c1af4bbc587b84c76f9527d6b14f7",
         "type": "github"
       },
       "original": {
@@ -114,6 +114,22 @@
         "type": "github"
       }
     },
+    "flake-compat_3": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1696426674,
+        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
+        "owner": "edolstra",
+        "repo": "flake-compat",
+        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
+        "type": "github"
+      },
+      "original": {
+        "owner": "edolstra",
+        "repo": "flake-compat",
+        "type": "github"
+      }
+    },
     "flake-utils": {
       "inputs": {
         "systems": "systems_2"
@@ -242,11 +258,11 @@
     },
     "nixpkgs_3": {
       "locked": {
-        "lastModified": 1719468428,
-        "narHash": "sha256-vN5xJAZ4UGREEglh3lfbbkIj+MPEYMuqewMn4atZFaQ=",
+        "lastModified": 1729850857,
+        "narHash": "sha256-WvLXzNNnnw+qpFOmgaM3JUlNEH+T4s22b5i2oyyCpXE=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "1e3deb3d8a86a870d925760db1a5adecc64d329d",
+        "rev": "41dea55321e5a999b17033296ac05fe8a8b5a257",
         "type": "github"
       },
       "original": {
@@ -305,6 +321,7 @@
     },
     "purescript-overlay": {
       "inputs": {
+        "flake-compat": "flake-compat_3",
         "nixpkgs": [
           "tlaternet-webserver",
           "dream2nix",
@@ -313,11 +330,11 @@
         "slimlock": "slimlock"
       },
       "locked": {
-        "lastModified": 1696022621,
-        "narHash": "sha256-eMjFmsj2G1E0Q5XiibUNgFjTiSz0GxIeSSzzVdoN730=",
+        "lastModified": 1728546539,
+        "narHash": "sha256-Sws7w0tlnjD+Bjck1nv29NjC5DbL6nH5auL9Ex9Iz2A=",
         "owner": "thomashoneyman",
         "repo": "purescript-overlay",
-        "rev": "047c7933abd6da8aa239904422e22d190ce55ead",
+        "rev": "4ad4c15d07bd899d7346b331f377606631eb0ee4",
         "type": "github"
       },
       "original": {
@@ -359,11 +376,11 @@
     "rust-analyzer-src": {
       "flake": false,
       "locked": {
-        "lastModified": 1719760370,
-        "narHash": "sha256-fsxAuW6RxKZYjAP3biUC6C4vaYFhDfWv8lp1Tmx3ZCY=",
+        "lastModified": 1737140097,
+        "narHash": "sha256-m4SN8DeKzsP10EQFS7+2zgGfCrMhTfTt1H0QRNesD08=",
         "owner": "rust-lang",
         "repo": "rust-analyzer",
-        "rev": "ea7fdada6a0940b239ddbde2048a4d7dac1efe1e",
+        "rev": "f61bfa4d7feb84d07538d361fe77d34a29e3b375",
         "type": "github"
       },
       "original": {
@@ -383,11 +400,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1688610262,
-        "narHash": "sha256-Wg0ViDotFWGWqKIQzyYCgayeH8s4U1OZcTiWTQYdAp4=",
+        "lastModified": 1688756706,
+        "narHash": "sha256-xzkkMv3neJJJ89zo3o2ojp7nFeaZc2G0fYwNXNJRFlo=",
         "owner": "thomashoneyman",
         "repo": "slimlock",
-        "rev": "b5c6cdcaf636ebbebd0a1f32520929394493f1a6",
+        "rev": "cf72723f59e2340d24881fd7bf61cb113b4c407c",
         "type": "github"
       },
       "original": {
@@ -505,11 +522,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1719851829,
-        "narHash": "sha256-M5miiIbiwP4uArTyeIr/RKA857rP14AEJUe11AZsKAc=",
+        "lastModified": 1737271785,
+        "narHash": "sha256-yVdaaawYK1/q9V5btfGpxVCQBdyQx1WcFHYO0yX5bP8=",
         "ref": "refs/heads/master",
-        "rev": "4a099f27a27f4107ceb14969e2158eaabebcf1d4",
-        "revCount": 74,
+        "rev": "5d3d84836101ec9b9867a5f754c9ee1b9d4dc538",
+        "revCount": 76,
         "type": "git",
         "url": "https://gitea.tlater.net/tlaternet/tlaternet.git"
       },
diff --git a/flake.nix b/flake.nix
index ea27f2d..e6f1dcb 100644
--- a/flake.nix
+++ b/flake.nix
@@ -2,7 +2,7 @@
   description = "tlater.net host configuration";
 
   inputs = {
-    nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05-small";
+    nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11-small";
     nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable-small";
     disko = {
       url = "github:nix-community/disko";
@@ -132,18 +132,6 @@
               ${nvfetcher-bin} -o _sources_pkgs -c nvfetcher.toml
             '').outPath;
         };
-
-        update-nextcloud-apps = {
-          type = "app";
-          program =
-            let
-              nvfetcher-bin = "${nvfetcher.packages.${system}.default}/bin/nvfetcher";
-            in
-            (pkgs.writeShellScript "update-nextcloud-apps" ''
-              cd "$(git rev-parse --show-toplevel)/pkgs"
-              ${nvfetcher-bin} -o _sources_nextcloud -c nextcloud-apps.toml
-            '').outPath;
-        };
       };
 
       ###########################
diff --git a/pkgs/_sources_nextcloud/generated.json b/pkgs/_sources_nextcloud/generated.json
deleted file mode 100644
index 1c553ce..0000000
--- a/pkgs/_sources_nextcloud/generated.json
+++ /dev/null
@@ -1,86 +0,0 @@
-{
-    "bookmarks": {
-        "cargoLocks": null,
-        "date": null,
-        "extract": null,
-        "name": "bookmarks",
-        "passthru": null,
-        "pinned": false,
-        "src": {
-            "sha256": "sha256-7BTNFsNcqmDACpj5PMEiS71xtr50v7Sqo3qeCL+3J9s=",
-            "type": "tarball",
-            "url": "https://github.com/nextcloud/bookmarks/releases/download/v14.2.6/bookmarks-14.2.6.tar.gz"
-        },
-        "version": "14.2.6"
-    },
-    "calendar": {
-        "cargoLocks": null,
-        "date": null,
-        "extract": null,
-        "name": "calendar",
-        "passthru": null,
-        "pinned": false,
-        "src": {
-            "sha256": "sha256-X2XcH7HpxgizCEJVrazGtzNQTBihFxvTq/ybK939cxo=",
-            "type": "tarball",
-            "url": "https://github.com/nextcloud-releases/calendar/releases/download/v4.7.16/calendar-v4.7.16.tar.gz"
-        },
-        "version": "v4.7.16"
-    },
-    "contacts": {
-        "cargoLocks": null,
-        "date": null,
-        "extract": null,
-        "name": "contacts",
-        "passthru": null,
-        "pinned": false,
-        "src": {
-            "sha256": "sha256-HCEjiAqn6sTNXKW6O5X6Ta9Ll4ehvzmGZUj1c0ue2Xc=",
-            "type": "tarball",
-            "url": "https://github.com/nextcloud-releases/contacts/releases/download/v5.5.3/contacts-v5.5.3.tar.gz"
-        },
-        "version": "v5.5.3"
-    },
-    "cookbook": {
-        "cargoLocks": null,
-        "date": null,
-        "extract": null,
-        "name": "cookbook",
-        "passthru": null,
-        "pinned": false,
-        "src": {
-            "sha256": "sha256-Pfa+Xbopg20os+pnGgg+wpEX1MI5fz5JMb0K4a8rBhs=",
-            "type": "tarball",
-            "url": "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v0.11.2/Cookbook-0.11.2.tar.gz"
-        },
-        "version": "0.11.2"
-    },
-    "news": {
-        "cargoLocks": null,
-        "date": null,
-        "extract": null,
-        "name": "news",
-        "passthru": null,
-        "pinned": false,
-        "src": {
-            "sha256": "sha256-pnvyMZQ+NYMgH0Unfh5S19HdZSjnghgoUDAoi2KIXNI=",
-            "type": "tarball",
-            "url": "https://github.com/nextcloud/news/releases/download/25.0.0-alpha12/news.tar.gz"
-        },
-        "version": "25.0.0-alpha12"
-    },
-    "notes": {
-        "cargoLocks": null,
-        "date": null,
-        "extract": null,
-        "name": "notes",
-        "passthru": null,
-        "pinned": false,
-        "src": {
-            "sha256": "sha256-Cu73H0hJREbkskLbj56M8qUF1Tp4EazORlCF9rpPL90=",
-            "type": "tarball",
-            "url": "https://github.com/nextcloud-releases/notes/releases/download/v4.11.0/notes-v4.11.0.tar.gz"
-        },
-        "version": "v4.11.0"
-    }
-}
\ No newline at end of file
diff --git a/pkgs/_sources_nextcloud/generated.nix b/pkgs/_sources_nextcloud/generated.nix
deleted file mode 100644
index da275cc..0000000
--- a/pkgs/_sources_nextcloud/generated.nix
+++ /dev/null
@@ -1,52 +0,0 @@
-# This file was generated by nvfetcher, please do not modify it manually.
-{ fetchgit, fetchurl, fetchFromGitHub, dockerTools }:
-{
-  bookmarks = {
-    pname = "bookmarks";
-    version = "14.2.6";
-    src = fetchTarball {
-      url = "https://github.com/nextcloud/bookmarks/releases/download/v14.2.6/bookmarks-14.2.6.tar.gz";
-      sha256 = "sha256-7BTNFsNcqmDACpj5PMEiS71xtr50v7Sqo3qeCL+3J9s=";
-    };
-  };
-  calendar = {
-    pname = "calendar";
-    version = "v4.7.16";
-    src = fetchTarball {
-      url = "https://github.com/nextcloud-releases/calendar/releases/download/v4.7.16/calendar-v4.7.16.tar.gz";
-      sha256 = "sha256-X2XcH7HpxgizCEJVrazGtzNQTBihFxvTq/ybK939cxo=";
-    };
-  };
-  contacts = {
-    pname = "contacts";
-    version = "v5.5.3";
-    src = fetchTarball {
-      url = "https://github.com/nextcloud-releases/contacts/releases/download/v5.5.3/contacts-v5.5.3.tar.gz";
-      sha256 = "sha256-HCEjiAqn6sTNXKW6O5X6Ta9Ll4ehvzmGZUj1c0ue2Xc=";
-    };
-  };
-  cookbook = {
-    pname = "cookbook";
-    version = "0.11.2";
-    src = fetchTarball {
-      url = "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v0.11.2/Cookbook-0.11.2.tar.gz";
-      sha256 = "sha256-Pfa+Xbopg20os+pnGgg+wpEX1MI5fz5JMb0K4a8rBhs=";
-    };
-  };
-  news = {
-    pname = "news";
-    version = "25.0.0-alpha12";
-    src = fetchTarball {
-      url = "https://github.com/nextcloud/news/releases/download/25.0.0-alpha12/news.tar.gz";
-      sha256 = "sha256-pnvyMZQ+NYMgH0Unfh5S19HdZSjnghgoUDAoi2KIXNI=";
-    };
-  };
-  notes = {
-    pname = "notes";
-    version = "v4.11.0";
-    src = fetchTarball {
-      url = "https://github.com/nextcloud-releases/notes/releases/download/v4.11.0/notes-v4.11.0.tar.gz";
-      sha256 = "sha256-Cu73H0hJREbkskLbj56M8qUF1Tp4EazORlCF9rpPL90=";
-    };
-  };
-}
diff --git a/pkgs/default.nix b/pkgs/default.nix
index 24ade6f..131282d 100644
--- a/pkgs/default.nix
+++ b/pkgs/default.nix
@@ -1,6 +1,5 @@
-{ pkgs, lib }:
+{ pkgs }:
 let
-  inherit (builtins) fromJSON mapAttrs readFile;
   inherit (pkgs) callPackage;
 in
 {
@@ -9,11 +8,3 @@ in
     sources = pkgs.callPackage ./_sources_pkgs/generated.nix { };
   };
 }
-// (
-  # Add nextcloud apps
-  let
-    mkNextcloudApp = pkgs.callPackage ./mkNextcloudApp.nix { };
-    sources = fromJSON (readFile ./_sources_nextcloud/generated.json);
-  in
-  mapAttrs (_: source: mkNextcloudApp source) sources
-)
diff --git a/pkgs/mkNextcloudApp.nix b/pkgs/mkNextcloudApp.nix
deleted file mode 100644
index 095b0e8..0000000
--- a/pkgs/mkNextcloudApp.nix
+++ /dev/null
@@ -1,7 +0,0 @@
-{ fetchNextcloudApp, lib }:
-source:
-fetchNextcloudApp {
-  url = source.src.url;
-  sha256 = source.src.sha256;
-  license = "unlicense"; # Blatant lie
-}
diff --git a/pkgs/nextcloud-apps.toml b/pkgs/nextcloud-apps.toml
deleted file mode 100644
index 4e6e0b2..0000000
--- a/pkgs/nextcloud-apps.toml
+++ /dev/null
@@ -1,30 +0,0 @@
-[bookmarks]
-# src.github = "nextcloud/bookmarks"
-# src.prefix = "v"
-src.manual = "14.2.6"
-fetch.tarball = "https://github.com/nextcloud/bookmarks/releases/download/v$ver/bookmarks-$ver.tar.gz"
-
-[calendar]
-# src.github = "nextcloud-releases/calendar"
-src.manual = "v4.7.16"
-fetch.tarball = "https://github.com/nextcloud-releases/calendar/releases/download/$ver/calendar-$ver.tar.gz"
-
-[contacts]
-# src.github = "nextcloud-releases/contacts"
-src.manual = "v5.5.3"
-fetch.tarball = "https://github.com/nextcloud-releases/contacts/releases/download/$ver/contacts-$ver.tar.gz"
-
-[cookbook]
-src.github = "christianlupus-nextcloud/cookbook-releases"
-src.prefix = "v"
-fetch.tarball = "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v$ver/Cookbook-$ver.tar.gz"
-
-[news]
-# Update manually until angular rewrite is done
-# src.github = "nextcloud/news"
-src.manual = "25.0.0-alpha12"
-fetch.tarball = "https://github.com/nextcloud/news/releases/download/$ver/news.tar.gz"
-
-[notes]
-src.github = "nextcloud-releases/notes"
-fetch.tarball = "https://github.com/nextcloud-releases/notes/releases/download/$ver/notes-$ver.tar.gz"

From ac2913c1867bb3a090c30689e818ff630d41c9e0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sun, 19 Jan 2025 01:35:15 +0800
Subject: [PATCH 26/67] chore: Ignore manual gcroots

---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index dbee5b9..7512d76 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 /result
 *.qcow2
+/gcroots/

From 22e1ab609572f9d20a95faab1a59e874a12a9ab7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sun, 19 Jan 2025 17:48:33 +0800
Subject: [PATCH 27/67] chore: Remove nextcloud apps that I don't really use
 anymore

---
 configuration/services/nextcloud.nix | 2 --
 1 file changed, 2 deletions(-)

diff --git a/configuration/services/nextcloud.nix b/configuration/services/nextcloud.nix
index 45cfe80..55ce7f8 100644
--- a/configuration/services/nextcloud.nix
+++ b/configuration/services/nextcloud.nix
@@ -52,12 +52,10 @@ in
 
     extraApps = {
       inherit (config.services.nextcloud.package.packages.apps)
-        bookmarks
         calendar
         contacts
         cookbook
         news
-        notes
         ;
     };
   };

From 9efc952c7c3b40948196bbdc802d34965196d0fb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sun, 19 Jan 2025 18:13:11 +0800
Subject: [PATCH 28/67] bump: Update nextcloud

---
 configuration/services/nextcloud.nix | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/configuration/services/nextcloud.nix b/configuration/services/nextcloud.nix
index 55ce7f8..e54df14 100644
--- a/configuration/services/nextcloud.nix
+++ b/configuration/services/nextcloud.nix
@@ -5,7 +5,7 @@
   ...
 }:
 let
-  nextcloud = pkgs.nextcloud29;
+  nextcloud = pkgs.nextcloud30;
   hostName = "nextcloud.${config.services.nginx.domain}";
 in
 {

From 73c06e6ec8c3ab1f2d41625d0d6a9f790a37eee9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Wed, 22 Jan 2025 01:56:58 +0800
Subject: [PATCH 29/67] chore: Renew encryption keys

---
 .sops.yaml            |   2 +-
 keys/production.yaml  |  82 ++++++------
 keys/staging.yaml     |  56 ++++-----
 keys/users/tlater.asc | 284 +++++++++++++++++++++++++++++++++---------
 4 files changed, 296 insertions(+), 128 deletions(-)

diff --git a/.sops.yaml b/.sops.yaml
index 7444d2c..bed2365 100644
--- a/.sops.yaml
+++ b/.sops.yaml
@@ -1,5 +1,5 @@
 keys:
-  - &tlater 535B61015823443941C744DD12264F6BBDFABA89
+  - &tlater B9C7AE554602D82B1AC2CFD0BC7BB2DB17C78E42!
   - &server_tlaternet 8a3737d48f1035fe6c3a0a8fd6a1976ca74c7f3b
   - &server_hetzner1 0af7641adb8aa843136cf6d047f71da3e5ad79f9
   - &server_staging 2f5caa73e7ceea4fcc8d2881fde587e6737d2dbc
diff --git a/keys/production.yaml b/keys/production.yaml
index da90860..6dd4c21 100644
--- a/keys/production.yaml
+++ b/keys/production.yaml
@@ -35,59 +35,59 @@ sops:
     lastmodified: "2024-04-15T23:13:18Z"
     mac: ENC[AES256_GCM,data:3/v+WgSWJ+VcBSBe1Wkis3z+tMmSjbKzLFqBB8xugc6DvgQG8J+1HRrPucLnpNNtEdmpyoTa72U6fPm6JnyUsuj5pLEghLprOJkqQNdRI06fllhw+9d3e3twx6D4oIIsVH6/io4ElXrGsGQTsfNbYhgn+987wa3WP5N25fBac3U=,iv:FL3tzPutOMN6IPkQfXIu/JOZT+OzUSqpMSQrUeXZQHE=,tag:jL1BTsYTA9XjrsjFszxZhA==,type:str]
     pgp:
-        - created_at: "2024-03-18T04:02:00Z"
+        - created_at: "2025-01-21T17:55:44Z"
           enc: |-
             -----BEGIN PGP MESSAGE-----
 
-            hQEMA7x7stsXx45CAQf7BjF+HR3WKdMyAV6R1M0+lqDz6hBHKyGH7YBB/QZBqRbK
-            3hdABIwWUsqpHjleEOp/Gj0VhZqwagqHxK4Fp5G0r3QBupbAO8u/+DNI8wll0Nva
-            dlOh0Jqp4E17TkERMQL02rrQ1ZmpOYmPkCd2//xkmWAQ1LatHWeRVSRxQBuMtPQi
-            btrefcQNjQCvS9/60dp8oTu8nxlFA4iHCBQKNIKVGqQH7jkdIfMPdUILjCkCiyCc
-            h+OxlHZZnpU6U9A+hjMBinvCzebSkZh48VX/T33Kr+4b0CBr1gR9MSXKG9f2MPQP
-            PMl6rPvqSqG6ddN9QDI+0HEHYaRvxPIV8uDS36tVxNJeAQHB5/6Lt7hJdYWgwf5E
-            TLgbZ0IxB17++6K++GlaG8WHO65l1jzmkPlN+ZGcwnhibDxnZjP6kqGqDFcZP4ge
-            cnV0KnhYcC59IooQYrWKzAJex9rnwPo7MGKV6XwZOQ==
-            =Hy9T
+            hQEMA7x7stsXx45CAQf6AjhhYCHhRvJx4xxiXPMTfpIpAvseB1CXVfuhfj2r2yrf
+            3HfJnNOSDBcmHdp9fiLJattqfsykcGisUDVIplCeA7cIJjH3sf8MuIJXDTLmvE0Z
+            BmV8LuwP/UPQSZzY3w1eTAoYT/by35gfJm4ofipft2qyIjQuBgOlrg/0swvBl7LK
+            47mI6mVdds8RutHw/xhJZeNjKF/5tADPJ2CHjOHbCQhLji13Kpm3yObOnM8K2SfV
+            P9uVudCFN/ZBiTlVkB7PsuitwZx1fW0SR3jcWxbRd17M2k2RAQQDUCqPKaoJ3T3f
+            r2ExwmyO4j7G2vkFv1RgQnhAoHqqRZ1nSjNw1+27MNJeAbT1ddia2TC5Q2zjRZY9
+            tRJi2pNZH9A424lpIBLnkPl5rpCR/UZ+bqhaQ9C2kFMldSldPn8dMiBy8XG0Trji
+            B6X44Q/0RCsJD3FS61GASIjaWdEX0DdSOdhtbtBLLQ==
+            =yLOx
             -----END PGP MESSAGE-----
-          fp: 535B61015823443941C744DD12264F6BBDFABA89
-        - created_at: "2024-03-18T04:02:00Z"
+          fp: B9C7AE554602D82B1AC2CFD0BC7BB2DB17C78E42!
+        - created_at: "2025-01-21T17:55:44Z"
           enc: |-
             -----BEGIN PGP MESSAGE-----
 
-            hQIMA9ahl2ynTH87AQ/+LNXxC3acjs2+c38gHZRW6Am4XFx1t/4tfxIgaaK/Boq8
-            PGU5CFNOMDGv8u/cwyDbfNM7GuL5g7vrLmBXzSV5ErZqc6bJ0+ZCNPTRIxP1Vxph
-            tWiDIyTwuqUzxWpOlSzii2Sqhlp8CyiWzBe95eIr96XzDCCtfzyCZ0BYyKgpHHxB
-            BltH0/+0JZFiR19zvf6M99AHwM8OddRQkXav+mRIJQpA87ovVZcAv5skYGJgNCqN
-            55fbskuYmqEnloQCZVJ2+2ZXK5Qn/uq4fLJCiIdZm4YsctJnV5spzZIL+dcOty65
-            Plk77BWzLaU5UOKCBAJWrK8oZSTGOrp4VZqb62DuqMRejG0JXmneIVk7p79yn5eA
-            ANVMGRF4b8RP9YUhzE8HACFzQebKpUU8XKv9+qsmO9Le5jUhU3UQeCSSzT/T5Dr8
-            kLDNtmW+mliQnxFlKcVWq2JIG+HaQD1KLOAl0JBNCOSLif2ofaHahuZ15agbYeis
-            hyrBY92EhzqYXHk/Kzv4ff4r+WUs9NN7R4Gg+wfWvMcTtVfbi4Ht+pjjTtCZwK1C
-            M8JebQn0NZSpVi3e7Xaz1fQ5Tqrg8PHZtkYGoIHLRPJQwLn9PHYtGzC3rFAk+Fqq
-            5WWHELxfcsZ6DakAGSXPK/80QhEZkpGmKizTwrEde+7fpEPxjdzUqlmH3rv7mFzS
-            WAGSiBIMjLR6ofb65vpghbwh6gXkpCtgUyINRhx/D+Kj5Z4lGD1u1I05DT1xD6VJ
-            FAbnH7oZ3PJecoAXgRT05FndFA1xfPMCkugmec8ML/sEZt+c3kbrXaA=
-            =MqS3
+            hQIMA9ahl2ynTH87AQ/9F/lyLXn60X5Slcd9I7VPdM6x4IjFI0UwMAhMVv0GeimD
+            9Mj1vKW+l1v0gFtqCGjANEEYpXMr109CES+m6z7dNXcIQeR6pyjW6uCTiPUK/ZO/
+            ZQyhJR0zsT15BTHc6c9Eso9YedsggpRAbjjVIlmrTJx52LfqYYGoRA0XqcLE6LUS
+            6v6KR/299zzSHsTFVon6wac9wY7i1XvL0Q7JiYSNV2cNADiCJdCIBw1UkaSVH1uz
+            sTVdoEoQ1m7hu9pgg4UksUzi9IV3xBpte82tlEK9p0M+RXK/02fjMTWcx3q5fnjN
+            pBu3HkVzLpAjAQHMQ/O2cgbjFmwgjp5APUhn3IBx5M3F2ypGICnAvsrjfzalTChN
+            nkCmTfLynNIL1bX7PViABX2Q/yXGzPqFDe96pPw2hGjOXmxjKxjDoLT2IHixYp4D
+            cxb5519/WmOMrFd4SJeGiUR2Ph/VBZBVGafRfGAKMzxi666igWjwSU0YSDYeEUW/
+            BalkkWoz/KQZ5HgQwL9dyp26/cjDtpIwe8jLKVNI6aWhZ2ZmBxFwNEB6fE1txOjf
+            ceIJAfm8y2qIolw3TpBAFk6s53jir17SrEux9VzfiEfFeQ0g5q7cjAs5HfhTOMfh
+            iuUnHcCFy27wd+8bPxEaRYR57u7hneenTn3BMuu1CZputDFJWRvweMZk3cH8tiXS
+            WAGpXw7aKGIOpxe7Ye5X+T3xvYCBN77aFQKkrOmHMWFCbkr2QfnwVanxmmL9BwxF
+            rf8pG+H0URxBAsy9RZzSC+dXugnwnNBse3wupXf5YkipLx3rX9gtz4Y=
+            =a7xO
             -----END PGP MESSAGE-----
           fp: 8a3737d48f1035fe6c3a0a8fd6a1976ca74c7f3b
-        - created_at: "2024-03-18T04:02:00Z"
+        - created_at: "2025-01-21T17:55:44Z"
           enc: |-
             -----BEGIN PGP MESSAGE-----
 
-            hQIMA0f3HaPlrXn5AQ/+N5NK5UJdtw5e7O9T4hfIhtMXci/og1cJiI64daSyNeDH
-            jq+CPJ8e73yiTPwu6wHHqfuEhlEuI6sJY0ZJVFU+h4SIBtG21veGEz7GzlYgBCJm
-            xvJHXjtM8AprqnFVO7Fj9QA/ik5QBP6ZpkOY7j8/qf1G7alOIne/MYRALXDvvIMH
-            HTWE+Y2N57yZK55Pokmdw10hawbrn/N1nt2Y7sa1+5TlRNtuA/+zLkXtEjRr5U3N
-            DId+hqCKgXDqKLBMkh4mZUTGOGsk8eeKAWwyPp9+8A5/0rfy+xOJYEjjHICXQMSE
-            zfe6qvj/fRJKGzT5lEzD+ZKHlR0zHEwGRfHqrVUTdPcPdKj3DZILjsoe5ba4VlAp
-            sS0CAYTg3YuWMT4iHuOQlY5IoQxHHrn7k8ox5iZULFecg58f6r6iJL3AepDYWAey
-            gtQXYBeaeCm5Ddwmd6TBVz8Q4bCVYIrHbVeAhSDkxfrWLc5UORggvLEWiXilGDJi
-            DzAv0MVHE2Wa3eOJLq05K2/LBqRBD1XYM3dcS6JSdFxWWMzvLdUOB4dAuPt9gpl9
-            liaA13Blw/ev+U4ADxptrl+QuYRbWz3z6rniYpluSrTbVCKFRoHXSGFPy5u8/N6O
-            QyjfoovIBxXKnbUq2kMoFa/qFpc1pDUn0sjQNsUBdtorAu3Up4icyoih7qwx2J3S
-            WAGB1jHWMfcsBJqPwjRYkqBf6MuwHAZWdd+zvj/fKfft9jtxLcCGOIM6QdfiWbl0
-            Wq4gHdH7OhSy+ZgRnaBRt/GAkzkHvfG68HfulviHZ1h2mrQN1y3mxpg=
-            =RCYB
+            hQIMA0f3HaPlrXn5ARAAph6bpRqnO1TKEE7K6cMCxCA9k3xj7hknBdHN1KlIQkeb
+            LUOW9lvxh96q/fQ3NvZXpEQqZoEgdhnYTHgr/Hqx7VSksSicOkJLorrBLELjP1Xo
+            FKTxRYQmgZmgmBc0u7+lF2t0VLey6DfsC9ehY2LQcRuY9WxxCp2nDjjR4wrfmMKi
+            i/SbpaM9Q29DpdNpwkSlTe2sKr+uMDVA2rCrjpisSDiUBgPe2eJEYPQJ7DHFxB4N
+            26NHS+QtUgZhAA1DOGYZvrXzqcZSeAPGk8WXY44KA7o2iRFw+TczpF/VaMHRR5vN
+            M62IoXGqnMIBau+tsiE1JEVg60DIHpBjsEY/WUgbNX02zfaHcp1OenxU4p7W19Xn
+            Y8psPm7JNzmi3+nItB2i3+OLQrumk6VaT021ykterc52tR/3ejCzQCsfbqDLnc/6
+            r2SvNVDiKpxQ/iFyHb0uLHWy0Jx0lYwmMUrThe1f4k/+m9fEPrA5v/1kTGY5o1Iy
+            aTuHE19VtB6V+g1H6ZRPr8g8wn/3pg1nC2vUoRzT+oUudxrijrUH8SSlwhu59y1z
+            7SrdMmtqA1/JsGNMawCLWd63u+/3GC9LmZzK2h/bV/R4DG5f8tsCpy9BrFAHqTMs
+            lZ3SONUUeM3uMOggQ/JT26EVxECmNGYIX1TYLOxcqisRXLbfco5LEc6T8PJvdivS
+            WAFr6kBMdoeWhUT8MdT5AJBm9mo95A0WM8I14pGrszaezfgo9zc2zs0ebdLEjhI4
+            jlTf4tXgK3RG455CRWOd9OA3ukR83W7UW6LYjoNaDWHw2RXZlb+hv8E=
+            =+MFT
             -----END PGP MESSAGE-----
           fp: 0af7641adb8aa843136cf6d047f71da3e5ad79f9
     unencrypted_suffix: _unencrypted
diff --git a/keys/staging.yaml b/keys/staging.yaml
index 17e7875..091424d 100644
--- a/keys/staging.yaml
+++ b/keys/staging.yaml
@@ -35,39 +35,39 @@ sops:
     lastmodified: "2024-04-15T23:13:27Z"
     mac: ENC[AES256_GCM,data:JhEVrKF2Jsqpdztcr3g5lMrgEFeLXfBRQTwQJ6PmLSNyDORcTU09TJPNWTPDnR5okDrvIU/wlzi5DZ8A0ebNhrKf6l0tNFBT9LSvQFHU5SBxqY/m8uEJKSrEC4IL5lugOOISDka2KSvYXVCXrumMHE5FnmOS/CgOZaZk6LUjPYA=,iv:ygygnSedcTo2Vsc56s2qrz1qkWchvSgvoiMTebRxQQ8=,tag:vf6z8rxsXmqzwpDy9Avifw==,type:str]
     pgp:
-        - created_at: "2023-12-29T15:25:27Z"
-          enc: |
+        - created_at: "2025-01-21T17:55:30Z"
+          enc: |-
             -----BEGIN PGP MESSAGE-----
 
-            hQEMA7x7stsXx45CAQf/RWxP6z7xjV5TqiA6lFhtygjrH9x3y1DUWG9aUb/dO+xH
-            zDbGMYqGe9RPlgi5sWPstdKXvCgs+AKNj93qJYMwEtaasJOinYXCGeAQmzg90+pt
-            bS6SoBHhGIxAvvLKKPtYx0V50I2reYR+32ux9bcrnzwIsV0P7/SSp1Cl8H+sotB8
-            yf+0ULXcpC+SYECmZqzR9qQ3S+3I6/+QS+QgWj4NsyF+apxnE9oQDcBLdYP4aKgR
-            JHERA9HYfDTKoS137pFHxgINqHkFRY6lhoZdz1yDzOjiPxd8YVfPdKyf022Rg+cX
-            J/Q2P+OhNZEG3gapNATp6wH3niovA89KwZKSmbTZOdJeAZ6NV6TiUP+TgGg5+CmV
-            pSLaGel2NZRnFVNdDFi0dsOwhHv3FpKhIpALJh08/jsmAAslfE7vVlcEnaoUJPTS
-            3v86AACUC5D/gUxmFrrED1qoxbELCmZ17xTwjQzxwg==
-            =KzdF
+            hQEMA7x7stsXx45CAQf9ELnm9TdXCIO6fTPiSCkKthx0tSHqBWX/s63158k4IUu7
+            v0WWgQy0SKFU3AwIFuVaAYEXB32SaOWKq2WbVAbFZU+xhyUmNe9asg9Fl24+zjGI
+            oYnPzv3lz/5vcI6Q9rZi8F2uIi2GQZnbscS1XfjA5u17uOalQpb0hjUXr0LMaUvU
+            Sggm1ZMKE1o1mHAWK6ZT9SrTMIroWFArJRZLS1eY/vI9ja7I5YR3z0MkLqIvdIp+
+            B4DsOXLlqAqtVoPGcK1CixQiXzzwyQAYHyJc3JFDpaF9Y4S5/bkMLGyQVMA259a+
+            W7ge+EngdJdXV8Unj4s7ndB1e1iM87Jc+4YOcA7jC9JeAR98n8GL+MN9vE8q2AsB
+            qSOXiGSwmAkhq7+ZwJHWlivlB1In0coyJ4eMd/yhyBuc2NrstO0t595HlA93GcLN
+            5JsXIFMqklqGSzE2KgEXhxa2aUoJxcpApVz2BLFPvg==
+            =X72N
             -----END PGP MESSAGE-----
-          fp: 535B61015823443941C744DD12264F6BBDFABA89
-        - created_at: "2023-12-29T15:25:27Z"
-          enc: |
+          fp: B9C7AE554602D82B1AC2CFD0BC7BB2DB17C78E42!
+        - created_at: "2025-01-21T17:55:30Z"
+          enc: |-
             -----BEGIN PGP MESSAGE-----
 
-            hQIMA/3lh+ZzfS28ARAAm729dMouF7juUeHAb+aHMoyZVKsXapxnxebkjE/LSIbz
-            IEZwegTNrtxQJLclV4Km2gUaBTcE4vLJCpB7YxZvk7JV9OdVKi97o9PcXUXbz9ej
-            /WomnEvFyyxTZGTiHU+L4kNudl8UAKhTt3P4fR3PLpTily75Kn53tzLFJuCO8fAY
-            I/YwQAzayxhPcxk3FuPsD/ONiG7mW8n2ZwfwgOkKXwnrlJv7DreKJRYzu/EeuvX/
-            d4oz+k+xofniOeZmQjZllzR7/++MBg/e1U9VocN1EAWpWHP5taLiThfnVSGDhlQM
-            +4WT5ezH6EuUQlAyQNpDaCincBvCHInhrNlUPOpW51nHMb0y3n4x2hMtZA0JbYEu
-            mkWTYDe65cHjImHXQk9oO2/v4oIyq7ywHX7g2hqVbbiLHZqqTaGfV8lP30+r6/UQ
-            29iAdWac1hY5HDzwbqpY6b38i60j4bkiS83xqrGYBy037bCFk1oHJqwxp5P7vrzr
-            rTv5NBr95BlwF+s8xPEPZneaEu7N3UnhhSzDWp1jgsCxN9b/XHarchNt70xEt2VS
-            xpgs9GEXhsJcbrFNPYqTkFb8vjLFI+poGPTfadW17j4Pp5ftIBRNdKvDG0ni/AIp
-            K98R/nvaHEFuX31SkL8ZUIRqhJm3JVqilFxLAJrqGuSN3jA6wKrimUYpK+t+64jS
-            WAEN9jHYFQDTVHix3g15S5YTGh5ROyqxouDhvSDFTmGtbm5W/HYgnkZmh53TgVeJ
-            Rph/O9QptculzTN+nEqshBhbjhl/uDsLsjLYo/O1AyCwTUSd3OKn6uU=
-            =zThh
+            hQIMA/3lh+ZzfS28AQ//TPVk5x8wZtKnNcbZjqmXUvi7FzaDMGYFNtiX+bQ17Lkm
+            qdo9TcH8gZI+xni6wlROQBVmu5MAVkT+NWnZIyxN7pokQPmb2v9zo7oyUPV70owU
+            dD/LDNVqgyFTVzWKco4wr8CUwQWhOJI9wM0sjTCOTTbCT5hYVnJOLe630sNG9G5b
+            cJYvaQFxKJeHKJq/DL1I9wT02gOE7vu2xh2OyEozEz3SlB7Bp2mGTLNSiOZBhbzh
+            DNwFRTeDc1Z/ACQJyoGEXkmj1VLyBFuCfXu4UvUQSmlfyCXKTD1/CUo2uiw1N44W
+            sYh5UpIrCU2eVAAXAiD1nB6dHxiau3QlapNQfbY2sOZVSnsB21yIja9C3aQN/0Q5
+            gRrKYcwULzLZ0Z3oQqQxQG9acU8L9CwjKJ1vOKgPVF7hcWkba2bLVsMMaK6seVNc
+            jazp9gDAj440S2aE86CdQvgcOEsfgPhBZrulYglbhW8ZaIN2SdjDN/xP1Tn5PadP
+            gS2DVgqILKPRMF4VavzV3uhEA77QF39Hr18SeToNWcDmfqNPNNf7HpnogstGPf3y
+            xrFAysLbD8IClU4LqI5M19akODON8qeQa5QD+jHOJmAYnMYNRmY/IwHb/SC5WyIm
+            EPNZg5E+q9cNrTKtEIuWec0SObqpaUz2E/Vt9+dge0uVgTA/QqPvMP7x19XBrRDS
+            WAFiKkv7MxImNgcqqe7D3StZoeNm+RXJiULaxxuR8qmMnmvaC+L7ggI4QR3TPQw2
+            mSoi7SkdjQUCa8ut15UwNHTGO+smbRs9aonGP4G7c1cOH90YYvR+BTs=
+            =q2IG
             -----END PGP MESSAGE-----
           fp: 2f5caa73e7ceea4fcc8d2881fde587e6737d2dbc
     unencrypted_suffix: _unencrypted
diff --git a/keys/users/tlater.asc b/keys/users/tlater.asc
index d9c50dd..d94a304 100644
--- a/keys/users/tlater.asc
+++ b/keys/users/tlater.asc
@@ -11,62 +11,230 @@ FMU/1LD0M+n+if7Ydw7RsMzgOnr4DEXYLtNtaOgebc/rZRu7Wkix+gvAYSTwV+ph
 eDSnFQZui1QXJ1gnzO6Hi4Xe4ChPwUrcIIAoJ07INWruF6nXo8h9dtpPOtMsIZ02
 Ena7OwfaCuKRf0hwNYERyZN+Lzc105BzUv0d9rsA6qlv4qlaG01Lz+2kdb1zhk7E
 8FYksFrdnSRwd1qYm4KKGJO/dKJat1sJI4ldK2rn2/O5Hrm9O9RaATT1QQARAQAB
-tDpUcmlzdGFuIERhbmnDq2wgTWFhdCAod29yaykgPHRyaXN0YW4ubWFhdEBjb2Rl
-dGhpbmsuY28udWs+iQJMBBMBCgA2FiEEU1thAVgjRDlBx0TdEiZPa736uokFAl4n
-HXICGwEECwkIBwQVCgkIBRYCAwEAAh4BAheAAAoJEBImT2u9+rqJy0oP/1rl/R4n
-oqJbVa4BCkUZI3wyVomibyodWed/nAFRT9BzapVWqrhYsZuOtv7Xy5/qzFHrxMOW
-9aaJ3Rz7lI72uy4o86AqwRdMmSsmgFDj+HEk98eUoZed3ijtAltR83xYzlpQuJ3+
-o+O+Vs+sUUAI57FZ/7RyEPzcxk/+9yU1aSGWGwjDP4tWR+Fe69kqCoCUskydU4IM
-Ss3LbNzEypVGG/GOa/rUlJ3n/XvG0HjjGm1g4tnelkE06zFDIbglhPKJNuLbeH1j
-RDUdj1iX81B5nFDr+ARr4zqS5PJFgyiQDxU7fDx55mTRuqQ8M/X8eYeK7PXn8w5U
-2DQgh1AEgfQrLbPdZ2lwf/aINHf5wRSGvxBKIAxXpsMt98RUfd+L//aPrl5Hwi6H
-ZKe0Pbkn/GwmKZq3iqd5uaN6vLqybl9cHHaQ58MPCb0guYAJD0higgrw1tgNMhX1
-RGAutfQCbgJhkzqgYQ2Ystd9ky+mf4L+d5Ct+ks9J/WkkjQ61A8WbtqR34iytE+P
-clR9Z+p1kgeF0mzN29ZYYrIxVFhxD7abBBZfzNLJPEmRiU7EstH0sqVtuD8G1Uec
-/u/v7NTECtUu1zq5BK09mV8ZkeqTkQKCx1iRyfD8JSFYYb3sGyYtCIaOvLnnQf93
-mhbzdlXAyHLshjzrHoF2TixCIpskMWx1zM/5tC1UcmlzdGFuIERhbmnDq2wgTWFh
-dCAodGxhdGVyKSA8dG1AdGxhdGVyLm5ldD6JAkwEEwEKADYWIQRTW2EBWCNEOUHH
-RN0SJk9rvfq6iQUCXica9AIbAQQLCQgHBBUKCQgFFgIDAQACHgECF4AACgkQEiZP
-a736uon/aA/6A0tn+otsfGfei9QxDgM255R1U76PdSVb2bEl4/IdSq4uw8CtM69b
-CesCoajj/qgXzEFhpijQ9pXZDpMDXk64EZtcO5T96RNXA8Oh5CkpnVXv2MOrFXVL
-Zc05EOh6qxMCRACliii7CyGExAbRU/TdhL86dWc06CAiMt0/vzYgHpy69jpomHsP
-OeWk8TghHsMHPHOpfk4sS8gYlvsKV7QDpW5sNPmbm/nCFr+PoR7R+BKnklhdX9HN
-d/Ha6KSXpEjzqIoI/X3TtYtTyhNdwZ0rbKPtQYqMi08dnr4INjED5kZvrVFr16s1
-nFp8CghrnnUq9t1hzFAnYTWX736/CU/0ZrANRVsaKdJ3tCey2OT+IdprYZlriFvO
-ZO9AD5BV/V/e+QFi7LUZEEmsK3AVFERmRxP+597ZyK4ozjc0s8aLI2q9O8GROGxR
-GHloGMH9Mv5T/gfBfyFtoMU3poYOHCfwvtt9sr5IuiaexsGKTSTqRUWhq9moiGb8
-mQxQnZwIoRuQkmcV1JlfuS2inSpnd/Ar7M+eFUjV/qjW4Pg6LUH5WQoZbTT/3TUS
-9qS1v10wLJNMIniYGZslh71yb937i6BsAKLzVP6VTsZgO4+8eoEpL46l1C/h/sTW
-gdWwG/cB8c3qgcYRTtn9t93TRofnxxr8pSVihe2TAzk6I1EKcf2DzymJAjMEEAEK
-AB0WIQTfYF3xdR5NoZx+auO0Z9GZCjri0AUCXiccgwAKCRC0Z9GZCjri0Mc3D/9X
-/OLjPBrwR2rnv7qGB8jhg304RskvYx/kzcSadp4JQhF8zD6Lzb+F/NRzaN09E9RD
-jsnF595UiOqQ9NUY1Ku0+1HicJHKg7chK11tQWQyjYZKyCc/WxoOye+G7LGjLLl0
-MpJ2uO/fgD5asF6ufXU0XDVPUGUBilM2NiEFuVRK51ZOmP7hrQYjMD+TSz3PfvT5
-xAyggGmDOswQGMYCRj2S/hIbTADkSVwG61OiPHWAKxIPaIK+MBJm04KM7bnZmTly
-4j7ZA9oj2MikMe2z5M99EYIIDauVy5N9R0qzaOcUCFZXDaoZpPfq1fwk5Aj9tG4S
-/FdlMZeYeJNHkk7ZNaZ0vdQf4P7lib6gv9V1XePB4WANoG1KRVSq8eVYQvlxlFhR
-EJjiuahoT59KhX1aC4tEmBo4yC0LwQ+G2Vw2DZMZHDo8IqP/wrAPGblyOlo09vr+
-Hqd7oyDSxiYFekttvLmS3wtD+Fz3X7xZ3NOooqemH1pKd4XYTTX2RNryEx+pIcMh
-Emkmyo9D8P/FgwB7qTj5ANOhEVY4zYWmYKDck8AlDe1VY/yQ8mo2cJWYKo1qdpI3
-mrdHBkDhNANwBfKBUu4zxrapBSrZvIYJd8YJjqvBX/EsqrQHb8Sf71HrZt8UILrQ
-WBhTC0/BETEay2BDgV8tP+9l3/lJyJZzRB8u6x4UtrkBDQReJx0UAQgAk+y5c4DR
-oWSiJvZMQ+w+Hz7hv4s8Q/xxvjVPmp921oYRk+qrMS963Qc9Zstn9RSI8ALZFksD
-gKDPZ+DAgF1FLkv9HqoggcE8iUU+WiYCVkxj4M67nmuOeUf/vIja4fxs/t0vJXkP
-U9/Hn2d5dyRyseZEYbxPdJvQGk6GJ1OO+h6hLos9GNrFB64SQug9j57YY2R5u+fU
-RwE/xg2YDb4xGH8sAyZkKRNFnfQ67cL1TdfcbKs9jrI2U6KFYbdWVbRgeWEQSlLS
-fIzQuUG73iHuo8FD2CKsag5smI9l4iV3W1UHEscc5soeDzLA2lH66sb/yl858bEJ
-KDci3k+wE3RQEwARAQABiQI7BBgBCgAmAhsMFiEEU1thAVgjRDlBx0TdEiZPa736
-uokFAmASBaMFCQPMHA8ACgkQEiZPa736uonUAw/4xh//cHEJ2UBgiei//8vBYR7E
-PB62NUmFXDphoAHB1xRMlFh3ljsU25hzXfTR1SyEvuYN9f7zmmW3ZmH0rV8xn0zb
-BCAORGmFm6auYV5x89Ika/ecoFAew8eeZbKuzT/ZWH9OEmGXoRP0eFAxDpOlEg85
-n+ErkRxnvc3VxUYt1swPhZ9Om/bZ26XzznJ11FztmYht6VXcB9jrpVwMjk5rAAAF
-LuK7Uiw9yQMaW8z7lcKQvAdiQ6j1TmGogIT3XAhVJkBNcMyb5qz+mylupMe69hs3
-L8I3PPMZJhT7ymll09KURChaGR8H3dohS2b/wLNdWoqMAyXqXWHDrZ83Uor/wzGh
-TQ6FHz0z8GMoiUgoU9GEQVu4vy2mjpR4vnHZ0pXP469rYdxQDkrfyuQSvbpYi9br
-ayllJQG8qoHXI92wugslD2CIeI14h8C14ZkOymI4uZCv0kR3mIxV9WVAanJyHVto
-HrYiHVt5TzJMqY0Eu3NPvr9W/B4x0srFOmM9MBivbTo4S3KDZEfRpqC5QCdw79qP
-spm35kqWIEpM+O4gc+zE4EHUbddu/68yXNaqvWRODg8mo8flFTZ5PvpIb/qNkPOG
-GDgPiiIae4ga6KNOS1STroHf63ort4G0zuQPzQg1N9ll4lo62OqDmW+25nzHC7yB
-PhCB2Dz76iQ5nDY4MQ==
-=R7Pm
+tC1UcmlzdGFuIERhbmnDq2wgTWFhdCAodGxhdGVyKSA8dG1AdGxhdGVyLm5ldD6J
+Ak8EEwEKADkCGwEECwkIBwQVCgkIBRYCAwEAAh4BAheAAhkBFiEEU1thAVgjRDlB
+x0TdEiZPa736uokFAmH0krIACgkQEiZPa736uomO9Q/8DauQv6uuYzuT0xIT4A7s
+xKZU8w3MoIv/z3DcJv9So81EYZBHvywKOkZyl8C0QX/Plkkpm8K72vTyD2FB3PtH
+jXdc+8l5a5uz3F22YOMGJHEgBNrCBii+BQ8sfDi6isbVbxGlpiYkm8BaEaXyC9Xv
+1AIu8s6VqzvED5oHB66yqGmr+4Nsij+37eYYkhxWO8UQzrYHHKkVqjchSrMtd/pe
+C3H9VXKXGaT8xLkkiPubPEH1DGQwfon5sfCOk0GOuFMKSdiKrW38MBJHPhNQqNtp
+kG35nKURQlWAXuxh7fCk3kcpSFFCs60XojA+R5+XlPSWpfHe45jbDzA6nyeQ7nfV
+kVxW6vYTGvZKT3QOHjaUePqaEqfmZz9KebsDF2W1+UzKMI7q7Q5ofH6Pp9gGd7cT
+Na2CGL4BHCH9qsQjWbDefuYxHOS1nVrgiSmt4FvXFMhmgLRwkRKJQuHmy6eGfI7D
+75648Jwy5ID/CiZV7vd1MdLZomV/lyb8VyChFYol3ErG4p04fZSdvZQMwemwji12
+j7vyj7GPKMf9dIx4+w25z58qE2En0fzmAeEfRA24o4XyQXy/tR24AmaR25i9/Cbj
+OtVioUaYEHQrwxTP/qXIMM3bwDjOuo3Lseil9x64dV5QooVp422W2KWlbnm/QWhW
+zmWDxZpubnUlYld5JPilPlGJAjMEEAEKAB0WIQTfYF3xdR5NoZx+auO0Z9GZCjri
+0AUCXiccgwAKCRC0Z9GZCjri0Mc3D/9X/OLjPBrwR2rnv7qGB8jhg304RskvYx/k
+zcSadp4JQhF8zD6Lzb+F/NRzaN09E9RDjsnF595UiOqQ9NUY1Ku0+1HicJHKg7ch
+K11tQWQyjYZKyCc/WxoOye+G7LGjLLl0MpJ2uO/fgD5asF6ufXU0XDVPUGUBilM2
+NiEFuVRK51ZOmP7hrQYjMD+TSz3PfvT5xAyggGmDOswQGMYCRj2S/hIbTADkSVwG
+61OiPHWAKxIPaIK+MBJm04KM7bnZmTly4j7ZA9oj2MikMe2z5M99EYIIDauVy5N9
+R0qzaOcUCFZXDaoZpPfq1fwk5Aj9tG4S/FdlMZeYeJNHkk7ZNaZ0vdQf4P7lib6g
+v9V1XePB4WANoG1KRVSq8eVYQvlxlFhREJjiuahoT59KhX1aC4tEmBo4yC0LwQ+G
+2Vw2DZMZHDo8IqP/wrAPGblyOlo09vr+Hqd7oyDSxiYFekttvLmS3wtD+Fz3X7xZ
+3NOooqemH1pKd4XYTTX2RNryEx+pIcMhEmkmyo9D8P/FgwB7qTj5ANOhEVY4zYWm
+YKDck8AlDe1VY/yQ8mo2cJWYKo1qdpI3mrdHBkDhNANwBfKBUu4zxrapBSrZvIYJ
+d8YJjqvBX/EsqrQHb8Sf71HrZt8UILrQWBhTC0/BETEay2BDgV8tP+9l3/lJyJZz
+RB8u6x4UtokCTAQTAQoANhYhBFNbYQFYI0Q5QcdE3RImT2u9+rqJBQJeJxr0AhsB
+BAsJCAcEFQoJCAUWAgMBAAIeAQIXgAAKCRASJk9rvfq6if9oD/oDS2f6i2x8Z96L
+1DEOAzbnlHVTvo91JVvZsSXj8h1Kri7DwK0zr1sJ6wKhqOP+qBfMQWGmKND2ldkO
+kwNeTrgRm1w7lP3pE1cDw6HkKSmdVe/Yw6sVdUtlzTkQ6HqrEwJEAKWKKLsLIYTE
+BtFT9N2Evzp1ZzToICIy3T+/NiAenLr2OmiYew855aTxOCEewwc8c6l+TixLyBiW
++wpXtAOlbmw0+Zub+cIWv4+hHtH4EqeSWF1f0c138dropJekSPOoigj9fdO1i1PK
+E13BnStso+1BioyLTx2evgg2MQPmRm+tUWvXqzWcWnwKCGuedSr23WHMUCdhNZfv
+fr8JT/RmsA1FWxop0ne0J7LY5P4h2mthmWuIW85k70APkFX9X975AWLstRkQSawr
+cBUURGZHE/7n3tnIrijONzSzxosjar07wZE4bFEYeWgYwf0y/lP+B8F/IW2gxTem
+hg4cJ/C+232yvki6Jp7GwYpNJOpFRaGr2aiIZvyZDFCdnAihG5CSZxXUmV+5LaKd
+Kmd38Cvsz54VSNX+qNbg+DotQflZChltNP/dNRL2pLW/XTAsk0wieJgZmyWHvXJv
+3fuLoGwAovNU/pVOxmA7j7x6gSkvjqXUL+H+xNaB1bAb9wHxzeqBxhFO2f233dNG
+h+fHGvylJWKF7ZMDOTojUQpx/YPPKbQ6VHJpc3RhbiBEYW5pw6tsIE1hYXQgKHdv
+cmspIDx0cmlzdGFuLm1hYXRAY29kZXRoaW5rLmNvLnVrPokCTAQTAQoANgIbAQQL
+CQgHBBUKCQgFFgIDAQACHgECF4AWIQRTW2EBWCNEOUHHRN0SJk9rvfq6iQUCYfSS
+sgAKCRASJk9rvfq6iTD2EACWRy0dijH+nF/Io3hZsr3TWhe+lmXCsAjc4wSBuqu6
+mPvYGLMKzY6iW/Z7RrVaLlM9BAhwcl11KHMkP7sNDNFzAomy11ofn/P2bQy1FTxI
+nSRj4NLDa9FybFPuyTG9buV58jYedXdWVaJuC0nLbi8wzkAEZCZEKRcQgIS1Bi0o
+qrGtx05RgBd/LDs4mUD9EB1kw7EoCOOQz1gL54pZvnN3Fw73guDnnBWtm0356+7h
+ZHjmXUBlbakdOZzVz73Dc5BTK6ma5aNrTBLccdxKXOKFCeyAVv+i5Hj26VEMdlVx
+Ja3xZznzbHNoU6K+/tcEJLkbCIaDEQaX6rmrJDuG8zWICf1zTVPRfa/oxuXASdUr
+4y2LAuz/m8zq2RKr3bv11AKifKIAP2vL2q6fZvZ4hrLJ3G6vHh/L1y5oy+l+eav9
+cER2bCweVeV6RhlBzwtej2ZB0J5MkF59OCK7OBfPJnmJCd33AuA74mlrzmi7x9um
+LQLPI9oZk9rQRj3FZ61Kv5jhJntDIDe2e1DK/vHnddtHeqbdH9Dx0NNl8/JWfSp8
+NccOBEzDe8nB+1sbvPyt7rUuZPhHzk3O45+k1pQrxZbIFGRPGZJkHdiOCWlG6m4A
+Pgul/U84sSnsberrQdyBBtMUoBV6jyVzUwI9/ZYHAZCguC4QG71zR31um2TB7kDt
+NYkCTAQTAQoANhYhBFNbYQFYI0Q5QcdE3RImT2u9+rqJBQJeJx1yAhsBBAsJCAcE
+FQoJCAUWAgMBAAIeAQIXgAAKCRASJk9rvfq6ictKD/9a5f0eJ6KiW1WuAQpFGSN8
+MlaJom8qHVnnf5wBUU/Qc2qVVqq4WLGbjrb+18uf6sxR68TDlvWmid0c+5SO9rsu
+KPOgKsEXTJkrJoBQ4/hxJPfHlKGXnd4o7QJbUfN8WM5aULid/qPjvlbPrFFACOex
+Wf+0chD83MZP/vclNWkhlhsIwz+LVkfhXuvZKgqAlLJMnVOCDErNy2zcxMqVRhvx
+jmv61JSd5/17xtB44xptYOLZ3pZBNOsxQyG4JYTyiTbi23h9Y0Q1HY9Yl/NQeZxQ
+6/gEa+M6kuTyRYMokA8VO3w8eeZk0bqkPDP1/HmHiuz15/MOVNg0IIdQBIH0Ky2z
+3WdpcH/2iDR3+cEUhr8QSiAMV6bDLffEVH3fi//2j65eR8Iuh2SntD25J/xsJima
+t4qnebmjery6sm5fXBx2kOfDDwm9ILmACQ9IYoIK8NbYDTIV9URgLrX0Am4CYZM6
+oGENmLLXfZMvpn+C/neQrfpLPSf1pJI0OtQPFm7akd+IsrRPj3JUfWfqdZIHhdJs
+zdvWWGKyMVRYcQ+2mwQWX8zSyTxJkYlOxLLR9LKlbbg/BtVHnP7v7+zUxArVLtc6
+uQStPZlfGZHqk5ECgsdYkcnw/CUhWGG97BsmLQiGjry550H/d5oW83ZVwMhy7IY8
+6x6Bdk4sQiKbJDFsdczP+YkCUgQwAQoAPBYhBFNbYQFYI0Q5QcdE3RImT2u9+rqJ
+BQJnj7iXHh0gTm8gbG9uZ2VyIHdvcmsgZm9yIENvZGV0aGluawAKCRASJk9rvfq6
+iVagD/oCuQ/RE4kpZLKo6kF4yBKMHX3jz4HpKYpnG/aBncr031zI8qpdgiVpnC4s
+pzbxah7/yBozsaCCTQo0s84Y3u2uD+XzKRujWoK23/+U0fgs06B98vzNEWeWTR67
+cdyL5VsFTSc2QiM18tgjMEAAcv6ts7YFKZXZYxsGrQ1Pn7ZD9xfJ2GXuPY0bAmX8
+ccDf6EQ/du6sICv5/C2kupOmbY93sMDCzQ10sz3O0P/xj9gFAg8m3AWU8IzmZQNx
+a/TPYCadglCxjDZcuIYDuG0DWWGdviEp4GARX+hrhBHDbqEUVhFwvZNfGSbCoICx
++sRZ3KHFjF9PV7b+2dOdYWa3ECSsm4R4e//AKruhH83yEOXuosbiZ+pc1LSxgfRy
+D2dKfOWC6yv9GO8CqpUmnoYZTSmuTZAp2Va8qh/B3M2Qv7GWRfvG5DgKXZBnv8Z0
+2XxclgTtWqixfE0Sr1RCAGk9c+/xjMwlkak9M+KJZgua7WDYvM3mGHm3XRgIc6T/
+6XgNTgerhdqozsDXSHdPApPfuQpNXNYY3frOiGsCfi/XlHsjIX0gd/1bgM9h8D8f
+rK8ebIQmId58S/q7hRqxnLW1+cccFOTDoUXJA2tq24t7A6hkdEwNgW0Kj4Mg2AsF
+GH3jVCAH1Y89i9NLknLsjhy56kef4m/770EjyO+pt63DujNWeLkBDQReJxz1AQgA
+1y1WKRdzA/SXJsU5qeZ7yAYVNGUYq44UVeJHDa6cEi302xxmI8ytSp9VBo6QhgGo
+J1vef8LYoB4Qv6AC9RnDtrS6SgomWcULh0RtS9hi4PX+MYY2kO4XRUKoliG/DIgA
+HuiRbeGTN3MHxAZYHGkT9gs6z71mDywCpXkv+pngjtdquXx4NdsEucBEC3l8eE+k
+AEJ1V5bp66+LH4UiW2FAi5UShn4QmKxvsxXzl0wJN89D1fXaBxOw5ZJuNV5i62KW
+QmV2N4P7FFZlxolHwu/Fn4Nd6x9l3G3TpWAq/wlyyFrL0KFt7/vGCiKG5N0u/RE/
+ZzWZcUji7iYXZuGIbpQhhQARAQABiQNyBBgBCgAmAhsCFiEEU1thAVgjRDlBx0Td
+EiZPa736uokFAmW8ZUIFCQl2e80BQMB0IAQZAQoAHRYhBKUpZWuzqrBd1I8zFkln
+D9d05DJoBQJeJxz1AAoJEElnD9d05DJo3lcIALppAubOBA0+Oxda2FZTyGr20+pK
+WSQ3HBhPOtWoO1D6OhDMaWTnF07gXC8EKG8pgwUFMDp8YlbBJJ6bAQ3NXlfxyPO4
+FS3BwaSB6p2pbm1bJCnOOjoF6H/IVOIqKPIhwQ5XR3BqVX1BmKsTCoYkwzLEs/uv
+3pT/rZ3lGDdBiwE6a3GMF7c5zNzRBLQSkHFIZLfCuyDfmKScPzBzAdf/ZCkDYMYw
++nbYsAn2yuW8z7FFdWiopYst4l2qlY11bntwH8+PWXvl+xiqA85Qa+OLGQ+usaX3
+TVEvcv6q8dHwEdOPuqbDEZV7JXjmmARSjfDWwXHzqgvejkzplG4RTBl/nKkJEBIm
+T2u9+rqJL+oP/2Uz2OuaLU5qsrj2o6Bv4nDGuEdGi2KR0NBqDWgISN+3pf+Fig/t
+M+CrSLE4ImydDeTYPav5iI48B3xvFVT/IE7YQN5pqVy4p6LQaxKZgaITJInAkl8r
+9wcCtY7+23n1AyoyqNvKJkik2ChANBu5oOSVxa6XGBTGxSEqdxoXm9pMmLOR7j9E
+ByMGYQqMrEnBvHeRk8UGHYGnRAZbAvNGGt8LaQygFhzqOBHXf6iTpjX+7cBIOKAB
+64onlpaGfUWsaNnlpdZDaSV4iDvpQu0wHlGozOLuuEi5nZ9ArIidtKt8PKWFaJSd
+BfexAKi1JYZv6RhURbBld6CS6/TdDyXF0MnxJrxRlVUt8a8mGJZ8i1qW69aQ8HEL
+u/rAGSxIj1LFkMio7fvtJe7v4rebsp0cvKsJde8aWqA6gNLns1enIpXLlaMtZ3rF
+YpeB5Wn3HqsXYC/k4jz+W0M99H+qVOn7rlvc44m/YQAZZAFX/iQ7fiXM+5t6gGje
+9wF4S2tZSzJFy62FUjEHtiULjZzqRUEWahnOvvGiMp7ZD/r6s191Ryg2BmUNn7LZ
+Wxx4k6ErZ+YroWjgUESacUmG+I4Oc0Va0rHE477qRHklyj94r2s6PtcEEtJjXv+k
+M59FIa6GVz1V5pf9rU8GQLCcGTTg/V9YpjSCRwPO4gzVEZdcVkDMKnu/iQNyBBgB
+CgAmAhsCFiEEU1thAVgjRDlBx0TdEiZPa736uokFAmeP2vYFCQtJ8YEBQMB0IAQZ
+AQoAHRYhBKUpZWuzqrBd1I8zFklnD9d05DJoBQJeJxz1AAoJEElnD9d05DJo3lcI
+ALppAubOBA0+Oxda2FZTyGr20+pKWSQ3HBhPOtWoO1D6OhDMaWTnF07gXC8EKG8p
+gwUFMDp8YlbBJJ6bAQ3NXlfxyPO4FS3BwaSB6p2pbm1bJCnOOjoF6H/IVOIqKPIh
+wQ5XR3BqVX1BmKsTCoYkwzLEs/uv3pT/rZ3lGDdBiwE6a3GMF7c5zNzRBLQSkHFI
+ZLfCuyDfmKScPzBzAdf/ZCkDYMYw+nbYsAn2yuW8z7FFdWiopYst4l2qlY11bntw
+H8+PWXvl+xiqA85Qa+OLGQ+usaX3TVEvcv6q8dHwEdOPuqbDEZV7JXjmmARSjfDW
+wXHzqgvejkzplG4RTBl/nKkJEBImT2u9+rqJZDQP/AlSEw5vH4/KJeemEcT/EbNs
+DjuxY6DIqcq8SlvgFsUypuamL3XBKKl478JiiYsvDnC1RDEGVMx5ZWohb/j6bmSN
+XbPGSnUxYwHl2QabCo/U3sZX9Tx8tmK8vFMLiZDsbqLaENbDjW+nlqRkuBUVVcUm
+zqgOIiZSN6lRPeFwodN2SGfz9jx3hkfxqlAJQpgX8F1NMv04uhzjD6gY757PHbG4
+oKizUDx/cW9g5IiBXjfsUs7Y7NtuhZgm3php25Kqgn1BsTqW5yb4hn9Xkib9hsId
+qXA6zQqvH32snTGdZsnCtcKVg7nSTf2ygL322y3zywS4EwOj66wloAbjEi01Q1rG
++qcV6Q9L32vcqd0YEh8iFN+sIMqii9B+K+773u7oFFVeCAHytoycpBJxEwsXNYqy
+gCK1LrIjBQZpWnkgGgIRmWdc1Tkw8UVcjxit16sCDVnOqWAsgPottOrCZ8mh0sjs
+gacoVN2vvP4LrYWCdaSrINKWKZAZGviwZ4JN3ihNGbjBx9QW58IhxWgxcQbkXtkr
+n8LvvqEgwjXwTBPaH0oRYQ+W04MLiBlRUm91O1Il9OBOQbjIImIqVrQhRXCK5rwj
+1K4punq4vy5gU8nySTp89flOkaupEf5HxCJYL0gHR834rNNOElEBz1FkfYGuUgHR
+15VVhgWwk5g6gBSxHRgquQENBF4nHRQBCACT7LlzgNGhZKIm9kxD7D4fPuG/izxD
+/HG+NU+an3bWhhGT6qsxL3rdBz1my2f1FIjwAtkWSwOAoM9n4MCAXUUuS/0eqiCB
+wTyJRT5aJgJWTGPgzruea455R/+8iNrh/Gz+3S8leQ9T38efZ3l3JHKx5kRhvE90
+m9AaToYnU476HqEuiz0Y2sUHrhJC6D2PnthjZHm759RHAT/GDZgNvjEYfywDJmQp
+E0Wd9DrtwvVN19xsqz2OsjZTooVht1ZVtGB5YRBKUtJ8jNC5QbveIe6jwUPYIqxq
+DmyYj2XiJXdbVQcSxxzmyh4PMsDaUfrqxv/KXznxsQkoNyLeT7ATdFATABEBAAGJ
+AjwEGAEKACYCGwwWIQRTW2EBWCNEOUHHRN0SJk9rvfq6iQUCZbxlUwUJCXZ7rgAK
+CRASJk9rvfq6iSKOD/45CB3J1W86NTmkHvdW2EMFyrJFNsp8sNdLdw18OVq62qZs
+HSAQaf+YIZkmf0fqUWVcE4FLZ24Vm15oU0Q3Dv793x+LfRPHTgYZDVcdfwFCW/fj
+FJfIdq0fSUUTOBMEiChAqiTp6Go7rrPOo7Y565b+QPOuSd6HueTlrZuUfTjuRrnu
+ImkMnbNWg5isSnTtzIqzMSIgdEtvbsry5O+OhGN9mLcBl9eeF3JdhYt/oYUAcr5M
+DwXuRd0VJrsKGEjtBoVS2+n8wk9aH7CidPDLpwR8a+q0PxQFXCxyKBpLKiQ3/IX8
+roaZNlZubmH3Q4doKZI0GnIupmSaRk9Byh1BYJegkA3ELkN3cpezVUvazs0v/Aes
+VBw5nWXvWJkY5U2aQC4PjfhM+4H5/8o0KB3Xdlmb125iwj9mVBGw1VWkQydEcZzG
+LIYP+ZHhCLE/wiqdCnFUy/IBT1ca0+j+d3KfWyx5G75PYwgB3Lzrkw5wa8pGPnMb
+MgP6GDNEOve2taQVGSe14+XW/8NSw7HfGIK+V/6E+jjdPZHDUQM6VzUO6TEaqcTe
+VyhAyiFUYV0oHr5b2w/7Y6XhZkjHmpyy8/5rL8fJ02iYOJ27BtM8l9Eupb7H8pH1
+yWTSrqIjDahFFrDQRVdCoZ2paOy1J7EMKcr3TB/8ZJhVpcf6Eq5zaQPk3qNh8okC
+PAQYAQoAJgIbDBYhBFNbYQFYI0Q5QcdE3RImT2u9+rqJBQJnj9r2BQkLSfFiAAoJ
+EBImT2u9+rqJDTgP+gPbgIPKEdiSonHgosE+vA0pvELjvrEOfWbBV4roXV/SpO5T
+NMx8npEHTEoi8Ef7ERrLklCHTtLkDAdKn3LCEA0OV2akTPB5Y2aiGrSfdJngvLpt
+bgdlPVCNwh0i0GjSfzgeQUlqjDDb4fO2asnX/2yX8pMZ/muunS8PNnc7tPqtBC+b
+MNLe8dxtmWi+TIRJq/fqZy4mnz/yh79sdLpN8ey9HFvkksSYd2xtY5uNPAUcE6sP
+B5jWGsR5jJKI17RCDjUculFm9gcw+ZoM3HO+Ikh6A7QUFbN1yGBtMcCHf+3YbKw6
+G1U2kR8WP1ZprcYXOkPugo7vbKlEA/TlAFTrPL0l6crV3ALhhT/6Ke6RdgBBMsyP
+hY5hV+VO8vA2FWXxF4xoAISuKtNXuMVdtUeAi6U+2C8dGoCGgZ0WLzApTSoNoasj
+j7ZNk3HN5m1cqiO6JKAMl9OB9E3C4YqfLuDDuWmSEjzicjAvvB36i9gA8Vsd4x96
+oSVsx+2TWfulxO2rrGvq3247DxxNNLVT2UuDYIEEb1MZXjWWRLzs1h4z8pN5e6ZB
+yQEqW3h9ortT6XtXsO8H7c0r+GtD+CPIfujKXH1XT0AgeeHJSEfPYtEGxVVt5N3i
+o46MIolcnit6ncHHjfOg23XPou2dgE7zIEMLrhnVowSIoBh7ChmnLcZBPVKTuQEN
+BF4nHSgBCAC1QMrJrjjWOjQf9wF5JC52EHtDh03grRHdS0PHlnc9kLDXYw8n41KE
+N2vE2skVTKBVufQhuckCAlXd6BpisW1YoyhaLs9Bcp6Un63VH3YvRvXzKtwXJHEv
+/5SnDrGqxo5UF6xTVTxC9ux0dnSSizAeQiremr9Zuzz4B25NJCiZ2lVZUOi8iG1m
+4082owuwZWIW6qrFWi3gUGtjz32EM3eUX75BE1ZcDap7BJj2GdYsMHO2iiHBZwQV
+OXd7Fvk/23f9IeQ95D2RMgeQun8OIF+7X5zaWzyzq1Tky4pijaSsUebnFk9Cxm6K
+Rg+yXgmIjpskskCY6kj82+wqFjPRIgxfABEBAAGJAjwEGAEKACYCGyAWIQRTW2EB
+WCNEOUHHRN0SJk9rvfq6iQUCZbxlUwUJCXZ7mgAKCRASJk9rvfq6iXZRD/0YRCw/
+kkoSSrjZHULWRM528PdX2oy1o5CICnbkWJMW/TTtr/qr18e7TwkkeEViLq+Y0F2T
+a3lpeEYAOBXc+i+2fSduJSijbHwkNYyS8kg/FEL0EDrzKGm04l+FMEpZpx9Uvye3
+Kfl5GQ8dKPMddXUyD0UtelbCjb1Ie1eglc0IgdPjYjzR9UDYgHDHqfwOFCReoOmF
+ZSBTPXKz4SdARI5B1Ilqqs8HgjMAX9VQkSS8tgJBJAUNA26WLtdAawLUccl8AFBY
+f8/k/E4wkyWaMt9DT465UL0ATaTYAB9J6JzmBAyiaiW4s9dkiMQoR/kFl9Kixs12
+VfgUID4bX9n4UPDNQZ/ocXACWRU0dIw9qHm7VHWmF/Aq4+68gVppwT8UhlBZRBTC
+HqtQh+7ft6+0FD0RpmrY3nOsyrEX1rTYBx4m3x7MY184y9Gxmg3f7rUEoH9zpe6B
+f7KhBT+jd6vpb3J5tNKO1ljRA/1axc5G1vr8TKwV6WAXw0Yhx/DBP2TrgxjYpymJ
+QpWrW1AN3YM+hDEenNblaamJsz2xOR1sHdegz7STsKEkxUbS963KoRAyRP80YUmr
+Jghi0E6uyHXWA0fJpBe4107kRK4LaEBmmGNgvX2MdNN+V7+uMM7uZKfCaLUhoR7J
+R9b2fP08YuRFKDhs7YwnF2QhYBQVG10B51X5OIkCPAQYAQoAJgIbIBYhBFNbYQFY
+I0Q5QcdE3RImT2u9+rqJBQJnj9r2BQkLSfFOAAoJEBImT2u9+rqJN6sQAIMCBOht
+7Vfcag9NAU4vi6avpPblvWmIh5JmGV2x808sJp/s6qOACGKDwB1RxmtnDUmuAcdx
+MuzVJaw11kf8u/nfn4yA3/ZbE4fJx7mfdkHgfrGDWEJc5xF5cDKV+XeBPUsJvdOO
+rl+xuBQZ9+wC5IwO6DrtxoEGEvWHfwzOGzf9czCqMTm/OPYHQG1/CuNfMznwv1d2
++riyj29PuMg3dktfTl4YZNGbPADo3imWvlCObyOfpnLvLJ77yin5YFQEzD3YPo9M
+SOOcQN1V9ZWdfVURLg0Lw0r4ybci2UyNLolsJ6mh8d7SjrSOmrYwaOYM6R0Pp6/C
+emxytol5QiiGFt7XJA11s96I444nBJKIXK8+em5lpLRELlLeiI78SfsVJC2Q2hUU
+9/9fodiDOdYNhdBKEBdWqeemgBcpX6/hX4HfAx6BrdYFLxIpdRyjXvCGfDg8cbR/
++dx1NaMj1zmVsOyPUxN/fXF7zR28qc93Rl1TCl0yMMtPeJbv7cAmlMBC9qjvoNfD
+JOGKCI5Wj8A3dpNp61gUa5RFxwqX8yiWgT+Zf9IdeQekHowk3lBdUDJSN6ABOHxo
++q7K6dkVhztlT4SUnO7dlFoYF8B9xhDm3HdJCl3wh5Rt/GKjsxVzHObOVbho8wvq
+7g+tSemUj0oNo/J5K2gr6IzEF5BfBukrCdVnuQINBF5Ss1kBEACuMP/sadvOLaHs
+KyQGwI8WNpsC8u58pqkv3LTvgOQs1t5mSqJ+vTGpp8B82V1iX0Wbu6WNAhOZXu53
+zcGRJQ/9Lq/6Uzh6epE9Pt9pA+5KNVtMiFRgGEZeN065a8X+aZmBGWb1+ZLyjLcR
+WxE7RFWNi5FdYkWW2rDNZLU2gBr61eQreZDV6DyfPJrIvp8u0H+V/Pv3jAweajTQ
+Pn/MzuAxMGK9fmizsBjMpSxBrm/g4Lp3Rt8RzdJoaf/8Yi4yI5pC4qnRszzT7PiW
+ChzeEOgEdveBiVLEpDaJ5m2DrhvRZqPfrJTiJaszXgr9HLGTshHA86X3zzi+5Wg9
+Cn3COvIL08bBcyVLsMLq6z0TQ6vjmotDyVe3VpDmI23+8X4UHgY+EEfbs63vy2j0
+7cdA+dpXr+6UC+Ic/ArAnJVlSPNVRDyTuxUR4d8EAC0saxnDWnrh2udIpdKirj/j
+kTZy4ftvKp/YvERO83Dk18Hv5gHaNWM3f3LEx77UwHs5rrVgpNrQqrcWdZMphduD
+Sf3xi43vaSMe09UP6bzNMvg+eu2mSxwZVpx+pVEWjhDe3jsMEdnV1vO2JgZX2Fjw
+DWHqqIaJAHqSeEP51FfVFnj95gowbQCkPKj3xioE81IDtkQ4lgGR4sSK46/pJQy7
+PjYiI3/Nr8S21mwoZ5sc9gVe5p+yRwARAQABiQI2BCgBCgAgFiEEU1thAVgjRDlB
+x0TdEiZPa736uokFAmeP2o8CHQMACgkQEiZPa736uonUSQ/9GVuZIooAMAZ7+gV9
+N05QU/HGpWGTaj4jSx+LiTU00cUx5zdtgG5AWQIPYmcVye8r/OnhPd4BRm6yK9f4
+S6CHGQjjgIB7cDMk5MqiMSBbdJgVh6oEC/42LcBbByubq+wdz6VnlXd30PzXBwjW
+aXJa1lc4X0GggrgBGXbWJMpwdea+xnYdgdyC7L66UQ3DwijGy0WB5ntMosRdq6ct
+gkdlELdyq2F/4DRbGfnWWmfgCFPs1h861XrdQY0HNj1L4y5H4YeY8Ivsraqv00JR
+Llwbakkh4nNdKbp6Cf8XtoDsLhHcKgpUN8wqoocWsFZ4acj3ggQD/7HV+xjlF5ov
++i/eCMBelitQuiROL3UYTZZ7X81LJrR6CNU+0c9v8w+chLhvWpYVM8XMziveHfw4
+4E6Gh/90PGQCfT+e5sjTSW1fEBTZ2ZC8YpplfS7/aKWi33Jn+f5mDZz8ZurJswmG
+CDgWSjyZDSB3ylgSo/u8sLtUPmBnIfkURANA/w15xVXbQn9wNuop1DwnCA8Q4dfy
+9wm0jR/5b/ddtXQXeuTOr8Se6XQODP2Yjty+bFSR4zpRkeri7jZ+AQYphcZHxALZ
+9xoBhPCCZp9g3jItCbcYbIbDTgjbFqT3JK0tg0Ea11s7W37DvJ3I3LujqmHnXvG9
+T6Zht1J3KxuUnvda2oUKfhuE/FeJBHIEGAEKACYCGw4WIQRTW2EBWCNEOUHHRN0S
+Jk9rvfq6iQUCZbxlUwUJCUrlaQJAwXQgBBkBCgAdFiEEmIAjjep/99rtvvjkNa7S
+nzgA4CkFAl5Ss1kACgkQNa7SnzgA4Cn3bRAAlzLmitlK8+fzwzo/Rkh/LnN9lXk/
+T/lOu8VgqGQM4FZ8Qe3QioUgR2g4ZH/jCoGTMfXK8EZ6q3cm6qF7GlK+T3aSOl4H
+QAodKps8m3vvlSQiq8KXowOAR5NtY5AS3yP7Q911fGFij0tOVW4QGbvqiXTeItvw
+qNcWNzvUbOu2QDQOAIP2ds5DvxRI8f4W4a+Eccd4B4w5n08Pw46uNu8yw/oFD5X6
+p1N5SBeDFQSy+PFqWWNzTjYJOUUswZRD6dk6dyybG4/f0VMUNapfQWOVMNMtBjYp
+Gwt84baLFTv2qpJgQO55cNYpDLwCUcvSDH11rOyL5wvkmuzx/tIuSX+Okt6QocIk
+pIDByShcPrZPoscVogTBEXPllQAcmWT8m303v9tUioNqz4YrjmbCr3gMtvobwVei
+z9WGmN8QKAW4JoSexXl6XMZHJqMM9MAlErxSxSxPHxoZNfunjShOgXJfCWXbajui
+KfQ2bGmNRw152nOA3Z8tNGtJEn5BmY5/M0WVYzFQD1w64Bh/XpIemGekEZYDgXJj
+gMcR7u6m1ds7tJV/XcoESeRmtksg3oM95wC/3lVusZ1fdHqUTMtzYCnGYhRbBak0
+qwiobZqJAN8g1gxXZYA902uCN9TOrz62Mh0u507MUPh1dZfayVR90tNa2PLN5s3Q
++pYwJKd727SQgUkJEBImT2u9+rqJK4YQAIG8rSAi1DKC7wq9BMV/lcBLCzDuAmtV
+xzTGIYKhLGf9jQQg6kztwr1dPyro/fMhBpr23WtghlReMxOKHFf+g1FdMg9Rr1gu
+mnfZxmVKkYaQEg31e+k8Nr/d6DcBym3NuR6rt4wHL6mxbfyJ0XsgknE+LhQaDgUc
++K2JKMm0udppKGDwm9vtqIbmMIQqh+EPG4MaqmXq1uncloEKYQ3Rs9IVz+vtifEC
+ydNX90gcIvGk9Nf4YzlBhPTj3mah+thdXfwmnELX++u63h8SqnEnFPJKHennqFTr
+GXUZ7D2mZj4VzzOzLaS9fQTtlSpKB6emh23fHndiDyr0ucKu2+3oVL3v8cqB9VeQ
++eKI6RdYMoygMezI4qu9fd6TkP1XicfDiXEMbmvBZ3ZQADC1Gb2kiRde/qZNewZu
+UGGBjXtmbzeGtENjaVy55/Vb29hhMkeXAW22aZnp01gPRoqR5hxhVLreqcKqVnlb
+W5FMvwFK/SYAAeFauQmGv++K3YFpin1rEKd6KQP4KmNVUDa4v09ImNrMCtwFMhSg
+wExue4DEExWrVRhZ8IczBAnXn1a1aZn3BlOaUeKyrcLQeLrGXhyQ3YV+LK8J5N9D
+Q65x2UVpB7BnxLsOe9+eIA2vyLFMw7hq3biljKmQXNMKIBseL+pGX/yE8Dzx36yI
+GmeDneCrlseO
+=ncr2
 -----END PGP PUBLIC KEY BLOCK-----

From 37c4613ab33678fd7c53e41f0c4bf667d2cbe1a7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Thu, 30 Jan 2025 04:01:09 +0800
Subject: [PATCH 30/67] fix: Add gateway for internet access in test envs

---
 configuration/hardware-specific/vm.nix | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/configuration/hardware-specific/vm.nix b/configuration/hardware-specific/vm.nix
index 1783956..225a846 100644
--- a/configuration/hardware-specific/vm.nix
+++ b/configuration/hardware-specific/vm.nix
@@ -15,6 +15,9 @@
 
   systemd.network.networks."10-eth0" = {
     matchConfig.Name = "eth0";
+    gateway = [
+      "192.168.9.1"
+    ];
     networkConfig = {
       Address = "192.168.9.2/24";
     };

From cf751d01992fec0e19957658f1866d98ed1ae720 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 31 Jan 2025 22:31:10 +0800
Subject: [PATCH 31/67] feat: Don't run battery manager in test VM

---
 configuration/hardware-specific/vm.nix | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/configuration/hardware-specific/vm.nix b/configuration/hardware-specific/vm.nix
index 225a846..db563fe 100644
--- a/configuration/hardware-specific/vm.nix
+++ b/configuration/hardware-specific/vm.nix
@@ -23,6 +23,9 @@
     };
   };
 
+  # Don't run this
+  services.batteryManager.enable = lib.mkForce false;
+
   # Both so we have a predictable key for the staging env, as well as
   # to have a static key for decrypting the sops secrets for the
   # staging env.

From 22981fdcdd70c30436fd34133af3f6e8c8e7ae29 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 24 Jan 2025 00:34:25 +0800
Subject: [PATCH 32/67] feat: Remove fail2ban

---
 configuration/default.nix                    |  1 -
 configuration/services/fail2ban.nix          | 43 -----------
 configuration/services/gitea.nix             | 18 -----
 configuration/services/metrics/exporters.nix | 28 -------
 configuration/services/metrics/options.nix   |  1 +
 configuration/services/nextcloud.nix         | 23 ------
 flake.lock                                   | 78 +-------------------
 flake.nix                                    | 17 -----
 pkgs/_sources_pkgs/generated.json            | 22 ------
 pkgs/_sources_pkgs/generated.nix             | 17 -----
 pkgs/default.nix                             |  3 -
 pkgs/nvfetcher.toml                          |  3 -
 pkgs/prometheus/fail2ban-exporter.nix        |  5 --
 13 files changed, 4 insertions(+), 255 deletions(-)
 delete mode 100644 configuration/services/fail2ban.nix
 delete mode 100644 pkgs/_sources_pkgs/generated.json
 delete mode 100644 pkgs/_sources_pkgs/generated.nix
 delete mode 100644 pkgs/nvfetcher.toml
 delete mode 100644 pkgs/prometheus/fail2ban-exporter.nix

diff --git a/configuration/default.nix b/configuration/default.nix
index 18d124e..a22f8fc 100644
--- a/configuration/default.nix
+++ b/configuration/default.nix
@@ -18,7 +18,6 @@
     ./services/backups.nix
     ./services/battery-manager.nix
     ./services/conduit.nix
-    ./services/fail2ban.nix
     ./services/foundryvtt.nix
     ./services/gitea.nix
     ./services/metrics
diff --git a/configuration/services/fail2ban.nix b/configuration/services/fail2ban.nix
deleted file mode 100644
index f09668c..0000000
--- a/configuration/services/fail2ban.nix
+++ /dev/null
@@ -1,43 +0,0 @@
-{ pkgs, ... }:
-{
-  services.fail2ban = {
-    enable = true;
-    extraPackages = [ pkgs.ipset ];
-    banaction = "iptables-ipset-proto6-allports";
-    bantime-increment.enable = true;
-
-    jails = {
-      nginx-botsearch = ''
-        enabled = true
-        logpath = /var/log/nginx/access.log
-      '';
-    };
-
-    ignoreIP = [
-      "127.0.0.0/8"
-      "10.0.0.0/8"
-      "172.16.0.0/12"
-      "192.168.0.0/16"
-    ];
-  };
-
-  # Allow metrics services to connect to the socket as well
-  users.groups.fail2ban = { };
-  systemd.services.fail2ban.serviceConfig = {
-    ExecStartPost =
-      "+"
-      + (pkgs.writeShellScript "fail2ban-post-start" ''
-        while ! [ -S /var/run/fail2ban/fail2ban.sock ]; do
-            sleep 1
-        done
-
-        while ! ${pkgs.netcat}/bin/nc -zU /var/run/fail2ban/fail2ban.sock; do
-            sleep 1
-        done
-
-        ${pkgs.coreutils}/bin/chown root:fail2ban /var/run/fail2ban /var/run/fail2ban/fail2ban.sock
-        ${pkgs.coreutils}/bin/chmod 660 /var/run/fail2ban/fail2ban.sock
-        ${pkgs.coreutils}/bin/chmod 710 /var/run/fail2ban
-      '');
-  };
-}
diff --git a/configuration/services/gitea.nix b/configuration/services/gitea.nix
index c88dd01..da01cde 100644
--- a/configuration/services/gitea.nix
+++ b/configuration/services/gitea.nix
@@ -59,24 +59,6 @@ in
       };
     };
 
-  # Block repeated failed login attempts
-  #
-  # TODO(tlater): Update this - we switched to forgejo, who knows what
-  # the new matches are.
-  # environment.etc = {
-  #   "fail2ban/filter.d/gitea.conf".text = ''
-  #     [Definition]
-  #     failregex = .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>
-  #     journalmatch = _SYSTEMD_UNIT=forgejo.service + _COMM=forgejo + SYSLOG_IDENTIFIER=forgejo
-  #   '';
-  # };
-
-  # services.fail2ban.jails = {
-  #   gitea = ''
-  #     enabled = true
-  #   '';
-  # };
-
   services.backups.forgejo = {
     user = "forgejo";
     paths = [
diff --git a/configuration/services/metrics/exporters.nix b/configuration/services/metrics/exporters.nix
index e16b945..ecd69bd 100644
--- a/configuration/services/metrics/exporters.nix
+++ b/configuration/services/metrics/exporters.nix
@@ -68,34 +68,6 @@ in
       };
     };
 
-    extraExporters = {
-      fail2ban =
-        let
-          cfg = config.services.prometheus.extraExporters.fail2ban;
-        in
-        {
-          port = 9191;
-          serviceOpts = {
-            after = [ "fail2ban.service" ];
-            requires = [ "fail2ban.service" ];
-            serviceConfig = {
-              Group = "fail2ban";
-              RestrictAddressFamilies = [
-                "AF_UNIX"
-                "AF_INET"
-                "AF_INET6"
-              ];
-              ExecStart = lib.concatStringsSep " " [
-                "${pkgs.local.prometheus-fail2ban-exporter}/bin/fail2ban-prometheus-exporter"
-                "--collector.f2b.socket=/var/run/fail2ban/fail2ban.sock"
-                "--web.listen-address='${cfg.listenAddress}:${toString cfg.port}'"
-                "--collector.f2b.exit-on-socket-connection-error=true"
-              ];
-            };
-          };
-        };
-    };
-
     # TODO(tlater):
     #   - wireguard (?)
     #   - postgres (?)
diff --git a/configuration/services/metrics/options.nix b/configuration/services/metrics/options.nix
index 69cbd6b..8868c6c 100644
--- a/configuration/services/metrics/options.nix
+++ b/configuration/services/metrics/options.nix
@@ -12,6 +12,7 @@ in
   options = {
     services.prometheus = {
       extraExporters = mkOption {
+        default = { };
         type = types.attrsOf (
           types.submodule {
             options = {
diff --git a/configuration/services/nextcloud.nix b/configuration/services/nextcloud.nix
index e54df14..b5cb691 100644
--- a/configuration/services/nextcloud.nix
+++ b/configuration/services/nextcloud.nix
@@ -70,29 +70,6 @@ in
     # The upstream module already adds HSTS
   };
 
-  # Block repeated failed login attempts
-  environment.etc = {
-    "fail2ban/filter.d/nextcloud.conf".text = ''
-      [Definition]
-      _groupsre = (?:(?:,?\s*"\w+":(?:"[^"]+"|\w+))*)
-      failregex = \{%(_groupsre)s,?\s*"remoteAddr":"<HOST>"%(_groupsre)s,?\s*"message":"Login failed:
-                  \{%(_groupsre)s,?\s*"remoteAddr":"<HOST>"%(_groupsre)s,?\s*"message":"Trusted domain error.
-      datepattern = ,?\s*"time"\s*:\s*"%%Y-%%m-%%d[T ]%%H:%%M:%%S(%%z)?"
-      journalmatch = SYSLOG_IDENTIFIER=Nextcloud
-    '';
-  };
-
-  services.fail2ban.jails = {
-    nextcloud = ''
-      enabled = true
-
-      # Nextcloud does some throttling already, so we need to set
-      # these to something bigger.
-      findtime = 43200
-      bantime = 86400
-    '';
-  };
-
   services.backups.nextcloud = {
     user = "nextcloud";
     paths = [
diff --git a/flake.lock b/flake.lock
index d349bea..d761f4f 100644
--- a/flake.lock
+++ b/flake.lock
@@ -114,44 +114,10 @@
         "type": "github"
       }
     },
-    "flake-compat_3": {
-      "flake": false,
-      "locked": {
-        "lastModified": 1696426674,
-        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
-        "owner": "edolstra",
-        "repo": "flake-compat",
-        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
-        "type": "github"
-      },
-      "original": {
-        "owner": "edolstra",
-        "repo": "flake-compat",
-        "type": "github"
-      }
-    },
     "flake-utils": {
       "inputs": {
         "systems": "systems_2"
       },
-      "locked": {
-        "lastModified": 1731533236,
-        "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
-        "owner": "numtide",
-        "repo": "flake-utils",
-        "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
-        "type": "github"
-      },
-      "original": {
-        "owner": "numtide",
-        "repo": "flake-utils",
-        "type": "github"
-      }
-    },
-    "flake-utils_2": {
-      "inputs": {
-        "systems": "systems_3"
-      },
       "locked": {
         "lastModified": 1726560853,
         "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
@@ -272,37 +238,15 @@
         "type": "github"
       }
     },
-    "nvfetcher": {
-      "inputs": {
-        "flake-compat": "flake-compat_2",
-        "flake-utils": "flake-utils",
-        "nixpkgs": [
-          "nixpkgs"
-        ]
-      },
-      "locked": {
-        "lastModified": 1732501185,
-        "narHash": "sha256-Z0BpHelaGQsE5VD9hBsBHsvMU9h+Xt0kfkDJyFivZOU=",
-        "owner": "berberman",
-        "repo": "nvfetcher",
-        "rev": "bdb14eab6fe9cefc29efe01e60c3a3f616d6b62a",
-        "type": "github"
-      },
-      "original": {
-        "owner": "berberman",
-        "repo": "nvfetcher",
-        "type": "github"
-      }
-    },
     "poetry2nixi": {
       "inputs": {
-        "flake-utils": "flake-utils_2",
+        "flake-utils": "flake-utils",
         "nix-github-actions": "nix-github-actions",
         "nixpkgs": [
           "sonnenshift",
           "nixpkgs"
         ],
-        "systems": "systems_4",
+        "systems": "systems_3",
         "treefmt-nix": "treefmt-nix"
       },
       "locked": {
@@ -321,7 +265,7 @@
     },
     "purescript-overlay": {
       "inputs": {
-        "flake-compat": "flake-compat_3",
+        "flake-compat": "flake-compat_2",
         "nixpkgs": [
           "tlaternet-webserver",
           "dream2nix",
@@ -367,7 +311,6 @@
         "foundryvtt": "foundryvtt",
         "nixpkgs": "nixpkgs_2",
         "nixpkgs-unstable": "nixpkgs-unstable",
-        "nvfetcher": "nvfetcher",
         "sonnenshift": "sonnenshift",
         "sops-nix": "sops-nix",
         "tlaternet-webserver": "tlaternet-webserver"
@@ -485,21 +428,6 @@
       }
     },
     "systems_3": {
-      "locked": {
-        "lastModified": 1681028828,
-        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
-        "owner": "nix-systems",
-        "repo": "default",
-        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nix-systems",
-        "repo": "default",
-        "type": "github"
-      }
-    },
-    "systems_4": {
       "locked": {
         "lastModified": 1681028828,
         "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
diff --git a/flake.nix b/flake.nix
index e6f1dcb..2253566 100644
--- a/flake.nix
+++ b/flake.nix
@@ -13,10 +13,6 @@
       url = "github:Mic92/sops-nix";
       inputs.nixpkgs.follows = "nixpkgs";
     };
-    nvfetcher = {
-      url = "github:berberman/nvfetcher";
-      inputs.nixpkgs.follows = "nixpkgs";
-    };
     tlaternet-webserver = {
       url = "git+https://gitea.tlater.net/tlaternet/tlaternet.git";
       inputs.nixpkgs.follows = "nixpkgs";
@@ -37,7 +33,6 @@
       self,
       nixpkgs,
       sops-nix,
-      nvfetcher,
       deploy-rs,
       ...
     }@inputs:
@@ -120,18 +115,6 @@
               ${vm.config.system.build.vm.outPath}/bin/run-testvm-vm
             '').outPath;
         };
-
-        update-pkgs = {
-          type = "app";
-          program =
-            let
-              nvfetcher-bin = "${nvfetcher.packages.${system}.default}/bin/nvfetcher";
-            in
-            (pkgs.writeShellScript "update-pkgs" ''
-              cd "$(git rev-parse --show-toplevel)/pkgs"
-              ${nvfetcher-bin} -o _sources_pkgs -c nvfetcher.toml
-            '').outPath;
-        };
       };
 
       ###########################
diff --git a/pkgs/_sources_pkgs/generated.json b/pkgs/_sources_pkgs/generated.json
deleted file mode 100644
index cec5a92..0000000
--- a/pkgs/_sources_pkgs/generated.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-    "prometheus-fail2ban-exporter": {
-        "cargoLocks": null,
-        "date": null,
-        "extract": null,
-        "name": "prometheus-fail2ban-exporter",
-        "passthru": null,
-        "pinned": false,
-        "src": {
-            "deepClone": false,
-            "fetchSubmodules": false,
-            "leaveDotGit": false,
-            "name": null,
-            "rev": "v0.10.1",
-            "sha256": "sha256-zGEhDy3uXIbvx4agSA8Mx7bRtiZZtoDZGbNbHc9L+yI=",
-            "sparseCheckout": [],
-            "type": "git",
-            "url": "https://gitlab.com/hectorjsmith/fail2ban-prometheus-exporter"
-        },
-        "version": "v0.10.1"
-    }
-}
\ No newline at end of file
diff --git a/pkgs/_sources_pkgs/generated.nix b/pkgs/_sources_pkgs/generated.nix
deleted file mode 100644
index 95fd75e..0000000
--- a/pkgs/_sources_pkgs/generated.nix
+++ /dev/null
@@ -1,17 +0,0 @@
-# This file was generated by nvfetcher, please do not modify it manually.
-{ fetchgit, fetchurl, fetchFromGitHub, dockerTools }:
-{
-  prometheus-fail2ban-exporter = {
-    pname = "prometheus-fail2ban-exporter";
-    version = "v0.10.1";
-    src = fetchgit {
-      url = "https://gitlab.com/hectorjsmith/fail2ban-prometheus-exporter";
-      rev = "v0.10.1";
-      fetchSubmodules = false;
-      deepClone = false;
-      leaveDotGit = false;
-      sparseCheckout = [ ];
-      sha256 = "sha256-zGEhDy3uXIbvx4agSA8Mx7bRtiZZtoDZGbNbHc9L+yI=";
-    };
-  };
-}
diff --git a/pkgs/default.nix b/pkgs/default.nix
index 131282d..036afd4 100644
--- a/pkgs/default.nix
+++ b/pkgs/default.nix
@@ -4,7 +4,4 @@ let
 in
 {
   starbound = callPackage ./starbound { };
-  prometheus-fail2ban-exporter = callPackage ./prometheus/fail2ban-exporter.nix {
-    sources = pkgs.callPackage ./_sources_pkgs/generated.nix { };
-  };
 }
diff --git a/pkgs/nvfetcher.toml b/pkgs/nvfetcher.toml
deleted file mode 100644
index d0dfbe5..0000000
--- a/pkgs/nvfetcher.toml
+++ /dev/null
@@ -1,3 +0,0 @@
-[prometheus-fail2ban-exporter]
-src.manual = "v0.10.1" # No gitlab support in nvfetcher
-fetch.git = "https://gitlab.com/hectorjsmith/fail2ban-prometheus-exporter"
diff --git a/pkgs/prometheus/fail2ban-exporter.nix b/pkgs/prometheus/fail2ban-exporter.nix
deleted file mode 100644
index dc22b6c..0000000
--- a/pkgs/prometheus/fail2ban-exporter.nix
+++ /dev/null
@@ -1,5 +0,0 @@
-{ buildGoModule, sources }:
-buildGoModule {
-  inherit (sources.prometheus-fail2ban-exporter) pname src version;
-  vendorHash = "sha256-5o8p5p0U/c0WAIV5dACnWA3ThzSh2tt5LIFMb59i9GY=";
-}

From d0c6f2bcbe387ed451cfa5a83d3ad78c9725cc3a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 24 Jan 2025 00:35:23 +0800
Subject: [PATCH 33/67] feat: Add crowdsec module

---
 flake.lock                                    |  17 +
 flake.nix                                     |  29 +-
 modules/crowdsec/default.nix                  | 361 ++++++++++++++++++
 .../remediations/cs-firewall-bouncer.nix      |  90 +++++
 modules/crowdsec/remediations/default.nix     |   5 +
 modules/default.nix                           |   7 +-
 pkgs/crowdsec/_sources/generated.json         |  42 ++
 pkgs/crowdsec/_sources/generated.nix          |  27 ++
 pkgs/crowdsec/default.nix                     |   9 +
 pkgs/crowdsec/firewall-bouncer.nix            |  26 ++
 pkgs/crowdsec/hub.nix                         |   4 +
 pkgs/crowdsec/nvfetcher.toml                  |   7 +
 pkgs/default.nix                              |   6 +-
 13 files changed, 624 insertions(+), 6 deletions(-)
 create mode 100644 modules/crowdsec/default.nix
 create mode 100644 modules/crowdsec/remediations/cs-firewall-bouncer.nix
 create mode 100644 modules/crowdsec/remediations/default.nix
 create mode 100644 pkgs/crowdsec/_sources/generated.json
 create mode 100644 pkgs/crowdsec/_sources/generated.nix
 create mode 100644 pkgs/crowdsec/default.nix
 create mode 100644 pkgs/crowdsec/firewall-bouncer.nix
 create mode 100644 pkgs/crowdsec/hub.nix
 create mode 100644 pkgs/crowdsec/nvfetcher.toml

diff --git a/flake.lock b/flake.lock
index d761f4f..d86b361 100644
--- a/flake.lock
+++ b/flake.lock
@@ -190,6 +190,22 @@
         "type": "github"
       }
     },
+    "nixpkgs-crowdsec": {
+      "locked": {
+        "lastModified": 1738085579,
+        "narHash": "sha256-7mLjMrOiiIi0vI7BJwbEipYQzwA7JF/NWHP+LM4q5S8=",
+        "owner": "tlater",
+        "repo": "nixpkgs",
+        "rev": "426a7afc9a6ecfdac544bda4022acef31e36df34",
+        "type": "github"
+      },
+      "original": {
+        "owner": "tlater",
+        "ref": "tlater/fix-crowdsec",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
     "nixpkgs-unstable": {
       "locked": {
         "lastModified": 1737192615,
@@ -310,6 +326,7 @@
         "disko": "disko",
         "foundryvtt": "foundryvtt",
         "nixpkgs": "nixpkgs_2",
+        "nixpkgs-crowdsec": "nixpkgs-crowdsec",
         "nixpkgs-unstable": "nixpkgs-unstable",
         "sonnenshift": "sonnenshift",
         "sops-nix": "sops-nix",
diff --git a/flake.nix b/flake.nix
index 2253566..3d04d7c 100644
--- a/flake.nix
+++ b/flake.nix
@@ -26,6 +26,8 @@
       url = "git+ssh://git@github.com/sonnenshift/battery-manager";
       inputs.nixpkgs.follows = "nixpkgs";
     };
+
+    nixpkgs-crowdsec.url = "github:tlater/nixpkgs/tlater/fix-crowdsec";
   };
 
   outputs =
@@ -98,7 +100,16 @@
       # Garbage collection root #
       ###########################
 
-      packages.${system}.default = vm.config.system.build.vm;
+      packages.${system} =
+        let
+          localPkgs = import ./pkgs { inherit pkgs; };
+        in
+        {
+          default = vm.config.system.build.vm;
+          crowdsec = pkgs.callPackage "${inputs.nixpkgs-crowdsec}/pkgs/by-name/cr/crowdsec/package.nix" { };
+          crowdsec-hub = localPkgs.crowdsec.hub;
+          crowdsec-firewall-bouncer = localPkgs.crowdsec.firewall-bouncer;
+        };
 
       ###################
       # Utility scripts #
@@ -115,6 +126,22 @@
               ${vm.config.system.build.vm.outPath}/bin/run-testvm-vm
             '').outPath;
         };
+
+        update-crowdsec-packages =
+          let
+            git = pkgs.lib.getExe pkgs.git;
+            nvfetcher = pkgs.lib.getExe pkgs.nvfetcher;
+          in
+          {
+            type = "app";
+            program =
+              (pkgs.writeShellScript "update-crowdsec-packages" ''
+                cd "$(${git} rev-parse --show-toplevel)"
+                cd ./pkgs/crowdsec
+                ${nvfetcher}
+                echo 'Remember to update the vendorHash of any go packages!'
+              '').outPath;
+          };
       };
 
       ###########################
diff --git a/modules/crowdsec/default.nix b/modules/crowdsec/default.nix
new file mode 100644
index 0000000..915ca0b
--- /dev/null
+++ b/modules/crowdsec/default.nix
@@ -0,0 +1,361 @@
+{
+  flake-inputs,
+  pkgs,
+  lib,
+  config,
+  ...
+}:
+let
+  cfg = config.security.crowdsec;
+  settingsFormat = pkgs.formats.yaml { };
+
+  crowdsec = flake-inputs.self.packages.${pkgs.system}.crowdsec;
+
+  hub = pkgs.fetchFromGitHub {
+    owner = "crowdsecurity";
+    repo = "hub";
+    rev = "7a3b4753f4577257c0cbeb8f8f90c7f17d2ae008";
+    hash = "sha256-HB4jHyhiO8gjBkLmpo6bDbwhfm5m5nAtNlKhDkZjt2I=";
+  };
+
+  cscli = pkgs.writeShellScriptBin "cscli" ''
+    export PATH="$PATH:${crowdsec}/bin/"
+
+    sudo=exec
+    if [ "$USER" != "crowdsec" ]; then
+        sudo='exec /run/wrappers/bin/sudo -u crowdsec'
+    fi
+
+    $sudo ${crowdsec}/bin/cscli "$@"
+  '';
+in
+{
+  imports = [ ./remediations ];
+
+  options.security.crowdsec =
+    let
+      inherit (lib.types)
+        nullOr
+        listOf
+        package
+        path
+        str
+        ;
+    in
+    {
+      enable = lib.mkEnableOption "crowdsec";
+
+      package = lib.mkOption {
+        type = package;
+        default = crowdsec;
+      };
+
+      stateDirectory = lib.mkOption {
+        type = path;
+        readOnly = true;
+
+        description = ''
+          The state directory of the crowdsec instance. Cannot be
+          changed, but is exposed for downstream use.
+        '';
+      };
+
+      settings = lib.mkOption {
+        inherit (settingsFormat) type;
+        default = { };
+
+        description = ''
+          The crowdsec configuration. Refer to
+          <https://docs.crowdsec.net/docs/next/configuration/crowdsec_configuration/>
+          for details on supported values.
+        '';
+      };
+
+      parserWhitelist = lib.mkOption {
+        type = listOf str;
+        default = [ ];
+        description = ''
+          Set of IP addresses to add to a parser-based whitelist.
+
+          Addresses can be specified either as plain IP addresses or
+          in CIDR notation.
+        '';
+      };
+
+      hubConfigurations = {
+        collections = lib.mkOption {
+          type = listOf str;
+          description = ''
+            List of pre-made crowdsec collections to install.
+          '';
+        };
+
+        scenarios = lib.mkOption {
+          type = listOf str;
+          description = ''
+            List of pre-made crowdsec scenarios to install.
+          '';
+        };
+
+        parsers = lib.mkOption {
+          type = listOf str;
+          description = ''
+            List of pre-made crowdsec parsers to install.
+          '';
+        };
+
+        postoverflows = lib.mkOption {
+          type = listOf str;
+          description = ''
+            List of pre-made crowdsec postoverflows to install.
+          '';
+        };
+
+        appsecConfigs = lib.mkOption {
+          type = listOf str;
+          description = ''
+            List of pre-made crowdsec appsec configurations to install.
+          '';
+        };
+
+        appsecRules = lib.mkOption {
+          type = listOf str;
+          description = ''
+            List of pre-made crowdsec appsec rules to install.
+          '';
+        };
+      };
+
+      centralApiCredentials = lib.mkOption {
+        type = nullOr path;
+        default = null;
+
+        description = ''
+          The API key to access crowdsec's central API - this is
+          required to access any of the shared blocklists.
+
+          Use of this feature is optional, entering no API key (the
+          default) turns all sharing or receiving of blocked IPs off.
+
+          Note that adding the API key by itself does not enable
+          sharing of blocked IPs with the central API. This limits the
+          types of blocklists this instance can access.
+
+          To also turn sharing blocked IPs on, set
+          `api.server.online_client.sharing = true;`.
+        '';
+      };
+
+      ctiApiKey = lib.mkOption {
+        type = nullOr path;
+        default = null;
+
+        description = ''
+          The API key for crowdsec's CTI offering.
+        '';
+      };
+    };
+
+  config = lib.mkIf cfg.enable {
+    # Set up default settings; anything that *shouldn't* be changed is
+    # set to the default priority so that users need to use
+    # `lib.mkForce`.
+    security.crowdsec = {
+      stateDirectory = "/var/lib/crowdsec";
+
+      settings = {
+        common = {
+          daemonize = true;
+          # The default logs to files, which isn't the preferred way
+          # on NixOS
+          log_media = "stdout";
+        };
+
+        config_paths = {
+          config_dir = "${cfg.stateDirectory}/config/";
+          data_dir = "${cfg.stateDirectory}/data/";
+          # This "config" file is intended to be written to using the
+          # cscli tool, so you can temporarily make it so rules don't
+          # do anything but log what they *would* do for
+          # experimentation.
+          simulation_path = "${cfg.stateDirectory}/config/simulation.yaml";
+
+          pattern_dir = lib.mkDefault "${cfg.package}/share/crowdsec/config/patterns";
+
+          hub_dir = hub;
+          index_path = "${hub}/.index.json";
+
+          # Integrations aren't supported for now
+          notification_dir = lib.mkDefault "/var/empty/";
+          plugin_dir = lib.mkDefault "/var/empty/";
+        };
+
+        crowdsec_service.acquisition_path = lib.mkDefault "${cfg.package}/share/crowdsec/config/acquis.yaml";
+
+        cscli = {
+          prometheus_uri = lib.mkDefault "127.0.0.1:6060";
+        };
+
+        db_config = {
+          type = lib.mkDefault "sqlite";
+          db_path = lib.mkDefault "${cfg.stateDirectory}/data/crowdsec.db";
+          use_wal = lib.mkDefault true;
+          flush = {
+            max_items = lib.mkDefault 5000;
+            max_age = lib.mkDefault "7d";
+          };
+        };
+
+        api = {
+          cti = {
+            enabled = cfg.ctiApiKey != null;
+            key = cfg.ctiApiKey;
+          };
+          client.credentials_path = "${cfg.stateDirectory}/local_credentials.yaml";
+          server = {
+            listen_uri = lib.mkDefault "127.0.0.1:8080";
+            profiles_path = lib.mkDefault "${cfg.package}/share/crowdsec/config/profiles.yaml";
+            console_path = lib.mkDefault "${cfg.package}/share/crowdsec/config/console.yaml";
+
+            online_client = {
+              # By default, we don't let crowdsec phone home, since
+              # this is usually within NixOS users' concerns.
+              #
+              # TODO: Enable when this option becomes available
+              # (1.6.4, current nixpkgs-unstable)
+              # sharing = lib.mkDefault false;
+              credentials_path = cfg.centralApiCredentials;
+            };
+          };
+        };
+
+        # We enable prometheus by default, since cscli relies on it
+        # for metrics
+        prometheus = {
+          enabled = lib.mkDefault true;
+          level = lib.mkDefault "full";
+          listen_addr = lib.mkDefault "127.0.0.1";
+          listen_port = lib.mkDefault 6060;
+        };
+      };
+    };
+
+    systemd.packages = [
+      cfg.package
+    ];
+
+    environment = {
+      systemPackages = [
+        # To add completions; sadly need to hand-roll this since
+        # neither `symlinkJoin` nor `buildEnv` have collision
+        # handling.
+        (pkgs.runCommandNoCCLocal "cscli" { } ''
+          mkdir -p $out
+          ln -s ${cscli}/bin $out/bin
+          ln -s ${cfg.package}/share $out/share
+        '')
+      ];
+
+      etc."crowdsec/config.yaml".source = settingsFormat.generate "crowdsec-settings.yaml" cfg.settings;
+    };
+
+    systemd = {
+      tmpfiles.settings."10-crowdsec" = {
+        "${cfg.stateDirectory}".d = {
+          user = "crowdsec";
+          group = "crowdsec";
+          mode = "0700";
+        };
+
+        # This must be created for the setup service to work
+        "${cfg.stateDirectory}/config".d = {
+          user = "crowdsec";
+          group = "crowdsec";
+          mode = "0700";
+        };
+
+        "${cfg.stateDirectory}/config/parsers".d = lib.mkIf (cfg.parserWhitelist != [ ]) {
+          user = "crowdsec";
+          group = "crowdsec";
+          mode = "0700";
+        };
+
+        "${cfg.stateDirectory}/config/parsers/s02-enrich".d = lib.mkIf (cfg.parserWhitelist != [ ]) {
+          user = "crowdsec";
+          group = "crowdsec";
+          mode = "0700";
+        };
+
+        "${cfg.stateDirectory}/config/parsers/s02-enrich/nixos-whitelist.yaml" =
+          lib.mkIf (cfg.parserWhitelist != [ ])
+            {
+              "L+".argument =
+                (settingsFormat.generate "crowdsec-nixos-whitelist.yaml" {
+                  name = "nixos/parser-whitelist";
+                  description = "Parser whitelist generated by the crowdsec NixOS module";
+                  whitelist = {
+                    reason = "Filtered by NixOS whitelist";
+                    ip = lib.lists.filter (ip: !(lib.hasInfix "/" ip)) cfg.parserWhitelist;
+                    cidr = lib.lists.filter (ip: lib.hasInfix "/" ip) cfg.parserWhitelist;
+                  };
+                }).outPath;
+            };
+      };
+
+      services = {
+        crowdsec-setup = {
+          # TODO(tlater): Depend on tmpfiles path for
+          # /var/lib/crowdsec/config
+          description = "Crowdsec database and config preparation";
+
+          script = ''
+            if [ ! -e '${cfg.settings.config_paths.simulation_path}' ]; then
+                cp '${cfg.package}/share/crowdsec/config/simulation.yaml' '${cfg.settings.config_paths.simulation_path}'
+            fi
+
+            if [ ! -e '${cfg.settings.api.client.credentials_path}' ]; then
+                ${cfg.package}/bin/cscli machines add --auto --file '${cfg.settings.api.client.credentials_path}'
+            fi
+          '';
+
+          serviceConfig = {
+            User = "crowdsec";
+            Group = "crowdsec";
+            StateDirectory = "crowdsec";
+
+            Type = "oneshot";
+            RemainAfterExit = true;
+          };
+        };
+
+        # Note that the service basics are already defined upstream
+        crowdsec = {
+          enable = true;
+
+          after = [ "crowdsec-setup.service" ];
+          bindsTo = [ "crowdsec-setup.service" ];
+          wantedBy = [ "multi-user.target" ];
+
+          serviceConfig = {
+            User = "crowdsec";
+            Group = "crowdsec";
+            SupplementaryGroups = [ "systemd-journal" ];
+
+            StateDirectory = "crowdsec";
+          };
+        };
+      };
+    };
+
+    users = {
+      users.crowdsec = {
+        isSystemUser = true;
+        home = cfg.stateDirectory;
+        group = "crowdsec";
+      };
+      groups = {
+        crowdsec = { };
+      };
+    };
+  };
+}
diff --git a/modules/crowdsec/remediations/cs-firewall-bouncer.nix b/modules/crowdsec/remediations/cs-firewall-bouncer.nix
new file mode 100644
index 0000000..aa70552
--- /dev/null
+++ b/modules/crowdsec/remediations/cs-firewall-bouncer.nix
@@ -0,0 +1,90 @@
+{
+  flake-inputs,
+  pkgs,
+  lib,
+  config,
+  ...
+}:
+let
+  crowdsecCfg = config.security.crowdsec;
+  cfg = crowdsecCfg.remediationComponents.firewallBouncer;
+  settingsFormat = pkgs.formats.yaml { };
+  crowdsec-firewall-bouncer = flake-inputs.self.packages.${pkgs.system}.crowdsec-firewall-bouncer;
+in
+{
+  options.security.crowdsec.remediationComponents.firewallBouncer = {
+    enable = lib.mkEnableOption "cs-firewall-bouncer";
+
+    settings = lib.mkOption {
+      inherit (settingsFormat) type;
+      default = { };
+
+      description = ''
+        The bouncer configuration. Refer to
+        <https://docs.crowdsec.net/u/bouncers/firewall/> for details
+        on supported values.
+      '';
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    security.crowdsec.remediationComponents.firewallBouncer.settings = {
+      mode = lib.mkDefault "${if config.networking.nftables.enable then "nftables" else "iptables"}";
+      log_mode = "stdout";
+      iptables_chains = [
+        "nixos-fw"
+      ];
+
+      # Don't let users easily override this; unfortunately we need to
+      # set up this key through substitution at runtime.
+      api_key = lib.mkForce "\${API_KEY}";
+      api_url = lib.mkDefault "http://${crowdsecCfg.settings.api.server.listen_uri}";
+    };
+
+    systemd = {
+      packages = [ crowdsec-firewall-bouncer ];
+
+      services = {
+        crowdsec-firewall-bouncer-setup = {
+          description = "Crowdsec firewall bouncer config preparation";
+          script = ''
+            if [ ! -e '${crowdsecCfg.stateDirectory}/firewall_bouncer_credentials.yaml' ]; then
+                ${crowdsecCfg.package}/bin/cscli -oraw bouncers add "cs-firewall-bouncer-$(${pkgs.coreutils}/bin/date +%s)" > \
+                  ${crowdsecCfg.stateDirectory}/firewall_bouncer_credentials.yaml
+            fi
+
+            # Stdout redirection is deliberately used to forcibly
+            # overwrite the file if it exists
+            API_KEY="$(<${crowdsecCfg.stateDirectory}/firewall_bouncer_credentials.yaml)" \
+              ${lib.getExe pkgs.envsubst} \
+              -i ${settingsFormat.generate "crowdsec-firewall-bouncer.yaml" cfg.settings} \
+              > /var/lib/crowdsec/config/crowdsec-firewall-bouncer.yaml
+          '';
+
+          serviceConfig = {
+            User = "crowdsec";
+            Group = "crowdsec";
+
+            Type = "oneshot";
+            RemainAfterExit = true;
+          };
+        };
+
+        crowdsec-firewall-bouncer = {
+          enable = true;
+
+          after = [ "crowdsec-firewall-bouncer-setup.service" ];
+          bindsTo = [ "crowdsec-firewall-bouncer-setup.service" ];
+          requiredBy = [ "crowdsec.service" ];
+
+          path =
+            lib.optionals (cfg.settings.mode == "ipset" || cfg.settings.mode == "iptables") [
+              pkgs.ipset
+            ]
+            ++ lib.optional (cfg.settings.mode == "iptables") pkgs.iptables
+            ++ lib.optional (cfg.settings.mode == "nftables") pkgs.nftables;
+        };
+      };
+    };
+  };
+}
diff --git a/modules/crowdsec/remediations/default.nix b/modules/crowdsec/remediations/default.nix
new file mode 100644
index 0000000..7df6ade
--- /dev/null
+++ b/modules/crowdsec/remediations/default.nix
@@ -0,0 +1,5 @@
+{
+  imports = [
+    ./cs-firewall-bouncer.nix
+  ];
+}
diff --git a/modules/default.nix b/modules/default.nix
index e1db4cc..89f1752 100644
--- a/modules/default.nix
+++ b/modules/default.nix
@@ -1 +1,6 @@
-{ imports = [ ./nginxExtensions.nix ]; }
+{
+  imports = [
+    ./crowdsec
+    ./nginxExtensions.nix
+  ];
+}
diff --git a/pkgs/crowdsec/_sources/generated.json b/pkgs/crowdsec/_sources/generated.json
new file mode 100644
index 0000000..8485779
--- /dev/null
+++ b/pkgs/crowdsec/_sources/generated.json
@@ -0,0 +1,42 @@
+{
+    "crowdsec-firewall-bouncer": {
+        "cargoLocks": null,
+        "date": null,
+        "extract": null,
+        "name": "crowdsec-firewall-bouncer",
+        "passthru": null,
+        "pinned": false,
+        "src": {
+            "deepClone": false,
+            "fetchSubmodules": false,
+            "leaveDotGit": false,
+            "name": null,
+            "owner": "crowdsecurity",
+            "repo": "cs-firewall-bouncer",
+            "rev": "v0.0.31",
+            "sha256": "sha256-59MWll8v00CF4WA53gjHZSTFc8hpYaHENg9O7LgTCrA=",
+            "type": "github"
+        },
+        "version": "v0.0.31"
+    },
+    "crowdsec-hub": {
+        "cargoLocks": null,
+        "date": "2025-01-30",
+        "extract": null,
+        "name": "crowdsec-hub",
+        "passthru": null,
+        "pinned": false,
+        "src": {
+            "deepClone": false,
+            "fetchSubmodules": false,
+            "leaveDotGit": false,
+            "name": null,
+            "owner": "crowdsecurity",
+            "repo": "hub",
+            "rev": "8f102f5ac79af59d3024ca2771b65ec87411ac02",
+            "sha256": "sha256-8K1HkBg0++Au1dr2KMrl9b2ruqXdo+vqWngOCwL11Mo=",
+            "type": "github"
+        },
+        "version": "8f102f5ac79af59d3024ca2771b65ec87411ac02"
+    }
+}
\ No newline at end of file
diff --git a/pkgs/crowdsec/_sources/generated.nix b/pkgs/crowdsec/_sources/generated.nix
new file mode 100644
index 0000000..6f845ec
--- /dev/null
+++ b/pkgs/crowdsec/_sources/generated.nix
@@ -0,0 +1,27 @@
+# This file was generated by nvfetcher, please do not modify it manually.
+{ fetchgit, fetchurl, fetchFromGitHub, dockerTools }:
+{
+  crowdsec-firewall-bouncer = {
+    pname = "crowdsec-firewall-bouncer";
+    version = "v0.0.31";
+    src = fetchFromGitHub {
+      owner = "crowdsecurity";
+      repo = "cs-firewall-bouncer";
+      rev = "v0.0.31";
+      fetchSubmodules = false;
+      sha256 = "sha256-59MWll8v00CF4WA53gjHZSTFc8hpYaHENg9O7LgTCrA=";
+    };
+  };
+  crowdsec-hub = {
+    pname = "crowdsec-hub";
+    version = "8f102f5ac79af59d3024ca2771b65ec87411ac02";
+    src = fetchFromGitHub {
+      owner = "crowdsecurity";
+      repo = "hub";
+      rev = "8f102f5ac79af59d3024ca2771b65ec87411ac02";
+      fetchSubmodules = false;
+      sha256 = "sha256-8K1HkBg0++Au1dr2KMrl9b2ruqXdo+vqWngOCwL11Mo=";
+    };
+    date = "2025-01-30";
+  };
+}
diff --git a/pkgs/crowdsec/default.nix b/pkgs/crowdsec/default.nix
new file mode 100644
index 0000000..66faac3
--- /dev/null
+++ b/pkgs/crowdsec/default.nix
@@ -0,0 +1,9 @@
+{ pkgs }:
+let
+  sources = pkgs.callPackage ./_sources/generated.nix { };
+  callPackage = pkgs.lib.callPackageWith (pkgs // { inherit sources; });
+in
+{
+  hub = callPackage ./hub.nix { };
+  firewall-bouncer = callPackage ./firewall-bouncer.nix { };
+}
diff --git a/pkgs/crowdsec/firewall-bouncer.nix b/pkgs/crowdsec/firewall-bouncer.nix
new file mode 100644
index 0000000..86370c4
--- /dev/null
+++ b/pkgs/crowdsec/firewall-bouncer.nix
@@ -0,0 +1,26 @@
+{
+  lib,
+  sources,
+  buildGoModule,
+  envsubst,
+  coreutils,
+}:
+let
+  envsubstBin = lib.getExe envsubst;
+in
+buildGoModule {
+  inherit (sources.crowdsec-firewall-bouncer) pname version src;
+
+  vendorHash = "sha256-7Jxvg8UEjUxnIz1llvXyI2AefJ31OVdNzhWD/C8wU/Y=";
+
+  postInstall = ''
+    mkdir -p $out/lib/systemd/system
+
+    CFG=/var/lib/crowdsec/config BIN=$out/bin/cs-firewall-bouncer ${envsubstBin} \
+      -i ./config/crowdsec-firewall-bouncer.service \
+      -o $out/lib/systemd/system/crowdsec-firewall-bouncer.service
+
+    substituteInPlace $out/lib/systemd/system/crowdsec-firewall-bouncer.service \
+      --replace-fail /bin/sleep ${coreutils}/bin/sleep
+  '';
+}
diff --git a/pkgs/crowdsec/hub.nix b/pkgs/crowdsec/hub.nix
new file mode 100644
index 0000000..d057ca8
--- /dev/null
+++ b/pkgs/crowdsec/hub.nix
@@ -0,0 +1,4 @@
+{
+  sources,
+}:
+sources.crowdsec-hub.src
diff --git a/pkgs/crowdsec/nvfetcher.toml b/pkgs/crowdsec/nvfetcher.toml
new file mode 100644
index 0000000..2287dba
--- /dev/null
+++ b/pkgs/crowdsec/nvfetcher.toml
@@ -0,0 +1,7 @@
+[crowdsec-hub]
+src.git = "https://github.com/crowdsecurity/hub.git"
+fetch.github = "crowdsecurity/hub"
+
+[crowdsec-firewall-bouncer]
+src.github = "crowdsecurity/cs-firewall-bouncer"
+fetch.github = "crowdsecurity/cs-firewall-bouncer"
diff --git a/pkgs/default.nix b/pkgs/default.nix
index 036afd4..0e5de7a 100644
--- a/pkgs/default.nix
+++ b/pkgs/default.nix
@@ -1,7 +1,5 @@
 { pkgs }:
-let
-  inherit (pkgs) callPackage;
-in
 {
-  starbound = callPackage ./starbound { };
+  crowdsec = import ./crowdsec { inherit pkgs; };
+  starbound = pkgs.callPackage ./starbound { };
 }

From 40187d4b2d64f6835dcddef68edaa160d2219daa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Thu, 30 Jan 2025 03:50:08 +0800
Subject: [PATCH 34/67] feat: Add crowdsec to replace fail2ban

---
 configuration/default.nix                     |  1 +
 configuration/services/crowdsec.nix           | 35 +++++++++++++++++++
 .../services/metrics/victoriametrics.nix      | 16 +++++++++
 3 files changed, 52 insertions(+)
 create mode 100644 configuration/services/crowdsec.nix

diff --git a/configuration/default.nix b/configuration/default.nix
index a22f8fc..c9c71ec 100644
--- a/configuration/default.nix
+++ b/configuration/default.nix
@@ -18,6 +18,7 @@
     ./services/backups.nix
     ./services/battery-manager.nix
     ./services/conduit.nix
+    ./services/crowdsec.nix
     ./services/foundryvtt.nix
     ./services/gitea.nix
     ./services/metrics
diff --git a/configuration/services/crowdsec.nix b/configuration/services/crowdsec.nix
new file mode 100644
index 0000000..110602c
--- /dev/null
+++ b/configuration/services/crowdsec.nix
@@ -0,0 +1,35 @@
+{ pkgs, ... }:
+{
+  security.crowdsec = {
+    enable = true;
+
+    parserWhitelist = [
+      "1.64.239.213"
+    ];
+
+    settings.crowdsec_service.acquisition_path = pkgs.writeText "crowdsec-acquisitions.yaml" ''
+      ---
+      source: journalctl
+      journalctl_filter:
+        - "SYSLOG_IDENTIFIER=Nextcloud"
+      labels:
+        type: syslog
+      ---
+      source: journalctl
+      journalctl_filter:
+        - "SYSLOG_IDENTIFIER=sshd-session"
+      labels:
+        type: syslog
+      ---
+    '';
+
+    remediationComponents.firewallBouncer = {
+      enable = true;
+      settings.prometheus = {
+        enabled = true;
+        listen_addr = "127.0.0.1";
+        listen_port = "60601";
+      };
+    };
+  };
+}
diff --git a/configuration/services/metrics/victoriametrics.nix b/configuration/services/metrics/victoriametrics.nix
index 710cf70..5cfc614 100644
--- a/configuration/services/metrics/victoriametrics.nix
+++ b/configuration/services/metrics/victoriametrics.nix
@@ -10,6 +10,22 @@
         extraSettings.authorization.credentials_file = config.sops.secrets."forgejo/metrics-token".path;
       };
       coturn.targets = [ "127.0.0.1:9641" ];
+
+      crowdsec.targets =
+        let
+          address = config.security.crowdsec.settings.prometheus.listen_addr;
+          port = config.security.crowdsec.settings.prometheus.listen_port;
+        in
+        [ "${address}:${toString port}" ];
+
+      csFirewallBouncer.targets =
+        let
+          address =
+            config.security.crowdsec.remediationComponents.firewallBouncer.settings.prometheus.listen_addr;
+          port =
+            config.security.crowdsec.remediationComponents.firewallBouncer.settings.prometheus.listen_port;
+        in
+        [ "${address}:${toString port}" ];
     };
   };
 }

From 2831fdb0f27e2b3e6eb32f907681a07337a752ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 1 Feb 2025 17:57:32 +0800
Subject: [PATCH 35/67] feat(crowdsec): Add proper support for acquisitions

---
 modules/crowdsec/default.nix | 34 ++++++++++++++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/modules/crowdsec/default.nix b/modules/crowdsec/default.nix
index 915ca0b..0d0ff1c 100644
--- a/modules/crowdsec/default.nix
+++ b/modules/crowdsec/default.nix
@@ -28,6 +28,12 @@ let
 
     $sudo ${crowdsec}/bin/cscli "$@"
   '';
+
+  acquisitions = ''
+    ---
+    ${lib.concatMapStringsSep "\n---\n" builtins.toJSON cfg.acquisitions}
+    ---
+  '';
 in
 {
   imports = [ ./remediations ];
@@ -82,6 +88,24 @@ in
         '';
       };
 
+      acquisitions = lib.mkOption {
+        type = listOf settingsFormat.type;
+        default = [ ];
+        description = ''
+          Log acquisitions.
+        '';
+      };
+
+      extraGroups = lib.mkOption {
+        type = listOf str;
+        default = [ ];
+        description = ''
+          Additional groups to make the service part of.
+
+          Required to permit reading from various log sources.
+        '';
+      };
+
       hubConfigurations = {
         collections = lib.mkOption {
           type = listOf str;
@@ -190,7 +214,13 @@ in
           plugin_dir = lib.mkDefault "/var/empty/";
         };
 
-        crowdsec_service.acquisition_path = lib.mkDefault "${cfg.package}/share/crowdsec/config/acquis.yaml";
+        crowdsec_service.acquisition_path =
+          # Using an if/else here because `mkMerge` does not work in
+          # YAML-type options
+          if cfg.acquisitions == [ ] then
+            "${cfg.package}/share/crowdsec/config/acquis.yaml"
+          else
+            pkgs.writeText "acquis.yaml" acquisitions;
 
         cscli = {
           prometheus_uri = lib.mkDefault "127.0.0.1:6060";
@@ -339,7 +369,7 @@ in
           serviceConfig = {
             User = "crowdsec";
             Group = "crowdsec";
-            SupplementaryGroups = [ "systemd-journal" ];
+            SupplementaryGroups = cfg.extraGroups;
 
             StateDirectory = "crowdsec";
           };

From 68450870cf3776f4f855cfdf117b24069777d3c9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 1 Feb 2025 17:58:15 +0800
Subject: [PATCH 36/67] feat(crowdsec-service): Add nginx monitoring

---
 configuration/services/crowdsec.nix | 50 ++++++++++++++++++++---------
 1 file changed, 34 insertions(+), 16 deletions(-)

diff --git a/configuration/services/crowdsec.nix b/configuration/services/crowdsec.nix
index 110602c..4891cad 100644
--- a/configuration/services/crowdsec.nix
+++ b/configuration/services/crowdsec.nix
@@ -1,4 +1,4 @@
-{ pkgs, ... }:
+{ config, lib, ... }:
 {
   security.crowdsec = {
     enable = true;
@@ -7,21 +7,39 @@
       "1.64.239.213"
     ];
 
-    settings.crowdsec_service.acquisition_path = pkgs.writeText "crowdsec-acquisitions.yaml" ''
-      ---
-      source: journalctl
-      journalctl_filter:
-        - "SYSLOG_IDENTIFIER=Nextcloud"
-      labels:
-        type: syslog
-      ---
-      source: journalctl
-      journalctl_filter:
-        - "SYSLOG_IDENTIFIER=sshd-session"
-      labels:
-        type: syslog
-      ---
-    '';
+    extraGroups = [
+      "systemd-journal"
+      "nginx"
+    ];
+
+    acquisitions = [
+      {
+        source = "journalctl";
+        labels.type = "syslog";
+        journalctl_filter = [
+          "SYSLOG_IDENTIFIER=Nextcloud"
+        ];
+      }
+
+      {
+        source = "journalctl";
+        labels.type = "syslog";
+        journalctl_filter = [
+          "SYSLOG_IDENTIFIER=sshd-session"
+        ];
+      }
+
+      {
+        labels.type = "nginx";
+        filenames =
+          [
+            "/var/log/nginx/*.log"
+          ]
+          ++ lib.mapAttrsToList (
+            vHost: _: "/var/log/nginx/${vHost}/access.log"
+          ) config.services.nginx.virtualHosts;
+      }
+    ];
 
     remediationComponents.firewallBouncer = {
       enable = true;

From 78c81a10284d2202be058c8e51f24baa539cb116 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 1 Feb 2025 18:16:52 +0800
Subject: [PATCH 37/67] feat(acme): Switch to porkbun

---
 configuration/nginx.nix | 13 ++++++++++---
 configuration/sops.nix  | 12 ++++++++----
 keys/production.yaml    | 10 ++++++----
 keys/staging.yaml       | 10 ++++++----
 4 files changed, 30 insertions(+), 15 deletions(-)

diff --git a/configuration/nginx.nix b/configuration/nginx.nix
index b38118b..0b72cc1 100644
--- a/configuration/nginx.nix
+++ b/configuration/nginx.nix
@@ -47,10 +47,17 @@
     acceptTerms = true;
 
     certs."tlater.net" = {
-      extraDomainNames = [ "*.tlater.net" ];
-      dnsProvider = "hetzner";
+      extraDomainNames = [
+        "*.tlater.net"
+        "tlater.com"
+        "*.tlater.com"
+      ];
+      dnsProvider = "porkbun";
       group = "nginx";
-      credentialFiles."HETZNER_API_KEY_FILE" = config.sops.secrets."hetzner-api".path;
+      credentialFiles = {
+        PORKBUN_API_KEY_FILE = config.sops.secrets."porkbun/api-key".path;
+        PORKBUN_SECRET_API_KEY_FILE = config.sops.secrets."porkbun/secret-api-key".path;
+      };
     };
   };
 
diff --git a/configuration/sops.nix b/configuration/sops.nix
index bc21834..bbfb888 100644
--- a/configuration/sops.nix
+++ b/configuration/sops.nix
@@ -34,16 +34,20 @@
       "heisenbridge/as-token" = { };
       "heisenbridge/hs-token" = { };
 
-      "hetzner-api" = {
-        owner = "acme";
-      };
-
       # Nextcloud
       "nextcloud/tlater" = {
         owner = "nextcloud";
         group = "nextcloud";
       };
 
+      # Porkbub/ACME
+      "porkbun/api-key" = {
+        owner = "acme";
+      };
+      "porkbun/secret-api-key" = {
+        owner = "acme";
+      };
+
       # Restic
       "restic/local-backups" = {
         owner = "root";
diff --git a/keys/production.yaml b/keys/production.yaml
index 6dd4c21..19df9bd 100644
--- a/keys/production.yaml
+++ b/keys/production.yaml
@@ -1,4 +1,6 @@
-hetzner-api: ENC[AES256_GCM,data:OsUfo86AzcBe/OELkfB5brEfsZ4gkbeehxwIVUBwQgE=,iv:Bt/cjlZ6oZEVUOQjWMDL7/mfL3HWLFAw1tEGeLMgeKg=,tag:TMU2XiHlMgP4aes10mIQYQ==,type:str]
+porkbun:
+    api-key: ENC[AES256_GCM,data:p3lqvGc8m2U/12rBPjoNR7hxQyD52CyEen/V8q59k5CSJZSqzZS8M5vEXFBsUMjz2lrmKM4pgtz4wa2fWK6Ty4LJCaI=,iv:OQC3FpwTtPmqHvDbA41mWF7LGYwC/jD2ZMBsE8ktNOg=,tag:kq5hUR7TBgczuGcXpsdu2A==,type:str]
+    secret-api-key: ENC[AES256_GCM,data:zV5PTKf45Zab8uW8mbuXmPNzciq6tV9OF0wUND7YnRk/DjZneYWItAsNBVoM+iHA+XsUPDoeKo6hoJiGkH/cCQ8WvuM=,iv:yr1M5DlgI8k6BgzNz3HRnqspHOrQuf2PmoZS1HGp0v8=,tag:JkNNziMMfKFZV2hnx5lXRg==,type:str]
 battery-manager:
     email: ENC[AES256_GCM,data:rYLUACXR/n+bLBmZ,iv:sUBEkh2+7qGjHZ5R23e/hoCiyTA7GTL4bJvXmxjZ5Sw=,tag:fdPMllaQQfRgX0WZKIre4g==,type:str]
     password: ENC[AES256_GCM,data:7cokZa6Q6ahSeiFPz+cV,iv:vz405P0IcG9FsAQXlY7mi78GuushQUKJm2irG6buGzc=,tag:JLHG2jTkJDGbinAq9dXRsQ==,type:str]
@@ -32,8 +34,8 @@ sops:
     azure_kv: []
     hc_vault: []
     age: []
-    lastmodified: "2024-04-15T23:13:18Z"
-    mac: ENC[AES256_GCM,data:3/v+WgSWJ+VcBSBe1Wkis3z+tMmSjbKzLFqBB8xugc6DvgQG8J+1HRrPucLnpNNtEdmpyoTa72U6fPm6JnyUsuj5pLEghLprOJkqQNdRI06fllhw+9d3e3twx6D4oIIsVH6/io4ElXrGsGQTsfNbYhgn+987wa3WP5N25fBac3U=,iv:FL3tzPutOMN6IPkQfXIu/JOZT+OzUSqpMSQrUeXZQHE=,tag:jL1BTsYTA9XjrsjFszxZhA==,type:str]
+    lastmodified: "2025-02-01T10:16:20Z"
+    mac: ENC[AES256_GCM,data:oFJNljU0RJdgsdK7qRXKCqRs7kPXgHqSyYcexEs8kXFnn68mKHNKKfl7skepCPKk0U7h6JqJQ+EOnAA0eo6mraBAMKLSXUcucTzqsfcI+V04rYcP2nGPMUiNDGdKHCcb6OmBhfvKw7+elnonPxKsBlyK31AqB9RFDKaTKXpcNMw=,iv:Q9t7ZkUrevHm5I4JBW95TfvZ88dl2Fq3Yq/E642dV6s=,tag:p2XWfii168qq29wX/RCJuQ==,type:str]
     pgp:
         - created_at: "2025-01-21T17:55:44Z"
           enc: |-
@@ -91,4 +93,4 @@ sops:
             -----END PGP MESSAGE-----
           fp: 0af7641adb8aa843136cf6d047f71da3e5ad79f9
     unencrypted_suffix: _unencrypted
-    version: 3.8.1
+    version: 3.9.2
diff --git a/keys/staging.yaml b/keys/staging.yaml
index 091424d..67e47ad 100644
--- a/keys/staging.yaml
+++ b/keys/staging.yaml
@@ -1,4 +1,6 @@
-hetzner-api: ENC[AES256_GCM,data:1Zjp003j60g=,iv:+vDcyiqYm4A9CMIrW4oGZKdZiczatBcvfL4qYYhKwCg=,tag:Xeu8JuRm+b+5RO+wFR2M8w==,type:str]
+porkbun:
+    api-key: ENC[AES256_GCM,data:A5J1sqwq6hs=,iv:77Mar3IX7mq7z7x6s9sSeGNVYc1Wv78HptJElEC7z3Q=,tag:eM/EF9TxKu+zcbJ1SYXiuA==,type:str]
+    secret-api-key: ENC[AES256_GCM,data:8Xv+jWYaWMI=,iv:li4tdY0pch5lksftMmfMVS729caAwfaacoztaQ49az0=,tag:KhfElBGzVH4ByFPfuQsdhw==,type:str]
 battery-manager:
     email: ENC[AES256_GCM,data:LM/EGzWHfVQ=,iv:jFaoUQuUfuGoOyj/GFpdI8TerH/c8D9fjvio+IEt2Tc=,tag:IWLiN011JEnHRLIXWQgfmA==,type:str]
     password: ENC[AES256_GCM,data:SUxjqS7SJHM=,iv:LvdKk88S+nSImh6/ZezbFGLCUBu1Lpdu+neF2xyHdBg=,tag:rcMyZuW4FVNbcbz00wQKBg==,type:str]
@@ -32,8 +34,8 @@ sops:
     azure_kv: []
     hc_vault: []
     age: []
-    lastmodified: "2024-04-15T23:13:27Z"
-    mac: ENC[AES256_GCM,data:JhEVrKF2Jsqpdztcr3g5lMrgEFeLXfBRQTwQJ6PmLSNyDORcTU09TJPNWTPDnR5okDrvIU/wlzi5DZ8A0ebNhrKf6l0tNFBT9LSvQFHU5SBxqY/m8uEJKSrEC4IL5lugOOISDka2KSvYXVCXrumMHE5FnmOS/CgOZaZk6LUjPYA=,iv:ygygnSedcTo2Vsc56s2qrz1qkWchvSgvoiMTebRxQQ8=,tag:vf6z8rxsXmqzwpDy9Avifw==,type:str]
+    lastmodified: "2025-02-01T10:16:31Z"
+    mac: ENC[AES256_GCM,data:N4RQHOyWvSXW16fepQvRznNbmGerct03kptyiY3IoTpYaJ+43cyFjW15ZqfpaRFyV66QIeqmceqV8c4eP8YSndj6e55e04w0RCyqREXQlFPR6Eh5elaBenokoJhjF6BCsq+xX1C+LUEcxiR/dgy5cwA3mAD/dLCm+G11a06EG6k=,iv:wt5fEOVP6CXHCzmMH9hNCQDDgPa66bLMOa39Eipux9Y=,tag:kWZPnWD1stANVAmWmvOjCg==,type:str]
     pgp:
         - created_at: "2025-01-21T17:55:30Z"
           enc: |-
@@ -71,4 +73,4 @@ sops:
             -----END PGP MESSAGE-----
           fp: 2f5caa73e7ceea4fcc8d2881fde587e6737d2dbc
     unencrypted_suffix: _unencrypted
-    version: 3.8.1
+    version: 3.9.2

From e1989a6009f0b5e7a8e7433498e55fe286aba94d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 8 Feb 2025 05:29:35 +0800
Subject: [PATCH 38/67] fix(crowdsec): Filter out events against matrix

---
 configuration/services/crowdsec.nix | 39 ++++++++++++++++++++++++++++-
 1 file changed, 38 insertions(+), 1 deletion(-)

diff --git a/configuration/services/crowdsec.nix b/configuration/services/crowdsec.nix
index 4891cad..f6f3c80 100644
--- a/configuration/services/crowdsec.nix
+++ b/configuration/services/crowdsec.nix
@@ -1,4 +1,9 @@
-{ config, lib, ... }:
+{
+  pkgs,
+  config,
+  lib,
+  ...
+}:
 {
   security.crowdsec = {
     enable = true;
@@ -50,4 +55,36 @@
       };
     };
   };
+
+  # Add whitelists for matrix
+  systemd.tmpfiles.settings."10-matrix" =
+    let
+      stateDir = config.security.crowdsec.stateDirectory;
+    in
+    {
+      "${stateDir}/config/postoverflows".d = {
+        user = "crowdsec";
+        group = "crowdsec";
+        mode = "0700";
+      };
+
+      "${stateDir}/config/postoverflows/s01-whitelist".d = {
+        user = "crowdsec";
+        group = "crowdsec";
+        mode = "0700";
+      };
+
+      "${stateDir}/config/postoverflows/s01-whitelist/matrix-whitelist.yaml"."L+".argument =
+        ((pkgs.formats.yaml { }).generate "crowdsec-matrix-whitelist.yaml" {
+          name = "tetsumaki/matrix";
+          description = "custom matrix whitelist";
+          whitelist = {
+            reason = "whitelist false positive for matrix";
+            expression = [
+              "evt.Overflow.Alert.Events[0].GetMeta('target_fqdn') == '${config.services.matrix-conduit.settings.global.server_name}'"
+              "evt.Overflow.Alert.GetScenario() in ['crowdsecurity/http-probing', 'crowdsecurity/http-crawl-non_statics']"
+            ];
+          };
+        }).outPath;
+    };
 }

From e11b6f810bd504af9783174bb9f8cebbd7f995c4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 7 Feb 2025 01:39:57 +0800
Subject: [PATCH 39/67] feat(crowdsec): Switch to whitelisting wireguard IP

My IP address is not static, and grafana seems to comfortably produce
enough traffic to get me IP banned.
---
 configuration/services/crowdsec.nix | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/configuration/services/crowdsec.nix b/configuration/services/crowdsec.nix
index f6f3c80..6e0f367 100644
--- a/configuration/services/crowdsec.nix
+++ b/configuration/services/crowdsec.nix
@@ -9,7 +9,7 @@
     enable = true;
 
     parserWhitelist = [
-      "1.64.239.213"
+      "10.45.249.2"
     ];
 
     extraGroups = [

From c939b935bfe4f4d201bc4e5b8fe4edb192f120f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 8 Feb 2025 05:47:44 +0800
Subject: [PATCH 40/67] feat(conduit): Refactor matrix appservices and add
 matrix-hookshot

---
 configuration/default.nix                     |   2 +-
 .../{conduit.nix => conduit/default.nix}      |  91 +----------
 .../services/conduit/heisenbridge.nix         |  78 ++++++++++
 configuration/services/conduit/lib.nix        |  67 ++++++++
 .../services/conduit/matrix-hookshot.nix      | 144 ++++++++++++++++++
 .../services/metrics/victoriametrics.nix      |   4 +
 configuration/sops.nix                        |   4 +
 keys/production.yaml                          |   7 +-
 keys/staging.yaml                             |   7 +-
 9 files changed, 313 insertions(+), 91 deletions(-)
 rename configuration/services/{conduit.nix => conduit/default.nix} (62%)
 create mode 100644 configuration/services/conduit/heisenbridge.nix
 create mode 100644 configuration/services/conduit/lib.nix
 create mode 100644 configuration/services/conduit/matrix-hookshot.nix

diff --git a/configuration/default.nix b/configuration/default.nix
index c9c71ec..239f9f6 100644
--- a/configuration/default.nix
+++ b/configuration/default.nix
@@ -17,7 +17,7 @@
 
     ./services/backups.nix
     ./services/battery-manager.nix
-    ./services/conduit.nix
+    ./services/conduit
     ./services/crowdsec.nix
     ./services/foundryvtt.nix
     ./services/gitea.nix
diff --git a/configuration/services/conduit.nix b/configuration/services/conduit/default.nix
similarity index 62%
rename from configuration/services/conduit.nix
rename to configuration/services/conduit/default.nix
index 4e53241..c3803f4 100644
--- a/configuration/services/conduit.nix
+++ b/configuration/services/conduit/default.nix
@@ -1,5 +1,4 @@
 {
-  pkgs,
   config,
   lib,
   ...
@@ -12,6 +11,11 @@ let
   turn-realm = "turn.${config.services.nginx.domain}";
 in
 {
+  imports = [
+    ./heisenbridge.nix
+    ./matrix-hookshot.nix
+  ];
+
   services.matrix-conduit = {
     enable = true;
     settings.global = {
@@ -40,91 +44,6 @@ in
     };
   };
 
-  systemd.services.heisenbridge =
-    let
-      replaceSecretBin = "${pkgs.replace-secret}/bin/replace-secret";
-      registrationFile = builtins.toFile "heisenbridge-registration.yaml" (
-        builtins.toJSON {
-          id = "heisenbridge";
-          url = "http://127.0.0.1:9898";
-          as_token = "@AS_TOKEN@";
-          hs_token = "@HS_TOKEN@";
-          rate_limited = false;
-          sender_localpart = "heisenbridge";
-          namespaces = {
-            users = [
-              {
-                regex = "@irc_.*";
-                exclusive = true;
-              }
-              {
-                regex = "@heisenbridge:.*";
-                exclusive = true;
-              }
-            ];
-            aliases = [ ];
-            rooms = [ ];
-          };
-        }
-      );
-
-      # TODO(tlater): Starting with systemd 253 it will become possible
-      # to do the credential setup as part of ExecStartPre/preStart
-      # instead.
-      #
-      # This will also make it possible to actually set caps on the
-      # heisenbridge process using systemd, so that we can run the
-      # identd process.
-      execScript = pkgs.writeShellScript "heisenbridge" ''
-        cp ${registrationFile} "$RUNTIME_DIRECTORY/heisenbridge-registration.yaml"
-        chmod 600 $RUNTIME_DIRECTORY/heisenbridge-registration.yaml
-        ${replaceSecretBin} '@AS_TOKEN@' "$CREDENTIALS_DIRECTORY/heisenbridge_as-token" "$RUNTIME_DIRECTORY/heisenbridge-registration.yaml"
-        ${replaceSecretBin} '@HS_TOKEN@' "$CREDENTIALS_DIRECTORY/heisenbridge_hs-token" "$RUNTIME_DIRECTORY/heisenbridge-registration.yaml"
-        chmod 400 $RUNTIME_DIRECTORY/heisenbridge-registration.yaml
-
-        ${pkgs.heisenbridge}/bin/heisenbridge \
-            --config $RUNTIME_DIRECTORY/heisenbridge-registration.yaml \
-            --owner @tlater:matrix.tlater.net \
-            'http://localhost:${toString cfg.settings.global.port}'
-      '';
-    in
-    {
-      description = "Matrix<->IRC bridge";
-      wantedBy = [ "multi-user.target" ];
-      after = [ "conduit.service" ];
-
-      serviceConfig = {
-        Type = "simple";
-
-        LoadCredential = "heisenbridge:/run/secrets/heisenbridge";
-
-        ExecStart = execScript;
-
-        DynamicUser = true;
-        RuntimeDirectory = "heisenbridge";
-        RuntimeDirectoryMode = "0700";
-
-        RestrictNamespaces = true;
-        PrivateUsers = true;
-        ProtectHostname = true;
-        ProtectClock = true;
-        ProtectKernelTunables = true;
-        ProtectKernelModules = true;
-        ProtectKernelLogs = true;
-        ProtectControlGroups = true;
-        RestrictAddressFamilies = [ "AF_INET AF_INET6" ];
-        LockPersonality = true;
-        RestrictRealtime = true;
-        ProtectProc = "invisible";
-        ProcSubset = "pid";
-        UMask = 77;
-
-        # For the identd port
-        # CapabilityBoundingSet = ["CAP_NET_BIND_SERVICE"];
-        # AmbientCapabilities = ["CAP_NET_BIND_SERVICE"];
-      };
-    };
-
   # Pass in the TURN secret via EnvironmentFile, not supported by
   # upstream module currently.
   #
diff --git a/configuration/services/conduit/heisenbridge.nix b/configuration/services/conduit/heisenbridge.nix
new file mode 100644
index 0000000..f0f7e49
--- /dev/null
+++ b/configuration/services/conduit/heisenbridge.nix
@@ -0,0 +1,78 @@
+{
+  pkgs,
+  lib,
+  config,
+  ...
+}:
+let
+  conduitCfg = config.services.matrix-conduit;
+  matrixLib = pkgs.callPackage ./lib.nix { };
+in
+{
+  systemd.services.heisenbridge =
+    let
+      registration = matrixLib.writeRegistrationScript {
+        id = "heisenbridge";
+        url = "http://127.0.0.1:9898";
+        sender_localpart = "heisenbridge";
+
+        namespaces = {
+          users = [
+            {
+              regex = "@irc_.*";
+              exclusive = true;
+            }
+            {
+              regex = "@heisenbridge:.*";
+              exclusive = true;
+            }
+          ];
+
+          aliases = [ ];
+          rooms = [ ];
+        };
+      };
+    in
+    {
+      description = "Matrix<->IRC bridge";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "conduit.service" ];
+
+      serviceConfig = {
+        Type = "exec";
+
+        LoadCredential = "heisenbridge:/run/secrets/heisenbridge";
+
+        inherit (registration) ExecStartPre;
+        ExecStart = lib.concatStringsSep " " [
+          "${lib.getExe pkgs.heisenbridge}"
+          "--config \${RUNTIME_DIRECTORY}/heisenbridge-registration.yaml"
+          "--owner @tlater:matrix.tlater.net"
+          "http://localhost:${toString conduitCfg.settings.global.port}"
+        ];
+
+        DynamicUser = true;
+        RuntimeDirectory = "heisenbridge";
+        RuntimeDirectoryMode = "0700";
+
+        RestrictNamespaces = true;
+        PrivateUsers = true;
+        ProtectHostname = true;
+        ProtectClock = true;
+        ProtectKernelTunables = true;
+        ProtectKernelModules = true;
+        ProtectKernelLogs = true;
+        ProtectControlGroups = true;
+        RestrictAddressFamilies = [ "AF_INET AF_INET6" ];
+        LockPersonality = true;
+        RestrictRealtime = true;
+        ProtectProc = "invisible";
+        ProcSubset = "pid";
+        UMask = 77;
+
+        # For the identd port
+        # CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
+        # AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
+      };
+    };
+}
diff --git a/configuration/services/conduit/lib.nix b/configuration/services/conduit/lib.nix
new file mode 100644
index 0000000..ef407cf
--- /dev/null
+++ b/configuration/services/conduit/lib.nix
@@ -0,0 +1,67 @@
+{
+  lib,
+  writeShellScript,
+  formats,
+  replace-secret,
+}:
+let
+  replaceSecretBin = "${lib.getExe replace-secret}";
+in
+{
+  # Write a script that will set up the service's registration.yaml
+  # with secrets from systemd credentials.
+  #
+  # The credentials should be named `${id}_as-token` and
+  # `${id}_hs-token`.
+  #
+  # This registration file needs to be manually added to conduit by
+  # messaging the admin with the yaml file.
+  #
+  # TODO(tlater): Conduwuit seems to support a CLI interface for this,
+  # may want to migrate to that sometime.
+  writeRegistrationScript =
+    {
+      id, # Must be unique among all registered appservices/bots
+      url, # The URL on which the service listens
+      sender_localpart,
+      rate_limited ? false,
+      namespaces ? {
+        aliases = [ ];
+        rooms = [ ];
+        users = [ ];
+      },
+      extraSettings ? { },
+      # The location to place the file; assumes systemd runtime dir
+      runtimeRegistration ? "$RUNTIME_DIRECTORY/${id}-registration.yaml",
+    }:
+    let
+      registrationFile = (formats.yaml { }).generate "${id}-registration.yaml" (
+        {
+          inherit
+            id
+            url
+            sender_localpart
+            rate_limited
+            namespaces
+            ;
+
+          as_token = "@AS_TOKEN@";
+          hs_token = "@HS_TOKEN@";
+        }
+        // extraSettings
+      );
+    in
+    {
+      inherit runtimeRegistration;
+      ExecStartPre = writeShellScript "${id}-registration-setup.sh" ''
+        cp -f ${registrationFile} "${runtimeRegistration}"
+        chmod 600 "${runtimeRegistration}"
+
+        # Write actual secrets into config
+        ${replaceSecretBin} '@AS_TOKEN@' "$CREDENTIALS_DIRECTORY/${id}_as-token" "${runtimeRegistration}"
+        ${replaceSecretBin} '@HS_TOKEN@' "$CREDENTIALS_DIRECTORY/${id}_hs-token" "${runtimeRegistration}"
+
+        chmod 400 "${runtimeRegistration}"
+      '';
+    };
+}
diff --git a/configuration/services/conduit/matrix-hookshot.nix b/configuration/services/conduit/matrix-hookshot.nix
new file mode 100644
index 0000000..6f11728
--- /dev/null
+++ b/configuration/services/conduit/matrix-hookshot.nix
@@ -0,0 +1,144 @@
+{
+  pkgs,
+  lib,
+  config,
+  ...
+}:
+let
+  matrixLib = pkgs.callPackage ./lib.nix { };
+
+  cfg = config.services.matrix-hookshot;
+  conduitCfg = config.services.matrix-conduit;
+
+  domain = conduitCfg.settings.global.server_name;
+
+  registration = matrixLib.writeRegistrationScript {
+    id = "matrix-hookshot";
+    url = "http://127.0.0.1:9993";
+    sender_localpart = "hookshot";
+
+    namespaces = {
+      aliases = [ ];
+      rooms = [ ];
+      users = [
+        {
+          regex = "@${cfg.settings.generic.userIdPrefix}.*:${domain}";
+          exclusive = true;
+        }
+      ];
+    };
+
+    # Encryption support
+    extraSettings = {
+      "de.sorunome.msc2409.push_ephemeral" = true;
+      push_ephemeral = true;
+      "org.matrix.msc3202" = true;
+    };
+
+    runtimeRegistration = "${cfg.registrationFile}";
+  };
+in
+{
+  systemd.services.matrix-hookshot = {
+    serviceConfig = {
+      Type = lib.mkForce "exec";
+
+      LoadCredential = "matrix-hookshot:/run/secrets/matrix-hookshot";
+      inherit (registration) ExecStartPre;
+
+      # Some library in matrix-hookshot wants a home directory
+      Environment = [ "HOME=/run/matrix-hookshot" ];
+
+      DynamicUser = true;
+      StateDirectory = "matrix-hookshot";
+      RuntimeDirectory = "matrix-hookshot";
+      RuntimeDirectoryMode = "0700";
+
+      RestrictNamespaces = true;
+      PrivateUsers = true;
+      ProtectHostname = true;
+      ProtectClock = true;
+      ProtectKernelTunables = true;
+      ProtectKernelModules = true;
+      ProtectKernelLogs = true;
+      ProtectControlGroups = true;
+      RestrictAddressFamilies = [ "AF_INET AF_INET6" ];
+      LockPersonality = true;
+      RestrictRealtime = true;
+      ProtectProc = "invisible";
+      ProcSubset = "pid";
+      UMask = 77;
+    };
+  };
+
+  services.matrix-hookshot = {
+    enable = true;
+
+    serviceDependencies = [
+      "conduit.service"
+    ];
+
+    registrationFile = "/run/matrix-hookshot/registration.yaml";
+
+    settings = {
+      bridge = {
+        inherit domain;
+        url = "http://localhost:${toString conduitCfg.settings.global.port}";
+        mediaUrl = conduitCfg.settings.global.well_known.client;
+        port = 9993;
+        bindAddress = "127.0.0.1";
+      };
+
+      bot.displayname = "Hookshot";
+
+      generic = {
+        enabled = true;
+        outbound = false;
+        # Only allow webhooks from localhost for the moment
+        urlPrefix = "http://127.0.0.1:9000/webhook";
+        userIdPrefix = "_webhooks_";
+        allowJsTransformationFunctions = true;
+      };
+
+      encryption.storagePath = "/var/lib/matrix-hookshot/cryptostore";
+
+      permissions = [
+        {
+          actor = "matrix.tlater.net";
+          services = [
+            {
+              service = "*";
+              level = "notifications";
+            }
+          ];
+        }
+        {
+          actor = "@tlater:matrix.tlater.net";
+          services = [
+            {
+              service = "*";
+              level = "admin";
+            }
+          ];
+        }
+      ];
+
+      listeners = [
+        {
+          port = 9000;
+          resources = [
+            "webhooks"
+          ];
+        }
+        {
+          port = 9001;
+          resources = [
+            "metrics"
+          ];
+        }
+      ];
+
+      metrics.enable = true;
+    };
+  };
+}
diff --git a/configuration/services/metrics/victoriametrics.nix b/configuration/services/metrics/victoriametrics.nix
index 5cfc614..d72215e 100644
--- a/configuration/services/metrics/victoriametrics.nix
+++ b/configuration/services/metrics/victoriametrics.nix
@@ -26,6 +26,10 @@
             config.security.crowdsec.remediationComponents.firewallBouncer.settings.prometheus.listen_port;
         in
         [ "${address}:${toString port}" ];
+
+      # Configured in the hookshot listeners, but it's hard to filter
+      # the correct values out of that config.
+      matrixHookshot.targets = [ "127.0.0.1:9001" ];
     };
   };
 }
diff --git a/configuration/sops.nix b/configuration/sops.nix
index bbfb888..4800e6b 100644
--- a/configuration/sops.nix
+++ b/configuration/sops.nix
@@ -34,6 +34,10 @@
       "heisenbridge/as-token" = { };
       "heisenbridge/hs-token" = { };
 
+      # Matrix-hookshot
+      "matrix-hookshot/as-token" = { };
+      "matrix-hookshot/hs-token" = { };
+
       # Nextcloud
       "nextcloud/tlater" = {
         owner = "nextcloud";
diff --git a/keys/production.yaml b/keys/production.yaml
index 19df9bd..0e906bd 100644
--- a/keys/production.yaml
+++ b/keys/production.yaml
@@ -16,6 +16,9 @@ steam:
 heisenbridge:
     as-token: ENC[AES256_GCM,data:+2yo6T18j34622H8ZWblAFB2phLw1q0k0vUQEZ5sFj7dQaRnkEiAMi0R3p17Zq0pOtGEC0RRZuPLYkcZ1oKP0w==,iv:lGwrQYp//FufpmJocrLIVyy9RK7lEEVcpAi0wmkjr34=,tag:yV06UbhAYJQz36O2XdhY+A==,type:str]
     hs-token: ENC[AES256_GCM,data:u52WpkQFd/J7JFoE/rfNluebyZQLOokvkVdL7+AEAvrhJhrkJli1ztkD79lbC+6tGUH4tT3T+nX9wvGKnrRUQg==,iv:as+9fVuvMg2IoE2WIKD9mHi+znhNcWRh5Zq+yr0xcDQ=,tag:mZ7fh7U0MfgI8hyq/28Bcg==,type:str]
+matrix-hookshot:
+    as-token: ENC[AES256_GCM,data:nXTanPhDyDF7R3AllLqpM5dzljBrHwlh1KJnTGIi5PhbDY2lPj4+uXkMEwvm1u+hQjPyM7vKZPfK+0/dms6Y7A==,iv:fSakJN+yai0gfOJKFxxaxgyUtk0pNmIeqVgrdq92/24=,tag:Qc7+SUnm5/Nq5+QIScR9kQ==,type:str]
+    hs-token: ENC[AES256_GCM,data:Bwyj0JTTN0NNnwOs1zA8CqbtZSNcvlINeT7QVc2eJiHda92J6vQk7bSxy6KuqCN9DxlUsK13ggYjNORY2vic5w==,iv:Npnp8arYQ3Yb6CXrnKgE03hD7ZjGINPa/DwFI8D+5tA=,tag:FqNE6yI0nF4puEUw9MGAjQ==,type:str]
 wireguard:
     server-key: ENC[AES256_GCM,data:mXb7ZznJHf5CgV8rI4uzPBATMRbmd7LimgtCkQM9kAjbIaGwUBqJZBN3fXs=,iv:3Po1Orinzov9rnEm9cLzgJY1PeD+5Jl9115MriABHh8=,tag:E/2CjDO1JCvJzxCnqKcNyw==,type:str]
 restic:
@@ -34,8 +37,8 @@ sops:
     azure_kv: []
     hc_vault: []
     age: []
-    lastmodified: "2025-02-01T10:16:20Z"
-    mac: ENC[AES256_GCM,data:oFJNljU0RJdgsdK7qRXKCqRs7kPXgHqSyYcexEs8kXFnn68mKHNKKfl7skepCPKk0U7h6JqJQ+EOnAA0eo6mraBAMKLSXUcucTzqsfcI+V04rYcP2nGPMUiNDGdKHCcb6OmBhfvKw7+elnonPxKsBlyK31AqB9RFDKaTKXpcNMw=,iv:Q9t7ZkUrevHm5I4JBW95TfvZ88dl2Fq3Yq/E642dV6s=,tag:p2XWfii168qq29wX/RCJuQ==,type:str]
+    lastmodified: "2025-02-07T19:44:49Z"
+    mac: ENC[AES256_GCM,data:+0hpd/E7GxK/27f2Itf0hDV+3Ga4gHb8xxLutJ32HLBWLZ5Y+dN03xgkz8jBTiM+BeHwS4gz70Cs9X3zLMHbosWVuIV9DLuRaHRq/IU9KiADwqmCySZALqCf3+T5QKZr3Qs4AZJHwaAXkRX9HbnRFriIAFDJW/BGdIHdoROquxY=,iv:TeXI8LGqHVa5wo61sGdNbZ2nJvSlPdgn9R3Lq5qUggU=,tag:TFort5wxVTdi9LMlMeT/DQ==,type:str]
     pgp:
         - created_at: "2025-01-21T17:55:44Z"
           enc: |-
diff --git a/keys/staging.yaml b/keys/staging.yaml
index 67e47ad..876d60e 100644
--- a/keys/staging.yaml
+++ b/keys/staging.yaml
@@ -16,6 +16,9 @@ steam:
 heisenbridge:
     as-token: ENC[AES256_GCM,data:tXbOeo7nv8I=,iv:wJAKcOXX9nGIw4n38ThOoj29u7dUWhsxSQG/p79JlEw=,tag:rTVaGS2UuWcea1uBa8YX2g==,type:str]
     hs-token: ENC[AES256_GCM,data:VBwvwomv0Xg=,iv:q6INtJ+rg+QiXj8uBdBzQYQZUBBXp+9odxDHwvu8Jxc=,tag:XKhm8nxygAkKaiVPJ2Fcdg==,type:str]
+matrix-hookshot:
+    as-token: ENC[AES256_GCM,data:uSUOo4f2KqA=,iv:Xb9G8Ecv6m59m51kDw2bOfq3SMJt4g9/6/EdH74R+KM=,tag:K9MSfO2c2Y4rlf0eYrmTnw==,type:str]
+    hs-token: ENC[AES256_GCM,data:0KsyA06InL4=,iv:zAR0Y1fk8SyodcSLBHlQ8I+BAmttz9Hkd8Q3OREFqs4=,tag:t1Et8N/3seq95DeGoUd7Sw==,type:str]
 wireguard:
     server-key: ENC[AES256_GCM,data:FvY897XdKoa/mckE8JQLCkklsnYD6Wz1wpsu5t3uhEnW3iarnDQxF9msuYU=,iv:jqGXfekM+Vs+J9b5nlZ5Skd1ZKHajoUo2Dc4tMYPm1w=,tag:EehikjI/FCU8wqtpvJRamQ==,type:str]
 restic:
@@ -34,8 +37,8 @@ sops:
     azure_kv: []
     hc_vault: []
     age: []
-    lastmodified: "2025-02-01T10:16:31Z"
-    mac: ENC[AES256_GCM,data:N4RQHOyWvSXW16fepQvRznNbmGerct03kptyiY3IoTpYaJ+43cyFjW15ZqfpaRFyV66QIeqmceqV8c4eP8YSndj6e55e04w0RCyqREXQlFPR6Eh5elaBenokoJhjF6BCsq+xX1C+LUEcxiR/dgy5cwA3mAD/dLCm+G11a06EG6k=,iv:wt5fEOVP6CXHCzmMH9hNCQDDgPa66bLMOa39Eipux9Y=,tag:kWZPnWD1stANVAmWmvOjCg==,type:str]
+    lastmodified: "2025-02-07T17:43:24Z"
+    mac: ENC[AES256_GCM,data:akmD/bfgeTyFzW1quvM16cdj0fC6+CbJ8WyX9173H11yKGxvE1USQYcErpl1SHOx9Jk8LVb7f+MsUm2fjQF1MEq6xaWI74jem12lZ9CGXFaTL7e87JvfbK7pV+aKpxSBBNFyJgbYm30ibdUwxwKmNVfPb1e0HT9qwenvoV7RobM=,iv:mKqOW0ULXL711uczUbRf9NPo6uPTQoS/IbR46S+JID4=,tag:vE6NYzYLbQHDImov1XGTcg==,type:str]
     pgp:
         - created_at: "2025-01-21T17:55:30Z"
           enc: |-

From 92f5040cbc66e77386572412aed2e821cec0e079 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Mon, 10 Feb 2025 03:04:44 +0800
Subject: [PATCH 41/67] fix(grafana): Fix root URL

---
 configuration/services/metrics/grafana.nix | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/configuration/services/metrics/grafana.nix b/configuration/services/metrics/grafana.nix
index 5c779f2..e597cff 100644
--- a/configuration/services/metrics/grafana.nix
+++ b/configuration/services/metrics/grafana.nix
@@ -6,7 +6,10 @@ in
   services.grafana = {
     enable = true;
     settings = {
-      server.http_port = 3001; # Default overlaps with gitea
+      server = {
+        http_port = 3001; # Default overlaps with gitea
+        root_url = "https://metrics.tlater.net";
+      };
 
       security = {
         admin_user = "tlater";

From 07b5064a85dd3766cbc43866afc31f3462ef748e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Tue, 11 Feb 2025 02:56:43 +0800
Subject: [PATCH 42/67] feat(metrics): Add blackbox exporter

---
 configuration/services/metrics/exporters.nix  | 15 +++++++-
 configuration/services/metrics/options.nix    |  3 +-
 .../services/metrics/victoriametrics.nix      | 35 ++++++++++++++++++-
 3 files changed, 50 insertions(+), 3 deletions(-)

diff --git a/configuration/services/metrics/exporters.nix b/configuration/services/metrics/exporters.nix
index ecd69bd..a47a701 100644
--- a/configuration/services/metrics/exporters.nix
+++ b/configuration/services/metrics/exporters.nix
@@ -10,6 +10,20 @@ in
 {
   services.prometheus = {
     exporters = {
+      blackbox = {
+        enable = true;
+        listenAddress = "127.0.0.1";
+        configFile = yaml.generate "blackbox.yaml" {
+          modules = {
+            http_2xx = {
+              prober = "http";
+              timeout = "5s";
+              http.preferred_ip_protocol = "ip4";
+            };
+          };
+        };
+      };
+
       # Periodically check domain registration status
       domain = {
         enable = true;
@@ -71,7 +85,6 @@ in
     # TODO(tlater):
     #   - wireguard (?)
     #   - postgres (?)
-    #   - blackbox (?) (curl to see if http and similar is up)
     #   - ssl_exporter (?)
   };
 }
diff --git a/configuration/services/metrics/options.nix b/configuration/services/metrics/options.nix
index 8868c6c..d69ecfb 100644
--- a/configuration/services/metrics/options.nix
+++ b/configuration/services/metrics/options.nix
@@ -47,7 +47,7 @@ in
               };
 
               extraSettings = mkOption {
-                type = types.anything;
+                inherit (pkgs.formats.yaml { }) type;
                 description = ''
                   Other settings to set for this scrape config.
                 '';
@@ -217,6 +217,7 @@ in
             name: exporter:
             # A bunch of deprecated exporters that need to be ignored
             !(builtins.elem name [
+              "blackbox"
               "minio"
               "tor"
               "unifi-poller"
diff --git a/configuration/services/metrics/victoriametrics.nix b/configuration/services/metrics/victoriametrics.nix
index d72215e..eca65d0 100644
--- a/configuration/services/metrics/victoriametrics.nix
+++ b/configuration/services/metrics/victoriametrics.nix
@@ -1,4 +1,8 @@
-{ config, ... }:
+{ config, lib, ... }:
+let
+  blackbox_host = config.services.prometheus.exporters.blackbox.listenAddress;
+  blackbox_port = config.services.prometheus.exporters.blackbox.port;
+in
 {
   config.services.victoriametrics = {
     enable = true;
@@ -9,6 +13,35 @@
         targets = [ "127.0.0.1:${toString config.services.forgejo.settings.server.HTTP_PORT}" ];
         extraSettings.authorization.credentials_file = config.sops.secrets."forgejo/metrics-token".path;
       };
+
+      blackbox = {
+        static_configs = lib.singleton {
+          targets = lib.mapAttrsToList (vHost: _: "https://${vHost}") config.services.nginx.virtualHosts;
+        };
+
+        extraSettings = {
+          metrics_path = "/probe";
+          params.module = [ "http_2xx" ];
+
+          relabel_configs = [
+            {
+              source_labels = [ "__address__" ];
+              target_label = "__param_target";
+            }
+            {
+              source_labels = [ "__param_target" ];
+              target_label = "instance";
+            }
+            {
+              target_label = "__address__";
+              replacement = "${blackbox_host}:${toString blackbox_port}";
+            }
+          ];
+        };
+      };
+
+      blackbox_exporter.targets = [ "${blackbox_host}:${toString blackbox_port}" ];
+
       coturn.targets = [ "127.0.0.1:9641" ];
 
       crowdsec.targets =

From 5be7d3f10ed59e4bb53c8d65af6174fdab35d1ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 8 Feb 2025 01:59:36 +0800
Subject: [PATCH 43/67] fix(vm): Make sops not break if running without battery
 manager

---
 configuration/sops.nix | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/configuration/sops.nix b/configuration/sops.nix
index 4800e6b..3a1c3d8 100644
--- a/configuration/sops.nix
+++ b/configuration/sops.nix
@@ -1,14 +1,15 @@
+{ config, lib, ... }:
 {
   sops = {
     defaultSopsFile = ../keys/production.yaml;
 
     secrets = {
-      "battery-manager/email" = {
+      "battery-manager/email" = lib.mkIf config.services.batteryManager.enable {
         owner = "battery-manager";
         group = "battery-manager";
       };
 
-      "battery-manager/password" = {
+      "battery-manager/password" = lib.mkIf config.services.batteryManager.enable {
         owner = "battery-manager";
         group = "battery-manager";
       };

From b93ea1aaca49c9aaf170bb13892b0ec9fbc3b84b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 7 Feb 2025 02:47:16 +0800
Subject: [PATCH 44/67] bump(flake.lock): Update sonnenshift input

---
 flake.lock | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/flake.lock b/flake.lock
index d86b361..7f117e9 100644
--- a/flake.lock
+++ b/flake.lock
@@ -266,11 +266,11 @@
         "treefmt-nix": "treefmt-nix"
       },
       "locked": {
-        "lastModified": 1731205797,
-        "narHash": "sha256-F7N1mxH1VrkVNHR3JGNMRvp9+98KYO4b832KS8Gl2xI=",
+        "lastModified": 1738741221,
+        "narHash": "sha256-UiTOA89yQV5YNlO1ZAp4IqJUGWOnTyBC83netvt8rQE=",
         "owner": "nix-community",
         "repo": "poetry2nix",
-        "rev": "f554d27c1544d9c56e5f1f8e2b8aff399803674e",
+        "rev": "be1fe795035d3d36359ca9135b26dcc5321b31fb",
         "type": "github"
       },
       "original": {
@@ -381,11 +381,11 @@
         "poetry2nixi": "poetry2nixi"
       },
       "locked": {
-        "lastModified": 1733296058,
-        "narHash": "sha256-2tYgb4TbvoLk+zsRdCPaglP0s9GCG5HOR9Jm9rsSiHU=",
+        "lastModified": 1738867540,
+        "narHash": "sha256-co2Fs1VoWtTzo7IAeRtaNnyofoUWFOv/Aa/+vSorurA=",
         "ref": "refs/heads/main",
-        "rev": "5f01c17df4dbe841bb6ccd85993c0d9b7368af72",
-        "revCount": 13,
+        "rev": "c6eeff42799c9d4073a241056198004d89bf87df",
+        "revCount": 15,
         "type": "git",
         "url": "ssh://git@github.com/sonnenshift/battery-manager"
       },
@@ -454,8 +454,9 @@
         "type": "github"
       },
       "original": {
-        "id": "systems",
-        "type": "indirect"
+        "owner": "nix-systems",
+        "repo": "default",
+        "type": "github"
       }
     },
     "tlaternet-webserver": {

From 3c7b6a7163628216c754bf564cd39e5793c36e61 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sun, 16 Feb 2025 18:35:16 +0800
Subject: [PATCH 45/67] bump: Update inputs

---
 flake.lock                            | 41 ++++++++-------------------
 flake.nix                             |  3 --
 modules/crowdsec/default.nix          |  9 ++----
 pkgs/crowdsec/_sources/generated.json |  8 +++---
 pkgs/crowdsec/_sources/generated.nix  |  8 +++---
 5 files changed, 23 insertions(+), 46 deletions(-)

diff --git a/flake.lock b/flake.lock
index 7f117e9..b2487b6 100644
--- a/flake.lock
+++ b/flake.lock
@@ -27,11 +27,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1737038063,
-        "narHash": "sha256-rMEuiK69MDhjz1JgbaeQ9mBDXMJ2/P8vmOYRbFndXsk=",
+        "lastModified": 1739634831,
+        "narHash": "sha256-xFnU+uUl48Icas2wPQ+ZzlL2O3n8f6J2LrzNK9f2nng=",
         "owner": "nix-community",
         "repo": "disko",
-        "rev": "bf0abfde48f469c256f2b0f481c6281ff04a5db2",
+        "rev": "fa5746ecea1772cf59b3f34c5816ab3531478142",
         "type": "github"
       },
       "original": {
@@ -190,29 +190,13 @@
         "type": "github"
       }
     },
-    "nixpkgs-crowdsec": {
-      "locked": {
-        "lastModified": 1738085579,
-        "narHash": "sha256-7mLjMrOiiIi0vI7BJwbEipYQzwA7JF/NWHP+LM4q5S8=",
-        "owner": "tlater",
-        "repo": "nixpkgs",
-        "rev": "426a7afc9a6ecfdac544bda4022acef31e36df34",
-        "type": "github"
-      },
-      "original": {
-        "owner": "tlater",
-        "ref": "tlater/fix-crowdsec",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
     "nixpkgs-unstable": {
       "locked": {
-        "lastModified": 1737192615,
-        "narHash": "sha256-jtucJjcdryEZQw1g0RThPSPxCdWNHF42sLp8pmMMGDs=",
+        "lastModified": 1739611738,
+        "narHash": "sha256-3bnOIZz8KXtzcaXGuH9Eriv0HiQyr1EIfcye+VHLQZE=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "09c71b16e6efc9e90edae7eb8b63348702ff9a85",
+        "rev": "31ff66eb77d02e9ac34b7256a02edb1c43fb9998",
         "type": "github"
       },
       "original": {
@@ -224,11 +208,11 @@
     },
     "nixpkgs_2": {
       "locked": {
-        "lastModified": 1737171713,
-        "narHash": "sha256-9mWmMXCto7e8U9hM8ZFozElv4dgOMTe308SSc7rEEFs=",
+        "lastModified": 1739578539,
+        "narHash": "sha256-jGiez5BtGGJUB/LXzRa+4AQurMO9acc1B69kBfgQhJc=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "8773174492fc61571b578f34a59953baba46471a",
+        "rev": "30d4471a8a2a13b716530d3aad60b9846ea5ff83",
         "type": "github"
       },
       "original": {
@@ -326,7 +310,6 @@
         "disko": "disko",
         "foundryvtt": "foundryvtt",
         "nixpkgs": "nixpkgs_2",
-        "nixpkgs-crowdsec": "nixpkgs-crowdsec",
         "nixpkgs-unstable": "nixpkgs-unstable",
         "sonnenshift": "sonnenshift",
         "sops-nix": "sops-nix",
@@ -401,11 +384,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1737107480,
-        "narHash": "sha256-GXUE9+FgxoZU8v0p6ilBJ8NH7k8nKmZjp/7dmMrCv3o=",
+        "lastModified": 1739262228,
+        "narHash": "sha256-7JAGezJ0Dn5qIyA2+T4Dt/xQgAbhCglh6lzCekTVMeU=",
         "owner": "Mic92",
         "repo": "sops-nix",
-        "rev": "4c4fb93f18b9072c6fa1986221f9a3d7bf1fe4b6",
+        "rev": "07af005bb7d60c7f118d9d9f5530485da5d1e975",
         "type": "github"
       },
       "original": {
diff --git a/flake.nix b/flake.nix
index 3d04d7c..b31d108 100644
--- a/flake.nix
+++ b/flake.nix
@@ -26,8 +26,6 @@
       url = "git+ssh://git@github.com/sonnenshift/battery-manager";
       inputs.nixpkgs.follows = "nixpkgs";
     };
-
-    nixpkgs-crowdsec.url = "github:tlater/nixpkgs/tlater/fix-crowdsec";
   };
 
   outputs =
@@ -106,7 +104,6 @@
         in
         {
           default = vm.config.system.build.vm;
-          crowdsec = pkgs.callPackage "${inputs.nixpkgs-crowdsec}/pkgs/by-name/cr/crowdsec/package.nix" { };
           crowdsec-hub = localPkgs.crowdsec.hub;
           crowdsec-firewall-bouncer = localPkgs.crowdsec.firewall-bouncer;
         };
diff --git a/modules/crowdsec/default.nix b/modules/crowdsec/default.nix
index 0d0ff1c..c0003a5 100644
--- a/modules/crowdsec/default.nix
+++ b/modules/crowdsec/default.nix
@@ -1,5 +1,4 @@
 {
-  flake-inputs,
   pkgs,
   lib,
   config,
@@ -9,8 +8,6 @@ let
   cfg = config.security.crowdsec;
   settingsFormat = pkgs.formats.yaml { };
 
-  crowdsec = flake-inputs.self.packages.${pkgs.system}.crowdsec;
-
   hub = pkgs.fetchFromGitHub {
     owner = "crowdsecurity";
     repo = "hub";
@@ -19,14 +16,14 @@ let
   };
 
   cscli = pkgs.writeShellScriptBin "cscli" ''
-    export PATH="$PATH:${crowdsec}/bin/"
+    export PATH="$PATH:${cfg.package}/bin/"
 
     sudo=exec
     if [ "$USER" != "crowdsec" ]; then
         sudo='exec /run/wrappers/bin/sudo -u crowdsec'
     fi
 
-    $sudo ${crowdsec}/bin/cscli "$@"
+    $sudo ${cfg.package}/bin/cscli "$@"
   '';
 
   acquisitions = ''
@@ -53,7 +50,7 @@ in
 
       package = lib.mkOption {
         type = package;
-        default = crowdsec;
+        default = pkgs.crowdsec;
       };
 
       stateDirectory = lib.mkOption {
diff --git a/pkgs/crowdsec/_sources/generated.json b/pkgs/crowdsec/_sources/generated.json
index 8485779..634bc18 100644
--- a/pkgs/crowdsec/_sources/generated.json
+++ b/pkgs/crowdsec/_sources/generated.json
@@ -21,7 +21,7 @@
     },
     "crowdsec-hub": {
         "cargoLocks": null,
-        "date": "2025-01-30",
+        "date": "2025-02-16",
         "extract": null,
         "name": "crowdsec-hub",
         "passthru": null,
@@ -33,10 +33,10 @@
             "name": null,
             "owner": "crowdsecurity",
             "repo": "hub",
-            "rev": "8f102f5ac79af59d3024ca2771b65ec87411ac02",
-            "sha256": "sha256-8K1HkBg0++Au1dr2KMrl9b2ruqXdo+vqWngOCwL11Mo=",
+            "rev": "f7d7f476f88a4af05e1cfb3994536990adecfb57",
+            "sha256": "sha256-m78uipryHDKixJzrF4K59ioAJ3WJN1JlXEC0DNVMCJ8=",
             "type": "github"
         },
-        "version": "8f102f5ac79af59d3024ca2771b65ec87411ac02"
+        "version": "f7d7f476f88a4af05e1cfb3994536990adecfb57"
     }
 }
\ No newline at end of file
diff --git a/pkgs/crowdsec/_sources/generated.nix b/pkgs/crowdsec/_sources/generated.nix
index 6f845ec..7ef44e6 100644
--- a/pkgs/crowdsec/_sources/generated.nix
+++ b/pkgs/crowdsec/_sources/generated.nix
@@ -14,14 +14,14 @@
   };
   crowdsec-hub = {
     pname = "crowdsec-hub";
-    version = "8f102f5ac79af59d3024ca2771b65ec87411ac02";
+    version = "f7d7f476f88a4af05e1cfb3994536990adecfb57";
     src = fetchFromGitHub {
       owner = "crowdsecurity";
       repo = "hub";
-      rev = "8f102f5ac79af59d3024ca2771b65ec87411ac02";
+      rev = "f7d7f476f88a4af05e1cfb3994536990adecfb57";
       fetchSubmodules = false;
-      sha256 = "sha256-8K1HkBg0++Au1dr2KMrl9b2ruqXdo+vqWngOCwL11Mo=";
+      sha256 = "sha256-m78uipryHDKixJzrF4K59ioAJ3WJN1JlXEC0DNVMCJ8=";
     };
-    date = "2025-01-30";
+    date = "2025-02-16";
   };
 }

From 586ab969a4bed26a3df9b1861deb4194234af40b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 21 Feb 2025 04:09:35 +0800
Subject: [PATCH 46/67] feat(battery-manager): Switch to rust version

---
 configuration/services/battery-manager.nix |   6 +-
 configuration/sops.nix                     |  11 +-
 flake.lock                                 | 846 +++++++++++++++++++--
 flake.nix                                  |   2 +-
 4 files changed, 799 insertions(+), 66 deletions(-)

diff --git a/configuration/services/battery-manager.nix b/configuration/services/battery-manager.nix
index a16cca1..9da7e32 100644
--- a/configuration/services/battery-manager.nix
+++ b/configuration/services/battery-manager.nix
@@ -4,9 +4,13 @@
 
   services.batteryManager = {
     enable = true;
-    battery = "3ca39300-c523-4315-b9a3-d030f85a9373";
 
     emailFile = "${config.sops.secrets."battery-manager/email".path}";
     passwordFile = "${config.sops.secrets."battery-manager/password".path}";
+
+    settings = {
+      battery_id = "3ca39300-c523-4315-b9a3-d030f85a9373";
+      log_level = "DEBUG";
+    };
   };
 }
diff --git a/configuration/sops.nix b/configuration/sops.nix
index 3a1c3d8..0337438 100644
--- a/configuration/sops.nix
+++ b/configuration/sops.nix
@@ -1,18 +1,11 @@
-{ config, lib, ... }:
 {
   sops = {
     defaultSopsFile = ../keys/production.yaml;
 
     secrets = {
-      "battery-manager/email" = lib.mkIf config.services.batteryManager.enable {
-        owner = "battery-manager";
-        group = "battery-manager";
-      };
+      "battery-manager/email" = { };
 
-      "battery-manager/password" = lib.mkIf config.services.batteryManager.enable {
-        owner = "battery-manager";
-        group = "battery-manager";
-      };
+      "battery-manager/password" = { };
 
       # Gitea
       "forgejo/metrics-token" = {
diff --git a/flake.lock b/flake.lock
index b2487b6..276b8b2 100644
--- a/flake.lock
+++ b/flake.lock
@@ -1,5 +1,206 @@
 {
   "nodes": {
+    "cachix": {
+      "inputs": {
+        "devenv": [
+          "sonnenshift",
+          "crate2nix"
+        ],
+        "flake-compat": [
+          "sonnenshift",
+          "crate2nix"
+        ],
+        "nixpkgs": "nixpkgs_3",
+        "pre-commit-hooks": [
+          "sonnenshift",
+          "crate2nix"
+        ]
+      },
+      "locked": {
+        "lastModified": 1709700175,
+        "narHash": "sha256-A0/6ZjLmT9qdYzKHmevnEIC7G+GiZ4UCr8v0poRPzds=",
+        "owner": "cachix",
+        "repo": "cachix",
+        "rev": "be97b37989f11b724197b5f4c7ffd78f12c8c4bf",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "ref": "latest",
+        "repo": "cachix",
+        "type": "github"
+      }
+    },
+    "cachix_2": {
+      "inputs": {
+        "devenv": [
+          "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable"
+        ],
+        "flake-compat": [
+          "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable"
+        ],
+        "nixpkgs": "nixpkgs_4",
+        "pre-commit-hooks": [
+          "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable"
+        ]
+      },
+      "locked": {
+        "lastModified": 1716549461,
+        "narHash": "sha256-lHy5kgx6J8uD+16SO47dPrbob98sh+W1tf4ceSqPVK4=",
+        "owner": "cachix",
+        "repo": "cachix",
+        "rev": "e2bb269fb8c0828d5d4d2d7b8d09ea85abcacbd4",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "ref": "latest",
+        "repo": "cachix",
+        "type": "github"
+      }
+    },
+    "cachix_3": {
+      "inputs": {
+        "devenv": [
+          "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable",
+          "crate2nix_stable"
+        ],
+        "flake-compat": [
+          "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable",
+          "crate2nix_stable"
+        ],
+        "nixpkgs": "nixpkgs_5",
+        "pre-commit-hooks": [
+          "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable",
+          "crate2nix_stable"
+        ]
+      },
+      "locked": {
+        "lastModified": 1716549461,
+        "narHash": "sha256-lHy5kgx6J8uD+16SO47dPrbob98sh+W1tf4ceSqPVK4=",
+        "owner": "cachix",
+        "repo": "cachix",
+        "rev": "e2bb269fb8c0828d5d4d2d7b8d09ea85abcacbd4",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "ref": "latest",
+        "repo": "cachix",
+        "type": "github"
+      }
+    },
+    "crate2nix": {
+      "inputs": {
+        "cachix": "cachix",
+        "crate2nix_stable": "crate2nix_stable",
+        "devshell": "devshell_3",
+        "flake-compat": "flake-compat_4",
+        "flake-parts": "flake-parts_3",
+        "nix-test-runner": "nix-test-runner_3",
+        "nixpkgs": [
+          "sonnenshift",
+          "nixpkgs"
+        ],
+        "pre-commit-hooks": "pre-commit-hooks_3"
+      },
+      "locked": {
+        "lastModified": 1739473963,
+        "narHash": "sha256-ItAhpjNUzEWd/cgZVyW/jvoGbCec4TK29e1Mnmn1oJE=",
+        "owner": "nix-community",
+        "repo": "crate2nix",
+        "rev": "be31feae9a82c225c0fd1bdf978565dc452a483a",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-community",
+        "repo": "crate2nix",
+        "type": "github"
+      }
+    },
+    "crate2nix_stable": {
+      "inputs": {
+        "cachix": "cachix_2",
+        "crate2nix_stable": "crate2nix_stable_2",
+        "devshell": "devshell_2",
+        "flake-compat": "flake-compat_3",
+        "flake-parts": "flake-parts_2",
+        "nix-test-runner": "nix-test-runner_2",
+        "nixpkgs": "nixpkgs_7",
+        "pre-commit-hooks": "pre-commit-hooks_2"
+      },
+      "locked": {
+        "lastModified": 1719760004,
+        "narHash": "sha256-esWhRnt7FhiYq0CcIxw9pvH+ybOQmWBfHYMtleaMhBE=",
+        "owner": "nix-community",
+        "repo": "crate2nix",
+        "rev": "1dee214bb20855fa3e1e7bb98d28922ddaff8c57",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-community",
+        "ref": "0.14.1",
+        "repo": "crate2nix",
+        "type": "github"
+      }
+    },
+    "crate2nix_stable_2": {
+      "inputs": {
+        "cachix": "cachix_3",
+        "crate2nix_stable": "crate2nix_stable_3",
+        "devshell": "devshell",
+        "flake-compat": "flake-compat_2",
+        "flake-parts": "flake-parts",
+        "nix-test-runner": "nix-test-runner",
+        "nixpkgs": "nixpkgs_6",
+        "pre-commit-hooks": "pre-commit-hooks"
+      },
+      "locked": {
+        "lastModified": 1712821484,
+        "narHash": "sha256-rGT3CW64cJS9nlnWPFWSc1iEa3dNZecVVuPVGzcsHe8=",
+        "owner": "nix-community",
+        "repo": "crate2nix",
+        "rev": "42883afcad3823fa5811e967fb7bff54bc3c9d6d",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-community",
+        "ref": "0.14.0",
+        "repo": "crate2nix",
+        "type": "github"
+      }
+    },
+    "crate2nix_stable_3": {
+      "inputs": {
+        "flake-utils": "flake-utils"
+      },
+      "locked": {
+        "lastModified": 1702842982,
+        "narHash": "sha256-A9AowkHIjsy1a4LuiPiVP88FMxyCWK41flZEZOUuwQM=",
+        "owner": "nix-community",
+        "repo": "crate2nix",
+        "rev": "75ac2973affa6b9b4f661a7b592cba6e4f51d426",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-community",
+        "ref": "0.12.0",
+        "repo": "crate2nix",
+        "type": "github"
+      }
+    },
     "deploy-rs": {
       "inputs": {
         "flake-compat": "flake-compat",
@@ -20,6 +221,78 @@
         "type": "github"
       }
     },
+    "devshell": {
+      "inputs": {
+        "flake-utils": "flake-utils_2",
+        "nixpkgs": [
+          "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable",
+          "crate2nix_stable",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1717408969,
+        "narHash": "sha256-Q0OEFqe35fZbbRPPRdrjTUUChKVhhWXz3T9ZSKmaoVY=",
+        "owner": "numtide",
+        "repo": "devshell",
+        "rev": "1ebbe68d57457c8cae98145410b164b5477761f4",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "devshell",
+        "type": "github"
+      }
+    },
+    "devshell_2": {
+      "inputs": {
+        "flake-utils": "flake-utils_3",
+        "nixpkgs": [
+          "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1717408969,
+        "narHash": "sha256-Q0OEFqe35fZbbRPPRdrjTUUChKVhhWXz3T9ZSKmaoVY=",
+        "owner": "numtide",
+        "repo": "devshell",
+        "rev": "1ebbe68d57457c8cae98145410b164b5477761f4",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "devshell",
+        "type": "github"
+      }
+    },
+    "devshell_3": {
+      "inputs": {
+        "flake-utils": "flake-utils_4",
+        "nixpkgs": [
+          "sonnenshift",
+          "crate2nix",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1711099426,
+        "narHash": "sha256-HzpgM/wc3aqpnHJJ2oDqPBkNsqWbW0WfWUO8lKu8nGk=",
+        "owner": "numtide",
+        "repo": "devshell",
+        "rev": "2d45b54ca4a183f2fdcf4b19c895b64fbf620ee8",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "devshell",
+        "type": "github"
+      }
+    },
     "disko": {
       "inputs": {
         "nixpkgs": [
@@ -42,7 +315,7 @@
     },
     "dream2nix": {
       "inputs": {
-        "nixpkgs": "nixpkgs_3",
+        "nixpkgs": "nixpkgs_8",
         "purescript-overlay": "purescript-overlay",
         "pyproject-nix": "pyproject-nix"
       },
@@ -99,6 +372,48 @@
       }
     },
     "flake-compat_2": {
+      "locked": {
+        "lastModified": 1696426674,
+        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
+        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
+        "revCount": 57,
+        "type": "tarball",
+        "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz"
+      },
+      "original": {
+        "type": "tarball",
+        "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
+      }
+    },
+    "flake-compat_3": {
+      "locked": {
+        "lastModified": 1696426674,
+        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
+        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
+        "revCount": 57,
+        "type": "tarball",
+        "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz"
+      },
+      "original": {
+        "type": "tarball",
+        "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
+      }
+    },
+    "flake-compat_4": {
+      "locked": {
+        "lastModified": 1696426674,
+        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
+        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
+        "revCount": 57,
+        "type": "tarball",
+        "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz"
+      },
+      "original": {
+        "type": "tarball",
+        "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
+      }
+    },
+    "flake-compat_5": {
       "flake": false,
       "locked": {
         "lastModified": 1696426674,
@@ -114,16 +429,157 @@
         "type": "github"
       }
     },
+    "flake-parts": {
+      "inputs": {
+        "nixpkgs-lib": [
+          "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable",
+          "crate2nix_stable",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1719745305,
+        "narHash": "sha256-xwgjVUpqSviudEkpQnioeez1Uo2wzrsMaJKJClh+Bls=",
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "rev": "c3c5ecc05edc7dafba779c6c1a61cd08ac6583e9",
+        "type": "github"
+      },
+      "original": {
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "type": "github"
+      }
+    },
+    "flake-parts_2": {
+      "inputs": {
+        "nixpkgs-lib": [
+          "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1719745305,
+        "narHash": "sha256-xwgjVUpqSviudEkpQnioeez1Uo2wzrsMaJKJClh+Bls=",
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "rev": "c3c5ecc05edc7dafba779c6c1a61cd08ac6583e9",
+        "type": "github"
+      },
+      "original": {
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "type": "github"
+      }
+    },
+    "flake-parts_3": {
+      "inputs": {
+        "nixpkgs-lib": [
+          "sonnenshift",
+          "crate2nix",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1712014858,
+        "narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
+        "type": "github"
+      },
+      "original": {
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "type": "github"
+      }
+    },
     "flake-utils": {
       "inputs": {
         "systems": "systems_2"
       },
       "locked": {
-        "lastModified": 1726560853,
-        "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
+        "lastModified": 1694529238,
+        "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
         "owner": "numtide",
         "repo": "flake-utils",
-        "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
+        "rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "flake-utils_2": {
+      "inputs": {
+        "systems": "systems_3"
+      },
+      "locked": {
+        "lastModified": 1701680307,
+        "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "flake-utils_3": {
+      "inputs": {
+        "systems": "systems_4"
+      },
+      "locked": {
+        "lastModified": 1701680307,
+        "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "flake-utils_4": {
+      "inputs": {
+        "systems": "systems_5"
+      },
+      "locked": {
+        "lastModified": 1701680307,
+        "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "flake-utils_5": {
+      "inputs": {
+        "systems": "systems_6"
+      },
+      "locked": {
+        "lastModified": 1710146030,
+        "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
         "type": "github"
       },
       "original": {
@@ -152,25 +608,123 @@
         "type": "github"
       }
     },
-    "nix-github-actions": {
+    "gitignore": {
       "inputs": {
         "nixpkgs": [
           "sonnenshift",
-          "poetry2nixi",
+          "crate2nix",
+          "crate2nix_stable",
+          "crate2nix_stable",
+          "pre-commit-hooks",
           "nixpkgs"
         ]
       },
       "locked": {
-        "lastModified": 1729742964,
-        "narHash": "sha256-B4mzTcQ0FZHdpeWcpDYPERtyjJd/NIuaQ9+BV1h+MpA=",
-        "owner": "nix-community",
-        "repo": "nix-github-actions",
-        "rev": "e04df33f62cdcf93d73e9a04142464753a16db67",
+        "lastModified": 1709087332,
+        "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
         "type": "github"
       },
       "original": {
-        "owner": "nix-community",
-        "repo": "nix-github-actions",
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "type": "github"
+      }
+    },
+    "gitignore_2": {
+      "inputs": {
+        "nixpkgs": [
+          "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable",
+          "pre-commit-hooks",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1709087332,
+        "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+        "type": "github"
+      },
+      "original": {
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "type": "github"
+      }
+    },
+    "gitignore_3": {
+      "inputs": {
+        "nixpkgs": [
+          "sonnenshift",
+          "crate2nix",
+          "pre-commit-hooks",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1709087332,
+        "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+        "type": "github"
+      },
+      "original": {
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "type": "github"
+      }
+    },
+    "nix-test-runner": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1588761593,
+        "narHash": "sha256-FKJykltAN/g3eIceJl4SfDnnyuH2jHImhMrXS2KvGIs=",
+        "owner": "stoeffel",
+        "repo": "nix-test-runner",
+        "rev": "c45d45b11ecef3eb9d834c3b6304c05c49b06ca2",
+        "type": "github"
+      },
+      "original": {
+        "owner": "stoeffel",
+        "repo": "nix-test-runner",
+        "type": "github"
+      }
+    },
+    "nix-test-runner_2": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1588761593,
+        "narHash": "sha256-FKJykltAN/g3eIceJl4SfDnnyuH2jHImhMrXS2KvGIs=",
+        "owner": "stoeffel",
+        "repo": "nix-test-runner",
+        "rev": "c45d45b11ecef3eb9d834c3b6304c05c49b06ca2",
+        "type": "github"
+      },
+      "original": {
+        "owner": "stoeffel",
+        "repo": "nix-test-runner",
+        "type": "github"
+      }
+    },
+    "nix-test-runner_3": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1588761593,
+        "narHash": "sha256-FKJykltAN/g3eIceJl4SfDnnyuH2jHImhMrXS2KvGIs=",
+        "owner": "stoeffel",
+        "repo": "nix-test-runner",
+        "rev": "c45d45b11ecef3eb9d834c3b6304c05c49b06ca2",
+        "type": "github"
+      },
+      "original": {
+        "owner": "stoeffel",
+        "repo": "nix-test-runner",
         "type": "github"
       }
     },
@@ -223,6 +777,80 @@
       }
     },
     "nixpkgs_3": {
+      "locked": {
+        "lastModified": 1700612854,
+        "narHash": "sha256-yrQ8osMD+vDLGFX7pcwsY/Qr5PUd6OmDMYJZzZi0+zc=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "19cbff58383a4ae384dea4d1d0c823d72b49d614",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs_4": {
+      "locked": {
+        "lastModified": 1715534503,
+        "narHash": "sha256-5ZSVkFadZbFP1THataCaSf0JH2cAH3S29hU9rrxTEqk=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "2057814051972fa1453ddfb0d98badbea9b83c06",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs_5": {
+      "locked": {
+        "lastModified": 1715534503,
+        "narHash": "sha256-5ZSVkFadZbFP1THataCaSf0JH2cAH3S29hU9rrxTEqk=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "2057814051972fa1453ddfb0d98badbea9b83c06",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs_6": {
+      "locked": {
+        "lastModified": 1719506693,
+        "narHash": "sha256-C8e9S7RzshSdHB7L+v9I51af1gDM5unhJ2xO1ywxNH8=",
+        "path": "/nix/store/4p0avw1s3vf27hspgqsrqs37gxk4i83i-source",
+        "rev": "b2852eb9365c6de48ffb0dc2c9562591f652242a",
+        "type": "path"
+      },
+      "original": {
+        "id": "nixpkgs",
+        "type": "indirect"
+      }
+    },
+    "nixpkgs_7": {
+      "locked": {
+        "lastModified": 1719506693,
+        "narHash": "sha256-C8e9S7RzshSdHB7L+v9I51af1gDM5unhJ2xO1ywxNH8=",
+        "path": "/nix/store/4p0avw1s3vf27hspgqsrqs37gxk4i83i-source",
+        "rev": "b2852eb9365c6de48ffb0dc2c9562591f652242a",
+        "type": "path"
+      },
+      "original": {
+        "id": "nixpkgs",
+        "type": "indirect"
+      }
+    },
+    "nixpkgs_8": {
       "locked": {
         "lastModified": 1729850857,
         "narHash": "sha256-WvLXzNNnnw+qpFOmgaM3JUlNEH+T4s22b5i2oyyCpXE=",
@@ -238,34 +866,118 @@
         "type": "github"
       }
     },
-    "poetry2nixi": {
+    "pre-commit-hooks": {
       "inputs": {
-        "flake-utils": "flake-utils",
-        "nix-github-actions": "nix-github-actions",
+        "flake-compat": [
+          "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable",
+          "crate2nix_stable",
+          "flake-compat"
+        ],
+        "gitignore": "gitignore",
         "nixpkgs": [
           "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable",
+          "crate2nix_stable",
           "nixpkgs"
         ],
-        "systems": "systems_3",
-        "treefmt-nix": "treefmt-nix"
+        "nixpkgs-stable": [
+          "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable",
+          "crate2nix_stable",
+          "nixpkgs"
+        ]
       },
       "locked": {
-        "lastModified": 1738741221,
-        "narHash": "sha256-UiTOA89yQV5YNlO1ZAp4IqJUGWOnTyBC83netvt8rQE=",
-        "owner": "nix-community",
-        "repo": "poetry2nix",
-        "rev": "be1fe795035d3d36359ca9135b26dcc5321b31fb",
+        "lastModified": 1719259945,
+        "narHash": "sha256-F1h+XIsGKT9TkGO3omxDLEb/9jOOsI6NnzsXFsZhry4=",
+        "owner": "cachix",
+        "repo": "pre-commit-hooks.nix",
+        "rev": "0ff4381bbb8f7a52ca4a851660fc7a437a4c6e07",
         "type": "github"
       },
       "original": {
-        "owner": "nix-community",
-        "repo": "poetry2nix",
+        "owner": "cachix",
+        "repo": "pre-commit-hooks.nix",
+        "type": "github"
+      }
+    },
+    "pre-commit-hooks_2": {
+      "inputs": {
+        "flake-compat": [
+          "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable",
+          "flake-compat"
+        ],
+        "gitignore": "gitignore_2",
+        "nixpkgs": [
+          "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable",
+          "nixpkgs"
+        ],
+        "nixpkgs-stable": [
+          "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1719259945,
+        "narHash": "sha256-F1h+XIsGKT9TkGO3omxDLEb/9jOOsI6NnzsXFsZhry4=",
+        "owner": "cachix",
+        "repo": "pre-commit-hooks.nix",
+        "rev": "0ff4381bbb8f7a52ca4a851660fc7a437a4c6e07",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "repo": "pre-commit-hooks.nix",
+        "type": "github"
+      }
+    },
+    "pre-commit-hooks_3": {
+      "inputs": {
+        "flake-compat": [
+          "sonnenshift",
+          "crate2nix",
+          "flake-compat"
+        ],
+        "flake-utils": "flake-utils_5",
+        "gitignore": "gitignore_3",
+        "nixpkgs": [
+          "sonnenshift",
+          "crate2nix",
+          "nixpkgs"
+        ],
+        "nixpkgs-stable": [
+          "sonnenshift",
+          "crate2nix",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1712055707,
+        "narHash": "sha256-4XLvuSIDZJGS17xEwSrNuJLL7UjDYKGJSbK1WWX2AK8=",
+        "owner": "cachix",
+        "repo": "pre-commit-hooks.nix",
+        "rev": "e35aed5fda3cc79f88ed7f1795021e559582093a",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "repo": "pre-commit-hooks.nix",
         "type": "github"
       }
     },
     "purescript-overlay": {
       "inputs": {
-        "flake-compat": "flake-compat_2",
+        "flake-compat": "flake-compat_5",
         "nixpkgs": [
           "tlaternet-webserver",
           "dream2nix",
@@ -358,21 +1070,22 @@
     },
     "sonnenshift": {
       "inputs": {
+        "crate2nix": "crate2nix",
         "nixpkgs": [
           "nixpkgs"
-        ],
-        "poetry2nixi": "poetry2nixi"
+        ]
       },
       "locked": {
-        "lastModified": 1738867540,
-        "narHash": "sha256-co2Fs1VoWtTzo7IAeRtaNnyofoUWFOv/Aa/+vSorurA=",
-        "ref": "refs/heads/main",
-        "rev": "c6eeff42799c9d4073a241056198004d89bf87df",
-        "revCount": 15,
+        "lastModified": 1740082109,
+        "narHash": "sha256-WdRNkwsIotFOSymee/yQyH46RmYtuxd1FENhvGL4KRc=",
+        "ref": "tlater/rust-rewrite",
+        "rev": "a1b48cf2ba194054e2d8816c94a84cebc4fb5de0",
+        "revCount": 23,
         "type": "git",
         "url": "ssh://git@github.com/sonnenshift/battery-manager"
       },
       "original": {
+        "ref": "tlater/rust-rewrite",
         "type": "git",
         "url": "ssh://git@github.com/sonnenshift/battery-manager"
       }
@@ -442,6 +1155,51 @@
         "type": "github"
       }
     },
+    "systems_4": {
+      "locked": {
+        "lastModified": 1681028828,
+        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+        "owner": "nix-systems",
+        "repo": "default",
+        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-systems",
+        "repo": "default",
+        "type": "github"
+      }
+    },
+    "systems_5": {
+      "locked": {
+        "lastModified": 1681028828,
+        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+        "owner": "nix-systems",
+        "repo": "default",
+        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-systems",
+        "repo": "default",
+        "type": "github"
+      }
+    },
+    "systems_6": {
+      "locked": {
+        "lastModified": 1681028828,
+        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+        "owner": "nix-systems",
+        "repo": "default",
+        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-systems",
+        "repo": "default",
+        "type": "github"
+      }
+    },
     "tlaternet-webserver": {
       "inputs": {
         "dream2nix": "dream2nix",
@@ -464,28 +1222,6 @@
         "url": "https://gitea.tlater.net/tlaternet/tlaternet.git"
       }
     },
-    "treefmt-nix": {
-      "inputs": {
-        "nixpkgs": [
-          "sonnenshift",
-          "poetry2nixi",
-          "nixpkgs"
-        ]
-      },
-      "locked": {
-        "lastModified": 1730120726,
-        "narHash": "sha256-LqHYIxMrl/1p3/kvm2ir925tZ8DkI0KA10djk8wecSk=",
-        "owner": "numtide",
-        "repo": "treefmt-nix",
-        "rev": "9ef337e492a5555d8e17a51c911ff1f02635be15",
-        "type": "github"
-      },
-      "original": {
-        "owner": "numtide",
-        "repo": "treefmt-nix",
-        "type": "github"
-      }
-    },
     "utils": {
       "inputs": {
         "systems": "systems"
diff --git a/flake.nix b/flake.nix
index b31d108..737a17f 100644
--- a/flake.nix
+++ b/flake.nix
@@ -23,7 +23,7 @@
     };
 
     sonnenshift = {
-      url = "git+ssh://git@github.com/sonnenshift/battery-manager";
+      url = "git+ssh://git@github.com/sonnenshift/battery-manager?ref=tlater/rust-rewrite";
       inputs.nixpkgs.follows = "nixpkgs";
     };
   };

From a60cb7f60cc58e2696f171884f9130d451b3d2c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sun, 16 Feb 2025 18:46:25 +0800
Subject: [PATCH 47/67] chore(coturn): Switch to letsencrypt certificate

Fixes #107
---
 configuration/nginx.nix                       |  8 ++++++-
 configuration/services/conduit/default.nix    | 11 +++++----
 configuration/services/metrics/exporters.nix  | 10 ++++++++
 .../services/metrics/victoriametrics.nix      | 24 +++++++++++++++++++
 4 files changed, 47 insertions(+), 6 deletions(-)

diff --git a/configuration/nginx.nix b/configuration/nginx.nix
index 0b72cc1..3ec3bd9 100644
--- a/configuration/nginx.nix
+++ b/configuration/nginx.nix
@@ -53,7 +53,7 @@
         "*.tlater.com"
       ];
       dnsProvider = "porkbun";
-      group = "nginx";
+      group = "ssl-cert";
       credentialFiles = {
         PORKBUN_API_KEY_FILE = config.sops.secrets."porkbun/api-key".path;
         PORKBUN_SECRET_API_KEY_FILE = config.sops.secrets."porkbun/secret-api-key".path;
@@ -61,6 +61,12 @@
     };
   };
 
+  users.groups.ssl-cert = { };
+
+  systemd.services.nginx.serviceConfig.SupplementaryGroups = [
+    config.security.acme.certs."tlater.net".group
+  ];
+
   services.backups.acme = {
     user = "acme";
     paths = lib.mapAttrsToList (
diff --git a/configuration/services/conduit/default.nix b/configuration/services/conduit/default.nix
index c3803f4..c7e4ab4 100644
--- a/configuration/services/conduit/default.nix
+++ b/configuration/services/conduit/default.nix
@@ -50,6 +50,10 @@ in
   # See also https://gitlab.com/famedly/conduit/-/issues/314
   systemd.services.conduit.serviceConfig.EnvironmentFile = config.sops.secrets."turn/env".path;
 
+  systemd.services.coturn.serviceConfig.SupplementaryGroups = [
+    config.security.acme.certs."tlater.net".group
+  ];
+
   services.coturn = {
     enable = true;
     no-cli = true;
@@ -59,11 +63,8 @@ in
     relay-ips = [ "116.202.158.55" ];
 
     # SSL config
-    #
-    # TODO(tlater): Switch to letsencrypt once google fix:
-    #  https://github.com/vector-im/element-android/issues/1533
-    pkey = config.sops.secrets."turn/ssl-key".path;
-    cert = config.sops.secrets."turn/ssl-cert".path;
+    pkey = "${config.security.acme.certs."tlater.net".directory}/key.pem";
+    cert = "${config.security.acme.certs."tlater.net".directory}/fullchain.pem";
 
     # Based on suggestions from
     # https://github.com/matrix-org/synapse/blob/develop/docs/turn-howto.md
diff --git a/configuration/services/metrics/exporters.nix b/configuration/services/metrics/exporters.nix
index a47a701..78ba684 100644
--- a/configuration/services/metrics/exporters.nix
+++ b/configuration/services/metrics/exporters.nix
@@ -20,6 +20,16 @@ in
               timeout = "5s";
               http.preferred_ip_protocol = "ip4";
             };
+
+            turn_server = {
+              prober = "tcp";
+              timeout = "5s";
+              tcp = {
+                preferred_ip_protocol = "ip4";
+                source_ip_address = "116.202.158.55";
+                tls = true;
+              };
+            };
           };
         };
       };
diff --git a/configuration/services/metrics/victoriametrics.nix b/configuration/services/metrics/victoriametrics.nix
index eca65d0..4a78d46 100644
--- a/configuration/services/metrics/victoriametrics.nix
+++ b/configuration/services/metrics/victoriametrics.nix
@@ -40,6 +40,30 @@ in
         };
       };
 
+      blackbox_turn = {
+        targets = [ "turn.tlater.net:${toString config.services.coturn.tls-listening-port}" ];
+
+        extraSettings = {
+          metrics_path = "/probe";
+          params.module = [ "turn_server" ];
+
+          relabel_configs = [
+            {
+              source_labels = [ "__address__" ];
+              target_label = "__param_target";
+            }
+            {
+              source_labels = [ "__param_target" ];
+              target_label = "instance";
+            }
+            {
+              target_label = "__address__";
+              replacement = "${blackbox_host}:${toString blackbox_port}";
+            }
+          ];
+        };
+      };
+
       blackbox_exporter.targets = [ "${blackbox_host}:${toString blackbox_port}" ];
 
       coturn.targets = [ "127.0.0.1:9641" ];

From be1d739b400a5c16c7b51c82916960b30692995c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sun, 23 Feb 2025 01:43:13 +0800
Subject: [PATCH 48/67] bump: Update inputs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Flake lock file updates:

• Updated input 'disko':
    'github:nix-community/disko/fa5746ecea1772cf59b3f34c5816ab3531478142?narHash=sha256-xFnU%2BuUl48Icas2wPQ%2BZzlL2O3n8f6J2LrzNK9f2nng%3D' (2025-02-15)
  → 'github:nix-community/disko/15dbf8cebd8e2655a883b74547108e089f051bf0?narHash=sha256-lSOXdgW/1zi/SSu7xp71v%2B55D5Egz8ACv0STkj7fhbs%3D' (2025-02-18)
• Updated input 'foundryvtt':
    'github:reckenrode/nix-foundryvtt/0a72a4bf64224c6584fd1b9e9f0012dd09af979a?narHash=sha256-vM9C1gFiQGa3nTYqmTBI8MoiUfprkQdepUBbxV7ECMQ%3D' (2025-01-17)
  → 'github:reckenrode/nix-foundryvtt/a7fa493ba2c623cf90e83756b62285b3b58f18d2?narHash=sha256-u3m%2BawbdL%2B0BKk8IWidsWMr%2BR0ian3GZMUlH7623kd8%3D' (2025-02-16)
• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/30d4471a8a2a13b716530d3aad60b9846ea5ff83?narHash=sha256-jGiez5BtGGJUB/LXzRa%2B4AQurMO9acc1B69kBfgQhJc%3D' (2025-02-15)
  → 'github:nixos/nixpkgs/11415c7ae8539d6292f2928317ee7a8410b28bb9?narHash=sha256-SSYxFhqCOb3aiPb6MmN68yEzBIltfom8IgRz7phHscM%3D' (2025-02-21)
• Updated input 'nixpkgs-unstable':
    'github:nixos/nixpkgs/31ff66eb77d02e9ac34b7256a02edb1c43fb9998?narHash=sha256-3bnOIZz8KXtzcaXGuH9Eriv0HiQyr1EIfcye%2BVHLQZE%3D' (2025-02-15)
  → 'github:nixos/nixpkgs/8465e233b0668cf162c608a92e62e8d78c1ba7e4?narHash=sha256-wzBbGGZ6i1VVBA/cDJaLfuuGYCUriD7fwsLgJJHRVRk%3D' (2025-02-22)
---
 flake.lock                            | 27 +++++++++++++--------------
 flake.nix                             |  2 +-
 pkgs/crowdsec/_sources/generated.json |  8 ++++----
 pkgs/crowdsec/_sources/generated.nix  |  8 ++++----
 4 files changed, 22 insertions(+), 23 deletions(-)

diff --git a/flake.lock b/flake.lock
index 276b8b2..37c3d5f 100644
--- a/flake.lock
+++ b/flake.lock
@@ -300,11 +300,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1739634831,
-        "narHash": "sha256-xFnU+uUl48Icas2wPQ+ZzlL2O3n8f6J2LrzNK9f2nng=",
+        "lastModified": 1739841949,
+        "narHash": "sha256-lSOXdgW/1zi/SSu7xp71v+55D5Egz8ACv0STkj7fhbs=",
         "owner": "nix-community",
         "repo": "disko",
-        "rev": "fa5746ecea1772cf59b3f34c5816ab3531478142",
+        "rev": "15dbf8cebd8e2655a883b74547108e089f051bf0",
         "type": "github"
       },
       "original": {
@@ -595,11 +595,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1737076827,
-        "narHash": "sha256-vM9C1gFiQGa3nTYqmTBI8MoiUfprkQdepUBbxV7ECMQ=",
+        "lastModified": 1739712626,
+        "narHash": "sha256-u3m+awbdL+0BKk8IWidsWMr+R0ian3GZMUlH7623kd8=",
         "owner": "reckenrode",
         "repo": "nix-foundryvtt",
-        "rev": "0a72a4bf64224c6584fd1b9e9f0012dd09af979a",
+        "rev": "a7fa493ba2c623cf90e83756b62285b3b58f18d2",
         "type": "github"
       },
       "original": {
@@ -746,11 +746,11 @@
     },
     "nixpkgs-unstable": {
       "locked": {
-        "lastModified": 1739611738,
-        "narHash": "sha256-3bnOIZz8KXtzcaXGuH9Eriv0HiQyr1EIfcye+VHLQZE=",
+        "lastModified": 1740215764,
+        "narHash": "sha256-wzBbGGZ6i1VVBA/cDJaLfuuGYCUriD7fwsLgJJHRVRk=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "31ff66eb77d02e9ac34b7256a02edb1c43fb9998",
+        "rev": "8465e233b0668cf162c608a92e62e8d78c1ba7e4",
         "type": "github"
       },
       "original": {
@@ -762,11 +762,11 @@
     },
     "nixpkgs_2": {
       "locked": {
-        "lastModified": 1739578539,
-        "narHash": "sha256-jGiez5BtGGJUB/LXzRa+4AQurMO9acc1B69kBfgQhJc=",
+        "lastModified": 1740162160,
+        "narHash": "sha256-SSYxFhqCOb3aiPb6MmN68yEzBIltfom8IgRz7phHscM=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "30d4471a8a2a13b716530d3aad60b9846ea5ff83",
+        "rev": "11415c7ae8539d6292f2928317ee7a8410b28bb9",
         "type": "github"
       },
       "original": {
@@ -1078,14 +1078,13 @@
       "locked": {
         "lastModified": 1740082109,
         "narHash": "sha256-WdRNkwsIotFOSymee/yQyH46RmYtuxd1FENhvGL4KRc=",
-        "ref": "tlater/rust-rewrite",
+        "ref": "refs/heads/main",
         "rev": "a1b48cf2ba194054e2d8816c94a84cebc4fb5de0",
         "revCount": 23,
         "type": "git",
         "url": "ssh://git@github.com/sonnenshift/battery-manager"
       },
       "original": {
-        "ref": "tlater/rust-rewrite",
         "type": "git",
         "url": "ssh://git@github.com/sonnenshift/battery-manager"
       }
diff --git a/flake.nix b/flake.nix
index 737a17f..b31d108 100644
--- a/flake.nix
+++ b/flake.nix
@@ -23,7 +23,7 @@
     };
 
     sonnenshift = {
-      url = "git+ssh://git@github.com/sonnenshift/battery-manager?ref=tlater/rust-rewrite";
+      url = "git+ssh://git@github.com/sonnenshift/battery-manager";
       inputs.nixpkgs.follows = "nixpkgs";
     };
   };
diff --git a/pkgs/crowdsec/_sources/generated.json b/pkgs/crowdsec/_sources/generated.json
index 634bc18..ac251aa 100644
--- a/pkgs/crowdsec/_sources/generated.json
+++ b/pkgs/crowdsec/_sources/generated.json
@@ -21,7 +21,7 @@
     },
     "crowdsec-hub": {
         "cargoLocks": null,
-        "date": "2025-02-16",
+        "date": "2025-02-22",
         "extract": null,
         "name": "crowdsec-hub",
         "passthru": null,
@@ -33,10 +33,10 @@
             "name": null,
             "owner": "crowdsecurity",
             "repo": "hub",
-            "rev": "f7d7f476f88a4af05e1cfb3994536990adecfb57",
-            "sha256": "sha256-m78uipryHDKixJzrF4K59ioAJ3WJN1JlXEC0DNVMCJ8=",
+            "rev": "f9883cd6c7d1913c13e4a3a69d9a0b887a7d57df",
+            "sha256": "sha256-45pUln7Qj5luY9I9BE2qhzjH7kv4IbYvNoEX3/4AVVg=",
             "type": "github"
         },
-        "version": "f7d7f476f88a4af05e1cfb3994536990adecfb57"
+        "version": "f9883cd6c7d1913c13e4a3a69d9a0b887a7d57df"
     }
 }
\ No newline at end of file
diff --git a/pkgs/crowdsec/_sources/generated.nix b/pkgs/crowdsec/_sources/generated.nix
index 7ef44e6..9c63cc5 100644
--- a/pkgs/crowdsec/_sources/generated.nix
+++ b/pkgs/crowdsec/_sources/generated.nix
@@ -14,14 +14,14 @@
   };
   crowdsec-hub = {
     pname = "crowdsec-hub";
-    version = "f7d7f476f88a4af05e1cfb3994536990adecfb57";
+    version = "f9883cd6c7d1913c13e4a3a69d9a0b887a7d57df";
     src = fetchFromGitHub {
       owner = "crowdsecurity";
       repo = "hub";
-      rev = "f7d7f476f88a4af05e1cfb3994536990adecfb57";
+      rev = "f9883cd6c7d1913c13e4a3a69d9a0b887a7d57df";
       fetchSubmodules = false;
-      sha256 = "sha256-m78uipryHDKixJzrF4K59ioAJ3WJN1JlXEC0DNVMCJ8=";
+      sha256 = "sha256-45pUln7Qj5luY9I9BE2qhzjH7kv4IbYvNoEX3/4AVVg=";
     };
-    date = "2025-02-16";
+    date = "2025-02-22";
   };
 }

From e4a7fa8764f2c283e0d1d989e53d61e078ed48d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 28 Feb 2025 01:47:58 +0800
Subject: [PATCH 49/67] feat(grafana): Use the victoriametrics metrics plugin

---
 configuration/services/metrics/grafana.nix | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/configuration/services/metrics/grafana.nix b/configuration/services/metrics/grafana.nix
index e597cff..d14b908 100644
--- a/configuration/services/metrics/grafana.nix
+++ b/configuration/services/metrics/grafana.nix
@@ -1,4 +1,4 @@
-{ config, ... }:
+{ pkgs, config, ... }:
 let
   domain = "metrics.${config.services.nginx.domain}";
 in
@@ -28,6 +28,10 @@ in
       };
     };
 
+    declarativePlugins = [
+      pkgs.grafanaPlugins.victoriametrics-metrics-datasource
+    ];
+
     provision = {
       enable = true;
 
@@ -35,7 +39,9 @@ in
         {
           name = "Victoriametrics - tlater.net";
           url = "http://localhost:8428";
-          type = "prometheus";
+          type = "victoriametrics-metrics-datasource";
+          access = "proxy";
+          isDefault = true;
         }
       ];
     };

From a398790ef496f6cac8a485b2a3ef1d065e48d639 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 28 Feb 2025 01:43:10 +0800
Subject: [PATCH 50/67] feat(metrics): Add victorialogs

---
 configuration/services/metrics/default.nix    |   1 +
 configuration/services/metrics/grafana.nix    |  15 ++-
 .../services/metrics/victorialogs.nix         | 110 ++++++++++++++++++
 3 files changed, 125 insertions(+), 1 deletion(-)
 create mode 100644 configuration/services/metrics/victorialogs.nix

diff --git a/configuration/services/metrics/default.nix b/configuration/services/metrics/default.nix
index 84e126a..fe250fe 100644
--- a/configuration/services/metrics/default.nix
+++ b/configuration/services/metrics/default.nix
@@ -5,5 +5,6 @@
     ./exporters.nix
     ./grafana.nix
     ./victoriametrics.nix
+    ./victorialogs.nix
   ];
 }
diff --git a/configuration/services/metrics/grafana.nix b/configuration/services/metrics/grafana.nix
index d14b908..b872833 100644
--- a/configuration/services/metrics/grafana.nix
+++ b/configuration/services/metrics/grafana.nix
@@ -1,4 +1,9 @@
-{ pkgs, config, ... }:
+{
+  pkgs,
+  config,
+  flake-inputs,
+  ...
+}:
 let
   domain = "metrics.${config.services.nginx.domain}";
 in
@@ -30,6 +35,7 @@ in
 
     declarativePlugins = [
       pkgs.grafanaPlugins.victoriametrics-metrics-datasource
+      flake-inputs.nixpkgs-unstable.legacyPackages.${pkgs.system}.grafanaPlugins.victoriametrics-logs-datasource
     ];
 
     provision = {
@@ -43,6 +49,13 @@ in
           access = "proxy";
           isDefault = true;
         }
+
+        {
+          name = "Victorialogs - tlater.net";
+          url = "http://${config.services.victorialogs.bindAddress}";
+          type = "victoriametrics-logs-datasource";
+          access = "proxy";
+        }
       ];
     };
   };
diff --git a/configuration/services/metrics/victorialogs.nix b/configuration/services/metrics/victorialogs.nix
new file mode 100644
index 0000000..ed74c59
--- /dev/null
+++ b/configuration/services/metrics/victorialogs.nix
@@ -0,0 +1,110 @@
+{
+  config,
+  pkgs,
+  lib,
+  ...
+}:
+let
+  cfg = config.services.victorialogs;
+  pkg = pkgs.victoriametrics;
+  dirname = "victorialogs";
+in
+{
+  options.services.victorialogs =
+    let
+      inherit (lib.types) str;
+    in
+    {
+      listenAddress = lib.mkOption {
+        default = ":9428";
+        type = str;
+      };
+
+      bindAddress = lib.mkOption {
+        readOnly = true;
+        type = str;
+        description = ''
+          Final address on which victorialogs listens.
+        '';
+      };
+    };
+
+  config = {
+    services.victorialogs.bindAddress =
+      (lib.optionalString (lib.hasPrefix ":" cfg.listenAddress) "127.0.0.1") + cfg.listenAddress;
+
+    services.journald.upload = {
+      enable = true;
+      settings.Upload = {
+        URL = "http://${cfg.bindAddress}/insert/journald";
+        NetworkTimeoutSec = "20s";
+      };
+    };
+
+    systemd.services."systemd-journal-upload".after = [ "victorialogs.service" ];
+
+    systemd.services.victorialogs = {
+      description = "VictoriaLogs log database";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      startLimitBurst = 5;
+
+      serviceConfig = {
+        ExecStart = lib.escapeShellArgs [
+          "${pkg}/bin/victoria-logs"
+          "-storageDataPath=/var/lib/${dirname}"
+          "-httpListenAddr=${cfg.listenAddress}"
+        ];
+
+        DynamicUser = true;
+        RestartSec = 1;
+        Restart = "on-failure";
+        RuntimeDirectory = dirname;
+        RuntimeDirectoryMode = "0700";
+        StateDirectory = dirname;
+        StateDirectoryMode = "0700";
+
+        LimitNOFILE = 1048576;
+
+        # Hardening
+        DeviceAllow = [ "/dev/null rw" ];
+        DevicePolicy = "strict";
+        LockPersonality = true;
+        MemoryDenyWriteExecute = true;
+        NoNewPrivileges = true;
+        PrivateDevices = true;
+        PrivateTmp = true;
+        PrivateUsers = true;
+        ProtectClock = true;
+        ProtectControlGroups = true;
+        ProtectHome = true;
+        ProtectHostname = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        ProtectProc = "invisible";
+        ProtectSystem = "full";
+        RemoveIPC = true;
+        RestrictAddressFamilies = [
+          "AF_INET"
+          "AF_INET6"
+          "AF_UNIX"
+        ];
+        RestrictNamespaces = true;
+        RestrictRealtime = true;
+        RestrictSUIDSGID = true;
+        SystemCallArchitectures = "native";
+        SystemCallFilter = [
+          "@system-service"
+          "~@privileged"
+        ];
+      };
+
+      postStart = lib.mkBefore ''
+        until ${lib.getBin pkgs.curl}/bin/curl -s -o /dev/null http://${cfg.bindAddress}/ping; do
+          sleep 1;
+        done
+      '';
+    };
+  };
+}

From 3c6afa0c66544826169432018f82ae22169c12cf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 4 Apr 2025 21:06:27 +0800
Subject: [PATCH 51/67] feat(matrix): Switch to conduwuit

This fixes support for the new sliding sync API.
---
 .../hardware-specific/hetzner/disko.nix       |  11 +
 configuration/services/conduit/default.nix    |  19 +-
 flake.lock                                    | 912 +++++++++++++++---
 flake.nix                                     |   4 +
 4 files changed, 807 insertions(+), 139 deletions(-)

diff --git a/configuration/hardware-specific/hetzner/disko.nix b/configuration/hardware-specific/hetzner/disko.nix
index cc15471..7e1acd7 100644
--- a/configuration/hardware-specific/hetzner/disko.nix
+++ b/configuration/hardware-specific/hetzner/disko.nix
@@ -80,6 +80,17 @@
                     inherit mountOptions;
                     mountpoint = "/var";
                   };
+                  "/volume/var/lib/private/matrix-conduit" = {
+                    mountOptions = [
+                      # Explicitly don't compress here, since
+                      # conduwuit's database does compression by
+                      # itself, and relies on being able to read the
+                      # raw file data from disk (which is impossible
+                      # if btrfs compresses it)
+                      "noatime"
+                    ];
+                    mountpoint = "/var/lib/private/matrix-conduit";
+                  };
                   "/volume/nix-store" = {
                     inherit mountOptions;
                     mountpoint = "/nix";
diff --git a/configuration/services/conduit/default.nix b/configuration/services/conduit/default.nix
index c7e4ab4..5a2b8ac 100644
--- a/configuration/services/conduit/default.nix
+++ b/configuration/services/conduit/default.nix
@@ -1,4 +1,6 @@
 {
+  pkgs,
+  flake-inputs,
   config,
   lib,
   ...
@@ -18,10 +20,12 @@ in
 
   services.matrix-conduit = {
     enable = true;
+    package = flake-inputs.conduwuit.packages.${pkgs.system}.default;
     settings.global = {
       address = "127.0.0.1";
       server_name = domain;
-      database_backend = "rocksdb";
+      new_user_displayname_suffix = "🦆";
+      allow_check_for_updates = true;
 
       # Set up delegation: https://docs.conduit.rs/delegation.html#automatic-recommended
       # This is primarily to make sliding sync work
@@ -44,11 +48,14 @@ in
     };
   };
 
-  # Pass in the TURN secret via EnvironmentFile, not supported by
-  # upstream module currently.
-  #
-  # See also https://gitlab.com/famedly/conduit/-/issues/314
-  systemd.services.conduit.serviceConfig.EnvironmentFile = config.sops.secrets."turn/env".path;
+  systemd.services.conduit.serviceConfig = {
+    ExecStart = lib.mkForce "${config.services.matrix-conduit.package}/bin/conduwuit";
+    # Pass in the TURN secret via EnvironmentFile, not supported by
+    # upstream module currently.
+    #
+    # See also https://gitlab.com/famedly/conduit/-/issues/314
+    EnvironmentFile = config.sops.secrets."turn/env".path;
+  };
 
   systemd.services.coturn.serviceConfig.SupplementaryGroups = [
     config.security.acme.certs."tlater.net".group
diff --git a/flake.lock b/flake.lock
index 37c3d5f..3f3fc39 100644
--- a/flake.lock
+++ b/flake.lock
@@ -1,6 +1,86 @@
 {
   "nodes": {
+    "attic": {
+      "inputs": {
+        "crane": "crane",
+        "flake-compat": "flake-compat",
+        "flake-parts": "flake-parts",
+        "nix-github-actions": "nix-github-actions",
+        "nixpkgs": "nixpkgs",
+        "nixpkgs-stable": "nixpkgs-stable"
+      },
+      "locked": {
+        "lastModified": 1738524606,
+        "narHash": "sha256-hPYEJ4juK3ph7kbjbvv7PlU1D9pAkkhl+pwx8fZY53U=",
+        "owner": "zhaofengli",
+        "repo": "attic",
+        "rev": "ff8a897d1f4408ebbf4d45fa9049c06b3e1e3f4e",
+        "type": "github"
+      },
+      "original": {
+        "owner": "zhaofengli",
+        "ref": "main",
+        "repo": "attic",
+        "type": "github"
+      }
+    },
     "cachix": {
+      "inputs": {
+        "devenv": "devenv",
+        "flake-compat": "flake-compat_2",
+        "git-hooks": "git-hooks",
+        "nixpkgs": "nixpkgs_4"
+      },
+      "locked": {
+        "lastModified": 1737621947,
+        "narHash": "sha256-8HFvG7fvIFbgtaYAY2628Tb89fA55nPm2jSiNs0/Cws=",
+        "owner": "cachix",
+        "repo": "cachix",
+        "rev": "f65a3cd5e339c223471e64c051434616e18cc4f5",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "ref": "master",
+        "repo": "cachix",
+        "type": "github"
+      }
+    },
+    "cachix_2": {
+      "inputs": {
+        "devenv": [
+          "conduwuit",
+          "cachix",
+          "devenv"
+        ],
+        "flake-compat": [
+          "conduwuit",
+          "cachix",
+          "devenv"
+        ],
+        "git-hooks": [
+          "conduwuit",
+          "cachix",
+          "devenv"
+        ],
+        "nixpkgs": "nixpkgs_2"
+      },
+      "locked": {
+        "lastModified": 1728672398,
+        "narHash": "sha256-KxuGSoVUFnQLB2ZcYODW7AVPAh9JqRlD5BrfsC/Q4qs=",
+        "owner": "cachix",
+        "repo": "cachix",
+        "rev": "aac51f698309fd0f381149214b7eee213c66ef0a",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "ref": "latest",
+        "repo": "cachix",
+        "type": "github"
+      }
+    },
+    "cachix_3": {
       "inputs": {
         "devenv": [
           "sonnenshift",
@@ -10,7 +90,7 @@
           "sonnenshift",
           "crate2nix"
         ],
-        "nixpkgs": "nixpkgs_3",
+        "nixpkgs": "nixpkgs_7",
         "pre-commit-hooks": [
           "sonnenshift",
           "crate2nix"
@@ -31,7 +111,7 @@
         "type": "github"
       }
     },
-    "cachix_2": {
+    "cachix_4": {
       "inputs": {
         "devenv": [
           "sonnenshift",
@@ -43,7 +123,7 @@
           "crate2nix",
           "crate2nix_stable"
         ],
-        "nixpkgs": "nixpkgs_4",
+        "nixpkgs": "nixpkgs_8",
         "pre-commit-hooks": [
           "sonnenshift",
           "crate2nix",
@@ -65,7 +145,7 @@
         "type": "github"
       }
     },
-    "cachix_3": {
+    "cachix_5": {
       "inputs": {
         "devenv": [
           "sonnenshift",
@@ -79,7 +159,7 @@
           "crate2nix_stable",
           "crate2nix_stable"
         ],
-        "nixpkgs": "nixpkgs_5",
+        "nixpkgs": "nixpkgs_9",
         "pre-commit-hooks": [
           "sonnenshift",
           "crate2nix",
@@ -102,13 +182,98 @@
         "type": "github"
       }
     },
+    "complement": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1741891349,
+        "narHash": "sha256-YvrzOWcX7DH1drp5SGa+E/fc7wN3hqFtPbqPjZpOu1Q=",
+        "owner": "girlbossceo",
+        "repo": "complement",
+        "rev": "e587b3df569cba411aeac7c20b6366d03c143745",
+        "type": "github"
+      },
+      "original": {
+        "owner": "girlbossceo",
+        "ref": "main",
+        "repo": "complement",
+        "type": "github"
+      }
+    },
+    "conduwuit": {
+      "inputs": {
+        "attic": "attic",
+        "cachix": "cachix",
+        "complement": "complement",
+        "crane": "crane_2",
+        "fenix": "fenix",
+        "flake-compat": "flake-compat_3",
+        "flake-utils": "flake-utils",
+        "liburing": "liburing",
+        "nix-filter": "nix-filter",
+        "nixpkgs": [
+          "nixpkgs"
+        ],
+        "rocksdb": "rocksdb"
+      },
+      "locked": {
+        "lastModified": 1743473828,
+        "narHash": "sha256-x/sfh6LCHGAz8rL23GHhH7dac1LtHBbRRJi1p8gOdtI=",
+        "owner": "girlbossceo",
+        "repo": "conduwuit",
+        "rev": "0f81c1e1ccdcb0c5c6d5a27e82f16eb37b1e61c8",
+        "type": "github"
+      },
+      "original": {
+        "owner": "girlbossceo",
+        "repo": "conduwuit",
+        "type": "github"
+      }
+    },
+    "crane": {
+      "inputs": {
+        "nixpkgs": [
+          "conduwuit",
+          "attic",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1722960479,
+        "narHash": "sha256-NhCkJJQhD5GUib8zN9JrmYGMwt4lCRp6ZVNzIiYCl0Y=",
+        "owner": "ipetkov",
+        "repo": "crane",
+        "rev": "4c6c77920b8d44cd6660c1621dea6b3fc4b4c4f4",
+        "type": "github"
+      },
+      "original": {
+        "owner": "ipetkov",
+        "repo": "crane",
+        "type": "github"
+      }
+    },
+    "crane_2": {
+      "locked": {
+        "lastModified": 1739936662,
+        "narHash": "sha256-x4syUjNUuRblR07nDPeLDP7DpphaBVbUaSoeZkFbGSk=",
+        "owner": "ipetkov",
+        "repo": "crane",
+        "rev": "19de14aaeb869287647d9461cbd389187d8ecdb7",
+        "type": "github"
+      },
+      "original": {
+        "owner": "ipetkov",
+        "ref": "master",
+        "repo": "crane",
+        "type": "github"
+      }
+    },
     "crate2nix": {
       "inputs": {
-        "cachix": "cachix",
+        "cachix": "cachix_3",
         "crate2nix_stable": "crate2nix_stable",
         "devshell": "devshell_3",
-        "flake-compat": "flake-compat_4",
-        "flake-parts": "flake-parts_3",
+        "flake-compat": "flake-compat_7",
+        "flake-parts": "flake-parts_5",
         "nix-test-runner": "nix-test-runner_3",
         "nixpkgs": [
           "sonnenshift",
@@ -132,13 +297,13 @@
     },
     "crate2nix_stable": {
       "inputs": {
-        "cachix": "cachix_2",
+        "cachix": "cachix_4",
         "crate2nix_stable": "crate2nix_stable_2",
         "devshell": "devshell_2",
-        "flake-compat": "flake-compat_3",
-        "flake-parts": "flake-parts_2",
+        "flake-compat": "flake-compat_6",
+        "flake-parts": "flake-parts_4",
         "nix-test-runner": "nix-test-runner_2",
-        "nixpkgs": "nixpkgs_7",
+        "nixpkgs": "nixpkgs_11",
         "pre-commit-hooks": "pre-commit-hooks_2"
       },
       "locked": {
@@ -158,13 +323,13 @@
     },
     "crate2nix_stable_2": {
       "inputs": {
-        "cachix": "cachix_3",
+        "cachix": "cachix_5",
         "crate2nix_stable": "crate2nix_stable_3",
         "devshell": "devshell",
-        "flake-compat": "flake-compat_2",
-        "flake-parts": "flake-parts",
+        "flake-compat": "flake-compat_5",
+        "flake-parts": "flake-parts_3",
         "nix-test-runner": "nix-test-runner",
-        "nixpkgs": "nixpkgs_6",
+        "nixpkgs": "nixpkgs_10",
         "pre-commit-hooks": "pre-commit-hooks"
       },
       "locked": {
@@ -184,7 +349,7 @@
     },
     "crate2nix_stable_3": {
       "inputs": {
-        "flake-utils": "flake-utils"
+        "flake-utils": "flake-utils_2"
       },
       "locked": {
         "lastModified": 1702842982,
@@ -203,8 +368,8 @@
     },
     "deploy-rs": {
       "inputs": {
-        "flake-compat": "flake-compat",
-        "nixpkgs": "nixpkgs",
+        "flake-compat": "flake-compat_4",
+        "nixpkgs": "nixpkgs_5",
         "utils": "utils"
       },
       "locked": {
@@ -221,9 +386,43 @@
         "type": "github"
       }
     },
+    "devenv": {
+      "inputs": {
+        "cachix": "cachix_2",
+        "flake-compat": [
+          "conduwuit",
+          "cachix",
+          "flake-compat"
+        ],
+        "git-hooks": [
+          "conduwuit",
+          "cachix",
+          "git-hooks"
+        ],
+        "nix": "nix",
+        "nixpkgs": [
+          "conduwuit",
+          "cachix",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1733323168,
+        "narHash": "sha256-d5DwB4MZvlaQpN6OQ4SLYxb5jA4UH5EtV5t5WOtjLPU=",
+        "owner": "cachix",
+        "repo": "devenv",
+        "rev": "efa9010b8b1cfd5dd3c7ed1e172a470c3b84a064",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "repo": "devenv",
+        "type": "github"
+      }
+    },
     "devshell": {
       "inputs": {
-        "flake-utils": "flake-utils_2",
+        "flake-utils": "flake-utils_3",
         "nixpkgs": [
           "sonnenshift",
           "crate2nix",
@@ -248,7 +447,7 @@
     },
     "devshell_2": {
       "inputs": {
-        "flake-utils": "flake-utils_3",
+        "flake-utils": "flake-utils_4",
         "nixpkgs": [
           "sonnenshift",
           "crate2nix",
@@ -272,7 +471,7 @@
     },
     "devshell_3": {
       "inputs": {
-        "flake-utils": "flake-utils_4",
+        "flake-utils": "flake-utils_5",
         "nixpkgs": [
           "sonnenshift",
           "crate2nix",
@@ -315,7 +514,7 @@
     },
     "dream2nix": {
       "inputs": {
-        "nixpkgs": "nixpkgs_8",
+        "nixpkgs": "nixpkgs_12",
         "purescript-overlay": "purescript-overlay",
         "pyproject-nix": "pyproject-nix"
       },
@@ -336,11 +535,34 @@
     "fenix": {
       "inputs": {
         "nixpkgs": [
-          "tlaternet-webserver",
+          "conduwuit",
           "nixpkgs"
         ],
         "rust-analyzer-src": "rust-analyzer-src"
       },
+      "locked": {
+        "lastModified": 1740724364,
+        "narHash": "sha256-D1jLIueJx1dPrP09ZZwTrPf4cubV+TsFMYbpYYTVj6A=",
+        "owner": "nix-community",
+        "repo": "fenix",
+        "rev": "edf7d9e431cda8782e729253835f178a356d3aab",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-community",
+        "ref": "main",
+        "repo": "fenix",
+        "type": "github"
+      }
+    },
+    "fenix_2": {
+      "inputs": {
+        "nixpkgs": [
+          "tlaternet-webserver",
+          "nixpkgs"
+        ],
+        "rust-analyzer-src": "rust-analyzer-src_2"
+      },
       "locked": {
         "lastModified": 1737181903,
         "narHash": "sha256-lvp77MhGzSN+ICd0MugppCjQR6cmlM2iAC5cjy2ZsaA=",
@@ -372,34 +594,55 @@
       }
     },
     "flake-compat_2": {
+      "flake": false,
       "locked": {
-        "lastModified": 1696426674,
-        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
-        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
-        "revCount": 57,
-        "type": "tarball",
-        "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz"
+        "lastModified": 1733328505,
+        "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
+        "owner": "edolstra",
+        "repo": "flake-compat",
+        "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
+        "type": "github"
       },
       "original": {
-        "type": "tarball",
-        "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
+        "owner": "edolstra",
+        "repo": "flake-compat",
+        "type": "github"
       }
     },
     "flake-compat_3": {
+      "flake": false,
       "locked": {
-        "lastModified": 1696426674,
-        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
-        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
-        "revCount": 57,
-        "type": "tarball",
-        "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz"
+        "lastModified": 1733328505,
+        "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
+        "owner": "edolstra",
+        "repo": "flake-compat",
+        "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
+        "type": "github"
       },
       "original": {
-        "type": "tarball",
-        "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
+        "owner": "edolstra",
+        "ref": "master",
+        "repo": "flake-compat",
+        "type": "github"
       }
     },
     "flake-compat_4": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1696426674,
+        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
+        "owner": "edolstra",
+        "repo": "flake-compat",
+        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
+        "type": "github"
+      },
+      "original": {
+        "owner": "edolstra",
+        "repo": "flake-compat",
+        "type": "github"
+      }
+    },
+    "flake-compat_5": {
       "locked": {
         "lastModified": 1696426674,
         "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
@@ -413,7 +656,35 @@
         "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
       }
     },
-    "flake-compat_5": {
+    "flake-compat_6": {
+      "locked": {
+        "lastModified": 1696426674,
+        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
+        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
+        "revCount": 57,
+        "type": "tarball",
+        "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz"
+      },
+      "original": {
+        "type": "tarball",
+        "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
+      }
+    },
+    "flake-compat_7": {
+      "locked": {
+        "lastModified": 1696426674,
+        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
+        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
+        "revCount": 57,
+        "type": "tarball",
+        "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz"
+      },
+      "original": {
+        "type": "tarball",
+        "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
+      }
+    },
+    "flake-compat_8": {
       "flake": false,
       "locked": {
         "lastModified": 1696426674,
@@ -430,6 +701,52 @@
       }
     },
     "flake-parts": {
+      "inputs": {
+        "nixpkgs-lib": [
+          "conduwuit",
+          "attic",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1722555600,
+        "narHash": "sha256-XOQkdLafnb/p9ij77byFQjDf5m5QYl9b2REiVClC+x4=",
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "rev": "8471fe90ad337a8074e957b69ca4d0089218391d",
+        "type": "github"
+      },
+      "original": {
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "type": "github"
+      }
+    },
+    "flake-parts_2": {
+      "inputs": {
+        "nixpkgs-lib": [
+          "conduwuit",
+          "cachix",
+          "devenv",
+          "nix",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1712014858,
+        "narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
+        "type": "github"
+      },
+      "original": {
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "type": "github"
+      }
+    },
+    "flake-parts_3": {
       "inputs": {
         "nixpkgs-lib": [
           "sonnenshift",
@@ -453,7 +770,7 @@
         "type": "github"
       }
     },
-    "flake-parts_2": {
+    "flake-parts_4": {
       "inputs": {
         "nixpkgs-lib": [
           "sonnenshift",
@@ -476,7 +793,7 @@
         "type": "github"
       }
     },
-    "flake-parts_3": {
+    "flake-parts_5": {
       "inputs": {
         "nixpkgs-lib": [
           "sonnenshift",
@@ -500,18 +817,19 @@
     },
     "flake-utils": {
       "inputs": {
-        "systems": "systems_2"
+        "systems": "systems"
       },
       "locked": {
-        "lastModified": 1694529238,
-        "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
+        "lastModified": 1731533236,
+        "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
         "owner": "numtide",
         "repo": "flake-utils",
-        "rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
+        "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
         "type": "github"
       },
       "original": {
         "owner": "numtide",
+        "ref": "main",
         "repo": "flake-utils",
         "type": "github"
       }
@@ -521,11 +839,11 @@
         "systems": "systems_3"
       },
       "locked": {
-        "lastModified": 1701680307,
-        "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
+        "lastModified": 1694529238,
+        "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
         "owner": "numtide",
         "repo": "flake-utils",
-        "rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
+        "rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
         "type": "github"
       },
       "original": {
@@ -574,6 +892,24 @@
       "inputs": {
         "systems": "systems_6"
       },
+      "locked": {
+        "lastModified": 1701680307,
+        "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "flake-utils_6": {
+      "inputs": {
+        "systems": "systems_7"
+      },
       "locked": {
         "lastModified": 1710146030,
         "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
@@ -608,14 +944,41 @@
         "type": "github"
       }
     },
+    "git-hooks": {
+      "inputs": {
+        "flake-compat": [
+          "conduwuit",
+          "cachix",
+          "flake-compat"
+        ],
+        "gitignore": "gitignore",
+        "nixpkgs": [
+          "conduwuit",
+          "cachix",
+          "nixpkgs"
+        ],
+        "nixpkgs-stable": "nixpkgs-stable_2"
+      },
+      "locked": {
+        "lastModified": 1733318908,
+        "narHash": "sha256-SVQVsbafSM1dJ4fpgyBqLZ+Lft+jcQuMtEL3lQWx2Sk=",
+        "owner": "cachix",
+        "repo": "git-hooks.nix",
+        "rev": "6f4e2a2112050951a314d2733a994fbab94864c6",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "repo": "git-hooks.nix",
+        "type": "github"
+      }
+    },
     "gitignore": {
       "inputs": {
         "nixpkgs": [
-          "sonnenshift",
-          "crate2nix",
-          "crate2nix_stable",
-          "crate2nix_stable",
-          "pre-commit-hooks",
+          "conduwuit",
+          "cachix",
+          "git-hooks",
           "nixpkgs"
         ]
       },
@@ -639,6 +1002,7 @@
           "sonnenshift",
           "crate2nix",
           "crate2nix_stable",
+          "crate2nix_stable",
           "pre-commit-hooks",
           "nixpkgs"
         ]
@@ -662,6 +1026,7 @@
         "nixpkgs": [
           "sonnenshift",
           "crate2nix",
+          "crate2nix_stable",
           "pre-commit-hooks",
           "nixpkgs"
         ]
@@ -680,6 +1045,141 @@
         "type": "github"
       }
     },
+    "gitignore_4": {
+      "inputs": {
+        "nixpkgs": [
+          "sonnenshift",
+          "crate2nix",
+          "pre-commit-hooks",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1709087332,
+        "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+        "type": "github"
+      },
+      "original": {
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "type": "github"
+      }
+    },
+    "libgit2": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1697646580,
+        "narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=",
+        "owner": "libgit2",
+        "repo": "libgit2",
+        "rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5",
+        "type": "github"
+      },
+      "original": {
+        "owner": "libgit2",
+        "repo": "libgit2",
+        "type": "github"
+      }
+    },
+    "liburing": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1740613216,
+        "narHash": "sha256-NpPOBqNND3Qe9IwqYs0mJLGTmIx7e6FgUEBAnJ+1ZLA=",
+        "owner": "axboe",
+        "repo": "liburing",
+        "rev": "e1003e496e66f9b0ae06674869795edf772d5500",
+        "type": "github"
+      },
+      "original": {
+        "owner": "axboe",
+        "ref": "master",
+        "repo": "liburing",
+        "type": "github"
+      }
+    },
+    "nix": {
+      "inputs": {
+        "flake-compat": [
+          "conduwuit",
+          "cachix",
+          "devenv"
+        ],
+        "flake-parts": "flake-parts_2",
+        "libgit2": "libgit2",
+        "nixpkgs": "nixpkgs_3",
+        "nixpkgs-23-11": [
+          "conduwuit",
+          "cachix",
+          "devenv"
+        ],
+        "nixpkgs-regression": [
+          "conduwuit",
+          "cachix",
+          "devenv"
+        ],
+        "pre-commit-hooks": [
+          "conduwuit",
+          "cachix",
+          "devenv"
+        ]
+      },
+      "locked": {
+        "lastModified": 1727438425,
+        "narHash": "sha256-X8ES7I1cfNhR9oKp06F6ir4Np70WGZU5sfCOuNBEwMg=",
+        "owner": "domenkozar",
+        "repo": "nix",
+        "rev": "f6c5ae4c1b2e411e6b1e6a8181cc84363d6a7546",
+        "type": "github"
+      },
+      "original": {
+        "owner": "domenkozar",
+        "ref": "devenv-2.24",
+        "repo": "nix",
+        "type": "github"
+      }
+    },
+    "nix-filter": {
+      "locked": {
+        "lastModified": 1731533336,
+        "narHash": "sha256-oRam5PS1vcrr5UPgALW0eo1m/5/pls27Z/pabHNy2Ms=",
+        "owner": "numtide",
+        "repo": "nix-filter",
+        "rev": "f7653272fd234696ae94229839a99b73c9ab7de0",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "ref": "main",
+        "repo": "nix-filter",
+        "type": "github"
+      }
+    },
+    "nix-github-actions": {
+      "inputs": {
+        "nixpkgs": [
+          "conduwuit",
+          "attic",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1729742964,
+        "narHash": "sha256-B4mzTcQ0FZHdpeWcpDYPERtyjJd/NIuaQ9+BV1h+MpA=",
+        "owner": "nix-community",
+        "repo": "nix-github-actions",
+        "rev": "e04df33f62cdcf93d73e9a04142464753a16db67",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-community",
+        "repo": "nix-github-actions",
+        "type": "github"
+      }
+    },
     "nix-test-runner": {
       "flake": false,
       "locked": {
@@ -730,11 +1230,11 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1702272962,
-        "narHash": "sha256-D+zHwkwPc6oYQ4G3A1HuadopqRwUY/JkMwHz1YF7j4Q=",
+        "lastModified": 1726042813,
+        "narHash": "sha256-LnNKCCxnwgF+575y0pxUdlGZBO/ru1CtGHIqQVfvjlA=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "e97b3e4186bcadf0ef1b6be22b8558eab1cdeb5d",
+        "rev": "159be5db480d1df880a0135ca0bfed84c2f88353",
         "type": "github"
       },
       "original": {
@@ -744,6 +1244,38 @@
         "type": "github"
       }
     },
+    "nixpkgs-stable": {
+      "locked": {
+        "lastModified": 1724316499,
+        "narHash": "sha256-Qb9MhKBUTCfWg/wqqaxt89Xfi6qTD3XpTzQ9eXi3JmE=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "797f7dc49e0bc7fab4b57c021cdf68f595e47841",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-24.05",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs-stable_2": {
+      "locked": {
+        "lastModified": 1730741070,
+        "narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "d063c1dd113c91ab27959ba540c0d9753409edf3",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-24.05",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
     "nixpkgs-unstable": {
       "locked": {
         "lastModified": 1740215764,
@@ -760,71 +1292,7 @@
         "type": "github"
       }
     },
-    "nixpkgs_2": {
-      "locked": {
-        "lastModified": 1740162160,
-        "narHash": "sha256-SSYxFhqCOb3aiPb6MmN68yEzBIltfom8IgRz7phHscM=",
-        "owner": "nixos",
-        "repo": "nixpkgs",
-        "rev": "11415c7ae8539d6292f2928317ee7a8410b28bb9",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nixos",
-        "ref": "nixos-24.11-small",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "nixpkgs_3": {
-      "locked": {
-        "lastModified": 1700612854,
-        "narHash": "sha256-yrQ8osMD+vDLGFX7pcwsY/Qr5PUd6OmDMYJZzZi0+zc=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "19cbff58383a4ae384dea4d1d0c823d72b49d614",
-        "type": "github"
-      },
-      "original": {
-        "owner": "NixOS",
-        "ref": "nixos-unstable",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "nixpkgs_4": {
-      "locked": {
-        "lastModified": 1715534503,
-        "narHash": "sha256-5ZSVkFadZbFP1THataCaSf0JH2cAH3S29hU9rrxTEqk=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "2057814051972fa1453ddfb0d98badbea9b83c06",
-        "type": "github"
-      },
-      "original": {
-        "owner": "NixOS",
-        "ref": "nixos-unstable",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "nixpkgs_5": {
-      "locked": {
-        "lastModified": 1715534503,
-        "narHash": "sha256-5ZSVkFadZbFP1THataCaSf0JH2cAH3S29hU9rrxTEqk=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "2057814051972fa1453ddfb0d98badbea9b83c06",
-        "type": "github"
-      },
-      "original": {
-        "owner": "NixOS",
-        "ref": "nixos-unstable",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "nixpkgs_6": {
+    "nixpkgs_10": {
       "locked": {
         "lastModified": 1719506693,
         "narHash": "sha256-C8e9S7RzshSdHB7L+v9I51af1gDM5unhJ2xO1ywxNH8=",
@@ -837,7 +1305,7 @@
         "type": "indirect"
       }
     },
-    "nixpkgs_7": {
+    "nixpkgs_11": {
       "locked": {
         "lastModified": 1719506693,
         "narHash": "sha256-C8e9S7RzshSdHB7L+v9I51af1gDM5unhJ2xO1ywxNH8=",
@@ -850,7 +1318,7 @@
         "type": "indirect"
       }
     },
-    "nixpkgs_8": {
+    "nixpkgs_12": {
       "locked": {
         "lastModified": 1729850857,
         "narHash": "sha256-WvLXzNNnnw+qpFOmgaM3JUlNEH+T4s22b5i2oyyCpXE=",
@@ -866,6 +1334,134 @@
         "type": "github"
       }
     },
+    "nixpkgs_2": {
+      "locked": {
+        "lastModified": 1730531603,
+        "narHash": "sha256-Dqg6si5CqIzm87sp57j5nTaeBbWhHFaVyG7V6L8k3lY=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "7ffd9ae656aec493492b44d0ddfb28e79a1ea25d",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs_3": {
+      "locked": {
+        "lastModified": 1717432640,
+        "narHash": "sha256-+f9c4/ZX5MWDOuB1rKoWj+lBNm0z0rs4CK47HBLxy1o=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "88269ab3044128b7c2f4c7d68448b2fb50456870",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "release-24.05",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs_4": {
+      "locked": {
+        "lastModified": 1733212471,
+        "narHash": "sha256-M1+uCoV5igihRfcUKrr1riygbe73/dzNnzPsmaLCmpo=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "55d15ad12a74eb7d4646254e13638ad0c4128776",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs_5": {
+      "locked": {
+        "lastModified": 1702272962,
+        "narHash": "sha256-D+zHwkwPc6oYQ4G3A1HuadopqRwUY/JkMwHz1YF7j4Q=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "e97b3e4186bcadf0ef1b6be22b8558eab1cdeb5d",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixpkgs-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs_6": {
+      "locked": {
+        "lastModified": 1740162160,
+        "narHash": "sha256-SSYxFhqCOb3aiPb6MmN68yEzBIltfom8IgRz7phHscM=",
+        "owner": "nixos",
+        "repo": "nixpkgs",
+        "rev": "11415c7ae8539d6292f2928317ee7a8410b28bb9",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nixos",
+        "ref": "nixos-24.11-small",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs_7": {
+      "locked": {
+        "lastModified": 1700612854,
+        "narHash": "sha256-yrQ8osMD+vDLGFX7pcwsY/Qr5PUd6OmDMYJZzZi0+zc=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "19cbff58383a4ae384dea4d1d0c823d72b49d614",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs_8": {
+      "locked": {
+        "lastModified": 1715534503,
+        "narHash": "sha256-5ZSVkFadZbFP1THataCaSf0JH2cAH3S29hU9rrxTEqk=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "2057814051972fa1453ddfb0d98badbea9b83c06",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs_9": {
+      "locked": {
+        "lastModified": 1715534503,
+        "narHash": "sha256-5ZSVkFadZbFP1THataCaSf0JH2cAH3S29hU9rrxTEqk=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "2057814051972fa1453ddfb0d98badbea9b83c06",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
     "pre-commit-hooks": {
       "inputs": {
         "flake-compat": [
@@ -875,7 +1471,7 @@
           "crate2nix_stable",
           "flake-compat"
         ],
-        "gitignore": "gitignore",
+        "gitignore": "gitignore_2",
         "nixpkgs": [
           "sonnenshift",
           "crate2nix",
@@ -913,7 +1509,7 @@
           "crate2nix_stable",
           "flake-compat"
         ],
-        "gitignore": "gitignore_2",
+        "gitignore": "gitignore_3",
         "nixpkgs": [
           "sonnenshift",
           "crate2nix",
@@ -948,8 +1544,8 @@
           "crate2nix",
           "flake-compat"
         ],
-        "flake-utils": "flake-utils_5",
-        "gitignore": "gitignore_3",
+        "flake-utils": "flake-utils_6",
+        "gitignore": "gitignore_4",
         "nixpkgs": [
           "sonnenshift",
           "crate2nix",
@@ -977,7 +1573,7 @@
     },
     "purescript-overlay": {
       "inputs": {
-        "flake-compat": "flake-compat_5",
+        "flake-compat": "flake-compat_8",
         "nixpkgs": [
           "tlaternet-webserver",
           "dream2nix",
@@ -1016,12 +1612,30 @@
         "type": "github"
       }
     },
+    "rocksdb": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1741308171,
+        "narHash": "sha256-YdBvdQ75UJg5ffwNjxizpviCVwVDJnBkM8ZtGIduMgY=",
+        "owner": "girlbossceo",
+        "repo": "rocksdb",
+        "rev": "3ce04794bcfbbb0d2e6f81ae35fc4acf688b6986",
+        "type": "github"
+      },
+      "original": {
+        "owner": "girlbossceo",
+        "ref": "v9.11.1",
+        "repo": "rocksdb",
+        "type": "github"
+      }
+    },
     "root": {
       "inputs": {
+        "conduwuit": "conduwuit",
         "deploy-rs": "deploy-rs",
         "disko": "disko",
         "foundryvtt": "foundryvtt",
-        "nixpkgs": "nixpkgs_2",
+        "nixpkgs": "nixpkgs_6",
         "nixpkgs-unstable": "nixpkgs-unstable",
         "sonnenshift": "sonnenshift",
         "sops-nix": "sops-nix",
@@ -1029,6 +1643,23 @@
       }
     },
     "rust-analyzer-src": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1740691488,
+        "narHash": "sha256-Fs6vBrByuiOf2WO77qeMDMTXcTGzrIMqLBv+lNeywwM=",
+        "owner": "rust-lang",
+        "repo": "rust-analyzer",
+        "rev": "fe3eda77d3a7ce212388bda7b6cec8bffcc077e5",
+        "type": "github"
+      },
+      "original": {
+        "owner": "rust-lang",
+        "ref": "nightly",
+        "repo": "rust-analyzer",
+        "type": "github"
+      }
+    },
+    "rust-analyzer-src_2": {
       "flake": false,
       "locked": {
         "lastModified": 1737140097,
@@ -1199,10 +1830,25 @@
         "type": "github"
       }
     },
+    "systems_7": {
+      "locked": {
+        "lastModified": 1681028828,
+        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+        "owner": "nix-systems",
+        "repo": "default",
+        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-systems",
+        "repo": "default",
+        "type": "github"
+      }
+    },
     "tlaternet-webserver": {
       "inputs": {
         "dream2nix": "dream2nix",
-        "fenix": "fenix",
+        "fenix": "fenix_2",
         "nixpkgs": [
           "nixpkgs"
         ]
@@ -1223,7 +1869,7 @@
     },
     "utils": {
       "inputs": {
-        "systems": "systems"
+        "systems": "systems_2"
       },
       "locked": {
         "lastModified": 1701680307,
diff --git a/flake.nix b/flake.nix
index b31d108..4f17def 100644
--- a/flake.nix
+++ b/flake.nix
@@ -4,6 +4,10 @@
   inputs = {
     nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11-small";
     nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable-small";
+    conduwuit = {
+      url = "github:girlbossceo/conduwuit";
+      inputs.nixpkgs.follows = "nixpkgs";
+    };
     disko = {
       url = "github:nix-community/disko";
       inputs.nixpkgs.follows = "nixpkgs";

From ee760bfa1ba04d642b38ad589495016ccb6622ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 4 Apr 2025 21:07:15 +0800
Subject: [PATCH 52/67] feat(victoriametrics): Add missing scrape configs

---
 configuration/services/conduit/matrix-hookshot.nix | 2 +-
 configuration/services/metrics/victoriametrics.nix | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/configuration/services/conduit/matrix-hookshot.nix b/configuration/services/conduit/matrix-hookshot.nix
index 6f11728..c1f16dc 100644
--- a/configuration/services/conduit/matrix-hookshot.nix
+++ b/configuration/services/conduit/matrix-hookshot.nix
@@ -138,7 +138,7 @@ in
         }
       ];
 
-      metrics.enable = true;
+      metrics.enabled = true;
     };
   };
 }
diff --git a/configuration/services/metrics/victoriametrics.nix b/configuration/services/metrics/victoriametrics.nix
index 4a78d46..53864d6 100644
--- a/configuration/services/metrics/victoriametrics.nix
+++ b/configuration/services/metrics/victoriametrics.nix
@@ -87,6 +87,8 @@ in
       # Configured in the hookshot listeners, but it's hard to filter
       # the correct values out of that config.
       matrixHookshot.targets = [ "127.0.0.1:9001" ];
+
+      victorialogs.targets = [ config.services.victorialogs.bindAddress ];
     };
   };
 }

From b396835f88cb8760a777e869b155418f51da0e74 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 4 Apr 2025 21:17:00 +0800
Subject: [PATCH 53/67] flake.lock: Update
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Flake lock file updates:

• Updated input 'conduwuit':
    'github:girlbossceo/conduwuit/0f81c1e1ccdcb0c5c6d5a27e82f16eb37b1e61c8' (2025-04-01)
  → 'github:girlbossceo/conduwuit/00f7745ec4ebcea5f892376c5de5db1299f71696' (2025-04-04)
• Updated input 'disko':
    'github:nix-community/disko/15dbf8cebd8e2655a883b74547108e089f051bf0' (2025-02-18)
  → 'github:nix-community/disko/329d3d7e8bc63dd30c39e14e6076db590a6eabe6' (2025-04-02)
• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/11415c7ae8539d6292f2928317ee7a8410b28bb9' (2025-02-21)
  → 'github:nixos/nixpkgs/bdb91860de2f719b57eef819b5617762f7120c70' (2025-04-03)
• Updated input 'nixpkgs-unstable':
    'github:nixos/nixpkgs/8465e233b0668cf162c608a92e62e8d78c1ba7e4' (2025-02-22)
  → 'github:nixos/nixpkgs/a462b946265ed006720d02153882780b12a8376d' (2025-04-04)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/07af005bb7d60c7f118d9d9f5530485da5d1e975' (2025-02-11)
  → 'github:Mic92/sops-nix/cff8437c5fe8c68fc3a840a21bf1f4dc801da40d' (2025-04-04)
---
 flake.lock | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/flake.lock b/flake.lock
index 3f3fc39..83911d7 100644
--- a/flake.lock
+++ b/flake.lock
@@ -216,11 +216,11 @@
         "rocksdb": "rocksdb"
       },
       "locked": {
-        "lastModified": 1743473828,
-        "narHash": "sha256-x/sfh6LCHGAz8rL23GHhH7dac1LtHBbRRJi1p8gOdtI=",
+        "lastModified": 1743735594,
+        "narHash": "sha256-aaP8OjY4fkpxk2JdSggx9S3Rk+P+VhuivT6aRpLxoj0=",
         "owner": "girlbossceo",
         "repo": "conduwuit",
-        "rev": "0f81c1e1ccdcb0c5c6d5a27e82f16eb37b1e61c8",
+        "rev": "00f7745ec4ebcea5f892376c5de5db1299f71696",
         "type": "github"
       },
       "original": {
@@ -499,11 +499,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1739841949,
-        "narHash": "sha256-lSOXdgW/1zi/SSu7xp71v+55D5Egz8ACv0STkj7fhbs=",
+        "lastModified": 1743598667,
+        "narHash": "sha256-ViE7NoFWytYO2uJONTAX35eGsvTYXNHjWALeHAg8OQY=",
         "owner": "nix-community",
         "repo": "disko",
-        "rev": "15dbf8cebd8e2655a883b74547108e089f051bf0",
+        "rev": "329d3d7e8bc63dd30c39e14e6076db590a6eabe6",
         "type": "github"
       },
       "original": {
@@ -1278,11 +1278,11 @@
     },
     "nixpkgs-unstable": {
       "locked": {
-        "lastModified": 1740215764,
-        "narHash": "sha256-wzBbGGZ6i1VVBA/cDJaLfuuGYCUriD7fwsLgJJHRVRk=",
+        "lastModified": 1743732435,
+        "narHash": "sha256-RrWgOj3F1N6kDG0xatvZzP0p1Zq00yhcTMlaj4bWi5E=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "8465e233b0668cf162c608a92e62e8d78c1ba7e4",
+        "rev": "a462b946265ed006720d02153882780b12a8376d",
         "type": "github"
       },
       "original": {
@@ -1400,11 +1400,11 @@
     },
     "nixpkgs_6": {
       "locked": {
-        "lastModified": 1740162160,
-        "narHash": "sha256-SSYxFhqCOb3aiPb6MmN68yEzBIltfom8IgRz7phHscM=",
+        "lastModified": 1743703532,
+        "narHash": "sha256-s1KLDALEeqy+ttrvqV3jx9mBZEvmthQErTVOAzbjHZs=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "11415c7ae8539d6292f2928317ee7a8410b28bb9",
+        "rev": "bdb91860de2f719b57eef819b5617762f7120c70",
         "type": "github"
       },
       "original": {
@@ -1727,11 +1727,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1739262228,
-        "narHash": "sha256-7JAGezJ0Dn5qIyA2+T4Dt/xQgAbhCglh6lzCekTVMeU=",
+        "lastModified": 1743756170,
+        "narHash": "sha256-2b11EYa08oqDmF3zEBLkG1AoNn9rB1k39ew/T/mSvbU=",
         "owner": "Mic92",
         "repo": "sops-nix",
-        "rev": "07af005bb7d60c7f118d9d9f5530485da5d1e975",
+        "rev": "cff8437c5fe8c68fc3a840a21bf1f4dc801da40d",
         "type": "github"
       },
       "original": {

From e37c589654c67863d32ad63ed1643b4a08f99188 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 4 Apr 2025 21:21:03 +0800
Subject: [PATCH 54/67] bump(crowdsec-hub): Update hub

---
 pkgs/crowdsec/_sources/generated.json | 8 ++++----
 pkgs/crowdsec/_sources/generated.nix  | 8 ++++----
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/pkgs/crowdsec/_sources/generated.json b/pkgs/crowdsec/_sources/generated.json
index ac251aa..97c4e87 100644
--- a/pkgs/crowdsec/_sources/generated.json
+++ b/pkgs/crowdsec/_sources/generated.json
@@ -21,7 +21,7 @@
     },
     "crowdsec-hub": {
         "cargoLocks": null,
-        "date": "2025-02-22",
+        "date": "2025-04-04",
         "extract": null,
         "name": "crowdsec-hub",
         "passthru": null,
@@ -33,10 +33,10 @@
             "name": null,
             "owner": "crowdsecurity",
             "repo": "hub",
-            "rev": "f9883cd6c7d1913c13e4a3a69d9a0b887a7d57df",
-            "sha256": "sha256-45pUln7Qj5luY9I9BE2qhzjH7kv4IbYvNoEX3/4AVVg=",
+            "rev": "eebc5f71379ea8f4de4a26f6695e0340444c719c",
+            "sha256": "sha256-/jhsqumekdOHDbHjBP8KvAICsSNhCg5ejMT3jSRiROo=",
             "type": "github"
         },
-        "version": "f9883cd6c7d1913c13e4a3a69d9a0b887a7d57df"
+        "version": "eebc5f71379ea8f4de4a26f6695e0340444c719c"
     }
 }
\ No newline at end of file
diff --git a/pkgs/crowdsec/_sources/generated.nix b/pkgs/crowdsec/_sources/generated.nix
index 9c63cc5..aca88b2 100644
--- a/pkgs/crowdsec/_sources/generated.nix
+++ b/pkgs/crowdsec/_sources/generated.nix
@@ -14,14 +14,14 @@
   };
   crowdsec-hub = {
     pname = "crowdsec-hub";
-    version = "f9883cd6c7d1913c13e4a3a69d9a0b887a7d57df";
+    version = "eebc5f71379ea8f4de4a26f6695e0340444c719c";
     src = fetchFromGitHub {
       owner = "crowdsecurity";
       repo = "hub";
-      rev = "f9883cd6c7d1913c13e4a3a69d9a0b887a7d57df";
+      rev = "eebc5f71379ea8f4de4a26f6695e0340444c719c";
       fetchSubmodules = false;
-      sha256 = "sha256-45pUln7Qj5luY9I9BE2qhzjH7kv4IbYvNoEX3/4AVVg=";
+      sha256 = "sha256-/jhsqumekdOHDbHjBP8KvAICsSNhCg5ejMT3jSRiROo=";
     };
-    date = "2025-02-22";
+    date = "2025-04-04";
   };
 }

From 89f9196ef0405d2b82a8330a4e00f45c5a8b7e28 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 4 Apr 2025 21:35:24 +0800
Subject: [PATCH 55/67] fix(victorialogs): Use new upstream module

---
 .../services/metrics/victorialogs.nix         | 100 +++---------------
 1 file changed, 12 insertions(+), 88 deletions(-)

diff --git a/configuration/services/metrics/victorialogs.nix b/configuration/services/metrics/victorialogs.nix
index ed74c59..ae47c39 100644
--- a/configuration/services/metrics/victorialogs.nix
+++ b/configuration/services/metrics/victorialogs.nix
@@ -1,37 +1,26 @@
 {
   config,
-  pkgs,
   lib,
   ...
 }:
 let
   cfg = config.services.victorialogs;
-  pkg = pkgs.victoriametrics;
-  dirname = "victorialogs";
 in
 {
-  options.services.victorialogs =
-    let
-      inherit (lib.types) str;
-    in
-    {
-      listenAddress = lib.mkOption {
-        default = ":9428";
-        type = str;
-      };
-
-      bindAddress = lib.mkOption {
-        readOnly = true;
-        type = str;
-        description = ''
-          Final address on which victorialogs listens.
-        '';
-      };
-    };
+  options.services.victorialogs.bindAddress = lib.mkOption {
+    readOnly = true;
+    type = lib.types.str;
+    description = ''
+      Final address on which victorialogs listens.
+    '';
+  };
 
   config = {
-    services.victorialogs.bindAddress =
-      (lib.optionalString (lib.hasPrefix ":" cfg.listenAddress) "127.0.0.1") + cfg.listenAddress;
+    services.victorialogs = {
+      enable = true;
+      bindAddress =
+        (lib.optionalString (lib.hasPrefix ":" cfg.listenAddress) "127.0.0.1") + cfg.listenAddress;
+    };
 
     services.journald.upload = {
       enable = true;
@@ -40,71 +29,6 @@ in
         NetworkTimeoutSec = "20s";
       };
     };
-
     systemd.services."systemd-journal-upload".after = [ "victorialogs.service" ];
-
-    systemd.services.victorialogs = {
-      description = "VictoriaLogs log database";
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network.target" ];
-      startLimitBurst = 5;
-
-      serviceConfig = {
-        ExecStart = lib.escapeShellArgs [
-          "${pkg}/bin/victoria-logs"
-          "-storageDataPath=/var/lib/${dirname}"
-          "-httpListenAddr=${cfg.listenAddress}"
-        ];
-
-        DynamicUser = true;
-        RestartSec = 1;
-        Restart = "on-failure";
-        RuntimeDirectory = dirname;
-        RuntimeDirectoryMode = "0700";
-        StateDirectory = dirname;
-        StateDirectoryMode = "0700";
-
-        LimitNOFILE = 1048576;
-
-        # Hardening
-        DeviceAllow = [ "/dev/null rw" ];
-        DevicePolicy = "strict";
-        LockPersonality = true;
-        MemoryDenyWriteExecute = true;
-        NoNewPrivileges = true;
-        PrivateDevices = true;
-        PrivateTmp = true;
-        PrivateUsers = true;
-        ProtectClock = true;
-        ProtectControlGroups = true;
-        ProtectHome = true;
-        ProtectHostname = true;
-        ProtectKernelLogs = true;
-        ProtectKernelModules = true;
-        ProtectKernelTunables = true;
-        ProtectProc = "invisible";
-        ProtectSystem = "full";
-        RemoveIPC = true;
-        RestrictAddressFamilies = [
-          "AF_INET"
-          "AF_INET6"
-          "AF_UNIX"
-        ];
-        RestrictNamespaces = true;
-        RestrictRealtime = true;
-        RestrictSUIDSGID = true;
-        SystemCallArchitectures = "native";
-        SystemCallFilter = [
-          "@system-service"
-          "~@privileged"
-        ];
-      };
-
-      postStart = lib.mkBefore ''
-        until ${lib.getBin pkgs.curl}/bin/curl -s -o /dev/null http://${cfg.bindAddress}/ping; do
-          sleep 1;
-        done
-      '';
-    };
   };
 }

From cfbc2999d75e53afe0e8e9bfed53f97086144394 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 17 May 2025 14:48:39 +0800
Subject: [PATCH 56/67] flake.lock: Update
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Flake lock file updates:

• Updated input 'conduwuit':
    'github:girlbossceo/conduwuit/00f7745ec4ebcea5f892376c5de5db1299f71696' (2025-04-04)
  → 'github:girlbossceo/conduwuit/d8311a5ff672fdc4729d956af5e3af8646b0670d' (2025-04-09)
• Updated input 'disko':
    'github:nix-community/disko/329d3d7e8bc63dd30c39e14e6076db590a6eabe6' (2025-04-02)
  → 'github:nix-community/disko/ec7c109a4f794fce09aad87239eab7f66540b888' (2025-05-15)
• Updated input 'foundryvtt':
    'github:reckenrode/nix-foundryvtt/a7fa493ba2c623cf90e83756b62285b3b58f18d2' (2025-02-16)
  → 'github:reckenrode/nix-foundryvtt/f1b401831d796dd94cf5a11b65fd169a199d4ff0' (2025-05-10)
• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/bdb91860de2f719b57eef819b5617762f7120c70' (2025-04-03)
  → 'github:nixos/nixpkgs/d6c9326e40bb557ebb8c040b4375590bc06413f8' (2025-05-16)
• Updated input 'nixpkgs-unstable':
    'github:nixos/nixpkgs/a462b946265ed006720d02153882780b12a8376d' (2025-04-04)
  → 'github:nixos/nixpkgs/b965e4c283060415956ccd39eee4ca34a6a56cf8' (2025-05-16)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/cff8437c5fe8c68fc3a840a21bf1f4dc801da40d' (2025-04-04)
  → 'github:Mic92/sops-nix/e93ee1d900ad264d65e9701a5c6f895683433386' (2025-05-05)
---
 flake.lock | 36 ++++++++++++++++++------------------
 1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/flake.lock b/flake.lock
index 83911d7..80f2bc5 100644
--- a/flake.lock
+++ b/flake.lock
@@ -216,11 +216,11 @@
         "rocksdb": "rocksdb"
       },
       "locked": {
-        "lastModified": 1743735594,
-        "narHash": "sha256-aaP8OjY4fkpxk2JdSggx9S3Rk+P+VhuivT6aRpLxoj0=",
+        "lastModified": 1744169934,
+        "narHash": "sha256-5YyHmPUUrXXrczWayji9327knihVTKnmjX+vX6+p6d0=",
         "owner": "girlbossceo",
         "repo": "conduwuit",
-        "rev": "00f7745ec4ebcea5f892376c5de5db1299f71696",
+        "rev": "d8311a5ff672fdc4729d956af5e3af8646b0670d",
         "type": "github"
       },
       "original": {
@@ -499,11 +499,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1743598667,
-        "narHash": "sha256-ViE7NoFWytYO2uJONTAX35eGsvTYXNHjWALeHAg8OQY=",
+        "lastModified": 1747274630,
+        "narHash": "sha256-87RJwXbfOHyzTB9LYagAQ6vOZhszCvd8Gvudu+gf3qo=",
         "owner": "nix-community",
         "repo": "disko",
-        "rev": "329d3d7e8bc63dd30c39e14e6076db590a6eabe6",
+        "rev": "ec7c109a4f794fce09aad87239eab7f66540b888",
         "type": "github"
       },
       "original": {
@@ -931,11 +931,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1739712626,
-        "narHash": "sha256-u3m+awbdL+0BKk8IWidsWMr+R0ian3GZMUlH7623kd8=",
+        "lastModified": 1746877938,
+        "narHash": "sha256-N9J96pSPg4vbozV+ZZ++dwLnMIf2Le6ONNMO0kZCj1M=",
         "owner": "reckenrode",
         "repo": "nix-foundryvtt",
-        "rev": "a7fa493ba2c623cf90e83756b62285b3b58f18d2",
+        "rev": "f1b401831d796dd94cf5a11b65fd169a199d4ff0",
         "type": "github"
       },
       "original": {
@@ -1278,11 +1278,11 @@
     },
     "nixpkgs-unstable": {
       "locked": {
-        "lastModified": 1743732435,
-        "narHash": "sha256-RrWgOj3F1N6kDG0xatvZzP0p1Zq00yhcTMlaj4bWi5E=",
+        "lastModified": 1747413287,
+        "narHash": "sha256-hOnqJr0tZBERWa29JWf9B3/8qr82mlt/UlKPvS7iYzA=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "a462b946265ed006720d02153882780b12a8376d",
+        "rev": "b965e4c283060415956ccd39eee4ca34a6a56cf8",
         "type": "github"
       },
       "original": {
@@ -1400,11 +1400,11 @@
     },
     "nixpkgs_6": {
       "locked": {
-        "lastModified": 1743703532,
-        "narHash": "sha256-s1KLDALEeqy+ttrvqV3jx9mBZEvmthQErTVOAzbjHZs=",
+        "lastModified": 1747418223,
+        "narHash": "sha256-DkCYFm09AR2+FPKcT7lD8iIMNXqTdesVvwKpCnqKiYg=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "bdb91860de2f719b57eef819b5617762f7120c70",
+        "rev": "d6c9326e40bb557ebb8c040b4375590bc06413f8",
         "type": "github"
       },
       "original": {
@@ -1727,11 +1727,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1743756170,
-        "narHash": "sha256-2b11EYa08oqDmF3zEBLkG1AoNn9rB1k39ew/T/mSvbU=",
+        "lastModified": 1746485181,
+        "narHash": "sha256-PxrrSFLaC7YuItShxmYbMgSuFFuwxBB+qsl9BZUnRvg=",
         "owner": "Mic92",
         "repo": "sops-nix",
-        "rev": "cff8437c5fe8c68fc3a840a21bf1f4dc801da40d",
+        "rev": "e93ee1d900ad264d65e9701a5c6f895683433386",
         "type": "github"
       },
       "original": {

From 1bef207356fce8770249aad33bc13ed16594ea19 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 17 May 2025 15:46:03 +0800
Subject: [PATCH 57/67] bump(crowdsec-up): Update hub

---
 pkgs/crowdsec/_sources/generated.json | 8 ++++----
 pkgs/crowdsec/_sources/generated.nix  | 8 ++++----
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/pkgs/crowdsec/_sources/generated.json b/pkgs/crowdsec/_sources/generated.json
index 97c4e87..f3c8f01 100644
--- a/pkgs/crowdsec/_sources/generated.json
+++ b/pkgs/crowdsec/_sources/generated.json
@@ -21,7 +21,7 @@
     },
     "crowdsec-hub": {
         "cargoLocks": null,
-        "date": "2025-04-04",
+        "date": "2025-05-17",
         "extract": null,
         "name": "crowdsec-hub",
         "passthru": null,
@@ -33,10 +33,10 @@
             "name": null,
             "owner": "crowdsecurity",
             "repo": "hub",
-            "rev": "eebc5f71379ea8f4de4a26f6695e0340444c719c",
-            "sha256": "sha256-/jhsqumekdOHDbHjBP8KvAICsSNhCg5ejMT3jSRiROo=",
+            "rev": "850614b9fcd4298f559b422c5ac685a69aa2e5ff",
+            "sha256": "sha256-96MMwFN5KongQA3YJVSuk7Kanbr1gR94CCyiflmez2k=",
             "type": "github"
         },
-        "version": "eebc5f71379ea8f4de4a26f6695e0340444c719c"
+        "version": "850614b9fcd4298f559b422c5ac685a69aa2e5ff"
     }
 }
\ No newline at end of file
diff --git a/pkgs/crowdsec/_sources/generated.nix b/pkgs/crowdsec/_sources/generated.nix
index aca88b2..19a7f5a 100644
--- a/pkgs/crowdsec/_sources/generated.nix
+++ b/pkgs/crowdsec/_sources/generated.nix
@@ -14,14 +14,14 @@
   };
   crowdsec-hub = {
     pname = "crowdsec-hub";
-    version = "eebc5f71379ea8f4de4a26f6695e0340444c719c";
+    version = "850614b9fcd4298f559b422c5ac685a69aa2e5ff";
     src = fetchFromGitHub {
       owner = "crowdsecurity";
       repo = "hub";
-      rev = "eebc5f71379ea8f4de4a26f6695e0340444c719c";
+      rev = "850614b9fcd4298f559b422c5ac685a69aa2e5ff";
       fetchSubmodules = false;
-      sha256 = "sha256-/jhsqumekdOHDbHjBP8KvAICsSNhCg5ejMT3jSRiROo=";
+      sha256 = "sha256-96MMwFN5KongQA3YJVSuk7Kanbr1gR94CCyiflmez2k=";
     };
-    date = "2025-04-04";
+    date = "2025-05-17";
   };
 }

From 09b90433e6d448b84540d8a1341dc2b089bbcd21 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 17 May 2025 15:46:26 +0800
Subject: [PATCH 58/67] feat(conduit): Switch from conduwuit to continuwuity

---
 configuration/services/conduit/default.nix |  2 +-
 flake.lock                                 | 59 +++++++++++-----------
 flake.nix                                  |  4 +-
 3 files changed, 33 insertions(+), 32 deletions(-)

diff --git a/configuration/services/conduit/default.nix b/configuration/services/conduit/default.nix
index 5a2b8ac..94d401a 100644
--- a/configuration/services/conduit/default.nix
+++ b/configuration/services/conduit/default.nix
@@ -20,7 +20,7 @@ in
 
   services.matrix-conduit = {
     enable = true;
-    package = flake-inputs.conduwuit.packages.${pkgs.system}.default;
+    package = flake-inputs.continuwuity.packages.${pkgs.system}.default;
     settings.global = {
       address = "127.0.0.1";
       server_name = domain;
diff --git a/flake.lock b/flake.lock
index 80f2bc5..c17c613 100644
--- a/flake.lock
+++ b/flake.lock
@@ -49,17 +49,17 @@
     "cachix_2": {
       "inputs": {
         "devenv": [
-          "conduwuit",
+          "continuwuity",
           "cachix",
           "devenv"
         ],
         "flake-compat": [
-          "conduwuit",
+          "continuwuity",
           "cachix",
           "devenv"
         ],
         "git-hooks": [
-          "conduwuit",
+          "continuwuity",
           "cachix",
           "devenv"
         ],
@@ -199,7 +199,7 @@
         "type": "github"
       }
     },
-    "conduwuit": {
+    "continuwuity": {
       "inputs": {
         "attic": "attic",
         "cachix": "cachix",
@@ -216,23 +216,24 @@
         "rocksdb": "rocksdb"
       },
       "locked": {
-        "lastModified": 1744169934,
-        "narHash": "sha256-5YyHmPUUrXXrczWayji9327knihVTKnmjX+vX6+p6d0=",
-        "owner": "girlbossceo",
-        "repo": "conduwuit",
-        "rev": "d8311a5ff672fdc4729d956af5e3af8646b0670d",
-        "type": "github"
+        "lastModified": 1745186840,
+        "narHash": "sha256-Oq2scBu3Ewao828BT1QGffqIqF5WoH9HMXEXKg1YU0o=",
+        "ref": "refs/tags/v0.5.0-rc.5",
+        "rev": "0a0f327ae034f5c44b12a3154cc1143aff10291c",
+        "revCount": 5147,
+        "type": "git",
+        "url": "https://forgejo.ellis.link/continuwuation/continuwuity.git"
       },
       "original": {
-        "owner": "girlbossceo",
-        "repo": "conduwuit",
-        "type": "github"
+        "ref": "refs/tags/v0.5.0-rc.5",
+        "type": "git",
+        "url": "https://forgejo.ellis.link/continuwuation/continuwuity.git"
       }
     },
     "crane": {
       "inputs": {
         "nixpkgs": [
-          "conduwuit",
+          "continuwuity",
           "attic",
           "nixpkgs"
         ]
@@ -390,18 +391,18 @@
       "inputs": {
         "cachix": "cachix_2",
         "flake-compat": [
-          "conduwuit",
+          "continuwuity",
           "cachix",
           "flake-compat"
         ],
         "git-hooks": [
-          "conduwuit",
+          "continuwuity",
           "cachix",
           "git-hooks"
         ],
         "nix": "nix",
         "nixpkgs": [
-          "conduwuit",
+          "continuwuity",
           "cachix",
           "nixpkgs"
         ]
@@ -535,7 +536,7 @@
     "fenix": {
       "inputs": {
         "nixpkgs": [
-          "conduwuit",
+          "continuwuity",
           "nixpkgs"
         ],
         "rust-analyzer-src": "rust-analyzer-src"
@@ -703,7 +704,7 @@
     "flake-parts": {
       "inputs": {
         "nixpkgs-lib": [
-          "conduwuit",
+          "continuwuity",
           "attic",
           "nixpkgs"
         ]
@@ -725,7 +726,7 @@
     "flake-parts_2": {
       "inputs": {
         "nixpkgs-lib": [
-          "conduwuit",
+          "continuwuity",
           "cachix",
           "devenv",
           "nix",
@@ -947,13 +948,13 @@
     "git-hooks": {
       "inputs": {
         "flake-compat": [
-          "conduwuit",
+          "continuwuity",
           "cachix",
           "flake-compat"
         ],
         "gitignore": "gitignore",
         "nixpkgs": [
-          "conduwuit",
+          "continuwuity",
           "cachix",
           "nixpkgs"
         ],
@@ -976,7 +977,7 @@
     "gitignore": {
       "inputs": {
         "nixpkgs": [
-          "conduwuit",
+          "continuwuity",
           "cachix",
           "git-hooks",
           "nixpkgs"
@@ -1104,7 +1105,7 @@
     "nix": {
       "inputs": {
         "flake-compat": [
-          "conduwuit",
+          "continuwuity",
           "cachix",
           "devenv"
         ],
@@ -1112,17 +1113,17 @@
         "libgit2": "libgit2",
         "nixpkgs": "nixpkgs_3",
         "nixpkgs-23-11": [
-          "conduwuit",
+          "continuwuity",
           "cachix",
           "devenv"
         ],
         "nixpkgs-regression": [
-          "conduwuit",
+          "continuwuity",
           "cachix",
           "devenv"
         ],
         "pre-commit-hooks": [
-          "conduwuit",
+          "continuwuity",
           "cachix",
           "devenv"
         ]
@@ -1161,7 +1162,7 @@
     "nix-github-actions": {
       "inputs": {
         "nixpkgs": [
-          "conduwuit",
+          "continuwuity",
           "attic",
           "nixpkgs"
         ]
@@ -1631,7 +1632,7 @@
     },
     "root": {
       "inputs": {
-        "conduwuit": "conduwuit",
+        "continuwuity": "continuwuity",
         "deploy-rs": "deploy-rs",
         "disko": "disko",
         "foundryvtt": "foundryvtt",
diff --git a/flake.nix b/flake.nix
index 4f17def..bdb60ed 100644
--- a/flake.nix
+++ b/flake.nix
@@ -4,8 +4,8 @@
   inputs = {
     nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11-small";
     nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable-small";
-    conduwuit = {
-      url = "github:girlbossceo/conduwuit";
+    continuwuity = {
+      url = "git+https://forgejo.ellis.link/continuwuation/continuwuity.git?ref=refs/tags/v0.5.0-rc.5";
       inputs.nixpkgs.follows = "nixpkgs";
     };
     disko = {

From fc991a0b07c2c1821bafd34fc0ffaff2b0bcc29f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Tue, 20 May 2025 01:06:44 +0800
Subject: [PATCH 59/67] fix(metrics-exporters): Fix dbus socket access for
 DynamicUsers

This broke the systemd exporter, I don't fully know what caused the
breakage, though.

See
https://discourse.nixos.org/t/systemd-exporter-couldnt-get-dbus-connection-read-unix-run-dbus-system-bus-socket-recvmsg-connection-reset-by-peer/
---
 configuration/services/metrics/exporters.nix | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/configuration/services/metrics/exporters.nix b/configuration/services/metrics/exporters.nix
index 78ba684..80a3480 100644
--- a/configuration/services/metrics/exporters.nix
+++ b/configuration/services/metrics/exporters.nix
@@ -97,4 +97,6 @@ in
     #   - postgres (?)
     #   - ssl_exporter (?)
   };
+
+  services.dbus.implementation = "broker";
 }

From 5c6b697e55e95e13f009cbcc4dcef4d070e83aee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Tue, 20 May 2025 20:37:05 +0800
Subject: [PATCH 60/67] feat(checks): Add linters

---
 checks/default.nix | 52 ++++++++++++++++++++++++++++++++++++++++++++++
 checks/lints.nu    | 39 ++++++++++++++++++++++++++++++++++
 flake.nix          |  2 +-
 3 files changed, 92 insertions(+), 1 deletion(-)
 create mode 100644 checks/default.nix
 create mode 100644 checks/lints.nu

diff --git a/checks/default.nix b/checks/default.nix
new file mode 100644
index 0000000..80279ba
--- /dev/null
+++ b/checks/default.nix
@@ -0,0 +1,52 @@
+{
+  self,
+  nixpkgs,
+  deploy-rs,
+  system,
+  ...
+}:
+let
+  pkgs = nixpkgs.legacyPackages.${system};
+
+  runNuCheck =
+    {
+      name,
+      packages,
+      check,
+    }:
+    pkgs.stdenvNoCC.mkDerivation {
+      inherit name;
+
+      src = nixpkgs.lib.cleanSourceWith {
+        src = self;
+        filter = nixpkgs.lib.cleanSourceFilter;
+      };
+
+      dontPatch = true;
+      dontConfigure = true;
+      dontBuild = true;
+      dontInstall = true;
+      dontFixup = true;
+      doCheck = true;
+
+      checkInputs = nixpkgs.lib.singleton pkgs.nushell ++ packages;
+
+      checkPhase = ''
+        nu ${check}
+      '';
+    };
+in
+nixpkgs.lib.recursiveUpdate {
+  lints = runNuCheck {
+    name = "lints";
+
+    packages = [
+      pkgs.deadnix
+      pkgs.nixfmt-rfc-style
+      pkgs.shellcheck
+      pkgs.statix
+    ];
+
+    check = ./lints.nu;
+  };
+} (deploy-rs.lib.${system}.deployChecks self.deploy)
diff --git a/checks/lints.nu b/checks/lints.nu
new file mode 100644
index 0000000..ffc2047
--- /dev/null
+++ b/checks/lints.nu
@@ -0,0 +1,39 @@
+#!/usr/bin/env nu
+
+let shell_files = ls **/*.sh | get name
+let nix_files = ls **/*.nix | where name !~ "hardware-configuration.nix|_sources" | get name
+
+let linters = [
+  ([shellcheck] ++ $shell_files)
+  ([nixfmt --check --strict] ++ $nix_files)
+  ([deadnix --fail] ++ $nix_files)
+  ([statix check] ++ $nix_files)
+]
+
+mkdir $env.out
+
+def run-linter [linterArgs: list<string>] {
+  print $'Running ($linterArgs.0)...'
+
+  let exit_code = try {
+    ^$linterArgs.0 ...($linterArgs | skip 1)
+    $env.LAST_EXIT_CODE
+  } catch {|e| $e.exit_code}
+
+  [$linterArgs.0, $exit_code]
+}
+
+let results = $linters | each {|linter| run-linter $linter}
+
+print 'Linter results:'
+
+let success = $results | each {|result|
+  match $result.1 {
+    0 => {print $'(ansi green)($result.0)(ansi reset)'}
+    _ => {print $'(ansi red)($result.0)(ansi reset)'}
+  }
+
+  $result.1
+} | math sum
+
+exit $success
diff --git a/flake.nix b/flake.nix
index bdb60ed..6747c24 100644
--- a/flake.nix
+++ b/flake.nix
@@ -96,7 +96,7 @@
       #########
       # Tests #
       #########
-      checks = builtins.mapAttrs (system: deployLib: deployLib.deployChecks self.deploy) deploy-rs.lib;
+      checks.${system} = import ./checks (inputs // { inherit system; });
 
       ###########################
       # Garbage collection root #

From 63b3cbe00be80ccb4b221aad64eb657ae5c96d70 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Tue, 20 May 2025 20:38:43 +0800
Subject: [PATCH 61/67] style(treewide): Apply linter suggestions

---
 checks/default.nix                            |  11 +-
 configuration/default.nix                     |  10 +-
 configuration/hardware-specific/vm.nix        |  35 +--
 configuration/nginx.nix                       |  78 ++---
 configuration/services/backups.nix            |   4 +-
 configuration/services/conduit/default.nix    | 286 +++++++++---------
 .../services/conduit/matrix-hookshot.nix      |  12 +-
 configuration/services/crowdsec.nix           |  16 +-
 configuration/services/foundryvtt.nix         |  58 ++--
 configuration/services/gitea.nix              | 114 +++----
 configuration/services/metrics/exporters.nix  |   2 +-
 configuration/services/metrics/options.nix    |  68 +++--
 .../services/metrics/victorialogs.nix         |   6 +-
 configuration/services/nextcloud.nix          | 152 +++++-----
 configuration/services/webserver.nix          |   2 +-
 flake.nix                                     |   2 -
 modules/crowdsec/default.nix                  |   4 +-
 .../remediations/cs-firewall-bouncer.nix      |  11 +-
 modules/crowdsec/remediations/default.nix     |   6 +-
 pkgs/crowdsec/hub.nix                         |   5 +-
 20 files changed, 432 insertions(+), 450 deletions(-)

diff --git a/checks/default.nix b/checks/default.nix
index 80279ba..f3db4ce 100644
--- a/checks/default.nix
+++ b/checks/default.nix
@@ -8,6 +8,15 @@
 let
   pkgs = nixpkgs.legacyPackages.${system};
 
+  statix' = pkgs.statix.overrideAttrs (old: {
+    patches = old.patches ++ [
+      (pkgs.fetchpatch {
+        url = "https://github.com/oppiliappan/statix/commit/925dec39bb705acbbe77178b4d658fe1b752abbb.patch";
+        hash = "sha256-0wacO6wuYJ4ufN9PGucRVJucFdFFNF+NoHYIrLXsCWs=";
+      })
+    ];
+  });
+
   runNuCheck =
     {
       name,
@@ -44,7 +53,7 @@ nixpkgs.lib.recursiveUpdate {
       pkgs.deadnix
       pkgs.nixfmt-rfc-style
       pkgs.shellcheck
-      pkgs.statix
+      statix'
     ];
 
     check = ./lints.nu;
diff --git a/configuration/default.nix b/configuration/default.nix
index 239f9f6..544e20c 100644
--- a/configuration/default.nix
+++ b/configuration/default.nix
@@ -1,7 +1,5 @@
 {
   config,
-  pkgs,
-  lib,
   modulesPath,
   flake-inputs,
   ...
@@ -31,13 +29,7 @@
     ./sops.nix
   ];
 
-  nixpkgs.overlays = [
-    (final: prev: {
-      local = import ../pkgs {
-        pkgs = prev;
-      };
-    })
-  ];
+  nixpkgs.overlays = [ (_: prev: { local = import ../pkgs { pkgs = prev; }; }) ];
 
   nix = {
     extraOptions = ''
diff --git a/configuration/hardware-specific/vm.nix b/configuration/hardware-specific/vm.nix
index db563fe..71870fb 100644
--- a/configuration/hardware-specific/vm.nix
+++ b/configuration/hardware-specific/vm.nix
@@ -6,26 +6,35 @@
   boot.kernelParams = [ "nomodeset" ];
 
   networking.hostName = "testvm";
-  # Sets the base domain for nginx to a local domain so that we can
-  # easily test locally with the VM.
-  services.nginx.domain = "dev.local";
+
+  services = {
+    # Sets the base domain for nginx to a local domain so that we can
+    # easily test locally with the VM.
+    nginx.domain = "dev.local";
+
+    # Don't run this
+    batteryManager.enable = lib.mkForce false;
+
+    openssh.hostKeys = lib.mkForce [
+      {
+        type = "rsa";
+        bits = 4096;
+        path = "/etc/staging.key";
+      }
+    ];
+  };
 
   # Use the staging secrets
   sops.defaultSopsFile = lib.mkOverride 99 ../../keys/staging.yaml;
 
   systemd.network.networks."10-eth0" = {
     matchConfig.Name = "eth0";
-    gateway = [
-      "192.168.9.1"
-    ];
+    gateway = [ "192.168.9.1" ];
     networkConfig = {
       Address = "192.168.9.2/24";
     };
   };
 
-  # Don't run this
-  services.batteryManager.enable = lib.mkForce false;
-
   # Both so we have a predictable key for the staging env, as well as
   # to have a static key for decrypting the sops secrets for the
   # staging env.
@@ -34,14 +43,6 @@
     source = ../../keys/hosts/staging.key;
   };
 
-  services.openssh.hostKeys = lib.mkForce [
-    {
-      type = "rsa";
-      bits = 4096;
-      path = "/etc/staging.key";
-    }
-  ];
-
   virtualisation.vmVariant = {
     virtualisation = {
       memorySize = 3941;
diff --git a/configuration/nginx.nix b/configuration/nginx.nix
index 3ec3bd9..3abef7f 100644
--- a/configuration/nginx.nix
+++ b/configuration/nginx.nix
@@ -1,40 +1,49 @@
 { config, lib, ... }:
 {
-  services.nginx = {
-    enable = true;
-    recommendedTlsSettings = true;
-    recommendedOptimisation = true;
-    recommendedGzipSettings = true;
-    recommendedProxySettings = true;
-    clientMaxBodySize = "10G";
+  services = {
+    nginx = {
+      enable = true;
+      recommendedTlsSettings = true;
+      recommendedOptimisation = true;
+      recommendedGzipSettings = true;
+      recommendedProxySettings = true;
+      clientMaxBodySize = "10G";
 
-    statusPage = true; # For metrics, should be accessible only from localhost
+      statusPage = true; # For metrics, should be accessible only from localhost
 
-    commonHttpConfig = ''
-      log_format upstream_time '$remote_addr - $remote_user [$time_local] '
-                         '"$request" $status $body_bytes_sent '
-                         '"$http_referer" "$http_user_agent" '
-                         'rt=$request_time uct="$upstream_connect_time" '
-                         'uht="$upstream_header_time" urt="$upstream_response_time"';
-    '';
-  };
+      commonHttpConfig = ''
+        log_format upstream_time '$remote_addr - $remote_user [$time_local] '
+                           '"$request" $status $body_bytes_sent '
+                           '"$http_referer" "$http_user_agent" '
+                           'rt=$request_time uct="$upstream_connect_time" '
+                           'uht="$upstream_header_time" urt="$upstream_response_time"';
+      '';
+    };
 
-  services.logrotate.settings =
-    {
-      # Override the default, just keep fewer logs
-      nginx.rotate = 6;
-    }
-    // lib.mapAttrs' (
-      virtualHost: _:
-      lib.nameValuePair "/var/log/nginx/${virtualHost}/access.log" {
-        frequency = "daily";
-        rotate = 2;
-        compress = true;
-        delaycompress = true;
-        su = "${config.services.nginx.user} ${config.services.nginx.group}";
-        postrotate = "[ ! -f /var/run/nginx/nginx.pid ] || kill -USR1 `cat /var/run/nginx/nginx.pid`";
+    logrotate.settings =
+      {
+        # Override the default, just keep fewer logs
+        nginx.rotate = 6;
       }
-    ) config.services.nginx.virtualHosts;
+      // lib.mapAttrs' (
+        virtualHost: _:
+        lib.nameValuePair "/var/log/nginx/${virtualHost}/access.log" {
+          frequency = "daily";
+          rotate = 2;
+          compress = true;
+          delaycompress = true;
+          su = "${config.services.nginx.user} ${config.services.nginx.group}";
+          postrotate = "[ ! -f /var/run/nginx/nginx.pid ] || kill -USR1 `cat /var/run/nginx/nginx.pid`";
+        }
+      ) config.services.nginx.virtualHosts;
+
+    backups.acme = {
+      user = "acme";
+      paths = lib.mapAttrsToList (
+        virtualHost: _: "/var/lib/acme/${virtualHost}"
+      ) config.services.nginx.virtualHosts;
+    };
+  };
 
   systemd.tmpfiles.rules = lib.mapAttrsToList (
     virtualHost: _:
@@ -66,11 +75,4 @@
   systemd.services.nginx.serviceConfig.SupplementaryGroups = [
     config.security.acme.certs."tlater.net".group
   ];
-
-  services.backups.acme = {
-    user = "acme";
-    paths = lib.mapAttrsToList (
-      virtualHost: _: "/var/lib/acme/${virtualHost}"
-    ) config.services.nginx.virtualHosts;
-  };
 }
diff --git a/configuration/services/backups.nix b/configuration/services/backups.nix
index 81e3554..baa61e3 100644
--- a/configuration/services/backups.nix
+++ b/configuration/services/backups.nix
@@ -57,7 +57,7 @@ in
       '';
       type = types.attrsOf (
         types.submodule (
-          { config, name, ... }:
+          { name, ... }:
           {
             options = {
               user = lib.mkOption {
@@ -246,7 +246,7 @@ in
         };
       }
       // lib.mapAttrs' (
-        name: backup:
+        name: _:
         lib.nameValuePair "backup-${name}" {
           wantedBy = [ "timers.target" ];
           timerConfig = {
diff --git a/configuration/services/conduit/default.nix b/configuration/services/conduit/default.nix
index 94d401a..58abc49 100644
--- a/configuration/services/conduit/default.nix
+++ b/configuration/services/conduit/default.nix
@@ -18,33 +18,153 @@ in
     ./matrix-hookshot.nix
   ];
 
-  services.matrix-conduit = {
-    enable = true;
-    package = flake-inputs.continuwuity.packages.${pkgs.system}.default;
-    settings.global = {
-      address = "127.0.0.1";
-      server_name = domain;
-      new_user_displayname_suffix = "🦆";
-      allow_check_for_updates = true;
+  services = {
+    matrix-conduit = {
+      enable = true;
+      package = flake-inputs.continuwuity.packages.${pkgs.system}.default;
+      settings.global = {
+        address = "127.0.0.1";
+        server_name = domain;
+        new_user_displayname_suffix = "🦆";
+        allow_check_for_updates = true;
 
-      # Set up delegation: https://docs.conduit.rs/delegation.html#automatic-recommended
-      # This is primarily to make sliding sync work
-      well_known = {
-        client = "https://${domain}";
-        server = "${domain}:443";
+        # Set up delegation: https://docs.conduit.rs/delegation.html#automatic-recommended
+        # This is primarily to make sliding sync work
+        well_known = {
+          client = "https://${domain}";
+          server = "${domain}:443";
+        };
+
+        turn_uris =
+          let
+            address = "${config.services.coturn.realm}:${toString config.services.coturn.listening-port}";
+            tls-address = "${config.services.coturn.realm}:${toString config.services.coturn.tls-listening-port}";
+          in
+          [
+            "turn:${address}?transport=udp"
+            "turn:${address}?transport=tcp"
+            "turns:${tls-address}?transport=udp"
+            "turns:${tls-address}?transport=tcp"
+          ];
       };
+    };
 
-      turn_uris =
-        let
-          address = "${config.services.coturn.realm}:${toString config.services.coturn.listening-port}";
-          tls-address = "${config.services.coturn.realm}:${toString config.services.coturn.tls-listening-port}";
-        in
-        [
-          "turn:${address}?transport=udp"
-          "turn:${address}?transport=tcp"
-          "turns:${tls-address}?transport=udp"
-          "turns:${tls-address}?transport=tcp"
-        ];
+    coturn = {
+      enable = true;
+      no-cli = true;
+      use-auth-secret = true;
+      static-auth-secret-file = config.sops.secrets."turn/secret".path;
+      realm = turn-realm;
+      relay-ips = [ "116.202.158.55" ];
+
+      # SSL config
+      pkey = "${config.security.acme.certs."tlater.net".directory}/key.pem";
+      cert = "${config.security.acme.certs."tlater.net".directory}/fullchain.pem";
+
+      # Based on suggestions from
+      # https://github.com/matrix-org/synapse/blob/develop/docs/turn-howto.md
+      # and
+      # https://www.foxypossibilities.com/2018/05/19/setting-up-a-turn-sever-for-matrix-on-nixos/
+      no-tcp-relay = true;
+      secure-stun = true;
+      extraConfig = ''
+        # Deny various local IP ranges, see
+        # https://www.rtcsec.com/article/cve-2020-26262-bypass-of-coturns-access-control-protection/
+        no-multicast-peers
+        denied-peer-ip=0.0.0.0-0.255.255.255
+        denied-peer-ip=10.0.0.0-10.255.255.255
+        denied-peer-ip=100.64.0.0-100.127.255.255
+        denied-peer-ip=127.0.0.0-127.255.255.255
+        denied-peer-ip=169.254.0.0-169.254.255.255
+        denied-peer-ip=172.16.0.0-172.31.255.255
+        denied-peer-ip=192.0.0.0-192.0.0.255
+        denied-peer-ip=192.0.2.0-192.0.2.255
+        denied-peer-ip=192.88.99.0-192.88.99.255
+        denied-peer-ip=192.168.0.0-192.168.255.255
+        denied-peer-ip=198.18.0.0-198.19.255.255
+        denied-peer-ip=198.51.100.0-198.51.100.255
+        denied-peer-ip=203.0.113.0-203.0.113.255
+        denied-peer-ip=240.0.0.0-255.255.255.255 denied-peer-ip=::1
+        denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff
+        denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255
+        denied-peer-ip=100::-100::ffff:ffff:ffff:ffff
+        denied-peer-ip=2001::-2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff
+        denied-peer-ip=2002::-2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+        denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+        denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+
+        # *Allow* any IP addresses that we explicitly set as relay IPs
+        ${concatMapStringsSep "\n" (ip: "allowed-peer-ip=${ip}") config.services.coturn.relay-ips}
+
+        # Various other security settings
+        no-tlsv1
+        no-tlsv1_1
+
+        # Monitoring
+        prometheus
+      '';
+    };
+
+    nginx.virtualHosts."${domain}" = {
+      useACMEHost = "tlater.net";
+
+      listen = [
+        {
+          addr = "0.0.0.0";
+          port = 80;
+        }
+        {
+          addr = "[::0]";
+          port = 80;
+        }
+        {
+          addr = "0.0.0.0";
+          port = 443;
+          ssl = true;
+        }
+        {
+          addr = "[::0]";
+          port = 443;
+          ssl = true;
+        }
+        {
+          addr = "0.0.0.0";
+          port = 8448;
+          ssl = true;
+        }
+        {
+          addr = "[::0]";
+          port = 8448;
+          ssl = true;
+        }
+      ];
+
+      forceSSL = true;
+      enableHSTS = true;
+      extraConfig = ''
+        merge_slashes off;
+      '';
+
+      locations = {
+        "/_matrix" = {
+          proxyPass = "http://${cfg.settings.global.address}:${toString cfg.settings.global.port}";
+          # Recommended by conduit
+          extraConfig = ''
+            proxy_buffering off;
+          '';
+        };
+        "/.well-known/matrix" = {
+          proxyPass = "http://${cfg.settings.global.address}:${toString cfg.settings.global.port}";
+        };
+      };
+    };
+
+    backups.conduit = {
+      user = "root";
+      paths = [ "/var/lib/private/matrix-conduit/" ];
+      # Other services store their data in conduit, so no other services
+      # need to be shut down currently.
+      pauseServices = [ "conduit.service" ];
     };
   };
 
@@ -60,122 +180,4 @@ in
   systemd.services.coturn.serviceConfig.SupplementaryGroups = [
     config.security.acme.certs."tlater.net".group
   ];
-
-  services.coturn = {
-    enable = true;
-    no-cli = true;
-    use-auth-secret = true;
-    static-auth-secret-file = config.sops.secrets."turn/secret".path;
-    realm = turn-realm;
-    relay-ips = [ "116.202.158.55" ];
-
-    # SSL config
-    pkey = "${config.security.acme.certs."tlater.net".directory}/key.pem";
-    cert = "${config.security.acme.certs."tlater.net".directory}/fullchain.pem";
-
-    # Based on suggestions from
-    # https://github.com/matrix-org/synapse/blob/develop/docs/turn-howto.md
-    # and
-    # https://www.foxypossibilities.com/2018/05/19/setting-up-a-turn-sever-for-matrix-on-nixos/
-    no-tcp-relay = true;
-    secure-stun = true;
-    extraConfig = ''
-      # Deny various local IP ranges, see
-      # https://www.rtcsec.com/article/cve-2020-26262-bypass-of-coturns-access-control-protection/
-      no-multicast-peers
-      denied-peer-ip=0.0.0.0-0.255.255.255
-      denied-peer-ip=10.0.0.0-10.255.255.255
-      denied-peer-ip=100.64.0.0-100.127.255.255
-      denied-peer-ip=127.0.0.0-127.255.255.255
-      denied-peer-ip=169.254.0.0-169.254.255.255
-      denied-peer-ip=172.16.0.0-172.31.255.255
-      denied-peer-ip=192.0.0.0-192.0.0.255
-      denied-peer-ip=192.0.2.0-192.0.2.255
-      denied-peer-ip=192.88.99.0-192.88.99.255
-      denied-peer-ip=192.168.0.0-192.168.255.255
-      denied-peer-ip=198.18.0.0-198.19.255.255
-      denied-peer-ip=198.51.100.0-198.51.100.255
-      denied-peer-ip=203.0.113.0-203.0.113.255
-      denied-peer-ip=240.0.0.0-255.255.255.255 denied-peer-ip=::1
-      denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff
-      denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255
-      denied-peer-ip=100::-100::ffff:ffff:ffff:ffff
-      denied-peer-ip=2001::-2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff
-      denied-peer-ip=2002::-2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff
-      denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
-      denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff
-
-      # *Allow* any IP addresses that we explicitly set as relay IPs
-      ${concatMapStringsSep "\n" (ip: "allowed-peer-ip=${ip}") config.services.coturn.relay-ips}
-
-      # Various other security settings
-      no-tlsv1
-      no-tlsv1_1
-
-      # Monitoring
-      prometheus
-    '';
-  };
-
-  services.nginx.virtualHosts."${domain}" = {
-    useACMEHost = "tlater.net";
-
-    listen = [
-      {
-        addr = "0.0.0.0";
-        port = 80;
-      }
-      {
-        addr = "[::0]";
-        port = 80;
-      }
-      {
-        addr = "0.0.0.0";
-        port = 443;
-        ssl = true;
-      }
-      {
-        addr = "[::0]";
-        port = 443;
-        ssl = true;
-      }
-      {
-        addr = "0.0.0.0";
-        port = 8448;
-        ssl = true;
-      }
-      {
-        addr = "[::0]";
-        port = 8448;
-        ssl = true;
-      }
-    ];
-
-    forceSSL = true;
-    enableHSTS = true;
-    extraConfig = ''
-      merge_slashes off;
-    '';
-
-    locations = {
-      "/_matrix" = {
-        proxyPass = "http://${cfg.settings.global.address}:${toString cfg.settings.global.port}";
-        # Recommended by conduit
-        extraConfig = ''
-          proxy_buffering off;
-        '';
-      };
-      "/.well-known/matrix" = {
-        proxyPass = "http://${cfg.settings.global.address}:${toString cfg.settings.global.port}";
-      };
-    };
-  };
-
-  services.backups.conduit = {
-    user = "root";
-    paths = [ "/var/lib/private/matrix-conduit/" ];
-    # Other services store their data in conduit, so no other services
-    # need to be shut down currently.
-    pauseServices = [ "conduit.service" ];
-  };
 }
diff --git a/configuration/services/conduit/matrix-hookshot.nix b/configuration/services/conduit/matrix-hookshot.nix
index c1f16dc..6846d99 100644
--- a/configuration/services/conduit/matrix-hookshot.nix
+++ b/configuration/services/conduit/matrix-hookshot.nix
@@ -74,9 +74,7 @@ in
   services.matrix-hookshot = {
     enable = true;
 
-    serviceDependencies = [
-      "conduit.service"
-    ];
+    serviceDependencies = [ "conduit.service" ];
 
     registrationFile = "/run/matrix-hookshot/registration.yaml";
 
@@ -126,15 +124,11 @@ in
       listeners = [
         {
           port = 9000;
-          resources = [
-            "webhooks"
-          ];
+          resources = [ "webhooks" ];
         }
         {
           port = 9001;
-          resources = [
-            "metrics"
-          ];
+          resources = [ "metrics" ];
         }
       ];
 
diff --git a/configuration/services/crowdsec.nix b/configuration/services/crowdsec.nix
index 6e0f367..b736047 100644
--- a/configuration/services/crowdsec.nix
+++ b/configuration/services/crowdsec.nix
@@ -8,9 +8,7 @@
   security.crowdsec = {
     enable = true;
 
-    parserWhitelist = [
-      "10.45.249.2"
-    ];
+    parserWhitelist = [ "10.45.249.2" ];
 
     extraGroups = [
       "systemd-journal"
@@ -21,25 +19,19 @@
       {
         source = "journalctl";
         labels.type = "syslog";
-        journalctl_filter = [
-          "SYSLOG_IDENTIFIER=Nextcloud"
-        ];
+        journalctl_filter = [ "SYSLOG_IDENTIFIER=Nextcloud" ];
       }
 
       {
         source = "journalctl";
         labels.type = "syslog";
-        journalctl_filter = [
-          "SYSLOG_IDENTIFIER=sshd-session"
-        ];
+        journalctl_filter = [ "SYSLOG_IDENTIFIER=sshd-session" ];
       }
 
       {
         labels.type = "nginx";
         filenames =
-          [
-            "/var/log/nginx/*.log"
-          ]
+          [ "/var/log/nginx/*.log" ]
           ++ lib.mapAttrsToList (
             vHost: _: "/var/log/nginx/${vHost}/access.log"
           ) config.services.nginx.virtualHosts;
diff --git a/configuration/services/foundryvtt.nix b/configuration/services/foundryvtt.nix
index 614b818..f25bbcd 100644
--- a/configuration/services/foundryvtt.nix
+++ b/configuration/services/foundryvtt.nix
@@ -11,37 +11,39 @@ in
 {
   imports = [ flake-inputs.foundryvtt.nixosModules.foundryvtt ];
 
-  services.foundryvtt = {
-    enable = true;
-    hostName = domain;
-    minifyStaticFiles = true;
-    proxySSL = true;
-    proxyPort = 443;
-    package = flake-inputs.foundryvtt.packages.${pkgs.system}.foundryvtt_11;
+  services = {
+    foundryvtt = {
+      enable = true;
+      hostName = domain;
+      minifyStaticFiles = true;
+      proxySSL = true;
+      proxyPort = 443;
+      package = flake-inputs.foundryvtt.packages.${pkgs.system}.foundryvtt_11;
+    };
+
+    nginx.virtualHosts."${domain}" =
+      let
+        inherit (config.services.foundryvtt) port;
+      in
+      {
+        forceSSL = true;
+        useACMEHost = "tlater.net";
+        enableHSTS = true;
+
+        locations."/" = {
+          proxyWebsockets = true;
+          proxyPass = "http://localhost:${toString port}";
+        };
+      };
+
+    backups.foundryvtt = {
+      user = "foundryvtt";
+      paths = [ config.services.foundryvtt.dataDir ];
+      pauseServices = [ "foundryvtt.service" ];
+    };
   };
 
   # Want to start it manually when I need it, not have it constantly
   # running
   systemd.services.foundryvtt.wantedBy = lib.mkForce [ ];
-
-  services.nginx.virtualHosts."${domain}" =
-    let
-      inherit (config.services.foundryvtt) port;
-    in
-    {
-      forceSSL = true;
-      useACMEHost = "tlater.net";
-      enableHSTS = true;
-
-      locations."/" = {
-        proxyWebsockets = true;
-        proxyPass = "http://localhost:${toString port}";
-      };
-    };
-
-  services.backups.foundryvtt = {
-    user = "foundryvtt";
-    paths = [ config.services.foundryvtt.dataDir ];
-    pauseServices = [ "foundryvtt.service" ];
-  };
 }
diff --git a/configuration/services/gitea.nix b/configuration/services/gitea.nix
index da01cde..613d30c 100644
--- a/configuration/services/gitea.nix
+++ b/configuration/services/gitea.nix
@@ -8,24 +8,68 @@ let
   domain = "gitea.${config.services.nginx.domain}";
 in
 {
-  services.forgejo = {
-    enable = true;
-    database.type = "postgres";
+  services = {
+    forgejo = {
+      enable = true;
+      database.type = "postgres";
 
-    settings = {
-      server = {
-        DOMAIN = domain;
-        HTTP_ADDR = "127.0.0.1";
-        ROOT_URL = "https://${domain}/";
-        SSH_PORT = 2222;
+      settings = {
+        server = {
+          DOMAIN = domain;
+          HTTP_ADDR = "127.0.0.1";
+          ROOT_URL = "https://${domain}/";
+          SSH_PORT = 2222;
+        };
+
+        metrics = {
+          ENABLED = true;
+          TOKEN = "#metricstoken#";
+        };
+        service.DISABLE_REGISTRATION = true;
+        session.COOKIE_SECURE = true;
+      };
+    };
+
+    # Set up SSL
+    nginx.virtualHosts."${domain}" =
+      let
+        httpAddress = config.services.forgejo.settings.server.HTTP_ADDR;
+        httpPort = config.services.forgejo.settings.server.HTTP_PORT;
+      in
+      {
+        forceSSL = true;
+        useACMEHost = "tlater.net";
+        enableHSTS = true;
+
+        locations."/".proxyPass = "http://${httpAddress}:${toString httpPort}";
+        locations."/metrics" = {
+          extraConfig = ''
+            access_log off;
+            allow 127.0.0.1;
+            ${lib.optionalString config.networking.enableIPv6 "allow ::1;"}
+            deny all;
+          '';
+        };
       };
 
-      metrics = {
-        ENABLED = true;
-        TOKEN = "#metricstoken#";
+    backups.forgejo = {
+      user = "forgejo";
+      paths = [
+        "/var/lib/forgejo/forgejo-db.sql"
+        "/var/lib/forgejo/repositories/"
+        "/var/lib/forgejo/data/"
+        "/var/lib/forgejo/custom/"
+        # Conf is backed up via nix
+      ];
+      preparation = {
+        packages = [ config.services.postgresql.package ];
+        text = "pg_dump ${config.services.forgejo.database.name} --file=/var/lib/forgejo/forgejo-db.sql";
       };
-      service.DISABLE_REGISTRATION = true;
-      session.COOKIE_SECURE = true;
+      cleanup = {
+        packages = [ pkgs.coreutils ];
+        text = "rm /var/lib/forgejo/forgejo-db.sql";
+      };
+      pauseServices = [ "forgejo.service" ];
     };
   };
 
@@ -36,46 +80,4 @@ in
       runConfig = "${config.services.forgejo.customDir}/conf/app.ini";
     in
     [ "+${replaceSecretBin} '#metricstoken#' '${secretPath}' '${runConfig}'" ];
-
-  # Set up SSL
-  services.nginx.virtualHosts."${domain}" =
-    let
-      httpAddress = config.services.forgejo.settings.server.HTTP_ADDR;
-      httpPort = config.services.forgejo.settings.server.HTTP_PORT;
-    in
-    {
-      forceSSL = true;
-      useACMEHost = "tlater.net";
-      enableHSTS = true;
-
-      locations."/".proxyPass = "http://${httpAddress}:${toString httpPort}";
-      locations."/metrics" = {
-        extraConfig = ''
-          access_log off;
-          allow 127.0.0.1;
-          ${lib.optionalString config.networking.enableIPv6 "allow ::1;"}
-          deny all;
-        '';
-      };
-    };
-
-  services.backups.forgejo = {
-    user = "forgejo";
-    paths = [
-      "/var/lib/forgejo/forgejo-db.sql"
-      "/var/lib/forgejo/repositories/"
-      "/var/lib/forgejo/data/"
-      "/var/lib/forgejo/custom/"
-      # Conf is backed up via nix
-    ];
-    preparation = {
-      packages = [ config.services.postgresql.package ];
-      text = "pg_dump ${config.services.forgejo.database.name} --file=/var/lib/forgejo/forgejo-db.sql";
-    };
-    cleanup = {
-      packages = [ pkgs.coreutils ];
-      text = "rm /var/lib/forgejo/forgejo-db.sql";
-    };
-    pauseServices = [ "forgejo.service" ];
-  };
 }
diff --git a/configuration/services/metrics/exporters.nix b/configuration/services/metrics/exporters.nix
index 80a3480..52c2a46 100644
--- a/configuration/services/metrics/exporters.nix
+++ b/configuration/services/metrics/exporters.nix
@@ -74,7 +74,7 @@ in
         listenAddress = "127.0.0.1";
         group = "nginx";
 
-        settings.namespaces = lib.mapAttrsToList (name: virtualHost: {
+        settings.namespaces = lib.mapAttrsToList (name: _: {
           inherit name;
           metrics_override.prefix = "nginxlog";
           namespace_label = "vhost";
diff --git a/configuration/services/metrics/options.nix b/configuration/services/metrics/options.nix
index d69ecfb..e1b0761 100644
--- a/configuration/services/metrics/options.nix
+++ b/configuration/services/metrics/options.nix
@@ -38,7 +38,7 @@ in
     services.victoriametrics.scrapeConfigs = mkOption {
       type = types.attrsOf (
         types.submodule (
-          { name, self, ... }:
+          { name, ... }:
           {
             options = {
               job_name = mkOption {
@@ -106,35 +106,37 @@ in
               # module is an intractable mess
               wantedBy = [ "multi-user.target" ];
               after = [ "network.target" ];
-              serviceConfig.Restart = mkDefault "always";
-              serviceConfig.PrivateTmp = mkDefault true;
-              serviceConfig.WorkingDirectory = mkDefault /tmp;
-              serviceConfig.DynamicUser = mkDefault true;
-              # Hardening
-              serviceConfig.CapabilityBoundingSet = mkDefault [ "" ];
-              serviceConfig.DeviceAllow = [ "" ];
-              serviceConfig.LockPersonality = true;
-              serviceConfig.MemoryDenyWriteExecute = true;
-              serviceConfig.NoNewPrivileges = true;
-              serviceConfig.PrivateDevices = mkDefault true;
-              serviceConfig.ProtectClock = mkDefault true;
-              serviceConfig.ProtectControlGroups = true;
-              serviceConfig.ProtectHome = true;
-              serviceConfig.ProtectHostname = true;
-              serviceConfig.ProtectKernelLogs = true;
-              serviceConfig.ProtectKernelModules = true;
-              serviceConfig.ProtectKernelTunables = true;
-              serviceConfig.ProtectSystem = mkDefault "strict";
-              serviceConfig.RemoveIPC = true;
-              serviceConfig.RestrictAddressFamilies = [
-                "AF_INET"
-                "AF_INET6"
-              ];
-              serviceConfig.RestrictNamespaces = true;
-              serviceConfig.RestrictRealtime = true;
-              serviceConfig.RestrictSUIDSGID = true;
-              serviceConfig.SystemCallArchitectures = "native";
-              serviceConfig.UMask = "0077";
+              serviceConfig = {
+                Restart = mkDefault "always";
+                PrivateTmp = mkDefault true;
+                WorkingDirectory = mkDefault /tmp;
+                DynamicUser = mkDefault true;
+                # Hardening
+                CapabilityBoundingSet = mkDefault [ "" ];
+                DeviceAllow = [ "" ];
+                LockPersonality = true;
+                MemoryDenyWriteExecute = true;
+                NoNewPrivileges = true;
+                PrivateDevices = mkDefault true;
+                ProtectClock = mkDefault true;
+                ProtectControlGroups = true;
+                ProtectHome = true;
+                ProtectHostname = true;
+                ProtectKernelLogs = true;
+                ProtectKernelModules = true;
+                ProtectKernelTunables = true;
+                ProtectSystem = mkDefault "strict";
+                RemoveIPC = true;
+                RestrictAddressFamilies = [
+                  "AF_INET"
+                  "AF_INET6"
+                ];
+                RestrictNamespaces = true;
+                RestrictRealtime = true;
+                RestrictSUIDSGID = true;
+                SystemCallArchitectures = "native";
+                UMask = "0077";
+              };
             }
             exporter.serviceOpts
           ]
@@ -144,7 +146,7 @@ in
       {
         vmagent-scrape-exporters =
           let
-            listenAddress = config.services.victoriametrics.listenAddress;
+            inherit (config.services.victoriametrics) listenAddress;
             vmAddr = (lib.optionalString (lib.hasPrefix ":" listenAddress) "127.0.0.1") + listenAddress;
             promscrape = yaml.generate "prometheus.yml" {
               scrape_configs = lib.mapAttrsToList (
@@ -153,7 +155,7 @@ in
                   inherit (scrape) job_name;
                   static_configs =
                     scrape.static_configs
-                    ++ lib.optional (scrape.targets != [ ]) { targets = scrape.targets; };
+                    ++ lib.optional (scrape.targets != [ ]) { inherit (scrape) targets; };
                 } scrape.extraSettings
               ) config.services.victoriametrics.scrapeConfigs;
             };
@@ -212,7 +214,7 @@ in
 
     services.victoriametrics.scrapeConfigs =
       let
-        allExporters = lib.mapAttrs (name: exporter: { inherit (exporter) listenAddress port; }) (
+        allExporters = lib.mapAttrs (_: exporter: { inherit (exporter) listenAddress port; }) (
           (lib.filterAttrs (
             name: exporter:
             # A bunch of deprecated exporters that need to be ignored
diff --git a/configuration/services/metrics/victorialogs.nix b/configuration/services/metrics/victorialogs.nix
index ae47c39..413659a 100644
--- a/configuration/services/metrics/victorialogs.nix
+++ b/configuration/services/metrics/victorialogs.nix
@@ -1,8 +1,4 @@
-{
-  config,
-  lib,
-  ...
-}:
+{ config, lib, ... }:
 let
   cfg = config.services.victorialogs;
 in
diff --git a/configuration/services/nextcloud.nix b/configuration/services/nextcloud.nix
index b5cb691..2f8fa76 100644
--- a/configuration/services/nextcloud.nix
+++ b/configuration/services/nextcloud.nix
@@ -9,93 +9,95 @@ let
   hostName = "nextcloud.${config.services.nginx.domain}";
 in
 {
-  services.nextcloud = {
-    inherit hostName;
+  services = {
+    nextcloud = {
+      inherit hostName;
 
-    package = nextcloud;
-    phpPackage = lib.mkForce (
-      pkgs.php.override {
-        packageOverrides = final: prev: {
-          extensions = prev.extensions // {
-            pgsql = prev.extensions.pgsql.overrideAttrs (old: {
-              configureFlags = [ "--with-pgsql=${lib.getDev config.services.postgresql.package}" ];
-            });
-            pdo_pgsql = prev.extensions.pdo_pgsql.overrideAttrs (old: {
-              configureFlags = [ "--with-pdo-pgsql=${lib.getDev config.services.postgresql.package}" ];
-            });
+      package = nextcloud;
+      phpPackage = lib.mkForce (
+        pkgs.php.override {
+          packageOverrides = _: prev: {
+            extensions = prev.extensions // {
+              pgsql = prev.extensions.pgsql.overrideAttrs (_: {
+                configureFlags = [ "--with-pgsql=${lib.getDev config.services.postgresql.package}" ];
+              });
+              pdo_pgsql = prev.extensions.pdo_pgsql.overrideAttrs (_: {
+                configureFlags = [ "--with-pdo-pgsql=${lib.getDev config.services.postgresql.package}" ];
+              });
+            };
           };
-        };
-      }
-    );
-    enable = true;
-    maxUploadSize = "2G";
-    https = true;
+        }
+      );
+      enable = true;
+      maxUploadSize = "2G";
+      https = true;
 
-    configureRedis = true;
+      configureRedis = true;
 
-    config = {
-      dbtype = "pgsql";
-      dbhost = "/run/postgresql";
+      config = {
+        dbtype = "pgsql";
+        dbhost = "/run/postgresql";
 
-      adminuser = "tlater";
-      adminpassFile = config.sops.secrets."nextcloud/tlater".path;
+        adminuser = "tlater";
+        adminpassFile = config.sops.secrets."nextcloud/tlater".path;
+      };
+
+      settings = {
+        default_phone_region = "AT";
+        overwriteprotocol = "https";
+      };
+
+      phpOptions = {
+        "opcache.interned_strings_buffer" = "16";
+      };
+
+      extraApps = {
+        inherit (config.services.nextcloud.package.packages.apps)
+          calendar
+          contacts
+          cookbook
+          news
+          ;
+      };
     };
 
-    settings = {
-      default_phone_region = "AT";
-      overwriteprotocol = "https";
+    # Set up SSL
+    nginx.virtualHosts."${hostName}" = {
+      forceSSL = true;
+      useACMEHost = "tlater.net";
+      # The upstream module already adds HSTS
     };
 
-    phpOptions = {
-      "opcache.interned_strings_buffer" = "16";
-    };
-
-    extraApps = {
-      inherit (config.services.nextcloud.package.packages.apps)
-        calendar
-        contacts
-        cookbook
-        news
-        ;
+    backups.nextcloud = {
+      user = "nextcloud";
+      paths = [
+        "/var/lib/nextcloud/nextcloud-db.sql"
+        "/var/lib/nextcloud/data/"
+        "/var/lib/nextcloud/config/config.php"
+      ];
+      preparation = {
+        packages = [
+          config.services.postgresql.package
+          config.services.nextcloud.occ
+        ];
+        text = ''
+          nextcloud-occ maintenance:mode --on
+          pg_dump ${config.services.nextcloud.config.dbname} --file=/var/lib/nextcloud/nextcloud-db.sql
+        '';
+      };
+      cleanup = {
+        packages = [
+          pkgs.coreutils
+          config.services.nextcloud.occ
+        ];
+        text = ''
+          rm /var/lib/nextcloud/nextcloud-db.sql
+          nextcloud-occ maintenance:mode --off
+        '';
+      };
     };
   };
 
   # Ensure that this service doesn't start before postgres is ready
   systemd.services.nextcloud-setup.after = [ "postgresql.service" ];
-
-  # Set up SSL
-  services.nginx.virtualHosts."${hostName}" = {
-    forceSSL = true;
-    useACMEHost = "tlater.net";
-    # The upstream module already adds HSTS
-  };
-
-  services.backups.nextcloud = {
-    user = "nextcloud";
-    paths = [
-      "/var/lib/nextcloud/nextcloud-db.sql"
-      "/var/lib/nextcloud/data/"
-      "/var/lib/nextcloud/config/config.php"
-    ];
-    preparation = {
-      packages = [
-        config.services.postgresql.package
-        config.services.nextcloud.occ
-      ];
-      text = ''
-        nextcloud-occ maintenance:mode --on
-        pg_dump ${config.services.nextcloud.config.dbname} --file=/var/lib/nextcloud/nextcloud-db.sql
-      '';
-    };
-    cleanup = {
-      packages = [
-        pkgs.coreutils
-        config.services.nextcloud.occ
-      ];
-      text = ''
-        rm /var/lib/nextcloud/nextcloud-db.sql
-        nextcloud-occ maintenance:mode --off
-      '';
-    };
-  };
 }
diff --git a/configuration/services/webserver.nix b/configuration/services/webserver.nix
index e6b49b3..864f6c0 100644
--- a/configuration/services/webserver.nix
+++ b/configuration/services/webserver.nix
@@ -1,6 +1,6 @@
 { config, ... }:
 let
-  domain = config.services.nginx.domain;
+  inherit (config.services.nginx) domain;
 in
 {
   services.tlaternet-webserver = {
diff --git a/flake.nix b/flake.nix
index 6747c24..90716e5 100644
--- a/flake.nix
+++ b/flake.nix
@@ -121,8 +121,6 @@
         run-vm = {
           type = "app";
           program =
-            let
-            in
             (pkgs.writeShellScript "" ''
               ${vm.config.system.build.vm.outPath}/bin/run-testvm-vm
             '').outPath;
diff --git a/modules/crowdsec/default.nix b/modules/crowdsec/default.nix
index c0003a5..ac93c4a 100644
--- a/modules/crowdsec/default.nix
+++ b/modules/crowdsec/default.nix
@@ -267,9 +267,7 @@ in
       };
     };
 
-    systemd.packages = [
-      cfg.package
-    ];
+    systemd.packages = [ cfg.package ];
 
     environment = {
       systemPackages = [
diff --git a/modules/crowdsec/remediations/cs-firewall-bouncer.nix b/modules/crowdsec/remediations/cs-firewall-bouncer.nix
index aa70552..42accc6 100644
--- a/modules/crowdsec/remediations/cs-firewall-bouncer.nix
+++ b/modules/crowdsec/remediations/cs-firewall-bouncer.nix
@@ -6,10 +6,11 @@
   ...
 }:
 let
+  inherit (flake-inputs.self.packages.${pkgs.system}) crowdsec-firewall-bouncer;
+
   crowdsecCfg = config.security.crowdsec;
   cfg = crowdsecCfg.remediationComponents.firewallBouncer;
   settingsFormat = pkgs.formats.yaml { };
-  crowdsec-firewall-bouncer = flake-inputs.self.packages.${pkgs.system}.crowdsec-firewall-bouncer;
 in
 {
   options.security.crowdsec.remediationComponents.firewallBouncer = {
@@ -31,9 +32,7 @@ in
     security.crowdsec.remediationComponents.firewallBouncer.settings = {
       mode = lib.mkDefault "${if config.networking.nftables.enable then "nftables" else "iptables"}";
       log_mode = "stdout";
-      iptables_chains = [
-        "nixos-fw"
-      ];
+      iptables_chains = [ "nixos-fw" ];
 
       # Don't let users easily override this; unfortunately we need to
       # set up this key through substitution at runtime.
@@ -78,9 +77,7 @@ in
           requiredBy = [ "crowdsec.service" ];
 
           path =
-            lib.optionals (cfg.settings.mode == "ipset" || cfg.settings.mode == "iptables") [
-              pkgs.ipset
-            ]
+            lib.optionals (cfg.settings.mode == "ipset" || cfg.settings.mode == "iptables") [ pkgs.ipset ]
             ++ lib.optional (cfg.settings.mode == "iptables") pkgs.iptables
             ++ lib.optional (cfg.settings.mode == "nftables") pkgs.nftables;
         };
diff --git a/modules/crowdsec/remediations/default.nix b/modules/crowdsec/remediations/default.nix
index 7df6ade..c3c0790 100644
--- a/modules/crowdsec/remediations/default.nix
+++ b/modules/crowdsec/remediations/default.nix
@@ -1,5 +1 @@
-{
-  imports = [
-    ./cs-firewall-bouncer.nix
-  ];
-}
+{ imports = [ ./cs-firewall-bouncer.nix ]; }
diff --git a/pkgs/crowdsec/hub.nix b/pkgs/crowdsec/hub.nix
index d057ca8..1b8c9b3 100644
--- a/pkgs/crowdsec/hub.nix
+++ b/pkgs/crowdsec/hub.nix
@@ -1,4 +1 @@
-{
-  sources,
-}:
-sources.crowdsec-hub.src
+{ sources }: sources.crowdsec-hub.src

From 8d0be61483178428191cf79f55705ff20cb2b8cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Tue, 20 May 2025 20:49:16 +0800
Subject: [PATCH 62/67] chore(ignore-revs): Ignore linter changes in `blame`

---
 .git-blame-ignore-revs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index df9d62b..40e5d59 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -9,3 +9,6 @@ fd138d45e6a2cad89fead6e9f246ba282070d6b7
 
 # Switch to alejandra formatting
 046a88905ddfa7f9edc3291c310dbb985dee34f9
+
+# Apply wide linting
+63b3cbe00be80ccb4b221aad64eb657ae5c96d70

From 913944cff37a3007574525735c854d4be6dd97eb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 23 May 2025 11:40:19 +0800
Subject: [PATCH 63/67] feat(immich): Add immich service

---
 configuration/default.nix                     |  1 +
 configuration/services/immich.nix             | 65 +++++++++++++++++++
 .../services/metrics/victoriametrics.nix      |  5 ++
 3 files changed, 71 insertions(+)
 create mode 100644 configuration/services/immich.nix

diff --git a/configuration/default.nix b/configuration/default.nix
index 544e20c..0377e9c 100644
--- a/configuration/default.nix
+++ b/configuration/default.nix
@@ -19,6 +19,7 @@
     ./services/crowdsec.nix
     ./services/foundryvtt.nix
     ./services/gitea.nix
+    ./services/immich.nix
     ./services/metrics
     ./services/nextcloud.nix
     ./services/webserver.nix
diff --git a/configuration/services/immich.nix b/configuration/services/immich.nix
new file mode 100644
index 0000000..b74c877
--- /dev/null
+++ b/configuration/services/immich.nix
@@ -0,0 +1,65 @@
+{
+  pkgs,
+  config,
+  lib,
+  ...
+}:
+let
+  hostName = "immich.${config.services.nginx.domain}";
+in
+{
+  services.immich = {
+    enable = true;
+    settings.server.externalDomain = "https://${hostName}";
+
+    environment.IMMICH_TELEMETRY_INCLUDE = "all";
+  };
+
+  services.nginx.virtualHosts.${hostName} =
+    let
+      local = "http://${config.services.immich.host}:${toString config.services.immich.port}";
+    in
+    {
+      forceSSL = true;
+      useACMEHost = "tlater.net";
+      enableHSTS = true;
+
+      locations."/" = {
+        proxyPass = local;
+        proxyWebsockets = true;
+      };
+      locations."/metrics" = {
+        extraConfig = ''
+          access_log off;
+          allow 127.0.0.1;
+          ${lib.optionalString config.networking.enableIPv6 "allow ::1;"}
+          deny all;
+        '';
+      };
+    };
+
+  backups.immich =
+    let
+      db-dump = "${config.services.immich.mediaLocation}/immich-db.sql";
+    in
+    {
+      user = "immich";
+      paths = [ config.services.immich.mediaLocation ];
+
+      preparation = {
+        packages = [ config.services.postgresql.package ];
+        text = ''
+          pg_dump ${config.services.immich.database.name} --clean --if-exists --file=${db-dump}
+        '';
+      };
+
+      cleanup = {
+        packages = [ pkgs.coreutils ];
+        text = "rm ${db-dump}";
+      };
+      pauseServices = [
+        "immich-server.service"
+        "immich-machine-learning.service"
+      ];
+    };
+}
diff --git a/configuration/services/metrics/victoriametrics.nix b/configuration/services/metrics/victoriametrics.nix
index 53864d6..f37b8b0 100644
--- a/configuration/services/metrics/victoriametrics.nix
+++ b/configuration/services/metrics/victoriametrics.nix
@@ -84,6 +84,11 @@ in
         in
         [ "${address}:${toString port}" ];
 
+      immich.targets = [
+        "127.0.0.1:8081"
+        "127.0.0.1:8082"
+      ];
+
       # Configured in the hookshot listeners, but it's hard to filter
       # the correct values out of that config.
       matrixHookshot.targets = [ "127.0.0.1:9001" ];

From b067bbc8c004af4780f8306c3ad7de466a9d823f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 24 May 2025 05:32:55 +0800
Subject: [PATCH 64/67] fix(immich): Set the correct backup attribute

---
 configuration/services/immich.nix | 106 +++++++++++++++---------------
 1 file changed, 54 insertions(+), 52 deletions(-)

diff --git a/configuration/services/immich.nix b/configuration/services/immich.nix
index b74c877..516ea3e 100644
--- a/configuration/services/immich.nix
+++ b/configuration/services/immich.nix
@@ -8,58 +8,60 @@ let
   hostName = "immich.${config.services.nginx.domain}";
 in
 {
-  services.immich = {
-    enable = true;
-    settings.server.externalDomain = "https://${hostName}";
+  services = {
+    immich = {
+      enable = true;
+      settings.server.externalDomain = "https://${hostName}";
 
-    environment.IMMICH_TELEMETRY_INCLUDE = "all";
+      environment.IMMICH_TELEMETRY_INCLUDE = "all";
+    };
+
+    nginx.virtualHosts.${hostName} =
+      let
+        local = "http://${config.services.immich.host}:${toString config.services.immich.port}";
+      in
+      {
+        forceSSL = true;
+        useACMEHost = "tlater.net";
+        enableHSTS = true;
+
+        locations."/" = {
+          proxyPass = local;
+          proxyWebsockets = true;
+        };
+        locations."/metrics" = {
+          extraConfig = ''
+            access_log off;
+            allow 127.0.0.1;
+            ${lib.optionalString config.networking.enableIPv6 "allow ::1;"}
+            deny all;
+          '';
+        };
+      };
+
+    backups.immich =
+      let
+        db-dump = "${config.services.immich.mediaLocation}/immich-db.sql";
+      in
+      {
+        user = "immich";
+        paths = [ config.services.immich.mediaLocation ];
+
+        preparation = {
+          packages = [ config.services.postgresql.package ];
+          text = ''
+            pg_dump ${config.services.immich.database.name} --clean --if-exists --file=${db-dump}
+          '';
+        };
+
+        cleanup = {
+          packages = [ pkgs.coreutils ];
+          text = "rm ${db-dump}";
+        };
+        pauseServices = [
+          "immich-server.service"
+          "immich-machine-learning.service"
+        ];
+      };
   };
-
-  services.nginx.virtualHosts.${hostName} =
-    let
-      local = "http://${config.services.immich.host}:${toString config.services.immich.port}";
-    in
-    {
-      forceSSL = true;
-      useACMEHost = "tlater.net";
-      enableHSTS = true;
-
-      locations."/" = {
-        proxyPass = local;
-        proxyWebsockets = true;
-      };
-      locations."/metrics" = {
-        extraConfig = ''
-          access_log off;
-          allow 127.0.0.1;
-          ${lib.optionalString config.networking.enableIPv6 "allow ::1;"}
-          deny all;
-        '';
-      };
-    };
-
-  backups.immich =
-    let
-      db-dump = "${config.services.immich.mediaLocation}/immich-db.sql";
-    in
-    {
-      user = "immich";
-      paths = [ config.services.immich.mediaLocation ];
-
-      preparation = {
-        packages = [ config.services.postgresql.package ];
-        text = ''
-          pg_dump ${config.services.immich.database.name} --clean --if-exists --file=${db-dump}
-        '';
-      };
-
-      cleanup = {
-        packages = [ pkgs.coreutils ];
-        text = "rm ${db-dump}";
-      };
-      pauseServices = [
-        "immich-server.service"
-        "immich-machine-learning.service"
-      ];
-    };
 }

From fc6be0c4c27dd00283bacb7c5cd3bcf1d5bab09c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 24 May 2025 22:53:33 +0800
Subject: [PATCH 65/67] chore(treewide): Upgrade to NixOS 25.05

---
 configuration/services/conduit/default.nix    |  3 +-
 .../services/conduit/matrix-hookshot.nix      | 42 +++++++++++++++----
 configuration/services/metrics/grafana.nix    |  9 +---
 configuration/services/nextcloud.nix          |  6 +--
 flake.nix                                     |  7 +---
 modules/crowdsec/default.nix                  |  5 +--
 6 files changed, 43 insertions(+), 29 deletions(-)

diff --git a/configuration/services/conduit/default.nix b/configuration/services/conduit/default.nix
index 58abc49..4ba5271 100644
--- a/configuration/services/conduit/default.nix
+++ b/configuration/services/conduit/default.nix
@@ -1,6 +1,5 @@
 {
   pkgs,
-  flake-inputs,
   config,
   lib,
   ...
@@ -21,7 +20,7 @@ in
   services = {
     matrix-conduit = {
       enable = true;
-      package = flake-inputs.continuwuity.packages.${pkgs.system}.default;
+      package = pkgs.matrix-continuwuity;
       settings.global = {
         address = "127.0.0.1";
         server_name = domain;
diff --git a/configuration/services/conduit/matrix-hookshot.nix b/configuration/services/conduit/matrix-hookshot.nix
index 6846d99..6b788b2 100644
--- a/configuration/services/conduit/matrix-hookshot.nix
+++ b/configuration/services/conduit/matrix-hookshot.nix
@@ -29,16 +29,29 @@ let
     };
 
     # Encryption support
-    extraSettings = {
-      "de.sorunome.msc2409.push_ephemeral" = true;
-      push_ephemeral = true;
-      "org.matrix.msc3202" = true;
-    };
+    # TODO(tlater): Enable when
+    # https://github.com/matrix-org/matrix-hookshot/issues/1060 is
+    # fixed
+    # extraSettings = {
+    #   "de.sorunome.msc2409.push_ephemeral" = true;
+    #   push_ephemeral = true;
+    #   "org.matrix.msc3202" = true;
+    # };
 
     runtimeRegistration = "${cfg.registrationFile}";
   };
 in
 {
+  # users = {
+  #   users.matrix-hookshot = {
+  #     home = "/run/matrix-hookshot";
+  #     group = "matrix-hookshot";
+  #     isSystemUser = true;
+  #   };
+
+  #   groups.matrix-hookshot = { };
+  # };
+
   systemd.services.matrix-hookshot = {
     serviceConfig = {
       Type = lib.mkForce "exec";
@@ -49,6 +62,7 @@ in
       # Some library in matrix-hookshot wants a home directory
       Environment = [ "HOME=/run/matrix-hookshot" ];
 
+      # User = "matrix-hookshot";
       DynamicUser = true;
       StateDirectory = "matrix-hookshot";
       RuntimeDirectory = "matrix-hookshot";
@@ -62,7 +76,11 @@ in
       ProtectKernelModules = true;
       ProtectKernelLogs = true;
       ProtectControlGroups = true;
-      RestrictAddressFamilies = [ "AF_INET AF_INET6" ];
+      RestrictAddressFamilies = [
+        # "AF_UNIX"
+        "AF_INET"
+        "AF_INET6"
+      ];
       LockPersonality = true;
       RestrictRealtime = true;
       ProtectProc = "invisible";
@@ -71,6 +89,11 @@ in
     };
   };
 
+  # services.redis.servers.matrix-hookshot = {
+  #   enable = true;
+  #   user = "matrix-hookshot";
+  # };
+
   services.matrix-hookshot = {
     enable = true;
 
@@ -89,6 +112,8 @@ in
 
       bot.displayname = "Hookshot";
 
+      # cache.redisUri = "redis://${config.services.redis.servers.matrix-hookshot.unixSocket}";
+
       generic = {
         enabled = true;
         outbound = false;
@@ -98,7 +123,10 @@ in
         allowJsTransformationFunctions = true;
       };
 
-      encryption.storagePath = "/var/lib/matrix-hookshot/cryptostore";
+      # TODO(tlater): Enable when
+      # https://github.com/matrix-org/matrix-hookshot/issues/1060 is
+      # fixed
+      # encryption.storagePath = "/var/lib/matrix-hookshot/cryptostore";
 
       permissions = [
         {
diff --git a/configuration/services/metrics/grafana.nix b/configuration/services/metrics/grafana.nix
index b872833..b30806c 100644
--- a/configuration/services/metrics/grafana.nix
+++ b/configuration/services/metrics/grafana.nix
@@ -1,9 +1,4 @@
-{
-  pkgs,
-  config,
-  flake-inputs,
-  ...
-}:
+{ pkgs, config, ... }:
 let
   domain = "metrics.${config.services.nginx.domain}";
 in
@@ -35,7 +30,7 @@ in
 
     declarativePlugins = [
       pkgs.grafanaPlugins.victoriametrics-metrics-datasource
-      flake-inputs.nixpkgs-unstable.legacyPackages.${pkgs.system}.grafanaPlugins.victoriametrics-logs-datasource
+      pkgs.grafanaPlugins.victoriametrics-logs-datasource
     ];
 
     provision = {
diff --git a/configuration/services/nextcloud.nix b/configuration/services/nextcloud.nix
index 2f8fa76..4af77a9 100644
--- a/configuration/services/nextcloud.nix
+++ b/configuration/services/nextcloud.nix
@@ -5,7 +5,7 @@
   ...
 }:
 let
-  nextcloud = pkgs.nextcloud30;
+  nextcloud = pkgs.nextcloud31;
   hostName = "nextcloud.${config.services.nginx.domain}";
 in
 {
@@ -19,10 +19,10 @@ in
           packageOverrides = _: prev: {
             extensions = prev.extensions // {
               pgsql = prev.extensions.pgsql.overrideAttrs (_: {
-                configureFlags = [ "--with-pgsql=${lib.getDev config.services.postgresql.package}" ];
+                configureFlags = [ "--with-pgsql=${lib.getDev config.services.postgresql.package.pg_config}" ];
               });
               pdo_pgsql = prev.extensions.pdo_pgsql.overrideAttrs (_: {
-                configureFlags = [ "--with-pdo-pgsql=${lib.getDev config.services.postgresql.package}" ];
+                configureFlags = [ "--with-pdo-pgsql=${lib.getDev config.services.postgresql.package.pg_config}" ];
               });
             };
           };
diff --git a/flake.nix b/flake.nix
index 90716e5..da8455f 100644
--- a/flake.nix
+++ b/flake.nix
@@ -2,12 +2,7 @@
   description = "tlater.net host configuration";
 
   inputs = {
-    nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11-small";
-    nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable-small";
-    continuwuity = {
-      url = "git+https://forgejo.ellis.link/continuwuation/continuwuity.git?ref=refs/tags/v0.5.0-rc.5";
-      inputs.nixpkgs.follows = "nixpkgs";
-    };
+    nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05-small";
     disko = {
       url = "github:nix-community/disko";
       inputs.nixpkgs.follows = "nixpkgs";
diff --git a/modules/crowdsec/default.nix b/modules/crowdsec/default.nix
index ac93c4a..44e6bc5 100644
--- a/modules/crowdsec/default.nix
+++ b/modules/crowdsec/default.nix
@@ -247,10 +247,7 @@ in
             online_client = {
               # By default, we don't let crowdsec phone home, since
               # this is usually within NixOS users' concerns.
-              #
-              # TODO: Enable when this option becomes available
-              # (1.6.4, current nixpkgs-unstable)
-              # sharing = lib.mkDefault false;
+              sharing = lib.mkDefault false;
               credentials_path = cfg.centralApiCredentials;
             };
           };

From f2cbeebbb5c9634e9b82a3bb672b3dbbb15739fb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 24 May 2025 18:28:51 +0800
Subject: [PATCH 66/67] flake.lock: Update
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Flake lock file updates:

• Updated input 'disko':
    'github:nix-community/disko/ec7c109a4f794fce09aad87239eab7f66540b888' (2025-05-15)
  → 'github:nix-community/disko/df522e787fdffc4f32ed3e1fca9ed0968a384d62' (2025-05-20)
• Updated input 'nixpkgs-unstable':
    'github:nixos/nixpkgs/b965e4c283060415956ccd39eee4ca34a6a56cf8' (2025-05-16)
  → 'github:nixos/nixpkgs/c3ee76c437067f1ae09d6e530df46a3f80977992' (2025-05-24)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/e93ee1d900ad264d65e9701a5c6f895683433386' (2025-05-05)
  → 'github:Mic92/sops-nix/8d215e1c981be3aa37e47aeabd4e61bb069548fd' (2025-05-18)
---
 flake.lock | 932 ++++++++---------------------------------------------
 1 file changed, 134 insertions(+), 798 deletions(-)

diff --git a/flake.lock b/flake.lock
index c17c613..885b579 100644
--- a/flake.lock
+++ b/flake.lock
@@ -1,86 +1,6 @@
 {
   "nodes": {
-    "attic": {
-      "inputs": {
-        "crane": "crane",
-        "flake-compat": "flake-compat",
-        "flake-parts": "flake-parts",
-        "nix-github-actions": "nix-github-actions",
-        "nixpkgs": "nixpkgs",
-        "nixpkgs-stable": "nixpkgs-stable"
-      },
-      "locked": {
-        "lastModified": 1738524606,
-        "narHash": "sha256-hPYEJ4juK3ph7kbjbvv7PlU1D9pAkkhl+pwx8fZY53U=",
-        "owner": "zhaofengli",
-        "repo": "attic",
-        "rev": "ff8a897d1f4408ebbf4d45fa9049c06b3e1e3f4e",
-        "type": "github"
-      },
-      "original": {
-        "owner": "zhaofengli",
-        "ref": "main",
-        "repo": "attic",
-        "type": "github"
-      }
-    },
     "cachix": {
-      "inputs": {
-        "devenv": "devenv",
-        "flake-compat": "flake-compat_2",
-        "git-hooks": "git-hooks",
-        "nixpkgs": "nixpkgs_4"
-      },
-      "locked": {
-        "lastModified": 1737621947,
-        "narHash": "sha256-8HFvG7fvIFbgtaYAY2628Tb89fA55nPm2jSiNs0/Cws=",
-        "owner": "cachix",
-        "repo": "cachix",
-        "rev": "f65a3cd5e339c223471e64c051434616e18cc4f5",
-        "type": "github"
-      },
-      "original": {
-        "owner": "cachix",
-        "ref": "master",
-        "repo": "cachix",
-        "type": "github"
-      }
-    },
-    "cachix_2": {
-      "inputs": {
-        "devenv": [
-          "continuwuity",
-          "cachix",
-          "devenv"
-        ],
-        "flake-compat": [
-          "continuwuity",
-          "cachix",
-          "devenv"
-        ],
-        "git-hooks": [
-          "continuwuity",
-          "cachix",
-          "devenv"
-        ],
-        "nixpkgs": "nixpkgs_2"
-      },
-      "locked": {
-        "lastModified": 1728672398,
-        "narHash": "sha256-KxuGSoVUFnQLB2ZcYODW7AVPAh9JqRlD5BrfsC/Q4qs=",
-        "owner": "cachix",
-        "repo": "cachix",
-        "rev": "aac51f698309fd0f381149214b7eee213c66ef0a",
-        "type": "github"
-      },
-      "original": {
-        "owner": "cachix",
-        "ref": "latest",
-        "repo": "cachix",
-        "type": "github"
-      }
-    },
-    "cachix_3": {
       "inputs": {
         "devenv": [
           "sonnenshift",
@@ -90,7 +10,7 @@
           "sonnenshift",
           "crate2nix"
         ],
-        "nixpkgs": "nixpkgs_7",
+        "nixpkgs": "nixpkgs_3",
         "pre-commit-hooks": [
           "sonnenshift",
           "crate2nix"
@@ -111,7 +31,7 @@
         "type": "github"
       }
     },
-    "cachix_4": {
+    "cachix_2": {
       "inputs": {
         "devenv": [
           "sonnenshift",
@@ -123,7 +43,7 @@
           "crate2nix",
           "crate2nix_stable"
         ],
-        "nixpkgs": "nixpkgs_8",
+        "nixpkgs": "nixpkgs_4",
         "pre-commit-hooks": [
           "sonnenshift",
           "crate2nix",
@@ -145,7 +65,7 @@
         "type": "github"
       }
     },
-    "cachix_5": {
+    "cachix_3": {
       "inputs": {
         "devenv": [
           "sonnenshift",
@@ -159,7 +79,7 @@
           "crate2nix_stable",
           "crate2nix_stable"
         ],
-        "nixpkgs": "nixpkgs_9",
+        "nixpkgs": "nixpkgs_5",
         "pre-commit-hooks": [
           "sonnenshift",
           "crate2nix",
@@ -182,99 +102,13 @@
         "type": "github"
       }
     },
-    "complement": {
-      "flake": false,
-      "locked": {
-        "lastModified": 1741891349,
-        "narHash": "sha256-YvrzOWcX7DH1drp5SGa+E/fc7wN3hqFtPbqPjZpOu1Q=",
-        "owner": "girlbossceo",
-        "repo": "complement",
-        "rev": "e587b3df569cba411aeac7c20b6366d03c143745",
-        "type": "github"
-      },
-      "original": {
-        "owner": "girlbossceo",
-        "ref": "main",
-        "repo": "complement",
-        "type": "github"
-      }
-    },
-    "continuwuity": {
-      "inputs": {
-        "attic": "attic",
-        "cachix": "cachix",
-        "complement": "complement",
-        "crane": "crane_2",
-        "fenix": "fenix",
-        "flake-compat": "flake-compat_3",
-        "flake-utils": "flake-utils",
-        "liburing": "liburing",
-        "nix-filter": "nix-filter",
-        "nixpkgs": [
-          "nixpkgs"
-        ],
-        "rocksdb": "rocksdb"
-      },
-      "locked": {
-        "lastModified": 1745186840,
-        "narHash": "sha256-Oq2scBu3Ewao828BT1QGffqIqF5WoH9HMXEXKg1YU0o=",
-        "ref": "refs/tags/v0.5.0-rc.5",
-        "rev": "0a0f327ae034f5c44b12a3154cc1143aff10291c",
-        "revCount": 5147,
-        "type": "git",
-        "url": "https://forgejo.ellis.link/continuwuation/continuwuity.git"
-      },
-      "original": {
-        "ref": "refs/tags/v0.5.0-rc.5",
-        "type": "git",
-        "url": "https://forgejo.ellis.link/continuwuation/continuwuity.git"
-      }
-    },
-    "crane": {
-      "inputs": {
-        "nixpkgs": [
-          "continuwuity",
-          "attic",
-          "nixpkgs"
-        ]
-      },
-      "locked": {
-        "lastModified": 1722960479,
-        "narHash": "sha256-NhCkJJQhD5GUib8zN9JrmYGMwt4lCRp6ZVNzIiYCl0Y=",
-        "owner": "ipetkov",
-        "repo": "crane",
-        "rev": "4c6c77920b8d44cd6660c1621dea6b3fc4b4c4f4",
-        "type": "github"
-      },
-      "original": {
-        "owner": "ipetkov",
-        "repo": "crane",
-        "type": "github"
-      }
-    },
-    "crane_2": {
-      "locked": {
-        "lastModified": 1739936662,
-        "narHash": "sha256-x4syUjNUuRblR07nDPeLDP7DpphaBVbUaSoeZkFbGSk=",
-        "owner": "ipetkov",
-        "repo": "crane",
-        "rev": "19de14aaeb869287647d9461cbd389187d8ecdb7",
-        "type": "github"
-      },
-      "original": {
-        "owner": "ipetkov",
-        "ref": "master",
-        "repo": "crane",
-        "type": "github"
-      }
-    },
     "crate2nix": {
       "inputs": {
-        "cachix": "cachix_3",
+        "cachix": "cachix",
         "crate2nix_stable": "crate2nix_stable",
         "devshell": "devshell_3",
-        "flake-compat": "flake-compat_7",
-        "flake-parts": "flake-parts_5",
+        "flake-compat": "flake-compat_4",
+        "flake-parts": "flake-parts_3",
         "nix-test-runner": "nix-test-runner_3",
         "nixpkgs": [
           "sonnenshift",
@@ -298,13 +132,13 @@
     },
     "crate2nix_stable": {
       "inputs": {
-        "cachix": "cachix_4",
+        "cachix": "cachix_2",
         "crate2nix_stable": "crate2nix_stable_2",
         "devshell": "devshell_2",
-        "flake-compat": "flake-compat_6",
-        "flake-parts": "flake-parts_4",
+        "flake-compat": "flake-compat_3",
+        "flake-parts": "flake-parts_2",
         "nix-test-runner": "nix-test-runner_2",
-        "nixpkgs": "nixpkgs_11",
+        "nixpkgs": "nixpkgs_7",
         "pre-commit-hooks": "pre-commit-hooks_2"
       },
       "locked": {
@@ -324,13 +158,13 @@
     },
     "crate2nix_stable_2": {
       "inputs": {
-        "cachix": "cachix_5",
+        "cachix": "cachix_3",
         "crate2nix_stable": "crate2nix_stable_3",
         "devshell": "devshell",
-        "flake-compat": "flake-compat_5",
-        "flake-parts": "flake-parts_3",
+        "flake-compat": "flake-compat_2",
+        "flake-parts": "flake-parts",
         "nix-test-runner": "nix-test-runner",
-        "nixpkgs": "nixpkgs_10",
+        "nixpkgs": "nixpkgs_6",
         "pre-commit-hooks": "pre-commit-hooks"
       },
       "locked": {
@@ -350,7 +184,7 @@
     },
     "crate2nix_stable_3": {
       "inputs": {
-        "flake-utils": "flake-utils_2"
+        "flake-utils": "flake-utils"
       },
       "locked": {
         "lastModified": 1702842982,
@@ -369,8 +203,8 @@
     },
     "deploy-rs": {
       "inputs": {
-        "flake-compat": "flake-compat_4",
-        "nixpkgs": "nixpkgs_5",
+        "flake-compat": "flake-compat",
+        "nixpkgs": "nixpkgs",
         "utils": "utils"
       },
       "locked": {
@@ -387,43 +221,9 @@
         "type": "github"
       }
     },
-    "devenv": {
-      "inputs": {
-        "cachix": "cachix_2",
-        "flake-compat": [
-          "continuwuity",
-          "cachix",
-          "flake-compat"
-        ],
-        "git-hooks": [
-          "continuwuity",
-          "cachix",
-          "git-hooks"
-        ],
-        "nix": "nix",
-        "nixpkgs": [
-          "continuwuity",
-          "cachix",
-          "nixpkgs"
-        ]
-      },
-      "locked": {
-        "lastModified": 1733323168,
-        "narHash": "sha256-d5DwB4MZvlaQpN6OQ4SLYxb5jA4UH5EtV5t5WOtjLPU=",
-        "owner": "cachix",
-        "repo": "devenv",
-        "rev": "efa9010b8b1cfd5dd3c7ed1e172a470c3b84a064",
-        "type": "github"
-      },
-      "original": {
-        "owner": "cachix",
-        "repo": "devenv",
-        "type": "github"
-      }
-    },
     "devshell": {
       "inputs": {
-        "flake-utils": "flake-utils_3",
+        "flake-utils": "flake-utils_2",
         "nixpkgs": [
           "sonnenshift",
           "crate2nix",
@@ -448,7 +248,7 @@
     },
     "devshell_2": {
       "inputs": {
-        "flake-utils": "flake-utils_4",
+        "flake-utils": "flake-utils_3",
         "nixpkgs": [
           "sonnenshift",
           "crate2nix",
@@ -472,7 +272,7 @@
     },
     "devshell_3": {
       "inputs": {
-        "flake-utils": "flake-utils_5",
+        "flake-utils": "flake-utils_4",
         "nixpkgs": [
           "sonnenshift",
           "crate2nix",
@@ -500,11 +300,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1747274630,
-        "narHash": "sha256-87RJwXbfOHyzTB9LYagAQ6vOZhszCvd8Gvudu+gf3qo=",
+        "lastModified": 1747742835,
+        "narHash": "sha256-kYL4GCwwznsypvsnA20oyvW8zB/Dvn6K5G/tgMjVMT4=",
         "owner": "nix-community",
         "repo": "disko",
-        "rev": "ec7c109a4f794fce09aad87239eab7f66540b888",
+        "rev": "df522e787fdffc4f32ed3e1fca9ed0968a384d62",
         "type": "github"
       },
       "original": {
@@ -515,7 +315,7 @@
     },
     "dream2nix": {
       "inputs": {
-        "nixpkgs": "nixpkgs_12",
+        "nixpkgs": "nixpkgs_8",
         "purescript-overlay": "purescript-overlay",
         "pyproject-nix": "pyproject-nix"
       },
@@ -534,35 +334,12 @@
       }
     },
     "fenix": {
-      "inputs": {
-        "nixpkgs": [
-          "continuwuity",
-          "nixpkgs"
-        ],
-        "rust-analyzer-src": "rust-analyzer-src"
-      },
-      "locked": {
-        "lastModified": 1740724364,
-        "narHash": "sha256-D1jLIueJx1dPrP09ZZwTrPf4cubV+TsFMYbpYYTVj6A=",
-        "owner": "nix-community",
-        "repo": "fenix",
-        "rev": "edf7d9e431cda8782e729253835f178a356d3aab",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nix-community",
-        "ref": "main",
-        "repo": "fenix",
-        "type": "github"
-      }
-    },
-    "fenix_2": {
       "inputs": {
         "nixpkgs": [
           "tlaternet-webserver",
           "nixpkgs"
         ],
-        "rust-analyzer-src": "rust-analyzer-src_2"
+        "rust-analyzer-src": "rust-analyzer-src"
       },
       "locked": {
         "lastModified": 1737181903,
@@ -595,97 +372,48 @@
       }
     },
     "flake-compat_2": {
-      "flake": false,
       "locked": {
-        "lastModified": 1733328505,
-        "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
-        "owner": "edolstra",
-        "repo": "flake-compat",
-        "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
-        "type": "github"
+        "lastModified": 1696426674,
+        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
+        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
+        "revCount": 57,
+        "type": "tarball",
+        "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz"
       },
       "original": {
-        "owner": "edolstra",
-        "repo": "flake-compat",
-        "type": "github"
+        "type": "tarball",
+        "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
       }
     },
     "flake-compat_3": {
-      "flake": false,
       "locked": {
-        "lastModified": 1733328505,
-        "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
-        "owner": "edolstra",
-        "repo": "flake-compat",
-        "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
-        "type": "github"
+        "lastModified": 1696426674,
+        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
+        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
+        "revCount": 57,
+        "type": "tarball",
+        "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz"
       },
       "original": {
-        "owner": "edolstra",
-        "ref": "master",
-        "repo": "flake-compat",
-        "type": "github"
+        "type": "tarball",
+        "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
       }
     },
     "flake-compat_4": {
-      "flake": false,
       "locked": {
         "lastModified": 1696426674,
         "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
-        "owner": "edolstra",
-        "repo": "flake-compat",
         "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
-        "type": "github"
+        "revCount": 57,
+        "type": "tarball",
+        "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz"
       },
       "original": {
-        "owner": "edolstra",
-        "repo": "flake-compat",
-        "type": "github"
+        "type": "tarball",
+        "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
       }
     },
     "flake-compat_5": {
-      "locked": {
-        "lastModified": 1696426674,
-        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
-        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
-        "revCount": 57,
-        "type": "tarball",
-        "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz"
-      },
-      "original": {
-        "type": "tarball",
-        "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
-      }
-    },
-    "flake-compat_6": {
-      "locked": {
-        "lastModified": 1696426674,
-        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
-        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
-        "revCount": 57,
-        "type": "tarball",
-        "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz"
-      },
-      "original": {
-        "type": "tarball",
-        "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
-      }
-    },
-    "flake-compat_7": {
-      "locked": {
-        "lastModified": 1696426674,
-        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
-        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
-        "revCount": 57,
-        "type": "tarball",
-        "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz"
-      },
-      "original": {
-        "type": "tarball",
-        "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
-      }
-    },
-    "flake-compat_8": {
       "flake": false,
       "locked": {
         "lastModified": 1696426674,
@@ -704,17 +432,19 @@
     "flake-parts": {
       "inputs": {
         "nixpkgs-lib": [
-          "continuwuity",
-          "attic",
+          "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable",
+          "crate2nix_stable",
           "nixpkgs"
         ]
       },
       "locked": {
-        "lastModified": 1722555600,
-        "narHash": "sha256-XOQkdLafnb/p9ij77byFQjDf5m5QYl9b2REiVClC+x4=",
+        "lastModified": 1719745305,
+        "narHash": "sha256-xwgjVUpqSviudEkpQnioeez1Uo2wzrsMaJKJClh+Bls=",
         "owner": "hercules-ci",
         "repo": "flake-parts",
-        "rev": "8471fe90ad337a8074e957b69ca4d0089218391d",
+        "rev": "c3c5ecc05edc7dafba779c6c1a61cd08ac6583e9",
         "type": "github"
       },
       "original": {
@@ -726,19 +456,18 @@
     "flake-parts_2": {
       "inputs": {
         "nixpkgs-lib": [
-          "continuwuity",
-          "cachix",
-          "devenv",
-          "nix",
+          "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable",
           "nixpkgs"
         ]
       },
       "locked": {
-        "lastModified": 1712014858,
-        "narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
+        "lastModified": 1719745305,
+        "narHash": "sha256-xwgjVUpqSviudEkpQnioeez1Uo2wzrsMaJKJClh+Bls=",
         "owner": "hercules-ci",
         "repo": "flake-parts",
-        "rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
+        "rev": "c3c5ecc05edc7dafba779c6c1a61cd08ac6583e9",
         "type": "github"
       },
       "original": {
@@ -748,53 +477,6 @@
       }
     },
     "flake-parts_3": {
-      "inputs": {
-        "nixpkgs-lib": [
-          "sonnenshift",
-          "crate2nix",
-          "crate2nix_stable",
-          "crate2nix_stable",
-          "nixpkgs"
-        ]
-      },
-      "locked": {
-        "lastModified": 1719745305,
-        "narHash": "sha256-xwgjVUpqSviudEkpQnioeez1Uo2wzrsMaJKJClh+Bls=",
-        "owner": "hercules-ci",
-        "repo": "flake-parts",
-        "rev": "c3c5ecc05edc7dafba779c6c1a61cd08ac6583e9",
-        "type": "github"
-      },
-      "original": {
-        "owner": "hercules-ci",
-        "repo": "flake-parts",
-        "type": "github"
-      }
-    },
-    "flake-parts_4": {
-      "inputs": {
-        "nixpkgs-lib": [
-          "sonnenshift",
-          "crate2nix",
-          "crate2nix_stable",
-          "nixpkgs"
-        ]
-      },
-      "locked": {
-        "lastModified": 1719745305,
-        "narHash": "sha256-xwgjVUpqSviudEkpQnioeez1Uo2wzrsMaJKJClh+Bls=",
-        "owner": "hercules-ci",
-        "repo": "flake-parts",
-        "rev": "c3c5ecc05edc7dafba779c6c1a61cd08ac6583e9",
-        "type": "github"
-      },
-      "original": {
-        "owner": "hercules-ci",
-        "repo": "flake-parts",
-        "type": "github"
-      }
-    },
-    "flake-parts_5": {
       "inputs": {
         "nixpkgs-lib": [
           "sonnenshift",
@@ -818,19 +500,18 @@
     },
     "flake-utils": {
       "inputs": {
-        "systems": "systems"
+        "systems": "systems_2"
       },
       "locked": {
-        "lastModified": 1731533236,
-        "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
+        "lastModified": 1694529238,
+        "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
         "owner": "numtide",
         "repo": "flake-utils",
-        "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
+        "rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
         "type": "github"
       },
       "original": {
         "owner": "numtide",
-        "ref": "main",
         "repo": "flake-utils",
         "type": "github"
       }
@@ -840,11 +521,11 @@
         "systems": "systems_3"
       },
       "locked": {
-        "lastModified": 1694529238,
-        "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
+        "lastModified": 1701680307,
+        "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
         "owner": "numtide",
         "repo": "flake-utils",
-        "rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
+        "rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
         "type": "github"
       },
       "original": {
@@ -893,24 +574,6 @@
       "inputs": {
         "systems": "systems_6"
       },
-      "locked": {
-        "lastModified": 1701680307,
-        "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
-        "owner": "numtide",
-        "repo": "flake-utils",
-        "rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
-        "type": "github"
-      },
-      "original": {
-        "owner": "numtide",
-        "repo": "flake-utils",
-        "type": "github"
-      }
-    },
-    "flake-utils_6": {
-      "inputs": {
-        "systems": "systems_7"
-      },
       "locked": {
         "lastModified": 1710146030,
         "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
@@ -945,41 +608,14 @@
         "type": "github"
       }
     },
-    "git-hooks": {
-      "inputs": {
-        "flake-compat": [
-          "continuwuity",
-          "cachix",
-          "flake-compat"
-        ],
-        "gitignore": "gitignore",
-        "nixpkgs": [
-          "continuwuity",
-          "cachix",
-          "nixpkgs"
-        ],
-        "nixpkgs-stable": "nixpkgs-stable_2"
-      },
-      "locked": {
-        "lastModified": 1733318908,
-        "narHash": "sha256-SVQVsbafSM1dJ4fpgyBqLZ+Lft+jcQuMtEL3lQWx2Sk=",
-        "owner": "cachix",
-        "repo": "git-hooks.nix",
-        "rev": "6f4e2a2112050951a314d2733a994fbab94864c6",
-        "type": "github"
-      },
-      "original": {
-        "owner": "cachix",
-        "repo": "git-hooks.nix",
-        "type": "github"
-      }
-    },
     "gitignore": {
       "inputs": {
         "nixpkgs": [
-          "continuwuity",
-          "cachix",
-          "git-hooks",
+          "sonnenshift",
+          "crate2nix",
+          "crate2nix_stable",
+          "crate2nix_stable",
+          "pre-commit-hooks",
           "nixpkgs"
         ]
       },
@@ -1003,7 +639,6 @@
           "sonnenshift",
           "crate2nix",
           "crate2nix_stable",
-          "crate2nix_stable",
           "pre-commit-hooks",
           "nixpkgs"
         ]
@@ -1027,7 +662,6 @@
         "nixpkgs": [
           "sonnenshift",
           "crate2nix",
-          "crate2nix_stable",
           "pre-commit-hooks",
           "nixpkgs"
         ]
@@ -1046,141 +680,6 @@
         "type": "github"
       }
     },
-    "gitignore_4": {
-      "inputs": {
-        "nixpkgs": [
-          "sonnenshift",
-          "crate2nix",
-          "pre-commit-hooks",
-          "nixpkgs"
-        ]
-      },
-      "locked": {
-        "lastModified": 1709087332,
-        "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
-        "owner": "hercules-ci",
-        "repo": "gitignore.nix",
-        "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
-        "type": "github"
-      },
-      "original": {
-        "owner": "hercules-ci",
-        "repo": "gitignore.nix",
-        "type": "github"
-      }
-    },
-    "libgit2": {
-      "flake": false,
-      "locked": {
-        "lastModified": 1697646580,
-        "narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=",
-        "owner": "libgit2",
-        "repo": "libgit2",
-        "rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5",
-        "type": "github"
-      },
-      "original": {
-        "owner": "libgit2",
-        "repo": "libgit2",
-        "type": "github"
-      }
-    },
-    "liburing": {
-      "flake": false,
-      "locked": {
-        "lastModified": 1740613216,
-        "narHash": "sha256-NpPOBqNND3Qe9IwqYs0mJLGTmIx7e6FgUEBAnJ+1ZLA=",
-        "owner": "axboe",
-        "repo": "liburing",
-        "rev": "e1003e496e66f9b0ae06674869795edf772d5500",
-        "type": "github"
-      },
-      "original": {
-        "owner": "axboe",
-        "ref": "master",
-        "repo": "liburing",
-        "type": "github"
-      }
-    },
-    "nix": {
-      "inputs": {
-        "flake-compat": [
-          "continuwuity",
-          "cachix",
-          "devenv"
-        ],
-        "flake-parts": "flake-parts_2",
-        "libgit2": "libgit2",
-        "nixpkgs": "nixpkgs_3",
-        "nixpkgs-23-11": [
-          "continuwuity",
-          "cachix",
-          "devenv"
-        ],
-        "nixpkgs-regression": [
-          "continuwuity",
-          "cachix",
-          "devenv"
-        ],
-        "pre-commit-hooks": [
-          "continuwuity",
-          "cachix",
-          "devenv"
-        ]
-      },
-      "locked": {
-        "lastModified": 1727438425,
-        "narHash": "sha256-X8ES7I1cfNhR9oKp06F6ir4Np70WGZU5sfCOuNBEwMg=",
-        "owner": "domenkozar",
-        "repo": "nix",
-        "rev": "f6c5ae4c1b2e411e6b1e6a8181cc84363d6a7546",
-        "type": "github"
-      },
-      "original": {
-        "owner": "domenkozar",
-        "ref": "devenv-2.24",
-        "repo": "nix",
-        "type": "github"
-      }
-    },
-    "nix-filter": {
-      "locked": {
-        "lastModified": 1731533336,
-        "narHash": "sha256-oRam5PS1vcrr5UPgALW0eo1m/5/pls27Z/pabHNy2Ms=",
-        "owner": "numtide",
-        "repo": "nix-filter",
-        "rev": "f7653272fd234696ae94229839a99b73c9ab7de0",
-        "type": "github"
-      },
-      "original": {
-        "owner": "numtide",
-        "ref": "main",
-        "repo": "nix-filter",
-        "type": "github"
-      }
-    },
-    "nix-github-actions": {
-      "inputs": {
-        "nixpkgs": [
-          "continuwuity",
-          "attic",
-          "nixpkgs"
-        ]
-      },
-      "locked": {
-        "lastModified": 1729742964,
-        "narHash": "sha256-B4mzTcQ0FZHdpeWcpDYPERtyjJd/NIuaQ9+BV1h+MpA=",
-        "owner": "nix-community",
-        "repo": "nix-github-actions",
-        "rev": "e04df33f62cdcf93d73e9a04142464753a16db67",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nix-community",
-        "repo": "nix-github-actions",
-        "type": "github"
-      }
-    },
     "nix-test-runner": {
       "flake": false,
       "locked": {
@@ -1230,160 +729,6 @@
       }
     },
     "nixpkgs": {
-      "locked": {
-        "lastModified": 1726042813,
-        "narHash": "sha256-LnNKCCxnwgF+575y0pxUdlGZBO/ru1CtGHIqQVfvjlA=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "159be5db480d1df880a0135ca0bfed84c2f88353",
-        "type": "github"
-      },
-      "original": {
-        "owner": "NixOS",
-        "ref": "nixpkgs-unstable",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "nixpkgs-stable": {
-      "locked": {
-        "lastModified": 1724316499,
-        "narHash": "sha256-Qb9MhKBUTCfWg/wqqaxt89Xfi6qTD3XpTzQ9eXi3JmE=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "797f7dc49e0bc7fab4b57c021cdf68f595e47841",
-        "type": "github"
-      },
-      "original": {
-        "owner": "NixOS",
-        "ref": "nixos-24.05",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "nixpkgs-stable_2": {
-      "locked": {
-        "lastModified": 1730741070,
-        "narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "d063c1dd113c91ab27959ba540c0d9753409edf3",
-        "type": "github"
-      },
-      "original": {
-        "owner": "NixOS",
-        "ref": "nixos-24.05",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "nixpkgs-unstable": {
-      "locked": {
-        "lastModified": 1747413287,
-        "narHash": "sha256-hOnqJr0tZBERWa29JWf9B3/8qr82mlt/UlKPvS7iYzA=",
-        "owner": "nixos",
-        "repo": "nixpkgs",
-        "rev": "b965e4c283060415956ccd39eee4ca34a6a56cf8",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nixos",
-        "ref": "nixos-unstable-small",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "nixpkgs_10": {
-      "locked": {
-        "lastModified": 1719506693,
-        "narHash": "sha256-C8e9S7RzshSdHB7L+v9I51af1gDM5unhJ2xO1ywxNH8=",
-        "path": "/nix/store/4p0avw1s3vf27hspgqsrqs37gxk4i83i-source",
-        "rev": "b2852eb9365c6de48ffb0dc2c9562591f652242a",
-        "type": "path"
-      },
-      "original": {
-        "id": "nixpkgs",
-        "type": "indirect"
-      }
-    },
-    "nixpkgs_11": {
-      "locked": {
-        "lastModified": 1719506693,
-        "narHash": "sha256-C8e9S7RzshSdHB7L+v9I51af1gDM5unhJ2xO1ywxNH8=",
-        "path": "/nix/store/4p0avw1s3vf27hspgqsrqs37gxk4i83i-source",
-        "rev": "b2852eb9365c6de48ffb0dc2c9562591f652242a",
-        "type": "path"
-      },
-      "original": {
-        "id": "nixpkgs",
-        "type": "indirect"
-      }
-    },
-    "nixpkgs_12": {
-      "locked": {
-        "lastModified": 1729850857,
-        "narHash": "sha256-WvLXzNNnnw+qpFOmgaM3JUlNEH+T4s22b5i2oyyCpXE=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "41dea55321e5a999b17033296ac05fe8a8b5a257",
-        "type": "github"
-      },
-      "original": {
-        "owner": "NixOS",
-        "ref": "nixpkgs-unstable",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "nixpkgs_2": {
-      "locked": {
-        "lastModified": 1730531603,
-        "narHash": "sha256-Dqg6si5CqIzm87sp57j5nTaeBbWhHFaVyG7V6L8k3lY=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "7ffd9ae656aec493492b44d0ddfb28e79a1ea25d",
-        "type": "github"
-      },
-      "original": {
-        "owner": "NixOS",
-        "ref": "nixos-unstable",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "nixpkgs_3": {
-      "locked": {
-        "lastModified": 1717432640,
-        "narHash": "sha256-+f9c4/ZX5MWDOuB1rKoWj+lBNm0z0rs4CK47HBLxy1o=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "88269ab3044128b7c2f4c7d68448b2fb50456870",
-        "type": "github"
-      },
-      "original": {
-        "owner": "NixOS",
-        "ref": "release-24.05",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "nixpkgs_4": {
-      "locked": {
-        "lastModified": 1733212471,
-        "narHash": "sha256-M1+uCoV5igihRfcUKrr1riygbe73/dzNnzPsmaLCmpo=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "55d15ad12a74eb7d4646254e13638ad0c4128776",
-        "type": "github"
-      },
-      "original": {
-        "owner": "NixOS",
-        "ref": "nixos-unstable",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "nixpkgs_5": {
       "locked": {
         "lastModified": 1702272962,
         "narHash": "sha256-D+zHwkwPc6oYQ4G3A1HuadopqRwUY/JkMwHz1YF7j4Q=",
@@ -1399,23 +744,23 @@
         "type": "github"
       }
     },
-    "nixpkgs_6": {
+    "nixpkgs_2": {
       "locked": {
-        "lastModified": 1747418223,
-        "narHash": "sha256-DkCYFm09AR2+FPKcT7lD8iIMNXqTdesVvwKpCnqKiYg=",
+        "lastModified": 1748085680,
+        "narHash": "sha256-XG90Q/040NiV70gAVvoYbXg1lULbiwIzfkWmwSINyGQ=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "d6c9326e40bb557ebb8c040b4375590bc06413f8",
+        "rev": "4e6eeca5ed45465087274fc9dc6bc2011254a0f3",
         "type": "github"
       },
       "original": {
         "owner": "nixos",
-        "ref": "nixos-24.11-small",
+        "ref": "nixos-25.05-small",
         "repo": "nixpkgs",
         "type": "github"
       }
     },
-    "nixpkgs_7": {
+    "nixpkgs_3": {
       "locked": {
         "lastModified": 1700612854,
         "narHash": "sha256-yrQ8osMD+vDLGFX7pcwsY/Qr5PUd6OmDMYJZzZi0+zc=",
@@ -1431,7 +776,7 @@
         "type": "github"
       }
     },
-    "nixpkgs_8": {
+    "nixpkgs_4": {
       "locked": {
         "lastModified": 1715534503,
         "narHash": "sha256-5ZSVkFadZbFP1THataCaSf0JH2cAH3S29hU9rrxTEqk=",
@@ -1447,7 +792,7 @@
         "type": "github"
       }
     },
-    "nixpkgs_9": {
+    "nixpkgs_5": {
       "locked": {
         "lastModified": 1715534503,
         "narHash": "sha256-5ZSVkFadZbFP1THataCaSf0JH2cAH3S29hU9rrxTEqk=",
@@ -1463,6 +808,48 @@
         "type": "github"
       }
     },
+    "nixpkgs_6": {
+      "locked": {
+        "lastModified": 1719506693,
+        "narHash": "sha256-C8e9S7RzshSdHB7L+v9I51af1gDM5unhJ2xO1ywxNH8=",
+        "path": "/nix/store/4p0avw1s3vf27hspgqsrqs37gxk4i83i-source",
+        "rev": "b2852eb9365c6de48ffb0dc2c9562591f652242a",
+        "type": "path"
+      },
+      "original": {
+        "id": "nixpkgs",
+        "type": "indirect"
+      }
+    },
+    "nixpkgs_7": {
+      "locked": {
+        "lastModified": 1719506693,
+        "narHash": "sha256-C8e9S7RzshSdHB7L+v9I51af1gDM5unhJ2xO1ywxNH8=",
+        "path": "/nix/store/4p0avw1s3vf27hspgqsrqs37gxk4i83i-source",
+        "rev": "b2852eb9365c6de48ffb0dc2c9562591f652242a",
+        "type": "path"
+      },
+      "original": {
+        "id": "nixpkgs",
+        "type": "indirect"
+      }
+    },
+    "nixpkgs_8": {
+      "locked": {
+        "lastModified": 1729850857,
+        "narHash": "sha256-WvLXzNNnnw+qpFOmgaM3JUlNEH+T4s22b5i2oyyCpXE=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "41dea55321e5a999b17033296ac05fe8a8b5a257",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixpkgs-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
     "pre-commit-hooks": {
       "inputs": {
         "flake-compat": [
@@ -1472,7 +859,7 @@
           "crate2nix_stable",
           "flake-compat"
         ],
-        "gitignore": "gitignore_2",
+        "gitignore": "gitignore",
         "nixpkgs": [
           "sonnenshift",
           "crate2nix",
@@ -1510,7 +897,7 @@
           "crate2nix_stable",
           "flake-compat"
         ],
-        "gitignore": "gitignore_3",
+        "gitignore": "gitignore_2",
         "nixpkgs": [
           "sonnenshift",
           "crate2nix",
@@ -1545,8 +932,8 @@
           "crate2nix",
           "flake-compat"
         ],
-        "flake-utils": "flake-utils_6",
-        "gitignore": "gitignore_4",
+        "flake-utils": "flake-utils_5",
+        "gitignore": "gitignore_3",
         "nixpkgs": [
           "sonnenshift",
           "crate2nix",
@@ -1574,7 +961,7 @@
     },
     "purescript-overlay": {
       "inputs": {
-        "flake-compat": "flake-compat_8",
+        "flake-compat": "flake-compat_5",
         "nixpkgs": [
           "tlaternet-webserver",
           "dream2nix",
@@ -1613,54 +1000,18 @@
         "type": "github"
       }
     },
-    "rocksdb": {
-      "flake": false,
-      "locked": {
-        "lastModified": 1741308171,
-        "narHash": "sha256-YdBvdQ75UJg5ffwNjxizpviCVwVDJnBkM8ZtGIduMgY=",
-        "owner": "girlbossceo",
-        "repo": "rocksdb",
-        "rev": "3ce04794bcfbbb0d2e6f81ae35fc4acf688b6986",
-        "type": "github"
-      },
-      "original": {
-        "owner": "girlbossceo",
-        "ref": "v9.11.1",
-        "repo": "rocksdb",
-        "type": "github"
-      }
-    },
     "root": {
       "inputs": {
-        "continuwuity": "continuwuity",
         "deploy-rs": "deploy-rs",
         "disko": "disko",
         "foundryvtt": "foundryvtt",
-        "nixpkgs": "nixpkgs_6",
-        "nixpkgs-unstable": "nixpkgs-unstable",
+        "nixpkgs": "nixpkgs_2",
         "sonnenshift": "sonnenshift",
         "sops-nix": "sops-nix",
         "tlaternet-webserver": "tlaternet-webserver"
       }
     },
     "rust-analyzer-src": {
-      "flake": false,
-      "locked": {
-        "lastModified": 1740691488,
-        "narHash": "sha256-Fs6vBrByuiOf2WO77qeMDMTXcTGzrIMqLBv+lNeywwM=",
-        "owner": "rust-lang",
-        "repo": "rust-analyzer",
-        "rev": "fe3eda77d3a7ce212388bda7b6cec8bffcc077e5",
-        "type": "github"
-      },
-      "original": {
-        "owner": "rust-lang",
-        "ref": "nightly",
-        "repo": "rust-analyzer",
-        "type": "github"
-      }
-    },
-    "rust-analyzer-src_2": {
       "flake": false,
       "locked": {
         "lastModified": 1737140097,
@@ -1728,11 +1079,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1746485181,
-        "narHash": "sha256-PxrrSFLaC7YuItShxmYbMgSuFFuwxBB+qsl9BZUnRvg=",
+        "lastModified": 1747603214,
+        "narHash": "sha256-lAblXm0VwifYCJ/ILPXJwlz0qNY07DDYdLD+9H+Wc8o=",
         "owner": "Mic92",
         "repo": "sops-nix",
-        "rev": "e93ee1d900ad264d65e9701a5c6f895683433386",
+        "rev": "8d215e1c981be3aa37e47aeabd4e61bb069548fd",
         "type": "github"
       },
       "original": {
@@ -1831,25 +1182,10 @@
         "type": "github"
       }
     },
-    "systems_7": {
-      "locked": {
-        "lastModified": 1681028828,
-        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
-        "owner": "nix-systems",
-        "repo": "default",
-        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nix-systems",
-        "repo": "default",
-        "type": "github"
-      }
-    },
     "tlaternet-webserver": {
       "inputs": {
         "dream2nix": "dream2nix",
-        "fenix": "fenix_2",
+        "fenix": "fenix",
         "nixpkgs": [
           "nixpkgs"
         ]
@@ -1870,7 +1206,7 @@
     },
     "utils": {
       "inputs": {
-        "systems": "systems_2"
+        "systems": "systems"
       },
       "locked": {
         "lastModified": 1701680307,

From 94ec261a94a844f33d5f98e5633f260449e7cf64 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sun, 25 May 2025 02:11:31 +0800
Subject: [PATCH 67/67] chore(foundryvtt): Upgrade to version 13

---
 configuration/services/foundryvtt.nix | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/configuration/services/foundryvtt.nix b/configuration/services/foundryvtt.nix
index f25bbcd..6c475a3 100644
--- a/configuration/services/foundryvtt.nix
+++ b/configuration/services/foundryvtt.nix
@@ -18,7 +18,7 @@ in
       minifyStaticFiles = true;
       proxySSL = true;
       proxyPort = 443;
-      package = flake-inputs.foundryvtt.packages.${pkgs.system}.foundryvtt_11;
+      package = flake-inputs.foundryvtt.packages.${pkgs.system}.foundryvtt_13;
     };
 
     nginx.virtualHosts."${domain}" =