fix: Gitea Traefik routing and connection pool optimization
Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled

- Remove middleware reference from Gitea Traefik labels (caused routing issues)
- Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s)
- Add explicit service reference in Traefik labels
- Fix intermittent 504 timeouts by improving PostgreSQL connection handling

Fixes Gitea unreachability via git.michaelschiemer.de
This commit is contained in:
2025-11-09 14:46:15 +01:00
parent 85c369e846
commit 36ef2a1e2c
1366 changed files with 104925 additions and 28719 deletions

View File

@@ -0,0 +1,254 @@
/**
* Security Manager
*
* Provides security-related utilities including CSRF, XSS protection, and CSP helpers.
*/
import { Logger } from '../../core/logger.js';
import { CsrfManager } from './CsrfManager.js';
/**
* SecurityManager - Centralized security utilities
*/
export class SecurityManager {
constructor(config = {}) {
this.config = {
csrf: config.csrf || {},
xss: {
enabled: config.xss?.enabled ?? true,
sanitizeOnInput: config.xss?.sanitizeOnInput ?? false
},
csp: {
enabled: config.csp?.enabled ?? false,
reportOnly: config.csp?.reportOnly ?? false
},
...config
};
this.csrfManager = null;
// Initialize
this.init();
}
/**
* Create a new SecurityManager instance
*/
static create(config = {}) {
return new SecurityManager(config);
}
/**
* Initialize security manager
*/
init() {
// Initialize CSRF manager
this.csrfManager = CsrfManager.create(this.config.csrf);
// Initialize XSS protection if enabled
if (this.config.xss.enabled) {
this.initXssProtection();
}
// Initialize CSP if enabled
if (this.config.csp.enabled) {
this.initCsp();
}
Logger.info('[SecurityManager] Initialized', {
csrf: !!this.csrfManager,
xss: this.config.xss.enabled,
csp: this.config.csp.enabled
});
}
/**
* Initialize XSS protection
*/
initXssProtection() {
// Add input sanitization if enabled
if (this.config.xss.sanitizeOnInput) {
document.addEventListener('input', (event) => {
if (event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA') {
this.sanitizeInput(event.target);
}
}, true);
}
}
/**
* Sanitize input value
*/
sanitizeInput(element) {
const originalValue = element.value;
const sanitized = this.sanitizeHtml(originalValue);
if (sanitized !== originalValue) {
element.value = sanitized;
Logger.warn('[SecurityManager] Sanitized potentially dangerous input', {
field: element.name || element.id
});
}
}
/**
* Sanitize HTML string
*/
sanitizeHtml(html) {
if (typeof html !== 'string') {
return html;
}
// Remove script tags and event handlers
return html
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
.replace(/on\w+\s*=\s*["'][^"']*["']/gi, '')
.replace(/javascript:/gi, '')
.replace(/data:text\/html/gi, '');
}
/**
* Initialize Content Security Policy
*/
initCsp() {
// CSP is typically set server-side, but we can validate it client-side
const cspHeader = this.getCspHeader();
if (cspHeader) {
Logger.debug('[SecurityManager] CSP header found', cspHeader);
this.validateCsp(cspHeader);
} else {
Logger.warn('[SecurityManager] No CSP header found');
}
}
/**
* Get CSP header from meta tag or response headers
*/
getCspHeader() {
// Try meta tag
const metaTag = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
if (metaTag) {
return metaTag.getAttribute('content');
}
// Note: Response headers are not accessible from JavaScript
// This would need to be passed from server or checked server-side
return null;
}
/**
* Validate CSP header
*/
validateCsp(cspHeader) {
// Basic validation - check for common security directives
const requiredDirectives = ['default-src', 'script-src', 'style-src'];
const directives = cspHeader.split(';').map(d => d.trim().split(' ')[0]);
const missing = requiredDirectives.filter(dir =>
!directives.some(d => d.toLowerCase() === dir.toLowerCase())
);
if (missing.length > 0) {
Logger.warn('[SecurityManager] CSP missing recommended directives', missing);
}
}
/**
* Get CSRF token
*/
getCsrfToken() {
return this.csrfManager?.getToken() || null;
}
/**
* Get CSRF token header
*/
getCsrfTokenHeader() {
return this.csrfManager?.getTokenHeader() || {};
}
/**
* Refresh CSRF token
*/
async refreshCsrfToken() {
if (this.csrfManager) {
return await this.csrfManager.refreshToken();
}
}
/**
* Validate security headers
*/
validateSecurityHeaders() {
const issues = [];
// Check for HTTPS
if (location.protocol !== 'https:' && location.hostname !== 'localhost') {
issues.push('Not using HTTPS');
}
// Check for CSP
if (!this.getCspHeader()) {
issues.push('No Content Security Policy header');
}
// Check for X-Frame-Options
// Note: Headers are not accessible from JavaScript, would need server-side check
return {
valid: issues.length === 0,
issues
};
}
/**
* Escape HTML to prevent XSS
*/
escapeHtml(text) {
if (typeof text !== 'string') {
return text;
}
const map = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#039;'
};
return text.replace(/[&<>"']/g, m => map[m]);
}
/**
* Validate URL to prevent XSS
*/
validateUrl(url) {
try {
const parsed = new URL(url, window.location.origin);
// Block javascript: and data: URLs
if (parsed.protocol === 'javascript:' || parsed.protocol === 'data:') {
return false;
}
return true;
} catch {
return false;
}
}
/**
* Destroy security manager
*/
destroy() {
if (this.csrfManager) {
this.csrfManager.destroy();
this.csrfManager = null;
}
Logger.info('[SecurityManager] Destroyed');
}
}