From 908b88ebf4aa557e8b08350cecfa56153e4cc2f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa=20Moreno?= Date: Fri, 18 Aug 2017 13:12:26 +0200 Subject: [PATCH] Storing the user password with secret-service --- Cargo.toml | 2 +- res/main_window.glade | 2 +- src/app.rs | 100 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 95 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 438f9253..f9db84f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,12 +2,12 @@ authors = ["Daniel Garcia "] name = "guillotine" version = "0.1.0" - [dependencies] gdk-pixbuf = "0.1.3" gio = "0.1.3" regex = "0.2.2" reqwest = "0.7.2" +secret-service = "0.4.0" serde = "1.0.11" serde_derive = "1.0.11" serde_json = "1.0.2" diff --git a/res/main_window.glade b/res/main_window.glade index e63f7c2e..bb30c6c9 100644 --- a/res/main_window.glade +++ b/res/main_window.glade @@ -394,7 +394,7 @@ False - address-book-new + image-missing 3 diff --git a/src/app.rs b/src/app.rs index 033b5fb0..b43bb4c2 100644 --- a/src/app.rs +++ b/src/app.rs @@ -2,6 +2,10 @@ extern crate gtk; extern crate gio; extern crate gdk_pixbuf; +extern crate secret_service; +use self::secret_service::SecretService; +use self::secret_service::EncryptionType; + use std::env; use std::sync::{Arc, Mutex}; use std::sync::mpsc::channel; @@ -14,6 +18,25 @@ use backend::Backend; use backend; +macro_rules! derror { + ($from: path, $to: path) => { + impl From<$from> for Error { + fn from(_: $from) -> Error { + $to + } + } + }; +} + + +#[derive(Debug)] +pub enum Error { + SecretServiceError, +} + +derror!(secret_service::SsError, Error::SecretServiceError); + + // TODO: Is this the correct format for GApplication IDs? const APP_ID: &'static str = "org.gnome.guillotine"; @@ -24,7 +47,7 @@ struct AppOp { } impl AppOp { - pub fn login(&mut self) { + pub fn login(&self) { let user_entry: gtk::Entry = self.gtk_builder.get_object("login_username").unwrap(); let pass_entry: gtk::Entry = self.gtk_builder.get_object("login_password").unwrap(); let server_entry: gtk::Entry = self.gtk_builder.get_object("login_server").unwrap(); @@ -35,18 +58,24 @@ impl AppOp { self.connect(username, password, server_entry.get_text()); } - pub fn connect(&mut self, username: String, password: String, server: Option) { + pub fn connect(&self, username: String, password: String, server: Option) { let server_url = match server { Some(s) => s, None => String::from("https://matrix.org") }; + self.store_pass(username.clone(), password.clone(), server_url.clone()) + .unwrap_or_else(|_| { + // TODO: show an error + println!("Error: Can't store the password using libsecret"); + }); + self.show_loading(); self.backend.login(username, password, server_url).unwrap(); self.hide_popup(); } - pub fn connect_guest(&mut self, server: Option) { + pub fn connect_guest(&self, server: Option) { let server_url = match server { Some(s) => s, None => String::from("https://matrix.org") @@ -103,9 +132,68 @@ impl AppOp { user_menu.hide(); } - pub fn disconnect(&mut self) { + pub fn disconnect(&self) { println!("Disconnecting"); } + + pub fn store_pass(&self, username: String, password: String, server: String) -> Result<(), Error> { + let ss = SecretService::new(EncryptionType::Dh)?; + let collection = ss.get_default_collection()?; + + //create new item + collection.create_item( + "guillotine", // label + vec![ + ("username", &username), + ("server", &server), + ], // properties + password.as_bytes(), //secret + true, // replace item with same attributes + "text/plain" // secret content type + )?; + + Ok(()) + } + + pub fn get_pass(&self) -> Result<(String, String, String), Error> { + let ss = SecretService::new(EncryptionType::Dh)?; + let collection = ss.get_default_collection()?; + let allpass = collection.get_all_items()?; + + let passwd = allpass.iter() + .find(|x| x.get_label().unwrap_or(String::from("")) == "guillotine"); + + if passwd.is_none() { + return Err(Error::SecretServiceError); + } + + let p = passwd.unwrap(); + let attrs = p.get_attributes()?; + let secret = p.get_secret()?; + + let mut attr = attrs.iter().find(|&ref x| x.0 == "username") + .ok_or(Error::SecretServiceError)?; + let username = attr.1.clone(); + attr = attrs.iter().find(|&ref x| x.0 == "server") + .ok_or(Error::SecretServiceError)?; + let server = attr.1.clone(); + + let tup = ( + username, + String::from_utf8(secret).unwrap(), + server, + ); + + Ok(tup) + } + + pub fn init(&self) { + if let Ok(pass) = self.get_pass() { + self.connect(pass.0, pass.1, Some(pass.2)); + } else { + self.connect_guest(None); + } + } } /// State for the main thread. @@ -212,9 +300,7 @@ impl App { let args = env::args().collect::>(); let args_refs = args.iter().map(|x| &x[..]).collect::>(); - // connecting as guest - // TODO: Use stored user if exists - self.op.lock().unwrap().connect_guest(None); + self.op.lock().unwrap().init(); // Run the main loop. self.gtk_app.run(args_refs.len() as i32, &args_refs);