This repository has no description
5.2 kB
136 lines
1{ self, inputs, ... }:
2{
3 perSystem =
4 {
5 pkgs,
6 system,
7 ...
8 }:
9 {
10 packages.pass = inputs.wrappers.lib.wrapPackage {
11 pkgs = pkgs;
12 package = pkgs.passage;
13 runtimeInputs = [
14 pkgs.age-plugin-fido2-hmac
15 pkgs.age-plugin-yubikey
16 pkgs.age-plugin-tpm
17 self.packages.${system}.pass-otp
18 self.packages.${system}.age-detect
19 ]
20 ++ (pkgs.lib.optionals pkgs.stdenv.isLinux [
21 self.packages.${system}.pinentry-rofi-age
22 ])
23 ++ (pkgs.lib.optionals pkgs.stdenv.isDarwin [
24 pkgs.age-plugin-se
25 ])
26 ++ (pkgs.lib.optionals (!pkgs.stdenv.isDarwin) [
27 # Dummy age-plugin-se for Linux (encryption only, no Secure Enclave hardware)
28 (pkgs.writeShellScriptBin "age-plugin-se" ''
29 exec env PYTHONUNBUFFERED=1 ${
30 pkgs.python3.withPackages (ps: [ ps.cryptography ])
31 }/bin/python3 ${./age-plugin-se-dummy.py} "$@"
32 '')
33 ]);
34 aliases = [ "pass" ];
35 wrapper =
36 {
37 exePath,
38 envString,
39 preHook,
40 ...
41 }:
42 ''
43 set -x
44 ${envString}
45 ${preHook}
46
47 # Check if bulk key file should be used for decryption
48 if [[ -n "''${PASS_BULK_KEY_FILE:-}" ]]; then
49 if [[ ! -f "$PASS_BULK_KEY_FILE" ]] || [[ ! -s "$PASS_BULK_KEY_FILE" ]]; then
50 mkdir -p "$(dirname "$PASS_BULK_KEY_FILE")"
51 ${exePath} show bulk-operations/age-key > "$PASS_BULK_KEY_FILE" 2>/dev/null || true
52 fi
53 fi
54
55 # Set up identities for age decryption
56 if [[ -n "''${PASS_BULK_KEY_FILE:-}" ]] && [[ -f "$PASS_BULK_KEY_FILE" ]] && [[ -s "$PASS_BULK_KEY_FILE" ]]; then
57 # Use bulk key if available
58 export PASSAGE_IDENTITIES_FILE="$PASS_BULK_KEY_FILE"
59 else
60 # Detect available age keys
61 export AGE_DETECT_KEYS_DIR="${self}/keys"
62 eval "$(age-detect)"
63
64 # Set up identity file if detected
65 if [[ -n "''${IDENTITY_FILE:-}" ]]; then
66 export PASSAGE_IDENTITIES_FILE="$IDENTITY_FILE"
67 trap 'rm -f "$IDENTITY_FILE"' EXIT
68 fi
69 fi
70
71 ${
72 if pkgs.stdenv.isLinux then
73 ''
74 maybe_set_tpm_pin() {
75 local target="''${1:-<stdin>}"
76 if [[ "''${KEY_TYPE:-}" != "tpm" ]]; then
77 return 0
78 fi
79 if [[ -n "''${AGE_TPM_PIN:-}" ]]; then
80 return 0
81 fi
82 AGE_TPM_PIN="$(${self.packages.${system}.pinentry-rofi-age}/bin/pinentry-rofi-age "$target")"
83 export AGE_TPM_PIN
84 }
85
86 decrypt_target=""
87 if [[ "''${1:-}" == "show" ]]; then
88 decrypt_target="''${2:-}"
89 elif [[ -n "''${1:-}" ]] && [[ "''${1:-}" != -* ]] && [[ "''${1:-}" != "otp" ]]; then
90 decrypt_target="''${1:-}"
91 fi
92
93 if [[ -n "$decrypt_target" ]]; then
94 maybe_set_tpm_pin "$decrypt_target"
95 fi
96 ''
97 else
98 ''
99 # No TPM on Darwin, define no-op
100 maybe_set_tpm_pin() { :; }
101 ''
102 }
103
104 # Handle OTP commands by delegating to pass-otp
105 if [[ "''${1:-}" == "otp" ]]; then
106 shift
107 # Extract pass name and options
108 clip_arg=""
109 pass_name=""
110 for arg in "$@"; do
111 case "$arg" in
112 "--clip"|"-c")
113 clip_arg="--clip"
114 ;;
115 *)
116 pass_name="$arg"
117 ;;
118 esac
119 done
120
121 if [[ -z "$pass_name" ]]; then
122 echo "Usage: pass otp [--clip,-c] pass-name"
123 exit 1
124 fi
125
126 # Show pass and pipe to OTP (identities already set up by age-detect)
127 maybe_set_tpm_pin "$pass_name"
128 ${exePath} show "$pass_name" | pass-otp $clip_arg
129 else
130 # Pass all other commands directly to passage (identities already set up)
131 ${exePath} "$@"
132 fi
133 '';
134 };
135 };
136}