libgnunetchat

library for GNUnet Messenger
Log | Files | Refs | README | LICENSE

commit d544b20eebaf5482f2368baae9d05f284befcd92
parent bdce2d9f95eda1ede38939b1fb1ef65a30b43dc3
Author: Jacki <jacki@thejackimonster.de>
Date:   Mon, 19 Jan 2026 08:54:16 +0100

Merge branch 'dev/thejackimonster/messenger' into master

Diffstat:
MDoxyfile | 2+-
Minclude/gnunet/gnunet_chat_lib.h | 30++++++++++++++++++++++++++----
Mmeson.build | 2+-
Msrc/gnunet_chat_account.c | 13+++++++++----
Msrc/gnunet_chat_account.h | 12+++++++++---
Msrc/gnunet_chat_handle.c | 17+++++++++++++++--
Msrc/gnunet_chat_handle.h | 7+++++--
Msrc/gnunet_chat_handle_intern.c | 14++++++++++----
Msrc/gnunet_chat_lib.c | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/gnunet_chat_lib_intern.c | 37+++++++++++++++++++++++++++++++------
Mtests/attribute/test_gnunet_chat_attribute_check.c | 17++++++++++++-----
Mtests/attribute/test_gnunet_chat_attribute_share.c | 26++++++++++++++++++--------
Mtests/discourse/test_gnunet_chat_discourse_open.c | 17++++++++++++-----
Mtests/discourse/test_gnunet_chat_discourse_write.c | 11+++++++++--
Mtests/file/test_gnunet_chat_file_send.c | 11+++++++++--
Mtests/group/test_gnunet_chat_group_open.c | 15+++++++++++----
Mtests/handle/meson.build | 11++++++++++-
Mtests/handle/test_gnunet_chat_handle_connection.c | 13++++++++++---
Atests/handle/test_gnunet_chat_handle_no_secret.c | 130+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtests/handle/test_gnunet_chat_handle_rename.c | 11+++++++++--
Mtests/handle/test_gnunet_chat_handle_update.c | 11+++++++++--
Mtests/lobby/test_gnunet_chat_lobby_join.c | 13++++++++++---
Mtests/lobby/test_gnunet_chat_lobby_open.c | 13++++++++++---
Mtests/meson.build | 3++-
Mtests/message/test_gnunet_chat_message_text.c | 17++++++++++++-----
Mtests/tag/test_gnunet_chat_tag_contact.c | 11+++++++++--
Mtests/tag/test_gnunet_chat_tag_message.c | 11+++++++++--
Mtools/gnunet_chat_lib_uml.c | 18++++++++++++++++--
Mtools/gnunet_messenger_ping.c | 15++++++++++++++-
Mtools/gnunet_messenger_uml.c | 15++++++++++++++-
30 files changed, 528 insertions(+), 85 deletions(-)

diff --git a/Doxyfile b/Doxyfile @@ -48,7 +48,7 @@ PROJECT_NAME = libgnunetchat # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 0.6.0 +PROJECT_NUMBER = 0.7.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/include/gnunet/gnunet_chat_lib.h b/include/gnunet/gnunet_chat_lib.h @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2021--2025 GNUnet e.V. + Copyright (C) 2021--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -55,7 +55,7 @@ struct GNUNET_CONFIGURATION_Handle; * the #GNUNET_MESSENGER_VERSION of the GNUnet Messenger * service while the patch version is independent. */ -#define GNUNET_CHAT_VERSION 0x000000060001L +#define GNUNET_CHAT_VERSION 0x000000070000L #define GNUNET_CHAT_VERSION_MAJOR ((GNUNET_CHAT_VERSION >> 32L) & 0xFFFFL) #define GNUNET_CHAT_VERSION_MINOR ((GNUNET_CHAT_VERSION >> 16L) & 0xFFFFL) @@ -600,14 +600,20 @@ GNUNET_CHAT_find_account (const struct GNUNET_CHAT_Handle *handle, const char *name); /** - * Connects a chat <i>handle</i> to a selected chat <i>account</i>. + * Connects a chat <i>handle</i> to a selected chat <i>account</i> using + * an optional secret for that account to encrypt/decrypt local keys + * in storage for end-to-end encrypted messages. * * @param[in,out] handle Chat handle * @param[in,out] account Chat account + * @param[in] secret Chat account secret or NULL + * @param[in] secret_len Length of secret or zero */ void GNUNET_CHAT_connect (struct GNUNET_CHAT_Handle *handle, - struct GNUNET_CHAT_Account *account); + struct GNUNET_CHAT_Account *account, + const char *secret, + uint32_t secret_len); /** * Disconnects a chat <i>handle</i> from the current chat account. @@ -2027,6 +2033,22 @@ GNUNET_CHAT_discourse_iterate_contacts (struct GNUNET_CHAT_Discourse *discourse, GNUNET_CHAT_DiscourseContactCallback callback, void *cls); +/** + * Generates a chat account <i>secret</i> which can be used + * in case the user may not pick a secret manually. The length + * can be explicitly provided. + * + * The provided buffer to store the secret needs to have enough + * space in memory for at least the amount of requested characters. + * + * @param[out] secret Chat account secret + * @param[in] secret_len Length of secret + * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure + */ +enum GNUNET_GenericReturnValue +GNUNET_CHAT_generate_secret (char *secret, + uint32_t secret_len); + /**@}*/ #endif /* GNUNET_CHAT_LIB_H_ */ diff --git a/meson.build b/meson.build @@ -1,6 +1,6 @@ # # This file is part of GNUnet. -# Copyright (C) 2023--2025 GNUnet e.V. +# Copyright (C) 2023--2026 GNUnet e.V. # # GNUnet is free software: you can redistribute it and/or modify it # under the terms of the GNU Affero General Public License as published diff --git a/src/gnunet_chat_account.c b/src/gnunet_chat_account.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2022--2025 GNUnet e.V. + Copyright (C) 2022--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -29,14 +29,18 @@ #include <gnunet/gnunet_common.h> #include <gnunet/gnunet_identity_service.h> #include <gnunet/gnunet_messenger_service.h> +#include <gnunet/gnunet_util_lib.h> struct GNUNET_CHAT_Account* -account_create (const char *name) +account_create (struct GNUNET_CHAT_Handle *handle, + const char *name) { GNUNET_assert(name); struct GNUNET_CHAT_Account *account = GNUNET_new(struct GNUNET_CHAT_Account); + account->handle = handle; + account->ego = NULL; account->created = GNUNET_NO; @@ -50,12 +54,13 @@ account_create (const char *name) } struct GNUNET_CHAT_Account* -account_create_from_ego (struct GNUNET_IDENTITY_Ego *ego, +account_create_from_ego (struct GNUNET_CHAT_Handle *handle, + struct GNUNET_IDENTITY_Ego *ego, const char *name) { GNUNET_assert((ego) && (name)); - struct GNUNET_CHAT_Account *account = account_create(name); + struct GNUNET_CHAT_Account *account = account_create(handle, name); account->ego = ego; account->created = GNUNET_YES; diff --git a/src/gnunet_chat_account.h b/src/gnunet_chat_account.h @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2022--2025 GNUnet e.V. + Copyright (C) 2022--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -33,6 +33,8 @@ struct GNUNET_CHAT_Handle; struct GNUNET_CHAT_Account { + struct GNUNET_CHAT_Handle *handle; + struct GNUNET_IDENTITY_Ego *ego; enum GNUNET_GenericReturnValue created; @@ -44,22 +46,26 @@ struct GNUNET_CHAT_Account /** * Creates a chat account using a given <i>name</i>. * + * @param[in,out] handle Handle * @param[in] name Name * @return New chat account */ struct GNUNET_CHAT_Account* -account_create (const char *name); +account_create (struct GNUNET_CHAT_Handle *handle, + const char *name); /** * Creates a chat account using a given <i>ego</i> and * a matching <i>name</i>. * + * @param[in,out] handle Handle * @param[in] ego EGO * @param[in] name Name * @return New chat account */ struct GNUNET_CHAT_Account* -account_create_from_ego (struct GNUNET_IDENTITY_Ego *ego, +account_create_from_ego (struct GNUNET_CHAT_Handle *handle, + struct GNUNET_IDENTITY_Ego *ego, const char *name); /** diff --git a/src/gnunet_chat_handle.c b/src/gnunet_chat_handle.c @@ -98,6 +98,7 @@ handle_create_from_config (const struct GNUNET_CONFIGURATION_Handle* cfg, handle->own_contact = NULL; handle->next = NULL; + handle->next_secret = NULL; handle->current = NULL; handle->monitor = NULL; @@ -202,6 +203,17 @@ handle_destroy (struct GNUNET_CHAT_Handle *handle) if (handle->current) handle_disconnect(handle); + if (handle->next_secret) + { + GNUNET_CRYPTO_zero_keys( + handle->next_secret, + sizeof(*(handle->next_secret)) + ); + + GNUNET_free(handle->next_secret); + handle->next_secret = NULL; + } + GNUNET_CONTAINER_multihashmap_iterate( handle->files, it_destroy_handle_files, NULL ); @@ -331,7 +343,8 @@ handle_update_identity(struct GNUNET_CHAT_Handle *handle) void handle_connect (struct GNUNET_CHAT_Handle *handle, - struct GNUNET_CHAT_Account *account) + struct GNUNET_CHAT_Account *account, + const struct GNUNET_HashCode *secret) { GNUNET_assert( (handle) && (account) && @@ -366,7 +379,7 @@ handle_connect (struct GNUNET_CHAT_Handle *handle, const char *name = account_get_name(account); handle->messenger = GNUNET_MESSENGER_connect( - handle->cfg, name, key, + handle->cfg, name, key, secret, on_handle_message, handle ); diff --git a/src/gnunet_chat_handle.h b/src/gnunet_chat_handle.h @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2021--2025 GNUnet e.V. + Copyright (C) 2021--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -111,6 +111,7 @@ struct GNUNET_CHAT_Handle struct GNUNET_CHAT_Contact *own_contact; struct GNUNET_CHAT_Account *next; + struct GNUNET_HashCode *next_secret; struct GNUNET_CHAT_Account *current; struct GNUNET_NAMESTORE_ZoneMonitor *monitor; @@ -182,10 +183,12 @@ handle_destroy (struct GNUNET_CHAT_Handle *handle); * * @param[in,out] handle Chat handle * @param[in] account Chat account + * @param[in] secret Chat account secret or NULL */ void handle_connect (struct GNUNET_CHAT_Handle *handle, - struct GNUNET_CHAT_Account *account); + struct GNUNET_CHAT_Account *account, + const struct GNUNET_HashCode *secret); /** * Disconnects a given chat <i>handle</i> from its current diff --git a/src/gnunet_chat_handle_intern.c b/src/gnunet_chat_handle_intern.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2021--2025 GNUnet e.V. + Copyright (C) 2021--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -330,6 +330,9 @@ on_handle_gnunet_identity (void *cls, if ((name) && ((!(accounts->account->name)) || (0 != strcmp(accounts->account->name, name)))) { + const char *old_name = account_get_name(accounts->account); + char *name_buffer = old_name? GNUNET_strdup(old_name) : NULL; + util_set_name_field(name, &(accounts->account->name)); handle_send_internal_message( @@ -337,9 +340,12 @@ on_handle_gnunet_identity (void *cls, accounts->account, NULL, GNUNET_CHAT_FLAG_UPDATE_ACCOUNT, - NULL, + name_buffer, GNUNET_YES ); + + if (name_buffer) + GNUNET_free(name_buffer); } else if ((!name) && (!(accounts->op))) { @@ -371,7 +377,7 @@ skip_account: accounts = internal_accounts_create( handle, - account_create_from_ego(ego, name) + account_create_from_ego(handle, ego, name) ); send_refresh: @@ -401,7 +407,7 @@ cb_account_creation (void *cls, if ((!(accounts->account)) && (accounts->identifier)) accounts->account = account_create( - accounts->identifier + accounts->handle, accounts->identifier ); internal_accounts_stop_method(accounts); diff --git a/src/gnunet_chat_lib.c b/src/gnunet_chat_lib.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2021--2025 GNUnet e.V. + Copyright (C) 2021--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -184,7 +184,9 @@ GNUNET_CHAT_find_account (const struct GNUNET_CHAT_Handle *handle, void GNUNET_CHAT_connect (struct GNUNET_CHAT_Handle *handle, - struct GNUNET_CHAT_Account *account) + struct GNUNET_CHAT_Account *account, + const char *secret, + uint32_t secret_len) { GNUNET_CHAT_VERSION_ASSERT(); @@ -201,15 +203,35 @@ GNUNET_CHAT_connect (struct GNUNET_CHAT_Handle *handle, return; } + handle->next = account; + + if (handle->next_secret) + { + GNUNET_CRYPTO_zero_keys( + handle->next_secret, + sizeof(*(handle->next_secret)) + ); + + GNUNET_free(handle->next_secret); + } + + if ((secret) && (secret_len > 0)) + { + handle->next_secret = GNUNET_new(struct GNUNET_HashCode); + + if (handle->next_secret) + GNUNET_CRYPTO_hash(secret, secret_len, handle->next_secret); + } + else + handle->next_secret = NULL; + if (handle->current) { - handle->next = account; handle->connection = NULL; GNUNET_CHAT_disconnect(handle); return; } - handle->next = account; handle->connection = GNUNET_SCHEDULER_add_now( task_handle_connection, handle @@ -2330,6 +2352,8 @@ GNUNET_CHAT_message_get_text (const struct GNUNET_CHAT_Message *message) if (GNUNET_CHAT_FLAG_WARNING == message->flag) return message->warning; + else if (GNUNET_CHAT_FLAG_UPDATE_ACCOUNT == message->flag) + return message->warning; else if (GNUNET_CHAT_FLAG_ATTRIBUTES == message->flag) return message->attr; @@ -3287,3 +3311,61 @@ GNUNET_CHAT_discourse_iterate_contacts (struct GNUNET_CHAT_Discourse *discourse, return iterations; } + +enum GNUNET_GenericReturnValue +GNUNET_CHAT_generate_secret (char *secret, + uint32_t secret_len) +{ + GNUNET_CHAT_VERSION_ASSERT(); + + if (secret_len <= 0) + return GNUNET_SYSERR; + + const uint32_t requested = secret_len * 5 / 8 + 1; + const uint32_t size = ((requested*8) + (((requested*8) % 5) > 0 ? 5 - ((requested*8) % 5) : 0)) / 5; + + char *raw_secret = GNUNET_malloc(requested); + char *buf; + + if (!raw_secret) + return GNUNET_SYSERR; + + if (size > secret_len) + { + buf = GNUNET_malloc(size); + + if (!buf) + { + GNUNET_free(raw_secret); + return GNUNET_SYSERR; + } + } + else + buf = secret; + + GNUNET_CRYPTO_random_block( + GNUNET_CRYPTO_QUALITY_STRONG, + raw_secret, + requested + ); + + enum GNUNET_GenericReturnValue result; + result = GNUNET_STRINGS_data_to_string( + raw_secret, + requested, + buf, + size + ) == NULL? GNUNET_SYSERR : GNUNET_OK; + + GNUNET_CRYPTO_zero_keys(raw_secret, requested); + GNUNET_free(raw_secret); + + if (buf != secret) + { + GNUNET_memcpy(secret, buf, secret_len); + GNUNET_CRYPTO_zero_keys(buf, size); + GNUNET_free(buf); + } + + return result; +} diff --git a/src/gnunet_chat_lib_intern.c b/src/gnunet_chat_lib_intern.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2021--2025 GNUnet e.V. + Copyright (C) 2021--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -82,9 +82,37 @@ task_handle_connection (void *cls) return; struct GNUNET_CHAT_Account *account = handle->next; + struct GNUNET_HashCode local_secret; + const struct GNUNET_HashCode *secret; + + if (handle->next_secret) + { + GNUNET_memcpy( + &local_secret, + handle->next_secret, + sizeof(local_secret) + ); + + secret = &local_secret; + + GNUNET_CRYPTO_zero_keys( + handle->next_secret, + sizeof(*(handle->next_secret)) + ); + + GNUNET_free(handle->next_secret); + handle->next_secret = NULL; + } + else + secret = NULL; + handle->next = NULL; + handle_connect(handle, account, secret); - handle_connect(handle, account); + GNUNET_CRYPTO_zero_keys( + &local_secret, + sizeof(local_secret) + ); } void @@ -100,10 +128,7 @@ task_handle_disconnection (void *cls) if (! handle->next) return; - struct GNUNET_CHAT_Account *account = handle->next; - handle->next = NULL; - - handle_connect(handle, account); + task_handle_connection(cls); } void diff --git a/tests/attribute/test_gnunet_chat_attribute_check.c b/tests/attribute/test_gnunet_chat_attribute_check.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2024 GNUnet e.V. + Copyright (C) 2024--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -24,9 +24,10 @@ #include "test_gnunet_chat.h" -#define TEST_CHECK_ID "gnunet_chat_attribute_check" -#define TEST_CHECK_NAME "test_attribute_check_name" -#define TEST_CHECK_VALUE "test_attribute_check_value" +#define TEST_CHECK_ID "gnunet_chat_attribute_check" +#define TEST_CHECK_NAME "test_attribute_check_name" +#define TEST_CHECK_VALUE "test_attribute_check_value" +#define TEST_CHECK_SECRET "test_secret_attribute_check" enum GNUNET_GenericReturnValue on_gnunet_chat_attribute_check_attr(void *cls, @@ -84,7 +85,13 @@ on_gnunet_chat_attribute_check_msg(void *cls, ck_assert_ptr_nonnull(account); - GNUNET_CHAT_connect(handle, account); + GNUNET_CHAT_connect( + handle, + account, + TEST_CHECK_SECRET, + strlen(TEST_CHECK_SECRET) + ); + attribute_stage = 1; } diff --git a/tests/attribute/test_gnunet_chat_attribute_share.c b/tests/attribute/test_gnunet_chat_attribute_share.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2024 GNUnet e.V. + Copyright (C) 2024--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -24,11 +24,13 @@ #include "test_gnunet_chat.h" -#define TEST_SHARE_ID_A "gnunet_chat_attribute_share_a" -#define TEST_SHARE_ID_B "gnunet_chat_attribute_share_b" -#define TEST_SHARE_GROUP "test_attribute_share_group" -#define TEST_SHARE_NAME "test_attribute_share_name" -#define TEST_SHARE_VALUE "test_attribute_share_value" +#define TEST_SHARE_ID_A "gnunet_chat_attribute_share_a" +#define TEST_SHARE_ID_B "gnunet_chat_attribute_share_b" +#define TEST_SHARE_GROUP "test_attribute_share_group" +#define TEST_SHARE_NAME "test_attribute_share_name" +#define TEST_SHARE_VALUE "test_attribute_share_value" +#define TEST_SHARE_SECRET_A "test_secret_attribute_share_a" +#define TEST_SHARE_SECRET_B "test_secret_attribute_share_b" enum GNUNET_GenericReturnValue on_gnunet_chat_attribute_share_attr(void *cls, @@ -102,7 +104,13 @@ on_gnunet_chat_attribute_share_msg(void *cls, ck_assert_ptr_nonnull(account); - GNUNET_CHAT_connect(handle, account); + GNUNET_CHAT_connect( + handle, + account, + TEST_SHARE_SECRET_A, + strlen(TEST_SHARE_SECRET_A) + ); + share_stage = 1; } @@ -184,7 +192,9 @@ on_gnunet_chat_attribute_share_msg(void *cls, GNUNET_CHAT_connect( handle, - GNUNET_CHAT_find_account(handle, TEST_SHARE_ID_B) + GNUNET_CHAT_find_account(handle, TEST_SHARE_ID_B), + TEST_SHARE_SECRET_B, + strlen(TEST_SHARE_SECRET_B) ); share_stage = 3; diff --git a/tests/discourse/test_gnunet_chat_discourse_open.c b/tests/discourse/test_gnunet_chat_discourse_open.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2024 GNUnet e.V. + Copyright (C) 2024--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -24,9 +24,10 @@ #include "test_gnunet_chat.h" -#define TEST_OPEN_ID "gnunet_chat_discourse_open" -#define TEST_OPEN_GROUP "gnunet_chat_discourse_open_group" -#define TEST_OPEN_DISCOURSE "gnunet_chat_discourse_open_discourse" +#define TEST_OPEN_ID "gnunet_chat_discourse_open" +#define TEST_OPEN_GROUP "gnunet_chat_discourse_open_group" +#define TEST_OPEN_DISCOURSE "gnunet_chat_discourse_open_discourse" +#define TEST_OPEN_SECRET "test_secret_discourse_open" enum GNUNET_GenericReturnValue on_gnunet_chat_discourse_open_msg(void *cls, @@ -66,7 +67,13 @@ on_gnunet_chat_discourse_open_msg(void *cls, ck_assert_ptr_nonnull(account); - GNUNET_CHAT_connect(handle, account); + GNUNET_CHAT_connect( + handle, + account, + TEST_OPEN_SECRET, + strlen(TEST_OPEN_SECRET) + ); + discourse_stage = 1; } diff --git a/tests/discourse/test_gnunet_chat_discourse_write.c b/tests/discourse/test_gnunet_chat_discourse_write.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2024 GNUnet e.V. + Copyright (C) 2024--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -27,6 +27,7 @@ #define TEST_WRITE_ID "gnunet_chat_discourse_write" #define TEST_WRITE_GROUP "gnunet_chat_discourse_write_group" #define TEST_WRITE_DISCOURSE "gnunet_chat_discourse_write_discourse" +#define TEST_WRITE_SECRET "test_secret_discourse_write" enum GNUNET_GenericReturnValue on_gnunet_chat_discourse_write_msg(void *cls, @@ -66,7 +67,13 @@ on_gnunet_chat_discourse_write_msg(void *cls, ck_assert_ptr_nonnull(account); - GNUNET_CHAT_connect(handle, account); + GNUNET_CHAT_connect( + handle, + account, + TEST_WRITE_SECRET, + strlen(TEST_WRITE_SECRET) + ); + discourse_stage = 1; } diff --git a/tests/file/test_gnunet_chat_file_send.c b/tests/file/test_gnunet_chat_file_send.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2022--2024 GNUnet e.V. + Copyright (C) 2022--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -28,6 +28,7 @@ #define TEST_SEND_TEXT "gnunet_chat_file_deleted" #define TEST_SEND_FILENAME "gnunet_chat_file_send_name" #define TEST_SEND_GROUP "gnunet_chat_file_send_group" +#define TEST_SEND_SECRET "test_secret_file_send" void on_gnunet_chat_file_send_upload(void *cls, @@ -107,7 +108,13 @@ on_gnunet_chat_file_send_msg(void *cls, ck_assert_ptr_nonnull(account); - GNUNET_CHAT_connect(handle, account); + GNUNET_CHAT_connect( + handle, + account, + TEST_SEND_SECRET, + strlen(TEST_SEND_SECRET) + ); + file_stage = 1; } diff --git a/tests/group/test_gnunet_chat_group_open.c b/tests/group/test_gnunet_chat_group_open.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2024 GNUnet e.V. + Copyright (C) 2024--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -24,8 +24,9 @@ #include "test_gnunet_chat.h" -#define TEST_OPEN_ID "gnunet_chat_group_open" -#define TEST_OPEN_GROUP "gnunet_chat_group_open_group" +#define TEST_OPEN_ID "gnunet_chat_group_open" +#define TEST_OPEN_GROUP "gnunet_chat_group_open_group" +#define TEST_OPEN_SECRET "test_secret_group_open" enum GNUNET_GenericReturnValue on_gnunet_chat_group_open_msg(void *cls, @@ -64,7 +65,13 @@ on_gnunet_chat_group_open_msg(void *cls, ck_assert_ptr_nonnull(account); - GNUNET_CHAT_connect(handle, account); + GNUNET_CHAT_connect( + handle, + account, + TEST_OPEN_SECRET, + strlen(TEST_OPEN_SECRET) + ); + group_stage = 1; } diff --git a/tests/handle/meson.build b/tests/handle/meson.build @@ -1,6 +1,6 @@ # # This file is part of GNUnet. -# Copyright (C) 2024 GNUnet e.V. +# Copyright (C) 2024--2026 GNUnet e.V. # # GNUnet is free software: you can redistribute it and/or modify it # under the terms of the GNU Affero General Public License as published @@ -45,6 +45,15 @@ test_gnunet_chat_handle_init = executable( extra_files: test_header, ) +test_gnunet_chat_handle_no_secret = executable( + 'test_gnunet_chat_handle_no_secret.test', + 'test_gnunet_chat_handle_no_secret.c', + dependencies: test_deps, + link_with: gnunetchat_lib, + include_directories: tests_include, + extra_files: test_header, +) + test_gnunet_chat_handle_rename = executable( 'test_gnunet_chat_handle_rename.test', 'test_gnunet_chat_handle_rename.c', diff --git a/tests/handle/test_gnunet_chat_handle_connection.c b/tests/handle/test_gnunet_chat_handle_connection.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2021--2024 GNUnet e.V. + Copyright (C) 2021--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -24,7 +24,8 @@ #include "test_gnunet_chat.h" -#define TEST_CONNECTION_ID "gnunet_chat_handle_connection" +#define TEST_CONNECTION_ID "gnunet_chat_handle_connection" +#define TEST_CONNECTION_SECRET "test_secret_handle_connection" enum GNUNET_GenericReturnValue on_gnunet_chat_handle_connection_msg(void *cls, @@ -63,7 +64,13 @@ on_gnunet_chat_handle_connection_msg(void *cls, ck_assert_ptr_nonnull(account); - GNUNET_CHAT_connect(handle, account); + GNUNET_CHAT_connect( + handle, + account, + TEST_CONNECTION_SECRET, + strlen(TEST_CONNECTION_SECRET) + ); + connection_stage = 1; } diff --git a/tests/handle/test_gnunet_chat_handle_no_secret.c b/tests/handle/test_gnunet_chat_handle_no_secret.c @@ -0,0 +1,130 @@ +/* + This file is part of GNUnet. + Copyright (C) 2026 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file test_gnunet_chat_handle_no_secret.c + */ + +#include "test_gnunet_chat.h" + +#define TEST_NO_SECRET_ID "gnunet_chat_handle_no_secret" + +enum GNUNET_GenericReturnValue +on_gnunet_chat_handle_no_secret_msg(void *cls, + struct GNUNET_CHAT_Context *context, + struct GNUNET_CHAT_Message *message) +{ + static unsigned int secret_stage = 0; + + struct GNUNET_CHAT_Handle *handle = *( + (struct GNUNET_CHAT_Handle**) cls + ); + + ck_assert_ptr_nonnull(handle); + ck_assert_ptr_null(context); + ck_assert_ptr_nonnull(message); + + struct GNUNET_CHAT_Account *connected; + struct GNUNET_CHAT_Account *account; + const char *name; + + connected = GNUNET_CHAT_get_connected(handle); + account = GNUNET_CHAT_message_get_account(message); + + switch (GNUNET_CHAT_message_get_kind(message)) + { + case GNUNET_CHAT_KIND_WARNING: + ck_abort_msg("%s\n", GNUNET_CHAT_message_get_text(message)); + break; + case GNUNET_CHAT_KIND_REFRESH: + ck_assert_ptr_null(context); + ck_assert_ptr_null(account); + + if (secret_stage == 0) + { + account = GNUNET_CHAT_find_account(handle, TEST_NO_SECRET_ID); + + ck_assert_ptr_nonnull(account); + + GNUNET_CHAT_connect( + handle, + account, + NULL, + 0 + ); + + secret_stage = 1; + } + + break; + case GNUNET_CHAT_KIND_LOGIN: + ck_assert_ptr_nonnull(connected); + ck_assert_ptr_nonnull(account); + ck_assert_ptr_eq(connected, account); + ck_assert_uint_eq(secret_stage, 1); + + name = GNUNET_CHAT_account_get_name(account); + + ck_assert_ptr_nonnull(name); + ck_assert_str_eq(name, TEST_NO_SECRET_ID); + + GNUNET_CHAT_disconnect(handle); + secret_stage = 2; + break; + case GNUNET_CHAT_KIND_LOGOUT: + ck_assert_ptr_nonnull(connected); + ck_assert_ptr_nonnull(account); + ck_assert_ptr_eq(connected, account); + ck_assert_uint_eq(secret_stage, 2); + + name = GNUNET_CHAT_account_get_name(account); + + ck_assert_ptr_nonnull(name); + ck_assert_str_eq(name, TEST_NO_SECRET_ID); + + GNUNET_CHAT_stop(handle); + secret_stage = 3; + break; + default: + ck_abort(); + break; + } + + return GNUNET_YES; +} + +REQUIRE_GNUNET_CHAT_ACCOUNT(gnunet_chat_handle_connection, TEST_NO_SECRET_ID) + +void +call_gnunet_chat_handle_connection(const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + static struct GNUNET_CHAT_Handle *handle = NULL; + handle = GNUNET_CHAT_start(cfg, on_gnunet_chat_handle_no_secret_msg, &handle); + + ck_assert_ptr_nonnull(handle); +} + +CREATE_GNUNET_TEST(test_gnunet_chat_handle_connection, gnunet_chat_handle_connection) + +START_SUITE(handle_suite, "Handle (no secret)") +ADD_TEST_TO_SUITE(test_gnunet_chat_handle_connection, "Connect/Disconnect") +END_SUITE + +MAIN_SUITE(handle_suite, CK_NORMAL) diff --git a/tests/handle/test_gnunet_chat_handle_rename.c b/tests/handle/test_gnunet_chat_handle_rename.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2021--2024 GNUnet e.V. + Copyright (C) 2021--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -26,6 +26,7 @@ #define TEST_RENAME_ID_A "gnunet_chat_handle_rename_a" #define TEST_RENAME_ID_B "gnunet_chat_handle_rename_b" +#define TEST_RENAME_SECRET "test_secret_rename" enum GNUNET_GenericReturnValue on_gnunet_chat_handle_rename_msg(void *cls, @@ -92,7 +93,13 @@ on_gnunet_chat_handle_rename_msg(void *cls, ck_assert_ptr_nonnull(account); ck_assert_uint_eq(rename_stage, 0); - GNUNET_CHAT_connect(handle, account); + GNUNET_CHAT_connect( + handle, + account, + TEST_RENAME_SECRET, + strlen(TEST_RENAME_SECRET) + ); + rename_stage = 1; break; case GNUNET_CHAT_KIND_DELETED_ACCOUNT: diff --git a/tests/handle/test_gnunet_chat_handle_update.c b/tests/handle/test_gnunet_chat_handle_update.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2021--2024 GNUnet e.V. + Copyright (C) 2021--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -25,6 +25,7 @@ #include "test_gnunet_chat.h" #define TEST_UPDATE_ID "gnunet_chat_handle_update" +#define TEST_UPDATE_SECRET "test_secret_handle_update" enum GNUNET_GenericReturnValue on_gnunet_chat_handle_update_msg(void *cls, @@ -62,8 +63,14 @@ on_gnunet_chat_handle_update_msg(void *cls, ck_assert_ptr_nonnull(account); + GNUNET_CHAT_connect( + handle, + account, + TEST_UPDATE_SECRET, + strlen(TEST_UPDATE_SECRET) + ); + update_stage = 1; - GNUNET_CHAT_connect(handle, account); } break; diff --git a/tests/lobby/test_gnunet_chat_lobby_join.c b/tests/lobby/test_gnunet_chat_lobby_join.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2022--2024 GNUnet e.V. + Copyright (C) 2022--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -24,7 +24,8 @@ #include "test_gnunet_chat.h" -#define TEST_JOIN_ID "gnunet_chat_lobby_join" +#define TEST_JOIN_ID "gnunet_chat_lobby_join" +#define TEST_JOIN_SECRET "test_secret_lobby_join" void on_gnunet_chat_lobby_join_open(void *cls, @@ -71,7 +72,13 @@ on_gnunet_chat_lobby_join_msg(void *cls, ck_assert_ptr_nonnull(account); - GNUNET_CHAT_connect(handle, account); + GNUNET_CHAT_connect( + handle, + account, + TEST_JOIN_SECRET, + strlen(TEST_JOIN_SECRET) + ); + lobby_stage = 1; } diff --git a/tests/lobby/test_gnunet_chat_lobby_open.c b/tests/lobby/test_gnunet_chat_lobby_open.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2022--2024 GNUnet e.V. + Copyright (C) 2022--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -24,7 +24,8 @@ #include "test_gnunet_chat.h" -#define TEST_OPEN_ID "gnunet_chat_lobby_open" +#define TEST_OPEN_ID "gnunet_chat_lobby_open" +#define TEST_OPEN_SECRET "test_secret_lobby_open" enum GNUNET_GenericReturnValue on_gnunet_chat_lobby_open_msg(void *cls, @@ -61,7 +62,13 @@ on_gnunet_chat_lobby_open_msg(void *cls, ck_assert_ptr_nonnull(account); - GNUNET_CHAT_connect(handle, account); + GNUNET_CHAT_connect( + handle, + account, + TEST_OPEN_SECRET, + strlen(TEST_OPEN_SECRET) + ); + lobby_stage = 1; } diff --git a/tests/meson.build b/tests/meson.build @@ -1,6 +1,6 @@ # # This file is part of GNUnet. -# Copyright (C) 2023--2024 GNUnet e.V. +# Copyright (C) 2023--2026 GNUnet e.V. # # GNUnet is free software: you can redistribute it and/or modify it # under the terms of the GNU Affero General Public License as published @@ -36,6 +36,7 @@ subdir('tag') test('test_gnunet_chat_handle_init', test_gnunet_chat_handle_init, depends: gnunetchat_lib, is_parallel : false) test('test_gnunet_chat_handle_accounts', test_gnunet_chat_handle_accounts, depends: gnunetchat_lib, is_parallel : false) +test('test_gnunet_chat_handle_no_secret', test_gnunet_chat_handle_no_secret, depends: gnunetchat_lib, is_parallel : false) test('test_gnunet_chat_handle_connection', test_gnunet_chat_handle_connection, depends: gnunetchat_lib, is_parallel : false) test('test_gnunet_chat_handle_update', test_gnunet_chat_handle_update, depends: gnunetchat_lib, is_parallel : false) test('test_gnunet_chat_handle_rename', test_gnunet_chat_handle_rename, depends: gnunetchat_lib, is_parallel : false) diff --git a/tests/message/test_gnunet_chat_message_text.c b/tests/message/test_gnunet_chat_message_text.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2023--2024 GNUnet e.V. + Copyright (C) 2023--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -24,9 +24,10 @@ #include "test_gnunet_chat.h" -#define TEST_TEXT_ID "gnunet_chat_message_text" -#define TEST_TEXT_GROUP "gnunet_chat_message_text_group" -#define TEST_TEXT_MSG "test_text_message" +#define TEST_TEXT_ID "gnunet_chat_message_text" +#define TEST_TEXT_GROUP "gnunet_chat_message_text_group" +#define TEST_TEXT_MSG "test_text_message" +#define TEST_TEXT_SECRET "test_secret_text" enum GNUNET_GenericReturnValue on_gnunet_chat_message_text_msg(void *cls, @@ -63,7 +64,13 @@ on_gnunet_chat_message_text_msg(void *cls, ck_assert_ptr_nonnull(account); - GNUNET_CHAT_connect(handle, account); + GNUNET_CHAT_connect( + handle, + account, + TEST_TEXT_SECRET, + strlen(TEST_TEXT_SECRET) + ); + text_stage = 1; } diff --git a/tests/tag/test_gnunet_chat_tag_contact.c b/tests/tag/test_gnunet_chat_tag_contact.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2024 GNUnet e.V. + Copyright (C) 2024--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -27,6 +27,7 @@ #define TEST_TAG_ID "gnunet_chat_tag_contact" #define TEST_TAG_GROUP "gnunet_chat_tag_contact_group" #define TEST_TAG_CONTACT_TAG "test_contact_tag_tagged" +#define TEST_TAG_SECRET "test_secret_tag_contact" enum GNUNET_GenericReturnValue on_gnunet_chat_tag_contact_msg(void *cls, @@ -65,7 +66,13 @@ on_gnunet_chat_tag_contact_msg(void *cls, ck_assert_ptr_nonnull(account); - GNUNET_CHAT_connect(handle, account); + GNUNET_CHAT_connect( + handle, + account, + TEST_TAG_SECRET, + strlen(TEST_TAG_SECRET) + ); + tag_stage = 1; } diff --git a/tests/tag/test_gnunet_chat_tag_message.c b/tests/tag/test_gnunet_chat_tag_message.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2024 GNUnet e.V. + Copyright (C) 2024--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -29,6 +29,7 @@ #define TEST_TAG_GROUP "gnunet_chat_tag_message_group" #define TEST_TAG_MSG "test_message_tag" #define TEST_TAG_MSG_TAG "test_message_tag_tagged" +#define TEST_TAG_SECRET "test_secret_tag_message" enum GNUNET_GenericReturnValue on_gnunet_chat_tag_message_msg(void *cls, @@ -65,7 +66,13 @@ on_gnunet_chat_tag_message_msg(void *cls, ck_assert_ptr_nonnull(account); - GNUNET_CHAT_connect(handle, account); + GNUNET_CHAT_connect( + handle, + account, + TEST_TAG_SECRET, + strlen(TEST_TAG_SECRET) + ); + tag_stage = 1; } diff --git a/tools/gnunet_chat_lib_uml.c b/tools/gnunet_chat_lib_uml.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2024 GNUnet e.V. + Copyright (C) 2024--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -35,6 +35,7 @@ struct GNUNET_CHAT_Tool char *account_name; char *group_name; char *contact_name; + char *secret; bool quit; }; @@ -49,7 +50,13 @@ accounts_iterate (void *cls, if (0 == strcmp(tool->account_name, account_name)) { - GNUNET_CHAT_connect(tool->handle, account); + GNUNET_CHAT_connect( + tool->handle, + account, + tool->secret, + tool->secret? strlen(tool->secret) : 0 + ); + return GNUNET_NO; } @@ -258,6 +265,13 @@ main (int argc, "name of group chat to read messages from", &(tool.group_name) ), + GNUNET_GETOPT_option_string( + 'S', + "secret", + "SECRET", + "storage secret for local keys", + &(tool.secret) + ), GNUNET_GETOPT_OPTION_END }; diff --git a/tools/gnunet_messenger_ping.c b/tools/gnunet_messenger_ping.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2025 GNUnet e.V. + Copyright (C) 2025--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -61,6 +61,7 @@ struct GNUNET_MESSENGER_PingTool char *ego_name; char *room_name; + char *secret_value; uint count; uint timeout; uint delay; @@ -477,10 +478,15 @@ ego_lookup (void *cls, const struct GNUNET_CRYPTO_BlindablePrivateKey *key; key = ego? GNUNET_IDENTITY_ego_get_private_key(ego) : NULL; + struct GNUNET_HashCode secret; + if (tool->secret_value) + GNUNET_CRYPTO_hash_from_string (tool->secret_value, &secret); + tool->handle = GNUNET_MESSENGER_connect( tool->cfg, tool->ego_name, key, + tool->secret_value? &secret : NULL, message_callback, tool ); @@ -633,6 +639,13 @@ main (int argc, "name of room to read messages from", &(tool.room_name) ), + GNUNET_GETOPT_option_string( + 'S', + "secret", + "SECRET", + "secret for local key storage", + &(tool.secret_value) + ), GNUNET_GETOPT_option_uint( 'c', "count", diff --git a/tools/gnunet_messenger_uml.c b/tools/gnunet_messenger_uml.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2024--2025 GNUnet e.V. + Copyright (C) 2024--2026 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -62,6 +62,7 @@ struct GNUNET_MESSENGER_Tool char *ego_name; char *room_name; + char *secret_value; int public_room; int ignore_targets; int ignore_epochs; @@ -401,10 +402,15 @@ ego_lookup (void *cls, const struct GNUNET_CRYPTO_BlindablePrivateKey *key; key = ego? GNUNET_IDENTITY_ego_get_private_key(ego) : NULL; + struct GNUNET_HashCode secret; + if (tool->secret_value) + GNUNET_CRYPTO_hash_from_string (tool->secret_value, &secret); + tool->handle = GNUNET_MESSENGER_connect( tool->cfg, tool->ego_name, key, + tool->secret_value? &secret : NULL, message_callback, tool ); @@ -491,6 +497,13 @@ main (int argc, "name of room to read messages from", &(tool.room_name) ), + GNUNET_GETOPT_option_string( + 'S', + "secret", + "SECRET", + "secret for local key storage", + &(tool.secret_value) + ), GNUNET_GETOPT_option_flag( 'P', "public",