Merge 482192dda320dd348ad1333866bbe72fa33f3397 into 144905369e4316bcbf230ad96e0e6317098cc4d1

This commit is contained in:
Matouš Volf 2024-09-13 07:19:29 +02:00 committed by GitHub
commit 91410f0a9d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 140 additions and 1 deletions

View File

@ -1,2 +1,3 @@
DATABASE_URL=postgres://app:app@db/todo_baggins DATABASE_URL=postgres://app:app@db/todo_baggins
LANGUAGE_CODE=en-US LANGUAGE_CODE=en-US
AUTH_TOKEN=my_token

16
Cargo.lock generated
View File

@ -558,6 +558,17 @@ dependencies = [
"unicode-segmentation", "unicode-segmentation",
] ]
[[package]]
name = "cookie"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747"
dependencies = [
"percent-encoding",
"time",
"version_check",
]
[[package]] [[package]]
name = "core-foundation-sys" name = "core-foundation-sys"
version = "0.8.7" version = "0.8.7"
@ -2943,16 +2954,21 @@ version = "0.1.0"
dependencies = [ dependencies = [
"async-std", "async-std",
"chrono", "chrono",
"cookie",
"diesel", "diesel",
"dioxus", "dioxus",
"dioxus-logger", "dioxus-logger",
"dioxus-query", "dioxus-query",
"dioxus-sdk", "dioxus-sdk",
"dotenvy", "dotenvy",
"http 1.1.0",
"pin-project-lite",
"serde", "serde",
"serde_json", "serde_json",
"serde_with", "serde_with",
"time", "time",
"tower-layer",
"tower-service",
"tracing", "tracing",
"tracing-wasm", "tracing-wasm",
"unic-langid-impl", "unic-langid-impl",

View File

@ -27,6 +27,11 @@ time = "0.3.36"
dioxus-sdk = { version = "0.5.0", features = ["i18n"] } dioxus-sdk = { version = "0.5.0", features = ["i18n"] }
unic-langid-impl = "0.9.5" unic-langid-impl = "0.9.5"
voca_rs = "1.15.2" voca_rs = "1.15.2"
http = "1.1.0"
pin-project-lite = "0.2.14"
tower-layer = "0.3.3"
tower-service = "0.3.3"
cookie = { version = "0.18.1", features = ["percent-encode"] }
[features] [features]
default = [] default = []

View File

@ -4,7 +4,7 @@ use dotenvy::dotenv;
use std::env; use std::env;
pub(crate) fn establish_database_connection() -> ConnectionResult<PgConnection> { pub(crate) fn establish_database_connection() -> ConnectionResult<PgConnection> {
dotenv().expect("Could not load environment variables."); dotenv().expect("Could not load environment variables from the .env file.");
let database_url = let database_url =
env::var("DATABASE_URL").expect("The environment variable DATABASE_URL has to be set."); env::var("DATABASE_URL").expect("The environment variable DATABASE_URL has to be set.");

View File

@ -0,0 +1,108 @@
use http::{Request, Response, StatusCode};
use pin_project_lite::pin_project;
use std::{env, future::Future, pin::Pin, task::{Context, Poll}};
use cookie::Cookie;
use dotenvy::dotenv;
use http::header::COOKIE;
use tower_layer::Layer;
use tower_service::Service;
#[derive(Debug, Clone, Copy)]
pub struct AuthLayer {}
impl AuthLayer {
pub fn new() -> Self {
AuthLayer {}
}
}
impl<S> Layer<S> for AuthLayer {
type Service = Auth<S>;
fn layer(&self, inner: S) -> Self::Service {
Auth::new(inner)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Auth<S> {
inner: S,
}
impl<S> Auth<S> {
pub fn new(inner: S) -> Self {
Self { inner }
}
pub fn layer() -> AuthLayer {
AuthLayer::new()
}
}
impl<S, ReqBody, ResBody> Service<Request<ReqBody>> for Auth<S>
where
S: Service<Request<ReqBody>, Response=Response<ResBody>>,
ResBody: Default,
{
type Response = S::Response;
type Error = S::Error;
type Future = ResponseFuture<S::Future>;
#[inline]
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx)
}
fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
let cookies = req.headers()
.get(COOKIE)
.and_then(|header| header.to_str().ok())
.map(Cookie::split_parse_encoded);
let token = cookies.and_then(
|cookies| cookies
.filter_map(|cookie| cookie.ok())
.find(|cookie| cookie.name() == "auth_token")
.map(|cookie| cookie.value().to_string())
);
ResponseFuture {
inner: self.inner.call(req),
token,
}
}
}
pin_project! {
pub struct ResponseFuture<F> {
#[pin]
inner: F,
#[pin]
token: Option<String>,
}
}
impl<F, B, E> Future for ResponseFuture<F>
where
F: Future<Output=Result<Response<B>, E>>,
B: Default,
{
type Output = Result<Response<B>, E>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
dotenv().expect("Could not load environment variables from the .env file.");
let this = self.project();
if !(*this.token).as_ref().is_some_and(
|token| token == env::var("AUTH_TOKEN")
.expect("The environment variable DATABASE_URL has to be set.").as_str()
) {
let mut res = Response::new(B::default());
*res.status_mut() = StatusCode::UNAUTHORIZED;
return Poll::Ready(Ok(res));
}
this.inner.poll(cx)
}
}

View File

@ -3,3 +3,4 @@ pub(crate) mod projects;
pub(crate) mod tasks; pub(crate) mod tasks;
pub(crate) mod subtasks; pub(crate) mod subtasks;
pub(crate) mod internationalization; pub(crate) mod internationalization;
mod middleware;

View File

@ -14,9 +14,17 @@ use crate::models::subtask::Subtask;
use crate::server::subtasks::restore_subtasks_of_task; use crate::server::subtasks::restore_subtasks_of_task;
#[server] #[server]
#[middleware(crate::server::middleware::AuthLayer::new())]
pub(crate) async fn create_task(new_task: NewTask) pub(crate) async fn create_task(new_task: NewTask)
-> Result<Task, ServerFnError<ErrorVec<TaskError>>> { -> Result<Task, ServerFnError<ErrorVec<TaskError>>> {
use crate::schema::tasks; use crate::schema::tasks;
println!("test");
let headers: http::HeaderMap = extract().await.unwrap();
dbg!(headers.iter().collect::<Vec<_>>());
// println!(headers.values().collect())
new_task.validate() new_task.validate()
.map_err::<ErrorVec<TaskError>, _>(|errors| errors.into())?; .map_err::<ErrorVec<TaskError>, _>(|errors| errors.into())?;