mirror of https://github.com/raftario/filite.git
Add basic database methods
This commit is contained in:
parent
81c9246634
commit
cc75c189a6
44
src/auth.rs
44
src/auth.rs
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
config::{Config, PasswordConfig},
|
||||
db::{self, User},
|
||||
reject::{self, TryExt},
|
||||
db::User,
|
||||
reject::TryExt,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use rand::Rng;
|
||||
|
@ -34,10 +34,10 @@ pub fn auth_required(
|
|||
#[tracing::instrument(level = "debug")]
|
||||
async fn user(header: String, db: &Db, config: &Config) -> Result<User, Rejection> {
|
||||
if &header[..5] != "Basic" {
|
||||
return Err(reject::unauthorized());
|
||||
return Err(crate::reject::unauthorized());
|
||||
}
|
||||
|
||||
let decoded = task::block_in_place(move || base64::decode(&header[6..])).or_401()?;
|
||||
let decoded = base64::decode(&header[6..]).or_401()?;
|
||||
|
||||
let (user, password) = {
|
||||
let mut split = None;
|
||||
|
@ -52,16 +52,27 @@ async fn user(header: String, db: &Db, config: &Config) -> Result<User, Rejectio
|
|||
(std::str::from_utf8(u).or_401()?, p)
|
||||
};
|
||||
|
||||
let user = db::user(user, db).or_500()?.or_401()?;
|
||||
let user = crate::db::user(user, db).or_500()?.or_401()?;
|
||||
if !verify(&user.password_hash, password, &config.password).or_500()? {
|
||||
return Err(reject::unauthorized());
|
||||
return Err(crate::reject::unauthorized());
|
||||
}
|
||||
|
||||
Ok(user)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(encoded, password))]
|
||||
fn verify(encoded: &str, password: &[u8], config: &PasswordConfig) -> Result<bool> {
|
||||
let res = match &config.secret {
|
||||
Some(s) => task::block_in_place(move || {
|
||||
argon2::verify_encoded_ext(encoded, password, s.as_bytes(), &[])
|
||||
})?,
|
||||
None => task::block_in_place(move || argon2::verify_encoded(encoded, password))?,
|
||||
};
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(password))]
|
||||
fn hash(password: &[u8], config: &PasswordConfig) -> Result<String> {
|
||||
pub fn hash(password: &[u8], config: &PasswordConfig) -> Result<String> {
|
||||
let mut cfg = argon2::Config::default();
|
||||
if let Some(hl) = config.hash_length {
|
||||
cfg.hash_length = hl;
|
||||
|
@ -79,22 +90,9 @@ fn hash(password: &[u8], config: &PasswordConfig) -> Result<String> {
|
|||
cfg.secret = s;
|
||||
}
|
||||
|
||||
let hashed = task::block_in_place(move || {
|
||||
let mut salt = vec![0; config.salt_length.unwrap_or(16)];
|
||||
rand::thread_rng().fill(&mut salt[..]);
|
||||
let mut salt = vec![0; config.salt_length.unwrap_or(16)];
|
||||
rand::thread_rng().fill(&mut salt[..]);
|
||||
|
||||
argon2::hash_encoded(password, &salt[..], &cfg)
|
||||
})?;
|
||||
let hashed = argon2::hash_encoded(password, &salt[..], &cfg)?;
|
||||
Ok(hashed)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(encoded, password))]
|
||||
fn verify(encoded: &str, password: &[u8], config: &PasswordConfig) -> Result<bool> {
|
||||
let res = match &config.secret {
|
||||
Some(s) => task::block_in_place(move || {
|
||||
argon2::verify_encoded_ext(encoded, password, s.as_bytes(), &[])
|
||||
})?,
|
||||
None => task::block_in_place(move || argon2::verify_encoded(encoded, password))?,
|
||||
};
|
||||
Ok(res)
|
||||
}
|
||||
|
|
76
src/db.rs
76
src/db.rs
|
@ -1,5 +1,6 @@
|
|||
use crate::config::DatabaseConfig;
|
||||
use crate::config::{Config, DatabaseConfig};
|
||||
use anyhow::Result;
|
||||
use rand::{distributions::Alphanumeric, Rng};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sled::Db;
|
||||
use tokio::task;
|
||||
|
@ -14,6 +15,53 @@ pub fn connect(config: &DatabaseConfig) -> Result<&'static Db> {
|
|||
Ok(Box::leak(Box::new(db)))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub enum Filite {
|
||||
File { data: Vec<u8>, mime: String },
|
||||
Link { location: String },
|
||||
Text { data: String },
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(db))]
|
||||
pub fn filite(id: &str, db: &Db) -> Result<Option<Filite>> {
|
||||
task::block_in_place(move || {
|
||||
let bytes = match db.get(id)? {
|
||||
Some(b) => b,
|
||||
None => return Ok(None),
|
||||
};
|
||||
let filite = bincode::deserialize(&bytes)?;
|
||||
Ok(Some(filite))
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(db))]
|
||||
pub fn create_filite(id: &str, filite: Filite, db: &Db) -> Result<bool> {
|
||||
task::block_in_place(move || {
|
||||
if db.contains_key(id)? {
|
||||
return Ok(false);
|
||||
}
|
||||
let bytes = bincode::serialize(&filite)?;
|
||||
db.insert(id, bytes)?;
|
||||
Ok(true)
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(db))]
|
||||
pub fn random_id(length: usize, db: &Db) -> Result<String> {
|
||||
task::block_in_place(move || {
|
||||
let mut id;
|
||||
loop {
|
||||
id = rand::thread_rng()
|
||||
.sample_iter(Alphanumeric)
|
||||
.take(length)
|
||||
.collect();
|
||||
if !db.contains_key(&id)? {
|
||||
break Ok(id);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct User {
|
||||
pub admin: bool,
|
||||
|
@ -32,3 +80,29 @@ pub fn user(id: &str, db: &Db) -> Result<Option<User>> {
|
|||
Ok(Some(user))
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(password, db))]
|
||||
pub fn create_user(
|
||||
id: &str,
|
||||
password: &str,
|
||||
admin: bool,
|
||||
db: &Db,
|
||||
config: &Config,
|
||||
) -> Result<bool> {
|
||||
task::block_in_place(move || {
|
||||
let users = db.open_tree("users")?;
|
||||
if users.contains_key(id)? {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let password_hash = crate::auth::hash(password.as_bytes(), &config.password)?;
|
||||
let user = User {
|
||||
admin,
|
||||
password_hash,
|
||||
};
|
||||
|
||||
let bytes = bincode::serialize(&user)?;
|
||||
users.insert(id, bytes)?;
|
||||
Ok(true)
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue