Files
seensite/src/lib.rs

114 lines
3.4 KiB
Rust

pub mod auth;
pub mod config;
mod error;
pub mod meilisearch;
pub mod page;
use meilisearch_sdk::client::Client as MeilisearchClient;
use rocket::fairing::{self, AdHoc};
use rocket::Rocket;
use rocket_dyn_templates::Template;
use tracing::error;
use config::Config;
pub use error::InitError;
pub struct Context {
client: MeilisearchClient,
jwt_secret: Vec<u8>,
oidc: config::OidcConfig,
oidc_client_secret: Option<String>,
oidc_http_client: reqwest::Client,
}
impl Context {
pub async fn init(config: &Config) -> Result<Self, InitError> {
let client = MeilisearchClient::try_from(config)?;
let jwt_secret = auth::load_secret(&config.auth.jwt_secret)
.map_err(InitError::LoadJwtSecret)?;
let oidc = config.oidc.clone();
let oidc_client_secret = match &config.oidc.client_secret {
Some(p) => match auth::load_secret(p) {
Ok(s) => Some(String::from_utf8_lossy(&s).trim().to_string()),
Err(e) => return Err(InitError::LoadOidcSecret(e)),
},
None => None,
};
let oidc_http_client = reqwest::ClientBuilder::new()
.redirect(reqwest::redirect::Policy::none())
.build()?;
Ok(Self {
client,
jwt_secret,
oidc,
oidc_client_secret,
oidc_http_client,
})
}
pub async fn oidc(&self) -> Result<auth::OidcClient, error::OidcError> {
auth::get_oidc_client(
self.oidc.discovery_url.clone(),
self.oidc.client_id.clone(),
self.oidc_client_secret.clone(),
self.oidc.callback_url.clone(),
&self.oidc_http_client,
)
.await
}
}
/// Initialize the application context
async fn init_context(rocket: Rocket<rocket::Build>) -> fairing::Result {
let config: &Config = rocket.state().unwrap();
let ctx = match Context::init(config).await {
Ok(c) => c,
Err(e) => {
eprintln!("Could not initialize application context: {}", e);
return Err(rocket);
},
};
// Use the JWT secret as the Rocket secret key, for encrypted cookies
let figment = rocket
.figment()
.clone()
.join(("secret_key", &ctx.jwt_secret));
Ok(rocket.configure(figment).manage(ctx))
}
/// Set up Meilisearch
async fn meilisearch_setup(rocket: Rocket<rocket::Build>) -> fairing::Result {
let config: &Config = rocket.state().unwrap();
let ctx: &Context = match rocket.state() {
Some(c) => c,
None => return Err(rocket),
};
let client = &ctx.client;
if let Err(e) =
meilisearch::ensure_index(client, &config.meilisearch.index).await
{
error!("Failed to create Meilisearch index: {}", e);
Err(rocket)
} else {
Ok(rocket)
}
}
pub fn rocket() -> Rocket<rocket::Build> {
rocket::build()
.mount(
"/",
rocket::routes![
page::index,
page::get_page,
auth::oidc_callback,
auth::oidc_login,
page::post_page
],
)
.attach(AdHoc::config::<Config>())
.attach(AdHoc::try_on_ignite("Initialize context", init_context))
.attach(AdHoc::try_on_ignite("Meilisearch Setup", meilisearch_setup))
.attach(Template::fairing())
}