Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 3.5.0 #351

Merged
merged 6 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading