diff options
author | Vika <vika@fireburn.ru> | 2022-09-28 03:55:48 +0300 |
---|---|---|
committer | Vika <vika@fireburn.ru> | 2022-09-28 03:55:48 +0300 |
commit | 6e20a3c51756c2e84290da6ec53b89a5fc58c0fc (patch) | |
tree | a360c40dce27b7804001038babd4631476232001 /kittybox-rs/src/indieauth | |
parent | 2f02bf76a40c971b9404aa0913bc8baa7dfde24c (diff) | |
download | kittybox-6e20a3c51756c2e84290da6ec53b89a5fc58c0fc.tar.zst |
Use tokens from the auth backend to authenticate for Micropub
Diffstat (limited to 'kittybox-rs/src/indieauth')
-rw-r--r-- | kittybox-rs/src/indieauth/mod.rs | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/kittybox-rs/src/indieauth/mod.rs b/kittybox-rs/src/indieauth/mod.rs index 36f207c..6dc9ec6 100644 --- a/kittybox-rs/src/indieauth/mod.rs +++ b/kittybox-rs/src/indieauth/mod.rs @@ -1,3 +1,5 @@ +use std::marker::PhantomData; + use tracing::error; use serde::Deserialize; use axum::{ @@ -27,6 +29,76 @@ const REFRESH_TOKEN_VALIDITY: u64 = ACCESS_TOKEN_VALIDITY / 7 * 60; // 60 days /// Internal scope for accessing the token introspection endpoint. const KITTYBOX_TOKEN_STATUS: &str = "kittybox:token_status"; +pub(crate) struct User<A: AuthBackend>(pub(crate) TokenData, pub(crate) PhantomData<A>); +impl<A: AuthBackend> std::fmt::Debug for User<A> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("User").field(&self.0).finish() + } +} +impl<A: AuthBackend> std::ops::Deref for User<A> { + type Target = TokenData; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +pub enum IndieAuthResourceError { + InvalidRequest, + Unauthorized, + InvalidToken +} +impl axum::response::IntoResponse for IndieAuthResourceError { + fn into_response(self) -> axum::response::Response { + use IndieAuthResourceError::*; + + match self { + Unauthorized => ( + StatusCode::UNAUTHORIZED, + [("WWW-Authenticate", "Bearer")] + ).into_response(), + InvalidRequest => ( + StatusCode::BAD_REQUEST, + Json(&serde_json::json!({"error": "invalid_request"})) + ).into_response(), + InvalidToken => ( + StatusCode::UNAUTHORIZED, + [("WWW-Authenticate", "Bearer, error=\"invalid_token\"")], + Json(&serde_json::json!({"error": "unauthorized"})) + ).into_response() + } + } +} + +#[async_trait::async_trait] +impl <B: Send, A: AuthBackend> axum::extract::FromRequest<B> for User<A> { + type Rejection = IndieAuthResourceError; + + async fn from_request(req: &mut axum::extract::RequestParts<B>) -> Result<Self, Self::Rejection> { + let TypedHeader(Authorization(token)) = + TypedHeader::<Authorization<Bearer>>::from_request(req) + .await + .map_err(|_| IndieAuthResourceError::Unauthorized)?; + + let axum::Extension(auth) = axum::Extension::<A>::from_request(req) + .await + .unwrap(); + + let Host(host) = Host::from_request(req) + .await + .map_err(|_| IndieAuthResourceError::InvalidRequest)?; + + auth.get_token( + &format!("https://{host}/").parse().unwrap(), + token.token() + ) + .await + .unwrap() + .ok_or(IndieAuthResourceError::InvalidToken) + .map(|t| User(t, PhantomData)) + } +} + pub async fn metadata( Host(host): Host ) -> Metadata { |