messenger-gtk

Gtk+3 graphical user interfaces for GNUnet Messenger
Log | Files | Refs | Submodules | README | LICENSE

secret.c (8002B)


      1 /*
      2    This file is part of GNUnet.
      3    Copyright (C) 2026 GNUnet e.V.
      4 
      5    GNUnet is free software: you can redistribute it and/or modify it
      6    under the terms of the GNU Affero General Public License as published
      7    by the Free Software Foundation, either version 3 of the License,
      8    or (at your option) any later version.
      9 
     10    GNUnet is distributed in the hope that it will be useful, but
     11    WITHOUT ANY WARRANTY; without even the implied warranty of
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13    Affero General Public License for more details.
     14 
     15    You should have received a copy of the GNU Affero General Public License
     16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 
     18    SPDX-License-Identifier: AGPL3.0-or-later
     19  */
     20 /*
     21  * @author Tobias Frisch
     22  * @file secret.c
     23  */
     24 
     25 #include "secret.h"
     26 
     27 #include <glib-2.0/glib.h>
     28 #include <gnunet/gnunet_chat_lib.h>
     29 #include <gnunet/gnunet_common.h>
     30 #include <string.h>
     31 #include <libsecret/secret.h>
     32 #include <gnunet/gnunet_util_lib.h>
     33 
     34 #ifndef MESSENGER_APPLICATION_ID
     35 #define SECRET_APP_ID "org.gnunet.Messenger"
     36 #else
     37 #define SECRET_APP_ID MESSENGER_APPLICATION_ID
     38 #endif
     39 
     40 const SecretSchema *
     41 _secret_schema(void)
     42 {
     43   static const SecretSchema schema = {
     44     "org.gnunet.chat.AccountSecret", SECRET_SCHEMA_NONE,
     45     {
     46       { "name", SECRET_SCHEMA_ATTRIBUTE_STRING },
     47       { "app_id", SECRET_SCHEMA_ATTRIBUTE_STRING },
     48       { "NULL", 0 },
     49     }
     50   };
     51   return &schema;
     52 }
     53 
     54 char*
     55 _secret_description(const char *name)
     56 {
     57   char *desc;
     58 
     59   GNUNET_asprintf(
     60     &desc,
     61     "GNUnet Messenger account secret for identity %s",
     62     name
     63   );
     64 
     65   return desc;
     66 }
     67 
     68 MESSENGER_SecretOperation*
     69 _secret_operation_new(MESSENGER_Application *application,
     70                       MESSENGER_SecretCallback callback,
     71                       gpointer user_data)
     72 {
     73   g_assert(application);
     74 
     75   GCancellable *cancellable = g_cancellable_new();
     76 
     77   if (!cancellable)
     78     return NULL;
     79 
     80   MESSENGER_SecretOperation* op = g_malloc(sizeof(MESSENGER_SecretOperation));
     81 
     82   op->application = application;
     83 
     84   op->callback = callback;
     85   op->cancellable = cancellable;
     86   op->user_data = user_data;
     87   op->ownership = FALSE;
     88 
     89   op->secret = NULL;
     90   op->secret_len = 0;
     91 
     92   application->secrets = g_list_append(
     93     application->secrets, 
     94     op
     95   );
     96 
     97   return op;
     98 }
     99 
    100 void
    101 _secret_operation_callback(MESSENGER_SecretOperation *op,
    102                            gboolean success,
    103                            gboolean error)
    104 {
    105   g_assert(op);
    106 
    107   if (op->callback)
    108   {
    109     op->callback(
    110       op->application,
    111       op->secret,
    112       op->secret_len,
    113       success,
    114       error,
    115       op->user_data
    116     );
    117   }
    118 
    119   secret_operation_drop(op);
    120 }
    121 
    122 void
    123 _secret_lookup_callback(GNUNET_UNUSED GObject *source_object,
    124                         GAsyncResult *result,
    125                         gpointer data)
    126 {
    127   GError *error = NULL;
    128   gchar *password;
    129 
    130   MESSENGER_SecretOperation *op = data;
    131 
    132   password = secret_password_lookup_finish(result, &error);
    133 
    134   if (error)
    135     _secret_operation_callback(op, FALSE, TRUE);
    136   else if (password)
    137   {
    138     op->secret = GNUNET_strdup(password);
    139     op->secret_len = g_utf8_strlen(password, -1);
    140 
    141     _secret_operation_callback(op, TRUE, FALSE);
    142 
    143     secret_password_free(password);
    144   }
    145   else
    146     _secret_operation_callback(op, FALSE, FALSE);
    147 }
    148 
    149 MESSENGER_SecretOperation*
    150 secret_operation_lookup(MESSENGER_Application *application,
    151                         const char *name,
    152                         MESSENGER_SecretCallback callback,
    153                         gpointer user_data)
    154 {
    155   g_assert((application) && (name));
    156 
    157   MESSENGER_SecretOperation *op = _secret_operation_new(
    158     application,
    159     callback,
    160     user_data
    161   );
    162 
    163   if (!op)
    164     return NULL;
    165   
    166   secret_password_lookup(
    167     _secret_schema(),
    168     op->cancellable,
    169     &_secret_lookup_callback,
    170     op,
    171     "name", name,
    172     "app_id", SECRET_APP_ID,
    173     NULL
    174   );
    175 
    176   return op;
    177 }
    178 
    179 void
    180 _secret_store_callback(GNUNET_UNUSED GObject *source_object,
    181                        GAsyncResult *result,
    182                        gpointer data)
    183 {
    184   GError *error = NULL;
    185   gboolean success;
    186 
    187   MESSENGER_SecretOperation *op = data;
    188 
    189   success = secret_password_store_finish(result, &error);
    190 
    191   if (error)
    192     _secret_operation_callback(op, FALSE, TRUE);
    193   else
    194     _secret_operation_callback(op, success, FALSE);
    195 }
    196 
    197 MESSENGER_SecretOperation*
    198 secret_operation_store(MESSENGER_Application *application,
    199                        const char *name,
    200                        const char *secret,
    201                        uint32_t secret_len,
    202                        MESSENGER_SecretCallback callback,
    203                        gpointer user_data)
    204 {
    205   g_assert((application) && (name) && (secret));
    206 
    207   if (strlen(secret) != secret_len)
    208     return NULL;
    209 
    210   MESSENGER_SecretOperation *op = _secret_operation_new(
    211     application,
    212     callback,
    213     user_data
    214   );
    215 
    216   if (!op)
    217     return NULL;
    218 
    219   op->secret = GNUNET_strndup(secret, secret_len + 1);
    220   op->secret_len = secret_len;
    221 
    222   secret_password_store(
    223     _secret_schema(),
    224     SECRET_COLLECTION_DEFAULT,
    225     _secret_description(name),
    226     secret,
    227     op->cancellable,
    228     &_secret_store_callback,
    229     op,
    230     "name", name,
    231     "app_id", SECRET_APP_ID,
    232     NULL
    233   );
    234 
    235   return op;
    236 }
    237 
    238 MESSENGER_SecretOperation*
    239 secret_operation_generate(MESSENGER_Application *application,
    240                           const char *name,
    241                           MESSENGER_SecretCallback callback,
    242                           gpointer user_data)
    243 {
    244   char new_secret [65];
    245   uint32_t secret_len;
    246 
    247   g_assert((application) && (name));
    248 
    249   secret_len = 64;
    250 
    251   if (GNUNET_OK != GNUNET_CHAT_generate_secret(new_secret, secret_len))
    252     return NULL;
    253 
    254   new_secret[secret_len] = '\0';
    255 
    256   MESSENGER_SecretOperation *op = secret_operation_store(
    257     application,
    258     name,
    259     new_secret,
    260     secret_len,
    261     callback,
    262     user_data
    263   );
    264 
    265   secret_password_wipe(new_secret);
    266   return op;
    267 }
    268 
    269 void
    270 _secret_delete_callback(GNUNET_UNUSED GObject *source_object,
    271                         GAsyncResult *result,
    272                         gpointer data)
    273 {
    274   GError *error = NULL;
    275   gboolean success;
    276 
    277   MESSENGER_SecretOperation *op = data;
    278 
    279   success = secret_password_clear_finish(result, &error);
    280 
    281   if (error)
    282     _secret_operation_callback(op, FALSE, TRUE);
    283   else
    284     _secret_operation_callback(op, success, FALSE);
    285 }
    286 
    287 MESSENGER_SecretOperation*
    288 secret_operation_delete(MESSENGER_Application *application,
    289                         const char *name,
    290                         MESSENGER_SecretCallback callback,
    291                         gpointer user_data)
    292 {
    293   g_assert((application) && (name));
    294 
    295   MESSENGER_SecretOperation *op = _secret_operation_new(
    296     application,
    297     callback,
    298     user_data
    299   );
    300 
    301   if (!op)
    302     return NULL;
    303 
    304   secret_password_clear(
    305     _secret_schema(),
    306     op->cancellable,
    307     &_secret_delete_callback,
    308     op,
    309     "name", name,
    310     "app_id", SECRET_APP_ID,
    311     NULL
    312   );
    313 
    314   return op;
    315 }
    316 
    317 void
    318 secret_operation_own_user_data(MESSENGER_SecretOperation *op)
    319 {
    320   g_assert(op);
    321 
    322   op->ownership = TRUE;
    323 }
    324 
    325 void
    326 secret_operation_cancel(MESSENGER_SecretOperation *op)
    327 {
    328   g_assert(op);
    329 
    330   if (!op->cancellable)
    331     return;
    332   
    333   if (!g_cancellable_is_cancelled(op->cancellable))
    334     g_cancellable_cancel(op->cancellable);
    335 }
    336 
    337 void
    338 secret_operation_cleanup(MESSENGER_SecretOperation *op)
    339 {
    340   g_assert(op);
    341 
    342   if (op->secret)
    343   {
    344     secret_password_wipe(op->secret);
    345     GNUNET_free(op->secret);
    346   }
    347 
    348   if ((op->ownership) && (op->user_data))
    349   {
    350     g_free(op->user_data);
    351     op->user_data = NULL;
    352   }
    353 
    354   if (!op->cancellable)
    355     return;
    356   
    357   g_object_unref(op->cancellable);
    358   op->cancellable = NULL;
    359 }
    360 
    361 void
    362 secret_operation_drop(MESSENGER_SecretOperation *op)
    363 {
    364   g_assert(op);
    365 
    366   if (op->application->secrets)
    367     op->application->secrets = g_list_remove(
    368       op->application->secrets,
    369       op
    370     );
    371   
    372   secret_operation_destroy(op);
    373 }
    374 
    375 void
    376 secret_operation_destroy(MESSENGER_SecretOperation *op)
    377 {
    378   g_assert(op);
    379 
    380   secret_operation_cleanup(op);
    381   g_free(op);
    382 }