/*
* Copyright (C) 2024 Jonni Liljamo <jonni@liljamo.com>
*
* This file is licensed under GPL-3.0-or-later, see NOTICE and LICENSE for
* more information.
*/
use std::{future::Future, pin::Pin};
use tonic::{Request, Status};
use tonic_async_interceptor::AsyncInterceptor;
#[derive(Clone)]
pub struct AuthInterceptor {
auth_token: String,
}
impl AuthInterceptor {
pub fn new(auth_token: String) -> Self {
Self { auth_token }
}
fn authenticate(
&self,
request: Request<()>,
) -> impl Future<Output = Result<Request<()>, Status>> + Send + 'static {
let auth_token = self.auth_token.clone();
async move {
let token = match request.metadata().get("authorization") {
Some(value) => match value.to_str() {
Ok(bearer_token) => bearer_token.trim_start_matches("Bearer "),
Err(_) => {
return Err(Status::invalid_argument(
"couldn't read bearer auth to string",
))
}
},
None => return Err(Status::unauthenticated("request had no authorization")),
};
if token == auth_token {
Ok(request)
} else {
Err(Status::unauthenticated("bad token"))
}
}
}
}
impl AsyncInterceptor for AuthInterceptor {
type Future = Pin<Box<dyn Future<Output = Result<Request<()>, Status>> + Send + 'static>>;
fn call(&mut self, request: Request<()>) -> Self::Future {
Box::pin(self.authenticate(request))
}
}