pinakes: import in parallel; various UI improvements
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I1eb47cd79cd4145c56af966f6756fe1d6a6a6964
This commit is contained in:
parent
278bcaa4b0
commit
116fe7b059
42 changed files with 4316 additions and 316 deletions
|
|
@ -5,16 +5,27 @@ use axum::extract::DefaultBodyLimit;
|
|||
use axum::http::{HeaderValue, Method, header};
|
||||
use axum::middleware;
|
||||
use axum::routing::{delete, get, patch, post, put};
|
||||
use tower::ServiceBuilder;
|
||||
use tower_governor::GovernorLayer;
|
||||
use tower_governor::governor::GovernorConfigBuilder;
|
||||
use tower_http::cors::CorsLayer;
|
||||
use tower_http::set_header::SetResponseHeaderLayer;
|
||||
use tower_http::trace::TraceLayer;
|
||||
|
||||
use crate::auth;
|
||||
use crate::routes;
|
||||
use crate::state::AppState;
|
||||
|
||||
/// Create the router with optional TLS configuration for HSTS headers
|
||||
pub fn create_router(state: AppState) -> Router {
|
||||
create_router_with_tls(state, None)
|
||||
}
|
||||
|
||||
/// Create the router with TLS configuration for security headers
|
||||
pub fn create_router_with_tls(
|
||||
state: AppState,
|
||||
tls_config: Option<&pinakes_core::config::TlsConfig>,
|
||||
) -> Router {
|
||||
// Global rate limit: 100 requests/sec per IP
|
||||
let global_governor = Arc::new(
|
||||
GovernorConfigBuilder::default()
|
||||
|
|
@ -41,11 +52,16 @@ pub fn create_router(state: AppState) -> Router {
|
|||
});
|
||||
|
||||
// Public routes (no auth required)
|
||||
let public_routes = Router::new().route("/s/{token}", get(routes::social::access_shared_media));
|
||||
let public_routes = Router::new()
|
||||
.route("/s/{token}", get(routes::social::access_shared_media))
|
||||
// Kubernetes-style health probes (no auth required for orchestration)
|
||||
.route("/health/live", get(routes::health::liveness))
|
||||
.route("/health/ready", get(routes::health::readiness));
|
||||
|
||||
// Read-only routes: any authenticated user (Viewer+)
|
||||
let viewer_routes = Router::new()
|
||||
.route("/health", get(routes::health::health))
|
||||
.route("/health/detailed", get(routes::health::health_detailed))
|
||||
.route("/media/count", get(routes::media::get_media_count))
|
||||
.route("/media", get(routes::media::list_media))
|
||||
.route("/media/{id}", get(routes::media::get_media))
|
||||
|
|
@ -393,7 +409,40 @@ pub fn create_router(state: AppState) -> Router {
|
|||
.merge(public_routes)
|
||||
.merge(protected_api);
|
||||
|
||||
Router::new()
|
||||
// Build security headers layer
|
||||
let security_headers = ServiceBuilder::new()
|
||||
// Prevent MIME type sniffing
|
||||
.layer(SetResponseHeaderLayer::overriding(
|
||||
header::X_CONTENT_TYPE_OPTIONS,
|
||||
HeaderValue::from_static("nosniff"),
|
||||
))
|
||||
// Prevent clickjacking
|
||||
.layer(SetResponseHeaderLayer::overriding(
|
||||
header::X_FRAME_OPTIONS,
|
||||
HeaderValue::from_static("DENY"),
|
||||
))
|
||||
// XSS protection (legacy but still useful for older browsers)
|
||||
.layer(SetResponseHeaderLayer::overriding(
|
||||
header::HeaderName::from_static("x-xss-protection"),
|
||||
HeaderValue::from_static("1; mode=block"),
|
||||
))
|
||||
// Referrer policy
|
||||
.layer(SetResponseHeaderLayer::overriding(
|
||||
header::REFERRER_POLICY,
|
||||
HeaderValue::from_static("strict-origin-when-cross-origin"),
|
||||
))
|
||||
// Permissions policy (disable unnecessary features)
|
||||
.layer(SetResponseHeaderLayer::overriding(
|
||||
header::HeaderName::from_static("permissions-policy"),
|
||||
HeaderValue::from_static("geolocation=(), microphone=(), camera=()"),
|
||||
))
|
||||
// Content Security Policy for API responses
|
||||
.layer(SetResponseHeaderLayer::overriding(
|
||||
header::CONTENT_SECURITY_POLICY,
|
||||
HeaderValue::from_static("default-src 'none'; frame-ancestors 'none'"),
|
||||
));
|
||||
|
||||
let router = Router::new()
|
||||
.nest("/api/v1", full_api)
|
||||
.layer(DefaultBodyLimit::max(10 * 1024 * 1024))
|
||||
.layer(GovernorLayer {
|
||||
|
|
@ -401,5 +450,26 @@ pub fn create_router(state: AppState) -> Router {
|
|||
})
|
||||
.layer(TraceLayer::new_for_http())
|
||||
.layer(cors)
|
||||
.with_state(state)
|
||||
.layer(security_headers);
|
||||
|
||||
// Add HSTS header when TLS is enabled
|
||||
if let Some(tls) = tls_config {
|
||||
if tls.enabled && tls.hsts_enabled {
|
||||
let hsts_value = format!("max-age={}; includeSubDomains", tls.hsts_max_age);
|
||||
let hsts_header = HeaderValue::from_str(&hsts_value).unwrap_or_else(|_| {
|
||||
HeaderValue::from_static("max-age=31536000; includeSubDomains")
|
||||
});
|
||||
|
||||
router
|
||||
.layer(SetResponseHeaderLayer::overriding(
|
||||
header::STRICT_TRANSPORT_SECURITY,
|
||||
hsts_header,
|
||||
))
|
||||
.with_state(state)
|
||||
} else {
|
||||
router.with_state(state)
|
||||
}
|
||||
} else {
|
||||
router.with_state(state)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue