use crate::{
constants::{
media_type_from_leader, MEDIA_TYPE_AGG_CONT_REQ, MEDIA_TYPE_AGG_INIT_REQ,
MEDIA_TYPE_AGG_SHARE_REQ, MEDIA_TYPE_COLLECT_REQ,
},
messages::{constant_time_eq, Id},
DapError, DapRequest,
};
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct BearerToken {
raw: String,
}
impl AsRef<str> for BearerToken {
fn as_ref(&self) -> &str {
self.raw.as_str()
}
}
impl PartialEq for BearerToken {
fn eq(&self, other: &Self) -> bool {
constant_time_eq(self.raw.as_bytes(), other.raw.as_bytes())
}
}
impl From<String> for BearerToken {
fn from(raw: String) -> Self {
Self { raw }
}
}
impl From<&str> for BearerToken {
fn from(raw: &str) -> Self {
Self {
raw: raw.to_string(),
}
}
}
impl AsRef<BearerToken> for BearerToken {
fn as_ref(&self) -> &Self {
self
}
}
#[async_trait(?Send)]
pub trait BearerTokenProvider<'a> {
type WrappedBearerToken: AsRef<BearerToken>;
async fn get_leader_bearer_token_for(
&'a self,
task_id: &'a Id,
) -> Result<Option<Self::WrappedBearerToken>, DapError>;
async fn get_collector_bearer_token_for(
&'a self,
task_id: &'a Id,
) -> Result<Option<Self::WrappedBearerToken>, DapError>;
async fn authorize_with_bearer_token(
&'a self,
task_id: &'a Id,
media_type: &'static str,
) -> Result<Self::WrappedBearerToken, DapError> {
if media_type_from_leader(media_type) {
let token = self
.get_leader_bearer_token_for(task_id)
.await?
.ok_or_else(|| {
DapError::Fatal("attempted to authorize request with unknown task ID".into())
})?;
return Ok(token);
}
Err(DapError::Fatal(format!(
"attempted to authorize request of type '{}'",
media_type
)))
}
async fn bearer_token_authorized(
&'a self,
req: &'a DapRequest<BearerToken>,
) -> Result<bool, DapError> {
if req.task_id.is_none() {
return Ok(false);
}
let task_id = req.task_id.as_ref().unwrap();
if matches!(
req.media_type,
Some(MEDIA_TYPE_AGG_INIT_REQ)
| Some(MEDIA_TYPE_AGG_CONT_REQ)
| Some(MEDIA_TYPE_AGG_SHARE_REQ)
) {
if let Some(ref got) = req.sender_auth {
if let Some(expected) = self.get_leader_bearer_token_for(task_id).await? {
return Ok(got == expected.as_ref());
}
}
}
if matches!(req.media_type, Some(MEDIA_TYPE_COLLECT_REQ)) {
if let Some(ref got) = req.sender_auth {
if let Some(expected) = self.get_collector_bearer_token_for(task_id).await? {
return Ok(got == expected.as_ref());
}
}
}
Ok(false)
}
}