From 668140531b0a14b0ade9abbcace5713e20dac0f6 Mon Sep 17 00:00:00 2001 From: Lukas Wurzinger Date: Sat, 1 Mar 2025 22:21:00 +0100 Subject: [PATCH] =?UTF-8?q?pluh=20=F0=9F=97=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 + classes/headful/cosmic.nix | 15 + classes/headful/fs.nix | 15 - classes/headful/gtk.nix | 5 + classes/headful/hardware.nix | 5 - classes/headful/plasma.nix | 27 -- classes/headless/grafana.nix | 43 +++ classes/headless/loki.nix | 79 +++++ classes/headless/prometheus.nix | 34 +++ classes/headless/promtail.nix | 42 +++ classes/kiosk/cosmic.nix | 31 ++ classes/kiosk/flatpak.nix | 14 + classes/kiosk/fonts.nix | 26 ++ classes/kiosk/gtk.nix | 5 + classes/kiosk/hardware.nix | 16 + classes/kiosk/location.nix | 3 + classes/kiosk/mullvad.nix | 6 + classes/kiosk/networking.nix | 10 + classes/kiosk/pipewire.nix | 11 + classes/kiosk/wayland.nix | 6 + classes/kiosk/xdg.nix | 3 + common/boot.nix | 5 + common/nix.nix | 9 +- common/puter.nix | 9 +- common/users.nix | 3 +- flake.lock | 280 +++++++++++++++--- flake.nix | 2 + hosts/headful/flamingo/filesystems.nix | 9 + hosts/headful/glacier/filesystems.nix | 9 + hosts/headful/glacier/lanzaboote.nix | 3 + hosts/headful/work/filesystems.nix | 9 + hosts/headless/abacus/authorized-keys.nix | 5 + hosts/headless/abacus/filesystems.nix | 14 + hosts/headless/abacus/fs.nix | 7 - hosts/headless/abacus/hardware.nix | 4 +- .../headless/vessel/filesystems.nix | 7 +- hosts/kiosk/insomniac/dolphin.nix | 5 + .../insomniac/filesystems.nix} | 4 +- hosts/kiosk/insomniac/firefox.nix | 5 + hosts/kiosk/insomniac/freetube.nix | 5 + hosts/kiosk/insomniac/hardware.nix | 25 ++ hosts/kiosk/insomniac/rmg.nix | 5 + hosts/kiosk/insomniac/steam.nix | 5 + hosts/kiosk/insomniac/system.nix | 3 + hosts/kiosk/insomniac/users.nix | 12 + lib.nix | 6 + modules/secure-boot.nix | 28 ++ packages/disk/disk.bash | 199 +++++++++---- packages/puter/puter.bash | 78 +++-- pubkeys.nix | 1 + secrets/forgejo-admin.age | Bin 558 -> 558 bytes secrets/forgejo-mailer.age | Bin 558 -> 558 bytes secrets/microbin.age | Bin 663 -> 663 bytes secrets/miniflux.age | Bin 599 -> 599 bytes secrets/restic-abacus.age | 21 +- secrets/restic-vessel.age | 20 +- secrets/secrets.nix | 3 +- secrets/user-lukas.age | Bin 1088 -> 1088 bytes secrets/vaultwarden.age | Bin 867 -> 867 bytes 59 files changed, 985 insertions(+), 219 deletions(-) create mode 100644 classes/headful/cosmic.nix delete mode 100644 classes/headful/fs.nix create mode 100644 classes/headful/gtk.nix delete mode 100644 classes/headful/plasma.nix create mode 100644 classes/headless/grafana.nix create mode 100644 classes/headless/loki.nix create mode 100644 classes/headless/prometheus.nix create mode 100644 classes/headless/promtail.nix create mode 100644 classes/kiosk/cosmic.nix create mode 100644 classes/kiosk/flatpak.nix create mode 100644 classes/kiosk/fonts.nix create mode 100644 classes/kiosk/gtk.nix create mode 100644 classes/kiosk/hardware.nix create mode 100644 classes/kiosk/location.nix create mode 100644 classes/kiosk/mullvad.nix create mode 100644 classes/kiosk/networking.nix create mode 100644 classes/kiosk/pipewire.nix create mode 100644 classes/kiosk/wayland.nix create mode 100644 classes/kiosk/xdg.nix create mode 100644 hosts/headful/flamingo/filesystems.nix create mode 100644 hosts/headful/glacier/filesystems.nix create mode 100644 hosts/headful/glacier/lanzaboote.nix create mode 100644 hosts/headful/work/filesystems.nix create mode 100644 hosts/headless/abacus/authorized-keys.nix create mode 100644 hosts/headless/abacus/filesystems.nix delete mode 100644 hosts/headless/abacus/fs.nix rename classes/headless/fs.nix => hosts/headless/vessel/filesystems.nix (56%) create mode 100644 hosts/kiosk/insomniac/dolphin.nix rename hosts/{headless/vessel/fs.nix => kiosk/insomniac/filesystems.nix} (51%) create mode 100644 hosts/kiosk/insomniac/firefox.nix create mode 100644 hosts/kiosk/insomniac/freetube.nix create mode 100644 hosts/kiosk/insomniac/hardware.nix create mode 100644 hosts/kiosk/insomniac/rmg.nix create mode 100644 hosts/kiosk/insomniac/steam.nix create mode 100644 hosts/kiosk/insomniac/system.nix create mode 100644 hosts/kiosk/insomniac/users.nix create mode 100644 modules/secure-boot.nix diff --git a/README.md b/README.md index 92860db..cd2b8cf 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ # :snowflake: puter This is my cobbled together NixOS configuration. There are many like it, but this one is mine. Copy at your own risk. + +## TODO + +- [ ] lanzaboote +- [ ] monitoring (prometheus) +- [ ] logging (loki) +- [ ] kiosk +- [ ] tailscale and headscale diff --git a/classes/headful/cosmic.nix b/classes/headful/cosmic.nix new file mode 100644 index 0000000..3c3caf6 --- /dev/null +++ b/classes/headful/cosmic.nix @@ -0,0 +1,15 @@ +{inputs, ...}: { + imports = [ + inputs.nixos-cosmic.nixosModules.default + ]; + + nix.settings = { + substituters = ["https://cosmic.cachix.org/"]; + trusted-public-keys = ["cosmic.cachix.org-1:Dya9IyXD4xdBehWjrkPv6rtxpmMdRel02smYzA85dPE="]; + }; + + services = { + desktopManager.cosmic.enable = true; + displayManager.cosmic-greeter.enable = true; + }; +} diff --git a/classes/headful/fs.nix b/classes/headful/fs.nix deleted file mode 100644 index 03989d2..0000000 --- a/classes/headful/fs.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ - boot.initrd.luks.devices.main.device = "/dev/disk/by-label/cryptmain"; - - fileSystems = { - "/" = { - fsType = "ext4"; - device = "/dev/mapper/main"; - options = ["noatime"]; - }; - "/boot" = { - label = "BOOT"; - fsType = "vfat"; - }; - }; -} diff --git a/classes/headful/gtk.nix b/classes/headful/gtk.nix new file mode 100644 index 0000000..b420942 --- /dev/null +++ b/classes/headful/gtk.nix @@ -0,0 +1,5 @@ +{ + xdg.portal.extraPortals = [pkgs.xdg-desktop-portal-gtk]; + + programs.dconf.enable = true; +} diff --git a/classes/headful/hardware.nix b/classes/headful/hardware.nix index b5416cc..05f7363 100644 --- a/classes/headful/hardware.nix +++ b/classes/headful/hardware.nix @@ -7,15 +7,10 @@ opentabletdriver.enable = true; graphics = { enable = true; - enable32Bit = true; extraPackages = [ pkgs.libvdpau-va-gl pkgs.vaapiVdpau ]; - extraPackages32 = [ - pkgs.pkgsi686Linux.libvdpau-va-gl - pkgs.pkgsi686Linux.vaapiVdpau - ]; }; }; } diff --git a/classes/headful/plasma.nix b/classes/headful/plasma.nix deleted file mode 100644 index e4a722a..0000000 --- a/classes/headful/plasma.nix +++ /dev/null @@ -1,27 +0,0 @@ -{pkgs, ...}: { - services = { - desktopManager.plasma6.enable = true; - displayManager.sddm = { - enable = true; - wayland.enable = true; - }; - }; - - environment.systemPackages = [ - pkgs.kdePackages.sddm-kcm - pkgs.kdePackages.discover - pkgs.kdePackages.kate - ]; - - programs = { - kdeconnect.enable = true; - partition-manager.enable = true; - }; - - xdg.portal = { - xdgOpenUsePortal = true; - extraPortals = [pkgs.xdg-desktop-portal-gtk]; - }; - - programs.dconf.enable = true; -} diff --git a/classes/headless/grafana.nix b/classes/headless/grafana.nix new file mode 100644 index 0000000..d1e49d4 --- /dev/null +++ b/classes/headless/grafana.nix @@ -0,0 +1,43 @@ +{ + services.grafana = { + enable = true; + domain = "grafana.pele"; + port = 9010; + addr = "127.0.0.1"; + + # WARNING: this should match nginx setup! + # prevents "Request origin is not authorized" + rootUrl = "http://192.168.1.10:8010"; # helps with nginx / ws / live + + protocol = "http"; + analytics.reporting.enable = false; + + provision = { + enable = true; + datasources = [ + { + name = "Prometheus"; + type = "prometheus"; + access = "proxy"; + url = "http://127.0.0.1:${toString config.services.prometheus.port}"; + } + { + name = "Loki"; + type = "loki"; + access = "proxy"; + url = "http://127.0.0.1:${toString config.services.loki.configuration.server.http_listen_port}"; + } + ]; + }; + }; + + services.nginx.virtualHosts.${config.services.grafana.domain} = { + locations."/" = { + proxyPass = "http://${lib.formatHostPort { + host = config.services.grafana.addr; + inherit (config.services.grafana) port; + }}"; + proxyWebsockets = true; + }; + }; +} diff --git a/classes/headless/loki.nix b/classes/headless/loki.nix new file mode 100644 index 0000000..0081db1 --- /dev/null +++ b/classes/headless/loki.nix @@ -0,0 +1,79 @@ +{ + services.loki = { + enable = true; + configuration = { + server.http_listen_port = 3030; + auth_enabled = false; + + ingester = { + lifecycler = { + address = "127.0.0.1"; + ring = { + kvstore = { + store = "inmemory"; + }; + replication_factor = 1; + }; + }; + chunk_idle_period = "1h"; + max_chunk_age = "1h"; + chunk_target_size = 999999; + chunk_retain_period = "30s"; + max_transfer_retries = 0; + }; + + schema_config = { + configs = [ + { + from = "2022-06-06"; + store = "boltdb-shipper"; + object_store = "filesystem"; + schema = "v12"; + index = { + prefix = "index_"; + period = "24h"; + }; + } + ]; + }; + + storage_config = { + boltdb_shipper = { + active_index_directory = "/var/lib/loki/boltdb-shipper-active"; + cache_location = "/var/lib/loki/boltdb-shipper-cache"; + cache_ttl = "24h"; + shared_store = "filesystem"; + }; + + filesystem = { + directory = "/var/lib/loki/chunks"; + }; + }; + + limits_config = { + reject_old_samples = true; + reject_old_samples_max_age = "168h"; + }; + + chunk_store_config = { + max_look_back_period = "0s"; + }; + + table_manager = { + retention_deletes_enabled = false; + retention_period = "0s"; + }; + + compactor = { + working_directory = "/var/lib/loki"; + shared_store = "filesystem"; + compactor_ring = { + kvstore = { + store = "inmemory"; + }; + }; + }; + }; + # user, group, dataDir, extraFlags, (configFile) + }; +} diff --git a/classes/headless/prometheus.nix b/classes/headless/prometheus.nix new file mode 100644 index 0000000..0daaa69 --- /dev/null +++ b/classes/headless/prometheus.nix @@ -0,0 +1,34 @@ +{ + config, + lib, + ... +}: { + services.prometheus = { + enable = true; + port = 3020; + + exporters = { + node = { + enable = true; + port = 3021; + enabledCollectors = ["systemd"]; + }; + }; + + scrapeConfigs = [ + { + job_name = "nodes"; + static_configs = [ + { + targets = let + target = lib.formatHostPort { + host = config.services.prometheus.exporters.node.listenAddr; + inherit (config.services.prometheus.exporters.node) port; + }; + in [target]; + } + ]; + } + ]; + }; +} diff --git a/classes/headless/promtail.nix b/classes/headless/promtail.nix new file mode 100644 index 0000000..e1dfad5 --- /dev/null +++ b/classes/headless/promtail.nix @@ -0,0 +1,42 @@ +{config, ...}: { + services.promtail = { + enable = true; + + configuration = { + server = { + http_listen_port = 3031; + grpc_listen_port = 0; + }; + + positions = { + filename = "/tmp/positions.yaml"; + }; + + clients = [ + { + url = "http://127.0.0.1:${toString config.services.loki.configuration.server.http_listen_port}/loki/api/v1/push"; + } + ]; + + scrape_configs = [ + { + job_name = "journal"; + journal = { + max_age = "12h"; + labels = { + job = "systemd-journal"; + host = "pihole"; + }; + }; + relabel_configs = [ + { + source_labels = ["__journal__systemd_unit"]; + target_label = "unit"; + } + ]; + } + ]; + }; + # extraFlags + }; +} diff --git a/classes/kiosk/cosmic.nix b/classes/kiosk/cosmic.nix new file mode 100644 index 0000000..ada019e --- /dev/null +++ b/classes/kiosk/cosmic.nix @@ -0,0 +1,31 @@ +{ + config, + inputs, + pkgs, + ... +}: { + imports = [ + inputs.nixos-cosmic.nixosModules.default + ]; + + nix.settings = { + substituters = ["https://cosmic.cachix.org/"]; + trusted-public-keys = ["cosmic.cachix.org-1:Dya9IyXD4xdBehWjrkPv6rtxpmMdRel02smYzA85dPE="]; + }; + + services = { + desktopManager.cosmic.enable = true; + displayManager.cosmic-greeter.enable = true; + + greetd.settings.initial_session = { + user = config.users.mainUser; + command = '' + ${lib.getExe' pkgs.coreutils "env"} XCURSOR_THEME="''${XCURSOR_THEME:-Pop}" systemd-cat --identifier start-cosmic ${lib.getExe' pkgs.cosmic-session "start-cosmic"} + ''; + }; + }; + + environment.cosmic.excludePackages = [ + pkgs.cosmic-store + ]; +} diff --git a/classes/kiosk/flatpak.nix b/classes/kiosk/flatpak.nix new file mode 100644 index 0000000..f59aa97 --- /dev/null +++ b/classes/kiosk/flatpak.nix @@ -0,0 +1,14 @@ +{inputs, ...}: { + imports = [ + inputs.flatpak.nixosModules.nix-flatpak + ]; + + services.flatpak = { + enable = true; + + update.auto = { + enable = true; + onCalendar = "weekly"; + }; + }; +} diff --git a/classes/kiosk/fonts.nix b/classes/kiosk/fonts.nix new file mode 100644 index 0000000..24ab985 --- /dev/null +++ b/classes/kiosk/fonts.nix @@ -0,0 +1,26 @@ +{pkgs, ...}: { + fonts = { + enableDefaultPackages = true; + packages = [ + pkgs.noto-fonts + pkgs.noto-fonts-extra + pkgs.noto-fonts-cjk-sans + pkgs.noto-fonts-cjk-serif + pkgs.noto-fonts-monochrome-emoji + pkgs.noto-fonts-color-emoji + ]; + + fontconfig = { + enable = true; + + defaultFonts = { + monospace = ["Noto Sans Mono"]; + sansSerif = ["Noto Sans"]; + serif = ["Noto Serif"]; + emoji = ["Noto Color Emoji" "Noto Emoji"]; + }; + }; + + fontDir.enable = true; + }; +} diff --git a/classes/kiosk/gtk.nix b/classes/kiosk/gtk.nix new file mode 100644 index 0000000..b420942 --- /dev/null +++ b/classes/kiosk/gtk.nix @@ -0,0 +1,5 @@ +{ + xdg.portal.extraPortals = [pkgs.xdg-desktop-portal-gtk]; + + programs.dconf.enable = true; +} diff --git a/classes/kiosk/hardware.nix b/classes/kiosk/hardware.nix new file mode 100644 index 0000000..05f7363 --- /dev/null +++ b/classes/kiosk/hardware.nix @@ -0,0 +1,16 @@ +{pkgs, ...}: { + hardware = { + bluetooth.enable = true; + steam-hardware.enable = true; + xone.enable = true; + xpadneo.enable = true; + opentabletdriver.enable = true; + graphics = { + enable = true; + extraPackages = [ + pkgs.libvdpau-va-gl + pkgs.vaapiVdpau + ]; + }; + }; +} diff --git a/classes/kiosk/location.nix b/classes/kiosk/location.nix new file mode 100644 index 0000000..474ee00 --- /dev/null +++ b/classes/kiosk/location.nix @@ -0,0 +1,3 @@ +{ + location.provider = "geoclue2"; +} diff --git a/classes/kiosk/mullvad.nix b/classes/kiosk/mullvad.nix new file mode 100644 index 0000000..31d3c05 --- /dev/null +++ b/classes/kiosk/mullvad.nix @@ -0,0 +1,6 @@ +{pkgs, ...}: { + services.mullvad-vpn = { + enable = true; + package = pkgs.mullvad-vpn; + }; +} diff --git a/classes/kiosk/networking.nix b/classes/kiosk/networking.nix new file mode 100644 index 0000000..d7cd8c0 --- /dev/null +++ b/classes/kiosk/networking.nix @@ -0,0 +1,10 @@ +{config, ...}: { + services.resolved.enable = true; + + networking.networkmanager = { + enable = true; + dns = "systemd-resolved"; + }; + + users.groups.networkmanager.members = config.users.normalUsers; +} diff --git a/classes/kiosk/pipewire.nix b/classes/kiosk/pipewire.nix new file mode 100644 index 0000000..157b2af --- /dev/null +++ b/classes/kiosk/pipewire.nix @@ -0,0 +1,11 @@ +{ + security.rtkit.enable = true; + + services.pipewire = { + enable = true; + wireplumber.enable = true; + alsa.enable = true; + pulse.enable = true; + jack.enable = true; + }; +} diff --git a/classes/kiosk/wayland.nix b/classes/kiosk/wayland.nix new file mode 100644 index 0000000..d11e343 --- /dev/null +++ b/classes/kiosk/wayland.nix @@ -0,0 +1,6 @@ +{ + environment.sessionVariables = { + NIXOS_OZONE_WL = "1"; + SDL_VIDEODRIVER = "wayland"; + }; +} diff --git a/classes/kiosk/xdg.nix b/classes/kiosk/xdg.nix new file mode 100644 index 0000000..a5a81d9 --- /dev/null +++ b/classes/kiosk/xdg.nix @@ -0,0 +1,3 @@ +{ + xdg.portal.xdgOpenUsePortal = true; +} diff --git a/common/boot.nix b/common/boot.nix index 403a4a4..ce488d2 100644 --- a/common/boot.nix +++ b/common/boot.nix @@ -1,4 +1,9 @@ { + fileSystems."/boot" = { + label = "BOOT"; + fsType = "vfat"; + }; + boot = { loader = { systemd-boot = { diff --git a/common/nix.nix b/common/nix.nix index 6b3bc34..f435fe5 100644 --- a/common/nix.nix +++ b/common/nix.nix @@ -9,9 +9,14 @@ nixPath = lib.mapAttrsToList (key: _: "${key}=flake:${key}") config.nix.registry; + optimise.automatic = true; + settings = { - trusted-users = config.users.normalUsers; - experimental-features = "nix-command flakes"; + trusted-users = ["root"] ++ config.users.normalUsers; + experimental-features = [ + "nix-command" + "flakes" + ]; auto-optimise-store = true; }; }; diff --git a/common/puter.nix b/common/puter.nix index 3991496..9304941 100644 --- a/common/puter.nix +++ b/common/puter.nix @@ -3,7 +3,10 @@ self, ... }: { - environment.systemPackages = [ - self.packages.${pkgs.system}.puter - ]; + environment = { + systemPackages = [ + self.packages.${pkgs.system}.puter + ]; + sessionVariables.PUTER_FLAKEREF = "git+https://forgejo@tea.wrz.one/lukas/puter.git"; + }; } diff --git a/common/users.nix b/common/users.nix index 5354763..fb5a0fc 100644 --- a/common/users.nix +++ b/common/users.nix @@ -15,7 +15,8 @@ in { users = { root = { hashedPassword = "!"; - openssh.authorizedKeys.keys = builtins.attrValues config.pubkeys.hosts; + # TODO define this more granularly + openssh.authorizedKeys.keys = []; }; ${mainUser} = { description = "Lukas Wurzinger"; diff --git a/flake.lock b/flake.lock index a20a87b..b9afc0a 100644 --- a/flake.lock +++ b/flake.lock @@ -35,11 +35,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1728672398, - "narHash": "sha256-KxuGSoVUFnQLB2ZcYODW7AVPAh9JqRlD5BrfsC/Q4qs=", + "lastModified": 1737621947, + "narHash": "sha256-8HFvG7fvIFbgtaYAY2628Tb89fA55nPm2jSiNs0/Cws=", "owner": "cachix", "repo": "cachix", - "rev": "aac51f698309fd0f381149214b7eee213c66ef0a", + "rev": "f65a3cd5e339c223471e64c051434616e18cc4f5", "type": "github" }, "original": { @@ -49,6 +49,21 @@ "type": "github" } }, + "crane": { + "locked": { + "lastModified": 1731098351, + "narHash": "sha256-HQkYvKvaLQqNa10KEFGgWHfMAbWBfFp+4cAgkut+NNE=", + "owner": "ipetkov", + "repo": "crane", + "rev": "ef80ead953c1b28316cc3f8613904edc2eb90c28", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, "darwin": { "inputs": { "nixpkgs": [ @@ -80,11 +95,11 @@ "nixpkgs": "nixpkgs_4" }, "locked": { - "lastModified": 1737973553, - "narHash": "sha256-mHi+KLwCPEgGg2x4WVvvNU4BvBSq6HJUkilzrQUShsg=", + "lastModified": 1740678151, + "narHash": "sha256-q0tKL+Yny0wkLCHRBHQ97YhjorNLnbnyjc+FnQZyKkM=", "owner": "cachix", "repo": "devenv", - "rev": "252cfc8ca213dd3627100339d3fcc829fb2d960a", + "rev": "af151da5e3d7391fe778050da00d8e7cefa2d087", "type": "github" }, "original": { @@ -106,6 +121,22 @@ } }, "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1733328505, + "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_2": { "flake": false, "locked": { "lastModified": 1696426674, @@ -121,7 +152,7 @@ "type": "github" } }, - "flake-compat_2": { + "flake-compat_3": { "flake": false, "locked": { "lastModified": 1733328505, @@ -164,11 +195,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1736143030, - "narHash": "sha256-+hu54pAoLDEZT9pjHlqL9DNzWz0NbUn8NEAHP7PQPzU=", + "lastModified": 1738453229, + "narHash": "sha256-7H9XgNiGLKN1G1CgRh0vUL4AheZSYzPm+zmZ7vxbJdo=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "b905f6fc23a9051a6e1b741e1438dbfc0634c6de", + "rev": "32ea77a06711b758da0ad9bd6a844c5740a87abd", "type": "github" }, "original": { @@ -177,6 +208,43 @@ "type": "github" } }, + "flake-parts_3": { + "inputs": { + "nixpkgs-lib": [ + "lanzaboote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1730504689, + "narHash": "sha256-hgmguH29K2fvs9szpq2r3pz2/8cJd2LPS+b4tfNFCwE=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "506278e768c2a08bec68eb62932193e341f55c90", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flatpak": { + "locked": { + "lastModified": 1739444422, + "narHash": "sha256-iAVVHi7X3kWORftY+LVbRiStRnQEob2TULWyjMS6dWg=", + "owner": "gmodena", + "repo": "nix-flatpak", + "rev": "5e54c3ca05a7c7d968ae1ddeabe01d2a9bc1e177", + "type": "github" + }, + "original": { + "owner": "gmodena", + "ref": "latest", + "repo": "nix-flatpak", + "type": "github" + } + }, "git-hooks": { "inputs": { "flake-compat": [ @@ -189,11 +257,11 @@ ] }, "locked": { - "lastModified": 1737301351, - "narHash": "sha256-2UNmLCKORvdBRhPGI8Vx0b6l7M8/QBey/nHLIxOl4jE=", + "lastModified": 1737465171, + "narHash": "sha256-R10v2hoJRLq8jcL4syVFag7nIGE7m13qO48wRIukWNg=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "15a87cedeb67e3dbc8d2f7b9831990dffcf4e69f", + "rev": "9364dc02281ce2d37a1f55b6e51f7c0f65a75f17", "type": "github" }, "original": { @@ -224,13 +292,35 @@ "type": "github" } }, + "gitignore_2": { + "inputs": { + "nixpkgs": [ + "lanzaboote", + "pre-commit-hooks-nix", + "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" + } + }, "hardware": { "locked": { - "lastModified": 1737751639, - "narHash": "sha256-ZEbOJ9iT72iwqXsiEMbEa8wWjyFvRA9Ugx8utmYbpz4=", + "lastModified": 1740646007, + "narHash": "sha256-dMReDQobS3kqoiUCQIYI9c0imPXRZnBubX20yX/G5LE=", "owner": "NixOS", "repo": "nixos-hardware", - "rev": "dfad538f751a5aa5d4436d9781ab27a6128ec9d4", + "rev": "009b764ac98a3602d41fc68072eeec5d24fc0e49", "type": "github" }, "original": { @@ -260,6 +350,30 @@ "type": "github" } }, + "lanzaboote": { + "inputs": { + "crane": "crane", + "flake-compat": "flake-compat_2", + "flake-parts": "flake-parts_3", + "nixpkgs": "nixpkgs_5", + "pre-commit-hooks-nix": "pre-commit-hooks-nix", + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1737639419, + "narHash": "sha256-AEEDktApTEZ5PZXNDkry2YV2k6t0dTgLPEmAZbnigXU=", + "owner": "nix-community", + "repo": "lanzaboote", + "rev": "a65905a09e2c43ff63be8c0e86a93712361f871e", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "v0.4.2", + "repo": "lanzaboote", + "type": "github" + } + }, "libgit2": { "flake": false, "locked": { @@ -295,11 +409,11 @@ ] }, "locked": { - "lastModified": 1727438425, - "narHash": "sha256-X8ES7I1cfNhR9oKp06F6ir4Np70WGZU5sfCOuNBEwMg=", + "lastModified": 1734114420, + "narHash": "sha256-n52PUzub5jZWc8nI/sR7UICOheU8rNA+YZ73YaHeCBg=", "owner": "domenkozar", "repo": "nix", - "rev": "f6c5ae4c1b2e411e6b1e6a8181cc84363d6a7546", + "rev": "bde6a1a0d1f2af86caa4d20d23eca019f3d57eee", "type": "github" }, "original": { @@ -327,23 +441,39 @@ }, "nixpkgs-lib": { "locked": { - "lastModified": 1735774519, - "narHash": "sha256-CewEm1o2eVAnoqb6Ml+Qi9Gg/EfNAxbRx1lANGVyoLI=", + "lastModified": 1738452942, + "narHash": "sha256-vJzFZGaCpnmo7I6i416HaBLpC+hvcURh/BQwROcGIp8=", "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/e9b51731911566bbf7e4895475a87fe06961de0b.tar.gz" + "url": "https://github.com/NixOS/nixpkgs/archive/072a6db25e947df2f31aab9eccd0ab75d5b2da11.tar.gz" }, "original": { "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/e9b51731911566bbf7e4895475a87fe06961de0b.tar.gz" + "url": "https://github.com/NixOS/nixpkgs/archive/072a6db25e947df2f31aab9eccd0ab75d5b2da11.tar.gz" + } + }, + "nixpkgs-stable": { + "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_2": { "locked": { - "lastModified": 1730531603, - "narHash": "sha256-Dqg6si5CqIzm87sp57j5nTaeBbWhHFaVyG7V6L8k3lY=", + "lastModified": 1733212471, + "narHash": "sha256-M1+uCoV5igihRfcUKrr1riygbe73/dzNnzPsmaLCmpo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "7ffd9ae656aec493492b44d0ddfb28e79a1ea25d", + "rev": "55d15ad12a74eb7d4646254e13638ad0c4128776", "type": "github" }, "original": { @@ -371,11 +501,11 @@ }, "nixpkgs_4": { "locked": { - "lastModified": 1716977621, - "narHash": "sha256-Q1UQzYcMJH4RscmpTkjlgqQDX5yi1tZL0O345Ri6vXQ=", + "lastModified": 1733477122, + "narHash": "sha256-qamMCz5mNpQmgBwc8SB5tVMlD5sbwVIToVZtSxMph9s=", "owner": "cachix", "repo": "devenv-nixpkgs", - "rev": "4267e705586473d3e5c8d50299e71503f16a6fb6", + "rev": "7bd9e84d0452f6d2e63b6e6da29fe73fac951857", "type": "github" }, "original": { @@ -387,11 +517,27 @@ }, "nixpkgs_5": { "locked": { - "lastModified": 1737885589, - "narHash": "sha256-Zf0hSrtzaM1DEz8//+Xs51k/wdSajticVrATqDrfQjg=", + "lastModified": 1731919951, + "narHash": "sha256-vOM6ETpl1yu9KLi/icTmLJIPbbdJCdAVYUXZceO/Ce4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "852ff1d9e153d8875a83602e03fdef8a63f0ecf8", + "rev": "04386ac325a813047fc314d4b4d838a5b1e3c7fe", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable-small", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_6": { + "locked": { + "lastModified": 1740695751, + "narHash": "sha256-D+R+kFxy1KsheiIzkkx/6L63wEHBYX21OIwlFV8JvDs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "6313551cd05425cd5b3e63fe47dbc324eabb15e4", "type": "github" }, "original": { @@ -401,13 +547,13 @@ "type": "github" } }, - "nixpkgs_6": { + "nixpkgs_7": { "locked": { - "lastModified": 1737525964, - "narHash": "sha256-3wFonKmNRWKq1himW9N3TllbeGIHFACI5vmLpk6moF8=", + "lastModified": 1740019556, + "narHash": "sha256-vn285HxnnlHLWnv59Og7muqECNMS33mWLM14soFIv2g=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "5757bbb8bd7c0630a0cc4bb19c47e588db30b97c", + "rev": "dad564433178067be1fbdfcce23b546254b6d641", "type": "github" }, "original": { @@ -419,16 +565,16 @@ }, "phps": { "inputs": { - "flake-compat": "flake-compat_2", - "nixpkgs": "nixpkgs_6", + "flake-compat": "flake-compat_3", + "nixpkgs": "nixpkgs_7", "utils": "utils" }, "locked": { - "lastModified": 1737949449, - "narHash": "sha256-7yVWKcXYlpvuj1roseMDRSSMMWw+m3PDnwPSwu5BO3A=", + "lastModified": 1740296995, + "narHash": "sha256-M0bsnyYP5DqO7EKL9ujwXCWKwwlg9F2xUklpMvbd/0s=", "owner": "fossar", "repo": "nix-phps", - "rev": "f2c3381b4ee144cb650f47e56548490c805decbe", + "rev": "6a6be7dd7f86f305deab7799a17af50aff0e3218", "type": "github" }, "original": { @@ -437,17 +583,67 @@ "type": "github" } }, + "pre-commit-hooks-nix": { + "inputs": { + "flake-compat": [ + "lanzaboote", + "flake-compat" + ], + "gitignore": "gitignore_2", + "nixpkgs": [ + "lanzaboote", + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1731363552, + "narHash": "sha256-vFta1uHnD29VUY4HJOO/D6p6rxyObnf+InnSMT4jlMU=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "cd1af27aa85026ac759d5d3fccf650abe7e1bbf0", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, "root": { "inputs": { "agenix": "agenix", "devenv": "devenv", "devenv-root": "devenv-root", "flake-parts": "flake-parts_2", + "flatpak": "flatpak", "hardware": "hardware", - "nixpkgs": "nixpkgs_5", + "lanzaboote": "lanzaboote", + "nixpkgs": "nixpkgs_6", "phps": "phps" } }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "lanzaboote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1731897198, + "narHash": "sha256-Ou7vLETSKwmE/HRQz4cImXXJBr/k9gp4J4z/PF8LzTE=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "0be641045af6d8666c11c2c40e45ffc9667839b5", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, "systems": { "locked": { "lastModified": 1681028828, diff --git a/flake.nix b/flake.nix index b31cfc3..ac85421 100644 --- a/flake.nix +++ b/flake.nix @@ -12,6 +12,8 @@ }; devenv.url = "github:cachix/devenv"; phps.url = "github:fossar/nix-phps"; + lanzaboote.url = "github:nix-community/lanzaboote/v0.4.2"; + flatpak.url = "github:gmodena/nix-flatpak?ref=latest"; }; outputs = { diff --git a/hosts/headful/flamingo/filesystems.nix b/hosts/headful/flamingo/filesystems.nix new file mode 100644 index 0000000..14ff284 --- /dev/null +++ b/hosts/headful/flamingo/filesystems.nix @@ -0,0 +1,9 @@ +{ + boot.initrd.luks.devices.main.device = "/dev/disk/by-label/cryptmain"; + + fileSystems."/" = { + fsType = "ext4"; + device = "/dev/mapper/main"; + options = ["noatime"]; + }; +} diff --git a/hosts/headful/glacier/filesystems.nix b/hosts/headful/glacier/filesystems.nix new file mode 100644 index 0000000..14ff284 --- /dev/null +++ b/hosts/headful/glacier/filesystems.nix @@ -0,0 +1,9 @@ +{ + boot.initrd.luks.devices.main.device = "/dev/disk/by-label/cryptmain"; + + fileSystems."/" = { + fsType = "ext4"; + device = "/dev/mapper/main"; + options = ["noatime"]; + }; +} diff --git a/hosts/headful/glacier/lanzaboote.nix b/hosts/headful/glacier/lanzaboote.nix new file mode 100644 index 0000000..9ede875 --- /dev/null +++ b/hosts/headful/glacier/lanzaboote.nix @@ -0,0 +1,3 @@ +{ + setups.secureBoot.enable = true; +} diff --git a/hosts/headful/work/filesystems.nix b/hosts/headful/work/filesystems.nix new file mode 100644 index 0000000..14ff284 --- /dev/null +++ b/hosts/headful/work/filesystems.nix @@ -0,0 +1,9 @@ +{ + boot.initrd.luks.devices.main.device = "/dev/disk/by-label/cryptmain"; + + fileSystems."/" = { + fsType = "ext4"; + device = "/dev/mapper/main"; + options = ["noatime"]; + }; +} diff --git a/hosts/headless/abacus/authorized-keys.nix b/hosts/headless/abacus/authorized-keys.nix new file mode 100644 index 0000000..41d2c3f --- /dev/null +++ b/hosts/headless/abacus/authorized-keys.nix @@ -0,0 +1,5 @@ +{config, ...}: { + users.users.root.openssh.authorizedKeys.keys = [ + config.pubkeys.hosts.vessel + ]; +} diff --git a/hosts/headless/abacus/filesystems.nix b/hosts/headless/abacus/filesystems.nix new file mode 100644 index 0000000..e22a8dd --- /dev/null +++ b/hosts/headless/abacus/filesystems.nix @@ -0,0 +1,14 @@ +{config, ...}: { + fileSystems = { + "/" = { + fsType = "ext4"; + label = "main"; + options = ["noatime"]; + }; + ${config.services.navidrome.settings.MusicFolder} = { + label = "music"; + fsType = "ext4"; + options = ["noatime"]; + }; + }; +} diff --git a/hosts/headless/abacus/fs.nix b/hosts/headless/abacus/fs.nix deleted file mode 100644 index 0a1531b..0000000 --- a/hosts/headless/abacus/fs.nix +++ /dev/null @@ -1,7 +0,0 @@ -{config, ...}: { - fileSystems.${config.services.navidrome.settings.MusicFolder} = { - label = "music"; - fsType = "ext4"; - options = ["noatime"]; - }; -} diff --git a/hosts/headless/abacus/hardware.nix b/hosts/headless/abacus/hardware.nix index dd4182c..8f2220e 100644 --- a/hosts/headless/abacus/hardware.nix +++ b/hosts/headless/abacus/hardware.nix @@ -1,5 +1,7 @@ {modulesPath, ...}: { - imports = ["${modulesPath}/profiles/qemu-guest.nix"]; + imports = [ + "${modulesPath}/profiles/qemu-guest.nix" + ]; nixpkgs.hostPlatform = "aarch64-linux"; diff --git a/classes/headless/fs.nix b/hosts/headless/vessel/filesystems.nix similarity index 56% rename from classes/headless/fs.nix rename to hosts/headless/vessel/filesystems.nix index 9c13b89..1da6965 100644 --- a/classes/headless/fs.nix +++ b/hosts/headless/vessel/filesystems.nix @@ -5,9 +5,10 @@ label = "main"; options = ["noatime"]; }; - "/boot" = { - label = "BOOT"; - fsType = "vfat"; + "/srv/backup" = { + label = "backup"; + fsType = "ext4"; + options = ["noatime"]; }; }; } diff --git a/hosts/kiosk/insomniac/dolphin.nix b/hosts/kiosk/insomniac/dolphin.nix new file mode 100644 index 0000000..c37c31b --- /dev/null +++ b/hosts/kiosk/insomniac/dolphin.nix @@ -0,0 +1,5 @@ +{ + services.flatpak.packages = [ + "org.DolphinEmu.dolphin-emu" + ]; +} diff --git a/hosts/headless/vessel/fs.nix b/hosts/kiosk/insomniac/filesystems.nix similarity index 51% rename from hosts/headless/vessel/fs.nix rename to hosts/kiosk/insomniac/filesystems.nix index e9bb2e0..5e977d8 100644 --- a/hosts/headless/vessel/fs.nix +++ b/hosts/kiosk/insomniac/filesystems.nix @@ -1,7 +1,7 @@ { - fileSystems."/srv/backup" = { - label = "backup"; + fileSystems."/" = { fsType = "ext4"; + label = "main"; options = ["noatime"]; }; } diff --git a/hosts/kiosk/insomniac/firefox.nix b/hosts/kiosk/insomniac/firefox.nix new file mode 100644 index 0000000..44cf818 --- /dev/null +++ b/hosts/kiosk/insomniac/firefox.nix @@ -0,0 +1,5 @@ +{ + services.flatpak.packages = [ + "org.mozilla.firefox" + ]; +} diff --git a/hosts/kiosk/insomniac/freetube.nix b/hosts/kiosk/insomniac/freetube.nix new file mode 100644 index 0000000..c56f588 --- /dev/null +++ b/hosts/kiosk/insomniac/freetube.nix @@ -0,0 +1,5 @@ +{ + services.flatpak.packages = [ + "io.freetubeapp.FreeTube" + ]; +} diff --git a/hosts/kiosk/insomniac/hardware.nix b/hosts/kiosk/insomniac/hardware.nix new file mode 100644 index 0000000..091424d --- /dev/null +++ b/hosts/kiosk/insomniac/hardware.nix @@ -0,0 +1,25 @@ +{ + inputs, + modulesPath, + ... +}: { + imports = [ + "${modulesPath}/installer/scan/not-detected.nix" + + inputs.hardware.nixosModules.common-cpu-amd + inputs.hardware.nixosModules.common-gpu-amd + inputs.hardware.nixosModules.common-pc-ssd + ]; + + nixpkgs.hostPlatform = "x86_64-linux"; + + boot = { + initrd = { + availableKernelModules = ["nvme" "xhci_pci" "ahci" "usb_storage" "sd_mod"]; + kernelModules = ["amdgpu"]; + }; + kernelModules = ["kvm-amd"]; + }; + + powerManagement.cpuFreqGovernor = "performance"; +} diff --git a/hosts/kiosk/insomniac/rmg.nix b/hosts/kiosk/insomniac/rmg.nix new file mode 100644 index 0000000..c8771df --- /dev/null +++ b/hosts/kiosk/insomniac/rmg.nix @@ -0,0 +1,5 @@ +{ + services.flatpak.packages = [ + "com.github.Rosalie241.RMG" + ]; +} diff --git a/hosts/kiosk/insomniac/steam.nix b/hosts/kiosk/insomniac/steam.nix new file mode 100644 index 0000000..e51a6e8 --- /dev/null +++ b/hosts/kiosk/insomniac/steam.nix @@ -0,0 +1,5 @@ +{ + services.flatpak.packages = [ + "com.valvesoftware.Steam" + ]; +} diff --git a/hosts/kiosk/insomniac/system.nix b/hosts/kiosk/insomniac/system.nix new file mode 100644 index 0000000..a05de83 --- /dev/null +++ b/hosts/kiosk/insomniac/system.nix @@ -0,0 +1,3 @@ +{ + system.stateVersion = "24.11"; +} diff --git a/hosts/kiosk/insomniac/users.nix b/hosts/kiosk/insomniac/users.nix new file mode 100644 index 0000000..c61ed67 --- /dev/null +++ b/hosts/kiosk/insomniac/users.nix @@ -0,0 +1,12 @@ +{ + config, + lib, + ... +}: let + inherit (config.users) mainUser; +in { + users = { + mainUser = lib.mkForce "user"; + users.${mainUser}.description = lib.mkForce "User"; + }; +} diff --git a/lib.nix b/lib.nix index 5323e84..b4f3667 100644 --- a/lib.nix +++ b/lib.nix @@ -9,6 +9,12 @@ lib: _: { ]) paths; + mkIfElse = condition: trueContent: falseContent: + lib.mkMerge [ + (lib.mkIf condition trueContent) + (lib.mkIf (!condition) falseContent) + ]; + formatHostPort = { host, port, diff --git a/modules/secure-boot.nix b/modules/secure-boot.nix new file mode 100644 index 0000000..7a37fce --- /dev/null +++ b/modules/secure-boot.nix @@ -0,0 +1,28 @@ +{ + config, + lib, + inputs, + pkgs, + ... +}: let + cfg = config.setups.secureBoot; +in { + imports = [ + inputs.lanzaboote.nixosModules.lanzaboote + ]; + + options.setups.secureBoot.enable = lib.mkEnableOption "Secure Boot"; + + config = lib.mkIf cfg.enable { + environment.systemPackages = [ + pkgs.sbctl + ]; + + boot.loader.systemd-boot.enable = lib.mkForce false; + + boot.lanzaboote = { + enable = lib.mkForce true; + pkiBundle = lib.mkDefault "/var/lib/sbctl"; + }; + }; +} diff --git a/packages/disk/disk.bash b/packages/disk/disk.bash index 7b9611b..c3e0887 100755 --- a/packages/disk/disk.bash +++ b/packages/disk/disk.bash @@ -19,50 +19,98 @@ error() { exit 1 } -args=$(getopt --options r:m:b:l:c: --longoptions=root:,mapping:,boot-label:,main-label:,cryptmain-label: --name "$progname" -- "$@") +skip() { + if (($# < 1)); then + error 'name of value to be skipped is required' + fi + + if (($# > 1)); then + error 'too many arguments' + fi + + local skip=$1 + + for s in "${skips[@]}"; do + if [[ $s == "$skip" ]]; then + return 1 + fi + done + + return 0 +} + +args=$( + getopt \ + --options r:b:l:c:m:B:M:v \ + --longoptions root:,boot-label:,main-label:,cryptmain-label:,mapping:,boot-options:,main-options:,verbose \ + --name "$progname" \ + -- "$@" +) eval set -- "$args" root=/mnt -mapping=main bootlbl=BOOT mainlbl=main cryptmainlbl=cryptmain +mapping=main +bootflags= +mainflags= +fatflags=() +ext4flags=() +skips=() while true; do - case "$1" in - (-r | --root) - root=$2 - shift 2 - ;; - (-m | --mapping) - mapping=$2 - shift 2 - ;; - (-b | --boot-label) - bootlbl=${2^^} - shift 2 - ;; - (-l | --main-label) - mainlbl=$2 - shift 2 - ;; - (-c | --cryptmain-label) - cryptmainlbl=$2 - shift 2 - ;; - (--) - shift - break - ;; - esac + case "$1" in + -r | --root) + root=$2 + shift 2 + ;; + -b | --boot-label) + skips+=(bootlbl) + bootlbl=${2^^} + shift 2 + ;; + -l | --main-label) + skips+=(mainlbl) + mainlbl=$2 + shift 2 + ;; + -c | --cryptmain-label) + skips+=(cryptmainlbl) + cryptmainlbl=$2 + shift 2 + ;; + -m | --mapping) + skips+=(mapping) + mapping=$2 + shift 2 + ;; + -B | --boot-options) + bootflags+=(--options "$2") + shift 2 + ;; + -M | --main-options) + mainflags+=(--options "$2") + shift 2 + ;; + -v | --verbose) + fatflags+=(-v) + ext4flags+=(-v) + shift + ;; + --) + shift + break + ;; + esac done -if (( $# < 1 )); then - error 'an argument specifying the block device is required' +if (($# < 1)); then + error 'an argument specifying the block device is required' fi -if (( $# > 1 )); then - error 'too many arguments' +if (($# > 1)); then + error 'too many arguments' fi blkdev=$1 @@ -75,45 +123,74 @@ EOF parts=() json=$(sfdisk --json -- "$blkdev") while IFS= read -r k; do - parts+=("$(jq --argjson k "$k" --raw-output '.partitiontable.partitions[$k].node' <<<"$json")") + parts+=("$(jq --argjson k "$k" --raw-output '.partitiontable.partitions[$k].node' <<<"$json")") done < <(jq '.partitiontable.partitions | keys[]' <<<"$json") bootfs="${parts[0]}" mainblkdev="${parts[1]}" -mkfs.vfat -F 32 -n "$bootlbl" -- "$bootfs" >/dev/null +if ! skip bootlbl; then + read -rep "Which label should the boot file system have? [$bootlbl] " input + if [[ -n $input ]]; then + bootlbl=$input + fi +fi + +mkfs.fat -F 32 -n "$bootlbl" "${fatflags[@]}" -- "$bootfs" >/dev/null while true; do - read -r -p 'Do you want your main partition to be encrypted [y/N]? ' luks - case "$luks" in - ([Yy]*) - while true; do - read -r -s -p 'Enter password: ' password - warn '' - read -r -s -p 'Re-enter password: ' repassword - warn '' - if [[ $password == "$repassword" ]]; then + read -rep 'Do you want your main partition to be encrypted? [y/N] ' input + case "$input" in + [Yy]*) + while true; do + read -rsp 'Enter password: ' password + warn '' + read -rsp 'Re-enter password: ' repassword + warn '' + if [[ $password == "$repassword" ]]; then + break + fi + done + + if ! skip cryptmainlbl; then + read -rep "Which label should the main LUKS partition have? [$cryptmainlbl] " input + if [[ -n $input ]]; then + cryptmainlbl=$input + fi + fi + + cryptsetup luksFormat --batch-mode --label "$cryptmainlbl" -- "$mainblkdev" <<<"$password" + + if ! skip mapping; then + read -rep "Which name should the main LUKS mapping have? [$mapping] " input + if [[ -n $input ]]; then + mapping=$input + fi + fi + + cryptsetup open -- "$mainblkdev" "$mapping" <<<"$password" + + mainfs=/dev/mapper/$mapping break - fi - done - - cryptsetup luksFormat --batch-mode --label "$cryptmainlbl" "$mainblkdev" <<<"$password" - cryptsetup open "$mainblkdev" "$mapping" <<<"$password" - - mainfs=/dev/mapper/$mapping - break - ;; - ('' | [Nn]*) - mainfs=$mainblkdev - break - ;; - (*) warn 'Please answer with yes or no' ;; - esac + ;; + '' | [Nn]*) + mainfs=$mainblkdev + break + ;; + *) warn 'Please answer with yes or no' ;; + esac done -mkfs.ext4 -q -F -L "$mainlbl" -- "$mainfs" +if ! skip mainlbl; then + read -rep "Which label should the main file system have? [$mainlbl] " input + if [[ -n $input ]]; then + mainlbl=$input + fi +fi + +mkfs.ext4 -qFL "$mainlbl" "${ext4flags[@]}" -- "$mainfs" mkdir --parents -- "$root" -mount --options noatime -- "$mainfs" "$root" +mount "${mainflags[@]}" -- "$mainfs" "$root" mkdir -- "$root/boot" -mount -- "$bootfs" "$root/boot" +mount "${bootflags[@]}" -- "$bootfs" "$root/boot" diff --git a/packages/puter/puter.bash b/packages/puter/puter.bash index 2c9b2aa..fd4a01a 100644 --- a/packages/puter/puter.bash +++ b/packages/puter/puter.bash @@ -19,10 +19,19 @@ error() { exit 1 } -args=$(getopt --options f:o:t:v --longoptions=flake:,on:,to:,verbose --name "$progname" -- "$@") +args=$( + getopt \ + --options F:f:o:t:v \ + --longoptions flakeref:,flake:,on:,to:,verbose \ + --name "$progname" \ + -- "$@" +) eval set -- "$args" +if [[ -n $PUTER_FLAKEREF ]]; then + flakeref=$PUTER_FLAKEREF +fi flags=( --refresh --use-remote-sudo @@ -31,25 +40,29 @@ flags=( verbose=false while true; do case $1 in - (-f | --flake) + -F | --flakeref) + flakeref=$2 + shift 2 + ;; + -f | --flake) flake=$2 shift 2 ;; - (-o | --on) + -o | --on) flags+=(--build-host "$2") shift 2 ;; - (-t | --to) + -t | --to) host=$2 flags+=(--target-host "$host") shift 2 ;; - (-v | --verbose) + -v | --verbose) flags+=(--verbose) verbose=true shift ;; - (--) + --) shift break ;; @@ -57,17 +70,26 @@ while true; do done if [[ ! -v flake ]]; then - if [[ -v host ]]; then - hostname=$(ssh -- "$host" hostname) + if [[ -v flakeref ]]; then + warn "using flake reference $flakeref" + if [[ -v host ]]; then + hostname=$(ssh -- "$host" hostname) + else + hostname=$(hostname) + fi + if [[ -z $hostname ]]; then + error 'hostname could not be resolved and no flake specified' + fi + flake=$flakeref#$hostname + warn "resolved to $flake" else - hostname=$(hostname) + error 'no flake or flake reference specified' fi - flake=git+https://forgejo@tea.wrz.one/lukas/puter.git#$hostname fi flags+=(--flake "$flake") -if (( $# == 0 )); then +if (($# == 0)); then error 'a subcommand is required' fi @@ -84,25 +106,25 @@ run() { sub=$1 case $sub in - (s | switch) - shift +s | switch) + shift - if (( $# > 0 )); then - error 'too many arguments' - fi + if (($# > 0)); then + error 'too many arguments' + fi - run switch - ;; - (b | boot) - shift + run switch + ;; +b | boot) + shift - if (( $# > 0 )); then - error 'too many arguments' - fi + if (($# > 0)); then + error 'too many arguments' + fi - run boot - ;; - (*) - error 'invalid subcommand' - ;; + run boot + ;; +*) + error 'invalid subcommand' + ;; esac diff --git a/pubkeys.nix b/pubkeys.nix index c93e70d..4880837 100644 --- a/pubkeys.nix +++ b/pubkeys.nix @@ -11,5 +11,6 @@ glacier = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHrKpoDV/ImivtTZVbSsQ59IbGYVvSsKls4av2Zc9Nk8"; vessel = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKkYcOb1JPNLTJtob1TcuC08cH9P2APAhLR26RYd573d"; work = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHw8sMeiUSUDQu/yyIuZ2Oc6lmYace47HEYdo3nmUWSR"; + insomniac = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHw8sMeiUSUDQu/yyIuZ2Oc6lmYace47HEYdo3nmUWSR"; }; } diff --git a/secrets/forgejo-admin.age b/secrets/forgejo-admin.age index dc5c111a7fcf39573ac4f072d6467120623b5272..52af37c3e1c1d080ea581c5b183e87ffae7a44c7 100644 GIT binary patch literal 558 zcmZY4OOBIZ003YU<3dj0#)Q>un#vEf1!7_{K%x9R3Z(@~GA1oQr98^Bg_cWr1sC36 zc533n3mBKKjB(=uTy*EGofCZdHc>bX^Ps+z$GFH}6?H_kBsP45H_d(+B5FJ)Ioy_J zPTk>s+89fd1EbQ{`9{-xI|%YXF)k5rDLR?eh2gO9vi+Sc5*S%+^q*5gRs zWJGH~v=cV4lQO?8Min>+ElTNp(G8ALbS5Gl^R1|Z4l|9-hl0u-IQA^-U9M$mrDDNSD2xo7hXHaFZ@bIc%5f5Eg@Kxe zWCtW6S5c3Ef3#vsVuJddCHzj*W?5?2x{y$c{-6zqxSbhFn+l+;$_Wohom5%1=%ZT7 zVw8uC-1}CQD_)N%7Bl}$?^W#XSN`eghwHcRcf#|xpWnwXz4eppMt=79#qZbt&+GO0 O?#JzyulF|}r~d$Ym%AJQ literal 558 zcmZY2yRMU9007{a7-LwR98E|xai~2lP+C|_ddlTc${h-2<5r;D;fKF;ad$9raWFoB zF($r)i>rwa4kqUTdid>O4Tctz9$9@=3GCPgmjk2Vx4JXgKPE4U8rm$?JLAM8%I+epywAguk(?2N-idc z&5Mr8grF8<$q)gN+*=5v$hb;nB5 zx+pTWrVqC5N>;-0TvLfEv5h#{^E3X$R7l;)B`KL8W;MWJGY=ci*2d=2b;&UcOCtDlw5k$33;;!uG`i(Q3wEf~ zoNaKKpF?a+W9`~h5=XQa2Fdaw6Vu0bO*L8}jk&-)A)Il;r&CYa(z4`xK|<%@U}HJV z87;M-0JU^8cWg#-$<==v7IeCf&eSrJNsQ?!m&=pspzCFk)g#h`TQz32Wv~O-;i7__ zy+Bry72m8GQBx{%4|z>Ej0IILR#{{xcA8kJmyE|L=DWe^zUFCOn{{XtXA1yk(;Ktd zVLqYv5*Ay4FhSTmadeq8oD`}1QVN$q!fc4T)Y}`3* zC>5Z9cD%1eQC=w>y7hE%Kkfdd#V{-2-fVcigVO34Rfq1_i(UqDmM|Qli;+U5G^TF^ zk2s$=UR~}KnU*Icq?TI3+obJKRn3+a8E-lS$8i++P?{T~I$XM$t`4piwJpCVjaKo4 z6PO)#6l>RFxzY0lqC9^8_3F(ne0AMEc=Ykt(=R`rKlRm}^yKq(_WJwnr?)S^eRvrD NhIj9{^N$yM;V<^_xVr!V literal 558 zcmZY2yRMU9007{{#Dv7;EXI|%5~N%UXE+H(C_kmN+}cB(%FpF+r-gEJ@C`J+fNx;p zpo@>;;;JuTVq6?FaX)@9@Ezk24@-C+>o%#%XVp0-IugNe(5AV=!+>I0Qb27*-JN^1 zqk)nzY)vGZQuj{2<0tE=v`!}a)`-!U1WGeX=zzA9k&DR69$AyTH6`vmbPw}w>9_$6 zj{Uf=7X}vjnne`tEd~GEu%I_hlmK_!I5WH+3b1Wxr}5_-`gtT*>+@-5F$XnPRey9^ z--HO+0r|{n>2Qd|lR$ky%z2Q68w;Fe8uFcqq! z#x|VB`2H3}MWgrV`WRpbPv3FtATz1{!aHel8vWc|u*oD<)r!q5Z7?=236SEnfrdQH z$HMJ5OkOcFArFXE8Vhhu8sm)e#eHvDgVeeRj^ik_tF4s4-c+>*H7$s%#Ww`s~2A${(1ZJ M`&VXrym@@}58Y_HnE(I) diff --git a/secrets/microbin.age b/secrets/microbin.age index c10817d496fbf8a8bf11f6c288843d7c3b30b515..7e9c887f4c6717f415d43bd79897d8ab614a92ea 100644 GIT binary patch delta 591 zcmV~$OK8&o002-wbg+Ow6hDVS=MGL{U6UsLc+f3v(xksMO`9%}DNWL*ZIU)k(xfRu zhYmpxqU9o!gRoWq08i%dKSLqt%9USwW&Q1rb8--7S%xdET<6IInNnA3RA zjF58J<2w|BH~N~{Fb&C&qKv~yIL&B0faN-MQfWzMITbHzh)OGTk?SxM`P2kR@(I?f z1uF#w%p++D2we1ARy|OaVHAa8eioEnhVdJ*Qrc+8?QY5rXEVu?jB}1u;Upo<5>=0P z^i0#KksZqP;s_vNM7!@%Xg@;}hM9$hQbs}zT&&?yF5QL|3bhn94S{s)-mjBowi%Dx z;6%7jx%DVjfD^93mYk4F5Ogsj<7I3rG@b2pAzEbsu}b9x8zOo+#)V~s)fFS8vU*5B zNm#2Da|tKuXoRft9c%vT-V=j7UvVPszS|DHBP)Q7`gBf$lqiOD^|IM&+lcr7Eq;W8q zpdvW`6fYYNWqR1WC`=gcFfV!)1Q9-F{eZVb<&3=pDIVm-*SE;(Lh zb2tv^K*7Xdt&x&TEUI=H8j+g3l#gH_<2!7XBN3Z$;!{+>lu<>l5SB!FlIh~f5NVJ} z2nK59NNhCfc}A?NfvMC;CMp1$&vDW28QhLL7GuIqm`RgXB2P1wR(C98l(Sy8U0@VH zt}vKFwsADlhF!m0su_q`5=!Z?VJL{237qp>(i(xLt$eenStLnG1a)(JP^t!spaT%g z6s^#5*?{F`HMCTspm|_OOO+8*tjcLR?xKDqNa>&>OF5^jsYM#cvu2A{LEh@(391E7 zwFs%41T+Xv2*~Zp-A86S3?#!vUt&^Fr{tttq3f_Fq1%uLH)|lv*rW*fn8%~FS|nS; zouE8chZRWV)wJG7bJ;dkNYoXKH@UVA^B6nMf^`lR0Jz)d9t6sE}vLz@TLj zgey``=un_8=}4oKoi&Mq=ZZNml2}=~{GD6ryF0o{cb^~JGuJ$CpUQF-RhP diff --git a/secrets/miniflux.age b/secrets/miniflux.age index 43f822d0f5ddb46f05779caf8f02e498420cd22a..537999145228b858683ca2526cd4f3e9d6545ffc 100644 GIT binary patch delta 527 zcmV~$JCD);007{eve?;#!9f-i4M$S?ppY12DNqW1($WVG3N3v>=?nT`xWn8JP;-OP zNjDRRb8#{;F}huX=9UxxfR5_mbWy+Wyl`H4ynkpe=~*|L3|&iyQ4Y6PZMfWqWz43D z1cI$~SCYe_LdBkw0zGy(6Z&gU1!E|Sbe9T(Fb5|YJYURpM>SY=?R#bnYpexS?v&!# zu1pOGMXQaHST<5YC?y64vxGjNU~-(d%-rgf!4qp)Fegoc>}K zG*?W`X-Ohs`71N?#&Xa%wKk6Pvg%S^rgZ#9H$tBLDk{3NkR%dYOU!IgtBunZq=mvNr*XNIjtYx z-zy#pE(;?K!kLgkv(aUAy&48ll3AQdM~;EE8JyG&cMMx81Jnj0l8o>q9=ajD%%`KC zLB}gzjk|r+9PxN9n8s!=!yBvsR4SDcrKF@W)^nS&f`!W`M#huOJa_S2;Q|O8xJhjy zH#nanH4wOZ(Hp#R|NcDr_x{$!hQ0UW#sj!|@$K#9OGlr=?cTfXiS^9holQ4KPhWm+ vb@o3VoL=i)dF^Z0zdyXI9v@6!^lyLJJ^xy)pCUI4uO5BaQfE7E^ZU<#X+y!e delta 527 zcmV~$JBZU@003Zxn}VW~hfW0-F_tE6(>B8$#H2}@=Gk7Gwhmq%ZJI~_zipBx&2n_O z-QzqI#Kpzi6hRROaXA#d&EW*m(ai%V4~N6=J6StfdvIsRGGZ#W#|%k}#ei`go^3TG zi=;w|j!=F8HQ3QAW|fhWIs(;s3&3bNY^!NI8fC@+TXMb!Bh*+3mNE$`%Xc+rYAqZj zznKfeaeinQ2?8f`ZPZRQEeD$28P4*wMUv6XOE`wLr@*zTKH)>24Sj(TFjPsWgcc-7 z6XIKBU^gf!#%at*Gkwu;WYCjSf@Xx7CRC*?o#HkH`g?!Y^-iJG9TcktZdPu`8Cs`C zCJ+tT-s%N<6{=(}ZlSVS_JJoMNvA+aMopRY%N09`Ow3IQRh*UG0`4Zzuc%3HVvaZ= zrjz~q7uRPBYWHq6){X$l0S2$7o1CpU+`t!zr=8lP*$Ytas3Pa@UdiW@u zj!bi2o2Hs+U`U1h_4MBR{R{7=-@@mI+t-`_j@3^`4?Sw{?`97QxB2Z=?(pZek3TL; z{PFp#?Cqtmr?) ssh-ed25519 SFHVrw U+aZt7fWa449Gl55hXRDD38PUijyhzp28XAMPmRPYm0 -CNCHCTxDX1OCedqbmT93DertJVC6X2eBQHSti9UpD3U --> ssh-ed25519 S+dwQQ tga1gW8cAcAe2nmUpKGZDfPBMNWYCz8F9t6y5Z3nSUs -RNjnzz1D8IyIs5Yy1anjvPNUMU73WXNx/xN52tBsiCw --> ssh-ed25519 bPbvlw S6OGsxSDtWeGnDkS/Pg/aM8xU3Z9ZMrLcC9QkmxsKzU -1Z0Gx7pq0q01WhSg3+20Dap7ekkzXKSGGdrXRvbmv7I --> ssh-ed25519 ffmsLw daLmGw0eJTSfFZMBw9aPqooDYXGFP0l7k1PrMQk2iEM -BRZE2oQXWytOVU5+R0buTov74Acj1DKogJPt7TbGY44 ---- 3ArhjIM9AlDiJjmn2BFe1ql/TUiveu+COhFVqN+5jsY - -:0U=5@V0e_"r^{ =ULoU % \ No newline at end of file +-> ssh-ed25519 SFHVrw /OTVcIQd3fJVTG7aEwQCY/x6lfTd+EZpn7Jc4MeEcE4 +31r1WrTF9ZnrL5za6p57fafVJfQAj5iyY6lLQriIwaY +-> ssh-ed25519 S+dwQQ TmWs92CYRNXJVaJCCsfQc7wWek38gofuVzaZiTchcRA ++zEDzASCzZbWn6weWXoBrCfDRLsOzKncFLLuXOTD/bc +-> ssh-ed25519 bPbvlw UuI6fU6RpT5aZBUZjgypR/q7N24usjkTxdu+hemcH2Q +AaqzU+V02ezyLuBLFpjiobv0qL87JaAI+CVur0nyuZ4 +-> ssh-ed25519 ffmsLw 41XX4wfkbdkgcOGV/QobtwxXjfyYEkpYrUSGjhg1wBw +YZFSenGSwenFCuVxlmFQSLUACP1XUewZlKtRGYTuzRE +--- FwFDJ/HQQyHH1Ik5HdCF4ZHihlNCvD9BYGxgM4KOims +F=Δ\*%]8lTp$Ó4m>;y9pgv! \ No newline at end of file diff --git a/secrets/restic-vessel.age b/secrets/restic-vessel.age index 27a7c9f..d30087e 100644 --- a/secrets/restic-vessel.age +++ b/secrets/restic-vessel.age @@ -1,11 +1,11 @@ age-encryption.org/v1 --> ssh-ed25519 SFHVrw ijulBUOGDExmjRrr0Pyf7QpMELMNAY5gh77yM9VpnQ4 -JCSSURYLwaOs/ga3dcQUcfMaWWxJugDZP5fbQhyPQ6s --> ssh-ed25519 S+dwQQ 6Jkn/HoEbeXAcIZ5BQrpJFjBlH4VqpDFmTlWAk98SQg -fOF3+MH/4IzHQ44SKQaLo7VrILZdu+hDHIIXGv4asLs --> ssh-ed25519 bPbvlw yvH9ggLK9QSrNoCIGkNQlpOS3UCegRz86f8LmZFUTEg -bOvwgPx3EAC4kXEV7Io6NHoPtuYLwqffjqx/cSWXeU0 --> ssh-ed25519 Sm0lOA T+w+u5UZlTnilbbTQy/Z6IFjp7/KaKg0MY2zhuSnOBI -pbqYRhd83jjTHqfQbY3Xpz5p3Znt9yr1lBc+UEa2ESo ---- xqFypHpvC9f/EaloV7W0PCvicGa/g/Igi69Rt5E9Pi4 -DO=$ӓu$ùT;Hi \ No newline at end of file +-> ssh-ed25519 SFHVrw fMNDH0URM0/+vDXt7G1XjLmdD3YkQMHJjfcF3g6Tty4 +k+Gc9ZrRrSkqor8Mm6k+bE18H+Tx6fDNiKaTNA+f5qA +-> ssh-ed25519 S+dwQQ jt/dEEBISxmpaUx6rjdamirV2MNzsIK9t9Eh79yA5UE +Nq4Bw8eH1vWHqCiQvfRsuYtw6fETWHR865gM5IDHPng +-> ssh-ed25519 bPbvlw pEfHE2mBNPsUCs2AFl3xBrhH935Ik6EJLpACTXmOwU8 +ctFSiMorm+7by4tzDEySBfAjvjuskEQjpWIyC5BK9cg +-> ssh-ed25519 Sm0lOA /pofcFqGH/aJo7JsrmaYBD7+/Eo0WyO7L1RCbU+LfAU +ZjILSFZeV68fSTDUuXlTFfdTqda7fe6k2FdXjcK1wb8 +--- SgzDlMCI5YwR8NLsV7DpKR48NAmTMGFS8vzyxMI/DF0 +I~1ܭ\37:;V M~k |O9%XbFbsrC;&*WH5&}ItZHG}(8n1x^=OztV9}Nv9Y_Jb)W$28ER~l$bO1zQRHEBQ+Kvh zmrCtj;CH!+qVYXP2=m%%coiCB)_@k!Tv@I{hPlw) z9BMY|ih0%QGcL^&sK>OUEHu|(vw(GZ7VOn{5DgtUbxC50v<)8U9Ata81D6Fn?ke4q zvnbxP#3U^FlVZ`&_k&(SGg=zfi;WK-YU+%j=XA@fm|jq`{fz=IbTk@^O1uPHzKEqR zItn~_I@|9H6&cQv4J0+pF7VtwQ&lX8SZbpSQ)(%)STPkSfX^^01IT=)HO%@@n?-PV zLbtfxXeS}D2v8#p<|&*dTaz7l%GPAE285U=VFpLByr5c87P-@{-{Y+icnHtpmDnC{ z^kW?=SK{zNLKk{CoQg{~kX`U;gvl_1Erx z9eL?n@zKYRf4Fo?Y4*$aO^DM+u3b2iK79Ym{o%#m?|pWZ{&efz8y{T1*}d}iGvQP6 z)xSP_Zt}5u>mTTkqgOtC?CZOzkG^{I)rZcW5Q2MtDUNPjB_24Vemni*+S9+j@cE17 a!E?e&c5*%d literal 1088 zcmZY7&5Pr70LF1w1f>UA1idUu@iK>4lO}2U3!<1bX`1(>d1)q|k~S}WNt(AdNx_S& z;zifPD&j%G(=Lj7Qb7o1-Li~(!2%r&`efG_Pwb-Z?uO!F!wJn2?TbvS_#|$ol#H#arC>tVaFeh4 zfZ^MIp_iS8^-UO7wP=kpf+=qUj?yY3r!+`&U0510Uby5HLEg>T3mUYjb-gRAMw7EV zZ7#FGQ@zmHnKcw6=!!0kJTmnxHbUE6!WFvhw9W)?%|bvdmI@Q6Si|wILXV@(s+A$6 zfj5{ZXd)-OE;z6Gn!n%FU4yWxXzI*yUXB>2G01(j}``9 zF*x``D+;Yv6@`FFv3kwXjTxk6hbP#f4Idm zjzs6R1saNF-4&Ne3YD5$c{P!9XM2@lHR6?4;esY)`%=3vjJZ7o+0yDzLNv?9hMKqZ zhQwKY>Qr){sJ(TKD+Cz&)Ud7;YY3Crh21QJpiHVe9n<*;)nO(&&~Y#ln%Y)1JH;~r z7q}#>W=3pzt;oQ--bsuknPIdYgPh16kqfa2&~e)FX`&d_Oxcfe$=6VLzPiw6B*;dk zx?q>)2eFL|ERo2~z$mDCGt}}_b>mo?V2uYObI8#+G6o$CadJL~>;h6~g_n5jfNVU_ znv4o|CNV1ZP40#CK6LmCZGJRvGrj9LoLXb$0eCuk?CUM-0ZtFe!@7yFJ|vmxYpzCe#2g20@)2LI#&$+>GqL71flvyd-u-opPzJ(zW>7of4=e8Klk50{Xw>0ymjl>%a`7Fd(-3FcYl7z zc|5%S_37WwJ@xeSM~{6|!e3mg9{AjX5 W`RG^QG1TIv_fE?PrPr)0H~$B{fph}^ diff --git a/secrets/vaultwarden.age b/secrets/vaultwarden.age index dc8692634baf26764694c8e30b5c6007aaf7197c..10a543287ae3994a0cefd860b1c9363db129b136 100644 GIT binary patch delta 797 zcmV+&1LFMS2IB^hEPrBWNn$l@N@;a(aaB%NcSSi?ZbDLIF-t*4L0B+rG)gotZ8bzs zV^2;+V+u=obZ%vFNqS3WX>@ipPBvy_GG=Q=Ol2=Jd2(82M@V*MQ+8o9G+22|Q3@?S zAaiqQEoEdfH8n9gAX6)3cTrIwIW%f7N>)--L}^4;RA)^|a7Iiyd2Cuka8N5nb#_BC zc`GwSVN_^zLTPF=3QJf?b6IgQVPZ{CX>o93Pg7=CLUAx@O+-aAd1Nt9O*2eUN_t{2 zL^M`Sk?|K-Phw?ROnFE~S7AhMM^R}@Hf}Xm&_dSyxd@P)$mDOEG9>a#CeCa$0&%HDqyWS7U8WO)G1YUjY|?Zb)ZV zWHfJ4ctlfEbVWorRz)jVQFeJ+c2;#uaClWodTwq`F=jL|X?aNsZ)Z17RZmS~ZgeXv zT4+}?X-RrZHEU8rSW|OKYD7ypba`QRWkq%|b!|8bEiEk|cx-HUWieq&NN!JgD?v|8 zF?vxiFicKoc|&Dsc4&4_Q)^UzHbQT6N>Oo13bjBGbMbz5$}}OufBUfz6hMT-0l+!q2#FtEiUR{0JJy;Gom4N4a}ua_0-HJ8ct%x z5CL~APLeYnomvHLDwn9>l@k9kP3J23WSLi3XIEEQT~?v{cumME%!z#v@hNoA9Z zCX>Fh847aLDZ&!N(Bb$0ZNsEp^Mj@rL{5m}5z*|o<361?GHDTIM)`hZ0%IV*NZw!c%-NW`=n bW2bzjtIkW*8`og@kzTM8yUg5bq9XdU$V5e6 delta 797 zcmV+&1LFMS2IB^hEPpn0b4gG)PH;#zP*zTCOhH6#b7*gLaY#;UL}GMSXl-t9LuhJp zXhJekI0{c?b~8CaD`{?cMpbfRSXgydW^QdmT1iYuc|>PKN=I){a6w{IR#Zo1X9_Jo zAaiqQEoEdfH8n9gAX6)3cTrIwYfDIaRe5MOLoqi~GDLQ2a7JoJIcQjIMK5_cQA|xs zXHRfzS9EMbVn%Lb3QRA0XEZWNYf4r!I7?_ud2TjRYG_79Y&bPzLpfC|D|BirZc=PC zXiIWgk?|K-LUB`0a$0p(Fj#IgFk)?GY%pv~SyW4SVpT+PMKWetZe?XJbwxLNQZhvf zF=JyjaBfalLPIl3GcY$+W=%ylYd2;@O+-;OLSkWTK}&X7WlJkFXEjBWUjY|?ZFehJ zcy~fXbyihTWN2(Mbai2EO-NyKd1Pr=F>N9S(wNDcUUqsPdMCaZo7_=cb*=wBL%A+$c{F*rbkVuRxxsh=dJ*{{$WtVLA?)qE5FS** z04(JQs0efS7Cyqaw9e|k#DEw;8`1g4^dBNzFU%afogD(FBZyr@eD#r0wP25WmrooV7R`irVpe&ypA7hEk zH^%Ws*vCHKO@)&pz+O#oU-VRJ7g-4K9iHTJAWkpaG`x)Z1R&3j3Hz^M$wOxY=?$LN zob&-O>D)*35_K(^0_A^K{dvoxz3&l2FqNlDZg|4FoB#IIA+nx bYI>W>F1E2gLgxcnxFfg9>)lP5Iuye(xwk*d