mirror of
https://gitlab.gnome.org/World/Authenticator.git
synced 2025-03-04 16:54:45 +01:00
add the possiblity to clear password & properly sync state
This commit is contained in:
parent
2068721006
commit
6e1f81b929
4 changed files with 114 additions and 33 deletions
|
@ -107,6 +107,20 @@
|
||||||
</style>
|
</style>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton">
|
||||||
|
<property name="action-name">preferences.reset_password</property>
|
||||||
|
<property name="halign">end</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="label">Reset</property>
|
||||||
|
<property name="margin-end">8</property>
|
||||||
|
<style>
|
||||||
|
<class name="destructive-action" />
|
||||||
|
<class name="large-button" />
|
||||||
|
<class name="pill-button" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
|
@ -28,10 +28,22 @@ pub struct ApplicationPrivate {
|
||||||
sender: Sender<Action>,
|
sender: Sender<Action>,
|
||||||
receiver: RefCell<Option<Receiver<Action>>>,
|
receiver: RefCell<Option<Receiver<Action>>>,
|
||||||
locked: Cell<bool>,
|
locked: Cell<bool>,
|
||||||
|
can_be_locked: Cell<bool>,
|
||||||
}
|
}
|
||||||
static PROPERTIES: [subclass::Property; 1] = [subclass::Property("locked", |name| {
|
static PROPERTIES: [subclass::Property; 2] = [
|
||||||
|
subclass::Property("locked", |name| {
|
||||||
glib::ParamSpec::boolean(name, "locked", "locked", false, glib::ParamFlags::READWRITE)
|
glib::ParamSpec::boolean(name, "locked", "locked", false, glib::ParamFlags::READWRITE)
|
||||||
})];
|
}),
|
||||||
|
subclass::Property("can-be-locked", |name| {
|
||||||
|
glib::ParamSpec::boolean(
|
||||||
|
name,
|
||||||
|
"can_be_locked",
|
||||||
|
"can be locked",
|
||||||
|
false,
|
||||||
|
glib::ParamFlags::READWRITE,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
];
|
||||||
impl ObjectSubclass for ApplicationPrivate {
|
impl ObjectSubclass for ApplicationPrivate {
|
||||||
const NAME: &'static str = "Application";
|
const NAME: &'static str = "Application";
|
||||||
type ParentType = gtk::Application;
|
type ParentType = gtk::Application;
|
||||||
|
@ -54,6 +66,7 @@ impl ObjectSubclass for ApplicationPrivate {
|
||||||
sender,
|
sender,
|
||||||
receiver,
|
receiver,
|
||||||
model,
|
model,
|
||||||
|
can_be_locked: Cell::new(false),
|
||||||
locked: Cell::new(false),
|
locked: Cell::new(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,6 +84,13 @@ impl ObjectImpl for ApplicationPrivate {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.locked.set(locked);
|
self.locked.set(locked);
|
||||||
}
|
}
|
||||||
|
subclass::Property("can-be-locked", ..) => {
|
||||||
|
let can_be_locked = value
|
||||||
|
.get()
|
||||||
|
.expect("type conformity checked by `Object::set_property`")
|
||||||
|
.unwrap();
|
||||||
|
self.can_be_locked.set(can_be_locked);
|
||||||
|
}
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,6 +100,7 @@ impl ObjectImpl for ApplicationPrivate {
|
||||||
|
|
||||||
match *prop {
|
match *prop {
|
||||||
subclass::Property("locked", ..) => Ok(self.locked.get().to_value()),
|
subclass::Property("locked", ..) => Ok(self.locked.get().to_value()),
|
||||||
|
subclass::Property("can-be-locked", ..) => Ok(self.can_be_locked.get().to_value()),
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,6 +161,10 @@ impl ApplicationImpl for ApplicationPrivate {
|
||||||
app_.set_locked(true);
|
app_.set_locked(true);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
application
|
||||||
|
.bind_property("can-be-locked", &get_action!(application, @lock), "enabled")
|
||||||
|
.flags(glib::BindingFlags::DEFAULT | glib::BindingFlags::SYNC_CREATE)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn activate(&self, _app: &gio::Application) {
|
fn activate(&self, _app: &gio::Application) {
|
||||||
|
@ -154,16 +179,16 @@ impl ApplicationImpl for ApplicationPrivate {
|
||||||
let window = app.create_window();
|
let window = app.create_window();
|
||||||
window.present();
|
window.present();
|
||||||
self.window.replace(Some(window));
|
self.window.replace(Some(window));
|
||||||
|
let has_set_password = Keyring::has_set_password().unwrap_or_else(|_| false);
|
||||||
|
|
||||||
app.set_resource_base_path(Some("/com/belmoussaoui/Authenticator"));
|
app.set_resource_base_path(Some("/com/belmoussaoui/Authenticator"));
|
||||||
app.set_accels_for_action("app.quit", &["<primary>q"]);
|
app.set_accels_for_action("app.quit", &["<primary>q"]);
|
||||||
|
app.set_accels_for_action("app.lock", &["<primary>l"]);
|
||||||
app.set_accels_for_action("win.show-help-overlay", &["<primary>question"]);
|
app.set_accels_for_action("win.show-help-overlay", &["<primary>question"]);
|
||||||
app.set_accels_for_action("win.search", &["<primary>f"]);
|
app.set_accels_for_action("win.search", &["<primary>f"]);
|
||||||
app.set_accels_for_action("win.add-account", &["<primary>n"]);
|
app.set_accels_for_action("win.add-account", &["<primary>n"]);
|
||||||
app.set_property(
|
app.set_locked(has_set_password);
|
||||||
"locked",
|
app.set_can_be_locked(has_set_password);
|
||||||
&Keyring::has_set_password().unwrap_or_else(|_| false),
|
|
||||||
);
|
|
||||||
let receiver = self.receiver.borrow_mut().take().unwrap();
|
let receiver = self.receiver.borrow_mut().take().unwrap();
|
||||||
receiver.attach(None, move |action| app.do_action(action));
|
receiver.attach(None, move |action| app.do_action(action));
|
||||||
}
|
}
|
||||||
|
@ -210,6 +235,10 @@ impl Application {
|
||||||
self.set_property("locked", &state);
|
self.set_property("locked", &state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_can_be_locked(&self, state: bool) {
|
||||||
|
self.set_property("can-be-locked", &state);
|
||||||
|
}
|
||||||
|
|
||||||
fn create_window(&self) -> Window {
|
fn create_window(&self) -> Window {
|
||||||
let self_ = ApplicationPrivate::from_instance(self);
|
let self_ = ApplicationPrivate::from_instance(self);
|
||||||
let window = Window::new(self_.model.clone(), self_.sender.clone(), &self.clone());
|
let window = Window::new(self_.model.clone(), self_.sender.clone(), &self.clone());
|
||||||
|
|
|
@ -40,6 +40,18 @@ impl Keyring {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reset_password() -> Result<(), SsError> {
|
||||||
|
let ss = SecretService::new(EncryptionType::Dh)?;
|
||||||
|
let col = Self::get_default_collection(&ss)?;
|
||||||
|
let items =
|
||||||
|
col.search_items(vec![("type", "password"), ("application", config::APP_ID)])?;
|
||||||
|
|
||||||
|
match items.get(0) {
|
||||||
|
Some(i) => i.delete(),
|
||||||
|
None => Err(SsError::NoResult),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_current_password(password: &str) -> Result<bool, SsError> {
|
pub fn is_current_password(password: &str) -> Result<bool, SsError> {
|
||||||
let ss = SecretService::new(EncryptionType::Dh)?;
|
let ss = SecretService::new(EncryptionType::Dh)?;
|
||||||
let col = Self::get_default_collection(&ss)?;
|
let col = Self::get_default_collection(&ss)?;
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
use crate::helpers::Keyring;
|
use crate::helpers::Keyring;
|
||||||
use gio::{ActionExt, ActionMapExt};
|
use gio::{ActionExt, ActionMapExt};
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
use std::cell::Cell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct PasswordPage {
|
pub struct PasswordPage {
|
||||||
pub widget: gtk::Box,
|
pub widget: gtk::Box,
|
||||||
builder: gtk::Builder,
|
builder: gtk::Builder,
|
||||||
actions: gio::SimpleActionGroup,
|
actions: gio::SimpleActionGroup,
|
||||||
|
has_set_password: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PasswordPage {
|
impl PasswordPage {
|
||||||
|
@ -14,50 +17,51 @@ impl PasswordPage {
|
||||||
"/com/belmoussaoui/Authenticator/preferences_password_page.ui",
|
"/com/belmoussaoui/Authenticator/preferences_password_page.ui",
|
||||||
);
|
);
|
||||||
get_widget!(builder, gtk::Box, password_page);
|
get_widget!(builder, gtk::Box, password_page);
|
||||||
|
|
||||||
|
let has_set_password = Keyring::has_set_password().unwrap_or_else(|_| false);
|
||||||
|
|
||||||
let page = Rc::new(Self {
|
let page = Rc::new(Self {
|
||||||
widget: password_page,
|
widget: password_page,
|
||||||
builder,
|
builder,
|
||||||
actions,
|
actions,
|
||||||
|
has_set_password: Cell::new(has_set_password),
|
||||||
});
|
});
|
||||||
page.init(page.clone());
|
page.init(page.clone());
|
||||||
page
|
page
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn validate(&self) {
|
||||||
|
get_widget!(self.builder, gtk::PasswordEntry, current_password_entry);
|
||||||
|
get_widget!(self.builder, gtk::PasswordEntry, password_entry);
|
||||||
|
get_widget!(self.builder, gtk::PasswordEntry, confirm_password_entry);
|
||||||
|
|
||||||
|
let current_password = current_password_entry.get_text().unwrap();
|
||||||
|
let password = password_entry.get_text().unwrap();
|
||||||
|
let password_repeat = confirm_password_entry.get_text().unwrap();
|
||||||
|
|
||||||
|
let is_valid = if self.has_set_password.get() {
|
||||||
|
password_repeat == password && current_password != password && password != ""
|
||||||
|
} else {
|
||||||
|
password_repeat == password && password != ""
|
||||||
|
};
|
||||||
|
|
||||||
|
get_action!(self.actions, @save_password).set_enabled(is_valid);
|
||||||
|
}
|
||||||
|
|
||||||
fn init(&self, page: Rc<Self>) {
|
fn init(&self, page: Rc<Self>) {
|
||||||
get_widget!(self.builder, gtk::PasswordEntry, current_password_entry);
|
get_widget!(self.builder, gtk::PasswordEntry, current_password_entry);
|
||||||
get_widget!(self.builder, gtk::PasswordEntry, password_entry);
|
get_widget!(self.builder, gtk::PasswordEntry, password_entry);
|
||||||
get_widget!(self.builder, gtk::PasswordEntry, confirm_password_entry);
|
get_widget!(self.builder, gtk::PasswordEntry, confirm_password_entry);
|
||||||
get_widget!(self.builder, libhandy::ActionRow, current_password_row);
|
get_widget!(self.builder, libhandy::ActionRow, current_password_row);
|
||||||
|
|
||||||
let has_set_password = Keyring::has_set_password().unwrap_or_else(|_| false);
|
password_entry.connect_changed(clone!(@strong page => move |_| page.validate()));
|
||||||
|
confirm_password_entry.connect_changed(clone!(@strong page => move |_| page.validate()));
|
||||||
|
|
||||||
let validate = clone!(@strong self.builder as builder,
|
if !self.has_set_password.get() {
|
||||||
@weak current_password_entry,
|
|
||||||
@weak password_entry,
|
|
||||||
@weak self.actions as actions,
|
|
||||||
@weak confirm_password_entry => move |_: >k::PasswordEntry| {
|
|
||||||
|
|
||||||
let current_password = current_password_entry.get_text().unwrap();
|
|
||||||
let password = password_entry.get_text().unwrap();
|
|
||||||
let password_repeat = confirm_password_entry.get_text().unwrap();
|
|
||||||
|
|
||||||
let is_valid = if has_set_password {
|
|
||||||
password_repeat == password && current_password != password
|
|
||||||
&& password != ""
|
|
||||||
} else {
|
|
||||||
password_repeat == password && password != ""
|
|
||||||
};
|
|
||||||
|
|
||||||
get_action!(actions, @save_password).set_enabled(is_valid);
|
|
||||||
});
|
|
||||||
|
|
||||||
password_entry.connect_changed(validate.clone());
|
|
||||||
confirm_password_entry.connect_changed(validate.clone());
|
|
||||||
|
|
||||||
if !has_set_password {
|
|
||||||
current_password_row.hide();
|
current_password_row.hide();
|
||||||
} else {
|
} else {
|
||||||
current_password_entry.connect_changed(validate.clone());
|
current_password_entry
|
||||||
|
.connect_changed(clone!(@strong page => move |_| page.validate()));
|
||||||
}
|
}
|
||||||
|
|
||||||
action!(
|
action!(
|
||||||
|
@ -67,7 +71,27 @@ impl PasswordPage {
|
||||||
page.save();
|
page.save();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
action!(
|
||||||
|
self.actions,
|
||||||
|
"reset_password",
|
||||||
|
clone!(@strong page => move |_,_| {
|
||||||
|
page.reset();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
get_action!(self.actions, @save_password).set_enabled(false);
|
get_action!(self.actions, @save_password).set_enabled(false);
|
||||||
|
get_action!(self.actions, @reset_password).set_enabled(self.has_set_password.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&self) {
|
||||||
|
if Keyring::reset_password().is_ok() {
|
||||||
|
get_action!(self.actions, @close_page).activate(None);
|
||||||
|
get_action!(self.actions, @save_password).set_enabled(false);
|
||||||
|
get_action!(self.actions, @reset_password).set_enabled(false);
|
||||||
|
get_widget!(self.builder, libhandy::ActionRow, @current_password_row).hide();
|
||||||
|
self.has_set_password.set(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save(&self) {
|
fn save(&self) {
|
||||||
|
@ -90,7 +114,9 @@ impl PasswordPage {
|
||||||
password_entry.set_text("");
|
password_entry.set_text("");
|
||||||
confirm_password_entry.set_text("");
|
confirm_password_entry.set_text("");
|
||||||
get_action!(self.actions, @save_password).set_enabled(false);
|
get_action!(self.actions, @save_password).set_enabled(false);
|
||||||
|
get_action!(self.actions, @reset_password).set_enabled(true);
|
||||||
get_action!(self.actions, @close_page).activate(None);
|
get_action!(self.actions, @close_page).activate(None);
|
||||||
|
self.has_set_password.set(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue