forked from jmug/stoatchat
201 lines
6.5 KiB
Rust
201 lines
6.5 KiB
Rust
#[macro_use]
|
|
extern crate rocket;
|
|
#[macro_use]
|
|
extern crate revolt_rocket_okapi;
|
|
#[macro_use]
|
|
extern crate serde_json;
|
|
|
|
pub mod routes;
|
|
pub mod util;
|
|
|
|
use revolt_config::config;
|
|
use revolt_database::events::client::EventV1;
|
|
use revolt_database::{Database, MongoDb};
|
|
use rocket::{Build, Rocket};
|
|
use rocket_cors::{AllowedOrigins, CorsOptions};
|
|
use rocket_prometheus::PrometheusMetrics;
|
|
use std::net::Ipv4Addr;
|
|
use std::str::FromStr;
|
|
|
|
use async_std::channel::unbounded;
|
|
use authifier::config::{
|
|
Captcha, Config as AuthifierConfig, EmailVerificationConfig, ResolveIp, SMTPSettings, Shield,
|
|
Template, Templates,
|
|
};
|
|
use authifier::{Authifier, AuthifierEvent};
|
|
use rocket::data::ToByteUnit;
|
|
|
|
pub async fn web() -> Rocket<Build> {
|
|
// Get settings
|
|
let config = config().await;
|
|
|
|
// Ensure environment variables are present
|
|
config.preflight_checks();
|
|
|
|
// Setup database
|
|
let db = revolt_database::DatabaseInfo::Auto.connect().await.unwrap();
|
|
db.migrate_database().await.unwrap();
|
|
|
|
// Setup Authifier event channel
|
|
let (sender, receiver) = unbounded();
|
|
|
|
// Setup Authifier
|
|
let authifier = Authifier {
|
|
database: match db.clone() {
|
|
Database::Reference(_) => Default::default(),
|
|
Database::MongoDb(MongoDb(client, _)) => authifier::Database::MongoDb(
|
|
authifier::database::MongoDb(client.database("revolt")),
|
|
),
|
|
},
|
|
config: authifier_config().await,
|
|
event_channel: Some(sender),
|
|
};
|
|
|
|
// Launch a listener for Authifier events
|
|
async_std::task::spawn(async move {
|
|
while let Ok(event) = receiver.recv().await {
|
|
match &event {
|
|
AuthifierEvent::CreateSession { .. } | AuthifierEvent::CreateAccount { .. } => {
|
|
EventV1::Auth(event).global().await
|
|
}
|
|
AuthifierEvent::DeleteSession { user_id, .. }
|
|
| AuthifierEvent::DeleteAllSessions { user_id, .. } => {
|
|
let id = user_id.to_string();
|
|
EventV1::Auth(event).private(id).await
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Launch background task workers
|
|
async_std::task::spawn(revolt_database::tasks::start_workers(
|
|
db.clone(),
|
|
authifier.database.clone(),
|
|
));
|
|
|
|
// Configure CORS
|
|
let cors = CorsOptions {
|
|
allowed_origins: AllowedOrigins::All,
|
|
allowed_methods: [
|
|
"Get", "Put", "Post", "Delete", "Options", "Head", "Trace", "Connect", "Patch",
|
|
]
|
|
.iter()
|
|
.map(|s| FromStr::from_str(s).unwrap())
|
|
.collect(),
|
|
..Default::default()
|
|
}
|
|
.to_cors()
|
|
.expect("Failed to create CORS.");
|
|
|
|
// Configure Swagger
|
|
let swagger = revolt_rocket_okapi::swagger_ui::make_swagger_ui(
|
|
&revolt_rocket_okapi::swagger_ui::SwaggerUIConfig {
|
|
url: "../openapi.json".to_owned(),
|
|
..Default::default()
|
|
},
|
|
)
|
|
.into();
|
|
|
|
// Configure Rocket
|
|
let rocket = rocket::build();
|
|
let prometheus = PrometheusMetrics::new();
|
|
|
|
routes::mount(config, rocket)
|
|
.attach(prometheus.clone())
|
|
.mount("/metrics", prometheus)
|
|
.mount("/", rocket_cors::catch_all_options_routes())
|
|
.mount("/", util::ratelimiter::routes())
|
|
.mount("/swagger/", swagger)
|
|
.manage(authifier)
|
|
.manage(db)
|
|
.manage(cors.clone())
|
|
.attach(util::ratelimiter::RatelimitFairing)
|
|
.attach(cors)
|
|
.configure(rocket::Config {
|
|
limits: rocket::data::Limits::default().limit("string", 5.megabytes()),
|
|
address: Ipv4Addr::new(0, 0, 0, 0).into(),
|
|
..Default::default()
|
|
})
|
|
}
|
|
|
|
pub async fn authifier_config() -> AuthifierConfig {
|
|
let config = config().await;
|
|
|
|
let mut auth_config = AuthifierConfig {
|
|
email_verification: if !config.api.smtp.host.is_empty() {
|
|
EmailVerificationConfig::Enabled {
|
|
smtp: SMTPSettings {
|
|
from: config.api.smtp.from_address,
|
|
host: config.api.smtp.host,
|
|
username: config.api.smtp.username,
|
|
password: config.api.smtp.password,
|
|
reply_to: Some(
|
|
config
|
|
.api
|
|
.smtp
|
|
.reply_to
|
|
.unwrap_or("support@revolt.chat".into()),
|
|
),
|
|
port: config.api.smtp.port,
|
|
use_tls: config.api.smtp.use_tls,
|
|
},
|
|
expiry: Default::default(),
|
|
templates: Templates {
|
|
verify: Template {
|
|
title: "Verify your Revolt account.".into(),
|
|
text: include_str!("templates/verify.txt").into(),
|
|
url: format!("{}/login/verify/", config.hosts.app),
|
|
html: Some(include_str!("templates/verify.html").into()),
|
|
},
|
|
reset: Template {
|
|
title: "Reset your Revolt password.".into(),
|
|
text: include_str!("templates/reset.txt").into(),
|
|
url: format!("{}/login/reset/", config.hosts.app),
|
|
html: Some(include_str!("templates/reset.html").into()),
|
|
},
|
|
deletion: Template {
|
|
title: "Confirm account deletion.".into(),
|
|
text: include_str!("templates/deletion.txt").into(),
|
|
url: format!("{}/delete/", config.hosts.app),
|
|
html: Some(include_str!("templates/deletion.html").into()),
|
|
},
|
|
welcome: None,
|
|
},
|
|
}
|
|
} else {
|
|
EmailVerificationConfig::Disabled
|
|
},
|
|
..Default::default()
|
|
};
|
|
|
|
auth_config.invite_only = config.api.registration.invite_only;
|
|
|
|
if !config.api.security.captcha.hcaptcha_key.is_empty() {
|
|
auth_config.captcha = Captcha::HCaptcha {
|
|
secret: config.api.security.captcha.hcaptcha_key,
|
|
};
|
|
}
|
|
|
|
if !config.api.security.authifier_shield_key.is_empty() {
|
|
auth_config.shield = Shield::Enabled {
|
|
api_key: config.api.security.authifier_shield_key,
|
|
strict: false,
|
|
};
|
|
}
|
|
|
|
if config.api.security.trust_cloudflare {
|
|
auth_config.resolve_ip = ResolveIp::Cloudflare;
|
|
}
|
|
|
|
auth_config
|
|
}
|
|
|
|
#[launch]
|
|
async fn rocket() -> _ {
|
|
// Configure logging and environment
|
|
revolt_config::configure!(api);
|
|
|
|
// Start web server
|
|
web().await
|
|
}
|