Skip to content

Commit

Permalink
UI copy&paste button (#30)
Browse files Browse the repository at this point in the history
* Copy totp button - toggling image
* Add account - selecting first entry in group drop down.
* Log4rs
* Ordering alphabetically groups and accounts
  • Loading branch information
gr211 authored Jun 25, 2020
1 parent a21ac7f commit 7bfcbb6
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 52 deletions.
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ futures = {version = "0.3.5", features = ["thread-pool"]}
futures-executor = "0.3.5"
gdk = "0.12.1"
gio = "0.8.1"
log = "0.4.8"
log4rs = "0.12.0"
rusqlite = "0.23.1"
serde_json = "1.0.55"
serde = { version = "1.0.111", features = ["derive"] }
serde_json = "1.0.55"
serde_yaml = "0.8.13"
totp-rs = "0.2.6"

[dependencies.gtk]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Download from the [release](https://github.com/grumlimited/authenticator-rs/rele

make target/release/authenticator-rs

$HOME/.cargo/bin/authenticator-rust
./target/release/authenticator-rs

## Running (dev)

Expand Down
14 changes: 14 additions & 0 deletions data/log4rs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
refresh_rate: 30 seconds

appenders:
stdout:
kind: console

root:
level: info
appenders:
- stdout

loggers:
authenticator_rs:
level: debug
1 change: 1 addition & 0 deletions data/uk.co.grumlimited.authenticator-rs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
<gresource prefix="/uk/co/grumlimited/authenticator-rs">
<file alias="authenticator-rs.svg">data/uk.co.grumlimited.authenticator-rs.svg</file>
<file alias="style.css">data/style.css</file>
<file alias="log4rs.yaml">data/log4rs.yaml</file>
</gresource>
</gresources>
85 changes: 40 additions & 45 deletions src/helpers/config_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,6 @@ pub enum LoadError {
}

impl ConfigManager {
pub fn _log4rs() -> std::path::PathBuf {
let mut path = ConfigManager::path();
path.push("log4rs.yaml");

path
}

fn db_path() -> std::path::PathBuf {
let mut path = ConfigManager::path();
path.push("authenticator.db");
Expand Down Expand Up @@ -54,7 +47,9 @@ impl ConfigManager {

let conn = conn.lock().unwrap();

let mut stmt = conn.prepare("SELECT id, name FROM groups").unwrap();
let mut stmt = conn
.prepare("SELECT id, name FROM groups ORDER BY LOWER(name)")
.unwrap();

stmt.query_map(params![], |row| {
let id: u32 = row.get(0)?;
Expand All @@ -75,27 +70,6 @@ impl ConfigManager {
.map_err(|e| LoadError::DbError(format!("{:?}", e)))
}

fn _create_group(
conn: Arc<Mutex<Connection>>,
group_name: &str,
) -> Result<AccountGroup, LoadError> {
let conn = conn.lock().unwrap();

conn.execute("INSERT INTO groups (name) VALUES (?1)", params![group_name])
.map_err(|e| LoadError::DbError(format!("{:?}", e)))
.unwrap();

let mut stmt = conn.prepare("SELECT last_insert_rowid()").unwrap();

stmt.query_row(NO_PARAMS, |row| row.get::<usize, u32>(0))
.map(|id| AccountGroup {
id,
name: group_name.to_owned(),
..Default::default()
})
.map_err(|e| LoadError::DbError(format!("{:?}", e)))
}

pub fn update_group(
conn: Arc<Mutex<Connection>>,
group: &AccountGroup,
Expand Down Expand Up @@ -274,8 +248,9 @@ impl ConfigManager {
}

fn get_accounts(conn: &Connection, group_id: u32) -> Result<Vec<Account>, rusqlite::Error> {
let mut stmt =
conn.prepare("SELECT id, label, secret FROM accounts WHERE group_id = ?1")?;
let mut stmt = conn.prepare(
"SELECT id, label, secret FROM accounts WHERE group_id = ?1 ORDER BY LOWER(label)",
)?;

stmt.query_map(params![group_id], |row| {
let id: u32 = row.get(0)?;
Expand All @@ -294,10 +269,8 @@ impl ConfigManager {
mod tests {
use super::ConfigManager;
use rusqlite::Connection;
use std::path::Path;

use crate::model::{Account, AccountGroup};
use async_std::task;
use std::sync::{Arc, Mutex};

#[test]
Expand All @@ -306,7 +279,7 @@ mod tests {

let _ = {
let conn = conn.clone();
ConfigManager::init_tables(conn);
ConfigManager::init_tables(conn).expect("boom!");
};

let mut group = AccountGroup::new(0, "new group", vec![]);
Expand Down Expand Up @@ -352,7 +325,7 @@ mod tests {

let _ = {
let conn = conn.clone();
ConfigManager::init_tables(conn);
ConfigManager::init_tables(conn).expect("boom!");
};

let mut group = AccountGroup::new(0, "new group", vec![]);
Expand Down Expand Up @@ -382,12 +355,13 @@ mod tests {

let _ = {
let conn = conn.clone();
ConfigManager::init_tables(conn);
ConfigManager::init_tables(conn).expect("boom!");
};

let mut group = AccountGroup::new(0, "existing_group2", vec![]);
let group = {
let conn = conn.clone();
ConfigManager::_create_group(conn, "existing_group2").unwrap()
ConfigManager::save_group(conn, &mut group).unwrap()
};

let mut account = Account::new(0, group.id, "label", "secret");
Expand All @@ -409,21 +383,42 @@ mod tests {
}

#[test]
fn get_or_create_group_with_new_group() {
fn save_group_ordering() {
let conn = Arc::new(Mutex::new(Connection::open_in_memory().unwrap()));

let _ = {
{
let conn = conn.clone();
ConfigManager::init_tables(conn);
ConfigManager::init_tables(conn).expect("boom!");
};

let group = {
{
let conn = conn.clone();
let conn2 = conn.clone();
let conn3 = conn.clone();
let mut group = AccountGroup::new(0, "bbb", vec![]);
ConfigManager::save_group(conn, &mut group).unwrap();

let mut account1 = Account::new(0, group.id, "hhh", "secret3");
ConfigManager::save_account(conn2, &mut account1).expect("boom!");
let mut account2 = Account::new(0, group.id, "ccc", "secret3");
ConfigManager::save_account(conn3, &mut account2).expect("boom!");
};

{
let conn = conn.clone();
ConfigManager::_create_group(conn, "existing_group2").unwrap()
let mut group = AccountGroup::new(0, "AAA", vec![]);
ConfigManager::save_group(conn, &mut group).expect("boom!");
};

assert!(group.id > 0);
assert_eq!("existing_group2", group.name);
let results = ConfigManager::load_account_groups(conn).unwrap();

//groups in order
assert_eq!("AAA", results.get(0).unwrap().name);
assert_eq!("bbb", results.get(1).unwrap().name);

//accounts in order
assert_eq!("ccc", results.get(1).unwrap().entries.get(0).unwrap().label);
assert_eq!("hhh", results.get(1).unwrap().entries.get(1).unwrap().label);
}

#[test]
Expand All @@ -432,7 +427,7 @@ mod tests {

let _ = {
let conn = conn.clone();
ConfigManager::init_tables(conn);
ConfigManager::init_tables(conn).expect("boom!");
};

let mut account = Account::new(0, 0, "label", "secret");
Expand Down
37 changes: 36 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use crate::model::AccountGroup;
use crate::ui::{AccountsWindow, AddGroupWindow, EditAccountWindow};
use gio::prelude::*;
use gtk::prelude::*;
use log4rs::config::Config;
use log4rs::file::{Deserializers, RawConfig};
use rusqlite::Connection;
use std::cell::RefCell;
use std::sync::{Arc, Mutex};
Expand All @@ -19,6 +21,8 @@ mod helpers;
mod model;
mod ui;

use log::info;

const NAMESPACE: &str = "uk.co.grumlimited.authenticator-rs";
const NAMESPACE_PREFIX: &str = "/uk/co/grumlimited/authenticator-rs";

Expand All @@ -27,7 +31,7 @@ fn main() {
.expect("Initialization failed...");

let resource = {
match gio::Resource::load(format!("/usr/share/{}/{}.gresource", NAMESPACE, NAMESPACE)) {
match gio::Resource::load(format!("data/{}.gresource", NAMESPACE)) {
Ok(resource) => resource,
Err(_) => gio::Resource::load(format!("data/{}.gresource", NAMESPACE)).unwrap(),
}
Expand All @@ -44,6 +48,8 @@ fn main() {
&provider,
gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
);

configure_logging();
});

application.connect_activate(|app| {
Expand Down Expand Up @@ -88,7 +94,36 @@ fn main() {
}

AccountsWindow::delete_buttons_actions(gui, connection);

info!("Authenticator RS initialised");
});

application.run(&[]);
}

/**
* Loads log4rs yaml config from gResource.
* And in the most convoluted possible way, feeds it to Log4rs.
*/
fn configure_logging() {
let log4rs_yaml = gio::functions::resources_lookup_data(
format!("{}/{}", NAMESPACE_PREFIX, "log4rs.yaml").as_str(),
gio::ResourceLookupFlags::NONE,
)
.unwrap();
let log4rs_yaml = log4rs_yaml.to_vec();
let log4rs_yaml = String::from_utf8(log4rs_yaml).unwrap();

// log4rs-0.12.0/src/file.rs#592
let config = serde_yaml::from_str::<RawConfig>(log4rs_yaml.as_str()).unwrap();
let (appenders, _) = config.appenders_lossy(&Deserializers::default());

// log4rs-0.12.0/src/priv_file.rs#deserialize(config: &RawConfig, deserializers: &Deserializers)#186
let config = Config::builder()
.appenders(appenders)
.loggers(config.loggers())
.build(config.root())
.unwrap();

log4rs::init_config(config).unwrap();
}
16 changes: 14 additions & 2 deletions src/main_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub struct MainWindow {
pub edit_account_window: ui::EditAccountWindow,
pub accounts_window: ui::AccountsWindow,
pub add_group: ui::AddGroupWindow,
pool: ThreadPool,
pub pool: ThreadPool,
state: Rc<RefCell<State>>,
}

Expand Down Expand Up @@ -235,10 +235,18 @@ impl MainWindow {
});
}

{
let titlebar = gtk::HeaderBarBuilder::new()
.decoration_layout(":")
.title("About")
.build();

let popup = self.popup.clone();
popup.set_titlebar(Some(&titlebar));
}
{
let popup = self.popup.clone();
about_button.connect_clicked(move |_| {
popup.set_title("About");
popover.set_visible(false);
popup.set_visible(true);
popup.show_all();
Expand Down Expand Up @@ -365,6 +373,10 @@ impl MainWindow {
.append(entry_id, group.name.as_str());
});

let first_entry = groups.get(0).map(|e| format!("{}", e.id));
let first_entry = first_entry.as_deref();
edit_account_window.input_group.set_active_id(first_entry);

edit_account_window.input_account_id.set_text("0");
edit_account_window.input_name.set_text("");

Expand Down
2 changes: 2 additions & 0 deletions src/mainwindow.glade
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,8 @@
<property name="modal">True</property>
<property name="window_position">center-on-parent</property>
<property name="destroy_with_parent">True</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="deletable">False</property>
<property name="transient_for">main_window</property>
<property name="attached_to">main_window</property>
Expand Down
12 changes: 10 additions & 2 deletions src/model/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use base32::Alphabet::RFC4648;

use gtk::prelude::*;
use gtk::{Align, Orientation};
use std::sync::{Arc, Mutex};

#[derive(Debug, Clone, Default, PartialEq)]
pub struct Account {
Expand All @@ -21,7 +22,10 @@ pub struct AccountWidgets {
pub grid: gtk::Grid,
pub edit_button: gtk::Button,
pub delete_button: gtk::Button,
pub copy_button: Arc<Mutex<gtk::Button>>,
pub popover: gtk::PopoverMenu,
pub edit_copy_img: Arc<Mutex<gtk::Image>>,
pub dialog_ok_img: Arc<Mutex<gtk::Image>>,
totp_label: gtk::Label,
totp_secret: String,
}
Expand Down Expand Up @@ -68,12 +72,13 @@ impl Account {
.xalign(0.0)
.build();

let image = gtk::ImageBuilder::new().icon_name("edit-copy").build();
let edit_copy_img = gtk::ImageBuilder::new().icon_name("edit-copy").build();
let dialog_ok_img = gtk::ImageBuilder::new().icon_name("dialog-ok").build();

let copy_button = gtk::ButtonBuilder::new()
.margin_start(5)
.margin_end(5)
.image(&image)
.image(&edit_copy_img)
.always_show_image(true)
.build();

Expand Down Expand Up @@ -146,6 +151,9 @@ impl Account {
grid,
edit_button,
delete_button,
copy_button: Arc::new(Mutex::new(copy_button)),
edit_copy_img: Arc::new(Mutex::new(edit_copy_img)),
dialog_ok_img: Arc::new(Mutex::new(dialog_ok_img)),
popover: popover_clone,
totp_label: totp_label_clone2,
totp_secret: self.secret.clone(),
Expand Down
Loading

0 comments on commit 7bfcbb6

Please sign in to comment.