Make use of nightly rustfmt features

This commit is contained in:
Bilal Elmoussaoui 2022-06-10 21:10:52 +02:00
parent 99a4bd1efe
commit da507399ca
44 changed files with 316 additions and 212 deletions

View file

@ -1,5 +1,6 @@
use image::io::Reader as ImageReader;
use std::{fmt, io::Cursor, path::PathBuf}; use std::{fmt, io::Cursor, path::PathBuf};
use image::io::Reader as ImageReader;
use tokio::{io::AsyncWriteExt, sync::Mutex}; use tokio::{io::AsyncWriteExt, sync::Mutex};
use url::Url; use url::Url;
@ -45,8 +46,8 @@ impl Favicon {
/// ///
/// # Panics /// # Panics
/// ///
/// If the favicon contains the data instead of a URL, you are supposed to check /// If the favicon contains the data instead of a URL, you are supposed to
/// it content using [`Favicon::is_url`] /// check it content using [`Favicon::is_url`]
pub fn url(&self) -> &Url { pub fn url(&self) -> &Url {
match &self.url { match &self.url {
Some(url) => url, Some(url) => url,

View file

@ -1,7 +1,7 @@
use url::Url;
use std::{fmt, path::Path}; use std::{fmt, path::Path};
use url::Url;
/// Supported image formats. /// Supported image formats.
#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)] #[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
pub enum Format { pub enum Format {
@ -11,11 +11,12 @@ pub enum Format {
} }
impl Format { impl Format {
/// Create a [`Format`] from a URL's path otherwise default to [`Format::Png`]. /// Create a [`Format`] from a URL's path otherwise default to
/// [`Format::Png`].
/// ///
/// ``` /// ```
/// use url::Url;
/// use favicon_scrapper::Format; /// use favicon_scrapper::Format;
/// use url::Url;
/// ///
/// let url = Url::parse("http://127.0.0.1:8000/favicon.ico").unwrap(); /// let url = Url::parse("http://127.0.0.1:8000/favicon.ico").unwrap();
/// assert!(Format::from_url(&url).is_ico()); /// assert!(Format::from_url(&url).is_ico());
@ -38,7 +39,8 @@ impl Format {
} }
} }
/// Create a [`Format`] from a mimetype otherwise default to [`Format::Png`]. /// Create a [`Format`] from a mimetype otherwise default to
/// [`Format::Png`].
/// ///
/// ``` /// ```
/// use favicon_scrapper::Format; /// use favicon_scrapper::Format;

View file

@ -16,9 +16,10 @@ pub use scrapper::Scrapper;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use url::Url; use url::Url;
use super::*;
#[tokio::test] #[tokio::test]
async fn parse_from_file() { async fn parse_from_file() {
let base_url = Url::parse("https://github.com").unwrap(); let base_url = Url::parse("https://github.com").unwrap();
@ -127,7 +128,8 @@ mod tests {
.await .await
.unwrap(); .unwrap();
assert!(!scrapper.is_empty()); assert!(!scrapper.is_empty());
// There are 16 but we always add the favicon.ico to try in case it exists as well // There are 16 but we always add the favicon.ico to try in case it exists as
// well
assert_eq!(scrapper.len(), 16 + 1); assert_eq!(scrapper.len(), 16 + 1);
assert_eq!( assert_eq!(

View file

@ -1,6 +1,7 @@
use std::{fmt, path::PathBuf};
use percent_encoding::percent_decode_str; use percent_encoding::percent_decode_str;
use quick_xml::events::{attributes::Attribute, BytesStart, Event}; use quick_xml::events::{attributes::Attribute, BytesStart, Event};
use std::{fmt, path::PathBuf};
use tracing::debug; use tracing::debug;
use url::Url; use url::Url;

7
rustfmt.toml Normal file
View file

@ -0,0 +1,7 @@
imports_granularity = "Crate"
format_code_in_doc_comments = true
group_imports = "StdExternalCrate"
newline_style = "Unix"
normalize_comments = true
normalize_doc_attributes = true
wrap_comments = true

View file

@ -1,3 +1,12 @@
use std::{collections::HashMap, str::FromStr};
use adw::prelude::*;
use gettextrs::gettext;
use glib::clone;
use gtk::{gio, glib, subclass::prelude::*};
use gtk_macros::{action, get_action};
use search_provider::{ResultID, ResultMeta, SearchProvider, SearchProviderImpl};
use crate::{ use crate::{
config, config,
models::{ models::{
@ -6,20 +15,15 @@ use crate::{
utils::spawn_tokio_blocking, utils::spawn_tokio_blocking,
widgets::{PreferencesWindow, ProvidersDialog, Window}, widgets::{PreferencesWindow, ProvidersDialog, Window},
}; };
use adw::prelude::*;
use gettextrs::gettext;
use glib::clone;
use gtk::{gio, glib, subclass::prelude::*};
use gtk_macros::{action, get_action};
use search_provider::{ResultID, ResultMeta, SearchProvider, SearchProviderImpl};
use std::{collections::HashMap, str::FromStr};
mod imp { mod imp {
use super::*; use std::cell::{Cell, RefCell};
use adw::subclass::prelude::*; use adw::subclass::prelude::*;
use glib::{ParamSpec, ParamSpecBoolean, Value, WeakRef}; use glib::{ParamSpec, ParamSpecBoolean, Value, WeakRef};
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use std::cell::{Cell, RefCell};
use super::*;
// The basic struct that holds our state and widgets // The basic struct that holds our state and widgets
// (Ref)Cells are used for members which need to be mutable // (Ref)Cells are used for members which need to be mutable

View file

@ -3,24 +3,24 @@
//! See https://github.com/beemdevelopment/Aegis/blob/master/docs/vault.md for a description of the //! See https://github.com/beemdevelopment/Aegis/blob/master/docs/vault.md for a description of the
//! aegis vault format. //! aegis vault format.
//! //!
//! This module does not convert all information from aegis (note, icon, group are lost). When //! This module does not convert all information from aegis (note, icon, group
//! exporting to the aegis json format the icon, url, help url, and tags are lost. //! are lost). When exporting to the aegis json format the icon, url, help url,
//! and tags are lost.
//! //!
//! Exported files by this module cannot be decrypted by the python script provided in the aegis //! Exported files by this module cannot be decrypted by the python script
//! repository (https://github.com/beemdevelopment/Aegis/blob/master/docs/decrypt.py). However, //! provided in the aegis repository (https://github.com/beemdevelopment/Aegis/blob/master/docs/decrypt.py). However,
//! aegis android app is able to read the files! See line 173 for a discussion. //! aegis android app is able to read the files! See line 173 for a discussion.
use super::{Backupable, Restorable, RestorableItem}; use aes_gcm::{aead::Aead, NewAead};
use crate::models::{Account, Algorithm, OTPMethod, Provider, ProvidersModel}; use anyhow::{Context, Result};
use aes_gcm::aead::Aead;
use aes_gcm::NewAead;
use anyhow::Context;
use anyhow::Result;
use gettextrs::gettext; use gettextrs::gettext;
use gtk::{glib::Cast, prelude::*}; use gtk::{glib::Cast, prelude::*};
use rand::RngCore; use rand::RngCore;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::{Backupable, Restorable, RestorableItem};
use crate::models::{Account, Algorithm, OTPMethod, Provider, ProvidersModel};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
pub enum Aegis { pub enum Aegis {
@ -49,7 +49,8 @@ impl Default for AegisPlainText {
} }
} }
/// Encrypted version of the JSON format. `db` is simply a base64 encoded string with an encrypted AegisDatabase. /// Encrypted version of the JSON format. `db` is simply a base64 encoded string
/// with an encrypted AegisDatabase.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AegisEncrypted { pub struct AegisEncrypted {
version: u32, version: u32,
@ -85,8 +86,8 @@ impl Aegis {
slots: Some(vec![HeaderSlot::default()]), slots: Some(vec![HeaderSlot::default()]),
}; };
// We only support password encrypted database so far so we don't have to do any checks // We only support password encrypted database so far so we don't have to do any
// for the slot type // checks for the slot type
let mut password_slot = &mut header.slots.as_mut().unwrap().get_mut(0).unwrap(); let mut password_slot = &mut header.slots.as_mut().unwrap().get_mut(0).unwrap();
// Derive key from given password // Derive key from given password
let mut derived_key: [u8; 32] = [0u8; 32]; let mut derived_key: [u8; 32] = [0u8; 32];
@ -115,7 +116,8 @@ impl Aegis {
) )
.map_err(|_| anyhow::anyhow!("Encrypter master key"))?; .map_err(|_| anyhow::anyhow!("Encrypter master key"))?;
// Add encrypted master key and tag to our password slot. If this assignment fails, we have a mistake in our logic, thus unwrap is okay. // Add encrypted master key and tag to our password slot. If this assignment
// fails, we have a mistake in our logic, thus unwrap is okay.
password_slot.key_params.tag = ciphertext.split_off(32).try_into().unwrap(); password_slot.key_params.tag = ciphertext.split_off(32).try_into().unwrap();
password_slot.key = ciphertext.try_into().unwrap(); password_slot.key = ciphertext.try_into().unwrap();
@ -153,7 +155,8 @@ impl Aegis {
/// Header of the Encrypted Aegis JSON File /// Header of the Encrypted Aegis JSON File
/// ///
/// Contains all necessary information for encrypting / decrypting the vault (db field). /// Contains all necessary information for encrypting / decrypting the vault (db
/// field).
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Header { pub struct Header {
#[serde(default)] #[serde(default)]
@ -177,9 +180,9 @@ pub struct HeaderSlot {
// //
// TODO rename should be changed to `rename = 2`. However this does not work yet with serde, // TODO rename should be changed to `rename = 2`. However this does not work yet with serde,
// see: https://github.com/serde-rs/serde/issues/745. This allows decrypting the exported file // see: https://github.com/serde-rs/serde/issues/745. This allows decrypting the exported file
// with the python script provided in the aegis repository. The python script expects an integer // with the python script provided in the aegis repository. The python script expects an
// but we provide a string. Thus, change the string in header / slots / password slot / `type = "1"` // integer but we provide a string. Thus, change the string in header / slots / password
// to `type = 1` to use the python script. // slot / `type = "1"` to `type = 1` to use the python script.
#[serde(rename = "type")] #[serde(rename = "type")]
pub type_: u32, pub type_: u32,
pub uuid: String, pub uuid: String,
@ -283,8 +286,8 @@ pub struct Item {
pub tags: Option<String>, pub tags: Option<String>,
// Note is omitted // Note is omitted
// Icon: // Icon:
// TODO: Aegis encodes icons as JPEG's encoded in Base64 with padding. Does authenticator support // TODO: Aegis encodes icons as JPEG's encoded in Base64 with padding. Does authenticator
// this? // support this?
// TODO tags are not imported/exported right now. // TODO tags are not imported/exported right now.
#[serde(rename = "icon")] #[serde(rename = "icon")]
pub thumbnail: Option<String>, pub thumbnail: Option<String>,
@ -482,8 +485,9 @@ impl Restorable for Aegis {
// Add the encryption tag // Add the encryption tag
ciphertext.append(&mut encrypted.header.params.as_ref().unwrap().tag.into()); ciphertext.append(&mut encrypted.header.params.as_ref().unwrap().tag.into());
// Find slots with type password and derive the corresponding key. This key is used // Find slots with type password and derive the corresponding key. This key is
// to decrypt the master key which in turn can be used to decrypt the database. // used to decrypt the master key which in turn can be used to
// decrypt the database.
let master_keys: Vec<Vec<u8>> = encrypted let master_keys: Vec<Vec<u8>> = encrypted
.header .header
.slots .slots
@ -494,9 +498,11 @@ impl Restorable for Aegis {
.map(|slot| -> Result<Vec<u8>> { .map(|slot| -> Result<Vec<u8>> {
tracing::info!("Found possible master key with UUID {}.", slot.uuid); tracing::info!("Found possible master key with UUID {}.", slot.uuid);
// Create parameters for scrypt function and derive decryption key for master key // Create parameters for scrypt function and derive decryption key for
// master key
// //
// Somehow, scrypt errors do not implement StdErr and cannot be converted to anyhow::Error. Should be possible but don't know why it doesn't work. // Somehow, scrypt errors do not implement StdErr and cannot be converted to
// anyhow::Error. Should be possible but don't know why it doesn't work.
let params = scrypt::Params::new( let params = scrypt::Params::new(
// TODO log2 for u64 is not stable yet. Change this in the future. // TODO log2 for u64 is not stable yet. Change this in the future.
(slot.n() as f64).log2() as u8, // Defaults to 15 by aegis (slot.n() as f64).log2() as u8, // Defaults to 15 by aegis
@ -518,7 +524,8 @@ impl Restorable for Aegis {
let mut ciphertext: Vec<u8> = slot.key.to_vec(); let mut ciphertext: Vec<u8> = slot.key.to_vec();
ciphertext.append(&mut slot.key_params.tag.to_vec()); ciphertext.append(&mut slot.key_params.tag.to_vec());
// Here we get the master key. The decrypt function does not return an error implementing std error. Thus, we have to convert it. // Here we get the master key. The decrypt function does not return an error
// implementing std error. Thus, we have to convert it.
cipher cipher
.decrypt( .decrypt(
aes_gcm::Nonce::from_slice(&slot.key_params.nonce), aes_gcm::Nonce::from_slice(&slot.key_params.nonce),
@ -526,7 +533,9 @@ impl Restorable for Aegis {
) )
.map_err(|_| anyhow::anyhow!("Cannot decrypt master key")) .map_err(|_| anyhow::anyhow!("Cannot decrypt master key"))
}) })
// Here, we don't want to fail the whole function because one key slot failed to get the correct master key. Maybe there is another slot we were able to decrypt. // Here, we don't want to fail the whole function because one key slot failed to
// get the correct master key. Maybe there is another slot we were able to
// decrypt.
.filter_map(|x| match x { .filter_map(|x| match x {
Ok(x) => Some(x), Ok(x) => Some(x),
Err(e) => { Err(e) => {
@ -536,7 +545,8 @@ impl Restorable for Aegis {
}) })
.collect(); .collect();
// Choose the first valid master key. I don't think there are aegis installations with two valid password slots. // Choose the first valid master key. I don't think there are aegis
// installations with two valid password slots.
tracing::info!( tracing::info!(
"Found {} valid password slots / master keys.", "Found {} valid password slots / master keys.",
master_keys.len() master_keys.len()

View file

@ -1,10 +1,11 @@
use super::{Backupable, Restorable, RestorableItem};
use crate::models::{Account, Algorithm, OTPMethod, Provider, ProvidersModel};
use anyhow::Result; use anyhow::Result;
use gettextrs::gettext; use gettextrs::gettext;
use gtk::{glib::Cast, prelude::*}; use gtk::{glib::Cast, prelude::*};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::{Backupable, Restorable, RestorableItem};
use crate::models::{Account, Algorithm, OTPMethod, Provider, ProvidersModel};
#[allow(clippy::upper_case_acronyms)] #[allow(clippy::upper_case_acronyms)]
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AndOTP { pub struct AndOTP {

View file

@ -1,9 +1,11 @@
use super::{Restorable, RestorableItem}; use std::str::FromStr;
use crate::models::{Algorithm, OTPMethod, OTPUri};
use anyhow::Result; use anyhow::Result;
use gettextrs::gettext; use gettextrs::gettext;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::str::FromStr;
use super::{Restorable, RestorableItem};
use crate::models::{Algorithm, OTPMethod, OTPUri};
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Bitwarden { pub struct Bitwarden {

View file

@ -1,10 +1,12 @@
use super::{Backupable, Restorable}; use std::str::FromStr;
use crate::models::{Account, OTPUri, Provider, ProvidersModel};
use anyhow::Result; use anyhow::Result;
use gettextrs::gettext; use gettextrs::gettext;
use gtk::prelude::*; use gtk::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::str::FromStr;
use super::{Backupable, Restorable};
use crate::models::{Account, OTPUri, Provider, ProvidersModel};
#[allow(clippy::upper_case_acronyms)] #[allow(clippy::upper_case_acronyms)]
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]

View file

@ -1,12 +1,14 @@
use super::Restorable; use std::borrow::Cow;
use crate::models::{Algorithm, OTPMethod, OTPUri};
use anyhow::Result; use anyhow::Result;
use gettextrs::gettext; use gettextrs::gettext;
use percent_encoding::percent_decode; use percent_encoding::percent_decode;
use prost::{Enumeration, Message}; use prost::{Enumeration, Message};
use std::borrow::Cow;
use url::Url; use url::Url;
use super::Restorable;
use crate::models::{Algorithm, OTPMethod, OTPUri};
#[derive(Default, Debug, Clone, PartialEq, Eq)] #[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct Google; pub struct Google;
@ -182,8 +184,7 @@ mod protobuf {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::super::RestorableItem; use super::{super::RestorableItem, *};
use super::*;
#[test] #[test]
fn test_google_restore_otpauth() { fn test_google_restore_otpauth() {

View file

@ -1,9 +1,10 @@
use super::{Restorable, RestorableItem};
use crate::models::{Algorithm, OTPMethod};
use anyhow::Result; use anyhow::Result;
use gettextrs::gettext; use gettextrs::gettext;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::{Restorable, RestorableItem};
use crate::models::{Algorithm, OTPMethod};
// Same as andOTP except uses the first tag for the issuer // Same as andOTP except uses the first tag for the issuer
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct LegacyAuthenticator { pub struct LegacyAuthenticator {
@ -30,7 +31,8 @@ impl Restorable for LegacyAuthenticator {
} }
fn title() -> String { fn title() -> String {
// Translators: this is for restoring a backup from the old Authenticator release // Translators: this is for restoring a backup from the old Authenticator
// release
gettext("Au_thenticator (Legacy)") gettext("Au_thenticator (Legacy)")
} }

View file

@ -1,9 +1,10 @@
use std::fmt::Debug; use std::fmt::Debug;
use crate::models::{Account, Algorithm, OTPMethod, ProvidersModel};
use anyhow::Result; use anyhow::Result;
use gtk::{gio, gio::prelude::*}; use gtk::{gio, gio::prelude::*};
use crate::models::{Account, Algorithm, OTPMethod, ProvidersModel};
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub enum Operation { pub enum Operation {
Backup, Backup,
@ -23,16 +24,17 @@ pub trait Restorable: Sized {
fn subtitle() -> String; fn subtitle() -> String;
fn identifier() -> String; fn identifier() -> String;
/// Restore many items from a slice of data, optionally using a key to unencrypt it. /// Restore many items from a slice of data, optionally using a key to
/// unencrypt it.
/// ///
/// If `key` is `None`, then the implementation should assume that the slice is unencrypted, and /// If `key` is `None`, then the implementation should assume that the slice
/// error if it only supports encrypted slices. /// is unencrypted, and error if it only supports encrypted slices.
fn restore_from_data(from: &[u8], key: Option<&str>) -> Result<Vec<Self::Item>>; fn restore_from_data(from: &[u8], key: Option<&str>) -> Result<Vec<Self::Item>>;
/// Restore many items from a file, optiontally using a key to unencrypt it. /// Restore many items from a file, optiontally using a key to unencrypt it.
/// ///
/// If `key` is `None`, then the implementation should assume that the file is unencrypted, and /// If `key` is `None`, then the implementation should assume that the file
/// error if it only supports encrypted files. /// is unencrypted, and error if it only supports encrypted files.
/// ///
/// By default, this method reads the file and passes the files content to /// By default, this method reads the file and passes the files content to
/// `Self::restore_from_data`. /// `Self::restore_from_data`.

View file

@ -1,3 +1,13 @@
use core::cmp::Ordering;
use std::cell::{Cell, RefCell};
use anyhow::{Context, Result};
use diesel::{BelongingToDsl, ExpressionMethods, QueryDsl, RunQueryDsl};
use glib::{clone, Cast, StaticType, ToValue};
use gtk::{glib, prelude::*, subclass::prelude::*};
use once_cell::sync::OnceCell;
use unicase::UniCase;
use super::{ use super::{
provider::{DiProvider, Provider}, provider::{DiProvider, Provider},
OTPMethod, OTPUri, RUNTIME, OTPMethod, OTPUri, RUNTIME,
@ -8,14 +18,6 @@ use crate::{
utils::spawn_tokio_blocking, utils::spawn_tokio_blocking,
widgets::QRCodeData, widgets::QRCodeData,
}; };
use anyhow::{Context, Result};
use core::cmp::Ordering;
use diesel::{BelongingToDsl, ExpressionMethods, QueryDsl, RunQueryDsl};
use glib::{clone, Cast, StaticType, ToValue};
use gtk::{glib, prelude::*, subclass::prelude::*};
use once_cell::sync::OnceCell;
use std::cell::{Cell, RefCell};
use unicase::UniCase;
#[derive(Insertable)] #[derive(Insertable)]
#[table_name = "accounts"] #[table_name = "accounts"]
@ -39,9 +41,10 @@ pub struct DiAccount {
#[doc(hidden)] #[doc(hidden)]
mod imp { mod imp {
use super::*;
use glib::{ParamSpec, ParamSpecObject, ParamSpecString, ParamSpecUInt, Value}; use glib::{ParamSpec, ParamSpecObject, ParamSpecString, ParamSpecUInt, Value};
use super::*;
pub struct Account { pub struct Account {
pub id: Cell<u32>, pub id: Cell<u32>,
pub otp: RefCell<String>, pub otp: RefCell<String>,

View file

@ -1,9 +1,10 @@
use gtk::glib; use gtk::glib;
mod imp { mod imp {
use gtk::subclass::prelude::*;
use super::*; use super::*;
use crate::models::Account; use crate::models::Account;
use gtk::subclass::prelude::*;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct AccountSorter; pub struct AccountSorter;

View file

@ -1,11 +1,13 @@
use super::account::Account;
use glib::StaticType; use glib::StaticType;
use gtk::{gio, glib, prelude::*, subclass::prelude::*}; use gtk::{gio, glib, prelude::*, subclass::prelude::*};
use super::account::Account;
mod imp { mod imp {
use super::*;
use std::cell::RefCell; use std::cell::RefCell;
use super::*;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct AccountsModel(pub RefCell<Vec<Account>>); pub struct AccountsModel(pub RefCell<Vec<Account>>);

View file

@ -1,8 +1,9 @@
use std::{str::FromStr, string::ToString};
use gettextrs::gettext; use gettextrs::gettext;
use gtk::glib; use gtk::glib;
use ring::hmac; use ring::hmac;
use serde::{de::Deserializer, ser::Serializer, Deserialize, Serialize}; use serde::{de::Deserializer, ser::Serializer, Deserialize, Serialize};
use std::{str::FromStr, string::ToString};
#[allow(clippy::upper_case_acronyms)] #[allow(clippy::upper_case_acronyms)]
#[derive(Debug, Eq, PartialEq, Clone, Copy, glib::Enum)] #[derive(Debug, Eq, PartialEq, Clone, Copy, glib::Enum)]

View file

@ -1,7 +1,8 @@
use std::{fs, fs::File, path::PathBuf};
use anyhow::Result; use anyhow::Result;
use diesel::{prelude::*, r2d2, r2d2::ConnectionManager}; use diesel::{prelude::*, r2d2, r2d2::ConnectionManager};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::{fs, fs::File, path::PathBuf};
type Pool = r2d2::Pool<ConnectionManager<SqliteConnection>>; type Pool = r2d2::Pool<ConnectionManager<SqliteConnection>>;

View file

@ -1,7 +1,9 @@
use crate::config; use std::collections::HashMap;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use rand::RngCore; use rand::RngCore;
use std::collections::HashMap;
use crate::config;
pub static SECRET_SERVICE: OnceCell<oo7::Keyring> = OnceCell::new(); pub static SECRET_SERVICE: OnceCell<oo7::Keyring> = OnceCell::new();

View file

@ -1,8 +1,12 @@
use super::Algorithm; use std::{
convert::TryInto,
time::{SystemTime, UNIX_EPOCH},
};
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use ring::hmac; use ring::hmac;
use std::convert::TryInto;
use std::time::{SystemTime, UNIX_EPOCH}; use super::Algorithm;
pub static STEAM_CHARS: &str = "23456789BCDFGHJKMNPQRTVWXY"; pub static STEAM_CHARS: &str = "23456789BCDFGHJKMNPQRTVWXY";
pub static STEAM_DEFAULT_PERIOD: u32 = 30; pub static STEAM_DEFAULT_PERIOD: u32 = 30;

View file

@ -1,11 +1,12 @@
use std::{fmt::Write, str::FromStr};
use percent_encoding::percent_decode_str;
use url::Url;
use crate::{ use crate::{
backup::RestorableItem, backup::RestorableItem,
models::{otp, Account, Algorithm, OTPMethod}, models::{otp, Account, Algorithm, OTPMethod},
}; };
use percent_encoding::percent_decode_str;
use std::fmt::Write;
use std::str::FromStr;
use url::Url;
#[allow(clippy::upper_case_acronyms)] #[allow(clippy::upper_case_acronyms)]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View file

@ -1,22 +1,24 @@
use super::algorithm::{Algorithm, OTPMethod};
use crate::{
models::{database, otp, Account, AccountsModel, FAVICONS_PATH},
schema::providers,
};
use anyhow::Result;
use core::cmp::Ordering; use core::cmp::Ordering;
use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl};
use glib::{clone, Cast, StaticType, ToValue};
use gtk::{gdk_pixbuf, gio, glib, prelude::*, subclass::prelude::*};
use std::{ use std::{
cell::{Cell, RefCell}, cell::{Cell, RefCell},
str::FromStr, str::FromStr,
string::ToString, string::ToString,
time::{SystemTime, UNIX_EPOCH}, time::{SystemTime, UNIX_EPOCH},
}; };
use anyhow::Result;
use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl};
use glib::{clone, Cast, StaticType, ToValue};
use gtk::{gdk_pixbuf, gio, glib, prelude::*, subclass::prelude::*};
use unicase::UniCase; use unicase::UniCase;
use url::Url; use url::Url;
use super::algorithm::{Algorithm, OTPMethod};
use crate::{
models::{database, otp, Account, AccountsModel, FAVICONS_PATH},
schema::providers,
};
#[derive(Debug)] #[derive(Debug)]
pub struct ProviderPatch { pub struct ProviderPatch {
pub name: String, pub name: String,
@ -60,10 +62,11 @@ pub struct DiProvider {
pub method: String, pub method: String,
} }
mod imp { mod imp {
use super::*;
use glib::{ParamSpec, ParamSpecObject, ParamSpecString, ParamSpecUInt, Value}; use glib::{ParamSpec, ParamSpecObject, ParamSpecString, ParamSpecUInt, Value};
use gst::glib::{ParamSpecUInt64, SourceId}; use gst::glib::{ParamSpecUInt64, SourceId};
use super::*;
pub struct Provider { pub struct Provider {
pub id: Cell<u32>, pub id: Cell<u32>,
pub name: RefCell<String>, pub name: RefCell<String>,
@ -387,8 +390,8 @@ impl Provider {
let icon_name = glib::base64_encode(icon_name.as_bytes()); let icon_name = glib::base64_encode(icon_name.as_bytes());
let small_icon_name = format!("{icon_name}_32x32"); let small_icon_name = format!("{icon_name}_32x32");
let large_icon_name = format!("{icon_name}_96x96"); let large_icon_name = format!("{icon_name}_96x96");
// TODO: figure out why trying to grab icons at specific size causes stack size errors // TODO: figure out why trying to grab icons at specific size causes stack size
// We need two sizes: // errors We need two sizes:
// - 32x32 for the accounts lists // - 32x32 for the accounts lists
// - 96x96 elsewhere // - 96x96 elsewhere
if let Some(best_favicon) = favicon.find_best().await { if let Some(best_favicon) = favicon.find_best().await {

View file

@ -1,10 +1,12 @@
use super::provider::Provider;
use gtk::glib; use gtk::glib;
use super::provider::Provider;
mod imp { mod imp {
use super::*;
use gtk::subclass::prelude::*; use gtk::subclass::prelude::*;
use super::*;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct ProviderSorter; pub struct ProviderSorter;

View file

@ -1,12 +1,14 @@
use super::{otp, Account, Algorithm, OTPMethod, Provider, ProviderPatch};
use anyhow::Result; use anyhow::Result;
use glib::StaticType; use glib::StaticType;
use gtk::{gio, glib, prelude::*, subclass::prelude::*}; use gtk::{gio, glib, prelude::*, subclass::prelude::*};
use super::{otp, Account, Algorithm, OTPMethod, Provider, ProviderPatch};
mod imp { mod imp {
use super::*;
use std::cell::RefCell; use std::cell::RefCell;
use super::*;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct ProvidersModel(pub RefCell<Vec<Provider>>); pub struct ProvidersModel(pub RefCell<Vec<Provider>>);
@ -60,8 +62,9 @@ impl ProvidersModel {
) -> Result<Provider> { ) -> Result<Provider> {
let provider = match self.find_by_name(name) { let provider = match self.find_by_name(name) {
Some(p) => { Some(p) => {
// Update potenitally different properties than what we have in the pre-shipped database // Update potenitally different properties than what we have in the pre-shipped
// Note this does a comparaison first to avoid a uselesss rewrite // database Note this does a comparaison first to avoid a
// uselesss rewrite
p.update(&ProviderPatch { p.update(&ProviderPatch {
name: name.to_owned(), name: name.to_owned(),
website, website,

View file

@ -1,21 +1,24 @@
use crate::{ use std::str::FromStr;
models::{otp, Account, OTPMethod, OTPUri, Provider, ProvidersModel},
widgets::{Camera, ErrorRevealer, ProviderImage, UrlRow},
};
use anyhow::Result; use anyhow::Result;
use gettextrs::gettext; use gettextrs::gettext;
use glib::{clone, signal::Inhibit}; use glib::{clone, signal::Inhibit};
use gtk::{glib, prelude::*, subclass::prelude::*, CompositeTemplate}; use gtk::{glib, prelude::*, subclass::prelude::*, CompositeTemplate};
use gtk_macros::spawn; use gtk_macros::spawn;
use once_cell::sync::{Lazy, OnceCell}; use once_cell::sync::{Lazy, OnceCell};
use std::str::FromStr;
use crate::{
models::{otp, Account, OTPMethod, OTPUri, Provider, ProvidersModel},
widgets::{Camera, ErrorRevealer, ProviderImage, UrlRow},
};
mod imp { mod imp {
use crate::widgets::providers::ProviderPage; use std::cell::RefCell;
use glib::subclass::{InitializingObject, Signal};
use super::*; use super::*;
use glib::subclass::{InitializingObject, Signal}; use crate::widgets::providers::ProviderPage;
use std::cell::RefCell;
#[derive(Debug, Default, CompositeTemplate)] #[derive(Debug, Default, CompositeTemplate)]
#[template(resource = "/com/belmoussaoui/Authenticator/account_add.ui")] #[template(resource = "/com/belmoussaoui/Authenticator/account_add.ui")]
@ -269,8 +272,9 @@ impl AccountAddDialog {
}), }),
); );
// in case the provider doesn't exists, let the user create a new one by showing a dialog for that // in case the provider doesn't exists, let the user create a new one by showing
// TODO: replace this whole completion provider thing with a custom widget // a dialog for that TODO: replace this whole completion provider thing
// with a custom widget
imp.provider_completion.connect_no_matches(clone!(@weak self as dialog => move |completion| { imp.provider_completion.connect_no_matches(clone!(@weak self as dialog => move |completion| {
let imp = dialog.imp(); let imp = dialog.imp();
let model = imp.model.get().unwrap(); let model = imp.model.get().unwrap();

View file

@ -1,8 +1,3 @@
use super::qrcode_paintable::QRCodePaintable;
use crate::{
models::{Account, OTPMethod, Provider, ProvidersModel},
widgets::UrlRow,
};
use gettextrs::gettext; use gettextrs::gettext;
use gtk::{ use gtk::{
gdk, gdk,
@ -11,17 +6,24 @@ use gtk::{
subclass::prelude::*, subclass::prelude::*,
CompositeTemplate, CompositeTemplate,
}; };
use super::qrcode_paintable::QRCodePaintable;
use crate::{
models::{Account, OTPMethod, Provider, ProvidersModel},
widgets::UrlRow,
};
mod imp { mod imp {
use std::cell::RefCell;
use glib::subclass::{self, Signal};
use once_cell::sync::{Lazy, OnceCell};
use super::*;
use crate::{ use crate::{
models::Provider, models::Provider,
widgets::{editable_label::EditableSpin, EditableLabel}, widgets::{editable_label::EditableSpin, EditableLabel},
}; };
use super::*;
use glib::subclass::{self, Signal};
use once_cell::sync::{Lazy, OnceCell};
use std::cell::RefCell;
#[derive(Debug, Default, CompositeTemplate)] #[derive(Debug, Default, CompositeTemplate)]
#[template(resource = "/com/belmoussaoui/Authenticator/account_details_page.ui")] #[template(resource = "/com/belmoussaoui/Authenticator/account_details_page.ui")]
pub struct AccountDetailsPage { pub struct AccountDetailsPage {

View file

@ -3,6 +3,7 @@ mod details;
mod qrcode_paintable; mod qrcode_paintable;
mod row; mod row;
pub use self::{add::AccountAddDialog, row::AccountRow};
pub use details::AccountDetailsPage; pub use details::AccountDetailsPage;
pub use qrcode_paintable::{QRCodeData, QRCodePaintable}; pub use qrcode_paintable::{QRCodeData, QRCodePaintable};
pub use self::{add::AccountAddDialog, row::AccountRow};

View file

@ -63,9 +63,10 @@ mod imp {
}); });
}); });
} }
use super::*;
use std::cell::RefCell; use std::cell::RefCell;
use super::*;
#[allow(clippy::upper_case_acronyms)] #[allow(clippy::upper_case_acronyms)]
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct QRCodePaintable { pub struct QRCodePaintable {

View file

@ -1,16 +1,18 @@
use crate::models::{Account, OTPMethod};
use gtk::{gdk, glib, prelude::*, subclass::prelude::*, CompositeTemplate};
use std::cell::RefCell; use std::cell::RefCell;
mod imp { use gtk::{gdk, glib, prelude::*, subclass::prelude::*, CompositeTemplate};
use crate::widgets::Window;
use super::*; use crate::models::{Account, OTPMethod};
mod imp {
use adw::subclass::prelude::*; use adw::subclass::prelude::*;
use gettextrs::gettext; use gettextrs::gettext;
use glib::{subclass, ParamSpec, ParamSpecObject, Value}; use glib::{subclass, ParamSpec, ParamSpecObject, Value};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use super::*;
use crate::widgets::Window;
#[derive(Debug, Default, CompositeTemplate)] #[derive(Debug, Default, CompositeTemplate)]
#[template(resource = "/com/belmoussaoui/Authenticator/account_row.ui")] #[template(resource = "/com/belmoussaoui/Authenticator/account_row.ui")]
pub struct AccountRow { pub struct AccountRow {

View file

@ -1,4 +1,8 @@
use crate::widgets::CameraPaintable; use std::{
cell::{Cell, RefCell},
os::unix::prelude::RawFd,
};
use adw::subclass::prelude::*; use adw::subclass::prelude::*;
use anyhow::Result; use anyhow::Result;
use ashpd::{desktop::screenshot::ScreenshotProxy, zbus}; use ashpd::{desktop::screenshot::ScreenshotProxy, zbus};
@ -17,10 +21,10 @@ use gtk::{
use gtk_macros::spawn; use gtk_macros::spawn;
use image::GenericImageView; use image::GenericImageView;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::cell::{Cell, RefCell};
use std::os::unix::prelude::RawFd;
use zbar_rust::ZBarImageScanner; use zbar_rust::ZBarImageScanner;
use crate::widgets::CameraPaintable;
mod screenshot { mod screenshot {
use super::*; use super::*;

View file

@ -1,17 +1,18 @@
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use crate::widgets::camera::CameraEvent;
use gst::prelude::*; use gst::prelude::*;
use gtk::prelude::*;
use gtk::subclass::prelude::*;
use gtk::{ use gtk::{
gdk, gdk,
glib::{self, clone, Sender}, glib::{self, clone, Sender},
graphene, graphene,
prelude::*,
subclass::prelude::*,
}; };
use gtk_macros::send; use gtk_macros::send;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use tracing::error; use tracing::error;
use crate::widgets::camera::CameraEvent;
static PIPELINE_NAME: Lazy<glib::GString> = Lazy::new(|| glib::GString::from("camera")); static PIPELINE_NAME: Lazy<glib::GString> = Lazy::new(|| glib::GString::from("camera"));
/// Fancy Camera with QR code detection using ZBar /// Fancy Camera with QR code detection using ZBar
/// ///
@ -21,8 +22,6 @@ static PIPELINE_NAME: Lazy<glib::GString> = Lazy::new(|| glib::GString::from("ca
/// pipewiresrc -- tee /// pipewiresrc -- tee
/// \ /// \
/// queue -- glsinkbin /// queue -- glsinkbin
///
///
mod imp { mod imp {
use std::cell::RefCell; use std::cell::RefCell;
@ -74,7 +73,8 @@ mod imp {
) { ) {
let snapshot = snapshot.downcast_ref::<gtk::Snapshot>().unwrap(); let snapshot = snapshot.downcast_ref::<gtk::Snapshot>().unwrap();
if let Some(ref image) = *self.sink_paintable.borrow() { if let Some(ref image) = *self.sink_paintable.borrow() {
// Transformation to avoid stretching the camera. We translate and scale the image. // Transformation to avoid stretching the camera. We translate and scale the
// image.
let aspect = width / height.max(std::f64::EPSILON); // Do not divide by zero. let aspect = width / height.max(std::f64::EPSILON); // Do not divide by zero.
let image_aspect = image.intrinsic_aspect_ratio(); let image_aspect = image.intrinsic_aspect_ratio();

View file

@ -1,9 +1,10 @@
use gtk::{glib, prelude::*, subclass::prelude::*}; use gtk::{glib, prelude::*, subclass::prelude::*};
mod imp { mod imp {
use super::*;
use adw::subclass::prelude::*; use adw::subclass::prelude::*;
use super::*;
#[derive(Debug, Default, gtk::CompositeTemplate)] #[derive(Debug, Default, gtk::CompositeTemplate)]
#[template(resource = "/com/belmoussaoui/Authenticator/editable_label.ui")] #[template(resource = "/com/belmoussaoui/Authenticator/editable_label.ui")]
pub struct EditableLabel { pub struct EditableLabel {

View file

@ -1,10 +1,11 @@
use gtk::{glib, prelude::*, subclass::prelude::*}; use gtk::{glib, prelude::*, subclass::prelude::*};
mod imp { mod imp {
use super::*;
use glib::subclass; use glib::subclass;
use gtk::CompositeTemplate; use gtk::CompositeTemplate;
use super::*;
#[derive(Debug, Default, CompositeTemplate)] #[derive(Debug, Default, CompositeTemplate)]
#[template(resource = "/com/belmoussaoui/Authenticator/error_revealer.ui")] #[template(resource = "/com/belmoussaoui/Authenticator/error_revealer.ui")]
pub struct ErrorRevealer { pub struct ErrorRevealer {

View file

@ -1,4 +1,5 @@
use crate::{utils::spawn_tokio, widgets::Camera}; use std::{cell::Cell, rc::Rc};
use adw::subclass::prelude::*; use adw::subclass::prelude::*;
use anyhow::Result; use anyhow::Result;
use gtk::{ use gtk::{
@ -10,14 +11,14 @@ use gtk::{
}; };
use gtk_macros::get_action; use gtk_macros::get_action;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use std::cell::Cell;
use std::rc::Rc;
use tokio::{ use tokio::{
select, select,
sync::oneshot, sync::oneshot,
time::{sleep, Duration}, time::{sleep, Duration},
}; };
use crate::{utils::spawn_tokio, widgets::Camera};
mod imp { mod imp {
use super::*; use super::*;
@ -67,8 +68,8 @@ impl CameraPage {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
// This is required because for whatever reason `glib::clone!` wouldn't let it be moved into // This is required because for whatever reason `glib::clone!` wouldn't let it
// the closure. // be moved into the closure.
let tx = Rc::new(Cell::new(Some(tx))); let tx = Rc::new(Cell::new(Some(tx)));
// This is to make it safe to access `src` inside of the connected closure to // This is to make it safe to access `src` inside of the connected closure to
@ -121,8 +122,8 @@ impl CameraPage {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
// This is required because for whatever reason `glib::clone!` wouldn't let it be moved into // This is required because for whatever reason `glib::clone!` wouldn't let it
// the closure. // be moved into the closure.
let tx = Rc::new(Cell::new(Some(tx))); let tx = Rc::new(Cell::new(Some(tx)));
// This is to make it safe to access `src` inside of the connected closure to // This is to make it safe to access `src` inside of the connected closure to

View file

@ -1,4 +1,5 @@
use crate::{config, models::keyring, utils::spawn_tokio, widgets::ErrorRevealer}; use std::cell::{Cell, RefCell};
use gettextrs::gettext; use gettextrs::gettext;
use gtk::{ use gtk::{
gio, gio,
@ -9,7 +10,8 @@ use gtk::{
}; };
use gtk_macros::{action, get_action}; use gtk_macros::{action, get_action};
use once_cell::sync::{Lazy, OnceCell}; use once_cell::sync::{Lazy, OnceCell};
use std::cell::{Cell, RefCell};
use crate::{config, models::keyring, utils::spawn_tokio, widgets::ErrorRevealer};
mod imp { mod imp {
use super::*; use super::*;

View file

@ -1,5 +1,11 @@
use super::camera_page::CameraPage; use adw::prelude::*;
use super::password_page::PasswordPage; use gettextrs::gettext;
use glib::clone;
use gtk::{gio, glib, subclass::prelude::*, CompositeTemplate};
use gtk_macros::{action, get_action, spawn};
use once_cell::sync::OnceCell;
use super::{camera_page::CameraPage, password_page::PasswordPage};
use crate::{ use crate::{
backup::{ backup::{
Aegis, AndOTP, Backupable, Bitwarden, FreeOTP, Google, LegacyAuthenticator, Operation, Aegis, AndOTP, Backupable, Bitwarden, FreeOTP, Google, LegacyAuthenticator, Operation,
@ -8,23 +14,21 @@ use crate::{
config, config,
models::ProvidersModel, models::ProvidersModel,
}; };
use adw::prelude::*;
use gettextrs::gettext;
use glib::clone;
use gtk::{gio, glib, subclass::prelude::*, CompositeTemplate};
use gtk_macros::{action, get_action, spawn};
use once_cell::sync::OnceCell;
mod imp { mod imp {
use super::*; use std::{
cell::{Cell, RefCell},
collections::HashMap,
};
use adw::subclass::{preferences_window::PreferencesWindowImpl, window::AdwWindowImpl}; use adw::subclass::{preferences_window::PreferencesWindowImpl, window::AdwWindowImpl};
use glib::{ use glib::{
subclass::{self, Signal}, subclass::{self, Signal},
ParamSpec, ParamSpecBoolean, Value, ParamSpec, ParamSpecBoolean, Value,
}; };
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::cell::{Cell, RefCell};
use std::collections::HashMap; use super::*;
#[derive(Debug, CompositeTemplate)] #[derive(Debug, CompositeTemplate)]
#[template(resource = "/com/belmoussaoui/Authenticator/preferences.ui")] #[template(resource = "/com/belmoussaoui/Authenticator/preferences.ui")]
@ -197,8 +201,9 @@ impl PreferencesWindow {
}), }),
); );
// FreeOTP is first in all of these lists, since its the way to backup Authenticator for use // FreeOTP is first in all of these lists, since its the way to backup
// with Authenticator. Others are sorted alphabetically. // Authenticator for use with Authenticator. Others are sorted
// alphabetically.
self.register_backup::<FreeOTP>(&["text/plain"]); self.register_backup::<FreeOTP>(&["text/plain"]);
self.register_backup::<Aegis>(&["application/json"]); self.register_backup::<Aegis>(&["application/json"]);

View file

@ -1,13 +1,13 @@
use gtk::prelude::*; use gtk::{gdk, glib, prelude::*, subclass::prelude::*};
use gtk::subclass::prelude::*;
use gtk::{gdk, glib};
pub(crate) mod imp { pub(crate) mod imp {
use super::*; use std::cell::Cell;
use glib::{ParamSpec, ParamSpecFloat, Value}; use glib::{ParamSpec, ParamSpecFloat, Value};
use gtk::{graphene, gsk}; use gtk::{graphene, gsk};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::cell::Cell;
use super::*;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct ProgressIcon { pub struct ProgressIcon {

View file

@ -1,11 +1,12 @@
use super::ProviderPage;
use crate::models::{Provider, ProviderSorter, ProvidersModel};
use adw::{prelude::*, subclass::prelude::*}; use adw::{prelude::*, subclass::prelude::*};
use gettextrs::gettext; use gettextrs::gettext;
use glib::clone; use glib::clone;
use gtk::{glib, pango, subclass::prelude::*, CompositeTemplate}; use gtk::{glib, pango, subclass::prelude::*, CompositeTemplate};
use row::ProviderActionRow; use row::ProviderActionRow;
use super::ProviderPage;
use crate::models::{Provider, ProviderSorter, ProvidersModel};
enum View { enum View {
List, List,
Form, Form,
@ -13,12 +14,12 @@ enum View {
} }
mod imp { mod imp {
use crate::config;
use super::*;
use adw::subclass::window::AdwWindowImpl; use adw::subclass::window::AdwWindowImpl;
use glib::subclass::{self, Signal}; use glib::subclass::{self, Signal};
use super::*;
use crate::config;
#[derive(Debug, Default, CompositeTemplate)] #[derive(Debug, Default, CompositeTemplate)]
#[template(resource = "/com/belmoussaoui/Authenticator/providers_dialog.ui")] #[template(resource = "/com/belmoussaoui/Authenticator/providers_dialog.ui")]
pub struct ProvidersDialog { pub struct ProvidersDialog {
@ -222,7 +223,8 @@ impl ProvidersDialog {
fn add_provider(&self) { fn add_provider(&self) {
self.set_view(View::Form); self.set_view(View::Form);
// By not setting the current provider we implicitly say it's for creating a new one // By not setting the current provider we implicitly say it's for creating a new
// one
self.imp().page.set_provider(None); self.imp().page.set_provider(None);
} }
@ -256,10 +258,12 @@ impl ProvidersDialog {
mod row { mod row {
use super::*; use super::*;
mod imp { mod imp {
use super::*;
use glib::{ParamSpec, ParamSpecObject, Value};
use std::cell::RefCell; use std::cell::RefCell;
use glib::{ParamSpec, ParamSpecObject, Value};
use super::*;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct ProviderActionRow { pub struct ProviderActionRow {
pub provider: RefCell<Option<Provider>>, pub provider: RefCell<Option<Provider>>,

View file

@ -1,20 +1,22 @@
use crate::models::RUNTIME;
use crate::models::{Provider, FAVICONS_PATH};
use glib::{clone, Receiver, Sender}; use glib::{clone, Receiver, Sender};
use gtk::{gio, glib, prelude::*, subclass::prelude::*, CompositeTemplate}; use gtk::{gio, glib, prelude::*, subclass::prelude::*, CompositeTemplate};
use gtk_macros::send; use gtk_macros::send;
use tracing::error; use tracing::error;
use crate::models::{Provider, FAVICONS_PATH, RUNTIME};
pub enum ImageAction { pub enum ImageAction {
Ready(String), Ready(String),
Failed, Failed,
} }
mod imp { mod imp {
use super::*;
use glib::{subclass, ParamSpec, ParamSpecObject, ParamSpecUInt, Value};
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use glib::{subclass, ParamSpec, ParamSpecObject, ParamSpecUInt, Value};
use super::*;
#[derive(Debug, CompositeTemplate)] #[derive(Debug, CompositeTemplate)]
#[template(resource = "/com/belmoussaoui/Authenticator/provider_image.ui")] #[template(resource = "/com/belmoussaoui/Authenticator/provider_image.ui")]
pub struct ProviderImage { pub struct ProviderImage {
@ -265,7 +267,7 @@ impl ProviderImage {
fn do_action(&self, action: ImageAction) -> glib::Continue { fn do_action(&self, action: ImageAction) -> glib::Continue {
let imp = self.imp(); let imp = self.imp();
let image_path = match action { let image_path = match action {
//TODO: handle network failure and other errors differently // TODO: handle network failure and other errors differently
ImageAction::Failed => { ImageAction::Failed => {
imp.image.set_from_icon_name(Some("provider-fallback")); imp.image.set_from_icon_name(Some("provider-fallback"));
"invalid".to_string() "invalid".to_string()

View file

@ -1,9 +1,10 @@
use glib::clone;
use gtk::{glib, prelude::*, subclass::prelude::*, CompositeTemplate};
use crate::{ use crate::{
models::{Account, Provider, ProviderSorter, ProvidersModel}, models::{Account, Provider, ProviderSorter, ProvidersModel},
widgets::providers::ProviderRow, widgets::providers::ProviderRow,
}; };
use glib::clone;
use gtk::{glib, prelude::*, subclass::prelude::*, CompositeTemplate};
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum ProvidersListView { pub enum ProvidersListView {
@ -12,9 +13,10 @@ pub enum ProvidersListView {
} }
mod imp { mod imp {
use super::*;
use glib::subclass::{self, Signal}; use glib::subclass::{self, Signal};
use super::*;
#[derive(Debug, Default, CompositeTemplate)] #[derive(Debug, Default, CompositeTemplate)]
#[template(resource = "/com/belmoussaoui/Authenticator/providers_list.ui")] #[template(resource = "/com/belmoussaoui/Authenticator/providers_list.ui")]
pub struct ProvidersList { pub struct ProvidersList {

View file

@ -1,17 +1,20 @@
use crate::{
models::{i18n, otp, Algorithm, OTPMethod, Provider, ProviderPatch, FAVICONS_PATH},
widgets::{ErrorRevealer, ProviderImage},
};
use adw::prelude::*; use adw::prelude::*;
use gettextrs::gettext; use gettextrs::gettext;
use glib::{clone, translate::IntoGlib}; use glib::{clone, translate::IntoGlib};
use gtk::{gdk_pixbuf, gio, glib, subclass::prelude::*, CompositeTemplate}; use gtk::{gdk_pixbuf, gio, glib, subclass::prelude::*, CompositeTemplate};
use crate::{
models::{i18n, otp, Algorithm, OTPMethod, Provider, ProviderPatch, FAVICONS_PATH},
widgets::{ErrorRevealer, ProviderImage},
};
mod imp { mod imp {
use std::cell::RefCell;
use glib::subclass::{self, Signal};
use super::*; use super::*;
use crate::models::OTPMethod; use crate::models::OTPMethod;
use glib::subclass::{self, Signal};
use std::cell::RefCell;
#[derive(Debug, CompositeTemplate)] #[derive(Debug, CompositeTemplate)]
#[template(resource = "/com/belmoussaoui/Authenticator/provider_page.ui")] #[template(resource = "/com/belmoussaoui/Authenticator/provider_page.ui")]
@ -230,8 +233,9 @@ impl ProviderPage {
} }
} }
// Validate the information typed by the user in order to enable/disable the save action // Validate the information typed by the user in order to enable/disable the
// Note that we don't validate the urls other than: does `url` crate can parse it or not // save action Note that we don't validate the urls other than: does `url`
// crate can parse it or not
fn validate(&self) { fn validate(&self) {
let imp = self.imp(); let imp = self.imp();

View file

@ -1,19 +1,23 @@
use std::time::{SystemTime, UNIX_EPOCH};
use adw::prelude::*;
use gtk::{glib, glib::clone, subclass::prelude::*, CompositeTemplate};
use crate::{ use crate::{
models::{Account, AccountSorter, OTPMethod, Provider}, models::{Account, AccountSorter, OTPMethod, Provider},
widgets::{accounts::AccountRow, ProgressIcon, ProviderImage}, widgets::{accounts::AccountRow, ProgressIcon, ProviderImage},
}; };
use adw::prelude::*;
use gtk::{glib, glib::clone, subclass::prelude::*, CompositeTemplate};
use std::time::{SystemTime, UNIX_EPOCH};
mod imp { mod imp {
use super::*; use std::cell::RefCell;
use glib::{ use glib::{
subclass::{self, Signal}, subclass::{self, Signal},
ParamSpec, ParamSpecObject, Value, ParamSpec, ParamSpecObject, Value,
}; };
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::cell::RefCell;
use super::*;
#[derive(Debug, Default, CompositeTemplate)] #[derive(Debug, Default, CompositeTemplate)]
#[template(resource = "/com/belmoussaoui/Authenticator/provider_row.ui")] #[template(resource = "/com/belmoussaoui/Authenticator/provider_row.ui")]

View file

@ -3,10 +3,12 @@ use glib::{clone, ToValue};
use gtk::{glib, subclass::prelude::*}; use gtk::{glib, subclass::prelude::*};
mod imp { mod imp {
use super::*; use std::cell::RefCell;
use adw::subclass::prelude::*; use adw::subclass::prelude::*;
use glib::{ParamSpec, ParamSpecString, Value}; use glib::{ParamSpec, ParamSpecString, Value};
use std::cell::RefCell;
use super::*;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct UrlRow { pub struct UrlRow {

View file

@ -1,3 +1,9 @@
use gettextrs::gettext;
use glib::{clone, signal::Inhibit};
use gtk::{gio, glib, prelude::*, subclass::prelude::*, CompositeTemplate};
use gtk_macros::{action, get_action};
use once_cell::sync::OnceCell;
use crate::{ use crate::{
application::Application, application::Application,
config, config,
@ -9,11 +15,6 @@ use crate::{
AccountAddDialog, ErrorRevealer, AccountAddDialog, ErrorRevealer,
}, },
}; };
use gettextrs::gettext;
use glib::{clone, signal::Inhibit};
use gtk::{gio, glib, prelude::*, subclass::prelude::*, CompositeTemplate};
use gtk_macros::{action, get_action};
use once_cell::sync::OnceCell;
#[derive(PartialEq, Eq, Debug)] #[derive(PartialEq, Eq, Debug)]
pub enum View { pub enum View {
@ -23,10 +24,11 @@ pub enum View {
} }
mod imp { mod imp {
use super::*;
use adw::subclass::prelude::*; use adw::subclass::prelude::*;
use glib::subclass; use glib::subclass;
use super::*;
#[derive(Debug, CompositeTemplate)] #[derive(Debug, CompositeTemplate)]
#[template(resource = "/com/belmoussaoui/Authenticator/window.ui")] #[template(resource = "/com/belmoussaoui/Authenticator/window.ui")]
pub struct Window { pub struct Window {