From 6e20a3c51756c2e84290da6ec53b89a5fc58c0fc Mon Sep 17 00:00:00 2001 From: Vika Date: Wed, 28 Sep 2022 03:55:48 +0300 Subject: Use tokens from the auth backend to authenticate for Micropub --- kittybox-rs/src/indieauth/mod.rs | 72 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'kittybox-rs/src/indieauth') 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(pub(crate) TokenData, pub(crate) PhantomData); +impl std::fmt::Debug for User { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("User").field(&self.0).finish() + } +} +impl std::ops::Deref for User { + 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 axum::extract::FromRequest for User { + type Rejection = IndieAuthResourceError; + + async fn from_request(req: &mut axum::extract::RequestParts) -> Result { + let TypedHeader(Authorization(token)) = + TypedHeader::>::from_request(req) + .await + .map_err(|_| IndieAuthResourceError::Unauthorized)?; + + let axum::Extension(auth) = axum::Extension::::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 { -- cgit 1.4.1