extern crate cli_clipboard; extern crate cursive; extern crate isahc; use std::{cell::RefCell, rc::Rc}; use cursive::theme::Effect::{Bold, Reverse, Underline}; use cursive::theme::{BorderStyle, Palette, Style}; use cursive::{ utils::markup::StyledString, views::{Dialog, EditView}, Cursive, With, }; use screen::TOTPScreen; use crate::client::Client; use crate::screen::{HomeScreen, LoginScreen, Screen}; mod client; mod screen; type ClientBox = Rc>; fn main() { let mut siv = cursive::default(); let client: ClientBox = Rc::new(RefCell::new(Client::try_new().unwrap())); siv.set_theme(cursive::theme::Theme { shadow: true, borders: BorderStyle::Simple, palette: Palette::retro().with(|palette| { use cursive::theme::BaseColor::*; use cursive::theme::Color::TerminalDefault; use cursive::theme::PaletteColor::*; palette[Background] = TerminalDefault; palette[View] = TerminalDefault; palette[Primary] = White.dark(); palette[TitlePrimary] = Blue.light(); palette[Secondary] = Blue.light(); palette[Highlight] = Blue.dark(); palette[cursive::theme::PaletteStyle::Highlight] = Style::from(Blue.light()).combine(Bold); palette[cursive::theme::PaletteStyle::HighlightInactive] = Style::secondary().combine(Reverse).combine(Underline) }), }); if client.borrow().check_connection().is_ok() { HomeScreen::new(&client).print(&mut siv); } else { LoginScreen::new(&client).print(&mut siv); } siv.run(); } #[allow(unused)] fn login(s: &mut Cursive, client: &ClientBox, username: &str, password: &str, totp: &str) { if username.is_empty() { info(s, "Please enter your username"); } else if password.is_empty() { info(s, "Please enter your password"); } else { Rc::clone(client) .borrow_mut() .set_username(username.to_string()); if Rc::clone(client).borrow().has_salt() { if Rc::clone(client) .borrow_mut() .derive_keyring(password.to_string()) .is_err() { info(s, "An error occurred while creating client") } else if Rc::clone(client).borrow().check_connection().is_err() { info(s, "An error occurred while logging in"); } else { HomeScreen::new(client).replace(s); } } else { match totp.parse() { Ok(totp) => { if Rc::clone(client).borrow_mut().fetch_salt(totp).is_err() { info(s, "An error occurred while fetching salt") } else if Rc::clone(client) .borrow_mut() .derive_keyring(password.to_string()) .is_err() { info(s, "An error occurred while creating client") } else if Rc::clone(client).borrow().check_connection().is_err() { info(s, "An error occurred while logging in"); } else { HomeScreen::new(client).replace(s); } } Err(err) => info(s, err), } } } } fn signup(s: &mut Cursive, client: &ClientBox, username: &str, password: &str, confirm: &str) { if username.is_empty() { info(s, "Please enter your username"); } else if password.is_empty() { info(s, "Please enter your password"); } else if confirm.is_empty() { info(s, "Please confirm your password"); } else if password != confirm { info(s, "Passwords does not match"); } else { Rc::clone(client) .borrow_mut() .set_username(username.to_string()); Rc::clone(client).borrow_mut().generate_random_salt(); if Rc::clone(client) .borrow_mut() .derive_keyring(password.to_string()) .is_err() { info(s, "An error occurred while creating client") } else { TOTPScreen::new(client) .with_label(username.to_string()) .with_generator( Rc::clone(client) .borrow() .get_totp_generator() .expect("Keyring disappeared"), ) .and_then(|s, client, success| { if success { if Rc::clone(client).borrow().create_account().is_err() { info(s, "An error occurred while signing up") } else { HomeScreen::new(client).replace(s); } } }) .print(s); } } } fn quit(s: &mut Cursive) { s.add_layer( Dialog::text("Are you sure?") .button("Go back", |s| { s.pop_layer(); }) .button("Quit", Cursive::quit), ); } fn secret_input() -> EditView { let mut input = EditView::new(); input.set_secret(true); input } fn info>(s: &mut Cursive, msg: S) { s.add_layer(Dialog::info(msg)); } fn get_content(view: &mut EditView) -> Rc { view.get_content() }