Problem
On a configured NK3 with 8 PIN attempts remaining, entering a wrong
Secrets App PIN in seal-hotpkey.sh causes the PIN retry counter display
to drop from 8 to 0 instead of showing the actual remaining attempts.
Root cause: ${admin_pin_retries:-0} at the end of both
show_pin_retries() and the max_attempts re-read block. When
hotp_verification info is re-queried and fails transiently (CCID
stalled after a wrong PIN), stdout is empty, the grep produces nothing,
and :-0 overwrites the last known value with 0.
Additionally, on NK3 with an unconfigured slot, hotp_verification info
may exit non-zero even though the dongle IS connected. The old presence
check relied on exit code, mistaking 'dongle present but slot
unconfigured' for 'no dongle'.
-
Temp variable guard: show_pin_retries() / max_attempts use a
temp variable to parse the counter; only update admin_pin_retries
when the re-query succeeds. Preserves the last known value across
transient failures instead of dropping to 0.
-
Presence check: capture stdout regardless of exit code, grep
for 'Connected device status:'. On failure, prompt user to
reinsert with the standard INPUT pattern.
-
No fabricated numbers: hotp_verification info output is the
truth. No ${var:-0} drop to 0, no non-numeric-to-8 fallback.
When the counter is non-numeric (unconfigured slot),
max_attempts falls through to the else clause (3).
Problem
On a configured NK3 with 8 PIN attempts remaining, entering a wrong
Secrets App PIN in seal-hotpkey.sh causes the PIN retry counter display
to drop from 8 to 0 instead of showing the actual remaining attempts.
Root cause: ${admin_pin_retries:-0} at the end of both
show_pin_retries() and the max_attempts re-read block. When
hotp_verification info is re-queried and fails transiently (CCID
stalled after a wrong PIN), stdout is empty, the grep produces nothing,
and :-0 overwrites the last known value with 0.
Additionally, on NK3 with an unconfigured slot, hotp_verification info
may exit non-zero even though the dongle IS connected. The old presence
check relied on exit code, mistaking 'dongle present but slot
unconfigured' for 'no dongle'.
Fix (PR #2116)
Temp variable guard: show_pin_retries() / max_attempts use a
temp variable to parse the counter; only update admin_pin_retries
when the re-query succeeds. Preserves the last known value across
transient failures instead of dropping to 0.
Presence check: capture stdout regardless of exit code, grep
for 'Connected device status:'. On failure, prompt user to
reinsert with the standard INPUT pattern.
No fabricated numbers: hotp_verification info output is the
truth. No ${var:-0} drop to 0, no non-numeric-to-8 fallback.
When the counter is non-numeric (unconfigured slot),
max_attempts falls through to the else clause (3).