🚚 Moving and renaming generator entity

refactoring/split-modules
German Lashevich 7 years ago
parent ba6a743159
commit f130fc2128
No known key found for this signature in database
GPG Key ID: 3446FAE369C9A8B4

@ -0,0 +1,62 @@
extern crate base32;
extern crate oath;
// Generator application struct
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TOTP {
name: String,
secret: String,
username: String,
secret_bytes: Vec<u8>,
}
impl TOTP {
pub fn new(name: &str, username: &str, secret: &str, secret_bytes: Vec<u8>) -> Self {
TOTP {
name: String::from(name),
secret: String::from(secret),
username: String::from(username),
secret_bytes: secret_bytes,
}
}
pub fn new_base32(
name: &str,
username: &str,
base32_secret: &str,
) -> Result<TOTP, String> {
if let Some(secret_bytes) = TOTP::base32_to_bytes(base32_secret) {
Ok(TOTP::new(name, username, base32_secret, secret_bytes))
} else {
Err(String::from("Couldn't decode secret key"))
}
}
pub fn get_name(&self) -> &str {
self.name.as_str()
}
pub fn set_name(&mut self, name: &str) {
self.name = String::from(name);
}
pub fn get_secret(&self) -> &str {
self.secret.as_str()
}
pub fn get_username(&self) -> &str {
self.username.as_str()
}
pub fn get_code(&self) -> u64 {
Self::totp(&self.secret_bytes)
}
fn base32_to_bytes(secret: &str) -> Option<Vec<u8>> {
base32::decode(base32::Alphabet::RFC4648 { padding: false }, secret)
}
fn totp(secret_bytes: &[u8]) -> u64 {
oath::totp_raw_now(&secret_bytes, 6, 0, 30, &oath::HashType::SHA1)
}
}

@ -1,14 +1,16 @@
#![feature(fs_read_write)]
extern crate base32;
extern crate crypto;
extern crate oath;
extern crate rand;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
mod generators;
use generators::TOTP;
use crypto::buffer::{BufferResult, ReadBuffer, WriteBuffer};
use crypto::digest::Digest;
use crypto::sha2::Sha256;
@ -24,9 +26,11 @@ use std::path::{Path, PathBuf};
const DATABASE_VERSION: u8 = 1;
// Application struct
// Contains database reference and in-memory generators (called «applications»)
pub struct RusTOTPony<DB: Database> {
database: DB,
applications: HashMap<String, GenApp>,
applications: HashMap<String, TOTP>,
}
impl<DB: Database> RusTOTPony<DB> {
@ -43,16 +47,12 @@ impl<DB: Database> RusTOTPony<DB> {
username: &str,
secret: &str,
) -> Result<(), String> {
if let Some(secret_bytes) = GenApp::base32_to_bytes(secret) {
let new_app = GenApp::new(name, username, secret, secret_bytes);
if self.applications.contains_key(name) {
Err(format!("Application with name '{}' already exists!", name))
} else {
&self.applications.insert(String::from(name), new_app);
Ok(())
}
let new_app = TOTP::new_base32(name, username, secret)?;
if self.applications.contains_key(name) {
Err(format!("Application with name '{}' already exists!", name))
} else {
return Err(String::from("Couldn't decode secret key"));
&self.applications.insert(String::from(name), new_app);
Ok(())
}
}
@ -69,14 +69,14 @@ impl<DB: Database> RusTOTPony<DB> {
pub fn rename_application(&mut self, name: &str, newname: &str) -> Result<(), String> {
if let Some(app) = self.applications.get_mut(name) {
app.name = String::from(newname);
app.set_name(newname);
Ok(())
} else {
Err(format!("Application '{}' wasn't found", name))
}
}
pub fn get_applications(&self) -> Result<&HashMap<String, GenApp>, String> {
pub fn get_applications(&self) -> Result<&HashMap<String, TOTP>, String> {
if self.applications.len() == 0 {
Err(String::from("There are no applications"))
} else {
@ -84,7 +84,7 @@ impl<DB: Database> RusTOTPony<DB> {
}
}
pub fn get_application(&self, name: &str) -> Result<&GenApp, String> {
pub fn get_application(&self, name: &str) -> Result<&TOTP, String> {
if let Some(app) = self.applications.get(name) {
Ok(app)
} else {
@ -101,18 +101,20 @@ impl<DB: Database> RusTOTPony<DB> {
}
}
// Database trait
pub trait Database {
fn get_applications(&self) -> HashMap<String, GenApp>;
fn save_applications(&self, applications: &HashMap<String, GenApp>);
fn get_applications(&self) -> HashMap<String, TOTP>;
fn save_applications(&self, applications: &HashMap<String, TOTP>);
}
// Database implementation for JSON database
impl Database for JsonDatabase {
fn get_applications(&self) -> HashMap<String, GenApp> {
fn get_applications(&self) -> HashMap<String, TOTP> {
let db_content = self.read_database_file();
db_content.content.applications
}
fn save_applications(&self, applications: &HashMap<String, GenApp>) {
fn save_applications(&self, applications: &HashMap<String, TOTP>) {
let mut db_content = Self::get_empty_schema();
db_content.content.applications = applications.clone();
self.save_database_file(db_content);
@ -127,7 +129,7 @@ struct JsonDatabaseSchema {
#[derive(Serialize, Deserialize)]
struct DatabaseContentSchema {
applications: HashMap<String, GenApp>,
applications: HashMap<String, TOTP>,
}
pub struct JsonDatabase {
@ -189,7 +191,8 @@ impl JsonDatabase {
fn save_database_file(&self, content: JsonDatabaseSchema) {
let mut file = match self.open_database_file_for_write() {
Ok(f) => f,
Err(ref err) if err.kind() == ErrorKind::NotFound => self.create_database_file()
Err(ref err) if err.kind() == ErrorKind::NotFound => self
.create_database_file()
.expect("Couldn't create database file"),
Err(err) => panic!("Couldn't open database file: {:?}", err),
};
@ -326,45 +329,6 @@ impl JsonDatabase {
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct GenApp {
name: String,
secret: String,
username: String,
secret_bytes: Vec<u8>,
}
impl GenApp {
fn new(name: &str, username: &str, secret: &str, secret_bytes: Vec<u8>) -> Self {
GenApp {
name: String::from(name),
secret: String::from(secret),
username: String::from(username),
secret_bytes: secret_bytes,
}
}
pub fn get_name(&self) -> &str {
self.name.as_str()
}
pub fn get_secret(&self) -> &str {
self.secret.as_str()
}
pub fn get_username(&self) -> &str {
self.username.as_str()
}
pub fn get_code(&self) -> u64 {
Self::totp(&self.secret_bytes)
}
fn base32_to_bytes(secret: &str) -> Option<Vec<u8>> {
base32::decode(base32::Alphabet::RFC4648 { padding: false }, secret)
}
fn totp(secret_bytes: &[u8]) -> u64 {
oath::totp_raw_now(&secret_bytes, 6, 0, 30, &oath::HashType::SHA1)
}
}
// Application → Database (JsonDatabase, EncryptedDatabase)
// ↓ ↓
// GeneratorApplication

Loading…
Cancel
Save