mirror of
https://github.com/MedzikUser/HomeDisk.git
synced 2024-08-14 21:46:53 +00:00
utils (crypto/database): update cryptographic functions/add comments and tests in database
This commit is contained in:
parent
0867e44d58
commit
5b79b4f7e2
8 changed files with 166 additions and 55 deletions
26
Cargo.lock
generated
26
Cargo.lock
generated
|
@ -275,6 +275,7 @@ dependencies = [
|
|||
"sha-1",
|
||||
"sha2",
|
||||
"toml",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -535,6 +536,21 @@ dependencies = [
|
|||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770"
|
||||
dependencies = [
|
||||
"sha1_smol",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1_smol"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.2"
|
||||
|
@ -694,6 +710,16 @@ version = "0.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"sha1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"core",
|
||||
"utils",
|
||||
"core"
|
||||
]
|
||||
resolver = "2"
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
mod init;
|
||||
|
||||
use homedisk_utils::{config::Config, database::Database};
|
||||
use homedisk_utils::{
|
||||
config::Config,
|
||||
database::{Database, User},
|
||||
};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
@ -8,5 +11,11 @@ async fn main() {
|
|||
|
||||
let _config = Config::parse().expect("parse configuration file");
|
||||
|
||||
let _db = Database::open().expect("open SQLite database");
|
||||
let _db = Database::open("homedisk.db").expect("open SQLite database");
|
||||
|
||||
let user = User::new("medzik", "password").unwrap();
|
||||
|
||||
println!("{:?}", user);
|
||||
|
||||
_db.create_user(user).unwrap();
|
||||
}
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
CREATE TABLE user (
|
||||
id INTEGER PRIMARY KEY,
|
||||
username TEXT NOT NULL,
|
||||
id TEXT PRIMARY KEY UNIQUE,
|
||||
username TEXT NOT NULL UNIQUE,
|
||||
password TEXT NOT NULL
|
||||
);
|
||||
|
||||
/* create root user with password 'root' */
|
||||
INSERT INTO user (username, password) VALUES ('root', '99adc231b045331e514a516b4b7680f588e3823213abe901738bc3ad67b2f6fcb3c64efb93d18002588d3ccc1a49efbae1ce20cb43df36b38651f11fa75678e8');
|
||||
|
|
|
@ -7,7 +7,7 @@ edition = "2021"
|
|||
full = ["crypto", "config", "database"]
|
||||
crypto = ["sha-1", "sha2", "hex"]
|
||||
config = ["toml", "anyhow", "dirs"]
|
||||
database = ["rusqlite"]
|
||||
database = ["rusqlite", "uuid"]
|
||||
|
||||
[dependencies]
|
||||
log = "0.4.16"
|
||||
|
@ -43,3 +43,7 @@ optional = true
|
|||
version = "0.27.0"
|
||||
features = ["bundled"]
|
||||
optional = true
|
||||
[dependencies.uuid]
|
||||
version = "0.8.2"
|
||||
features = ["v4", "v5"]
|
||||
optional = true
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use hex::encode;
|
||||
pub use hex::encode;
|
||||
use sha1::Sha1;
|
||||
use sha2::{Digest, Sha256, Sha512};
|
||||
|
||||
|
@ -7,73 +7,102 @@ use super::{Error, Result};
|
|||
/// create a cryptographic hash from a string (sha1, sha256, sha512)
|
||||
///
|
||||
/// ```
|
||||
/// use homedisk_utils::crypto::hasher;
|
||||
/// use homedisk_utils::crypto::{CryptographicHash, encode};
|
||||
///
|
||||
/// let sha1 = hasher("SHA-1", "test string".to_string()).unwrap();
|
||||
/// assert_eq!(sha1, "661295c9cbf9d6b2f6428414504a8deed3020641".to_string())
|
||||
/// let mut sha1 = CryptographicHash::new("SHA-1").unwrap();
|
||||
/// sha1.update(b"test sha1 hash");
|
||||
///
|
||||
/// let hash = encode(sha1.finalize());
|
||||
///
|
||||
/// assert_eq!(hash, "7726bd9560e1ad4a1a4f056cae5c0c9ea8bacfc2".to_string())
|
||||
/// ```
|
||||
pub fn hasher(algo: &str, input: String) -> Result<String> {
|
||||
let hash = match algo {
|
||||
"SHA-1" | "SHA1" | "Sha1" | "sha1" => {
|
||||
let mut hasher = Sha1::new();
|
||||
hasher.update(input.as_bytes());
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CryptographicHash {
|
||||
Sha1(Sha1),
|
||||
Sha256(Sha256),
|
||||
Sha512(Sha512),
|
||||
}
|
||||
|
||||
encode(hasher.finalize())
|
||||
impl CryptographicHash {
|
||||
pub fn new(algo: &str) -> Result<Self> {
|
||||
match algo {
|
||||
"SHA-1" | "SHA1" | "Sha1" | "sha1" => Ok(Self::Sha1(Sha1::new())),
|
||||
"SHA-256" | "SHA256" | "Sha256" | "sha256" => Ok(Self::Sha256(Sha256::new())),
|
||||
"SHA-512" | "SHA512" | "Sha512" | "sha512" => Ok(Self::Sha512(Sha512::new())),
|
||||
_ => Err(Error::UnknownAlgorithm("digest", algo.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
"SHA-256" | "SHA256" | "Sha256" | "sha256" => {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(input.as_bytes());
|
||||
|
||||
encode(hasher.finalize())
|
||||
pub fn update(&mut self, input: &[u8]) {
|
||||
match self {
|
||||
Self::Sha1(sha1) => sha1.update(input),
|
||||
Self::Sha256(sha256) => sha256.update(input),
|
||||
Self::Sha512(sha512) => sha512.update(input),
|
||||
}
|
||||
}
|
||||
|
||||
"SHA-512" | "SHA512" | "Sha512" | "sha512" => {
|
||||
let mut hasher = Sha512::new();
|
||||
hasher.update(input.as_bytes());
|
||||
|
||||
encode(hasher.finalize())
|
||||
pub fn finalize(&mut self) -> Vec<u8> {
|
||||
match self {
|
||||
Self::Sha1(sha1) => sha1.finalize_reset().to_vec(),
|
||||
Self::Sha256(sha256) => sha256.finalize_reset().to_vec(),
|
||||
Self::Sha512(sha512) => sha512.finalize_reset().to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
_ => return Err(Error::UnknownAlgorithm("digest", algo.to_string())),
|
||||
};
|
||||
pub fn hash(algo: &str, input: &[u8]) -> Result<Vec<u8>> {
|
||||
let mut hasher = Self::new(algo)?;
|
||||
|
||||
Ok(hash)
|
||||
hasher.update(input);
|
||||
|
||||
Ok(hasher.finalize())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::crypto::{hasher, Error};
|
||||
use crate::crypto::{encode, CryptographicHash, Error};
|
||||
|
||||
#[test]
|
||||
fn sha1() {
|
||||
let sha1 = hasher("sha1", "test string".to_string()).unwrap();
|
||||
assert_eq!(sha1, "661295c9cbf9d6b2f6428414504a8deed3020641".to_string());
|
||||
let mut sha1 = CryptographicHash::new("SHA-1").unwrap();
|
||||
sha1.update(b"test sha1 hash");
|
||||
|
||||
let hash = encode(sha1.finalize());
|
||||
|
||||
assert_eq!(hash, "7726bd9560e1ad4a1a4f056cae5c0c9ea8bacfc2".to_string())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sha256() {
|
||||
let sha1 = hasher("sha256", "test string".to_string()).unwrap();
|
||||
let mut sha256 = CryptographicHash::new("SHA-256").unwrap();
|
||||
sha256.update(b"test sha256 hash");
|
||||
|
||||
let hash = encode(sha256.finalize());
|
||||
|
||||
assert_eq!(
|
||||
sha1,
|
||||
"d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b".to_string()
|
||||
);
|
||||
hash,
|
||||
"eaf6e4198f39ccd63bc3e957d43bf4ef67f12c318c8e3cdc2567a37339902dac".to_string()
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sha512() {
|
||||
let sha1 = hasher("sha512", "test string".to_string()).unwrap();
|
||||
let mut sha512 = CryptographicHash::new("SHA-512").unwrap();
|
||||
sha512.update(b"test sha512 hash");
|
||||
|
||||
let hash = encode(sha512.finalize());
|
||||
|
||||
assert_eq!(
|
||||
sha1,
|
||||
"10e6d647af44624442f388c2c14a787ff8b17e6165b83d767ec047768d8cbcb71a1a3226e7cc7816bc79c0427d94a9da688c41a3992c7bf5e4d7cc3e0be5dbac".to_string()
|
||||
);
|
||||
hash,
|
||||
"b43b4d7178014c92f55be828d66c9f98211fc67b385f7790a5b4b2fcb89fe1831645b5a4c17f3f7f11d8f34d2800a77a2b8faa5a0fb9d6b8f7befbc29a9ce795".to_string()
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_algorithm() {
|
||||
let algo = "unknow_algo";
|
||||
let err = hasher(algo, "test string".to_string()).unwrap_err();
|
||||
let err = CryptographicHash::new(algo).unwrap_err();
|
||||
|
||||
assert_eq!(err, Error::UnknownAlgorithm("digest", algo.to_string()));
|
||||
assert_eq!(err, Error::UnknownAlgorithm("digest", algo.to_string()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use log::debug;
|
||||
use rusqlite::Connection;
|
||||
|
||||
use crate::crypto;
|
||||
|
||||
use super::{user, Error};
|
||||
|
||||
pub struct Database {
|
||||
|
@ -10,22 +8,40 @@ pub struct Database {
|
|||
}
|
||||
|
||||
impl Database {
|
||||
pub fn open() -> Result<Self, Error> {
|
||||
/// Open SQLite Database file
|
||||
/// ```
|
||||
/// use homedisk_utils::database::Database;
|
||||
///
|
||||
/// Database::open("/tmp/homedisk.db").unwrap();
|
||||
/// ```
|
||||
pub fn open(path: &str) -> Result<Self, Error> {
|
||||
debug!("opening SQLite database");
|
||||
|
||||
let conn = Connection::open("homedisk.db")?;
|
||||
let conn = Connection::open(path)?;
|
||||
|
||||
Ok(Self { conn })
|
||||
}
|
||||
|
||||
pub fn create_user(&mut self, user: user::User) -> Result<usize, Error> {
|
||||
/// Create new User
|
||||
/// ```
|
||||
/// use std::fs;
|
||||
///
|
||||
/// use rusqlite::Connection;
|
||||
/// use homedisk_utils::database::{Database, User};
|
||||
///
|
||||
/// let db = Database { conn: Connection::open_in_memory().unwrap() };
|
||||
/// let user = User::new("medzik", "SuperSecretPassword123").unwrap();
|
||||
///
|
||||
/// db.conn.execute(&fs::read_to_string("../template.sql").unwrap(), []).unwrap();
|
||||
///
|
||||
/// db.create_user(user).unwrap();
|
||||
/// ```
|
||||
pub fn create_user(&self, user: user::User) -> Result<usize, Error> {
|
||||
debug!("creating user - {}", user.username);
|
||||
|
||||
// hash password using sha512
|
||||
let password = crypto::hasher("sha512", user.password)?;
|
||||
|
||||
Ok(self.conn.execute(
|
||||
"INSERT INTO user (username, password) VALUES (?1, ?2)",
|
||||
[user.username, password],
|
||||
"INSERT INTO user (id, username, password) VALUES (?1, ?2, ?3)",
|
||||
[user.id, user.username, user.password],
|
||||
)?)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,35 @@
|
|||
use hex::encode;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::crypto::{self, CryptographicHash};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct User {
|
||||
pub id: String,
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
impl User {
|
||||
/// Create a new User type (note **this doesn't create a new user in the database!**)
|
||||
///
|
||||
/// This function creates a unique UUID for the user and creates a password hash using SHA-512
|
||||
/// ```
|
||||
/// use homedisk_utils::database::User;
|
||||
///
|
||||
/// let user = User::new("medzik", "SuperSecretPassword123!").unwrap();
|
||||
/// ```
|
||||
pub fn new(username: &str, password: &str) -> Result<Self, crypto::Error> {
|
||||
// create user UUID
|
||||
let sha1_name = CryptographicHash::hash("SHA-1", username.as_bytes())?;
|
||||
let id = Uuid::new_v5(&Uuid::NAMESPACE_X500, &sha1_name).to_string();
|
||||
|
||||
let password = encode(CryptographicHash::hash("SHA-512", password.as_bytes())?);
|
||||
|
||||
Ok(Self {
|
||||
id,
|
||||
username: username.to_string(),
|
||||
password,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue