mirror of
https://gitlab.gnome.org/World/Authenticator.git
synced 2025-03-03 16:24:40 +01:00
Make use of nightly rustfmt features
This commit is contained in:
parent
99a4bd1efe
commit
da507399ca
44 changed files with 316 additions and 212 deletions
|
@ -1,5 +1,6 @@
|
|||
use image::io::Reader as ImageReader;
|
||||
use std::{fmt, io::Cursor, path::PathBuf};
|
||||
|
||||
use image::io::Reader as ImageReader;
|
||||
use tokio::{io::AsyncWriteExt, sync::Mutex};
|
||||
use url::Url;
|
||||
|
||||
|
@ -45,8 +46,8 @@ impl Favicon {
|
|||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If the favicon contains the data instead of a URL, you are supposed to check
|
||||
/// it content using [`Favicon::is_url`]
|
||||
/// If the favicon contains the data instead of a URL, you are supposed to
|
||||
/// check it content using [`Favicon::is_url`]
|
||||
pub fn url(&self) -> &Url {
|
||||
match &self.url {
|
||||
Some(url) => url,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use url::Url;
|
||||
|
||||
use std::{fmt, path::Path};
|
||||
|
||||
use url::Url;
|
||||
|
||||
/// Supported image formats.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
|
||||
pub enum Format {
|
||||
|
@ -11,11 +11,12 @@ pub enum 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 url::Url;
|
||||
///
|
||||
/// let url = Url::parse("http://127.0.0.1:8000/favicon.ico").unwrap();
|
||||
/// 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;
|
||||
|
|
|
@ -16,9 +16,10 @@ pub use scrapper::Scrapper;
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use url::Url;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn parse_from_file() {
|
||||
let base_url = Url::parse("https://github.com").unwrap();
|
||||
|
@ -127,7 +128,8 @@ mod tests {
|
|||
.await
|
||||
.unwrap();
|
||||
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!(
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use std::{fmt, path::PathBuf};
|
||||
|
||||
use percent_encoding::percent_decode_str;
|
||||
use quick_xml::events::{attributes::Attribute, BytesStart, Event};
|
||||
use std::{fmt, path::PathBuf};
|
||||
use tracing::debug;
|
||||
use url::Url;
|
||||
|
||||
|
|
7
rustfmt.toml
Normal file
7
rustfmt.toml
Normal 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
|
|
@ -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::{
|
||||
config,
|
||||
models::{
|
||||
|
@ -6,20 +15,15 @@ use crate::{
|
|||
utils::spawn_tokio_blocking,
|
||||
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 {
|
||||
use super::*;
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
use adw::subclass::prelude::*;
|
||||
use glib::{ParamSpec, ParamSpecBoolean, Value, WeakRef};
|
||||
use once_cell::sync::OnceCell;
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
use super::*;
|
||||
|
||||
// The basic struct that holds our state and widgets
|
||||
// (Ref)Cells are used for members which need to be mutable
|
||||
|
|
|
@ -3,24 +3,24 @@
|
|||
//! See https://github.com/beemdevelopment/Aegis/blob/master/docs/vault.md for a description of the
|
||||
//! aegis vault format.
|
||||
//!
|
||||
//! This module does not convert all information from aegis (note, icon, group are lost). When
|
||||
//! exporting to the aegis json format the icon, url, help url, and tags are lost.
|
||||
//! This module does not convert all information from aegis (note, icon, group
|
||||
//! 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
|
||||
//! repository (https://github.com/beemdevelopment/Aegis/blob/master/docs/decrypt.py). However,
|
||||
//! Exported files by this module cannot be decrypted by the python script
|
||||
//! 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.
|
||||
|
||||
use super::{Backupable, Restorable, RestorableItem};
|
||||
use crate::models::{Account, Algorithm, OTPMethod, Provider, ProvidersModel};
|
||||
use aes_gcm::aead::Aead;
|
||||
use aes_gcm::NewAead;
|
||||
use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
use aes_gcm::{aead::Aead, NewAead};
|
||||
use anyhow::{Context, Result};
|
||||
use gettextrs::gettext;
|
||||
use gtk::{glib::Cast, prelude::*};
|
||||
use rand::RngCore;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{Backupable, Restorable, RestorableItem};
|
||||
use crate::models::{Account, Algorithm, OTPMethod, Provider, ProvidersModel};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
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)]
|
||||
pub struct AegisEncrypted {
|
||||
version: u32,
|
||||
|
@ -85,8 +86,8 @@ impl Aegis {
|
|||
slots: Some(vec![HeaderSlot::default()]),
|
||||
};
|
||||
|
||||
// We only support password encrypted database so far so we don't have to do any checks
|
||||
// for the slot type
|
||||
// We only support password encrypted database so far so we don't have to do any
|
||||
// checks for the slot type
|
||||
let mut password_slot = &mut header.slots.as_mut().unwrap().get_mut(0).unwrap();
|
||||
// Derive key from given password
|
||||
let mut derived_key: [u8; 32] = [0u8; 32];
|
||||
|
@ -115,7 +116,8 @@ impl Aegis {
|
|||
)
|
||||
.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 = ciphertext.try_into().unwrap();
|
||||
|
||||
|
@ -153,7 +155,8 @@ impl Aegis {
|
|||
|
||||
/// 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)]
|
||||
pub struct Header {
|
||||
#[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,
|
||||
// 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
|
||||
// but we provide a string. Thus, change the string in header / slots / password slot / `type = "1"`
|
||||
// to `type = 1` to use the python script.
|
||||
// with the python script provided in the aegis repository. The python script expects an
|
||||
// integer but we provide a string. Thus, change the string in header / slots / password
|
||||
// slot / `type = "1"` to `type = 1` to use the python script.
|
||||
#[serde(rename = "type")]
|
||||
pub type_: u32,
|
||||
pub uuid: String,
|
||||
|
@ -283,8 +286,8 @@ pub struct Item {
|
|||
pub tags: Option<String>,
|
||||
// Note is omitted
|
||||
// Icon:
|
||||
// TODO: Aegis encodes icons as JPEG's encoded in Base64 with padding. Does authenticator support
|
||||
// this?
|
||||
// TODO: Aegis encodes icons as JPEG's encoded in Base64 with padding. Does authenticator
|
||||
// support this?
|
||||
// TODO tags are not imported/exported right now.
|
||||
#[serde(rename = "icon")]
|
||||
pub thumbnail: Option<String>,
|
||||
|
@ -482,8 +485,9 @@ impl Restorable for Aegis {
|
|||
// Add the encryption tag
|
||||
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
|
||||
// to decrypt the master key which in turn can be used to decrypt the database.
|
||||
// Find slots with type password and derive the corresponding key. This key is
|
||||
// used to decrypt the master key which in turn can be used to
|
||||
// decrypt the database.
|
||||
let master_keys: Vec<Vec<u8>> = encrypted
|
||||
.header
|
||||
.slots
|
||||
|
@ -494,9 +498,11 @@ impl Restorable for Aegis {
|
|||
.map(|slot| -> Result<Vec<u8>> {
|
||||
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(
|
||||
// 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
|
||||
|
@ -518,7 +524,8 @@ impl Restorable for Aegis {
|
|||
let mut ciphertext: Vec<u8> = slot.key.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
|
||||
.decrypt(
|
||||
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"))
|
||||
})
|
||||
// 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 {
|
||||
Ok(x) => Some(x),
|
||||
Err(e) => {
|
||||
|
@ -536,7 +545,8 @@ impl Restorable for Aegis {
|
|||
})
|
||||
.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!(
|
||||
"Found {} valid password slots / master keys.",
|
||||
master_keys.len()
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use super::{Backupable, Restorable, RestorableItem};
|
||||
use crate::models::{Account, Algorithm, OTPMethod, Provider, ProvidersModel};
|
||||
use anyhow::Result;
|
||||
use gettextrs::gettext;
|
||||
use gtk::{glib::Cast, prelude::*};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{Backupable, Restorable, RestorableItem};
|
||||
use crate::models::{Account, Algorithm, OTPMethod, Provider, ProvidersModel};
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AndOTP {
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
use super::{Restorable, RestorableItem};
|
||||
use crate::models::{Algorithm, OTPMethod, OTPUri};
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::Result;
|
||||
use gettextrs::gettext;
|
||||
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)]
|
||||
pub struct Bitwarden {
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
use super::{Backupable, Restorable};
|
||||
use crate::models::{Account, OTPUri, Provider, ProvidersModel};
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::Result;
|
||||
use gettextrs::gettext;
|
||||
use gtk::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::str::FromStr;
|
||||
|
||||
use super::{Backupable, Restorable};
|
||||
use crate::models::{Account, OTPUri, Provider, ProvidersModel};
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
use super::Restorable;
|
||||
use crate::models::{Algorithm, OTPMethod, OTPUri};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use anyhow::Result;
|
||||
use gettextrs::gettext;
|
||||
use percent_encoding::percent_decode;
|
||||
use prost::{Enumeration, Message};
|
||||
use std::borrow::Cow;
|
||||
use url::Url;
|
||||
|
||||
use super::Restorable;
|
||||
use crate::models::{Algorithm, OTPMethod, OTPUri};
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Google;
|
||||
|
||||
|
@ -182,8 +184,7 @@ mod protobuf {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::RestorableItem;
|
||||
use super::*;
|
||||
use super::{super::RestorableItem, *};
|
||||
|
||||
#[test]
|
||||
fn test_google_restore_otpauth() {
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use super::{Restorable, RestorableItem};
|
||||
use crate::models::{Algorithm, OTPMethod};
|
||||
use anyhow::Result;
|
||||
use gettextrs::gettext;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{Restorable, RestorableItem};
|
||||
use crate::models::{Algorithm, OTPMethod};
|
||||
|
||||
// Same as andOTP except uses the first tag for the issuer
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct LegacyAuthenticator {
|
||||
|
@ -30,7 +31,8 @@ impl Restorable for LegacyAuthenticator {
|
|||
}
|
||||
|
||||
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)")
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use std::fmt::Debug;
|
||||
|
||||
use crate::models::{Account, Algorithm, OTPMethod, ProvidersModel};
|
||||
use anyhow::Result;
|
||||
use gtk::{gio, gio::prelude::*};
|
||||
|
||||
use crate::models::{Account, Algorithm, OTPMethod, ProvidersModel};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub enum Operation {
|
||||
Backup,
|
||||
|
@ -23,16 +24,17 @@ pub trait Restorable: Sized {
|
|||
fn subtitle() -> 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
|
||||
/// error if it only supports encrypted slices.
|
||||
/// If `key` is `None`, then the implementation should assume that the slice
|
||||
/// is unencrypted, and error if it only supports encrypted slices.
|
||||
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.
|
||||
///
|
||||
/// If `key` is `None`, then the implementation should assume that the file is unencrypted, and
|
||||
/// error if it only supports encrypted files.
|
||||
/// If `key` is `None`, then the implementation should assume that the file
|
||||
/// is unencrypted, and error if it only supports encrypted files.
|
||||
///
|
||||
/// By default, this method reads the file and passes the files content to
|
||||
/// `Self::restore_from_data`.
|
||||
|
|
|
@ -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::{
|
||||
provider::{DiProvider, Provider},
|
||||
OTPMethod, OTPUri, RUNTIME,
|
||||
|
@ -8,14 +18,6 @@ use crate::{
|
|||
utils::spawn_tokio_blocking,
|
||||
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)]
|
||||
#[table_name = "accounts"]
|
||||
|
@ -39,9 +41,10 @@ pub struct DiAccount {
|
|||
|
||||
#[doc(hidden)]
|
||||
mod imp {
|
||||
use super::*;
|
||||
use glib::{ParamSpec, ParamSpecObject, ParamSpecString, ParamSpecUInt, Value};
|
||||
|
||||
use super::*;
|
||||
|
||||
pub struct Account {
|
||||
pub id: Cell<u32>,
|
||||
pub otp: RefCell<String>,
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use gtk::glib;
|
||||
|
||||
mod imp {
|
||||
use gtk::subclass::prelude::*;
|
||||
|
||||
use super::*;
|
||||
use crate::models::Account;
|
||||
use gtk::subclass::prelude::*;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct AccountSorter;
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
use super::account::Account;
|
||||
use glib::StaticType;
|
||||
use gtk::{gio, glib, prelude::*, subclass::prelude::*};
|
||||
|
||||
use super::account::Account;
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
use std::cell::RefCell;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct AccountsModel(pub RefCell<Vec<Account>>);
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use std::{str::FromStr, string::ToString};
|
||||
|
||||
use gettextrs::gettext;
|
||||
use gtk::glib;
|
||||
use ring::hmac;
|
||||
use serde::{de::Deserializer, ser::Serializer, Deserialize, Serialize};
|
||||
use std::{str::FromStr, string::ToString};
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Copy, glib::Enum)]
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use std::{fs, fs::File, path::PathBuf};
|
||||
|
||||
use anyhow::Result;
|
||||
use diesel::{prelude::*, r2d2, r2d2::ConnectionManager};
|
||||
use once_cell::sync::Lazy;
|
||||
use std::{fs, fs::File, path::PathBuf};
|
||||
|
||||
type Pool = r2d2::Pool<ConnectionManager<SqliteConnection>>;
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use crate::config;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use once_cell::sync::OnceCell;
|
||||
use rand::RngCore;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::config;
|
||||
|
||||
pub static SECRET_SERVICE: OnceCell<oo7::Keyring> = OnceCell::new();
|
||||
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
use super::Algorithm;
|
||||
use std::{
|
||||
convert::TryInto,
|
||||
time::{SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
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_DEFAULT_PERIOD: u32 = 30;
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use std::{fmt::Write, str::FromStr};
|
||||
|
||||
use percent_encoding::percent_decode_str;
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
backup::RestorableItem,
|
||||
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)]
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
@ -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 diesel::{ExpressionMethods, QueryDsl, RunQueryDsl};
|
||||
use glib::{clone, Cast, StaticType, ToValue};
|
||||
use gtk::{gdk_pixbuf, gio, glib, prelude::*, subclass::prelude::*};
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
str::FromStr,
|
||||
string::ToString,
|
||||
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 url::Url;
|
||||
|
||||
use super::algorithm::{Algorithm, OTPMethod};
|
||||
use crate::{
|
||||
models::{database, otp, Account, AccountsModel, FAVICONS_PATH},
|
||||
schema::providers,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ProviderPatch {
|
||||
pub name: String,
|
||||
|
@ -60,10 +62,11 @@ pub struct DiProvider {
|
|||
pub method: String,
|
||||
}
|
||||
mod imp {
|
||||
use super::*;
|
||||
use glib::{ParamSpec, ParamSpecObject, ParamSpecString, ParamSpecUInt, Value};
|
||||
use gst::glib::{ParamSpecUInt64, SourceId};
|
||||
|
||||
use super::*;
|
||||
|
||||
pub struct Provider {
|
||||
pub id: Cell<u32>,
|
||||
pub name: RefCell<String>,
|
||||
|
@ -387,8 +390,8 @@ impl Provider {
|
|||
let icon_name = glib::base64_encode(icon_name.as_bytes());
|
||||
let small_icon_name = format!("{icon_name}_32x32");
|
||||
let large_icon_name = format!("{icon_name}_96x96");
|
||||
// TODO: figure out why trying to grab icons at specific size causes stack size errors
|
||||
// We need two sizes:
|
||||
// TODO: figure out why trying to grab icons at specific size causes stack size
|
||||
// errors We need two sizes:
|
||||
// - 32x32 for the accounts lists
|
||||
// - 96x96 elsewhere
|
||||
if let Some(best_favicon) = favicon.find_best().await {
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
use super::provider::Provider;
|
||||
use gtk::glib;
|
||||
|
||||
use super::provider::Provider;
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
use gtk::subclass::prelude::*;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ProviderSorter;
|
||||
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
use super::{otp, Account, Algorithm, OTPMethod, Provider, ProviderPatch};
|
||||
use anyhow::Result;
|
||||
use glib::StaticType;
|
||||
use gtk::{gio, glib, prelude::*, subclass::prelude::*};
|
||||
|
||||
use super::{otp, Account, Algorithm, OTPMethod, Provider, ProviderPatch};
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
use std::cell::RefCell;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ProvidersModel(pub RefCell<Vec<Provider>>);
|
||||
|
||||
|
@ -60,8 +62,9 @@ impl ProvidersModel {
|
|||
) -> Result<Provider> {
|
||||
let provider = match self.find_by_name(name) {
|
||||
Some(p) => {
|
||||
// Update potenitally different properties than what we have in the pre-shipped database
|
||||
// Note this does a comparaison first to avoid a uselesss rewrite
|
||||
// Update potenitally different properties than what we have in the pre-shipped
|
||||
// database Note this does a comparaison first to avoid a
|
||||
// uselesss rewrite
|
||||
p.update(&ProviderPatch {
|
||||
name: name.to_owned(),
|
||||
website,
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
use crate::{
|
||||
models::{otp, Account, OTPMethod, OTPUri, Provider, ProvidersModel},
|
||||
widgets::{Camera, ErrorRevealer, ProviderImage, UrlRow},
|
||||
};
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::Result;
|
||||
use gettextrs::gettext;
|
||||
use glib::{clone, signal::Inhibit};
|
||||
use gtk::{glib, prelude::*, subclass::prelude::*, CompositeTemplate};
|
||||
use gtk_macros::spawn;
|
||||
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 {
|
||||
use crate::widgets::providers::ProviderPage;
|
||||
use std::cell::RefCell;
|
||||
|
||||
use glib::subclass::{InitializingObject, Signal};
|
||||
|
||||
use super::*;
|
||||
use glib::subclass::{InitializingObject, Signal};
|
||||
use std::cell::RefCell;
|
||||
use crate::widgets::providers::ProviderPage;
|
||||
|
||||
#[derive(Debug, Default, CompositeTemplate)]
|
||||
#[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
|
||||
// TODO: replace this whole completion provider thing with a custom widget
|
||||
// in case the provider doesn't exists, let the user create a new one by showing
|
||||
// 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| {
|
||||
let imp = dialog.imp();
|
||||
let model = imp.model.get().unwrap();
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
use super::qrcode_paintable::QRCodePaintable;
|
||||
use crate::{
|
||||
models::{Account, OTPMethod, Provider, ProvidersModel},
|
||||
widgets::UrlRow,
|
||||
};
|
||||
use gettextrs::gettext;
|
||||
use gtk::{
|
||||
gdk,
|
||||
|
@ -11,17 +6,24 @@ use gtk::{
|
|||
subclass::prelude::*,
|
||||
CompositeTemplate,
|
||||
};
|
||||
|
||||
use super::qrcode_paintable::QRCodePaintable;
|
||||
use crate::{
|
||||
models::{Account, OTPMethod, Provider, ProvidersModel},
|
||||
widgets::UrlRow,
|
||||
};
|
||||
mod imp {
|
||||
use std::cell::RefCell;
|
||||
|
||||
use glib::subclass::{self, Signal};
|
||||
use once_cell::sync::{Lazy, OnceCell};
|
||||
|
||||
use super::*;
|
||||
use crate::{
|
||||
models::Provider,
|
||||
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)]
|
||||
#[template(resource = "/com/belmoussaoui/Authenticator/account_details_page.ui")]
|
||||
pub struct AccountDetailsPage {
|
||||
|
|
|
@ -3,6 +3,7 @@ mod details;
|
|||
mod qrcode_paintable;
|
||||
mod row;
|
||||
|
||||
pub use self::{add::AccountAddDialog, row::AccountRow};
|
||||
pub use details::AccountDetailsPage;
|
||||
pub use qrcode_paintable::{QRCodeData, QRCodePaintable};
|
||||
|
||||
pub use self::{add::AccountAddDialog, row::AccountRow};
|
||||
|
|
|
@ -63,9 +63,10 @@ mod imp {
|
|||
});
|
||||
});
|
||||
}
|
||||
use super::*;
|
||||
use std::cell::RefCell;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct QRCodePaintable {
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
use crate::models::{Account, OTPMethod};
|
||||
use gtk::{gdk, glib, prelude::*, subclass::prelude::*, CompositeTemplate};
|
||||
use std::cell::RefCell;
|
||||
|
||||
mod imp {
|
||||
use crate::widgets::Window;
|
||||
use gtk::{gdk, glib, prelude::*, subclass::prelude::*, CompositeTemplate};
|
||||
|
||||
use super::*;
|
||||
use crate::models::{Account, OTPMethod};
|
||||
|
||||
mod imp {
|
||||
use adw::subclass::prelude::*;
|
||||
use gettextrs::gettext;
|
||||
use glib::{subclass, ParamSpec, ParamSpecObject, Value};
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use super::*;
|
||||
use crate::widgets::Window;
|
||||
|
||||
#[derive(Debug, Default, CompositeTemplate)]
|
||||
#[template(resource = "/com/belmoussaoui/Authenticator/account_row.ui")]
|
||||
pub struct AccountRow {
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
use crate::widgets::CameraPaintable;
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
os::unix::prelude::RawFd,
|
||||
};
|
||||
|
||||
use adw::subclass::prelude::*;
|
||||
use anyhow::Result;
|
||||
use ashpd::{desktop::screenshot::ScreenshotProxy, zbus};
|
||||
|
@ -17,10 +21,10 @@ use gtk::{
|
|||
use gtk_macros::spawn;
|
||||
use image::GenericImageView;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::os::unix::prelude::RawFd;
|
||||
use zbar_rust::ZBarImageScanner;
|
||||
|
||||
use crate::widgets::CameraPaintable;
|
||||
|
||||
mod screenshot {
|
||||
use super::*;
|
||||
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
use crate::widgets::camera::CameraEvent;
|
||||
use gst::prelude::*;
|
||||
use gtk::prelude::*;
|
||||
use gtk::subclass::prelude::*;
|
||||
use gtk::{
|
||||
gdk,
|
||||
glib::{self, clone, Sender},
|
||||
graphene,
|
||||
prelude::*,
|
||||
subclass::prelude::*,
|
||||
};
|
||||
use gtk_macros::send;
|
||||
use once_cell::sync::Lazy;
|
||||
use tracing::error;
|
||||
|
||||
use crate::widgets::camera::CameraEvent;
|
||||
static PIPELINE_NAME: Lazy<glib::GString> = Lazy::new(|| glib::GString::from("camera"));
|
||||
/// 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
|
||||
/// \
|
||||
/// queue -- glsinkbin
|
||||
///
|
||||
///
|
||||
mod imp {
|
||||
use std::cell::RefCell;
|
||||
|
||||
|
@ -74,7 +73,8 @@ mod imp {
|
|||
) {
|
||||
let snapshot = snapshot.downcast_ref::<gtk::Snapshot>().unwrap();
|
||||
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 image_aspect = image.intrinsic_aspect_ratio();
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use gtk::{glib, prelude::*, subclass::prelude::*};
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
use adw::subclass::prelude::*;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, gtk::CompositeTemplate)]
|
||||
#[template(resource = "/com/belmoussaoui/Authenticator/editable_label.ui")]
|
||||
pub struct EditableLabel {
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use gtk::{glib, prelude::*, subclass::prelude::*};
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
use glib::subclass;
|
||||
use gtk::CompositeTemplate;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, CompositeTemplate)]
|
||||
#[template(resource = "/com/belmoussaoui/Authenticator/error_revealer.ui")]
|
||||
pub struct ErrorRevealer {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::{utils::spawn_tokio, widgets::Camera};
|
||||
use std::{cell::Cell, rc::Rc};
|
||||
|
||||
use adw::subclass::prelude::*;
|
||||
use anyhow::Result;
|
||||
use gtk::{
|
||||
|
@ -10,14 +11,14 @@ use gtk::{
|
|||
};
|
||||
use gtk_macros::get_action;
|
||||
use once_cell::sync::OnceCell;
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
use tokio::{
|
||||
select,
|
||||
sync::oneshot,
|
||||
time::{sleep, Duration},
|
||||
};
|
||||
|
||||
use crate::{utils::spawn_tokio, widgets::Camera};
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
|
||||
|
@ -67,8 +68,8 @@ impl CameraPage {
|
|||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
// This is required because for whatever reason `glib::clone!` wouldn't let it be moved into
|
||||
// the closure.
|
||||
// This is required because for whatever reason `glib::clone!` wouldn't let it
|
||||
// be moved into the closure.
|
||||
let tx = Rc::new(Cell::new(Some(tx)));
|
||||
|
||||
// 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();
|
||||
|
||||
// This is required because for whatever reason `glib::clone!` wouldn't let it be moved into
|
||||
// the closure.
|
||||
// This is required because for whatever reason `glib::clone!` wouldn't let it
|
||||
// be moved into the closure.
|
||||
let tx = Rc::new(Cell::new(Some(tx)));
|
||||
|
||||
// This is to make it safe to access `src` inside of the connected closure to
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::{config, models::keyring, utils::spawn_tokio, widgets::ErrorRevealer};
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
use gettextrs::gettext;
|
||||
use gtk::{
|
||||
gio,
|
||||
|
@ -9,7 +10,8 @@ use gtk::{
|
|||
};
|
||||
use gtk_macros::{action, get_action};
|
||||
use once_cell::sync::{Lazy, OnceCell};
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
use crate::{config, models::keyring, utils::spawn_tokio, widgets::ErrorRevealer};
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
use super::camera_page::CameraPage;
|
||||
use super::password_page::PasswordPage;
|
||||
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;
|
||||
|
||||
use super::{camera_page::CameraPage, password_page::PasswordPage};
|
||||
use crate::{
|
||||
backup::{
|
||||
Aegis, AndOTP, Backupable, Bitwarden, FreeOTP, Google, LegacyAuthenticator, Operation,
|
||||
|
@ -8,23 +14,21 @@ use crate::{
|
|||
config,
|
||||
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 {
|
||||
use super::*;
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
collections::HashMap,
|
||||
};
|
||||
|
||||
use adw::subclass::{preferences_window::PreferencesWindowImpl, window::AdwWindowImpl};
|
||||
use glib::{
|
||||
subclass::{self, Signal},
|
||||
ParamSpec, ParamSpecBoolean, Value,
|
||||
};
|
||||
use once_cell::sync::Lazy;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, CompositeTemplate)]
|
||||
#[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
|
||||
// with Authenticator. Others are sorted alphabetically.
|
||||
// FreeOTP is first in all of these lists, since its the way to backup
|
||||
// Authenticator for use with Authenticator. Others are sorted
|
||||
// alphabetically.
|
||||
|
||||
self.register_backup::<FreeOTP>(&["text/plain"]);
|
||||
self.register_backup::<Aegis>(&["application/json"]);
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use gtk::prelude::*;
|
||||
use gtk::subclass::prelude::*;
|
||||
use gtk::{gdk, glib};
|
||||
use gtk::{gdk, glib, prelude::*, subclass::prelude::*};
|
||||
|
||||
pub(crate) mod imp {
|
||||
use super::*;
|
||||
use std::cell::Cell;
|
||||
|
||||
use glib::{ParamSpec, ParamSpecFloat, Value};
|
||||
use gtk::{graphene, gsk};
|
||||
use once_cell::sync::Lazy;
|
||||
use std::cell::Cell;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ProgressIcon {
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use super::ProviderPage;
|
||||
use crate::models::{Provider, ProviderSorter, ProvidersModel};
|
||||
use adw::{prelude::*, subclass::prelude::*};
|
||||
use gettextrs::gettext;
|
||||
use glib::clone;
|
||||
use gtk::{glib, pango, subclass::prelude::*, CompositeTemplate};
|
||||
use row::ProviderActionRow;
|
||||
|
||||
use super::ProviderPage;
|
||||
use crate::models::{Provider, ProviderSorter, ProvidersModel};
|
||||
|
||||
enum View {
|
||||
List,
|
||||
Form,
|
||||
|
@ -13,12 +14,12 @@ enum View {
|
|||
}
|
||||
|
||||
mod imp {
|
||||
use crate::config;
|
||||
|
||||
use super::*;
|
||||
use adw::subclass::window::AdwWindowImpl;
|
||||
use glib::subclass::{self, Signal};
|
||||
|
||||
use super::*;
|
||||
use crate::config;
|
||||
|
||||
#[derive(Debug, Default, CompositeTemplate)]
|
||||
#[template(resource = "/com/belmoussaoui/Authenticator/providers_dialog.ui")]
|
||||
pub struct ProvidersDialog {
|
||||
|
@ -222,7 +223,8 @@ impl ProvidersDialog {
|
|||
|
||||
fn add_provider(&self) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -256,10 +258,12 @@ impl ProvidersDialog {
|
|||
mod row {
|
||||
use super::*;
|
||||
mod imp {
|
||||
use super::*;
|
||||
use glib::{ParamSpec, ParamSpecObject, Value};
|
||||
use std::cell::RefCell;
|
||||
|
||||
use glib::{ParamSpec, ParamSpecObject, Value};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ProviderActionRow {
|
||||
pub provider: RefCell<Option<Provider>>,
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
use crate::models::RUNTIME;
|
||||
use crate::models::{Provider, FAVICONS_PATH};
|
||||
use glib::{clone, Receiver, Sender};
|
||||
use gtk::{gio, glib, prelude::*, subclass::prelude::*, CompositeTemplate};
|
||||
use gtk_macros::send;
|
||||
use tracing::error;
|
||||
|
||||
use crate::models::{Provider, FAVICONS_PATH, RUNTIME};
|
||||
|
||||
pub enum ImageAction {
|
||||
Ready(String),
|
||||
Failed,
|
||||
}
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
use glib::{subclass, ParamSpec, ParamSpecObject, ParamSpecUInt, Value};
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
use glib::{subclass, ParamSpec, ParamSpecObject, ParamSpecUInt, Value};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, CompositeTemplate)]
|
||||
#[template(resource = "/com/belmoussaoui/Authenticator/provider_image.ui")]
|
||||
pub struct ProviderImage {
|
||||
|
@ -265,7 +267,7 @@ impl ProviderImage {
|
|||
fn do_action(&self, action: ImageAction) -> glib::Continue {
|
||||
let imp = self.imp();
|
||||
let image_path = match action {
|
||||
//TODO: handle network failure and other errors differently
|
||||
// TODO: handle network failure and other errors differently
|
||||
ImageAction::Failed => {
|
||||
imp.image.set_from_icon_name(Some("provider-fallback"));
|
||||
"invalid".to_string()
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use glib::clone;
|
||||
use gtk::{glib, prelude::*, subclass::prelude::*, CompositeTemplate};
|
||||
|
||||
use crate::{
|
||||
models::{Account, Provider, ProviderSorter, ProvidersModel},
|
||||
widgets::providers::ProviderRow,
|
||||
};
|
||||
use glib::clone;
|
||||
use gtk::{glib, prelude::*, subclass::prelude::*, CompositeTemplate};
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub enum ProvidersListView {
|
||||
|
@ -12,9 +13,10 @@ pub enum ProvidersListView {
|
|||
}
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
use glib::subclass::{self, Signal};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, CompositeTemplate)]
|
||||
#[template(resource = "/com/belmoussaoui/Authenticator/providers_list.ui")]
|
||||
pub struct ProvidersList {
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
use crate::{
|
||||
models::{i18n, otp, Algorithm, OTPMethod, Provider, ProviderPatch, FAVICONS_PATH},
|
||||
widgets::{ErrorRevealer, ProviderImage},
|
||||
};
|
||||
use adw::prelude::*;
|
||||
use gettextrs::gettext;
|
||||
use glib::{clone, translate::IntoGlib};
|
||||
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 {
|
||||
use std::cell::RefCell;
|
||||
|
||||
use glib::subclass::{self, Signal};
|
||||
|
||||
use super::*;
|
||||
use crate::models::OTPMethod;
|
||||
use glib::subclass::{self, Signal};
|
||||
use std::cell::RefCell;
|
||||
|
||||
#[derive(Debug, CompositeTemplate)]
|
||||
#[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
|
||||
// Note that we don't validate the urls other than: does `url` crate can parse it or not
|
||||
// Validate the information typed by the user in order to enable/disable the
|
||||
// save action Note that we don't validate the urls other than: does `url`
|
||||
// crate can parse it or not
|
||||
fn validate(&self) {
|
||||
let imp = self.imp();
|
||||
|
||||
|
|
|
@ -1,19 +1,23 @@
|
|||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use adw::prelude::*;
|
||||
use gtk::{glib, glib::clone, subclass::prelude::*, CompositeTemplate};
|
||||
|
||||
use crate::{
|
||||
models::{Account, AccountSorter, OTPMethod, Provider},
|
||||
widgets::{accounts::AccountRow, ProgressIcon, ProviderImage},
|
||||
};
|
||||
use adw::prelude::*;
|
||||
use gtk::{glib, glib::clone, subclass::prelude::*, CompositeTemplate};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
use std::cell::RefCell;
|
||||
|
||||
use glib::{
|
||||
subclass::{self, Signal},
|
||||
ParamSpec, ParamSpecObject, Value,
|
||||
};
|
||||
use once_cell::sync::Lazy;
|
||||
use std::cell::RefCell;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, CompositeTemplate)]
|
||||
#[template(resource = "/com/belmoussaoui/Authenticator/provider_row.ui")]
|
||||
|
|
|
@ -3,10 +3,12 @@ use glib::{clone, ToValue};
|
|||
use gtk::{glib, subclass::prelude::*};
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
use std::cell::RefCell;
|
||||
|
||||
use adw::subclass::prelude::*;
|
||||
use glib::{ParamSpec, ParamSpecString, Value};
|
||||
use std::cell::RefCell;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct UrlRow {
|
||||
|
|
|
@ -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::{
|
||||
application::Application,
|
||||
config,
|
||||
|
@ -9,11 +15,6 @@ use crate::{
|
|||
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)]
|
||||
pub enum View {
|
||||
|
@ -23,10 +24,11 @@ pub enum View {
|
|||
}
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
use adw::subclass::prelude::*;
|
||||
use glib::subclass;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, CompositeTemplate)]
|
||||
#[template(resource = "/com/belmoussaoui/Authenticator/window.ui")]
|
||||
pub struct Window {
|
||||
|
|
Loading…
Add table
Reference in a new issue