From 2961345beabb2d2809b31398d861c1d55e826906 Mon Sep 17 00:00:00 2001 From: ThoNohT Date: Wed, 17 Jun 2026 17:34:07 +0200 Subject: [PATCH] Implement listing users --- src/noh.h | 12 +++--- src/userctl.c | 104 ++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 85 insertions(+), 31 deletions(-) diff --git a/src/noh.h b/src/noh.h index 24ccbfd..bd98f9e 100644 --- a/src/noh.h +++ b/src/noh.h @@ -397,13 +397,13 @@ void noh_sv_trim_right(Noh_String_View *sv, bool (*do_trim)(char)); void noh_sv_trim(Noh_String_View *sv, bool (*do_trim)(char)); // Trims spaces from the left part of a string view. -inline void noh_sv_trim_space_left(Noh_String_View *sv); +void noh_sv_trim_space_left(Noh_String_View *sv); // Trims spaces from the right part of a string view. -inline void noh_sv_trim_space_right(Noh_String_View *sv); +void noh_sv_trim_space_right(Noh_String_View *sv); // Trims spaces from both sides of a string view. -inline void noh_sv_trim_space(Noh_String_View *sv); +void noh_sv_trim_space(Noh_String_View *sv); // Creates a string view from a c-string. Noh_String_View noh_sv_from_cstr(const char *cstr); @@ -1000,15 +1000,15 @@ bool is_space(char c) { return isspace(c) > 0; } -inline void noh_sv_trim_space_left(Noh_String_View *sv) { +void noh_sv_trim_space_left(Noh_String_View *sv) { noh_sv_trim_left(sv, &is_space); } -inline void noh_sv_trim_space_right(Noh_String_View *sv) { +void noh_sv_trim_space_right(Noh_String_View *sv) { noh_sv_trim_right(sv, &is_space); } -inline void noh_sv_trim_space(Noh_String_View *sv) { +void noh_sv_trim_space(Noh_String_View *sv) { noh_sv_trim(sv, &is_space); } diff --git a/src/userctl.c b/src/userctl.c index f4e1361..48c543c 100644 --- a/src/userctl.c +++ b/src/userctl.c @@ -8,6 +8,8 @@ #include "path.c" +Noh_Arena temp; + static void show_usage(char *program_name, char *error) { noh_log(NOH_INFO, "Usage:"); noh_log(NOH_INFO, "%s command [args]", program_name); @@ -24,11 +26,15 @@ static void show_usage(char *program_name, char *error) { noh_log(NOH_INFO, " username: The username of the user to delete."); noh_log(NOH_INFO, "Deletes a user, optionally also deleting their library folder."); noh_log(NOH_INFO, ""); + noh_log(NOH_INFO, "%s list library_path", program_name); + noh_log(NOH_INFO, " library_path: The path to the library where the users file and user subfolders are located."); + noh_log(NOH_INFO, "Lists all users defined in the provided library path."); + noh_log(NOH_INFO, ""); noh_log(NOH_ERROR, "%s", error); exit(1); } -Noh_String hash_password(Noh_Arena *arena, Noh_String_View username, Noh_String_View password) { +Noh_String hash_password(Noh_String_View username, Noh_String_View password) { // Build the sha input string. Noh_String input = {0}; noh_string_append_sv(&input, username); @@ -43,12 +49,12 @@ Noh_String hash_password(Noh_Arena *arena, Noh_String_View username, Noh_String_ sha256_final(&ctx, hash); // Build the result string. - noh_arena_save(arena); + noh_arena_save(&temp); Noh_String result = {0}; for (int i = 0; i < 32; i++) { - noh_string_append_cstr(&result, noh_arena_sprintf(arena, "%02x", hash[i])); + noh_string_append_cstr(&result, noh_arena_sprintf(&temp, "%02x", hash[i])); } - noh_arena_reset(arena); + noh_arena_reset(&temp); return result; } @@ -64,16 +70,21 @@ typedef struct { size_t capacity; } Users; - bool read_users_file(char *file_path, Users *users) { Noh_String users_file = {0}; + noh_log(NOH_INFO, "Reading users file: %s", file_path); if (!noh_file_exists(file_path)) return true; if (!noh_string_read_file(&users_file, file_path)) return false; Noh_String_View users_file_sv = noh_sv_from_string(users_file); + Noh_String_View line = {0}; for (size_t i = 0; users_file_sv.count > 0; i++) { - Noh_String_View line = noh_sv_chop_line(&users_file_sv); + line = noh_sv_chop_line(&users_file_sv); + + // Ignore empty lines. + noh_sv_trim_space(&line); + if (line.count == 0) continue; Noh_String_View un = noh_sv_chop_by_delim(&line, ':'); @@ -103,9 +114,24 @@ bool write_users_file(char *file_path, Users *users) { } +/// Prompts a user with a question and returns their response. +bool prompt_user(char *question) { + noh_arena_save(&temp); + noh_log(NOH_INFO, noh_arena_sprintf(&temp, "%s [yn]", question)); + noh_arena_reset(&temp); + + char response; + if (!scanf(" %c", &response)) { + noh_log(NOH_ERROR, "Error reading response from stdin."); + return false; + } + + return response == 'y' || response == 'Y'; +} + bool register_user(Noh_String_View library_path, Noh_String_View username, Noh_String_View password) { // Read the file. - Noh_String_View file_name = noh_sv_from_cstr("users.txt"); + Noh_String_View file_name = noh_sv_from_cstr("users.conf"); Noh_String users_file_path = build_path(false, &library_path, &file_name); noh_string_append_null(&users_file_path); @@ -115,8 +141,7 @@ bool register_user(Noh_String_View library_path, Noh_String_View username, Noh_S bool result = true; // Hash the password. - Noh_Arena arena = noh_arena_init(1 KB); - Noh_String hashed = hash_password(&arena, username, password); + Noh_String hashed = hash_password(username, password); // Find the user in the map of users. for (size_t i = 0; i < users.count; i++) { @@ -124,15 +149,7 @@ bool register_user(Noh_String_View library_path, Noh_String_View username, Noh_S if (!noh_sv_eq_ci(user->username, username)) continue; // The user exists. Update password after confirmation. - noh_log(NOH_INFO, "User already exists. Update password? [yn]"); - - char response; - if (!scanf(" %c", &response)) { - noh_log(NOH_ERROR, "Error reading response from stdin."); - noh_return_defer(false); - } - - if (response != 'y') { + if (!prompt_user("User already exists. Update password? [yn]")) { noh_log(NOH_INFO, "Ok, not changing anything."); noh_return_defer(true); } @@ -154,10 +171,39 @@ defer: return result; } +bool list_users(Noh_String_View library_path) { + // Read the file. + Noh_String_View file_name = noh_sv_from_cstr("users.conf"); + Noh_String users_file_path = build_path(false, &library_path, &file_name); + noh_string_append_null(&users_file_path); + + // Build users map. + Users users = {0}; + if (!read_users_file(users_file_path.elems, &users)) return false; + + if (users.count == 0) { + noh_log(NOH_INFO, "No users registered."); + noh_da_free(&users); + return true; + } + + noh_arena_save(&temp); + noh_log(NOH_INFO, "Users:"); + for (size_t i = 0; i < users.count; i++) { + User *user = &users.elems[i]; + noh_log(NOH_INFO, noh_arena_sprintf(&temp, "- "Nsv_Fmt, Nsv_Arg(user->username))); + } + noh_arena_reset(&temp); + + noh_da_free(&users); + return true; +} + int main(int argc, char **argv) { + temp = noh_arena_init(64 KB); + // Parse input parameters. char *program_name = noh_shift_args(&argc, &argv); - Noh_Arena arena = noh_arena_init(64 KB); if (argc < 1) show_usage(program_name, "Command not provided"); Noh_String_View command = noh_sv_from_cstr(noh_shift_args(&argc, &argv)); @@ -165,21 +211,29 @@ int main(int argc, char **argv) { if (argc < 1) show_usage(program_name, "Library path not provided."); Noh_String_View library_path = noh_sv_from_cstr(noh_shift_args(&argc, &argv)); - if (argc < 1) show_usage(program_name, "Username not provided."); - Noh_String_View username = noh_sv_from_cstr(noh_shift_args(&argc, &argv)); - if (noh_sv_eq_ci(command, noh_sv_from_cstr("register"))) { + if (argc < 1) show_usage(program_name, "Username not provided."); + Noh_String_View username = noh_sv_from_cstr(noh_shift_args(&argc, &argv)); + if (argc < 1) show_usage(program_name, "Password not provided."); Noh_String_View password = noh_sv_from_cstr(noh_shift_args(&argc, &argv)); - if (!register_user(library_path, username, password)) return 1; - return 0; + return register_user(library_path, username, password); } else if (noh_sv_eq_ci(command, sv("delete"))) { + if (argc < 1) show_usage(program_name, "Username not provided."); + Noh_String_View username = noh_sv_from_cstr(noh_shift_args(&argc, &argv)); + (void)username; + noh_assert(false); + } else if (noh_sv_eq_ci(command, sv("list"))) { + return list_users(library_path); + } else { - show_usage(program_name, noh_arena_sprintf(&arena, "Unknown command: "Nsv_Fmt, Nsv_Arg(command))); + noh_arena_save(&temp); + show_usage(program_name, noh_arena_sprintf(&temp, "Unknown command: "Nsv_Fmt, Nsv_Arg(command))); + noh_arena_reset(&temp); } }