Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package otpclient for openSUSE:Factory 
checked in at 2022-07-06 15:41:51
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/otpclient (Old)
 and      /work/SRC/openSUSE:Factory/.otpclient.new.1548 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "otpclient"

Wed Jul  6 15:41:51 2022 rev:16 rq:986970 version:2.6.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/otpclient/otpclient.changes      2022-07-02 
15:34:47.639040417 +0200
+++ /work/SRC/openSUSE:Factory/.otpclient.new.1548/otpclient.changes    
2022-07-06 15:42:02.982521661 +0200
@@ -1,0 +2,13 @@
+Wed Jul  6 06:53:14 UTC 2022 - Paolo Stivanin <i...@paolostivanin.com>
+
+- Update to 2.6.2:
+  * Add info message about the new secret service behavior.
+
+-------------------------------------------------------------------
+Tue Jul  5 13:43:05 UTC 2022 - Paolo Stivanin <i...@paolostivanin.com>
+
+- Update to 2.6.1:
+  * Add ability to import google migration QR also via webcam.
+  * Avoid double free on error while importing encrypted aegis.
+
+-------------------------------------------------------------------

Old:
----
  v2.6.0.tar.gz
  v2.6.0.tar.gz.asc

New:
----
  v2.6.2.tar.gz
  v2.6.2.tar.gz.asc

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ otpclient.spec ++++++
--- /var/tmp/diff_new_pack.PXlFTY/_old  2022-07-06 15:42:04.666524142 +0200
+++ /var/tmp/diff_new_pack.PXlFTY/_new  2022-07-06 15:42:04.670524149 +0200
@@ -18,7 +18,7 @@
 
 %define uclname OTPClient
 Name:           otpclient
-Version:        2.6.0
+Version:        2.6.2
 Release:        0
 Summary:        Simple GTK+ client for managing TOTP and HOTP
 License:        GPL-3.0-or-later

++++++ v2.6.0.tar.gz -> v2.6.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-2.6.0/CMakeLists.txt 
new/OTPClient-2.6.2/CMakeLists.txt
--- old/OTPClient-2.6.0/CMakeLists.txt  2022-07-01 14:43:11.000000000 +0200
+++ new/OTPClient-2.6.2/CMakeLists.txt  2022-07-06 08:51:34.000000000 +0200
@@ -1,5 +1,5 @@
 cmake_minimum_required(VERSION 3.10)
-project(OTPClient VERSION "2.6.0" LANGUAGES "C")
+project(OTPClient VERSION "2.6.2" LANGUAGES "C")
 
 configure_file("src/common/version.h.in" "version.h")
 include_directories(${PROJECT_BINARY_DIR})
@@ -127,6 +127,7 @@
         src/common/exports.h
         src/parse-uri.h
         src/common/get-providers-data.h
+        src/google-migration.pb-c.h
         src/secret-schema.h)
 
 set(CLI_SOURCE_FILES
@@ -141,19 +142,29 @@
         src/common/andotp.c
         src/common/aegis.c
         src/common/freeotp.c
-        src/secret-schema.c)
+        src/secret-schema.c
+        src/google-migration.pb-c.c)
 
 if(BUILD_GUI AND BUILD_CLI)
         list(APPEND CLI_SOURCE_FILES
                 src/treeview.c
                 src/liststore-misc.c
                 src/gui-common.c
+                src/add-common.c
+                src/imports.c
+                src/authplus.c
+                src/password-cb.c
+                src/get-builder.c
                 src/message-dialogs.c)
 
         list(APPEND CLI_HEADER_FILES
                 src/treeview.h
                 src/liststore-misc.h
                 src/gui-common.h
+                src/add-common.h
+                src/imports.h
+                src/password-cb.h
+                src/get-builder.h
                 src/message-dialogs.h)
 endif()
 
@@ -191,6 +202,7 @@
 if(BUILD_CLI)
         include_directories(${GTK3_INCLUDE_DIRS}
                 ${GCRYPT_INCLUDE_DIRS}
+                ${BASEENCODE_INCLUDE_DIRS}
                 ${COTP_INCLUDE_DIRS}
                 ${BASEENCODE_INCLUDE_DIRS}
                 ${JANSSON_INCLUDE_DIRS}
@@ -212,6 +224,7 @@
                 ${GLIB2_LIBRARIES}
                 ${GIO_LIBRARIES}
                 ${GCRYPT_LIBRARIES}
+                ${BASEENCODE_LIBRARIES}
                 ${COTP_LIBRARIES}
                 ${JANSSON_LIBRARIES}
                 ${UUID_LIBRARIES}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-2.6.0/README.md 
new/OTPClient-2.6.2/README.md
--- old/OTPClient-2.6.0/README.md       2022-07-01 14:43:11.000000000 +0200
+++ new/OTPClient-2.6.2/README.md       2022-07-06 08:51:34.000000000 +0200
@@ -10,19 +10,23 @@
 |----------------------------------------------------|-------------|
 | GTK+                                               | 3.20        |
 | Glib                                               | 2.48.0      |
-| jansson                                            | 2.6.0       |
+| jansson                                            | 2.100       |
 | libgcrypt                                          | 1.6.0       |
 | libzip                                             | 1.0.0       |
 | libpng                                             | 1.2.0       |
-| [libcotp](https://github.com/paolostivanin/libcotp) | 1.2.1       |-|
+| [libbaseencode](https://github.com/paolostivanin/libbaseencode) | 1.0.12     
|
+| [libcotp](https://github.com/paolostivanin/libcotp) | 1.2.1      |
 | zbar                                               | 0.20        |
 | protobuf-c                                         | 1.30        |
 | protobuf                                           | 3.6         |
+| uuid                                               | 2.34        |
+| libsecret                                          | 0.20        |
 
 :warning: Please note that the memlock value should be `>= 4 MB`. Any value 
less than this may cause issues when dealing with tens of tokens (especially 
when importing from third parties backups).
 See this [wiki 
section](https://github.com/paolostivanin/OTPClient/wiki/Secure-Memory-Limitations)
 for info on how to check the current value and set, if needed, a higher one.
 
 ## Features
+- integration with the OS' secret service provider via libsecret
 - support both TOTP and HOTP
 - support setting custom digits (between 4 and 10 inclusive)
 - support setting a custom period (between 10 and 120 seconds inclusive)
@@ -32,6 +36,7 @@
 - import and export encrypted/plain [andOTP](https://github.com/flocke/andOTP) 
backup
 - import and export encrypted/plain 
[Aegis](https://github.com/beemdevelopment/Aegis) backup
 - import and export plain 
[FreeOTPPlus](https://github.com/helloworld1/FreeOTPPlus) backup (key URI 
format only)
+- import of Google's migration QR codes
 - local database is encrypted using AES256-GCM
   - key is derived using PBKDF2 with SHA512 and 100k iterations
   - decrypted file is never saved (and hopefully never swapped) to disk. While 
the app is running, the decrypted content resides in a "secure memory" buffer 
allocated by Gcrypt
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/OTPClient-2.6.0/data/com.github.paolostivanin.OTPClient.appdata.xml 
new/OTPClient-2.6.2/data/com.github.paolostivanin.OTPClient.appdata.xml
--- old/OTPClient-2.6.0/data/com.github.paolostivanin.OTPClient.appdata.xml     
2022-07-01 14:43:11.000000000 +0200
+++ new/OTPClient-2.6.2/data/com.github.paolostivanin.OTPClient.appdata.xml     
2022-07-06 08:51:34.000000000 +0200
@@ -83,6 +83,23 @@
   </content_rating>
 
   <releases>
+    <release version="2.6.2" date="2022-07-06">
+      <description>
+        <p>OTPClient 2.6.2 add an upgrade message</p>
+        <ul>
+          <li>warn user about new secret service behavior</li>
+        </ul>
+      </description>
+    </release>
+    <release version="2.6.1" date="2022-07-05">
+      <description>
+        <p>OTPClient 2.6.1 some fixes and a new feature</p>
+        <ul>
+          <li>add ability to import Google migration QR also via webcam</li>
+          <li>fix double free in case of error</li>
+        </ul>
+      </description>
+    </release>
     <release version="2.6.0" date="2022-07-01">
       <description>
         <p>OTPClient 2.6.0 brings lots of new features</p>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-2.6.0/src/add-from-qr.c 
new/OTPClient-2.6.2/src/add-from-qr.c
--- old/OTPClient-2.6.0/src/add-from-qr.c       2022-07-01 14:43:11.000000000 
+0200
+++ new/OTPClient-2.6.2/src/add-from-qr.c       2022-07-06 08:51:34.000000000 
+0200
@@ -1,13 +1,14 @@
 #include <gtk/gtk.h>
 #include <gcrypt.h>
 #include <glib/gstdio.h>
-#include <baseencode.h>
 #include "imports.h"
 #include "qrcode-parser.h"
 #include "message-dialogs.h"
 #include "add-common.h"
 #include "get-builder.h"
-#include "google-migration.pb-c.h"
+#include "common/common.h"
+#include "gui-common.h"
+
 
 typedef struct gtimeout_data_t {
     GtkWidget *diag;
@@ -32,8 +33,6 @@
                                           GdkPixbuf     *pixbuf,
                                           gpointer       user_data);
 
-static GSList  *decode_migration_data    (const gchar   *uri);
-
 
 void
 add_qr_from_file (GSimpleAction *simple,
@@ -42,7 +41,7 @@
 {
     const gchar *action_name = g_action_get_name (G_ACTION(simple));
     gboolean google_migration;
-    (g_strcmp0 (action_name, GOOGLE_MIGRATION_ACTION_NAME) == 0) ? 
google_migration = TRUE : FALSE;
+    (g_strcmp0 (action_name, GOOGLE_MIGRATION_FILE_ACTION_NAME) == 0) ? 
google_migration = TRUE : FALSE;
 
     AppData *app_data = (AppData *)user_data;
 
@@ -136,34 +135,12 @@
         return;
     }
 
-    GSList *otpauth_decoded_uris = NULL;
-    if (google_migration == TRUE) {
-        gint failed = 0;
-        otpauth_decoded_uris = decode_migration_data (otpauth_uri);
-        for (gint i = 0; i < g_slist_length (otpauth_decoded_uris); i++) {
-            gchar *uri = g_slist_nth_data (otpauth_decoded_uris, i);
-            err_msg = add_data_to_db (uri, app_data);
-            if (err_msg != NULL) {
-                failed++;
-                g_free (err_msg);
-            }
-        }
-        if (failed > 0) {
-            GString *e_msg = g_string_new (NULL);
-            g_string_printf (e_msg, "Failed to add all OTPs. Only %u out of %u 
were successfully added.", g_slist_length (otpauth_decoded_uris) - failed,
-                             g_slist_length (otpauth_decoded_uris));
-            show_message_dialog (app_data->main_window, e_msg->str, 
GTK_MESSAGE_ERROR);
-            g_string_free (e_msg, TRUE);
-        }
-        g_slist_free_full (otpauth_decoded_uris, g_free);
+    err_msg = parse_uris_migration (app_data, otpauth_uri, google_migration);
+    if (err_msg != NULL) {
+        show_message_dialog (app_data->main_window, err_msg, 
GTK_MESSAGE_ERROR);
+        g_free (err_msg);
     } else {
-        err_msg = add_data_to_db (otpauth_uri, app_data);
-        if (err_msg != NULL) {
-            show_message_dialog (app_data->main_window, err_msg, 
GTK_MESSAGE_ERROR);
-            g_free (err_msg);
-        } else {
-            show_message_dialog (app_data->main_window, "QRCode successfully 
imported.", GTK_MESSAGE_INFO);
-        }
+        show_message_dialog (app_data->main_window, "QRCode successfully 
scanned", GTK_MESSAGE_INFO);
     }
 
     gcry_free (otpauth_uri);
@@ -225,78 +202,4 @@
     } else {
         show_message_dialog (app_data->main_window, "Couldn't get QR code 
image from clipboard", GTK_MESSAGE_ERROR);
     }
-}
-
-
-static GSList *
-decode_migration_data (const gchar *encoded_uri)
-{
-    const gchar *encoded_uri_copy = encoded_uri;
-    if (g_ascii_strncasecmp (encoded_uri_copy, 
"otpauth-migration://offline?data=", 33) != 0) {
-        return NULL;
-    }
-    encoded_uri_copy += 33;
-    gsize out_len;
-    guchar *data = g_base64_decode (g_uri_unescape_string ((encoded_uri_copy), 
NULL), &out_len);
-
-    GSList *uris = NULL;
-    gchar *uri = NULL;
-    MigrationPayload *msg = migration_payload__unpack (NULL, out_len, data);
-    for (gint i = 0; i < msg->n_otp_parameters; i++) {
-        uri = g_strconcat ("otpauth://", NULL);
-        if (msg->otp_parameters[i]->type == 1) {
-            uri = g_strconcat (uri, "hotp/", NULL);
-        } else if (msg->otp_parameters[i]->type == 2) {
-            uri = g_strconcat (uri, "totp/", NULL);
-        } else {
-            g_printerr ("OTP type not recognized, skipping %s\n", 
msg->otp_parameters[i]->name);
-            goto end;
-        }
-
-        uri = g_strconcat (uri, msg->otp_parameters[i]->name, "?", NULL);
-
-        if (msg->otp_parameters[i]->algorithm == 1) {
-            uri = g_strconcat (uri, "algorithm=SHA1&", NULL);
-        } else if (msg->otp_parameters[i]->algorithm == 2) {
-            uri = g_strconcat (uri, "algorithm=SHA256&", NULL);
-        } else if (msg->otp_parameters[i]->algorithm == 3) {
-            uri = g_strconcat (uri, "algorithm=SHA512&", NULL);
-        } else {
-            g_printerr ("Algorithm type not supported, skipping %s\n", 
msg->otp_parameters[i]->name);
-            goto end;
-        }
-
-        if (msg->otp_parameters[i]->digits == 1) {
-            uri = g_strconcat (uri, "digits=6&", NULL);
-        } else if (msg->otp_parameters[i]->digits == 2) {
-            uri = g_strconcat (uri, "digits=8&", NULL);
-        } else {
-            g_printerr ("Algorithm type not supported, skipping %s\n", 
msg->otp_parameters[i]->name);
-            goto end;
-        }
-
-        if (msg->otp_parameters[i]->issuer != NULL) {
-            uri = g_strconcat (uri, "issuer=", msg->otp_parameters[i]->issuer, 
"&", NULL);
-        }
-
-        if (msg->otp_parameters[i]->type == 1) {
-            uri = g_strconcat (uri, "counter=", 
msg->otp_parameters[i]->counter, "&", NULL);
-        }
-
-        baseencode_error_t b_err;
-        gchar *b32_encoded_secret = base32_encode 
(msg->otp_parameters[i]->secret.data, msg->otp_parameters[i]->secret.len, 
&b_err);
-        if (b32_encoded_secret == NULL) {
-            g_printerr ("Error while encoding the secret (error code %d)\n", 
b_err);
-            goto end;
-        }
-
-        uri = g_strconcat (uri, "secret=", b32_encoded_secret, NULL);
-
-        uris = g_slist_append (uris, g_strdup (uri));
-
-        end:
-        g_free (uri);
-    }
-
-    return uris;
 }
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-2.6.0/src/app.c 
new/OTPClient-2.6.2/src/app.c
--- old/OTPClient-2.6.0/src/app.c       2022-07-01 14:43:11.000000000 +0200
+++ new/OTPClient-2.6.2/src/app.c       2022-07-06 08:51:34.000000000 +0200
@@ -36,6 +36,15 @@
                                              gint                height,
                                              AppData            *app_data);
 
+static gboolean   show_upgrade_msg          (void);
+
+static void       set_info_bar              (AppData            *app_data,
+                                             const gchar        *msg);
+
+static void       on_bar_response           (GtkInfoBar         *ib,
+                                             gint                response_id,
+                                             gpointer            user_data);
+
 static gboolean   set_action_group          (GtkBuilder         *builder,
                                              AppData            *app_data);
 
@@ -272,6 +281,13 @@
     app_data->source_id_last_activity = g_timeout_add_seconds (1, 
check_inactivity, app_data);
 
     gtk_widget_show_all (app_data->main_window);
+
+    app_data->info_bar = GTK_WIDGET(gtk_builder_get_object (app_data->builder, 
"info_bar_id"));
+    if (show_upgrade_msg ()) {
+        set_info_bar (app_data, "Release <b>2.6.0</b>: please check the 
'Secret Service Integration' new feature <a 
href=\"https://github.com/paolostivanin/OTPClient/wiki/How-to-use-OTPClient#secret-service-integration\";>HERE</a>");
+    } else {
+        gtk_widget_hide (app_data->info_bar);
+    }
 }
 
 
@@ -432,6 +448,68 @@
 
 
 static gboolean
+show_upgrade_msg ()
+{
+    gboolean show_msg = TRUE;
+    GKeyFile *kf = get_kf_ptr ();
+    if (kf != NULL) {
+        gchar *up_msg = g_key_file_get_string (kf, "config", "upgrade_msg", 
NULL);
+        if (up_msg == NULL) {
+            show_msg = TRUE;
+        } else {
+            show_msg = (g_strcmp0 (up_msg, "v2_6") == 0) ? FALSE : TRUE;
+        }
+    }
+
+    g_key_file_free (kf);
+
+    return show_msg;
+}
+
+
+static void
+set_info_bar (AppData     *app_data,
+              const gchar *msg)
+{
+    GtkWidget *label = GTK_WIDGET(gtk_builder_get_object (app_data->builder, 
"info_bar_label_id"));
+
+    g_signal_connect (app_data->info_bar, "response", 
G_CALLBACK(on_bar_response), NULL);
+
+    gtk_label_set_markup (GTK_LABEL(label), msg);
+    gtk_info_bar_set_message_type (GTK_INFO_BAR(app_data->info_bar), 
GTK_MESSAGE_INFO);
+    gtk_widget_show (app_data->info_bar);
+}
+
+
+static void
+on_bar_response (GtkInfoBar *ib,
+                 gint        response_id __attribute__((unused)),
+                 gpointer    user_data   __attribute__((unused)))
+{
+    GError *err = NULL;
+    GKeyFile *kf = get_kf_ptr ();
+    if (kf != NULL) {
+        g_key_file_set_string (kf, "config", "upgrade_msg", "v2_6");
+        gchar *cfg_file_path;
+#ifndef USE_FLATPAK_APP_FOLDER
+        cfg_file_path = g_build_filename (g_get_user_config_dir (), 
"otpclient.cfg", NULL);
+#else
+        cfg_file_path = g_build_filename (g_get_user_data_dir (), 
"otpclient.cfg", NULL);
+#endif
+        g_key_file_save_to_file (kf, cfg_file_path, &err);
+        if (err != NULL) {
+            g_printerr ("%s\n", err->message);
+        }
+        g_free (cfg_file_path);
+    }
+
+    g_key_file_free (kf);
+
+    gtk_widget_hide (GTK_WIDGET(ib));
+}
+
+
+static gboolean
 set_action_group (GtkBuilder *builder,
                   AppData    *app_data)
 {
@@ -447,7 +525,8 @@
             { .name = FREEOTPPLUS_EXPORT_ACTION_NAME, .activate = 
export_data_cb },
             { .name = AEGIS_EXPORT_ACTION_NAME, .activate = export_data_cb },
             { .name = AEGIS_EXPORT_PLAIN_ACTION_NAME, .activate = 
export_data_cb },
-            { .name = GOOGLE_MIGRATION_ACTION_NAME, .activate = 
add_qr_from_file },
+            { .name = GOOGLE_MIGRATION_FILE_ACTION_NAME, .activate = 
add_qr_from_file },
+            { .name = GOOGLE_MIGRATION_WEBCAM_ACTION_NAME, .activate = 
webcam_cb },
             { .name = "create_newdb", .activate = new_db_cb },
             { .name = "change_db", .activate = change_db_cb },
             { .name = "change_pwd", .activate = change_password_cb },
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-2.6.0/src/common/aegis.c 
new/OTPClient-2.6.2/src/common/aegis.c
--- old/OTPClient-2.6.0/src/common/aegis.c      2022-07-01 14:43:11.000000000 
+0200
+++ new/OTPClient-2.6.2/src/common/aegis.c      2022-07-06 08:51:34.000000000 
+0200
@@ -135,8 +135,6 @@
     guchar *b64decoded_db = g_base64_decode (json_string_value 
(json_object_get(json, "db")), &out_len);
     if (out_len > max_file_size) {
         g_set_error (err, file_too_big_gquark (), FILE_TOO_BIG, "File is too 
big");
-        g_free (key_nonce);
-        g_free (key_tag);
         gcry_cipher_close (hd);
         gcry_free (master_key);
         return NULL;
@@ -146,8 +144,6 @@
     gpg_err = gcry_cipher_checktag(hd, tag, TAG_SIZE);
     if (gpg_err != 0) {
         g_set_error (err, bad_tag_gquark (), BAD_TAG_ERRCODE, "Invalid TAG 
(database). Either the password is wrong or the file is corrupted.");
-        g_free (key_nonce);
-        g_free (key_tag);
         gcry_cipher_close (hd);
         gcry_free (master_key);
         g_free (decrypted_db);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-2.6.0/src/common/common.c 
new/OTPClient-2.6.2/src/common/common.c
--- old/OTPClient-2.6.0/src/common/common.c     2022-07-01 14:43:11.000000000 
+0200
+++ new/OTPClient-2.6.2/src/common/common.c     2022-07-06 08:51:34.000000000 
+0200
@@ -1,8 +1,10 @@
 #include <glib.h>
 #include <sys/resource.h>
 #include <cotp.h>
+#include <baseencode.h>
 #include "gcrypt.h"
 #include "jansson.h"
+#include "../google-migration.pb-c.h"
 
 gint32
 get_max_file_size_from_memlock (void)
@@ -165,3 +167,77 @@
 
     return result;
 }
+
+
+GSList *
+decode_migration_data (const gchar *encoded_uri)
+{
+    const gchar *encoded_uri_copy = encoded_uri;
+    if (g_ascii_strncasecmp (encoded_uri_copy, 
"otpauth-migration://offline?data=", 33) != 0) {
+        return NULL;
+    }
+    encoded_uri_copy += 33;
+    gsize out_len;
+    guchar *data = g_base64_decode (g_uri_unescape_string ((encoded_uri_copy), 
NULL), &out_len);
+
+    GSList *uris = NULL;
+    gchar *uri = NULL;
+    MigrationPayload *msg = migration_payload__unpack (NULL, out_len, data);
+    for (gint i = 0; i < msg->n_otp_parameters; i++) {
+        uri = g_strconcat ("otpauth://", NULL);
+        if (msg->otp_parameters[i]->type == 1) {
+            uri = g_strconcat (uri, "hotp/", NULL);
+        } else if (msg->otp_parameters[i]->type == 2) {
+            uri = g_strconcat (uri, "totp/", NULL);
+        } else {
+            g_printerr ("OTP type not recognized, skipping %s\n", 
msg->otp_parameters[i]->name);
+            goto end;
+        }
+
+        uri = g_strconcat (uri, msg->otp_parameters[i]->name, "?", NULL);
+
+        if (msg->otp_parameters[i]->algorithm == 1) {
+            uri = g_strconcat (uri, "algorithm=SHA1&", NULL);
+        } else if (msg->otp_parameters[i]->algorithm == 2) {
+            uri = g_strconcat (uri, "algorithm=SHA256&", NULL);
+        } else if (msg->otp_parameters[i]->algorithm == 3) {
+            uri = g_strconcat (uri, "algorithm=SHA512&", NULL);
+        } else {
+            g_printerr ("Algorithm type not supported, skipping %s\n", 
msg->otp_parameters[i]->name);
+            goto end;
+        }
+
+        if (msg->otp_parameters[i]->digits == 1) {
+            uri = g_strconcat (uri, "digits=6&", NULL);
+        } else if (msg->otp_parameters[i]->digits == 2) {
+            uri = g_strconcat (uri, "digits=8&", NULL);
+        } else {
+            g_printerr ("Algorithm type not supported, skipping %s\n", 
msg->otp_parameters[i]->name);
+            goto end;
+        }
+
+        if (msg->otp_parameters[i]->issuer != NULL) {
+            uri = g_strconcat (uri, "issuer=", msg->otp_parameters[i]->issuer, 
"&", NULL);
+        }
+
+        if (msg->otp_parameters[i]->type == 1) {
+            uri = g_strconcat (uri, "counter=", 
msg->otp_parameters[i]->counter, "&", NULL);
+        }
+
+        baseencode_error_t b_err;
+        gchar *b32_encoded_secret = base32_encode 
(msg->otp_parameters[i]->secret.data, msg->otp_parameters[i]->secret.len, 
&b_err);
+        if (b32_encoded_secret == NULL) {
+            g_printerr ("Error while encoding the secret (error code %d)\n", 
b_err);
+            goto end;
+        }
+
+        uri = g_strconcat (uri, "secret=", b32_encoded_secret, NULL);
+
+        uris = g_slist_append (uris, g_strdup (uri));
+
+        end:
+        g_free (uri);
+    }
+
+    return uris;
+}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-2.6.0/src/common/common.h 
new/OTPClient-2.6.2/src/common/common.h
--- old/OTPClient-2.6.0/src/common/common.h     2022-07-01 14:43:11.000000000 
+0200
+++ new/OTPClient-2.6.2/src/common/common.h     2022-07-06 08:51:34.000000000 
+0200
@@ -31,4 +31,6 @@
 gchar      *bytes_to_hexstr                 (const guchar   *data,
                                              size_t          datalen);
 
+GSList     *decode_migration_data           (const gchar    *encoded_uri);
+
 G_END_DECLS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-2.6.0/src/data.h 
new/OTPClient-2.6.2/src/data.h
--- old/OTPClient-2.6.0/src/data.h      2022-07-01 14:43:11.000000000 +0200
+++ new/OTPClient-2.6.2/src/data.h      2022-07-06 08:51:34.000000000 +0200
@@ -31,6 +31,7 @@
     GtkBuilder *builder;
 
     GtkWidget *main_window;
+    GtkWidget *info_bar;
     GtkTreeView *tree_view;
 
     GtkClipboard *clipboard;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-2.6.0/src/gui-common.c 
new/OTPClient-2.6.2/src/gui-common.c
--- old/OTPClient-2.6.0/src/gui-common.c        2022-07-01 14:43:11.000000000 
+0200
+++ new/OTPClient-2.6.2/src/gui-common.c        2022-07-06 08:51:34.000000000 
+0200
@@ -1,5 +1,8 @@
 #include <gtk/gtk.h>
 #include <jansson.h>
+#include "message-dialogs.h"
+#include "add-common.h"
+#include "common/common.h"
 
 
 void
@@ -61,3 +64,37 @@
 {
     gtk_dialog_response (GTK_DIALOG(gtk_widget_get_toplevel (entry)), 
GTK_RESPONSE_OK);
 }
+
+
+gchar *
+parse_uris_migration (AppData  *app_data,
+                      const     gchar *user_uri,
+                      gboolean  google_migration)
+{
+    gchar *return_err_msg = NULL;
+    GSList *otpauth_decoded_uris = NULL;
+    if (google_migration == TRUE) {
+        gint failed = 0;
+        otpauth_decoded_uris = decode_migration_data (user_uri);
+        for (gint i = 0; i < g_slist_length (otpauth_decoded_uris); i++) {
+            gchar *uri = g_slist_nth_data (otpauth_decoded_uris, i);
+            gchar *err_msg = add_data_to_db (uri, app_data);
+            if (err_msg != NULL) {
+                failed++;
+                g_free (err_msg);
+            }
+        }
+        if (failed > 0) {
+            GString *e_msg = g_string_new (NULL);
+            g_string_printf (e_msg, "Failed to add all OTPs. Only %u out of %u 
were successfully added.", g_slist_length (otpauth_decoded_uris) - failed,
+                             g_slist_length (otpauth_decoded_uris));
+            return_err_msg = g_strdup (e_msg->str);
+            g_string_free (e_msg, TRUE);
+        }
+        g_slist_free_full (otpauth_decoded_uris, g_free);
+    } else {
+        return_err_msg = add_data_to_db (user_uri, app_data);
+    }
+
+    return return_err_msg;
+}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-2.6.0/src/gui-common.h 
new/OTPClient-2.6.2/src/gui-common.h
--- old/OTPClient-2.6.0/src/gui-common.h        2022-07-01 14:43:11.000000000 
+0200
+++ new/OTPClient-2.6.2/src/gui-common.h        2022-07-06 08:51:34.000000000 
+0200
@@ -2,27 +2,32 @@
 
 #include <gtk/gtk.h>
 #include <jansson.h>
+#include "data.h"
 
 G_BEGIN_DECLS
 
-void         icon_press_cb              (GtkEntry       *entry,
-                                         gint            position,
-                                         GdkEventButton *event,
-                                         gpointer        data);
-
-guint        get_row_number_from_iter   (GtkListStore   *list_store,
-                                         GtkTreeIter     iter);
-
-json_t      *build_json_obj             (const gchar *type,
-                                         const gchar *acc_label,
-                                         const gchar *acc_iss,
-                                         const gchar *acc_key,
-                                         guint        digits,
-                                         const gchar *algo,
-                                         guint        period,
-                                         guint64      ctr);
-
-void send_ok_cb                         (GtkWidget *entry,
-                                         gpointer   user_data);
+void    icon_press_cb            (GtkEntry       *entry,
+                                  gint            position,
+                                  GdkEventButton *event,
+                                  gpointer        data);
+
+guint   get_row_number_from_iter (GtkListStore   *list_store,
+                                  GtkTreeIter     iter);
+
+json_t *build_json_obj           (const gchar    *type,
+                                  const gchar    *acc_label,
+                                  const gchar    *acc_iss,
+                                  const gchar    *acc_key,
+                                  guint           digits,
+                                  const gchar    *algo,
+                                  guint           period,
+                                  guint64         ctr);
+
+void    send_ok_cb               (GtkWidget      *entry,
+                                  gpointer        user_data);
+
+gchar  *parse_uris_migration     (AppData        *app_data,
+                                  const gchar    *user_uri,
+                                  gboolean        google_migration);
 
 G_END_DECLS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-2.6.0/src/imports.h 
new/OTPClient-2.6.2/src/imports.h
--- old/OTPClient-2.6.0/src/imports.h   2022-07-01 14:43:11.000000000 +0200
+++ new/OTPClient-2.6.2/src/imports.h   2022-07-06 08:51:34.000000000 +0200
@@ -11,7 +11,8 @@
 #define FREEOTPPLUS_IMPORT_ACTION_NAME      "import_freeotpplus"
 #define AEGIS_IMPORT_ACTION_NAME            "import_aegis"
 #define AEGIS_IMPORT_ENC_ACTION_NAME        "import_aegis_enc"
-#define GOOGLE_MIGRATION_ACTION_NAME        "import_qr_google_migration_file"
+#define GOOGLE_MIGRATION_FILE_ACTION_NAME   "import_google_qr_file"
+#define GOOGLE_MIGRATION_WEBCAM_ACTION_NAME "import_google_qr_webcam"
 
 typedef struct otp_object_t {
     gchar *type;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-2.6.0/src/ui/otpclient.ui 
new/OTPClient-2.6.2/src/ui/otpclient.ui
--- old/OTPClient-2.6.0/src/ui/otpclient.ui     2022-07-01 14:43:11.000000000 
+0200
+++ new/OTPClient-2.6.2/src/ui/otpclient.ui     2022-07-06 08:51:34.000000000 
+0200
@@ -1863,12 +1863,13 @@
           </packing>
         </child>
         <child>
-          <object class="GtkModelButton" 
id="import_google_migration_qr_btn_id">
+          <object class="GtkModelButton" id="import_google_qr_model_btn_id">
             <property name="visible">True</property>
             <property name="can-focus">True</property>
             <property name="receives-default">True</property>
-            <property 
name="action-name">settings_menu.import_qr_google_migration_file</property>
             <property name="text" translatable="yes">Google Migration 
QR</property>
+            <property name="menu-name">import_google_qr_menu</property>
+            <accelerator key="g" signal="activate" 
modifiers="GDK_CONTROL_MASK"/>
           </object>
           <packing>
             <property name="expand">False</property>
@@ -2092,6 +2093,45 @@
         <property name="position">3</property>
       </packing>
     </child>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="can-focus">False</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkModelButton" id="import_google_qr_file_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property 
name="action-name">settings_menu.import_google_qr_file</property>
+            <property name="text" translatable="yes">From file</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="import_google_qr_webcam_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property 
name="action-name">settings_menu.import_google_qr_webcam</property>
+            <property name="text" translatable="yes">From webcam</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="submenu">import_google_qr_menu</property>
+        <property name="position">4</property>
+      </packing>
+    </child>
   </object>
   <object class="GtkApplicationWindow" id="appwindow_id">
     <property name="can-focus">False</property>
@@ -2100,23 +2140,93 @@
     <property name="default-height">350</property>
     <property name="gravity">center</property>
     <child>
-      <object class="GtkScrolledWindow" id="scrolledwin_id">
+      <object class="GtkBox">
         <property name="visible">True</property>
-        <property name="can-focus">True</property>
-        <property name="hexpand">True</property>
-        <property name="vexpand">True</property>
-        <property name="shadow-type">etched-in</property>
+        <property name="can-focus">False</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkInfoBar" id="info_bar_id">
+            <property name="visible">False</property>
+            <property name="can-focus">False</property>
+            <property name="orientation">vertical</property>
+            <child internal-child="action_area">
+              <object class="GtkButtonBox">
+                <property name="can-focus">False</property>
+                <property name="spacing">6</property>
+                <property name="layout-style">end</property>
+                <child>
+                  <object class="GtkButton" id="info_bar_ok_btn_id">
+                    <property name="label" translatable="yes">OK</property>
+                    <property name="visible">True</property>
+                    <property name="can-focus">True</property>
+                    <property name="receives-default">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child internal-child="content_area">
+              <object class="GtkBox">
+                <property name="can-focus">False</property>
+                <property name="spacing">16</property>
+                <child>
+                  <object class="GtkLabel" id="info_bar_label_id">
+                    <property name="visible">True</property>
+                    <property name="can-focus">False</property>
+                    <property name="label" translatable="yes">label</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <action-widgets>
+              <action-widget response="-5">info_bar_ok_btn_id</action-widget>
+            </action-widgets>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
         <child>
-          <object class="GtkTreeView" id="treeview_id">
+          <object class="GtkScrolledWindow" id="scrolledwin_id">
             <property name="visible">True</property>
             <property name="can-focus">True</property>
             <property name="hexpand">True</property>
             <property name="vexpand">True</property>
-            <property name="headers-clickable">False</property>
-            <property name="enable-grid-lines">horizontal</property>
-            <property name="activate-on-single-click">True</property>
-            <child internal-child="selection">
-              <object class="GtkTreeSelection"/>
+            <property name="shadow-type">etched-in</property>
+            <child>
+              <object class="GtkTreeView" id="treeview_id">
+                <property name="visible">True</property>
+                <property name="can-focus">True</property>
+                <property name="hexpand">True</property>
+                <property name="vexpand">True</property>
+                <property name="headers-clickable">False</property>
+                <property name="enable-grid-lines">horizontal</property>
+                <property name="activate-on-single-click">True</property>
+                <child internal-child="selection">
+                  <object class="GtkTreeSelection"/>
+                </child>
+              </object>
             </child>
           </object>
         </child>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-2.6.0/src/webcam-add-cb.c 
new/OTPClient-2.6.2/src/webcam-add-cb.c
--- old/OTPClient-2.6.0/src/webcam-add-cb.c     2022-07-01 14:43:11.000000000 
+0200
+++ new/OTPClient-2.6.2/src/webcam-add-cb.c     2022-07-06 08:51:34.000000000 
+0200
@@ -7,6 +7,7 @@
 #include "add-common.h"
 #include "get-builder.h"
 #include "common/common.h"
+#include "gui-common.h"
 
 
 typedef struct config_data_t {
@@ -28,6 +29,10 @@
            GVariant      *parameter __attribute__((unused)),
            gpointer       user_data)
 {
+    const gchar *action_name = g_action_get_name (G_ACTION(simple));
+    gboolean google_migration;
+    (g_strcmp0 (action_name, GOOGLE_MIGRATION_WEBCAM_ACTION_NAME) == 0) ? 
google_migration = TRUE : FALSE;
+
     AppData *app_data = (AppData *)user_data;
 
     ConfigData *cfg_data = g_new0 (ConfigData, 1);
@@ -59,7 +64,7 @@
     if (response == GTK_RESPONSE_CANCEL) {
         if (cfg_data->qrcode_found) {
             zbar_processor_destroy (proc);
-            gchar *err_msg = add_data_to_db (cfg_data->otp_uri, app_data);
+            gchar *err_msg = parse_uris_migration (app_data, 
cfg_data->otp_uri, google_migration);
             if (err_msg != NULL) {
                 show_message_dialog (app_data->main_window, err_msg, 
GTK_MESSAGE_ERROR);
                 g_free (err_msg);

Reply via email to