Files
nixos/caesium.home.nix
T

177 lines
5.6 KiB
Nix

{ pkgs, ... }:
let
# Wraps the interactive pamu2fcfg ceremony (touch required, can't be
# scripted away) so the repo's yubikey.u2f-mappings file always ends up
# well-formed: one line per user, credentials colon-separated. See
# module.yubikey.nix for how the file is consumed.
yubikeyEnroll = pkgs.writeShellApplication {
name = "yubikey-enroll";
runtimeInputs = [ pkgs.pam_u2f pkgs.gawk pkgs.gnugrep ];
text = ''
REPO="''${YUBIKEY_REPO:-$HOME/nixos}"
MAP_FILE="$REPO/yubikey.u2f-mappings"
USERNAME="''${1:-$(whoami)}"
if [[ ! -f "$MAP_FILE" ]]; then
echo "error: $MAP_FILE not found (expected the nixos repo checkout at $REPO)" >&2
exit 1
fi
existing_line="$(grep "^''${USERNAME}:" "$MAP_FILE" || true)"
echo "Insert the YubiKey to enroll, then touch it when it blinks."
if [[ -z "$existing_line" ]]; then
new_line="$(pamu2fcfg -u "$USERNAME" -o pam://mbessette -i pam://mbessette)"
else
cred="$(pamu2fcfg -n -o pam://mbessette -i pam://mbessette)"
new_line="''${existing_line}:''${cred}"
fi
if [[ "$(printf '%s\n' "$new_line" | wc -l)" -ne 1 ]]; then
echo "error: unexpected multi-line credential output, aborting without writing" >&2
exit 1
fi
tmp="$(mktemp)"
if [[ -z "$existing_line" ]]; then
{ grep -v "^''${USERNAME}:" "$MAP_FILE" || true; printf '%s\n' "$new_line"; } > "$tmp"
else
awk -F: -v u="$USERNAME" -v line="$new_line" 'BEGIN{OFS=":"} $1==u {print line; next} {print}' "$MAP_FILE" > "$tmp"
fi
n=$(grep -c "^''${USERNAME}:" "$tmp")
if [[ "$n" -ne 1 ]]; then
echo "error: expected exactly one line for $USERNAME, got $n; not writing" >&2
rm -f "$tmp"
exit 1
fi
mv "$tmp" "$MAP_FILE"
count=$(awk -F: -v u="$USERNAME" '$1==u{print NF-1}' "$MAP_FILE")
echo "Enrolled. $USERNAME now has $count credential(s) in $MAP_FILE."
echo "Review the diff, then run nix-update to install it to /etc/u2f_mappings."
'';
};
yubikeyUnenroll = pkgs.writeShellApplication {
name = "yubikey-unenroll";
runtimeInputs = [ pkgs.gawk pkgs.gnugrep pkgs.coreutils ];
text = ''
REPO="''${YUBIKEY_REPO:-$HOME/nixos}"
MAP_FILE="$REPO/yubikey.u2f-mappings"
if [[ ! -f "$MAP_FILE" ]]; then
echo "error: $MAP_FILE not found (expected the nixos repo checkout at $REPO)" >&2
exit 1
fi
list_credentials() {
local user="$1" line
line="$(grep "^''${user}:" "$MAP_FILE" || true)"
if [[ -z "$line" ]]; then
echo "$user: no credentials enrolled"
return
fi
awk -F: -v u="$user" '$1==u {
for (i=2;i<=NF;i++) { split($i, f, ","); printf " %d: %s...\n", i-1, substr(f[1],1,16) }
}' <<<"$line"
}
if [[ $# -eq 0 ]]; then
echo "usage: yubikey-unenroll <index> [username] (no args: list credentials)"
while IFS= read -r user; do
list_credentials "$user"
done < <(awk -F: '{print $1}' "$MAP_FILE" | sort -u)
exit 0
fi
INDEX="$1"
USERNAME="''${2:-$(whoami)}"
if ! [[ "$INDEX" =~ ^[0-9]+$ ]]; then
echo "error: index must be a positive integer" >&2
exit 1
fi
line="$(grep "^''${USERNAME}:" "$MAP_FILE" || true)"
if [[ -z "$line" ]]; then
echo "error: no entry for $USERNAME in $MAP_FILE" >&2
exit 1
fi
count=$(( $(awk -F: '{print NF}' <<<"$line") - 1 ))
if [[ "$INDEX" -lt 1 || "$INDEX" -gt "$count" ]]; then
echo "error: $USERNAME has $count credential(s); index must be 1..$count" >&2
list_credentials "$USERNAME"
exit 1
fi
new_line="$(awk -F: -v OFS=: -v idx="$INDEX" '{ out=$1; for (i=2;i<=NF;i++) if (i-1!=idx) out=out OFS $i; print out }' <<<"$line")"
tmp="$(mktemp)"
if [[ "$count" -eq 1 ]]; then
awk -F: -v u="$USERNAME" '$1!=u' "$MAP_FILE" > "$tmp"
else
awk -F: -v u="$USERNAME" -v line="$new_line" 'BEGIN{OFS=":"} $1==u {print line; next} {print}' "$MAP_FILE" > "$tmp"
fi
mv "$tmp" "$MAP_FILE"
echo "Removed credential #$INDEX for $USERNAME. $((count - 1)) credential(s) remain."
if [[ "$count" -eq 1 ]]; then
echo "Note: $USERNAME now has zero credentials -- pam_u2f falls through to password (control=sufficient), not a lockout."
fi
echo "Review the diff in $MAP_FILE, then run nix-update to apply it."
'';
};
in
{
imports = [
./programs.vscode.nix
./programs.thunderbird.nix
./module.accounts.nix
./module.evolution.nix
];
programs.firefox.enable = true;
home.packages = with pkgs; [
wowup-cf
faugus-launcher
yubikeyEnroll
yubikeyUnenroll
];
services.flatpak = {
# nix-flatpak's home-manager module always manages the "user" flatpak
# installation, independent of NixOS's services.flatpak.enable (system
# scope) below in caesium.nixos.nix. Standalone home-manager has no
# osConfig to inherit from, so this must be set explicitly.
enable = true;
uninstallUnmanaged = true;
packages = [
"com.spotify.Client"
"com.discordapp.Discord"
"org.signal.Signal"
"io.openrct2.OpenRCT2"
"io.github.enginkirmaci.lumux"
];
};
programs.zsh.shellAliases = {
claude = "nix run github:sadjow/claude-code-nix";
};
home.sessionVariables = {
NPM_CONFIG_PREFIX = "/mnt/Projects/.npm-global/.npm-global";
};
home.sessionPath = [
"/mnt/Projects/.npm-global/bin"
];
home.file.".npmrc".text = ''
prefix=/mnt/Projects/.npm-global/.npm-global
'';
}