datatrash/src/main.rs

135 lines
5.0 KiB
Rust
Raw Permalink Normal View History

mod config;
mod db;
2020-07-09 17:27:24 +00:00
mod deleter;
mod download;
mod file_info;
mod mime_relations;
2020-07-08 19:26:46 +00:00
mod multipart;
2022-08-21 16:44:12 +00:00
mod rate_limit;
mod script_nonce;
mod template;
mod upload;
2020-07-08 19:26:46 +00:00
2022-08-21 16:44:12 +00:00
use crate::rate_limit::ForwardedPeerIpKeyExtractor;
use actix_files::Files;
2022-08-21 16:44:12 +00:00
use actix_governor::{Governor, GovernorConfigBuilder};
2022-02-26 23:34:57 +00:00
use actix_web::{
2023-04-20 19:46:56 +00:00
http::header::{
HeaderName, CROSS_ORIGIN_OPENER_POLICY, PERMISSIONS_POLICY, REFERRER_POLICY,
2023-04-20 19:46:56 +00:00
X_CONTENT_TYPE_OPTIONS, X_FRAME_OPTIONS, X_XSS_PROTECTION,
},
middleware::{self, Condition, DefaultHeaders},
2022-02-26 23:34:57 +00:00
web::{self, Data},
App, Error, HttpResponse, HttpServer,
};
use actix_web_lab::middleware::from_fn;
use env_logger::Env;
use sqlx::postgres::PgPool;
2020-07-08 19:26:46 +00:00
use std::env;
use tokio::sync::mpsc::channel;
2020-07-08 19:26:46 +00:00
static DEFAULT_PERMISSIONS: (HeaderName, &str) = (
2023-04-20 19:46:56 +00:00
PERMISSIONS_POLICY,
"accelerometer=(), ambient-light-sensor=(), battery=(), camera=(), display-capture=(), document-domain=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), sync-xhr=(), usb=(), web-share=()"
);
static DEFAULT_CONTENT_TYPE_OPTIONS: (HeaderName, &str) = (X_CONTENT_TYPE_OPTIONS, "nosniff");
static DEFAULT_FRAME_OPTIONS: (HeaderName, &str) = (X_FRAME_OPTIONS, "deny");
static DEFAULT_XSS_PROTECTION: (HeaderName, &str) = (X_XSS_PROTECTION, "1; mode=block");
static DEFAULT_REFERRER_POLICY: (HeaderName, &str) = (REFERRER_POLICY, "no-referrer");
static DEFAULT_CROSS_ORIGIN_OPENER_POLICY: (HeaderName, &str) =
(CROSS_ORIGIN_OPENER_POLICY, "same-origin");
2020-08-19 14:24:42 +00:00
async fn not_found() -> Result<HttpResponse, Error> {
Ok(HttpResponse::NotFound()
.content_type("text/plain")
.body("not found"))
}
2022-02-26 23:34:57 +00:00
#[tokio::main]
2020-07-08 19:26:46 +00:00
async fn main() -> std::io::Result<()> {
env_logger::Builder::from_env(Env::default().default_filter_or("info,sqlx=warn")).init();
2020-07-08 19:26:46 +00:00
2022-11-04 10:37:10 +00:00
let pool: PgPool = db::setup().await;
let config = config::from_env().await;
2022-02-26 23:34:57 +00:00
let (sender, receiver) = channel(8);
2021-08-18 21:22:50 +00:00
let db = web::Data::new(pool.clone());
let expiry_watch_sender = web::Data::new(sender);
let bind_address = env::var("BIND_ADDRESS").unwrap_or_else(|_| "0.0.0.0:8000".to_owned());
let deleter = tokio::spawn(deleter::delete_old_files(
2020-07-14 15:53:43 +00:00
receiver,
2021-08-18 21:22:50 +00:00
pool,
2020-07-11 21:27:15 +00:00
config.files_dir.clone(),
));
2020-07-09 17:27:24 +00:00
template::write_prefillable_templates(&config).await;
2022-02-26 23:34:57 +00:00
let config = Data::new(config);
2022-08-21 16:44:12 +00:00
let governor_conf = GovernorConfigBuilder::default()
.per_second(config.rate_limit_replenish_seconds)
2022-08-21 16:44:12 +00:00
.burst_size(config.rate_limit_burst)
.key_extractor(ForwardedPeerIpKeyExtractor {
proxied: config.proxied,
})
.use_headers()
.finish()
.unwrap();
log::info!("Listening on {bind_address}");
log::info!("omnomnom");
let http_server = HttpServer::new({
2020-07-11 21:27:15 +00:00
move || {
2023-03-15 08:44:31 +00:00
App::new()
.wrap(
DefaultHeaders::new()
.add(DEFAULT_PERMISSIONS.clone())
.add(DEFAULT_CONTENT_TYPE_OPTIONS.clone())
.add(DEFAULT_FRAME_OPTIONS.clone())
.add(DEFAULT_XSS_PROTECTION.clone())
.add(DEFAULT_REFERRER_POLICY.clone())
.add(DEFAULT_CROSS_ORIGIN_OPENER_POLICY.clone()),
)
2022-02-26 23:34:57 +00:00
.wrap(middleware::Compress::default())
2023-03-15 08:44:31 +00:00
.wrap(middleware::NormalizePath::trim())
.wrap(from_fn(script_nonce::insert_script_nonce))
2020-07-11 21:27:15 +00:00
.app_data(db.clone())
2020-12-03 22:30:37 +00:00
.app_data(expiry_watch_sender.clone())
2022-02-26 23:34:57 +00:00
.app_data(config.clone())
2023-04-14 08:00:44 +00:00
.service(
web::resource("/")
.route(web::get().to(upload::index))
.route(web::head().to(upload::index)),
)
.service(web::resource("/upload").route(web::post().to(upload::upload)))
2020-08-02 23:12:42 +00:00
.service(
2020-08-03 00:42:27 +00:00
web::resource(["/upload/{id}", "/upload/{id}/{name}"])
2023-04-14 08:00:44 +00:00
.route(web::get().to(upload::uploaded))
.route(web::head().to(upload::uploaded)),
2020-08-03 00:42:27 +00:00
)
.service(Files::new("/static", "static").disable_content_disposition())
2023-03-15 08:44:31 +00:00
.default_service(web::route().to(not_found))
.service(
2023-04-14 08:00:44 +00:00
web::resource(["/{id:[a-z0-9]{5}}", "/{id:[a-z0-9]{5}}/{name}"])
.wrap(Condition::new(
config.enable_rate_limit,
Governor::new(&governor_conf),
))
.route(web::get().to(download::download))
.route(web::head().to(download::download)),
2020-08-02 23:12:42 +00:00
)
2020-07-11 21:27:15 +00:00
}
2020-07-08 19:26:46 +00:00
})
2020-07-11 21:27:15 +00:00
.bind(bind_address)?
.run();
// exit when http_server exits OR when deleter errors
tokio::select! {
result = http_server => result,
result = deleter => {
result?.map(|_| unreachable!("deletion runs infinitely")).expect("deletion may not fail")
},
}
2020-07-08 19:26:46 +00:00
}