2020-12-08 21:59:55 +00:00
|
|
|
use actix_web::{
|
|
|
|
dev::{Payload, Service, ServiceRequest, Transform},
|
|
|
|
http::StatusCode,
|
|
|
|
web, FromRequest, HttpMessage, HttpRequest, HttpResponse, ResponseError,
|
|
|
|
};
|
2021-09-06 20:44:01 +00:00
|
|
|
use std::{
|
|
|
|
future::{ready, Future, Ready},
|
|
|
|
pin::Pin,
|
|
|
|
task::{Context, Poll},
|
2020-12-08 21:59:55 +00:00
|
|
|
};
|
2021-09-06 20:44:01 +00:00
|
|
|
use tokio::sync::oneshot;
|
2020-12-08 21:59:55 +00:00
|
|
|
use uuid::Uuid;
|
|
|
|
|
2021-09-06 20:44:01 +00:00
|
|
|
type LocalBoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
|
|
|
|
|
2020-12-08 21:59:55 +00:00
|
|
|
pub(crate) struct Verify;
|
|
|
|
pub(crate) struct VerifyMiddleware<S>(S);
|
|
|
|
|
2021-09-19 19:32:04 +00:00
|
|
|
#[derive(Debug)]
|
2020-12-08 21:59:55 +00:00
|
|
|
pub struct ValidToken {
|
|
|
|
pub(crate) token: Uuid,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FromRequest for ValidToken {
|
|
|
|
type Error = TokenError;
|
|
|
|
type Future = LocalBoxFuture<'static, Result<Self, Self::Error>>;
|
|
|
|
|
|
|
|
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
|
|
|
|
let res = req
|
|
|
|
.extensions_mut()
|
|
|
|
.remove::<oneshot::Receiver<Self>>()
|
|
|
|
.ok_or(TokenError);
|
|
|
|
|
|
|
|
Box::pin(async move { res?.await.map_err(|_| TokenError) })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, thiserror::Error)]
|
|
|
|
#[error("Invalid token")]
|
|
|
|
pub struct TokenError;
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, thiserror::Error)]
|
|
|
|
#[error("Invalid token")]
|
|
|
|
struct VerifyError;
|
|
|
|
|
|
|
|
impl ResponseError for TokenError {
|
|
|
|
fn status_code(&self) -> StatusCode {
|
|
|
|
StatusCode::UNAUTHORIZED
|
|
|
|
}
|
|
|
|
|
|
|
|
fn error_response(&self) -> HttpResponse {
|
|
|
|
HttpResponse::build(self.status_code())
|
|
|
|
.content_type(mime::TEXT_PLAIN.essence_str())
|
|
|
|
.body(self.to_string())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ResponseError for VerifyError {
|
|
|
|
fn status_code(&self) -> StatusCode {
|
|
|
|
StatusCode::UNAUTHORIZED
|
|
|
|
}
|
|
|
|
|
|
|
|
fn error_response(&self) -> HttpResponse {
|
|
|
|
HttpResponse::build(self.status_code())
|
|
|
|
.content_type(mime::TEXT_PLAIN.essence_str())
|
|
|
|
.body(self.to_string())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-10 21:20:36 +00:00
|
|
|
impl<S> Transform<S, ServiceRequest> for Verify
|
2020-12-08 21:59:55 +00:00
|
|
|
where
|
2021-02-10 21:20:36 +00:00
|
|
|
S: Service<ServiceRequest, Error = actix_web::Error>,
|
2020-12-08 21:59:55 +00:00
|
|
|
S::Future: 'static,
|
|
|
|
{
|
|
|
|
type Response = S::Response;
|
|
|
|
type Error = S::Error;
|
|
|
|
type InitError = ();
|
|
|
|
type Transform = VerifyMiddleware<S>;
|
|
|
|
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
|
|
|
|
|
|
|
fn new_transform(&self, service: S) -> Self::Future {
|
2021-09-06 20:44:01 +00:00
|
|
|
ready(Ok(VerifyMiddleware(service)))
|
2020-12-08 21:59:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-10 21:20:36 +00:00
|
|
|
impl<S> Service<ServiceRequest> for VerifyMiddleware<S>
|
2020-12-08 21:59:55 +00:00
|
|
|
where
|
2021-02-10 21:20:36 +00:00
|
|
|
S: Service<ServiceRequest, Error = actix_web::Error>,
|
2020-12-08 21:59:55 +00:00
|
|
|
S::Future: 'static,
|
|
|
|
{
|
|
|
|
type Response = S::Response;
|
|
|
|
type Error = S::Error;
|
|
|
|
type Future = LocalBoxFuture<'static, Result<S::Response, S::Error>>;
|
|
|
|
|
2021-02-10 21:20:36 +00:00
|
|
|
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
2020-12-08 21:59:55 +00:00
|
|
|
self.0.poll_ready(cx)
|
|
|
|
}
|
|
|
|
|
2021-02-10 21:20:36 +00:00
|
|
|
fn call(&self, req: ServiceRequest) -> Self::Future {
|
2020-12-08 21:59:55 +00:00
|
|
|
let (req, pl) = req.into_parts();
|
|
|
|
|
|
|
|
let state_fut = web::Data::<crate::State>::extract(&req);
|
|
|
|
let token_fut = Option::<web::Query<crate::Token>>::extract(&req);
|
2020-12-10 05:09:39 +00:00
|
|
|
let path_fut = web::Path::<crate::CollectionPath>::extract(&req);
|
2020-12-08 21:59:55 +00:00
|
|
|
|
2021-02-10 21:20:36 +00:00
|
|
|
let req = ServiceRequest::from_parts(req, pl);
|
2020-12-08 21:59:55 +00:00
|
|
|
|
|
|
|
let (tx, rx) = oneshot::channel();
|
|
|
|
|
|
|
|
req.extensions_mut().insert(rx);
|
|
|
|
|
|
|
|
let service_fut = self.0.call(req);
|
|
|
|
|
|
|
|
Box::pin(async move {
|
|
|
|
let state = state_fut.await?;
|
|
|
|
let path = path_fut.await?;
|
|
|
|
let token = token_fut.await?;
|
|
|
|
|
|
|
|
if let Some(token) = token {
|
|
|
|
let token = token.into_inner();
|
|
|
|
|
|
|
|
if verify(&path, token.clone(), &state).await.is_ok() {
|
|
|
|
tx.send(ValidToken { token: token.token })
|
|
|
|
.map_err(|_| VerifyError)?;
|
|
|
|
} else {
|
|
|
|
drop(tx);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
drop(tx);
|
|
|
|
}
|
|
|
|
|
|
|
|
service_fut.await
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn verify(
|
2020-12-10 05:09:39 +00:00
|
|
|
path: &crate::CollectionPath,
|
2020-12-08 21:59:55 +00:00
|
|
|
token: crate::Token,
|
|
|
|
state: &crate::State,
|
|
|
|
) -> Result<(), VerifyError> {
|
2020-12-12 04:33:56 +00:00
|
|
|
let token_storage = state
|
|
|
|
.store
|
|
|
|
.token(path)
|
|
|
|
.await
|
|
|
|
.map_err(|_| VerifyError)?
|
|
|
|
.ok_or(VerifyError)?;
|
2020-12-08 21:59:55 +00:00
|
|
|
|
|
|
|
let verified = web::block(move || token_storage.verify(&token))
|
|
|
|
.await
|
2021-02-10 21:20:36 +00:00
|
|
|
.map_err(|_| VerifyError)?
|
2020-12-08 21:59:55 +00:00
|
|
|
.map_err(|_| VerifyError)?;
|
|
|
|
|
|
|
|
if !verified {
|
|
|
|
return Err(VerifyError);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|