From 740ff7a14fa49ef45e9a5e4f0672b7e9bdcc27d2 Mon Sep 17 00:00:00 2001 From: Paolo Stivanin Date: Tue, 12 Dec 2023 10:33:25 +0100 Subject: [PATCH 1/4] Fix handling of base32 string this fixes #328 --- CMakeLists.txt | 2 +- README.md | 2 +- src/parse-data.c | 94 +++++++++++++++++++++++------------------------- 3 files changed, 46 insertions(+), 52 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 022c7c9..878b0fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,7 @@ endif() find_package(PkgConfig REQUIRED) find_package(Protobuf 3.6.0 REQUIRED) find_package(Gcrypt 1.8.0 REQUIRED) -pkg_check_modules(COTP REQUIRED cotp>=2.0.0) +pkg_check_modules(COTP REQUIRED cotp>=2.2.0) pkg_check_modules(PNG REQUIRED libpng>=1.6.30) pkg_check_modules(JANSSON REQUIRED jansson>=2.12) pkg_check_modules(ZBAR REQUIRED zbar>=0.20) diff --git a/README.md b/README.md index ce65405..5c5d729 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Highly secure and easy to use GTK+ software for two-factor authentication that s | jansson | 2.12 | | libgcrypt | 1.8.0 | | libpng | 1.6.30 | -| [libcotp](https://github.com/paolostivanin/libcotp) | 2.0.0 | +| [libcotp](https://github.com/paolostivanin/libcotp) | 2.2.0 | | zbar | 0.20 | | protobuf-c | 1.3.0 | | protobuf | 3.6.0 | diff --git a/src/parse-data.c b/src/parse-data.c index 0e030a4..7a8d6e1 100644 --- a/src/parse-data.c +++ b/src/parse-data.c @@ -10,27 +10,26 @@ #include "common/common.h" -static gboolean is_input_valid (GtkWidget *dialog, - const gchar *acc_label, - const gchar *acc_iss, - const gchar *secret, - const gchar *digits, - const gchar *period, - gboolean period_active, - const gchar *counter, - gboolean counter_active); - -static gboolean str_is_only_num_or_alpha (const gchar *string); - -static gboolean str_is_only_num (const gchar *string); - -static json_t *get_json_obj (Widgets *widgets, - const gchar *acc_label, - const gchar *acc_iss, - const gchar *acc_key, - const gchar *digits, - const gchar *period, - const gchar *counter); +static gboolean is_input_valid (GtkWidget *dialog, + const gchar *acc_label, + const gchar *acc_iss, + const gchar *secret, + const gchar *digits, + const gchar *period, + gboolean period_active, + const gchar *counter, + gboolean counter_active); + +static gboolean is_str_valid (const gchar *string, + gboolean (*validation_func)(gunichar)); + +static json_t *get_json_obj (Widgets *widgets, + const gchar *acc_label, + const gchar *acc_iss, + const gchar *acc_key, + const gchar *digits, + const gchar *period, + const gchar *counter); gboolean @@ -39,20 +38,20 @@ parse_user_data (Widgets *widgets, { json_t *obj; - const gchar *acc_label = gtk_entry_get_text (GTK_ENTRY (widgets->label_entry)); - const gchar *acc_iss = gtk_entry_get_text (GTK_ENTRY (widgets->iss_entry)); - const gchar *acc_key = gtk_entry_get_text (GTK_ENTRY (widgets->sec_entry)); - const gchar *digits = gtk_entry_get_text (GTK_ENTRY (widgets->digits_entry)); - const gchar *period = gtk_entry_get_text (GTK_ENTRY (widgets->period_entry)); - const gchar *counter = gtk_entry_get_text (GTK_ENTRY (widgets->counter_entry)); + const gchar *acc_label = gtk_entry_get_text (GTK_ENTRY(widgets->label_entry)); + const gchar *acc_iss = gtk_entry_get_text (GTK_ENTRY(widgets->iss_entry)); + const gchar *acc_key = gtk_entry_get_text (GTK_ENTRY(widgets->sec_entry)); + const gchar *digits = gtk_entry_get_text (GTK_ENTRY(widgets->digits_entry)); + const gchar *period = gtk_entry_get_text (GTK_ENTRY(widgets->period_entry)); + const gchar *counter = gtk_entry_get_text (GTK_ENTRY(widgets->counter_entry)); gboolean period_active = gtk_widget_get_sensitive (widgets->period_entry); gboolean counter_active = gtk_widget_get_sensitive (widgets->counter_entry); gchar *acc_key_trimmed = g_trim_whitespace (acc_key); if (is_input_valid (widgets->dialog, acc_label, acc_iss, acc_key_trimmed, digits, period, period_active, counter, counter_active)) { obj = get_json_obj (widgets, acc_label, acc_iss, acc_key_trimmed, digits, period, counter); guint32 hash = json_object_get_hash (obj); - if (g_slist_find_custom (db_data->objects_hash, GUINT_TO_POINTER (hash), check_duplicate) == NULL) { - db_data->objects_hash = g_slist_append (db_data->objects_hash, g_memdupX (&hash, sizeof (guint))); + if (g_slist_find_custom (db_data->objects_hash, GUINT_TO_POINTER(hash), check_duplicate) == NULL) { + db_data->objects_hash = g_slist_append (db_data->objects_hash, g_memdupX(&hash, sizeof (guint))); db_data->data_to_add = g_slist_append (db_data->data_to_add, obj); } else { g_print ("[INFO] Duplicate element not added\n"); @@ -87,28 +86,28 @@ is_input_valid (GtkWidget *dialog, g_free (msg); return FALSE; } - if (!str_is_only_num_or_alpha (secret)) { - gchar *msg = g_strconcat ("Secret can contain only characters from the english alphabet and digits. Entry with label '", + if (!is_string_valid_b32 (secret)) { + gchar *msg = g_strconcat ("Secret is not a valid base32 encoded string. Entry with label '", acc_label, "' will not be added.", NULL); show_message_dialog (dialog, msg, GTK_MESSAGE_ERROR); g_free (msg); return FALSE; } - if (!str_is_only_num (digits) || g_ascii_strtoll (digits, NULL, 10) < 4 || g_ascii_strtoll (digits, NULL, 10) > 10) { + if (!is_str_valid (digits, g_unichar_isdigit) || g_ascii_strtoll (digits, NULL, 10) < 4 || g_ascii_strtoll (digits, NULL, 10) > 10) { gchar *msg = g_strconcat ("The digits entry should contain only digits and the value should be between 4 and 10 inclusive.\n" "Entry with label '", acc_label, "' will not be added.", NULL); show_message_dialog (dialog, msg, GTK_MESSAGE_ERROR); g_free (msg); return FALSE; } - if (period_active && (!str_is_only_num (period) || g_ascii_strtoll (period, NULL, 10) < 10 || g_ascii_strtoll (period, NULL, 10) > 120)) { + if (period_active && (!is_str_valid (period, g_unichar_isdigit) || g_ascii_strtoll (period, NULL, 10) < 10 || g_ascii_strtoll (period, NULL, 10) > 120)) { gchar *msg = g_strconcat ("The period entry should contain only digits and the value should be between 10 and 120 (inclusive).\n" "Entry with label '", acc_label, "' will not be added.", NULL); show_message_dialog (dialog, msg, GTK_MESSAGE_ERROR); g_free (msg); return FALSE; } - if (counter_active && (!str_is_only_num (counter) || g_ascii_strtoll (counter, NULL, 10) < 1 || g_ascii_strtoll (counter, NULL, 10) == G_MAXINT64)) { + if (counter_active && (!is_str_valid (counter, g_unichar_isdigit) || g_ascii_strtoll (counter, NULL, 10) < 1 || g_ascii_strtoll (counter, NULL, 10) == G_MAXINT64)) { gchar *msg = g_strconcat ("The counter entry should contain only digits and the value should be between 1 and G_MAXINT64-1 (inclusive).\n" "Entry with label '", acc_label, "' will not be added.", NULL); show_message_dialog (dialog, msg, GTK_MESSAGE_ERROR); @@ -121,27 +120,22 @@ is_input_valid (GtkWidget *dialog, static gboolean -str_is_only_num_or_alpha (const gchar *string) +is_str_valid (const gchar *string, + gboolean (*validation_func)(gunichar)) { - size_t s_len = g_utf8_strlen (string, -1); - for (gint i = 0; i < s_len; i++) { - if (!g_ascii_isalnum (string[i])) { - return FALSE; - } + if (string == NULL || !g_utf8_validate (string, -1, NULL)) { + return FALSE; } - return TRUE; -} + gsize s_len = g_utf8_strlen (string, -1); -static gboolean -str_is_only_num (const gchar *string) -{ - size_t s_len = g_utf8_strlen (string, -1); - for (gint i = 0; i < s_len; i++) { - if (!g_ascii_isdigit (string[i])) { + for (gsize i = 0; i < s_len; i++) { + gunichar character = g_utf8_get_char (g_utf8_offset_to_pointer (string, (glong)i)); + if (!validation_func (character)) { return FALSE; } } + return TRUE; } @@ -155,8 +149,8 @@ get_json_obj (Widgets *widgets, const gchar *period, const gchar *counter) { - gchar *type = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (widgets->otp_cb)); - gchar *algo = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (widgets->algo_cb)); + gchar *type = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT(widgets->otp_cb)); + gchar *algo = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT(widgets->algo_cb)); gint digits_int = (gint)g_ascii_strtoll (digits, NULL, 10); gint period_int = (gint)g_ascii_strtoll (period, NULL, 10); gint64 ctr = g_ascii_strtoll (counter, NULL, 10); From 6701848a97f00aecda08f6ea6b82b9b189b5c860 Mon Sep 17 00:00:00 2001 From: Paolo Stivanin Date: Wed, 20 Dec 2023 15:05:41 +0100 Subject: [PATCH 2/4] Update CMakeLists.txt and README.md --- CMakeLists.txt | 4 ++-- README.md | 2 +- src/parse-data.c | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 878b0fa..5f153bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.16) -project(OTPClient VERSION "3.2.2" LANGUAGES "C") +project(OTPClient VERSION "3.3.0" LANGUAGES "C") include(GNUInstallDirs) configure_file("src/common/version.h.in" "version.h") @@ -45,7 +45,7 @@ endif() find_package(PkgConfig REQUIRED) find_package(Protobuf 3.6.0 REQUIRED) find_package(Gcrypt 1.8.0 REQUIRED) -pkg_check_modules(COTP REQUIRED cotp>=2.2.0) +pkg_check_modules(COTP REQUIRED cotp>=3.0.0) pkg_check_modules(PNG REQUIRED libpng>=1.6.30) pkg_check_modules(JANSSON REQUIRED jansson>=2.12) pkg_check_modules(ZBAR REQUIRED zbar>=0.20) diff --git a/README.md b/README.md index 5c5d729..9e1a2d3 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Highly secure and easy to use GTK+ software for two-factor authentication that s | jansson | 2.12 | | libgcrypt | 1.8.0 | | libpng | 1.6.30 | -| [libcotp](https://github.com/paolostivanin/libcotp) | 2.2.0 | +| [libcotp](https://github.com/paolostivanin/libcotp) | 3.0.0 | | zbar | 0.20 | | protobuf-c | 1.3.0 | | protobuf | 3.6.0 | diff --git a/src/parse-data.c b/src/parse-data.c index 7a8d6e1..f95ef13 100644 --- a/src/parse-data.c +++ b/src/parse-data.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "db-misc.h" #include "manual-add-cb.h" #include "gquarks.h" From 7ccce8c9964688f275c898289bf94d2ada98038c Mon Sep 17 00:00:00 2001 From: Paolo Stivanin Date: Wed, 20 Dec 2023 15:29:41 +0100 Subject: [PATCH 3/4] Set brackground to red when delete mode is entered this fixes #323 --- src/app.c | 22 ++++++++++++++++------ src/data.h | 3 ++- src/ui/otpclient.ui | 1 + 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/app.c b/src/app.c index afd2ffb..2b34897 100644 --- a/src/app.c +++ b/src/app.c @@ -672,13 +672,21 @@ del_data_cb (GtkToggleButton *btn, { AppData *app_data = (AppData *)user_data; - GtkStyleContext *gsc = gtk_widget_get_style_context (GTK_WIDGET(btn)); + GtkStyleContext *gsc_btn = gtk_widget_get_style_context (GTK_WIDGET(btn)); + GtkStyleContext *gsc_tv = gtk_widget_get_style_context (GTK_WIDGET(app_data->tree_view)); + GtkTreeSelection *tree_selection = gtk_tree_view_get_selection (app_data->tree_view); if (gtk_toggle_button_get_active (btn)) { - app_data->css_provider = gtk_css_provider_new (); - gtk_css_provider_load_from_data (app_data->css_provider, "#delbtn { background: #ff0033; }", -1, NULL); - gtk_style_context_add_provider (gsc, GTK_STYLE_PROVIDER(app_data->css_provider), GTK_STYLE_PROVIDER_PRIORITY_USER); + app_data->delbtn_css_provider = gtk_css_provider_new (); + app_data->tv_css_provider = gtk_css_provider_new (); + + gtk_css_provider_load_from_data (app_data->delbtn_css_provider, "#delbtn { background: #970000; }", -1, NULL); + gtk_css_provider_load_from_data (app_data->tv_css_provider, "#tv { background: #970000; }", -1, NULL); + + gtk_style_context_add_provider (gsc_btn, GTK_STYLE_PROVIDER(app_data->delbtn_css_provider), GTK_STYLE_PROVIDER_PRIORITY_USER); + gtk_style_context_add_provider (gsc_tv, GTK_STYLE_PROVIDER(app_data->tv_css_provider), GTK_STYLE_PROVIDER_PRIORITY_USER); + const gchar *msg = _("You just entered the deletion mode. You can now click on the row(s) you'd like to delete.\n" "Please note that once a row has been deleted, it's impossible to recover the associated data."); @@ -693,8 +701,10 @@ del_data_cb (GtkToggleButton *btn, gtk_toggle_button_set_active (btn, FALSE); } } else { - gtk_style_context_remove_provider (gsc, GTK_STYLE_PROVIDER(app_data->css_provider)); - g_object_unref (app_data->css_provider); + gtk_style_context_remove_provider (gsc_btn, GTK_STYLE_PROVIDER(app_data->delbtn_css_provider)); + gtk_style_context_remove_provider (gsc_tv, GTK_STYLE_PROVIDER(app_data->tv_css_provider)); + g_object_unref (app_data->delbtn_css_provider); + g_object_unref (app_data->tv_css_provider); g_signal_handlers_disconnect_by_func (app_data->tree_view, delete_rows_cb, app_data); g_signal_connect (app_data->tree_view, "row-activated", G_CALLBACK(row_selected_cb), app_data); } diff --git a/src/data.h b/src/data.h index 8616a65..6d3d33a 100644 --- a/src/data.h +++ b/src/data.h @@ -42,7 +42,8 @@ typedef struct app_data_t { gboolean auto_lock; gint inactivity_timeout; - GtkCssProvider *css_provider; + GtkCssProvider *delbtn_css_provider; + GtkCssProvider *tv_css_provider; GNotification *notification; diff --git a/src/ui/otpclient.ui b/src/ui/otpclient.ui index 942d696..8786598 100644 --- a/src/ui/otpclient.ui +++ b/src/ui/otpclient.ui @@ -2612,6 +2612,7 @@ but not the number of digits and/or the period/counter. etched-in + tv True True True From 3cde29d1396adf85ed86991812e4191432c34c29 Mon Sep 17 00:00:00 2001 From: Paolo Stivanin Date: Mon, 8 Jan 2024 12:11:29 +0100 Subject: [PATCH 4/4] Update appdata and ui --- data/com.github.paolostivanin.OTPClient.appdata.xml | 9 +++++++++ src/ui/otpclient.ui | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/data/com.github.paolostivanin.OTPClient.appdata.xml b/data/com.github.paolostivanin.OTPClient.appdata.xml index ce3e392..55d9fb6 100644 --- a/data/com.github.paolostivanin.OTPClient.appdata.xml +++ b/data/com.github.paolostivanin.OTPClient.appdata.xml @@ -87,6 +87,15 @@ + + +

OTPClient 3.3.0 brings the following changes:

+
    +
  • NEW: set background to red when delete mode is entered (#323)
  • +
  • FIX: handling of base32 string (#328)
  • +
+
+

OTPClient 3.2.1 fixes a couple of issues.

diff --git a/src/ui/otpclient.ui b/src/ui/otpclient.ui index 8786598..246812a 100644 --- a/src/ui/otpclient.ui +++ b/src/ui/otpclient.ui @@ -1437,7 +1437,7 @@ but not the number of digits and/or the period/counter. 255 False dialog-password-symbolic - Secret + Must be an uppercase base32 string. It may contain spaces. Secret password