diff --git a/common.nix b/common.nix index 5086598..ced8d64 100644 --- a/common.nix +++ b/common.nix @@ -125,6 +125,7 @@ in ./services/code-server.nix ./services/redlib.nix ./services/stardew-tracker.nix + ./services/flowtrack.nix ./services/hardware-health.nix ./services/wan-watchdog.nix ./services/deployment.nix diff --git a/flake.lock b/flake.lock index c7eb073..35d8477 100644 --- a/flake.lock +++ b/flake.lock @@ -170,6 +170,26 @@ "type": "github" } }, + "flowtrack": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1792309033, + "narHash": "sha256-77igZpo8WI7XbLuAgD0HibkgdKao4efvvCjezdMqssQ=", + "ref": "refs/heads/main", + "rev": "94372c6abc7f93070eddd9d0ac35962a36567309", + "revCount": 1, + "type": "git", + "url": "https://forg.gregersen.it/rope/flowtrack" + }, + "original": { + "type": "git", + "url": "https://forg.gregersen.it/rope/flowtrack" + } + }, "fromYaml": { "flake": false, "locked": { @@ -451,6 +471,7 @@ }, "root": { "inputs": { + "flowtrack": "flowtrack", "home-manager": "home-manager", "lanzaboote": "lanzaboote", "loupe": "loupe", diff --git a/flake.nix b/flake.nix index 5b131a9..0d848ef 100644 --- a/flake.nix +++ b/flake.nix @@ -35,6 +35,11 @@ flake = false; }; + flowtrack = { + url = "git+https://forg.gregersen.it/rope/flowtrack"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + stardew-tracker = { url = "git+https://forg.gregersen.it/rope/stardew-tracker"; inputs.nixpkgs.follows = "nixpkgs"; @@ -54,6 +59,7 @@ , stylix , proton-cachyos-nix , stardew-tracker + , flowtrack , ... } @ inputs: let @@ -64,6 +70,7 @@ home-manager.nixosModules.home-manager stylix.nixosModules.stylix stardew-tracker.nixosModules.default + flowtrack.nixosModules.default ./settings/stylix.nix ]; mkHost = hostname: extraModules: nixpkgs.lib.nixosSystem { diff --git a/services/authelia.nix b/services/authelia.nix index 8237d98..9a01d7e 100644 --- a/services/authelia.nix +++ b/services/authelia.nix @@ -44,6 +44,8 @@ { domain = "reddit.nordhammer.it"; policy = "one_factor"; } { domain = "panel.nordhammer.it"; policy = "one_factor"; } { domain = "stardew.nordhammer.it"; policy = "one_factor"; } + # Health data: only the two people the app knows about. + { domain = "flowtrack.nordhammer.it"; policy = "one_factor"; subject = [ "user:kayla" "user:fred" ]; } ]; }; @@ -52,8 +54,10 @@ domain = "nordhammer.it"; authelia_url = "https://auth.nordhammer.it"; }]; - expiration = "12h"; - inactivity = "2h"; + # Long enough that the home-screen Flowtrack app on a phone does not + # ask for a login every time it opens. + expiration = "30d"; + inactivity = "7d"; }; storage.local.path = "/var/lib/authelia-main/db.sqlite3"; diff --git a/services/flowtrack.nix b/services/flowtrack.nix new file mode 100644 index 0000000..8523ba0 --- /dev/null +++ b/services/flowtrack.nix @@ -0,0 +1,21 @@ +# services/flowtrack.nix — Kayla's private period tracker. +# +# The application and NixOS module live in the standalone flowtrack flake. +# nginx is the only public listener and Authelia admits just kayla and fred; +# the app maps them to owner and read-only viewer. Nightly snapshots go +# straight to the SSD branch of the pool (not via mergerfs), which had the +# cleanest SMART record of the data disks. +{ config, lib, ... }: +{ + config = lib.mkIf (config.networking.hostName == "FredOS-Mediaserver") { + services.flowtrack = { + enable = true; + port = 8093; + editors = [ "kayla" ]; + viewers = [ "fred" ]; + backup.directory = "/mnt/disk2/backups/flowtrack"; + }; + + systemd.tmpfiles.rules = [ "d /mnt/disk2/backups 0755 root root -" ]; + }; +} diff --git a/services/nginx.nix b/services/nginx.nix index 115df06..c754b5f 100644 --- a/services/nginx.nix +++ b/services/nginx.nix @@ -203,6 +203,13 @@ in proxy_set_header Remote-Email $email; ''; }; + # Period tracker. The app trusts Remote-User for roles, so nginx must + # always overwrite it with the Authelia identity. + "flowtrack.nordhammer.it" = lib.recursiveUpdate (protectedProxy 8093) { + locations."/".extraConfig = autheliaAuthConfig + '' + proxy_set_header Remote-User $user; + ''; + }; # Pelican game panel. Can't turn off its own login (no such option # upstream), so Authelia is the outer gate and the Pelican account