mirror of
https://gitlab.gnome.org/World/Authenticator.git
synced 2025-03-04 00:34:40 +01:00
ui: integrate hotp support
This commit is contained in:
parent
aa5cfe50f8
commit
2a0b7a4e5d
14 changed files with 1791 additions and 1354 deletions
|
@ -1,5 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<object class="GtkAdjustment" id="counter_adjustment">
|
||||
<property name="upper">60</property>
|
||||
<property name="step_increment">1</property>
|
||||
<property name="page_increment">10</property>
|
||||
</object>
|
||||
<template parent="HdyWindow" class="AccountAddDialog">
|
||||
<property name="modal">True</property>
|
||||
<property name="default_width">360</property>
|
||||
|
@ -45,156 +50,202 @@
|
|||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyClamp">
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-top">12</property>
|
||||
<property name="margin-bottom">12</property>
|
||||
<property name="vexpand">True</property>
|
||||
<object class="GtkScrolledWindow">
|
||||
<child>
|
||||
<object class="GtkBox" id="main_container">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">42</property>
|
||||
<property name="margin-start">8</property>
|
||||
<property name="margin-end">8</property>
|
||||
|
||||
<object class="HdyClamp">
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-top">12</property>
|
||||
<property name="margin-bottom">12</property>
|
||||
<property name="vexpand">True</property>
|
||||
<child>
|
||||
<object class="GtkStack" id="image_stack">
|
||||
<property name="transition-type">crossfade</property>
|
||||
<object class="GtkBox" id="main_container">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">42</property>
|
||||
<property name="margin-start">8</property>
|
||||
<property name="margin-end">8</property>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">image</property>
|
||||
<property name="child">
|
||||
<object class="GtkImage" id="image">
|
||||
<property name="icon-name">image-missing</property>
|
||||
<property name="pixel-size">96</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">loading</property>
|
||||
<property name="child">
|
||||
<object class="GtkSpinner" id="spinner">
|
||||
<property name="valign">center</property>
|
||||
<property name="halign">center</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkListBox" id="basic_list">
|
||||
<property name="selection_mode">none</property>
|
||||
<child>
|
||||
<object class="HdyActionRow">
|
||||
<property name="activatable_widget">provider_entry</property>
|
||||
<property name="title" translatable="yes">Provider</property>
|
||||
<object class="GtkStack" id="image_stack">
|
||||
<property name="transition-type">crossfade</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="provider_entry">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="completion">provider_completion</property>
|
||||
<property name="enable_emoji_completion">True</property>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">image</property>
|
||||
<property name="child">
|
||||
<object class="GtkImage" id="image">
|
||||
<property name="icon-name">image-missing</property>
|
||||
<property name="pixel-size">96</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">loading</property>
|
||||
<property name="child">
|
||||
<object class="GtkSpinner" id="spinner">
|
||||
<property name="valign">center</property>
|
||||
<property name="halign">center</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyActionRow">
|
||||
<property name="activatable_widget">username_entry</property>
|
||||
<property name="title" translatable="yes">Account</property>
|
||||
<object class="GtkListBox" id="basic_list">
|
||||
<property name="selection_mode">none</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="username_entry">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="enable_emoji_completion">True</property>
|
||||
<object class="HdyActionRow">
|
||||
<property name="activatable_widget">provider_entry</property>
|
||||
<property name="title" translatable="yes">Provider</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="provider_entry">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="completion">provider_completion</property>
|
||||
<property name="enable_emoji_completion">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyActionRow">
|
||||
<property name="activatable_widget">username_entry</property>
|
||||
<property name="title" translatable="yes">Account</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="username_entry">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="enable_emoji_completion">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyActionRow" id="token_row">
|
||||
<property name="activatable_widget">token_entry</property>
|
||||
<property name="title" translatable="yes">Token</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="token_entry">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="visibility">False</property>
|
||||
<property name="secondary_icon_name">dialog-information-symbolic</property>
|
||||
<property name="secondary_icon_tooltip_text" translatable="yes">Enable 2FA for this account</property>
|
||||
<property name="secondary_icon_tooltip_markup" translatable="yes">Enable 2FA for this account</property>
|
||||
<property name="input_purpose">pin</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyActionRow" id="counter_row">
|
||||
<property name="activatable_widget">counter_spinbutton</property>
|
||||
<property name="title" translatable="yes">Counter</property>
|
||||
<property name="visible">False</property>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="counter_spinbutton">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="text" translatable="yes">0</property>
|
||||
<property name="adjustment">counter_adjustment</property>
|
||||
<property name="numeric">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="content"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyActionRow" id="token_row">
|
||||
<property name="activatable_widget">token_entry</property>
|
||||
<property name="title" translatable="yes">Token</property>
|
||||
<object class="GtkListBox" id="more_list">
|
||||
<property name="visible">False</property>
|
||||
<property name="selection_mode">none</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="token_entry">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="visibility">False</property>
|
||||
<property name="secondary_icon_name">dialog-information-symbolic</property>
|
||||
<property name="secondary_icon_tooltip_text" translatable="yes">Enable 2FA for this account</property>
|
||||
<property name="secondary_icon_tooltip_markup" translatable="yes">Enable 2FA for this account</property>
|
||||
<property name="input_purpose">pin</property>
|
||||
<object class="HdyActionRow" id="provider_website_row">
|
||||
<property name="title" translatable="yes">Website</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="icon-name">link-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="content"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkListBox" id="more_list">
|
||||
<property name="visible">False</property>
|
||||
<property name="selection_mode">none</property>
|
||||
<child>
|
||||
<object class="HdyActionRow" id="provider_website_row">
|
||||
<property name="title" translatable="yes">Website</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="icon-name">link-symbolic</property>
|
||||
<object class="HdyActionRow" id="provider_help_row">
|
||||
<property name="title" translatable="yes">How to setup</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="icon-name">help-page-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyActionRow" id="provider_help_row">
|
||||
<property name="title" translatable="yes">How to setup</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="icon-name">help-page-symbolic</property>
|
||||
<object class="HdyActionRow" id="digits_row">
|
||||
<property name="title" translatable="yes">Digits</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="digits_label">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyActionRow">
|
||||
<property name="title" translatable="yes">Period</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="period_label">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<object class="HdyActionRow" id="hmac_algorithm_row">
|
||||
<property name="title" translatable="yes">HMAC Algorithm</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="hmac_algorithm_label">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyActionRow" id="algorithm_row">
|
||||
<property name="title" translatable="yes">Algorithm</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="algorithm_label">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<object class="HdyActionRow" id="period_row">
|
||||
<property name="title" translatable="yes">Period</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="period_label">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyActionRow" id="algorithm_row">
|
||||
<property name="title" translatable="yes">Algorithm</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="algorithm_label">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="content"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="content"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
@ -224,6 +275,7 @@
|
|||
<widget name="provider_entry"/>
|
||||
<widget name="username_entry"/>
|
||||
<widget name="token_entry"/>
|
||||
<widget name="counter_spinbutton"/>
|
||||
</widgets>
|
||||
</object>
|
||||
</interface>
|
||||
|
|
|
@ -5,9 +5,21 @@
|
|||
<property name="step_increment">1</property>
|
||||
<property name="page_increment">10</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="default_counter_adjustment">
|
||||
<property name="upper">60</property>
|
||||
<property name="step_increment">1</property>
|
||||
<property name="page_increment">10</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="digits_adjustment">
|
||||
<property name="upper">60</property>
|
||||
<property name="step_increment">1</property>
|
||||
<property name="page_increment">10</property>
|
||||
</object>
|
||||
<object class="GtkSizeGroup">
|
||||
<widgets>
|
||||
<widget name="digits_spinbutton"/>
|
||||
<widget name="period_spinbutton"/>
|
||||
<widget name="default_counter_spinbutton"/>
|
||||
<widget name="provider_website_entry"/>
|
||||
<widget name="provider_help_entry"/>
|
||||
<widget name="name_entry"/>
|
||||
|
@ -134,7 +146,15 @@
|
|||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyActionRow">
|
||||
<object class="HdyComboRow" id="algorithm_comborow">
|
||||
<property name="title" translatable="yes">Algorithm</property>
|
||||
<property name="expression">
|
||||
<lookup type="HdyEnumValueObject" name="name"/>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyActionRow" id="period_row">
|
||||
<property name="activatable_widget">period_spinbutton</property>
|
||||
<property name="title" translatable="yes">Period</property>
|
||||
<child>
|
||||
|
@ -150,13 +170,46 @@
|
|||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyComboRow" id="algorithm_comborow">
|
||||
<property name="title" translatable="yes">Algorithm</property>
|
||||
<object class="HdyComboRow" id="hmac_algorithm_comborow">
|
||||
<property name="title" translatable="yes">HMAC Algorithm</property>
|
||||
<property name="expression">
|
||||
<lookup type="HdyEnumValueObject" name="name"/>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyActionRow" id="default_counter_row">
|
||||
<property name="activatable_widget">default_counter_spinbutton</property>
|
||||
<property name="title" translatable="yes">Default Counter</property>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="default_counter_spinbutton">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="text" translatable="yes">0</property>
|
||||
<property name="adjustment">default_counter_adjustment</property>
|
||||
<property name="numeric">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="HdyActionRow" id="digits_row">
|
||||
<property name="activatable_widget">digits_spinbutton</property>
|
||||
<property name="title" translatable="yes">Digits</property>
|
||||
<property name="subtitle" translatable="yes">Defaults to 6</property>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="digits_spinbutton">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="text" translatable="yes">0</property>
|
||||
<property name="adjustment">digits_adjustment</property>
|
||||
<property name="numeric">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="content"/>
|
||||
</style>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
CREATE TABLE "accounts" (
|
||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE,
|
||||
"name" VARCHAR NOT NULL,
|
||||
"counter" INTEGER NULL DEFAULT 1,
|
||||
"token_id" VARCHAR NOT NULL,
|
||||
"provider_id" INTEGER NOT NULL
|
||||
)
|
||||
|
|
|
@ -5,6 +5,9 @@ CREATE TABLE "providers" (
|
|||
"website" VARCHAR NULL,
|
||||
"help_url" VARCHAR NULL,
|
||||
"image_uri" VARCHAR NULL,
|
||||
"digits" INTEGER NULL DEFAULT 6,
|
||||
"period" INTEGER NULL DEFAULT 30,
|
||||
"default_counter" INTEGER NULL DEFAULT 1,
|
||||
"hmac_algorithm" VARCHAR NULL DEFAULT "SHA1",
|
||||
"algorithm" VARCHAR DEFAULT "TOTP"
|
||||
);
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -18,6 +18,7 @@ struct NewAccount {
|
|||
pub name: String,
|
||||
pub token_id: String,
|
||||
pub provider_id: i32,
|
||||
pub counter: i32,
|
||||
}
|
||||
|
||||
#[derive(Identifiable, Queryable, Associations, Hash, PartialEq, Eq, Debug, Clone)]
|
||||
|
@ -26,6 +27,7 @@ struct NewAccount {
|
|||
pub struct DiAccount {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub counter: i32,
|
||||
pub token_id: String,
|
||||
pub provider_id: i32,
|
||||
}
|
||||
|
@ -34,11 +36,12 @@ pub struct AccountPriv {
|
|||
pub id: Cell<i32>,
|
||||
pub otp: RefCell<String>,
|
||||
pub name: RefCell<String>,
|
||||
pub counter: Cell<i32>,
|
||||
pub token_id: RefCell<String>,
|
||||
pub provider: RefCell<Option<Provider>>,
|
||||
}
|
||||
|
||||
static PROPERTIES: [subclass::Property; 5] = [
|
||||
static PROPERTIES: [subclass::Property; 6] = [
|
||||
subclass::Property("id", |name| {
|
||||
glib::ParamSpec::int(
|
||||
name,
|
||||
|
@ -50,6 +53,17 @@ static PROPERTIES: [subclass::Property; 5] = [
|
|||
glib::ParamFlags::READWRITE,
|
||||
)
|
||||
}),
|
||||
subclass::Property("counter", |name| {
|
||||
glib::ParamSpec::int(
|
||||
name,
|
||||
"counter",
|
||||
"Counter",
|
||||
0,
|
||||
i32::MAX,
|
||||
0,
|
||||
glib::ParamFlags::READWRITE,
|
||||
)
|
||||
}),
|
||||
subclass::Property("name", |name| {
|
||||
glib::ParamSpec::string(name, "name", "Name", None, glib::ParamFlags::READWRITE)
|
||||
}),
|
||||
|
@ -98,6 +112,7 @@ impl ObjectSubclass for AccountPriv {
|
|||
fn new() -> Self {
|
||||
Self {
|
||||
id: Cell::new(0),
|
||||
counter: Cell::new(1),
|
||||
name: RefCell::new("".to_string()),
|
||||
otp: RefCell::new("".to_string()),
|
||||
token_id: RefCell::new("".to_string()),
|
||||
|
@ -125,6 +140,13 @@ impl ObjectImpl for AccountPriv {
|
|||
.unwrap();
|
||||
self.name.replace(name);
|
||||
}
|
||||
subclass::Property("counter", ..) => {
|
||||
let counter = value
|
||||
.get()
|
||||
.expect("type conformity checked by `Object::set_property`")
|
||||
.unwrap();
|
||||
self.counter.replace(counter);
|
||||
}
|
||||
subclass::Property("otp", ..) => {
|
||||
let otp = value
|
||||
.get()
|
||||
|
@ -155,6 +177,7 @@ impl ObjectImpl for AccountPriv {
|
|||
match *prop {
|
||||
subclass::Property("id", ..) => self.id.get().to_value(),
|
||||
subclass::Property("name", ..) => self.name.borrow().to_value(),
|
||||
subclass::Property("counter", ..) => self.counter.get().to_value(),
|
||||
subclass::Property("otp", ..) => self.otp.borrow().to_value(),
|
||||
subclass::Property("token-id", ..) => self.token_id.borrow().to_value(),
|
||||
subclass::Property("provider", ..) => self.provider.borrow().to_value(),
|
||||
|
@ -177,6 +200,7 @@ impl Account {
|
|||
name: name.to_string(),
|
||||
token_id: token_id.to_string(),
|
||||
provider_id: provider.id(),
|
||||
counter: provider.default_counter(),
|
||||
})
|
||||
.execute(&conn)?;
|
||||
|
||||
|
@ -189,6 +213,7 @@ impl Account {
|
|||
account.id,
|
||||
&account.name,
|
||||
&account.token_id,
|
||||
account.counter,
|
||||
provider.clone(),
|
||||
)
|
||||
})
|
||||
|
@ -202,7 +227,15 @@ impl Account {
|
|||
let results = DiAccount::belonging_to(&dip)
|
||||
.load::<DiAccount>(&conn)?
|
||||
.into_iter()
|
||||
.map(|account| Self::new(account.id, &account.name, &account.token_id, p.clone()))
|
||||
.map(|account| {
|
||||
Self::new(
|
||||
account.id,
|
||||
&account.name,
|
||||
&account.token_id,
|
||||
account.counter,
|
||||
p.clone(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<Account>>();
|
||||
Ok(results)
|
||||
}
|
||||
|
@ -214,7 +247,7 @@ impl Account {
|
|||
account1.name().cmp(&account2.name())
|
||||
}
|
||||
|
||||
pub fn new(id: i32, name: &str, token_id: &str, provider: Provider) -> Account {
|
||||
pub fn new(id: i32, name: &str, token_id: &str, counter: i32, provider: Provider) -> Account {
|
||||
let account = glib::Object::new(
|
||||
Account::static_type(),
|
||||
&[
|
||||
|
@ -222,6 +255,7 @@ impl Account {
|
|||
("name", &name),
|
||||
("token-id", &token_id),
|
||||
("provider", &provider),
|
||||
("counter", &counter),
|
||||
],
|
||||
)
|
||||
.expect("Failed to create account")
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use gettextrs::gettext;
|
||||
use std::str::FromStr;
|
||||
use std::string::ToString;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Copy, GEnum)]
|
||||
#[repr(u32)]
|
||||
#[genum(type_name = "ProviderAlgorithm")]
|
||||
|
@ -13,11 +12,27 @@ pub enum Algorithm {
|
|||
Steam = 2,
|
||||
}
|
||||
|
||||
impl Default for Algorithm {
|
||||
fn default() -> Self {
|
||||
Self::TOTP
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Algorithm {
|
||||
fn from(u: u32) -> Self {
|
||||
match u {
|
||||
1 => Algorithm::HOTP,
|
||||
2 => Algorithm::Steam,
|
||||
_ => Algorithm::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Algorithm {
|
||||
pub fn to_locale_string(&self) -> String {
|
||||
match *self {
|
||||
Algorithm::HOTP => gettext("HMAC-based One-time Password"),
|
||||
Algorithm::TOTP => gettext("Time-based One-Time-Password"),
|
||||
Algorithm::HOTP => gettext("HMAC-based"),
|
||||
Algorithm::TOTP => gettext("Time-based"),
|
||||
Algorithm::Steam => gettext("Steam"),
|
||||
}
|
||||
}
|
||||
|
@ -45,3 +60,54 @@ impl ToString for Algorithm {
|
|||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Copy, GEnum)]
|
||||
#[repr(u32)]
|
||||
#[genum(type_name = "ProviderHOTPAlgorithm")]
|
||||
pub enum HOTPAlgorithm {
|
||||
#[genum(name = "SHA1")]
|
||||
SHA1 = 0,
|
||||
#[genum(name = "SHA256")]
|
||||
SHA256 = 1,
|
||||
#[genum(name = "SHA512")]
|
||||
SHA512 = 2,
|
||||
}
|
||||
|
||||
impl Default for HOTPAlgorithm {
|
||||
fn default() -> Self {
|
||||
Self::SHA1
|
||||
}
|
||||
}
|
||||
|
||||
impl HOTPAlgorithm {
|
||||
pub fn to_locale_string(&self) -> String {
|
||||
match *self {
|
||||
HOTPAlgorithm::SHA1 => gettext("SHA1"),
|
||||
HOTPAlgorithm::SHA256 => gettext("SHA256"),
|
||||
HOTPAlgorithm::SHA512 => gettext("SHA512"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for HOTPAlgorithm {
|
||||
type Err = anyhow::Error;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.to_lowercase().as_ref() {
|
||||
"sha1" | "otp" => Ok(Self::SHA1),
|
||||
"sha256" => Ok(Self::SHA256),
|
||||
"sha512" => Ok(Self::SHA512),
|
||||
_ => anyhow::bail!("Unsupported HMAC algorithm"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for HOTPAlgorithm {
|
||||
fn to_string(&self) -> String {
|
||||
match *self {
|
||||
HOTPAlgorithm::SHA1 => "sha1",
|
||||
HOTPAlgorithm::SHA256 => "sha256",
|
||||
HOTPAlgorithm::SHA512 => "sha512",
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ mod providers;
|
|||
pub use self::account::Account;
|
||||
pub use self::account_sorter::AccountSorter;
|
||||
pub use self::accounts::AccountsModel;
|
||||
pub use self::algorithm::Algorithm;
|
||||
pub use self::algorithm::{Algorithm, HOTPAlgorithm};
|
||||
pub use self::favicon::{FaviconError, FaviconScrapper};
|
||||
pub use self::provider::Provider;
|
||||
pub use self::provider_sorter::ProviderSorter;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::algorithm::Algorithm;
|
||||
use super::algorithm::{Algorithm, HOTPAlgorithm};
|
||||
use crate::models::{database, Account, AccountsModel, FaviconError, FaviconScrapper};
|
||||
use crate::schema::providers;
|
||||
use anyhow::Result;
|
||||
|
@ -19,11 +19,14 @@ use url::Url;
|
|||
#[table_name = "providers"]
|
||||
struct NewProvider {
|
||||
pub name: String,
|
||||
pub period: i32,
|
||||
pub algorithm: String,
|
||||
pub website: Option<String>,
|
||||
pub help_url: Option<String>,
|
||||
pub image_uri: Option<String>,
|
||||
pub period: i32,
|
||||
pub digits: i32,
|
||||
pub default_counter: i32,
|
||||
pub hmac_algorithm: String,
|
||||
pub algorithm: String,
|
||||
}
|
||||
|
||||
#[derive(Identifiable, Queryable, Associations, Hash, PartialEq, Eq, Debug, Clone)]
|
||||
|
@ -31,11 +34,14 @@ struct NewProvider {
|
|||
pub struct DiProvider {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub period: i32,
|
||||
pub algorithm: String,
|
||||
pub website: Option<String>,
|
||||
pub help_url: Option<String>,
|
||||
pub image_uri: Option<String>,
|
||||
pub period: i32,
|
||||
pub digits: i32,
|
||||
pub default_counter: i32,
|
||||
pub hmac_algorithm: String,
|
||||
pub algorithm: String,
|
||||
}
|
||||
|
||||
pub struct ProviderPriv {
|
||||
|
@ -43,6 +49,9 @@ pub struct ProviderPriv {
|
|||
pub name: RefCell<String>,
|
||||
pub period: Cell<i32>,
|
||||
pub algorithm: RefCell<String>,
|
||||
pub default_counter: Cell<i32>,
|
||||
pub hmac_algorithm: RefCell<String>,
|
||||
pub digits: Cell<i32>,
|
||||
pub website: RefCell<Option<String>>,
|
||||
pub help_url: RefCell<Option<String>>,
|
||||
pub image_uri: RefCell<Option<String>>,
|
||||
|
@ -50,7 +59,7 @@ pub struct ProviderPriv {
|
|||
pub filter_model: gtk::FilterListModel,
|
||||
}
|
||||
|
||||
static PROPERTIES: [subclass::Property; 8] = [
|
||||
static PROPERTIES: [subclass::Property; 11] = [
|
||||
subclass::Property("id", |name| {
|
||||
glib::ParamSpec::int(
|
||||
name,
|
||||
|
@ -85,12 +94,43 @@ static PROPERTIES: [subclass::Property; 8] = [
|
|||
glib::ParamFlags::READWRITE,
|
||||
)
|
||||
}),
|
||||
subclass::Property("digits", |name| {
|
||||
glib::ParamSpec::int(
|
||||
name,
|
||||
"digits",
|
||||
"Digits",
|
||||
0,
|
||||
1000,
|
||||
6,
|
||||
glib::ParamFlags::READWRITE,
|
||||
)
|
||||
}),
|
||||
subclass::Property("default-counter", |name| {
|
||||
glib::ParamSpec::int(
|
||||
name,
|
||||
"default_counter",
|
||||
"default_counter",
|
||||
0,
|
||||
1000,
|
||||
1,
|
||||
glib::ParamFlags::READWRITE,
|
||||
)
|
||||
}),
|
||||
subclass::Property("hmac-algorithm", |name| {
|
||||
glib::ParamSpec::string(
|
||||
name,
|
||||
"hmac_algorithm",
|
||||
"HMAC algorithm",
|
||||
Some(&HOTPAlgorithm::default().to_string()),
|
||||
glib::ParamFlags::READWRITE,
|
||||
)
|
||||
}),
|
||||
subclass::Property("algorithm", |name| {
|
||||
glib::ParamSpec::string(
|
||||
name,
|
||||
"algorithm",
|
||||
"Algorithm",
|
||||
Some(&Algorithm::TOTP.to_string()),
|
||||
Some(&Algorithm::default().to_string()),
|
||||
glib::ParamFlags::READWRITE,
|
||||
)
|
||||
}),
|
||||
|
@ -140,11 +180,14 @@ impl ObjectSubclass for ProviderPriv {
|
|||
let model = AccountsModel::new();
|
||||
Self {
|
||||
id: Cell::new(0),
|
||||
default_counter: Cell::new(1),
|
||||
hmac_algorithm: RefCell::new(HOTPAlgorithm::default().to_string()),
|
||||
digits: Cell::new(6),
|
||||
name: RefCell::new("".to_string()),
|
||||
website: RefCell::new(None),
|
||||
help_url: RefCell::new(None),
|
||||
image_uri: RefCell::new(None),
|
||||
algorithm: RefCell::new(Algorithm::TOTP.to_string()),
|
||||
algorithm: RefCell::new(Algorithm::default().to_string()),
|
||||
period: Cell::new(30),
|
||||
filter_model: gtk::FilterListModel::new(Some(&model), gtk::NONE_FILTER),
|
||||
accounts: model,
|
||||
|
@ -184,6 +227,25 @@ impl ObjectImpl for ProviderPriv {
|
|||
.unwrap();
|
||||
self.algorithm.replace(algorithm);
|
||||
}
|
||||
subclass::Property("digits", ..) => {
|
||||
let digits = value
|
||||
.get_some()
|
||||
.expect("type conformity checked by `Object::set_property`");
|
||||
self.digits.replace(digits);
|
||||
}
|
||||
subclass::Property("hmac-algorithm", ..) => {
|
||||
let hmac_algorithm = value
|
||||
.get()
|
||||
.expect("type conformity checked by `Object::set_property`")
|
||||
.unwrap();
|
||||
self.hmac_algorithm.replace(hmac_algorithm);
|
||||
}
|
||||
subclass::Property("default-counter", ..) => {
|
||||
let default_counter = value
|
||||
.get_some()
|
||||
.expect("type conformity checked by `Object::set_property`");
|
||||
self.default_counter.replace(default_counter);
|
||||
}
|
||||
subclass::Property("website", ..) => {
|
||||
let website = value
|
||||
.get()
|
||||
|
@ -214,6 +276,9 @@ impl ObjectImpl for ProviderPriv {
|
|||
subclass::Property("name", ..) => self.name.borrow().to_value(),
|
||||
subclass::Property("period", ..) => self.period.get().to_value(),
|
||||
subclass::Property("algorithm", ..) => self.algorithm.borrow().to_value(),
|
||||
subclass::Property("digits", ..) => self.digits.get().to_value(),
|
||||
subclass::Property("hmac-algorithm", ..) => self.hmac_algorithm.borrow().to_value(),
|
||||
subclass::Property("default-counter", ..) => self.default_counter.get().to_value(),
|
||||
subclass::Property("website", ..) => self.website.borrow().to_value(),
|
||||
subclass::Property("help-url", ..) => self.help_url.borrow().to_value(),
|
||||
subclass::Property("image-uri", ..) => self.image_uri.borrow().to_value(),
|
||||
|
@ -232,6 +297,9 @@ impl Provider {
|
|||
period: i32,
|
||||
algorithm: Algorithm,
|
||||
website: Option<String>,
|
||||
hmac_algorithm: HOTPAlgorithm,
|
||||
digits: i32,
|
||||
default_counter: i32,
|
||||
) -> Result<Self> {
|
||||
use crate::diesel::ExpressionMethods;
|
||||
let db = database::connection();
|
||||
|
@ -243,6 +311,9 @@ impl Provider {
|
|||
period,
|
||||
algorithm: algorithm.to_string(),
|
||||
website,
|
||||
hmac_algorithm: hmac_algorithm.to_string(),
|
||||
digits,
|
||||
default_counter,
|
||||
help_url: None,
|
||||
image_uri: None,
|
||||
})
|
||||
|
@ -285,6 +356,9 @@ impl Provider {
|
|||
name: &str,
|
||||
period: i32,
|
||||
algorithm: Algorithm,
|
||||
hmac_algorithm: HOTPAlgorithm,
|
||||
digits: i32,
|
||||
default_counter: i32,
|
||||
website: Option<String>,
|
||||
help_url: Option<String>,
|
||||
image_uri: Option<String>,
|
||||
|
@ -299,6 +373,9 @@ impl Provider {
|
|||
("image-uri", &image_uri),
|
||||
("period", &period),
|
||||
("algorithm", &algorithm.to_string()),
|
||||
("hmac-algorithm", &hmac_algorithm.to_string()),
|
||||
("digits", &digits),
|
||||
("default-counter", &default_counter),
|
||||
],
|
||||
)
|
||||
.expect("Failed to create provider")
|
||||
|
@ -342,11 +419,26 @@ impl Provider {
|
|||
priv_.name.borrow().clone()
|
||||
}
|
||||
|
||||
pub fn digits(&self) -> i32 {
|
||||
let priv_ = ProviderPriv::from_instance(self);
|
||||
priv_.digits.get()
|
||||
}
|
||||
|
||||
pub fn default_counter(&self) -> i32 {
|
||||
let priv_ = ProviderPriv::from_instance(self);
|
||||
priv_.default_counter.get()
|
||||
}
|
||||
|
||||
pub fn period(&self) -> i32 {
|
||||
let priv_ = ProviderPriv::from_instance(self);
|
||||
priv_.period.get()
|
||||
}
|
||||
|
||||
pub fn hmac_algorithm(&self) -> HOTPAlgorithm {
|
||||
let priv_ = ProviderPriv::from_instance(self);
|
||||
HOTPAlgorithm::from_str(&priv_.hmac_algorithm.borrow().clone()).unwrap()
|
||||
}
|
||||
|
||||
pub fn algorithm(&self) -> Algorithm {
|
||||
let priv_ = ProviderPriv::from_instance(self);
|
||||
Algorithm::from_str(&priv_.algorithm.borrow().clone()).unwrap()
|
||||
|
@ -417,6 +509,9 @@ impl From<DiProvider> for Provider {
|
|||
&p.name,
|
||||
p.period,
|
||||
Algorithm::from_str(&p.algorithm).unwrap(),
|
||||
HOTPAlgorithm::from_str(&p.hmac_algorithm).unwrap(),
|
||||
p.digits,
|
||||
p.default_counter,
|
||||
p.website,
|
||||
p.help_url,
|
||||
p.image_uri,
|
||||
|
@ -431,6 +526,9 @@ impl From<&Provider> for DiProvider {
|
|||
name: p.name(),
|
||||
period: p.period(),
|
||||
algorithm: p.algorithm().to_string(),
|
||||
hmac_algorithm: p.hmac_algorithm().to_string(),
|
||||
digits: p.digits(),
|
||||
default_counter: p.default_counter(),
|
||||
website: p.website(),
|
||||
help_url: p.help_url(),
|
||||
image_uri: p.image_uri(),
|
||||
|
|
|
@ -2,6 +2,7 @@ table! {
|
|||
accounts (id) {
|
||||
id -> Integer,
|
||||
name -> Text,
|
||||
counter -> Integer,
|
||||
token_id -> Text,
|
||||
provider_id -> Integer,
|
||||
}
|
||||
|
@ -11,11 +12,14 @@ table! {
|
|||
providers (id) {
|
||||
id -> Integer,
|
||||
name -> Text,
|
||||
period -> Integer,
|
||||
algorithm -> Text,
|
||||
website -> Nullable<Text>,
|
||||
help_url -> Nullable<Text>,
|
||||
image_uri -> Nullable<Text>,
|
||||
period -> Integer,
|
||||
digits -> Integer,
|
||||
default_counter -> Integer,
|
||||
hmac_algorithm -> Text,
|
||||
algorithm -> Text,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::application::Action;
|
||||
use crate::helpers::{qrcode, Keyring};
|
||||
use crate::models::{Account, Provider, ProvidersModel};
|
||||
use crate::models::{Account, Algorithm, Provider, ProvidersModel};
|
||||
use anyhow::Result;
|
||||
use gio::prelude::*;
|
||||
use gio::{subclass::ObjectSubclass, ActionMapExt};
|
||||
|
@ -42,6 +42,9 @@ mod imp {
|
|||
#[template_child(id = "period_label")]
|
||||
pub period_label: TemplateChild<gtk::Label>,
|
||||
|
||||
#[template_child(id = "digits_label")]
|
||||
pub digits_label: TemplateChild<gtk::Label>,
|
||||
|
||||
#[template_child(id = "provider_entry")]
|
||||
pub provider_entry: TemplateChild<gtk::Entry>,
|
||||
|
||||
|
@ -54,6 +57,15 @@ mod imp {
|
|||
#[template_child(id = "provider_help_row")]
|
||||
pub provider_help_row: TemplateChild<libhandy::ActionRow>,
|
||||
|
||||
#[template_child(id = "hmac_algorithm_row")]
|
||||
pub hmac_algorithm_row: TemplateChild<libhandy::ActionRow>,
|
||||
|
||||
#[template_child(id = "counter_row")]
|
||||
pub counter_row: TemplateChild<libhandy::ActionRow>,
|
||||
|
||||
#[template_child(id = "period_row")]
|
||||
pub period_row: TemplateChild<libhandy::ActionRow>,
|
||||
|
||||
#[template_child(id = "provider_completion")]
|
||||
pub provider_completion: TemplateChild<gtk::EntryCompletion>,
|
||||
|
||||
|
@ -93,11 +105,15 @@ mod imp {
|
|||
username_entry: TemplateChild::default(),
|
||||
more_list: TemplateChild::default(),
|
||||
period_label: TemplateChild::default(),
|
||||
digits_label: TemplateChild::default(),
|
||||
provider_entry: TemplateChild::default(),
|
||||
algorithm_label: TemplateChild::default(),
|
||||
provider_website_row: TemplateChild::default(),
|
||||
provider_help_row: TemplateChild::default(),
|
||||
provider_completion: TemplateChild::default(),
|
||||
hmac_algorithm_row: TemplateChild::default(),
|
||||
counter_row: TemplateChild::default(),
|
||||
period_row: TemplateChild::default(),
|
||||
image: TemplateChild::default(),
|
||||
spinner: TemplateChild::default(),
|
||||
image_stack: TemplateChild::default(),
|
||||
|
@ -229,6 +245,24 @@ impl AccountAddDialog {
|
|||
.get()
|
||||
.set_text(&provider.algorithm().to_locale_string());
|
||||
|
||||
self_
|
||||
.digits_label
|
||||
.get()
|
||||
.set_text(&provider.digits().to_string());
|
||||
match provider.algorithm() {
|
||||
Algorithm::TOTP => {
|
||||
self_.hmac_algorithm_row.get().hide();
|
||||
self_.counter_row.get().hide();
|
||||
self_.period_row.get().show();
|
||||
}
|
||||
Algorithm::HOTP => {
|
||||
self_.hmac_algorithm_row.get().show();
|
||||
self_.counter_row.get().show();
|
||||
self_.period_row.get().hide();
|
||||
}
|
||||
Algorithm::Steam => {}
|
||||
};
|
||||
|
||||
if let Some(ref website) = provider.website() {
|
||||
self_.provider_website_row.get().set_subtitle(Some(website));
|
||||
}
|
||||
|
@ -291,6 +325,7 @@ impl AccountAddDialog {
|
|||
.provider_completion
|
||||
.get()
|
||||
.set_model(Some(&self_.model.get().unwrap().completion_model()));
|
||||
|
||||
self_.provider_completion.get().connect_match_selected(
|
||||
clone!(@strong self as dialog, @strong self_.model as model => move |_, store, iter| {
|
||||
let provider_id = store.get_value(iter, 0). get_some::<i32>().unwrap();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::models::{Algorithm, Provider};
|
||||
use crate::models::{Algorithm, HOTPAlgorithm, Provider};
|
||||
use gio::subclass::ObjectSubclass;
|
||||
use glib::subclass::prelude::*;
|
||||
use glib::translate::ToGlib;
|
||||
|
@ -22,6 +22,10 @@ mod imp {
|
|||
pub name_entry: TemplateChild<gtk::Entry>,
|
||||
#[template_child(id = "period_spinbutton")]
|
||||
pub period_spinbutton: TemplateChild<gtk::SpinButton>,
|
||||
#[template_child(id = "digits_spinbutton")]
|
||||
pub digits_spinbutton: TemplateChild<gtk::SpinButton>,
|
||||
#[template_child(id = "default_counter_spinbutton")]
|
||||
pub default_counter_spinbutton: TemplateChild<gtk::SpinButton>,
|
||||
#[template_child(id = "provider_website_entry")]
|
||||
pub provider_website_entry: TemplateChild<gtk::Entry>,
|
||||
#[template_child(id = "provider_help_entry")]
|
||||
|
@ -32,9 +36,18 @@ mod imp {
|
|||
pub spinner: TemplateChild<gtk::Spinner>,
|
||||
#[template_child(id = "algorithm_comborow")]
|
||||
pub algorithm_comborow: TemplateChild<libhandy::ComboRow>,
|
||||
#[template_child(id = "hmac_algorithm_comborow")]
|
||||
pub hmac_algorithm_comborow: TemplateChild<libhandy::ComboRow>,
|
||||
#[template_child(id = "period_row")]
|
||||
pub period_row: TemplateChild<libhandy::ActionRow>,
|
||||
#[template_child(id = "digits_row")]
|
||||
pub digits_row: TemplateChild<libhandy::ActionRow>,
|
||||
#[template_child(id = "default_counter_row")]
|
||||
pub default_counter_row: TemplateChild<libhandy::ActionRow>,
|
||||
#[template_child(id = "title")]
|
||||
pub title: TemplateChild<gtk::Label>,
|
||||
pub algorithms_model: libhandy::EnumListModel,
|
||||
pub hmac_algorithms_model: libhandy::EnumListModel,
|
||||
}
|
||||
|
||||
impl ObjectSubclass for ProviderPage {
|
||||
|
@ -48,17 +61,25 @@ mod imp {
|
|||
|
||||
fn new() -> Self {
|
||||
let algorithms_model = libhandy::EnumListModel::new(Algorithm::static_type());
|
||||
let hmac_algorithms_model = libhandy::EnumListModel::new(HOTPAlgorithm::static_type());
|
||||
|
||||
Self {
|
||||
name_entry: TemplateChild::default(),
|
||||
period_spinbutton: TemplateChild::default(),
|
||||
digits_spinbutton: TemplateChild::default(),
|
||||
default_counter_spinbutton: TemplateChild::default(),
|
||||
provider_website_entry: TemplateChild::default(),
|
||||
provider_help_entry: TemplateChild::default(),
|
||||
image_stack: TemplateChild::default(),
|
||||
spinner: TemplateChild::default(),
|
||||
algorithm_comborow: TemplateChild::default(),
|
||||
hmac_algorithm_comborow: TemplateChild::default(),
|
||||
period_row: TemplateChild::default(),
|
||||
digits_row: TemplateChild::default(),
|
||||
default_counter_row: TemplateChild::default(),
|
||||
title: TemplateChild::default(),
|
||||
algorithms_model,
|
||||
hmac_algorithms_model,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,6 +135,22 @@ impl ProviderPage {
|
|||
.algorithms_model
|
||||
.find_position(provider.algorithm().to_glib()),
|
||||
);
|
||||
self.on_algorithm_changed();
|
||||
|
||||
self_
|
||||
.default_counter_spinbutton
|
||||
.get()
|
||||
.set_value(provider.default_counter() as f64);
|
||||
self_
|
||||
.digits_spinbutton
|
||||
.get()
|
||||
.set_value(provider.digits() as f64);
|
||||
|
||||
self_.hmac_algorithm_comborow.get().set_selected(
|
||||
self_
|
||||
.hmac_algorithms_model
|
||||
.find_position(provider.hmac_algorithm().to_glib()),
|
||||
);
|
||||
|
||||
/*let sender = self.sender.clone();
|
||||
spawn!(async move {
|
||||
|
@ -134,6 +171,40 @@ impl ProviderPage {
|
|||
.algorithm_comborow
|
||||
.get()
|
||||
.set_model(Some(&self_.algorithms_model));
|
||||
|
||||
let default_counter_row = self_.default_counter_row.get();
|
||||
let hmac_algorithm_comborow = self_.hmac_algorithm_comborow.get();
|
||||
let period_row = self_.period_row.get();
|
||||
|
||||
self_
|
||||
.algorithm_comborow
|
||||
.get()
|
||||
.connect_property_selected_item_notify(clone!(@weak self as page => move |_| {
|
||||
page.on_algorithm_changed();
|
||||
}));
|
||||
self_
|
||||
.hmac_algorithm_comborow
|
||||
.get()
|
||||
.set_model(Some(&self_.hmac_algorithms_model));
|
||||
}
|
||||
|
||||
fn on_algorithm_changed(&self) {
|
||||
let self_ = imp::ProviderPage::from_instance(self);
|
||||
|
||||
let selected = Algorithm::from(self_.algorithm_comborow.get().get_selected());
|
||||
match selected {
|
||||
Algorithm::TOTP => {
|
||||
self_.default_counter_row.get().hide();
|
||||
self_.hmac_algorithm_comborow.get().hide();
|
||||
self_.period_row.get().show();
|
||||
}
|
||||
Algorithm::HOTP => {
|
||||
self_.default_counter_row.get().show();
|
||||
self_.hmac_algorithm_comborow.get().show();
|
||||
self_.period_row.get().hide();
|
||||
}
|
||||
Algorithm::Steam => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_mode(&self, mode: ProviderPageMode) {
|
||||
|
|
|
@ -57,8 +57,8 @@ for db_file in glob(DATA_DIR + "/*.yml"):
|
|||
name = provider.get("name").replace("&", "&")
|
||||
website = provider.get("url", "")
|
||||
help_url = provider.get("doc", "")
|
||||
up_query += f"INSERT INTO `providers` (`name`, `website`, `help_url`) VALUES (`{name}`, `{website}`, `{help_url}`);\n"
|
||||
down_query += f"DELETE FROM `providers` WHERE `name`=`{name}`;\n"
|
||||
up_query += f'INSERT INTO "providers" ("name", "website", "help_url") VALUES ("{name}", "{website}", "{help_url}");\n'
|
||||
down_query += f'DELETE FROM "providers" WHERE "name"="{name}";\n'
|
||||
except (yaml.YAMLError, TypeError, KeyError) as error:
|
||||
pass
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue