Skip to content

Commit

Permalink
Merge pull request #351 from paolostivanin/newpr_rb
Browse files Browse the repository at this point in the history
Release 3.5.0
  • Loading branch information
paolostivanin committed Mar 1, 2024
2 parents ebb2b11 + 338c81e commit 691f105
Show file tree
Hide file tree
Showing 29 changed files with 1,326 additions and 312 deletions.
6 changes: 3 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
version: 2.0

jobs:
ubuntu2004:
ubuntu2304:
docker:
- image: ubuntu:20.04
- image: ubuntu:23.04
steps:
- checkout
- run: apt update && DEBIAN_FRONTEND=noninteractive apt -y install git gcc clang cmake libgcrypt20-dev libgtk-3-dev libzip-dev libjansson-dev libpng-dev libzbar-dev libprotobuf-c-dev libsecret-1-dev uuid-dev libprotobuf-dev libqrencode-dev
Expand Down Expand Up @@ -50,7 +50,7 @@ workflows:
version: 2
build:
jobs:
- ubuntu2004
- ubuntu2304
- ubuntuLatestRolling
- debianLatestStable
- fedoraLatestStable
Expand Down
16 changes: 10 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.16)
project(OTPClient VERSION "3.4.1" LANGUAGES "C")
project(OTPClient VERSION "3.5.0" LANGUAGES "C")
include(GNUInstallDirs)

configure_file("src/common/version.h.in" "version.h")
Expand Down Expand Up @@ -44,14 +44,14 @@ endif()

find_package(PkgConfig REQUIRED)
find_package(Protobuf 3.6.0 REQUIRED)
find_package(Gcrypt 1.8.0 REQUIRED)
find_package(Gcrypt 1.10.1 REQUIRED)
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)
pkg_check_modules(GTK3 REQUIRED gtk+-3.0>=3.24.0)
pkg_check_modules(GLIB2 REQUIRED glib-2.0>=2.64.0)
pkg_check_modules(GIO REQUIRED gio-2.0>=2.64.0)
pkg_check_modules(GLIB2 REQUIRED glib-2.0>=2.68.0)
pkg_check_modules(GIO REQUIRED gio-2.0>=2.68.0)
pkg_check_modules(UUID REQUIRED uuid>=2.34.0)
pkg_check_modules(PROTOC REQUIRED libprotobuf-c>=1.3.0)
pkg_check_modules(LIBSECRET REQUIRED libsecret-1>=0.20.0)
Expand Down Expand Up @@ -130,7 +130,9 @@ set(GUI_SOURCE_FILES
src/show-qr-cb.c
src/setup-signals-shortcuts.c
src/change-pwd-cb.c
src/dbinfo-cb.c)
src/dbinfo-cb.c
src/common/twofas.c
src/common/authpro.c)

set(CLI_HEADER_FILES
src/cli/get-data.h
Expand Down Expand Up @@ -159,7 +161,9 @@ set(CLI_SOURCE_FILES
src/common/aegis.c
src/common/freeotp.c
src/secret-schema.c
src/google-migration.pb-c.c)
src/google-migration.pb-c.c
src/common/twofas.c
src/common/authpro.c)

if(BUILD_GUI AND BUILD_CLI)
list(APPEND CLI_SOURCE_FILES
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ Highly secure and easy to use GTK+ software for two-factor authentication that s
| Name | Min Version |
|----------------------------------------------------|-------------|
| GTK+ | 3.24 |
| Glib | 2.64.0 |
| Glib | 2.68.0 |
| jansson | 2.12 |
| libgcrypt | 1.8.0 |
| libgcrypt | 1.10.1 |
| libpng | 1.6.30 |
| [libcotp](https://github.com/paolostivanin/libcotp) | 3.0.0 |
| zbar | 0.20 |
Expand All @@ -38,6 +38,8 @@ See this [wiki section](https://github.com/paolostivanin/OTPClient/wiki/Secure-M
- 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 and export encrypted/plain [AuthenticatorPro](https://github.com/jamie-mh/AuthenticatorPro) backup
- import and export encrypted/plain [2FAS](https://github.com/twofas) backup
- import of Google's migration QR codes
- local database is encrypted using AES256-GCM
- key is derived using PBKDF2 with SHA512 and 100k iterations
Expand Down
6 changes: 4 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ The following list describes whether a version is eligible or not for security u

| Version | Supported | EOL |
|---------|--------------------|-------------|
| 3.4.x | :white_check_mark: | - |
| 3.3.x | :white_check_mark: | 03-Mar-2024 |
| 3.5.x | :white_check_mark: | - |
| 3.4.1 | :white_check_mark: | 31-May-2024 |
| 3.4.0 | :x: | 29-Feb-2024 |
| 3.3.x | :x: | 29-Feb-2024 |
| 3.2.x | :x: | 31-Jan-2024 |
| 3.1.x | :x: | 30-Nov-2023 |
| 3.0.x | :x: | 31-Dec-2022 |
Expand Down
20 changes: 15 additions & 5 deletions data/com.github.paolostivanin.OTPClient.appdata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<metadata_license>CC-BY-4.0</metadata_license>
<project_license>GPL-3.0+</project_license>
<name>OTPClient</name>
<summary>GTK+ application for managing TOTP and HOTP tokens with built-in encryption.</summary>
<summary>Application for managing TOTP/HOTP tokens with built-in encryption</summary>

<keywords>
<keyword>otp</keyword>
Expand Down Expand Up @@ -89,6 +89,20 @@
</content_rating>

<releases>
<release version="3.5.0" date="2024-03-01x">
<description>
<p>OTPClient 3.5.0 brings some new features and improvements:</p>
<ul>
<li>NEW: add support for importing and exporting plain/encrypted 2FAS backups (#322)</li>
<li>NEW: add support for importing and exporting plain/encrypted AuthenticatorPro backups (#322)</li>
<li>CHANGE: show warning when exporting a plain backup</li>
<li>CHANGE: remove support for older Glib and GCrypt</li>
<li>FIX: add 2fa keyword to the desktop file (#349)</li>
<li>FIX: remove custom keywords from metadata file (#348)</li>
<li>FIX: returning to a dialog won't crash the widget</li>
</ul>
</description>
</release>
<release version="3.4.1" date="2024-02-12">
<description>
<p>OTPClient 3.4.1 brings a single fix::</p>
Expand Down Expand Up @@ -561,8 +575,4 @@
</description>
</release>
</releases>
<custom>
<value key="Purism::form_factor">workstation</value>
<value key="Purism::form_factor">mobile</value>
</custom>
</component>
2 changes: 1 addition & 1 deletion data/com.github.paolostivanin.OTPClient.desktop
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Type=Application
Exec=otpclient
Icon=com.github.paolostivanin.OTPClient
Keywords=otp;totp;hotp;
Keywords=otp;totp;hotp;2fa
Terminal=false
Name=OTPClient
Comment=GTK+ TOTP and HOTP client
Expand Down
16 changes: 8 additions & 8 deletions flatpak/com.github.paolostivanin.OTPClient.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
app-id: com.github.paolostivanin.OTPClient
runtime: org.gnome.Platform
runtime-version: '44'
runtime-version: '45'
sdk: org.gnome.Sdk
command: otpclient
finish-args:
- "--share=ipc"
- "--socket=x11"
- "--socket=fallback-x11"
- "--socket=wayland"
- "--device=all"
- "--talk-name=org.freedesktop.secrets"
Expand Down Expand Up @@ -42,8 +42,8 @@ modules:
- "/lib/*.la"
sources:
- type: archive
url: https://github.com/protobuf-c/protobuf-c/archive/refs/tags/v1.4.1.tar.gz
sha256: 99be336cdb15dfc5827efe34e5ac9aaa962e2485db547dd254d2a122a7d23102
url: https://github.com/protobuf-c/protobuf-c/archive/refs/tags/v1.5.0.tar.gz
sha256: 7b404c63361ed35b3667aec75cc37b54298d56dd2bcf369de3373212cc06fd98
- name: qrencode
buildsystem: cmake-ninja
config-opts:
Expand All @@ -66,8 +66,8 @@ modules:
- "--enable-codes=qrcode"
sources:
- type: archive
url: https://www.linuxtv.org/downloads/zbar/zbar-0.23.90.tar.gz
sha256: ff857dd7e3dbe043dac3765b5182c91dfd0477800713a75d15287d797cee60fa
url: https://www.linuxtv.org/downloads/zbar/zbar-0.23.93.tar.gz
sha256: 78ae427a529f0399561bc198de5c2c7ca3f11d05fa9e903e65e501168433d218
- name: libcotp
buildsystem: cmake-ninja
config-opts:
Expand All @@ -77,8 +77,8 @@ modules:
- "/include"
sources:
- type: archive
url: https://github.com/paolostivanin/libcotp/archive/v2.0.1.tar.gz
sha256: b111d528bbde7c1a0a392f49293b25ae33e6e78fbcbe378e0cf8bc6d59743d11
url: https://github.com/paolostivanin/libcotp/archive/v3.0.0.tar.gz
sha256: ff0b9ce208c4c6542a0f1e739cf31978fbf28848c573837c671a6cb7b56b2c12
- name: OTPClient
buildsystem: cmake-ninja
config-opts:
Expand Down
10 changes: 10 additions & 0 deletions src/app.c
Original file line number Diff line number Diff line change
Expand Up @@ -536,11 +536,19 @@ set_action_group (GtkBuilder *builder,
{ .name = FREEOTPPLUS_IMPORT_ACTION_NAME, .activate = select_file_cb },
{ .name = AEGIS_IMPORT_ACTION_NAME, .activate = select_file_cb },
{ .name = AEGIS_IMPORT_ENC_ACTION_NAME, .activate = select_file_cb },
{ .name = AUTHPRO_IMPORT_ENC_ACTION_NAME, .activate = select_file_cb },
{ .name = AUTHPRO_IMPORT_PLAIN_ACTION_NAME, .activate = select_file_cb },
{ .name = TWOFAS_IMPORT_ENC_ACTION_NAME, .activate = select_file_cb },
{ .name = TWOFAS_IMPORT_PLAIN_ACTION_NAME, .activate = select_file_cb },
{ .name = ANDOTP_EXPORT_ACTION_NAME, .activate = export_data_cb },
{ .name = ANDOTP_EXPORT_PLAIN_ACTION_NAME, .activate = export_data_cb },
{ .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 = AUTHPRO_EXPORT_ENC_ACTION_NAME, .activate = export_data_cb },
{ .name = AUTHPRO_EXPORT_PLAIN_ACTION_NAME, .activate = export_data_cb },
{ .name = TWOFAS_EXPORT_ENC_ACTION_NAME, .activate = export_data_cb },
{ .name = TWOFAS_EXPORT_PLAIN_ACTION_NAME, .activate = export_data_cb },
{ .name = GOOGLE_MIGRATION_FILE_ACTION_NAME, .activate = add_qr_from_file },
{ .name = GOOGLE_MIGRATION_WEBCAM_ACTION_NAME, .activate = webcam_add_cb },
{ .name = "create_newdb", .activate = new_db_cb },
Expand Down Expand Up @@ -601,6 +609,8 @@ get_db_path (AppData *app_data)
gchar *msg = g_strconcat ("Database file/location:\n<b>", db_path, "</b>\ndoes not exist. A new database will be created.", NULL);
show_message_dialog (app_data->main_window, msg, GTK_MESSAGE_ERROR);
g_free (msg);
g_free (db_path);
db_path = NULL;
goto new_db;
}
goto end;
Expand Down
5 changes: 2 additions & 3 deletions src/change-db-cb.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,9 @@ change_db (AppData *app_data)
g_free (old_db_path);
break;
case GTK_RESPONSE_CANCEL:
gtk_widget_destroy (changedb_diag);
return QUIT_APP;
default:
break;
gtk_widget_hide (changedb_diag);
return QUIT_APP;
}
gtk_widget_destroy (changedb_diag);

Expand Down
2 changes: 1 addition & 1 deletion src/cli/exec-action.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ gboolean exec_action (CmdlineOpts *cmdline_opts,
}
}
exported_file_path = g_build_filename (export_directory, export_pwd != NULL ? "aegis_exports.json.aes" : "aegis_exports.json", NULL);
ret_msg = export_aegis (exported_file_path, db_data->json_data, export_pwd);
ret_msg = export_aegis (exported_file_path, export_pwd, db_data->json_data);
gcry_free (export_pwd);
exported = TRUE;
}
Expand Down
8 changes: 0 additions & 8 deletions src/cli/get-data.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,21 +59,13 @@ show_token (DatabaseData *db_data,

// Translators: please do not translate 'account'
GString *msg = g_string_new (_("Given account: %s"));
#if GLIB_CHECK_VERSION(2, 68, 0)
g_string_replace (msg, "%s", account != NULL ? account : "<none>", 0);
#else
g_string_replace_backported (msg, "%s", account != NULL ? account : "<none>", 0);
#endif
g_printerr ("%s\n", msg->str);
g_string_free (msg, TRUE);

// Translators: please do not translate 'issuer'
msg = g_string_new (_("Given issuer: %s"));
#if GLIB_CHECK_VERSION(2, 68, 0)
g_string_replace (msg, "%s", issuer != NULL ? issuer : "<none>", 0);
#else
g_string_replace_backported (msg, "%s", issuer != NULL ? issuer : "<none>", 0);
#endif
g_printerr ("%s\n", msg->str);
g_string_free (msg, TRUE);

Expand Down
45 changes: 23 additions & 22 deletions src/common/aegis.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,22 @@ static GSList *get_otps_from_encrypted_backup (const gchar *path,
gint32 max_file_size,
GError **err);

static GSList *parse_json_data (const gchar *data,
static GSList *parse_aegis_json_data (const gchar *data,
GError **err);


GSList *
get_aegis_data (const gchar *path,
const gchar *password,
gint32 max_file_size,
gboolean encrypted,
GError **err)
{
if (g_file_test (path, G_FILE_TEST_IS_SYMLINK | G_FILE_TEST_IS_DIR) ) {
g_set_error (err, generic_error_gquark (), GENERIC_ERRCODE, "Selected file is either a symlink or a directory.");
return NULL;
}

return (encrypted == TRUE) ? get_otps_from_encrypted_backup(path, password, max_file_size, err) : get_otps_from_plain_backup(path, err);
return (password != NULL) ? get_otps_from_encrypted_backup (path, password, max_file_size, err) : get_otps_from_plain_backup (path, err);
}


Expand All @@ -53,8 +52,8 @@ get_otps_from_plain_backup (const gchar *path,
return NULL;
}

gchar *dumped_json = json_dumps(json_object_get (json, "db"), 0);
GSList *otps = parse_json_data (dumped_json, err);
gchar *dumped_json = json_dumps (json_object_get (json, "db"), 0);
GSList *otps = parse_aegis_json_data (dumped_json, err);
gcry_free (dumped_json);

return otps;
Expand Down Expand Up @@ -204,7 +203,7 @@ get_otps_from_encrypted_backup (const gchar *path,
g_regex_unref (regex);
gcry_free (decrypted_db);

GSList *otps = parse_json_data (cleaned_db, err);
GSList *otps = parse_aegis_json_data (cleaned_db, err);
gcry_free (cleaned_db);

return otps;
Expand All @@ -213,8 +212,8 @@ get_otps_from_encrypted_backup (const gchar *path,

gchar *
export_aegis (const gchar *export_path,
json_t *json_db_data,
const gchar *password)
const gchar *password,
json_t *json_db_data)
{
GError *err = NULL;
json_t *root = json_object ();
Expand Down Expand Up @@ -422,8 +421,8 @@ export_aegis (const gchar *export_path,


static GSList *
parse_json_data (const gchar *data,
GError **err)
parse_aegis_json_data (const gchar *data,
GError **err)
{
json_error_t jerr;
json_t *root = json_loads (data, JSON_DISABLE_EOF_CHECK, &jerr);
Expand Down Expand Up @@ -451,6 +450,7 @@ parse_json_data (const gchar *data,
otp->secret = secure_strdup (json_string_value (json_object_get (info_obj, "secret")));
otp->digits = (guint32) json_integer_value (json_object_get(info_obj, "digits"));

gboolean skip = FALSE;
const gchar *type = json_string_value (json_object_get (obj, "type"));
if (g_ascii_strcasecmp (type, "TOTP") == 0) {
otp->type = g_strdup (type);
Expand All @@ -468,11 +468,8 @@ parse_json_data (const gchar *data,
g_free (otp->issuer);
otp->issuer = g_strdup ("Steam");
} else {
g_set_error (err, generic_error_gquark (), GENERIC_ERRCODE, "otp type is neither TOTP nor HOTP");
gcry_free (otp->secret);
g_free (otp);
json_decref (obj);
return NULL;
g_printerr ("Skipping token due to unsupported type: %s\n", type);
skip = TRUE;
}

const gchar *algo = json_string_value (json_object_get (info_obj, "algo"));
Expand All @@ -481,16 +478,20 @@ parse_json_data (const gchar *data,
g_ascii_strcasecmp (algo, "SHA512") == 0) {
otp->algo = g_ascii_strup (algo, -1);
} else {
g_printerr ("algo not supported (must be either one of: sha1, sha256 or sha512\n");
g_printerr ("Skipping token due to unsupported algo: %s\n", algo);
skip = TRUE;
}

if (!skip) {
otps = g_slist_append (otps, otp);
} else {
gcry_free (otp->secret);
g_free (otp->issuer);
g_free (otp->account_name);
g_free (otp->algo);
g_free (otp->type);
g_free (otp);
json_decref (obj);
json_decref (info_obj);
return NULL;
}

otps = g_slist_append (otps, g_memdupX (otp, sizeof (otp_t)));
g_free (otp);
}

json_decref (root);
Expand Down
Loading

0 comments on commit 691f105

Please sign in to comment.