From: jxnshi Date: Mon, 6 Jan 2025 17:22:33 +0000 (+0100) Subject: add README.md X-Git-Url: https://jxnshi.xyz/repos?a=commitdiff_plain;h=65f20c0eeed917d158fd0971b1f755d5b87fb9ce;p=mesange.git add README.md --- diff --git a/README.md b/README.md new file mode 100644 index 0000000..e4d0c76 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# Mesange + +/!\ This is still in early development. /!\ + +Mesange is a federated messaging project focusing on privacy. + +I'm working on a server and CLI client implementation and I plan on making a GUI +client too, but you're obviously free to make your own servers and clients or +even branch the ones I made. diff --git a/client-cli/client-cli b/client-cli/client-cli index 268c675..d0fb4e1 100755 Binary files a/client-cli/client-cli and b/client-cli/client-cli differ diff --git a/client-cli/config.odin b/client-cli/config.odin index f9359eb..ac7e669 100644 --- a/client-cli/config.odin +++ b/client-cli/config.odin @@ -24,7 +24,7 @@ config_from_parsed :: proc(parsed_config: Config_Parsed) -> Config { selected_profile: Maybe(string) if parsed_selected_profile, ok := parsed_config.selected_profile.?; ok { - selected_profile, _ = strings.clone(parsed_selected_profile) + selected_profile = parsed_selected_profile } return { @@ -40,15 +40,15 @@ config_to_parsed :: proc(config: Config) -> Config_Parsed { config_load :: proc(app: ^App) -> (Config, Maybe(Config_Load_Error)) { config_path := fpath.join({ app.storage_path, "config.json" }, context.temp_allocator) - raw_config, config_read := os.read_entire_file_from_filename(config_path) + parsed_config: Config_Parsed if !config_read { return {}, .No_File_Present } - err := json.unmarshal(raw_config, &parsed_config, allocator = context.temp_allocator) + err := json.unmarshal(raw_config, &parsed_config) if err != nil { return {}, .Invalid_File @@ -58,8 +58,8 @@ config_load :: proc(app: ^App) -> (Config, Maybe(Config_Load_Error)) { } config_deinit :: proc(config: Config) { - if selected_profiles, ok := config.selected_profile.?; ok { - delete(selected_profiles) + if selected_profile, ok := config.selected_profile.?; ok { + delete(selected_profile) } } diff --git a/client-cli/main.odin b/client-cli/main.odin index eb6499a..92d3078 100644 --- a/client-cli/main.odin +++ b/client-cli/main.odin @@ -133,7 +133,7 @@ app_deinit :: proc(app: ^App) { nc.delwin(box_message) } - nc.endwin() + nc.endwin() delete(app.profiles_path) } @@ -189,9 +189,16 @@ app_set_box_message :: proc(app: ^App, lines: []string) { nc.wrefresh(box_message) - sync.mutex_lock(&app.mutex) - app.box_message = box_message - sync.mutex_unlock(&app.mutex) + { + sync.mutex_lock(&app.mutex) + defer sync.mutex_unlock(&app.mutex) + + if box_message, ok := app.box_message.?; ok { + nc.delwin(box_message) + } + + app.box_message = box_message + } } app_update_info_bar :: proc(app: ^App) { @@ -284,12 +291,14 @@ app_get_input :: proc(app: ^App, hidden := false, allow_empty := false, allocato buffer[buffer_len] = 0 output := string(buffer[:buffer_len + 1]) - if !hidden { - nc.wclear(app.input_window) + nc.wclear(app.input_window) + + if !hidden || (buffer_len != 0 && buffer[0] == ':') { nc.mvwprintw(app.input_window, 0, 0, strings.unsafe_string_to_cstring(output)) - nc.wrefresh(app.input_window) nc.wmove(app.input_window, 0, i32(cursor_pos)) } + + nc.wrefresh(app.input_window) } nc.curs_set(0) @@ -349,10 +358,12 @@ handle_state :: proc(app: ^App) { main :: proc() { home_path := os.get_env("HOME") + defer delete(home_path) storage_path := fpath.join({ home_path, "mesange" }) defer delete(storage_path) + // Setup logger. log_path := fpath.join({ storage_path, "log.txt" }, context.temp_allocator) if !os.exists(storage_path) { @@ -365,11 +376,6 @@ main :: proc() { context.logger = log.create_file_logger(log_file) defer log.destroy_file_logger(context.logger) - now := transmute(u64)time.now() - rng_state := rand.create(now) - - context.random_generator = rand.default_random_generator(&rng_state) - when ODIN_DEBUG { track: mem.Tracking_Allocator mem.tracking_allocator_init(&track, context.allocator) @@ -378,34 +384,48 @@ main :: proc() { defer { if len(track.allocation_map) > 0 { - log.errorf("%v allocations not freed:", len(track.allocation_map)) + log.errorf("%v allocation not freed.", len(track.allocation_map)) for _, entry in track.allocation_map { - log.errorf("- %v bytes at %v\n", entry.size, entry.location) + log.errorf("- %v bytes at %v", entry.size, entry.location) } } if len(track.bad_free_array) > 0 { - log.errof("%v incorrect frees:\n", len(track.bad_free_array)) + log.errorf("%v incorrect frees.", len(track.bad_free_array)) for entry in track.bad_free_array { - log.errorf("- %p at %v\n", entry.memory, entry.location) + log.errorf("- %p at %v", entry.memory, entry.location) } } mem.tracking_allocator_destroy(&track) } } + + { // Setup random generator. + now := transmute(u64)time.now() + rng_state := rand.create(now) + + context.random_generator = rand.default_random_generator(&rng_state) + } app := app_init(storage_path) defer app_deinit(&app) + // Setup state thread. handle_state_thread_context := runtime.default_context() handle_state_thread_context.logger = context.logger handle_state_thread_context.random_generator = context.random_generator + defer free_all(handle_state_thread_context.temp_allocator) + handle_state_thread := thread.create_and_start_with_poly_data(&app, handle_state, handle_state_thread_context) - defer thread.terminate(handle_state_thread, 0) + + defer { + thread.terminate(handle_state_thread, 0) + thread.destroy(handle_state_thread) + } for app.running { defer { diff --git a/client-cli/profile.odin b/client-cli/profile.odin index 956e059..abca948 100644 --- a/client-cli/profile.odin +++ b/client-cli/profile.odin @@ -41,11 +41,9 @@ profile_from_parsed :: proc(parsed_profile: Profile_Parsed, allocator := context private_key: ed25519.Private_Key _ = ed25519.private_key_set_bytes(&private_key, parsed_profile.private_key[:]) - host, err := strings.clone(parsed_profile.host, allocator) - return { private_key = private_key, - host = host, + host = parsed_profile.host, } } @@ -84,9 +82,9 @@ profile_load_from_name :: proc(name: string, app: ^App) -> (Profile, Maybe(Profi chacha_context: chacha.Context chacha.init_xchacha(&chacha_context, password_hash[:]) - iv := buffer[:chacha.XIV_SIZE] - tag := buffer[len(iv):][:chacha.TAG_SIZE] - ciphertext := buffer[len(iv) + len(tag):] + iv := profile_content[:chacha.XIV_SIZE] + tag := profile_content[len(iv):][:chacha.TAG_SIZE] + ciphertext := profile_content[len(iv) + len(tag):] if !chacha.open(&chacha_context, buffer[:len(ciphertext)], iv, {}, ciphertext, tag) { return {}, .Invalid_Password @@ -95,7 +93,7 @@ profile_load_from_name :: proc(name: string, app: ^App) -> (Profile, Maybe(Profi json_string := string(buffer[:len(ciphertext)]) parsed_profile: Profile_Parsed - err := json.unmarshal(transmute([]u8)json_string, &parsed_profile, allocator = context.temp_allocator) + err := json.unmarshal(transmute([]u8)json_string, &parsed_profile) if err != nil { return {}, .Invalid_File diff --git a/client-cli/state.odin b/client-cli/state.odin index 60f2cc3..67390bc 100644 --- a/client-cli/state.odin +++ b/client-cli/state.odin @@ -49,7 +49,12 @@ state_load_config :: proc(app: ^App) { } } - app.config = config + { + sync.mutex_lock(&app.mutex) + defer sync.mutex_unlock(&app.mutex) + + app.config = config + } app_set_state(app, .Load_Profile) } @@ -111,9 +116,14 @@ state_load_profile :: proc(app: ^App) { return } - app.profile = profile + { + sync.mutex_lock(&app.mutex) + defer sync.mutex_unlock(&app.mutex) - app_set_state(app, .Main) + app.profile = profile + } + + app_set_state(app, .Connect_To_Host) } state_invalid_profile :: proc(app: ^App) { @@ -187,7 +197,17 @@ state_ask_profile_password :: proc(app: ^App) { delete(app.profile_password) } - app.profile_password = app_get_input(app, true, true) + input := app_get_input(app, true, true) + + if err, ok := handle_command(app, input).?; ok { + if err != .Not_A_Command { + return + } + } else { + return + } + + app.profile_password = input app_set_state(app, .Load_Profile) } @@ -318,7 +338,17 @@ state_ask_profile_set_password :: proc(app: ^App) { }, ) - app.profile_password = app_get_input(app, true, true) + input := app_get_input(app, true, true) + + if err, ok := handle_command(app, input).?; ok { + if err != .Not_A_Command { + return + } + } else { + return + } + + app.profile_password = input app_set_state(app, .Ask_Profile_Confirm_Password) } @@ -333,6 +363,14 @@ state_ask_profile_confirm_password :: proc(app: ^App) { input := app_get_input(app, true, true, context.temp_allocator) + if err, ok := handle_command(app, input).?; ok { + if err != .Not_A_Command { + return + } + } else { + return + } + if input != app.profile_password { app_set_info_bar(app, "Passwords don't match.") return @@ -412,5 +450,14 @@ state_invalid_host :: proc(app: ^App) { } state_main :: proc(app: ^App) { - + input := app_get_input(app) + + if err, ok := handle_command(app, input).?; ok { + if err != .Not_A_Command { + return + } + } else { + delete(input) + return + } }