mirror of
https://gitlab.gnome.org/World/Authenticator.git
synced 2025-03-04 08:44:40 +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>
|
||||
</object>
|
||||
</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>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
@ -28,10 +28,22 @@ pub struct ApplicationPrivate {
|
|||
sender: Sender<Action>,
|
||||
receiver: RefCell<Option<Receiver<Action>>>,
|
||||
locked: Cell<bool>,
|
||||
can_be_locked: Cell<bool>,
|
||||
}
|
||||
static PROPERTIES: [subclass::Property; 1] = [subclass::Property("locked", |name| {
|
||||
glib::ParamSpec::boolean(name, "locked", "locked", false, glib::ParamFlags::READWRITE)
|
||||
})];
|
||||
static PROPERTIES: [subclass::Property; 2] = [
|
||||
subclass::Property("locked", |name| {
|
||||
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 {
|
||||
const NAME: &'static str = "Application";
|
||||
type ParentType = gtk::Application;
|
||||
|
@ -54,6 +66,7 @@ impl ObjectSubclass for ApplicationPrivate {
|
|||
sender,
|
||||
receiver,
|
||||
model,
|
||||
can_be_locked: Cell::new(false),
|
||||
locked: Cell::new(false),
|
||||
}
|
||||
}
|
||||
|
@ -71,6 +84,13 @@ impl ObjectImpl for ApplicationPrivate {
|
|||
.unwrap();
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
|
@ -80,6 +100,7 @@ impl ObjectImpl for ApplicationPrivate {
|
|||
|
||||
match *prop {
|
||||
subclass::Property("locked", ..) => Ok(self.locked.get().to_value()),
|
||||
subclass::Property("can-be-locked", ..) => Ok(self.can_be_locked.get().to_value()),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
@ -140,6 +161,10 @@ impl ApplicationImpl for ApplicationPrivate {
|
|||
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) {
|
||||
|
@ -154,16 +179,16 @@ impl ApplicationImpl for ApplicationPrivate {
|
|||
let window = app.create_window();
|
||||
window.present();
|
||||
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_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.search", &["<primary>f"]);
|
||||
app.set_accels_for_action("win.add-account", &["<primary>n"]);
|
||||
app.set_property(
|
||||
"locked",
|
||||
&Keyring::has_set_password().unwrap_or_else(|_| false),
|
||||
);
|
||||
app.set_locked(has_set_password);
|
||||
app.set_can_be_locked(has_set_password);
|
||||
let receiver = self.receiver.borrow_mut().take().unwrap();
|
||||
receiver.attach(None, move |action| app.do_action(action));
|
||||
}
|
||||
|
@ -210,6 +235,10 @@ impl Application {
|
|||
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 {
|
||||
let self_ = ApplicationPrivate::from_instance(self);
|
||||
let window = Window::new(self_.model.clone(), self_.sender.clone(), &self.clone());
|
||||
|
|
|
@ -40,6 +40,18 @@ impl Keyring {
|
|||
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> {
|
||||
let ss = SecretService::new(EncryptionType::Dh)?;
|
||||
let col = Self::get_default_collection(&ss)?;
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
use crate::helpers::Keyring;
|
||||
use gio::{ActionExt, ActionMapExt};
|
||||
use gtk::prelude::*;
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct PasswordPage {
|
||||
pub widget: gtk::Box,
|
||||
builder: gtk::Builder,
|
||||
actions: gio::SimpleActionGroup,
|
||||
has_set_password: Cell<bool>,
|
||||
}
|
||||
|
||||
impl PasswordPage {
|
||||
|
@ -14,50 +17,51 @@ impl PasswordPage {
|
|||
"/com/belmoussaoui/Authenticator/preferences_password_page.ui",
|
||||
);
|
||||
get_widget!(builder, gtk::Box, password_page);
|
||||
|
||||
let has_set_password = Keyring::has_set_password().unwrap_or_else(|_| false);
|
||||
|
||||
let page = Rc::new(Self {
|
||||
widget: password_page,
|
||||
builder,
|
||||
actions,
|
||||
has_set_password: Cell::new(has_set_password),
|
||||
});
|
||||
page.init(page.clone());
|
||||
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>) {
|
||||
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);
|
||||
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,
|
||||
@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 {
|
||||
if !self.has_set_password.get() {
|
||||
current_password_row.hide();
|
||||
} else {
|
||||
current_password_entry.connect_changed(validate.clone());
|
||||
current_password_entry
|
||||
.connect_changed(clone!(@strong page => move |_| page.validate()));
|
||||
}
|
||||
|
||||
action!(
|
||||
|
@ -67,7 +71,27 @@ impl PasswordPage {
|
|||
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, @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) {
|
||||
|
@ -90,7 +114,9 @@ impl PasswordPage {
|
|||
password_entry.set_text("");
|
||||
confirm_password_entry.set_text("");
|
||||
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);
|
||||
self.has_set_password.set(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue