bjorn-acme 0.3.2

Building blocks for an ACME server
Documentation
use crate::types;

#[derive(Debug)]
pub struct Headers<R> {
    pub responder: R,
    pub headers: Vec<(String, String)>,
}

impl<'r, 'a: 'r, R: rocket::response::Responder<'r, 'a>> rocket::response::Responder<'r, 'a> for Headers<R> {
    fn respond_to(self, request: &'r rocket::request::Request<'_>) -> rocket::response::Result<'a> {
        let mut result = self.responder.respond_to(request)?;
        for header in self.headers {
            result.set_raw_header(header.0, header.1);
        }
        Ok(result)
    }
}

pub enum InnerACMEResponse<'r, 'a: 'r, R: rocket::response::Responder<'r, 'a>> {
    Ok((R, rocket::http::Status)),
    Error(rocket::serde::json::Json<types::error::Error>),
    _Phantom1(std::convert::Infallible, std::marker::PhantomData<&'r R>,),
    _Phantom2(std::convert::Infallible, std::marker::PhantomData<&'a R>,),
}

impl<'r, 'a: 'r, R: rocket::response::Responder<'r, 'a> > rocket::response::Responder<'r, 'a> for InnerACMEResponse<'r, 'a, R> {
    fn respond_to(self, request: &'r rocket::request::Request<'_>) -> rocket::response::Result<'a> {
        match self {
            InnerACMEResponse::Ok((r, s)) => {
                let mut res = r.respond_to(request)?;
                res.set_status(s);
                Ok(res)
            },
            InnerACMEResponse::Error(e) => {
                let status = rocket::http::Status::from_code(e.status).unwrap_or(rocket::http::Status::InternalServerError);
                let mut r = e.respond_to(request)?;
                r.set_status(status);
                r.set_raw_header("Content-Type", "application/problem+json");
                Ok(r)
            }
            InnerACMEResponse::_Phantom1(_, _) | InnerACMEResponse::_Phantom2(_, _) => unreachable!()
        }
    }
}


pub enum ACMEResponse<'r, 'a, R: rocket::response::Responder<'r, 'a>> {
    Normal(super::replay::ReplayNonce<super::links::LinksHeaders<InnerACMEResponse<'r, 'a, R>>>),
    Raw(InnerACMEResponse<'r, 'a, R>)
}

impl<'r, 'a: 'r, R: rocket::response::Responder<'r, 'a>> rocket::response::Responder<'r, 'a> for ACMEResponse<'r, 'a, R> {
    fn respond_to(self, request: &'r rocket::request::Request<'_>) -> rocket::response::Result<'a> {
        match self {
            ACMEResponse::Normal(r) => r.respond_to(request),
            ACMEResponse::Raw(r) => r.respond_to(request)
        }
    }
}

impl<'r, 'a: 'r, R: rocket::response::Responder<'r, 'a> + 'r + 'a> ACMEResponse<'r, 'a, R> {
    pub async fn new(
        r: InnerACMEResponse<'r, 'a, R>, mut extra_links: Vec<super::links::LinkHeader>,
        db: &crate::DBConn, config: &crate::acme::Config
    ) -> ACMEResponse<'r, 'a, R> {
        extra_links.push(super::links::LinkHeader {
            url: super::DIRECTORY_URI.to_string(),
            relative: true,
            relation: "index".to_string(),
        });
        match super::replay::ReplayNonce::new_nonce(
            db,
            super::links::LinksHeaders::new_links(r, extra_links, config)
        ).await {
            Ok(r) => ACMEResponse::Normal(r),
            Err(e) => {
                error!("Failed to generate nonce: {}", e);
                ACMEResponse::Raw(InnerACMEResponse::Error(rocket::serde::json::Json(crate::internal_server_error!())))
            }
        }
    }

    pub async fn new_error(err: types::error::Error, db: &crate::DBConn, config: &crate::acme::Config) -> ACMEResponse<'r, 'a, R> {
        ACMEResponse::new(InnerACMEResponse::Error(rocket::serde::json::Json(err)), vec![], db, config).await
    }
}