mirror of
https://gitlab.gnome.org/World/Authenticator.git
synced 2025-03-04 00:34: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 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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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!(
|
||||||
|
|
|
@ -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
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::{
|
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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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`.
|
||||||
|
|
|
@ -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>,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>>);
|
||||||
|
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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>>;
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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::*;
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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::*;
|
||||||
|
|
|
@ -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"]);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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>>,
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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")]
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Add table
Reference in a new issue