diff --git a/flake.lock b/flake.lock index b7a36ad..f6fc874 100644 --- a/flake.lock +++ b/flake.lock @@ -18,13 +18,33 @@ "type": "github" } }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1751336185, + "narHash": "sha256-ptnVr2x+sl7cZcTuGx/0BOE2qCAIYHTcgfA+/h60ml0=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "96354906f58464605ff81d2f6c2ea23211cbf051", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, "nixpkgs": { "locked": { - "lastModified": 1750122687, - "narHash": "sha256-zcGClfkXh4pckf4aGOZ18GFv73n1xHbdMWl17cPLouE=", + "lastModified": 1751285371, + "narHash": "sha256-/hDU+2AUeFFu5qGHO/UyFMc4UG/x5Cw5uXO36KGTk6c=", "owner": "nixos", "repo": "nixpkgs", - "rev": "c539ae8d21e49776966d714f82fba33b1fca78bc", + "rev": "b9c03fbbaf84d85bb28eee530c7e9edc4021ca1b", "type": "github" }, "original": { @@ -49,21 +69,46 @@ "type": "github" } }, + "plasma-manager": { + "inputs": { + "home-manager": [ + "home-manager" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1748196248, + "narHash": "sha256-1iHjsH6/5UOerJEoZKE+Gx1BgAoge/YcnUsOA4wQ/BU=", + "owner": "nix-community", + "repo": "plasma-manager", + "rev": "b7697abe89967839b273a863a3805345ea54ab56", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "plasma-manager", + "type": "github" + } + }, "root": { "inputs": { "flake-parts": "flake-parts", + "home-manager": "home-manager", "nixpkgs": "nixpkgs", + "plasma-manager": "plasma-manager", "yubikeyGuide": "yubikeyGuide" } }, "yubikeyGuide": { "flake": false, "locked": { - "lastModified": 1750017933, - "narHash": "sha256-lj90IEekf3nVCTfGqLRLqsAocLzJJVEFW30e3oFVXuA=", + "lastModified": 1750291111, + "narHash": "sha256-hdZhAIi18jUhDJB7A5yMnoUltnxMGCYAv0N2nU5+nb0=", "owner": "drduh", "repo": "YubiKey-Guide", - "rev": "428d8452142e1bf1667e5c7c87bb9325bbcae0a2", + "rev": "08a22f8bde48d2d134dbacdf9910c0ca874afbaa", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 33cb95f..6af21a0 100644 --- a/flake.nix +++ b/flake.nix @@ -4,13 +4,22 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs?ref=nixpkgs-unstable"; flake-parts.url = "github:hercules-ci/flake-parts"; + home-manager = { + url = "github:nix-community/home-manager"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + plasma-manager = { + url = "github:nix-community/plasma-manager"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.home-manager.follows = "home-manager"; + }; yubikeyGuide = { url = "github:drduh/YubiKey-Guide"; flake = false; }; }; - outputs = inputs@{ self, nixpkgs, flake-parts, ... }: + outputs = inputs@{ self, nixpkgs, flake-parts, home-manager, plasma-manager, ... }: flake-parts.lib.mkFlake { inherit inputs; } { @@ -29,6 +38,7 @@ fos-generate = pkgs.writeShellScriptBin "fos-generate" (builtins.readFile ./fos-generate); fos-mount = pkgs.writeShellScriptBin "fos-mount" (builtins.readFile ./fos-mount); fos-partitions = pkgs.writeShellScriptBin "fos-partitions" (builtins.readFile ./fos-partitions); + fos-renew = pkgs.writeShellScriptBin "fos-renew" (builtins.readFile ./fos-renew); fos-sync = pkgs.writeShellScriptBin "fos-sync" (builtins.readFile ./fos-sync); fos-working-directory = pkgs.writeShellScriptBin "fos-working-directory" (builtins.readFile ./fos-working-directory); openpgp-ca = pkgs.openpgp-ca.overrideAttrs (prevAttrs: rec { @@ -57,6 +67,13 @@ "${nixpkgs}/nixos/modules/profiles/all-hardware.nix" "${nixpkgs}/nixos/modules/installer/cd-dvd/iso-image.nix" ./iso.nix + home-manager.nixosModules.home-manager + { + home-manager.useGlobalPkgs = true; + home-manager.useUserPackages = true; + home-manager.sharedModules = [ plasma-manager.homeManagerModules.plasma-manager ]; + home-manager.users.nixos = import ./home.nix; + } ]; specialArgs = { inherit inputs; diff --git a/fos-generate b/fos-generate index 7de84c0..8323a6b 100755 --- a/fos-generate +++ b/fos-generate @@ -36,7 +36,7 @@ mkdir "${fos_working_dir}/archive/employee-keys/${localpart}@famedly.com/" cp "${fos_key_file}" "${fos_working_dir}/archive/employee-keys/${localpart}@famedly.com/secret.asc" sq key import "$fos_key_file" -key_fingerprint=$(sq inspect /tmp/fos/s.kim.asc | grep "Fingerprint" | xargs | cut -d " " -f2) +key_fingerprint=$(sq inspect /tmp/fos/${localpart}.asc | grep "Fingerprint" | xargs | cut -d " " -f2) sq cert export --output "${fos_working_dir}/archive/employee-keys/${localpart}@famedly.com/public.asc" --cert-email "${localpart}@famedly.com" --trust-root "$key_fingerprint" cd "${fos_working_dir}/archive" diff --git a/fos-renew b/fos-renew new file mode 100644 index 0000000..aadec23 --- /dev/null +++ b/fos-renew @@ -0,0 +1,75 @@ +#!/usr/bin/env bash + +function confirm { + while true; do + read -p "$* ([y]/n): " answer + case $answer in + "") return 0 ;; + [Yy]) return 0 ;; + [Nn]) return 1 ;; + esac + done +} + +if [ -z "$1" ]; then + days=60 +else + days=$1 +fi + +echo "looking for public keys in /tmp/fos/famedly.oca that will expire in the next $days days" + +expired_certs=$(oca -d /tmp/fos/famedly.oca user check expiry -d $days | grep -oP 'fingerprint\s+\K\w+') + +if [ -z "$expired_certs" ]; then + echo "no public keys to renew" + exit 0 +fi + +# ensure primary secret without whitespace exists +if [ ! -f /tmp/fos/primary-secret-trimmed ]; then + cat /tmp/fos/primary-secret | tr -d "[:space:]" > /tmp/fos/primary-secret-trimmed +fi + +# export current keylist +oca -d /tmp/fos/famedly.oca keylist export -fp /tmp/fos/ --sig-uri https://tmp.only +# remove unneeded sig +rm -f /tmp/fos/tmp.only + +for id in $expired_certs; do + email=$(cat /tmp/fos/keylist.json | jq -r ".keys[] | select(.fingerprint == \"${id}\") | .email") + name=$(cat /tmp/fos/keylist.json | jq -r ".keys[] | select(.fingerprint == \"${id}\") | .name") + if confirm "extend public key expiration date for $name ($email)?"; then + archive_path="$(fos-working-directory)/archive/employee-keys/${email}" + + # import private and public key + sq -q key import "$archive_path/secret.asc" || exit 1 + sq -q cert import "$archive_path/public.asc" || exit 1 + + # extend expiration date for public key + sq -q --password-file "/tmp/fos/primary-secret-trimmed" key expire --cert "$id" --expiration 2y || exit 1 + + # extend expiration date for all subkeys of public key + subkeys=$(cat $archive_path/public.asc | gpg -q --with-colons --import-options show-only --import | grep "fpr" | tail -n +2 | cut -d ":" -f10) + for skid in $subkeys; do + echo "sq -q key subkey expire --cert "$id" --key "$skid" --expiration 2y" + sq -q --password-file "/tmp/fos/primary-secret-trimmed" key subkey expire --cert "$id" --key "$skid" --expiration 2y || exit 1 + done + + # write the new cert and inspect it for review + sq cert export --cert "$id" --output "$archive_path/public.asc" --overwrite || exit 1 + sq inspect --cert-file "$archive_path/public.asc" + + if confirm "update OCA with $archive_path/public.asc and commit file?"; then + oca -d /tmp/fos/famedly.oca user update -f "$archive_path/public.asc" || exit 1 + cd "$(fos-working-directory)/archive" + git add "$archive_path" || exit 1 + git commit -m "extend public key expiration date for $name <$email>" || exit 1 + else + echo "$archive_path/public.asc not added to OCA and git repository." + fi + else + echo "skipped $name ($email)" + continue + fi +done diff --git a/home.nix b/home.nix new file mode 100644 index 0000000..f9ee515 --- /dev/null +++ b/home.nix @@ -0,0 +1,82 @@ +{ config, pkgs, ... }: + +{ + # https://nix-community.github.io/home-manager/options.xhtml + home.username = "nixos"; + home.homeDirectory = "/home/nixos"; + home.stateVersion = "25.05"; + programs.home-manager.enable = true; + + # https://nix-community.github.io/plasma-manager/options.xhtml + programs.plasma = { + enable = true; + workspace = { + lookAndFeel = "org.kde.breezedark.desktop"; + }; + panels = [ + { + location = "bottom"; + floating = true; + widgets = [ + { + kicker = { + behavior = { + sortAlphabetically = true; + }; + settings = { + icon = "nix-snowflake"; + }; + }; + } + { + iconTasks = { + launchers = [ + "applications:org.kde.dolphin.desktop" + "applications:org.kde.konsole.desktop" + "applications:org.kde.kate.desktop" + ]; + }; + } + "org.kde.plasma.marginsseparator" + { + systemTray.items = { + hidden = [ + "org.kde.plasma.networkmanagement" + "org.kde.plasma.volume" + ]; + }; + } + { + digitalClock = { + calendar.firstDayOfWeek = "monday"; + time.format = "24h"; + }; + } + ]; + } + ]; + input.keyboard.layouts = [ + { + layout = "us"; + } + { + layout = "gb"; + } + { + layout = "de"; + variant = "nodeadkeys"; + } + ]; + kscreenlocker = { + lockOnResume = false; + passwordRequired = false; + }; + powerdevil = { + AC.autoSuspend.action = "nothing"; + battery.autoSuspend = { + action = "sleep"; + idleTimeout = 1800; + }; + }; + }; +} diff --git a/iso.nix b/iso.nix index 34a32fd..c957c84 100644 --- a/iso.nix +++ b/iso.nix @@ -32,7 +32,6 @@ let name = "yubikey-guide"; paths = [ viewYubikeyGuide shortcut ]; }; - session = "dbus-run-session -- startplasma-wayland"; in { isoImage = { @@ -60,11 +59,11 @@ in enable = true; settings = { initial_session = { - command = "${session}"; + command = "startplasma-wayland"; user = "nixos"; }; default_session = { - command = "${pkgs.greetd.greetd}/bin/agreety --cmd ${session}"; + command = "${pkgs.greetd.greetd}/bin/agreety --cmd startplasma-wayland"; user = "greeter"; }; }; @@ -151,6 +150,7 @@ in flake.packages.${system}.fos-generate flake.packages.${system}.fos-mount flake.packages.${system}.fos-partitions + flake.packages.${system}.fos-renew flake.packages.${system}.fos-sync flake.packages.${system}.fos-working-directory ]; @@ -163,8 +163,6 @@ in plasma-browser-integration ]; - nixpkgs.config.allowBroken = true; - # Disable networking so the system is air-gapped # Comment all of these lines out if you'll need internet access boot.initrd.network.enable = false;