Skip to content

Commit 358d4a7

Browse files
committed
Updated Api
1 parent 7d5e4bb commit 358d4a7

File tree

25 files changed

+547
-472
lines changed

25 files changed

+547
-472
lines changed

crates/codora-framework-identity/src/email.rs renamed to crates/codora-framework-identity/src/cframeworkidentity/email.rs

File renamed without changes.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use std::sync::Arc;
2+
3+
pub mod email;
4+
pub mod user;
5+
6+
pub struct CFrameworkIdentity {
7+
// extension
8+
inner: Arc<CFrameworkIdentityInner>,
9+
}
10+
11+
impl CFrameworkIdentity {
12+
// maanage cframework security
13+
// worker for background tasks perhaps
14+
}
15+
16+
pub struct CFrameworkIdentityInner {}
17+
18+
#[cfg(test)]
19+
mod tests {
20+
21+
#[tokio::test]
22+
async fn test_cf_identiy() -> anyhow::Result<()> {
23+
Ok(())
24+
}
25+
}

crates/codora-framework-identity/src/user/mod.rs renamed to crates/codora-framework-identity/src/cframeworkidentity/user/mod.rs

File renamed without changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod value;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
mod email;
2+
mod pii;
3+
4+
pub use email::*;
5+
pub use pii::*;

crates/codora-framework-identity/src/lib.rs

Lines changed: 3 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -19,53 +19,6 @@ extern crate tracing;
1919
#[macro_use]
2020
extern crate derive_new;
2121

22-
pub mod domain {
23-
mod value {
24-
mod email;
25-
mod pii;
26-
}
27-
28-
pub use value::*;
29-
}
30-
pub mod email;
31-
pub mod user;
32-
33-
// use anyhow::anyhow;
34-
// use axum::{
35-
// Router,
36-
// body::Body,
37-
// http::Request,
38-
// response::{IntoResponse, Response},
39-
// routing::get,
40-
// };
41-
// use codora_framework::{Context, Startup, StartupError};
42-
// use std::{convert::Infallible, pin::Pin, sync::Arc};
43-
// use tokio::{net::TcpListener, runtime::Runtime};
44-
// use tower::Service;
45-
46-
// struct WebServiceFuture {}
47-
48-
// impl Future for WebServiceFuture {
49-
// type Output = Result<Response, Infallible>;
50-
51-
// fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Output> {
52-
// todo!()
53-
// }
54-
// }
55-
56-
// // implement tower_service::Service for WebService this wouled allow us to inject Webservice into AxumService built by Router
57-
// impl tower_service::Service<Request<Body>> for WebService {
58-
// type Response = Response;
59-
// type Error = Infallible;
60-
61-
// // Fix this later but that's the idea;
62-
// type Future = WebServiceFuture;
63-
64-
// fn poll_ready(&mut self, cx: &mut std::task::Context<'_>) -> std::task::Poll<Result<(), Self::Error>> {
65-
// std::task::Poll::Ready(Ok(()))
66-
// }
67-
68-
// fn call(&mut self, req: Request<Body>) -> Self::Future {
69-
// WebServiceFuture {}
70-
// }
71-
// }
22+
pub mod cframeworkidentity;
23+
// API
24+
pub mod domain;

crates/codora-framework-security/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ categories = ["web-programming", "authentication"]
99

1010

1111
[features]
12-
default = ["axum"]
12+
default = ["axum", "cookie"]
1313
axum = ["dep:axum", "dep:tower-service"]
14+
cookie = []
1415

1516
[dependencies]
1617
# third party crates
@@ -32,3 +33,4 @@ tokio = { workspace = true, features = ["rt-multi-thread"] }
3233
anyhow = { workspace = true }
3334
tower = { workspace = true, features = ["full"] }
3435
tracing-subscriber = { workspace = true, features = ["env-filter"] }
36+
serde = { workspace = true, features = ["derive"] }
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
use crate::codoraframeworksecurity::{CFrameworkSecurity, Extension};
2+
use axum::{
3+
extract::{FromRequestParts, Request},
4+
response::Response,
5+
};
6+
use http::{StatusCode, request::Parts};
7+
use pin_project_lite::pin_project;
8+
use std::{pin::Pin, task::Poll};
9+
use tower_service::Service;
10+
11+
#[derive(new, Clone)]
12+
pub struct CFrameworkService<S> {
13+
inner: S,
14+
extension: Extension,
15+
}
16+
17+
pin_project! {
18+
#[derive(Debug, new)]
19+
pub struct ServiceResponseFuture<F> {
20+
#[pin]
21+
future: F
22+
}
23+
}
24+
25+
impl<S> Service<Request> for CFrameworkService<S>
26+
where
27+
S: Service<Request, Response = Response> + Send + 'static,
28+
S::Future: Send + 'static,
29+
{
30+
type Response = S::Response;
31+
type Error = S::Error;
32+
type Future = ServiceResponseFuture<S::Future>;
33+
34+
fn poll_ready(&mut self, cx: &mut std::task::Context<'_>) -> Poll<Result<(), Self::Error>> {
35+
self.inner.poll_ready(cx)
36+
}
37+
38+
fn call(&mut self, mut request: Request) -> Self::Future {
39+
// Insert a CframeworkSecurity back inside the extension
40+
let prev = request
41+
.extensions_mut()
42+
.insert(CFrameworkSecurity::new(self.extension.clone()));
43+
debug_assert!(prev.is_none(), "Context already present in request extensions");
44+
ServiceResponseFuture::new(self.inner.call(request))
45+
}
46+
}
47+
48+
impl<S> tower_layer::Layer<S> for CFrameworkSecurity {
49+
type Service = CFrameworkService<S>;
50+
51+
fn layer(&self, inner: S) -> Self::Service {
52+
CFrameworkService::new(inner, self.extension().clone())
53+
}
54+
}
55+
56+
impl<F> Future for ServiceResponseFuture<F>
57+
where
58+
F: Future,
59+
{
60+
type Output = F::Output;
61+
62+
fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
63+
let this = self.project();
64+
65+
// Forward the inner future's poll result directly.
66+
match this.future.poll(cx) {
67+
Poll::Ready(output) => Poll::Ready(output),
68+
Poll::Pending => Poll::Pending,
69+
}
70+
}
71+
}
72+
73+
impl<S> FromRequestParts<S> for CFrameworkSecurity
74+
where
75+
S: Send + Sync,
76+
{
77+
type Rejection = (StatusCode, &'static str);
78+
79+
async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
80+
parts
81+
.extensions
82+
.get::<CFrameworkSecurity>()
83+
.cloned()
84+
.ok_or_else(|| {
85+
//TODO: Update this error message later
86+
error!("Can't extract CFrameworkSecurity. Is `CFrameworkSecurity` added as layer in your `Router`");
87+
(StatusCode::INTERNAL_SERVER_ERROR, "Unknown error occured, Please check the log!")
88+
})
89+
}
90+
}
91+
92+
#[cfg(test)]
93+
mod axum_tests {
94+
use crate::prelude::*;
95+
use anyhow::Result;
96+
use axum::{
97+
Router,
98+
body::Body,
99+
extract::Request,
100+
response::{IntoResponse, Response},
101+
routing::{get, post},
102+
};
103+
use http::{StatusCode, request::Parts};
104+
use tower::ServiceExt;
105+
106+
#[allow(dead_code)]
107+
#[derive(Debug, serde::Deserialize)]
108+
pub struct JwtBody {
109+
token: String,
110+
}
111+
112+
#[tokio::test]
113+
async fn test_context_if_it_compiles_it_works() -> Result<()> {
114+
let app = Router::new()
115+
.route("/signup", get(|_cf_security: CFrameworkSecurity| async { () }))
116+
.layer(CFrameworkSecurity::default());
117+
118+
let req = Request::builder()
119+
.uri("/")
120+
.body(Body::empty())?;
121+
122+
let res = app.oneshot(req).await?;
123+
assert_eq!(res.status(), StatusCode::OK);
124+
Ok(())
125+
}
126+
127+
#[tokio::test]
128+
async fn test_cookie_sign_in_with_axum_parts() -> Result<()> {
129+
let cf = CFrameworkSecurity::default().add_cookie(|option| {
130+
// setup option here
131+
132+
option
133+
});
134+
135+
async fn authentication_handler(parts: Parts, mut ctx: CFrameworkSecurity) -> Result<Response, Response> {
136+
// cookie response
137+
let _response = ctx
138+
.with(parts)
139+
.sign_in_with_cookie(CookieState {}, CookiePayload {})
140+
.await
141+
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR.into_response())?;
142+
143+
Ok(String::from("Yet to be implemented").into_response())
144+
}
145+
146+
let app = Router::new()
147+
.route("/", post(authentication_handler))
148+
.layer(cf);
149+
150+
let req = Request::builder()
151+
.uri("/")
152+
.body(Body::empty())?;
153+
154+
let res = app.oneshot(req).await?;
155+
assert_eq!(res.status(), StatusCode::OK);
156+
157+
Ok(())
158+
}
159+
160+
#[tokio::test]
161+
async fn test_cookie_sign_in_with_axum_typed_request() -> Result<()> {
162+
let cf = CFrameworkSecurity::default().add_cookie(|option| {
163+
// setup option here
164+
165+
option
166+
});
167+
168+
async fn authentication_handler(parts: Parts, mut ctx: CFrameworkSecurity) -> Result<Response, Response> {
169+
let _response = ctx
170+
.with(parts)
171+
.sign_in_with_cookie(CookieState {}, CookiePayload {})
172+
.await
173+
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR.into_response())?;
174+
175+
Ok(String::from("Yet to be implemented").into_response())
176+
}
177+
178+
let app = Router::new()
179+
.route("/", post(authentication_handler))
180+
.layer(cf);
181+
182+
let req = Request::builder()
183+
.uri("/")
184+
.body(Body::empty())?;
185+
186+
let res = app.oneshot(req).await?;
187+
assert_eq!(res.status(), StatusCode::OK);
188+
189+
Ok(())
190+
}
191+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub(super) mod codoraframeworksecurity;
2+
pub mod request;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use crate::codoraframeworksecurity::http::IntoCfSecurityRequest;
2+
use http::{Request, request::Parts};
3+
4+
impl IntoCfSecurityRequest for Parts {
5+
type Body = ();
6+
7+
fn into_cf_security_request(&self) -> Request<Self::Body> {
8+
todo!()
9+
}
10+
}

0 commit comments

Comments
 (0)