v0.0.11 - Improve startup UX: print version, visible mnemonic entry, retry up to 10 attempts, and support q/x quit
This commit is contained in:
150
src/main.c
150
src/main.c
@@ -451,8 +451,8 @@ int socket_name_random(char *out, size_t out_len);
|
||||
/* Version information (auto-updated by build/version tooling) */
|
||||
#define NSIGNER_VERSION_MAJOR 0
|
||||
#define NSIGNER_VERSION_MINOR 0
|
||||
#define NSIGNER_VERSION_PATCH 10
|
||||
#define NSIGNER_VERSION "v0.0.10"
|
||||
#define NSIGNER_VERSION_PATCH 11
|
||||
#define NSIGNER_VERSION "v0.0.11"
|
||||
|
||||
|
||||
/* NSIGNER_HEADERLESS_DECLS_END */
|
||||
@@ -807,7 +807,7 @@ static void render_status(const role_table_t *role_table,
|
||||
}
|
||||
|
||||
printf("\nHotkeys\n-------\n");
|
||||
printf("q quit l lock/reunlock r refresh a toggle auto-approve(prompt): %s\n",
|
||||
printf("q/x quit l lock/reunlock r refresh a toggle auto-approve(prompt): %s\n",
|
||||
g_auto_approve ? "ON" : "OFF");
|
||||
fflush(stdout);
|
||||
}
|
||||
@@ -836,94 +836,101 @@ static int prompt_load_mnemonic(mnemonic_state_t *mnemonic) {
|
||||
char phrase[MNEMONIC_MAX_LEN];
|
||||
char phrase_copy[MNEMONIC_MAX_LEN];
|
||||
char mode[MNEMONIC_MAX_LEN];
|
||||
struct termios old_term;
|
||||
struct termios new_term;
|
||||
int have_term = 0;
|
||||
int invalid_attempts = 0;
|
||||
const int max_invalid_attempts = 10;
|
||||
|
||||
if (mnemonic == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Mnemonic source: [E]nter existing or [G]enerate new (default E; you can also paste mnemonic here): ");
|
||||
fflush(stdout);
|
||||
if (read_line_stdin(mode, sizeof(mode)) != 0) {
|
||||
fprintf(stderr, "Failed to read mnemonic source choice\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strchr(mode, ' ') != NULL && mode[0] != 'g' && mode[0] != 'G') {
|
||||
if (mnemonic_load(mnemonic, mode) != 0) {
|
||||
fprintf(stderr, "Invalid mnemonic (must be 12/15/18/21/24 words)\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mode[0] == 'g' || mode[0] == 'G') {
|
||||
int idx = 1;
|
||||
char *ctx = NULL;
|
||||
char *word;
|
||||
|
||||
if (mnemonic_generate(12, phrase, sizeof(phrase)) != 0) {
|
||||
fprintf(stderr, "Failed to generate mnemonic\n");
|
||||
while (invalid_attempts < max_invalid_attempts) {
|
||||
printf("Mnemonic source: [E]nter existing or [G]enerate new (default E; you can also paste mnemonic here): ");
|
||||
fflush(stdout);
|
||||
if (read_line_stdin(mode, sizeof(mode)) != 0) {
|
||||
fprintf(stderr, "Failed to read mnemonic source choice\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(phrase_copy, phrase, sizeof(phrase_copy) - 1);
|
||||
phrase_copy[sizeof(phrase_copy) - 1] = '\0';
|
||||
|
||||
printf("\nGenerated mnemonic (WRITE THIS DOWN - it will not be shown again):\n");
|
||||
word = strtok_r(phrase_copy, " ", &ctx);
|
||||
while (word != NULL) {
|
||||
printf("%2d. %s\n", idx, word);
|
||||
idx++;
|
||||
word = strtok_r(NULL, " ", &ctx);
|
||||
if ((mode[0] == 'q' || mode[0] == 'Q' || mode[0] == 'x' || mode[0] == 'X') && mode[1] == '\0') {
|
||||
fprintf(stderr, "User requested exit.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mnemonic_load(mnemonic, phrase) != 0) {
|
||||
if (strchr(mode, ' ') != NULL && mode[0] != 'g' && mode[0] != 'G') {
|
||||
if (mnemonic_load(mnemonic, mode) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
invalid_attempts++;
|
||||
fprintf(stderr,
|
||||
"Invalid mnemonic (must be 12/15/18/21/24 words). Attempts: %d/%d\n",
|
||||
invalid_attempts,
|
||||
max_invalid_attempts);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mode[0] == 'g' || mode[0] == 'G') {
|
||||
int idx = 1;
|
||||
char *ctx = NULL;
|
||||
char *word;
|
||||
|
||||
if (mnemonic_generate(12, phrase, sizeof(phrase)) != 0) {
|
||||
fprintf(stderr, "Failed to generate mnemonic\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(phrase_copy, phrase, sizeof(phrase_copy) - 1);
|
||||
phrase_copy[sizeof(phrase_copy) - 1] = '\0';
|
||||
|
||||
printf("\nGenerated mnemonic (WRITE THIS DOWN - it will not be shown again):\n");
|
||||
word = strtok_r(phrase_copy, " ", &ctx);
|
||||
while (word != NULL) {
|
||||
printf("%2d. %s\n", idx, word);
|
||||
idx++;
|
||||
word = strtok_r(NULL, " ", &ctx);
|
||||
}
|
||||
|
||||
if (mnemonic_load(mnemonic, phrase) != 0) {
|
||||
memset(phrase, 0, sizeof(phrase));
|
||||
memset(phrase_copy, 0, sizeof(phrase_copy));
|
||||
fprintf(stderr, "Failed to load generated mnemonic\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(phrase, 0, sizeof(phrase));
|
||||
memset(phrase_copy, 0, sizeof(phrase_copy));
|
||||
fprintf(stderr, "Failed to load generated mnemonic\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("Enter mnemonic (12/15/18/21/24 words): ");
|
||||
fflush(stdout);
|
||||
|
||||
if (read_line_stdin(phrase, sizeof(phrase)) != 0) {
|
||||
fprintf(stderr, "Failed to read mnemonic\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(phrase, 0, sizeof(phrase));
|
||||
memset(phrase_copy, 0, sizeof(phrase_copy));
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("Enter mnemonic (12/15/18/21/24 words): ");
|
||||
fflush(stdout);
|
||||
|
||||
if (isatty(STDIN_FILENO) && tcgetattr(STDIN_FILENO, &old_term) == 0) {
|
||||
new_term = old_term;
|
||||
new_term.c_lflag &= (tcflag_t)~ECHO;
|
||||
if (tcsetattr(STDIN_FILENO, TCSANOW, &new_term) == 0) {
|
||||
have_term = 1;
|
||||
if ((phrase[0] == 'q' || phrase[0] == 'Q' || phrase[0] == 'x' || phrase[0] == 'X') && phrase[1] == '\0') {
|
||||
memset(phrase, 0, sizeof(phrase));
|
||||
fprintf(stderr, "User requested exit.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (read_line_stdin(phrase, sizeof(phrase)) != 0) {
|
||||
if (have_term) {
|
||||
(void)tcsetattr(STDIN_FILENO, TCSANOW, &old_term);
|
||||
if (mnemonic_load(mnemonic, phrase) == 0) {
|
||||
memset(phrase, 0, sizeof(phrase));
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr, "Failed to read mnemonic\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (have_term) {
|
||||
(void)tcsetattr(STDIN_FILENO, TCSANOW, &old_term);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (mnemonic_load(mnemonic, phrase) != 0) {
|
||||
memset(phrase, 0, sizeof(phrase));
|
||||
fprintf(stderr, "Invalid mnemonic (must be 12/15/18/21/24 words)\n");
|
||||
return -1;
|
||||
invalid_attempts++;
|
||||
fprintf(stderr,
|
||||
"Invalid mnemonic (must be 12/15/18/21/24 words). Attempts: %d/%d\n",
|
||||
invalid_attempts,
|
||||
max_invalid_attempts);
|
||||
}
|
||||
|
||||
memset(phrase, 0, sizeof(phrase));
|
||||
return 0;
|
||||
fprintf(stderr, "Too many invalid mnemonic attempts (%d). Exiting.\n", max_invalid_attempts);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void apply_test_overrides(policy_table_t *policy) {
|
||||
@@ -1055,6 +1062,9 @@ int main(int argc, char *argv[]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("nsigner %s\n", NSIGNER_VERSION);
|
||||
fflush(stdout);
|
||||
|
||||
mnemonic_init(&mnemonic);
|
||||
if (prompt_load_mnemonic(&mnemonic) != 0) {
|
||||
mnemonic_unload(&mnemonic);
|
||||
@@ -1207,7 +1217,7 @@ int main(int argc, char *argv[]) {
|
||||
char ch = '\0';
|
||||
if (read(STDIN_FILENO, &ch, 1) > 0) {
|
||||
ch = (char)tolower((unsigned char)ch);
|
||||
if (ch == 'q') {
|
||||
if (ch == 'q' || ch == 'x') {
|
||||
g_running = 0;
|
||||
} else if (ch == 'r') {
|
||||
render_status(&role_table, &mnemonic, derived_count, socket_name);
|
||||
|
||||
Reference in New Issue
Block a user