Merge pull request #211 from BillionClaw/clawoss/fix/csp-session-loop

fix(auth): resolve CSP blocking inline styles and fix session refresh loop
This commit is contained in:
Dionisio Pozo
2026-03-16 23:17:19 +01:00
committed by GitHub
2 changed files with 28 additions and 16 deletions
+22 -13
View File
@@ -30,8 +30,10 @@ pub const CSRF_HEADER: &str = "x-csrf-token";
/// Resolution order:
/// 1. `OXICLOUD_COOKIE_SECURE=true|false` — explicit override.
/// 2. `OXICLOUD_BASE_URL` starts with `https` → `true`.
/// 3. **Default: `true`** (safe-by-default). Set `OXICLOUD_COOKIE_SECURE=false`
/// explicitly for plain-HTTP development environments.
/// 3. `OXICLOUD_BASE_URL` starts with `http` → `false`.
/// 4. **Default: `false`** for compatibility with HTTP deployments
/// (Docker, local development). Set `OXICLOUD_COOKIE_SECURE=true`
/// explicitly for production HTTPS environments.
fn cookie_secure() -> bool {
if let Ok(v) = std::env::var("OXICLOUD_COOKIE_SECURE") {
let secure = v == "true" || v == "1";
@@ -44,18 +46,25 @@ fn cookie_secure() -> bool {
}
return secure;
}
// Auto-detect from base URL, defaulting to secure when unset
let secure = std::env::var("OXICLOUD_BASE_URL")
.map(|u| u.starts_with("https"))
.unwrap_or(true);
if !secure {
tracing::warn!(
"OXICLOUD_BASE_URL does not start with https — \
cookie Secure flag is OFF. Set OXICLOUD_COOKIE_SECURE=true \
to override if your proxy terminates TLS."
);
// Auto-detect from base URL, defaulting to insecure for compatibility
match std::env::var("OXICLOUD_BASE_URL") {
Ok(url) if url.starts_with("https") => true,
Ok(url) if url.starts_with("http://") => {
tracing::info!(
"OXICLOUD_BASE_URL is HTTP — cookie Secure flag is OFF. \
Set OXICLOUD_COOKIE_SECURE=true to override if your proxy terminates TLS."
);
false
}
_ => {
// Default to false for compatibility with HTTP deployments
tracing::info!(
"OXICLOUD_BASE_URL not set — defaulting to non-secure cookies \
for HTTP compatibility. Set OXICLOUD_COOKIE_SECURE=true for HTTPS deployments."
);
false
}
}
secure
}
/// Build a `Set-Cookie` header value.
+6 -3
View File
@@ -416,15 +416,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
app = app
.layer(SetResponseHeaderLayer::overriding(
HeaderName::from_static("content-security-policy"),
// All inline scripts and styles have been migrated to external
// files, so 'unsafe-inline' is no longer needed.
// Note: 'unsafe-inline' is required for style-src because the
// frontend JavaScript dynamically sets inline styles (e.g.,
// element.style.display = 'none'). This is a common pattern
// for UI state management and cannot be easily migrated to
// external CSS classes without significant refactoring.
// frame-src: '*' only matches network schemes, so 'blob:' must be
// listed explicitly for inline PDF/document viewers.
// media-src: needed for blob: video/audio playback.
HeaderValue::from_static(
"default-src 'self'; \
script-src 'self'; \
style-src 'self'; \
style-src 'self' 'unsafe-inline'; \
img-src 'self' data: blob:; \
media-src 'self' blob:; \
connect-src 'self'; \