25#include <freertos/FreeRTOS.h>
26#include <freertos/semphr.h>
32static const char*
TAG =
"FIDO2_UI";
37 {
"mod_fido2.title",
"WebAuthn"},
38 {
"mod_fido2.fido2_key",
"FIDO2 Key"},
39 {
"mod_fido2.sign_in_to",
"Sign in to"},
40 {
"mod_fido2.register_key",
"Register Key"},
41 {
"mod_fido2.sign_in",
"Sign In"},
42 {
"mod_fido2.use_device",
"Use this device?"},
43 {
"mod_fido2.no_entries",
"No entries"},
44 {
"mod_fido2.overwrite_key",
"OVERWRITE KEY!"},
45 {
"mod_fido2.overwrite_warning",
"Overwrite existing key?"},
101 if (!a && !b)
return 0;
104 return strcasecmp(a, b);
135 "%.45s", info.
rp_id);
146 for (uint8_t display = 0; display < count; display++) {
149 s_listItems[display].userData =
reinterpret_cast<void*
>(
static_cast<uintptr_t
>(display));
167 if (display_index >= count)
return;
169 uint8_t store_index =
s_sortMap[display_index];
175 const char* key_type = (strncmp(info.
rp_id,
"ssh:", 4) == 0) ?
"SSH" :
"WebAuthn";
179 uint8_t pubkey[64] = {};
184 strlcpy(fingerprint,
"(no key)",
sizeof(fingerprint));
187 static char detail_text[384];
189 snprintf(detail_text,
sizeof(detail_text),
190 "Relying Party:\n%s\n\n"
191 "Type: %s Algo: %s\n"
196 "Fingerprint:\n%s\n\n"
205 ui::tr(
"core.hint_back"));
220 if (display_index >= count)
return;
222 uint8_t store_index =
s_sortMap[display_index];
263 items[2] = {
ui::tr(
"core.cancel"), []() {}};
265 const uint8_t store_idx =
s_sortMap[sel];
267 const char* title =
s_labels[store_idx];
269 strncpy(s_contextTitle, info.
rp_id,
sizeof(s_contextTitle) - 1);
270 s_contextTitle[
sizeof(s_contextTitle) - 1] =
'\0';
271 title = s_contextTitle;
273 showContextMenu(title, items, 3);
312 display->backlightOff();
452 return ui::tr(
"mod_fido2.title");
472 LOG_I(
TAG,
"User presence: action=%s, rp='%s', promptActive=%d",
478 (strcmp(
rp_id,
".dummy") == 0 || strcmp(
rp_id,
"make.me.blink") == 0)) {
486 LOG_W(
TAG,
"Presence request supersedes active prompt -> cancel old");
518 display->backlightOn();
521 const char* confirm_msg =
ui::tr(
"mod_fido2.overwrite_warning");
528 const TickType_t poll = pdMS_TO_TICKS(100);
529 TickType_t remaining = pdMS_TO_TICKS(30000);
530 bool approved =
false;
531 bool timedOut =
true;
532 while (remaining > 0) {
533 TickType_t wait = remaining < poll ? remaining : poll;
543 LOG_W(
TAG,
"Overwrite confirm timeout");
548 display->backlightOff();
550 LOG_I(
TAG,
"Overwrite denied/timeout - aborting registration");
553 LOG_I(
TAG,
"Overwrite acknowledged, proceeding to user-presence prompt");
564 LOG_W(
TAG,
"Drained stale semaphore");
573 LOG_W(
TAG,
"Could not acquire ViewStack lock for FIDO2 prompt");
588 display->backlightOn();
591 const char* headline =
nullptr;
593 headline =
ui::tr(
"mod_fido2.use_device");
595 headline =
ui::tr(
"mod_fido2.register_key");
597 headline =
ui::tr(
"mod_fido2.overwrite_key");
599 headline =
ui::tr(
"mod_fido2.sign_in");
602 static char prompt_text[260];
604 snprintf(prompt_text,
sizeof(prompt_text),
607 ui::tr(
"core.hint_approve_deny"));
609 snprintf(prompt_text,
sizeof(prompt_text),
610 "!!! %s !!!\n\n%s\n\n%s\n\n%s",
613 ui::tr(
"mod_fido2.overwrite_warning"),
614 ui::tr(
"core.hint_approve_deny"));
616 snprintf(prompt_text,
sizeof(prompt_text),
620 ui::tr(
"core.hint_approve_deny"));
623 const char* title =
ui::tr(
"mod_fido2.title");
624 LOG_I(
TAG,
"Prompt title='%s', text='%.50s...'", title ? title :
"(null)", prompt_text);
630 stack.resetInactivityTimer();
636 const TickType_t up_poll = pdMS_TO_TICKS(100);
637 TickType_t up_remaining = pdMS_TO_TICKS(30000);
638 bool up_done =
false;
639 bool up_cancelled =
false;
640 while (up_remaining > 0) {
641 TickType_t wait = up_remaining < up_poll ? up_remaining : up_poll;
651 up_remaining -= wait;
657 LOG_W(
TAG,
"Semaphore signalled with PENDING result -> deny");
664 LOG_W(
TAG,
"User presence cancelled by CTAP host");
666 LOG_W(
TAG,
"User presence timeout");
673 display->backlightOff();
684 LOG_W(
TAG,
"Prompt aborted externally");
Internationalization with English fallbacks in code and overlay translations loaded at runtime from a...
bool key_fingerprint_from_pubkey(const uint8_t *pubkey, size_t pubkey_len, char *buf, size_t len)
Generates human-readable fingerprint from public key bytes.
#define KEY_FINGERPRINT_MAX_LEN
Shared RAII wrappers for firmware resources.
CDC Log: logging over TinyUSB CDC and UART.
#define LOG_W(tag, fmt,...)
#define LOG_I(tag, fmt,...)
RAII wrapper for a FreeRTOS semaphore / mutex.
static constexpr uint8_t BADGE_PIN_MAX
bool verifyBadgePin(const char *pin)
Verifies badge PIN, updates retries, and handles lockout transitions.
static constexpr uint8_t BADGE_PIN_MIN
static PinManager & instance()
Returns singleton PIN manager instance.
static I18n & instance()
Singleton accessor.
void registerEnglishTable(const I18nEntry *entries, std::size_t count)
Append English entries to the lookup table.
static ViewStack & instance()
Returns singleton view-stack instance.
void push(IView *view, void *context=nullptr)
void ctap2_clear_cancel(void)
Clears the cancel flag. Called when a new CTAPHID channel is opened so a cancel from a previous chann...
bool ctap2_is_cancelled(void)
Returns true if the current CTAP2 operation has been cancelled.
uint32_t ctaphid_get_current_cid(void)
Returns the channel identifier of the currently processed request.
#define CTAPHID_STATUS_UPNEEDED
void ctaphid_send_keepalive(uint32_t cid, uint8_t status)
Sends a CTAPHID KEEPALIVE packet immediately over USB.
#define CDC_CURVE_ED25519
#define FIDO2_MAX_CREDENTIALS
void fido2_set_pin_verified(bool verified)
Stores whether PIN verification was completed via ClientPIN.
#define FIDO2_RP_ID_MAX_LEN
bool fido2_get_credential_info(uint8_t index, fido2_credential_info_t *info)
bool fido2_delete_credential(uint8_t slot)
Deletes credential in given slot.
fido2_user_presence_result_t
bool fido2_is_pin_verified(void)
Returns current PIN-verified state.
uint8_t fido2_get_credential_count(void)
Returns number of stored credentials.
@ FIDO2_ACTION_AUTHENTICATE
char rp_id[FIDO2_RP_ID_MAX_LEN]
char user_name[FIDO2_USER_NAME_MAX_LEN]
uint8_t fido2_storage_ecc_start(void)
Returns configured ECC start slot.
bool fido2_storage_get_pubkey(uint8_t slot, uint8_t *pubkey)
Reads public key from secure-element slot.
IDisplay * getDisplayInstance()
Returns lazily created singleton display instance.
static ui::PinEntryView * s_pinEntry
static ui::InfoView * s_detailView
static void onPinFailure(bool lockedOut)
PIN failure callback handling lockout vs retry messaging.
cdc::ui::IView * fido2_ui_get_list_view()
Returns FIDO2 credential list view.
static void onOverwriteConfirm(void *)
static ui::ListItem s_listItems[FIDO2_MAX_CREDENTIALS]
static bool onPinVerify(const char *pin)
PIN verification callback for locked-screen approval flow.
static void ensurePromptMutex()
static ui::IView * s_promptReturnView
static void onPinCancel()
PIN cancel callback denying user presence.
static SemaphoreHandle_t s_promptSem
User-presence prompt state shared across callback and UI flow.
static volatile fido2_user_presence_result_t s_promptResult
static uint8_t s_listCount
static volatile bool s_overwriteApproved
static void onListSelect(uint16_t index, void *userData)
List selection callback opening credential detail view.
static char s_promptRpId[FIDO2_RP_ID_MAX_LEN]
static void handleDelete(uint16_t display_index)
Deletes selected credential and refreshes list.
static bool s_promptBacklightWasOn
bool fido2_ui_abort_prompt()
Forcibly denies any in-flight user-presence prompt.
static SemaphoreHandle_t s_overwriteSem
Pre-confirm modal state for overwrite warning.
void fido2_ui_init()
Initializes FIDO2 UI resources and list views.
static void rebuildList()
Rebuilds credential list view from current storage contents.
static void showDetail(uint16_t display_index)
Shows detailed view for selected credential.
constexpr ui::I18nEntry kStrings[]
static void promptComplete(fido2_user_presence_result_t result)
Completes user-presence prompt flow with result handling.
static void onPromptApprove(void *userData)
Prompt approve callback; optionally triggers PIN entry on lock screen.
static void onOverwriteCancel(void *)
static uint8_t s_promptReturnDepth
static ui::ListView * s_listView
FIDO2 UI view and list state.
static int strcasecmp_safe(const char *a, const char *b)
Null-safe ASCII case-insensitive comparison.
static void onListMenu(uint16_t index, void *userData)
List menu callback opening context actions for selected credential.
static SemaphoreHandle_t s_promptMutex
static volatile bool s_promptActive
static void registerStrings()
static void onPromptDeny(void *userData)
Prompt deny callback.
static fido2_action_t s_promptAction
static uint8_t s_sortMap[FIDO2_MAX_CREDENTIALS]
static char s_labels[FIDO2_MAX_CREDENTIALS][100]
static ui::InfoView * s_promptView
fido2_user_presence_result_t fido2_ui_user_presence_callback(const char *rp_id, fido2_action_t action, const char *user_name)
User-presence callback used by FIDO2 core for approval prompts.
static bool s_promptWasLocked
static void onPinSuccess()
PIN success callback approving user presence.
const char * fido2_ui_get_label()
Returns localized module label for menus.
static void restoreView()
Restores view stack to pre-prompt depth.
const char * tr(const char *key)
Look up a translation by string key.
void showConfirm(const char *message, ConfirmView::ConfirmCallback onConfirm, ConfirmView::CancelCallback onCancel=nullptr, ConfirmView::Icon icon=ConfirmView::Icon::QUESTION, void *userData=nullptr)
Shows a shared modal confirmation dialog instance.
void showToastSuccess(const char *message, uint16_t durationMs=1500)
Shows a success toast message.
void showToastError(const char *message, uint16_t durationMs=1500)
Shows an error toast message.
Single English translation entry.