account_add: Better error handling

In the case where the token is not a valid Base32 string or the provider
was not found the ErrorRevealer widget is used.

Fixes: https://gitlab.gnome.org/World/Authenticator/-/issues/225
This commit is contained in:
Maximiliano Sandoval R 2021-01-29 17:43:17 +01:00
parent 758f5d0c54
commit 8e0927036b
Failed to generate hash of commit
4 changed files with 31 additions and 7 deletions

View file

@ -85,6 +85,11 @@
<property name="size">96</property>
</object>
</child>
<child>
<object class="ErrorRevealer" id="error_revealer">
<property name="margin-top">12</property>
</object>
</child>
<child>
<object class="GtkListBox">
<property name="selection-mode">none</property>

View file

@ -19,6 +19,7 @@ src/backup/bitwarden.rs
src/backup/freeotp.rs
src/backup/legacy.rs
src/models/algorithm.rs
src/widgets/accounts/add.rs
src/widgets/window.rs
src/widgets/preferences/password_page.rs
src/widgets/preferences/window.rs

View file

@ -15,12 +15,17 @@ pub static TOTP_DEFAULT_PERIOD: u32 = 30;
/// https://github.com/TimDumol/rust-otp/blob/master/src/lib.rs
/// Decodes a secret (given as an RFC4648 base32-encoded ASCII string)
/// into a byte string
/// into a byte string. It fails if secret is not a valid Base32 string.
fn decode_secret(secret: &str) -> Result<Vec<u8>> {
let res = BASE32.decode(secret.as_bytes())?;
Ok(res)
}
/// Validates if `secret` is a valid Base32 String.
pub fn is_valid(secret: &str) -> bool {
decode_secret(secret).is_ok()
}
/// Calculates the HMAC digest for the given secret and counter.
fn calc_digest(decoded_secret: &[u8], counter: u64, algorithm: hmac::Algorithm) -> hmac::Tag {
let key = hmac::Key::new(algorithm, decoded_secret);

View file

@ -1,8 +1,9 @@
use crate::{
models::{Account, OTPMethod, OTPUri, Provider, ProvidersModel},
widgets::{Camera, ProviderImage, UrlRow},
models::{otp, Account, OTPMethod, OTPUri, Provider, ProvidersModel},
widgets::{Camera, ErrorRevealer, ProviderImage, UrlRow},
};
use anyhow::Result;
use anyhow::{Context, Result};
use gettextrs::gettext;
use glib::{clone, signal::Inhibit};
use gtk::{gio, glib, prelude::*, subclass::prelude::*, CompositeTemplate};
use gtk_macros::{action, get_action};
@ -52,6 +53,8 @@ mod imp {
pub period_row: TemplateChild<adw::ActionRow>,
#[template_child]
pub provider_completion: TemplateChild<gtk::EntryCompletion>,
#[template_child]
pub error_revealer: TemplateChild<ErrorRevealer>,
}
impl ObjectSubclass for AccountAddDialog {
@ -87,6 +90,7 @@ mod imp {
period_row: TemplateChild::default(),
deck: TemplateChild::default(),
camera: TemplateChild::default(),
error_revealer: TemplateChild::default(),
}
}
@ -192,14 +196,23 @@ impl AccountAddDialog {
let self_ = imp::AccountAddDialog::from_instance(self);
if let Some(ref provider) = *self_.selected_provider.borrow() {
let username = self_.username_entry.get_text().unwrap();
let token = self_.token_entry.get_text().unwrap();
let username = self_
.username_entry
.get_text()
.context("Could not get text")?;
let token = self_.token_entry.get_text().context("Could not get text")?;
if !otp::is_valid(&token) {
self_.error_revealer.popup(&gettext("Invalid Token"));
anyhow::bail!("Token {} is not a valid Base32 secret", &token);
}
let account = Account::create(&username, &token, provider)?;
self_.model.get().unwrap().add_account(&account, &provider);
self.emit("added", &[]).unwrap();
// TODO: display an error message saying there was an error form keyring
// TODO: display an error message saying there was an error form keyring
} else {
anyhow::bail!("Could not find provider");
}
Ok(())
}