Split out a support library

This commit is contained in:
Savanni D'Gerinel 2023-10-03 16:18:19 -04:00
parent f3940111c4
commit 1b161435df
6 changed files with 71 additions and 56 deletions

View File

@ -6,6 +6,16 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
auth-cli = [ "clap" ]
[[bin]]
name = "auth-cli"
path = "src/bin/cli.rs"
required-features = [ "auth-cli" ]
[target.auth-cli.dependencies]
[dependencies] [dependencies]
build_html = { version = "2" } build_html = { version = "2" }
bytes = { version = "1" } bytes = { version = "1" }
@ -28,6 +38,7 @@ tokio = { version = "1", features = [ "full" ] }
uuid = { version = "0.4", features = [ "serde", "v4" ] } uuid = { version = "0.4", features = [ "serde", "v4" ] }
warp = { version = "0.3" } warp = { version = "0.3" }
base64ct = { version = "1", features = [ "alloc" ] } base64ct = { version = "1", features = [ "alloc" ] }
clap = { version = "4", features = [ "derive" ], optional = true }
[dev-dependencies] [dev-dependencies]
cool_asserts = { version = "2" } cool_asserts = { version = "2" }

View File

@ -1,9 +1,9 @@
use build_html::Html; use build_html::Html;
use http::{Error, StatusCode}; use http::{Error, StatusCode};
use std::{collections::HashMap, future::Future}; use std::collections::HashMap;
use warp::http::Response; use warp::http::Response;
use crate::{pages, App, AuthToken, FileHandle, FileId, FileInfo, ReadFileError, SessionToken}; use crate::{pages, App, AuthToken, FileId, FileInfo, ReadFileError, SessionToken};
pub async fn handle_index( pub async fn handle_index(
app: App, app: App,

6
file-service/src/lib.rs Normal file
View File

@ -0,0 +1,6 @@
mod store;
pub use store::{
AuthDB, AuthError, AuthToken, FileHandle, FileId, FileInfo, ReadFileError, SessionToken, Store,
Username, WriteFileError,
};

View File

@ -8,25 +8,25 @@ use http::status::StatusCode;
use bytes::Buf; use bytes::Buf;
use futures_util::StreamExt; use futures_util::StreamExt;
use std::{ use std::{
collections::HashMap, collections::HashSet,
convert::Infallible, convert::Infallible,
io::Read, io::Read,
net::{IpAddr, Ipv4Addr, SocketAddr}, net::{IpAddr, Ipv4Addr, SocketAddr},
path::PathBuf, path::PathBuf,
sync::{Arc, RwLock}, sync::Arc,
}; };
use store::Username; use tokio::sync::RwLock;
use warp::{filters::multipart::Part, Filter, Rejection}; use warp::{filters::multipart::Part, Filter, Rejection};
mod handlers; mod handlers;
mod html; mod html;
mod pages; mod pages;
mod store;
pub use handlers::handle_index; pub use file_service::{
pub use store::{ AuthDB, AuthError, AuthToken, FileHandle, FileId, FileInfo, ReadFileError, SessionToken, Store,
App, AuthDB, AuthToken, FileHandle, FileId, FileInfo, ReadFileError, SessionToken, Store, Username, WriteFileError,
}; };
pub use handlers::handle_index;
/* /*
async fn authenticate_user(app: App, auth_token: String) -> Result<Username, warp::Rejection> { async fn authenticate_user(app: App, auth_token: String) -> Result<Username, warp::Rejection> {
@ -112,6 +112,45 @@ async fn handle_upload(
} }
*/ */
#[derive(Clone)]
pub struct App {
authdb: Arc<RwLock<AuthDB>>,
store: Arc<RwLock<Store>>,
}
impl App {
pub fn new(authdb: AuthDB, store: Store) -> Self {
Self {
authdb: Arc::new(RwLock::new(authdb)),
store: Arc::new(RwLock::new(store)),
}
}
pub async fn auth_token(&self, token: AuthToken) -> Result<Option<SessionToken>, AuthError> {
self.authdb.read().await.auth_token(token).await
}
pub async fn auth_session(&self, token: SessionToken) -> Result<Option<Username>, AuthError> {
self.authdb.read().await.auth_session(token).await
}
pub async fn list_files(&self) -> Result<HashSet<FileId>, ReadFileError> {
self.store.read().await.list_files()
}
pub async fn get_file(&self, id: &FileId) -> Result<FileHandle, ReadFileError> {
self.store.read().await.get_file(id)
}
pub async fn add_file(
&self,
filename: String,
content: Vec<u8>,
) -> Result<FileHandle, WriteFileError> {
self.store.write().await.add_file(filename, content)
}
}
fn with_app(app: App) -> impl Filter<Extract = (App,), Error = Infallible> + Clone { fn with_app(app: App) -> impl Filter<Extract = (App,), Error = Infallible> + Clone {
warp::any().map(move || app.clone()) warp::any().map(move || app.clone())
} }

View File

@ -1,8 +1,6 @@
use crate::{ use crate::html::*;
html::*,
store::{FileHandle, FileId, ReadFileError},
};
use build_html::{self, Container, ContainerType, Html, HtmlContainer}; use build_html::{self, Container, ContainerType, Html, HtmlContainer};
use file_service::{FileHandle, FileId, ReadFileError};
pub fn auth(_message: Option<String>) -> build_html::HtmlPage { pub fn auth(_message: Option<String>) -> build_html::HtmlPage {
build_html::HtmlPage::new() build_html::HtmlPage::new()

View File

@ -242,45 +242,6 @@ impl FileRoot for Context {
} }
} }
#[derive(Clone)]
pub struct App {
authdb: Arc<RwLock<AuthDB>>,
store: Arc<RwLock<Store>>,
}
impl App {
pub fn new(authdb: AuthDB, store: Store) -> Self {
Self {
authdb: Arc::new(RwLock::new(authdb)),
store: Arc::new(RwLock::new(store)),
}
}
pub async fn auth_token(&self, token: AuthToken) -> Result<Option<SessionToken>, AuthError> {
self.authdb.read().await.auth_token(token).await
}
pub async fn auth_session(&self, token: SessionToken) -> Result<Option<Username>, AuthError> {
self.authdb.read().await.auth_session(token).await
}
pub async fn list_files(&self) -> Result<HashSet<FileId>, ReadFileError> {
self.store.read().await.list_files()
}
pub async fn get_file(&self, id: &FileId) -> Result<FileHandle, ReadFileError> {
self.store.read().await.get_file(id)
}
pub async fn add_file(
&self,
filename: String,
content: Vec<u8>,
) -> Result<FileHandle, WriteFileError> {
self.store.write().await.add_file(filename, content)
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct AuthDB { pub struct AuthDB {
pool: SqlitePool, pool: SqlitePool,
@ -294,7 +255,7 @@ impl AuthDB {
Ok(Self { pool }) Ok(Self { pool })
} }
async fn add_user(&self, username: Username) -> Result<AuthToken, AuthError> { pub async fn add_user(&self, username: Username) -> Result<AuthToken, AuthError> {
let mut hasher = Sha256::new(); let mut hasher = Sha256::new();
hasher.update(Uuid::new_v4().hyphenated().to_string()); hasher.update(Uuid::new_v4().hyphenated().to_string());
hasher.update(username.to_string()); hasher.update(username.to_string());
@ -309,7 +270,7 @@ impl AuthDB {
Ok(AuthToken::from(auth_token)) Ok(AuthToken::from(auth_token))
} }
async fn list_users(&self) -> Result<Vec<Username>, AuthError> { pub async fn list_users(&self) -> Result<Vec<Username>, AuthError> {
let usernames = sqlx::query_as::<_, Username>("SELECT (username) FROM users") let usernames = sqlx::query_as::<_, Username>("SELECT (username) FROM users")
.fetch_all(&self.pool) .fetch_all(&self.pool)
.await?; .await?;
@ -317,7 +278,7 @@ impl AuthDB {
Ok(usernames) Ok(usernames)
} }
async fn auth_token(&self, token: AuthToken) -> Result<Option<SessionToken>, AuthError> { pub async fn auth_token(&self, token: AuthToken) -> Result<Option<SessionToken>, AuthError> {
let results = sqlx::query("SELECT * FROM users WHERE token = $1") let results = sqlx::query("SELECT * FROM users WHERE token = $1")
.bind(token.to_string()) .bind(token.to_string())
.fetch_all(&self.pool) .fetch_all(&self.pool)
@ -347,7 +308,7 @@ impl AuthDB {
Ok(Some(SessionToken::from(session_token))) Ok(Some(SessionToken::from(session_token)))
} }
async fn auth_session(&self, token: SessionToken) -> Result<Option<Username>, AuthError> { pub async fn auth_session(&self, token: SessionToken) -> Result<Option<Username>, AuthError> {
let rows = sqlx::query( let rows = sqlx::query(
"SELECT users.username FROM sessions INNER JOIN users ON sessions.user_id = users.id WHERE sessions.token = $1", "SELECT users.username FROM sessions INNER JOIN users ON sessions.user_id = users.id WHERE sessions.token = $1",
) )