Téléverser les fichiers vers "modules"
This commit is contained in:
+114
-94
@@ -127,124 +127,144 @@ let
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pinPython = pkgs.python3.withPackages (ps: [
|
||||||
|
ps.fido2
|
||||||
|
]);
|
||||||
|
|
||||||
pinHelper = pkgs.writeTextFile {
|
pinHelper = pkgs.writeTextFile {
|
||||||
name = "nixos-workstations-pin-helper";
|
name = "nixos-workstations-pin-helper";
|
||||||
executable = true;
|
executable = true;
|
||||||
text = ''
|
text = ''
|
||||||
#!${pkgs.expect}/bin/expect -f
|
#!${pinPython}/bin/python3
|
||||||
|
"""Change a FIDO2 PIN without exposing secrets in argv.
|
||||||
|
|
||||||
# Une seule invocation de ykman par clic : aucune tentative automatique
|
Input on stdin, one UTF-8 line each:
|
||||||
# supplémentaire n'est faite en cas de mauvais PIN.
|
1. current PIN
|
||||||
log_user 0
|
2. new PIN
|
||||||
exp_internal 0
|
3. confirmation
|
||||||
set timeout 30
|
|
||||||
|
|
||||||
proc fail {token code} {
|
Output contains technical tokens only, never the PIN values.
|
||||||
puts stderr $token
|
Exactly one CTAP2 change_pin operation is attempted.
|
||||||
exit $code
|
"""
|
||||||
}
|
|
||||||
|
|
||||||
if {[gets stdin current] < 0 || [gets stdin newpin] < 0 || [gets stdin confirm] < 0} {
|
import sys
|
||||||
fail "INPUT_ERROR" 30
|
|
||||||
}
|
|
||||||
|
|
||||||
if {$newpin ne $confirm} {
|
from fido2.ctap import CtapError
|
||||||
fail "CONFIRM_MISMATCH" 31
|
from fido2.ctap2 import Ctap2
|
||||||
}
|
from fido2.ctap2.pin import ClientPin
|
||||||
|
from fido2.hid import CAPABILITY, CtapHidDevice
|
||||||
|
|
||||||
spawn -noecho ${pkgs.coreutils}/bin/env LC_ALL=C LANG=C ${pkgs.yubikey-manager}/bin/ykman fido access change-pin
|
|
||||||
|
|
||||||
set transcript ""
|
def fail(token: str, code: int) -> "None":
|
||||||
|
print(token, file=sys.stderr, flush=True)
|
||||||
|
raise SystemExit(code)
|
||||||
|
|
||||||
# Une clé déjà provisionnée doit demander le PIN actuel. Si ykman passe
|
|
||||||
# directement au nouveau PIN, la clé n'a pas le pré-provisionnement attendu.
|
|
||||||
expect {
|
|
||||||
-re {(?i)enter.*current.*pin.*:} {
|
|
||||||
append transcript $expect_out(buffer)
|
|
||||||
send -- "$current\r"
|
|
||||||
}
|
|
||||||
-re {(?i)enter.*new.*pin.*:} {
|
|
||||||
append transcript $expect_out(buffer)
|
|
||||||
fail "PIN_NOT_CONFIGURED" 32
|
|
||||||
}
|
|
||||||
-re {(?i)(no yubikey|multiple yubikey|failed to connect|no fido|device.*not found|permission denied|access denied)} {
|
|
||||||
append transcript $expect_out(buffer)
|
|
||||||
fail "NO_YUBIKEY" 33
|
|
||||||
}
|
|
||||||
eof {
|
|
||||||
append transcript $expect_out(buffer)
|
|
||||||
if {[regexp -nocase {no yubikey|multiple yubikey|failed to connect|no fido|device.*not found|permission denied|access denied} $transcript]} {
|
|
||||||
fail "NO_YUBIKEY" 34
|
|
||||||
}
|
|
||||||
fail "PIN_FAILED" 35
|
|
||||||
}
|
|
||||||
timeout {
|
|
||||||
fail "TIMEOUT_CURRENT_PIN" 124
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set current ""
|
def read_secret() -> str:
|
||||||
|
value = sys.stdin.readline()
|
||||||
|
if value == "":
|
||||||
|
fail("INPUT_ERROR", 30)
|
||||||
|
return value.rstrip("\r\n")
|
||||||
|
|
||||||
expect {
|
|
||||||
-re {(?i)enter.*new.*pin.*:} {
|
|
||||||
append transcript $expect_out(buffer)
|
|
||||||
send -- "$newpin\r"
|
|
||||||
}
|
|
||||||
eof {
|
|
||||||
append transcript $expect_out(buffer)
|
|
||||||
fail "PIN_FAILED" 36
|
|
||||||
}
|
|
||||||
timeout {
|
|
||||||
fail "TIMEOUT_NEW_PIN" 124
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expect {
|
current = read_secret()
|
||||||
-re {(?i)(repeat|confirm).*:} {
|
new_pin = read_secret()
|
||||||
append transcript $expect_out(buffer)
|
confirmation = read_secret()
|
||||||
send -- "$confirm\r"
|
|
||||||
}
|
|
||||||
eof {
|
|
||||||
append transcript $expect_out(buffer)
|
|
||||||
fail "PIN_FAILED" 37
|
|
||||||
}
|
|
||||||
timeout {
|
|
||||||
fail "TIMEOUT_CONFIRM_PIN" 124
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set newpin ""
|
if new_pin != confirmation:
|
||||||
set confirm ""
|
fail("CONFIRM_MISMATCH", 31)
|
||||||
|
|
||||||
expect eof
|
if len(current) < 4 or len(new_pin) < 4:
|
||||||
append transcript $expect_out(buffer)
|
fail("PIN_POLICY", 32)
|
||||||
set waitResult [wait]
|
|
||||||
set exitCode [lindex $waitResult 3]
|
|
||||||
|
|
||||||
if {$exitCode == 0} {
|
# CTAP2 PINs are UTF-8 strings with a maximum encoded size of 63 bytes.
|
||||||
puts "OK"
|
if len(current.encode("utf-8")) > 63 or len(new_pin.encode("utf-8")) > 63:
|
||||||
exit 0
|
fail("PIN_POLICY", 32)
|
||||||
}
|
|
||||||
|
|
||||||
if {[regexp -nocase {pin[_ ]auth[_ ]blocked|ctaperr_pin_auth_blocked|temporarily blocked} $transcript]} {
|
devices = []
|
||||||
fail "PIN_AUTH_BLOCKED" $exitCode
|
device = None
|
||||||
} elseif {[regexp -nocase {pin[_ ]blocked|ctaperr_pin_blocked|pin is blocked} $transcript]} {
|
|
||||||
fail "PIN_BLOCKED" $exitCode
|
|
||||||
} elseif {[regexp -nocase {wrong pin|pin_invalid|pin auth invalid|pin verification failed|ctaperr_pin_invalid} $transcript]} {
|
|
||||||
fail "WRONG_PIN" $exitCode
|
|
||||||
} elseif {[regexp -nocase {no yubikey|multiple yubikey|failed to connect|no fido|device.*not found|permission denied|access denied} $transcript]} {
|
|
||||||
fail "NO_YUBIKEY" $exitCode
|
|
||||||
} elseif {[regexp -nocase {complexity|policy|minimum pin length|must be at least|too short} $transcript]} {
|
|
||||||
fail "PIN_POLICY" $exitCode
|
|
||||||
}
|
|
||||||
|
|
||||||
fail "PIN_FAILED" $exitCode
|
try:
|
||||||
|
devices = list(CtapHidDevice.list_devices())
|
||||||
|
|
||||||
|
if len(devices) == 0:
|
||||||
|
fail("NO_YUBIKEY", 33)
|
||||||
|
|
||||||
|
if len(devices) > 1:
|
||||||
|
fail("MULTIPLE_YUBIKEY", 34)
|
||||||
|
|
||||||
|
device = devices[0]
|
||||||
|
|
||||||
|
if not (device.capabilities & CAPABILITY.CBOR):
|
||||||
|
fail("NO_FIDO2", 35)
|
||||||
|
|
||||||
|
ctap = Ctap2(device)
|
||||||
|
info = ctap.get_info()
|
||||||
|
|
||||||
|
# clientPin=True means a PIN is currently configured.
|
||||||
|
if not info.options.get("clientPin", False):
|
||||||
|
fail("PIN_NOT_CONFIGURED", 36)
|
||||||
|
|
||||||
|
client_pin = ClientPin(ctap)
|
||||||
|
|
||||||
|
# IMPORTANT: exactly one PIN-changing command. Do not verify the old PIN
|
||||||
|
# first: that would add an unnecessary extra PIN operation.
|
||||||
|
client_pin.change_pin(current, new_pin)
|
||||||
|
|
||||||
|
# Forget Python references as soon as the operation is complete.
|
||||||
|
current = ""
|
||||||
|
new_pin = ""
|
||||||
|
confirmation = ""
|
||||||
|
|
||||||
|
print("OK", flush=True)
|
||||||
|
raise SystemExit(0)
|
||||||
|
|
||||||
|
except CtapError as exc:
|
||||||
|
code = exc.code
|
||||||
|
|
||||||
|
if code == CtapError.ERR.PIN_INVALID:
|
||||||
|
fail("WRONG_PIN", 40)
|
||||||
|
if code == CtapError.ERR.PIN_AUTH_BLOCKED:
|
||||||
|
fail("PIN_AUTH_BLOCKED", 41)
|
||||||
|
if code == CtapError.ERR.PIN_BLOCKED:
|
||||||
|
fail("PIN_BLOCKED", 42)
|
||||||
|
if code == CtapError.ERR.PIN_NOT_SET:
|
||||||
|
fail("PIN_NOT_CONFIGURED", 43)
|
||||||
|
if code == CtapError.ERR.PIN_POLICY_VIOLATION:
|
||||||
|
fail("PIN_POLICY", 44)
|
||||||
|
|
||||||
|
fail("PIN_FAILED", 45)
|
||||||
|
|
||||||
|
except (PermissionError, OSError):
|
||||||
|
fail("NO_YUBIKEY", 46)
|
||||||
|
|
||||||
|
except ValueError:
|
||||||
|
# python-fido2 may reject an invalid PIN before sending CTAP2.
|
||||||
|
fail("PIN_POLICY", 47)
|
||||||
|
|
||||||
|
except SystemExit:
|
||||||
|
raise
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
# Do not expose exception text: it could contain device/environment
|
||||||
|
# details and is not needed by the UI. The setup log stores the token.
|
||||||
|
fail("PIN_HELPER_ERROR", 48)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
current = ""
|
||||||
|
new_pin = ""
|
||||||
|
confirmation = ""
|
||||||
|
for dev in devices:
|
||||||
|
try:
|
||||||
|
dev.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
workstationSetup = pkgs.stdenv.mkDerivation {
|
workstationSetup = pkgs.stdenv.mkDerivation {
|
||||||
pname = "nixos-workstations-setup";
|
pname = "nixos-workstations-setup";
|
||||||
version = "1.4.0";
|
version = "1.5.0";
|
||||||
|
|
||||||
src = ../workstation-setup;
|
src = ../workstation-setup;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user