Implement deleting a user

This commit is contained in:
2026-06-05 10:02:11 +02:00
parent bc73c1055e
commit 1c10371540
2 changed files with 95 additions and 9 deletions

View File

@@ -5,7 +5,7 @@ static Noh_String build_path_(bool url, Noh_String_View *first, ...) {
va_start(args, first); va_start(args, first);
bool start = true; bool start = true;
Noh_String result = {0}; Noh_String result = {0};
if (url) noh_string_append_cstr(&result, "/"); if (url || noh_sv_starts_with(*first, noh_sv_from_cstr("/"))) noh_string_append_cstr(&result, "/");
while (elem_ != NULL) { while (elem_ != NULL) {
Noh_String_View elem = *elem_; Noh_String_View elem = *elem_;

View File

@@ -1,5 +1,6 @@
#include <stdio.h> #include <stdio.h>
#include <sha256.h> #include <sha256.h>
#include <dirent.h>
#define NOH_IMPLEMENTATION #define NOH_IMPLEMENTATION
#include "noh.h" #include "noh.h"
@@ -70,6 +71,38 @@ typedef struct {
size_t capacity; size_t capacity;
} Users; } Users;
bool remove_directory(char *path) {
noh_arena_save(&temp);
bool result = true;
DIR *dir = opendir(path);
if (!dir) return false;
struct dirent *p;
while ((p = readdir(dir))) {
// Ignore . and .. file entries.
if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..")) continue;
char *sub_path = noh_arena_sprintf(&temp, "%s/%s", path, p->d_name);
// Delete files and recurse subfolders.
struct stat statbuf;
if (!stat(sub_path, &statbuf)) {
if (S_ISDIR(statbuf.st_mode))
result &= remove_directory(sub_path);
else
result &= unlink(sub_path) == 0;
}
}
closedir(dir);
if (result) result = rmdir(path);
noh_arena_reset(&temp);
return result;
}
bool read_users_file(char *file_path, Users *users) { bool read_users_file(char *file_path, Users *users) {
Noh_String users_file = {0}; Noh_String users_file = {0};
@@ -99,11 +132,13 @@ bool read_users_file(char *file_path, Users *users) {
return true; return true;
} }
bool write_users_file(char *file_path, Users *users) { bool write_users_file(char *file_path, Users *users, User *user_to_skip) {
Noh_String users_file = {0}; Noh_String users_file = {0};
for (size_t i = 0; i < users->count; i++) { for (size_t i = 0; i < users->count; i++) {
User *u = &users->elems[i]; User *u = &users->elems[i];
if (u == user_to_skip) continue;
noh_string_append_sv(&users_file, u->username); noh_string_append_sv(&users_file, u->username);
noh_string_append_cstr(&users_file, ":"); noh_string_append_cstr(&users_file, ":");
noh_string_append_sv(&users_file, u->hash); noh_string_append_sv(&users_file, u->hash);
@@ -149,14 +184,14 @@ bool register_user(Noh_String_View library_path, Noh_String_View username, Noh_S
if (!noh_sv_eq_ci(user->username, username)) continue; if (!noh_sv_eq_ci(user->username, username)) continue;
// The user exists. Update password after confirmation. // The user exists. Update password after confirmation.
if (!prompt_user("User already exists. Update password? [yn]")) { if (!prompt_user("User already exists. Update password?")) {
noh_log(NOH_INFO, "Ok, not changing anything."); noh_log(NOH_INFO, "Ok, not changing anything.");
noh_return_defer(true); noh_return_defer(true);
} }
noh_log(NOH_INFO, "Updating user password."); noh_log(NOH_INFO, "Updating user password.");
user->hash = noh_sv_from_string(hashed); user->hash = noh_sv_from_string(hashed);
if (!write_users_file(users_file_path.elems, &users)) noh_return_defer(false); if (!write_users_file(users_file_path.elems, &users, NULL)) noh_return_defer(false);
noh_return_defer(true); noh_return_defer(true);
} }
@@ -164,7 +199,58 @@ bool register_user(Noh_String_View library_path, Noh_String_View username, Noh_S
// User was not found, add it to the list. // User was not found, add it to the list.
noh_log(NOH_INFO, "Adding a new user."); noh_log(NOH_INFO, "Adding a new user.");
noh_da_append(&users, ((User){ .username = username, .hash = noh_sv_from_string(hashed) })); noh_da_append(&users, ((User){ .username = username, .hash = noh_sv_from_string(hashed) }));
if (!write_users_file(users_file_path.elems, &users)) noh_return_defer(false); if (!write_users_file(users_file_path.elems, &users, NULL)) noh_return_defer(false);
defer:
noh_da_free(&users);
return result;
}
bool delete_user(Noh_String_View library_path, Noh_String_View username) {
// 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;
bool result = true;
// Check if the user exists.
User *user_to_delete = NULL;
for (size_t i = 0; i < users.count; i++) {
User *user = &users.elems[i];
if (!noh_sv_eq_ci(user->username, username)) continue;
user_to_delete = user;
break;
}
// User does not exist, don't change anything.
if (!user_to_delete) {
noh_log(NOH_INFO, "User does not exist.");
noh_return_defer(true);
}
// The user exists. Prompt to confirm deletion.
if (!prompt_user("User found, delete the user?")) {
noh_log(NOH_INFO, "Ok, not changing anything.");
noh_return_defer(true);
}
noh_log(NOH_INFO, "Deleting user.");
if (!write_users_file(users_file_path.elems, &users, user_to_delete)) noh_return_defer(false);
// Prompt to delete the user's library folder.
Noh_String user_folder_path = build_path(false, &library_path, &username);
noh_string_append_null(&user_folder_path);
if (!noh_file_exists(user_folder_path.elems)) noh_return_defer(true);
if (prompt_user("Library folder exists. Delete it?")) {
noh_log(NOH_INFO, "Deleting library folder.");
return remove_directory(user_folder_path.elems);
}
defer: defer:
noh_da_free(&users); noh_da_free(&users);
@@ -218,22 +304,22 @@ int main(int argc, char **argv) {
if (argc < 1) show_usage(program_name, "Password not provided."); if (argc < 1) show_usage(program_name, "Password not provided.");
Noh_String_View password = noh_sv_from_cstr(noh_shift_args(&argc, &argv)); Noh_String_View password = noh_sv_from_cstr(noh_shift_args(&argc, &argv));
return register_user(library_path, username, password); return register_user(library_path, username, password) ? 0 : 1;
} else if (noh_sv_eq_ci(command, sv("delete"))) { } else if (noh_sv_eq_ci(command, sv("delete"))) {
if (argc < 1) show_usage(program_name, "Username not provided."); if (argc < 1) show_usage(program_name, "Username not provided.");
Noh_String_View username = noh_sv_from_cstr(noh_shift_args(&argc, &argv)); Noh_String_View username = noh_sv_from_cstr(noh_shift_args(&argc, &argv));
(void)username;
noh_assert(false); return delete_user(library_path, username) ? 0 : 1;
} else if (noh_sv_eq_ci(command, sv("list"))) { } else if (noh_sv_eq_ci(command, sv("list"))) {
return list_users(library_path); return list_users(library_path) ? 0 : 1;
} else { } else {
noh_arena_save(&temp); noh_arena_save(&temp);
show_usage(program_name, noh_arena_sprintf(&temp, "Unknown command: "Nsv_Fmt, Nsv_Arg(command))); show_usage(program_name, noh_arena_sprintf(&temp, "Unknown command: "Nsv_Fmt, Nsv_Arg(command)));
noh_arena_reset(&temp); noh_arena_reset(&temp);
return 1;
} }
} }