Implement listing users

This commit is contained in:
2026-06-03 13:50:11 +02:00
parent e0669792c1
commit bc73c1055e
2 changed files with 85 additions and 31 deletions

View File

@@ -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);
}
}