mod.rs
⎇
Raw
1use std::sync::Arc;
2
3use axum::Router;
4use axum::http::HeaderValue;
5use axum::routing::{delete, get, post, put};
6use tower_http::set_header::SetResponseHeaderLayer;
7
8use crate::error::AppState;
9
10/// Content-Security-Policy tuned to the built Trunk frontend.
11///
12/// * `script-src 'unsafe-inline'` — Trunk emits one inline bootstrap module
13/// in index.html; every real JS file also carries an SRI integrity hash.
14/// * `'wasm-unsafe-eval'` — compiling the same-origin WASM module.
15/// * `style-src 'unsafe-inline'` — the context menu sets an inline `style=`.
16/// * Everything else locked to the same origin; frames/plugins banned.
17const CSP: &str = "default-src 'self'; script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; media-src 'self' blob:; connect-src 'self'; font-src 'self' data:; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none';";
18
19mod admin;
20mod auth;
21mod common;
22mod files;
23mod shares;
24mod spa;
25
26pub fn router(state: Arc<AppState>) -> Router {
27 Router::new()
28 .route("/api/auth/login", post(auth::login))
29 .route("/api/auth/logout", post(auth::logout))
30 .route("/api/auth/me", get(auth::me))
31 .route("/api/auth/setup", post(auth::setup))
32 .route("/api/files/{root_id}", get(files::list_root))
33 .route("/api/files/{root_id}/{*path}", get(files::file_get))
34 .route("/api/files/{root_id}/{*path}", put(files::file_put))
35 .route("/api/files/{root_id}", post(files::dispatch_root))
36 .route("/api/files/{root_id}/{*path}", post(files::dispatch))
37 .route("/api/files/{root_id}/{*path}", delete(files::delete))
38 .route("/api/shares", get(shares::list))
39 .route("/api/shares", post(shares::create))
40 .route("/api/shares/{id}", delete(shares::delete))
41 .route("/api/share/{token}", get(shares::resolve))
42 .route("/api/admin/users", get(admin::list_users))
43 .route("/api/admin/users", post(admin::create_user))
44 .route("/api/admin/users/{id}", put(admin::update_user))
45 .route("/api/admin/users/{id}", delete(admin::delete_user))
46 .route("/api/admin/settings", get(admin::get_settings))
47 .route("/api/admin/settings", put(admin::update_settings))
48 .fallback(spa::fallback)
49 .with_state(state)
50 // Hard security headers on every response (API and static alike).
51 .layer(SetResponseHeaderLayer::overriding(
52 "content-security-policy".parse().unwrap(),
53 HeaderValue::from_static(CSP),
54 ))
55 .layer(SetResponseHeaderLayer::overriding(
56 "x-content-type-options".parse().unwrap(),
57 HeaderValue::from_static("nosniff"),
58 ))
59 .layer(SetResponseHeaderLayer::overriding(
60 "x-frame-options".parse().unwrap(),
61 HeaderValue::from_static("DENY"),
62 ))
63 .layer(SetResponseHeaderLayer::overriding(
64 "referrer-policy".parse().unwrap(),
65 HeaderValue::from_static("no-referrer"),
66 ))
67}
68