use crate::config::Config;
use crate::errors::DecodeTokenError;
use backoff::ExponentialBackoffBuilder;
use cookie::Cookie;
use http::{header::COOKIE, uri::Authority, HeaderMap, HeaderValue, Uri};
use hyper::Client;
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
use serde::{Deserialize, Serialize};
pub(crate) type HttpClient = Client<hyper::client::HttpConnector>;
#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct AuthCookie {
pub exp: usize,
pub iat: usize,
pub iss: String,
pub nbf: usize,
pub sub: String,
pub name: String,
pub email: String,
pub origin: String,
pub addr: String,
pub picture: String,
}
pub(crate) fn decode_auth_cookie(
headers: &HeaderMap<HeaderValue>,
config: &Config,
) -> Result<AuthCookie, DecodeTokenError> {
let cookie_header = headers
.get(COOKIE)
.ok_or(DecodeTokenError::NoCookieHeader)?;
let cookie = cookie_header
.to_str()
.unwrap()
.split(';')
.map(str::trim)
.filter(|s| !s.is_empty())
.flat_map(Cookie::parse)
.find(|cookie| cookie.name() == config.auth_cookie_name)
.ok_or(DecodeTokenError::ParseError)?;
let token = decode::<AuthCookie>(
cookie.value(),
&DecodingKey::from_secret(config.secret.as_ref().as_bytes()),
&Validation::new(Algorithm::HS512),
)
.map_err(DecodeTokenError::JWTError)?;
Ok(token.claims)
}
pub(crate) async fn http_healthcheck(
client: HttpClient,
authority: Authority,
) -> Result<(), backoff::Error<hyper::Error>> {
println!("waiting for server {} to start up", &authority);
let uri = Uri::builder()
.scheme("http")
.authority(authority)
.path_and_query("/")
.build()
.unwrap();
client.get(uri).await?;
Ok(())
}
pub(crate) async fn wait_for_http_service(authority: Authority) {
let client = Client::new();
backoff::future::retry(
ExponentialBackoffBuilder::new()
.with_multiplier(1.5)
.build(),
|| http_healthcheck(client.clone(), authority.clone()),
)
.await
.unwrap();
}