114 lines
3.4 KiB
Rust
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())
|
|
}
|