summaryrefslogtreecommitdiff
path: root/src/login/extract/login.rs
diff options
context:
space:
mode:
authorOwen Jacobson <owen@grimoire.ca>2024-09-04 00:28:35 -0400
committerOwen Jacobson <owen@grimoire.ca>2024-09-04 00:28:35 -0400
commit2965a788cfcf4a0386cb8832e0d96491bf54c1d3 (patch)
tree096b00f64b092396e99d04ebe124fa15d734f6c1 /src/login/extract/login.rs
parent289e99ba977ebe6c4599141bc368c17f9905ffcc (diff)
Display a different / page depending on whether the current identity is valid or not.
This is mostly a proof of concept for the implementation of form login implemented in previous commits, but it _is_ useful as it controls whether the / page shows login, or shows logout. From here, chat is next!
Diffstat (limited to 'src/login/extract/login.rs')
-rw-r--r--src/login/extract/login.rs61
1 files changed, 61 insertions, 0 deletions
diff --git a/src/login/extract/login.rs b/src/login/extract/login.rs
new file mode 100644
index 0000000..f49933a
--- /dev/null
+++ b/src/login/extract/login.rs
@@ -0,0 +1,61 @@
+use axum::{
+ extract::{FromRequestParts, State},
+ http::{request::Parts, StatusCode},
+ response::{IntoResponse, Response},
+};
+use sqlx::sqlite::SqlitePool;
+
+use crate::{
+ error::InternalError,
+ login::{
+ extract::IdentityToken,
+ repo::{logins::Login, tokens::Provider as _},
+ },
+};
+
+#[async_trait::async_trait]
+impl FromRequestParts<SqlitePool> for Login {
+ type Rejection = LoginError<InternalError>;
+
+ async fn from_request_parts(
+ parts: &mut Parts,
+ state: &SqlitePool,
+ ) -> Result<Self, Self::Rejection> {
+ let identity_token = IdentityToken::from_request_parts(parts, state).await?;
+
+ let token = identity_token.token().ok_or(LoginError::Forbidden)?;
+
+ let db = State::<SqlitePool>::from_request_parts(parts, state).await?;
+ let mut tx = db.begin().await?;
+ let login = tx.tokens().validate(token).await?;
+ tx.commit().await?;
+
+ login.ok_or(LoginError::Forbidden)
+ }
+}
+
+pub enum LoginError<E> {
+ Failure(E),
+ Forbidden,
+}
+
+impl<E> IntoResponse for LoginError<E>
+where
+ E: IntoResponse,
+{
+ fn into_response(self) -> Response {
+ match self {
+ Self::Forbidden => (StatusCode::FORBIDDEN, "forbidden").into_response(),
+ Self::Failure(e) => e.into_response(),
+ }
+ }
+}
+
+impl<E> From<E> for LoginError<InternalError>
+where
+ E: Into<InternalError>,
+{
+ fn from(err: E) -> Self {
+ Self::Failure(err.into())
+ }
+}