diff --git a/docker/Dockerfile b/docker/Dockerfile index 6f2b9afe..4133ee08 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -9,6 +9,7 @@ COPY package*.json ./ ENV npm_config_target_platform=linux ENV npm_config_target_arch=x64 ENV npm_config_target_libc=glibc +ENV NODE_OPTIONS="--max-old-space-size=4096" RUN npm ci --force --ignore-scripts && \ npm cache clean --force @@ -19,7 +20,11 @@ WORKDIR /app COPY . . +ENV NODE_OPTIONS="--max-old-space-size=4096" +ENV NODE_ENV=production + RUN npm run build +RUN npm run build:types # Stage 3: Build backend TypeScript FROM deps AS backend-builder @@ -30,6 +35,8 @@ COPY . . ENV npm_config_target_platform=linux ENV npm_config_target_arch=x64 ENV npm_config_target_libc=glibc +ENV NODE_OPTIONS="--max-old-space-size=4096" +ENV NODE_ENV=production RUN npm rebuild better-sqlite3 --force @@ -46,6 +53,7 @@ COPY package*.json ./ ENV npm_config_target_platform=linux ENV npm_config_target_arch=x64 ENV npm_config_target_libc=glibc +ENV NODE_OPTIONS="--max-old-space-size=4096" RUN npm ci --only=production --ignore-scripts --force && \ npm rebuild better-sqlite3 bcryptjs --force && \ diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index dcf9b0f2..51c3f92f 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -25,15 +25,33 @@ chown -R node:node /app/data chmod 755 /app/data if [ "$ENABLE_SSL" = "true" ]; then - echo "Generating SSL certificates..." + echo "Checking SSL certificate configuration..." mkdir -p /app/data/ssl chown -R node:node /app/data/ssl chmod 755 /app/data/ssl DOMAIN=${SSL_DOMAIN:-localhost} - echo "Generating certificate for domain: $DOMAIN" + + # Check if certificates already exist and are valid + if [ -f "/app/data/ssl/termix.crt" ] && [ -f "/app/data/ssl/termix.key" ]; then + echo "SSL certificates found, checking validity..." + + # Check if certificate is still valid (not expired within 30 days) + if openssl x509 -in /app/data/ssl/termix.crt -checkend 2592000 -noout >/dev/null 2>&1; then + echo "SSL certificates are valid and will be reused for domain: $DOMAIN" + else + echo "SSL certificate is expired or expiring soon, regenerating..." + rm -f /app/data/ssl/termix.crt /app/data/ssl/termix.key + fi + else + echo "SSL certificates not found, will generate new ones..." + fi + + # Generate certificates only if they don't exist or are invalid + if [ ! -f "/app/data/ssl/termix.crt" ] || [ ! -f "/app/data/ssl/termix.key" ]; then + echo "Generating SSL certificates for domain: $DOMAIN" - cat > /app/data/ssl/openssl.conf << EOF + cat > /app/data/ssl/openssl.conf << EOF [req] default_bits = 2048 prompt = no @@ -62,17 +80,18 @@ IP.1 = 127.0.0.1 IP.2 = ::1 EOF - openssl genrsa -out /app/data/ssl/termix.key 2048 + openssl genrsa -out /app/data/ssl/termix.key 2048 - openssl req -new -x509 -key /app/data/ssl/termix.key -out /app/data/ssl/termix.crt -days 365 -config /app/data/ssl/openssl.conf -extensions v3_req + openssl req -new -x509 -key /app/data/ssl/termix.key -out /app/data/ssl/termix.crt -days 365 -config /app/data/ssl/openssl.conf -extensions v3_req - chmod 600 /app/data/ssl/termix.key - chmod 644 /app/data/ssl/termix.crt - chown node:node /app/data/ssl/termix.key /app/data/ssl/termix.crt + chmod 600 /app/data/ssl/termix.key + chmod 644 /app/data/ssl/termix.crt + chown node:node /app/data/ssl/termix.key /app/data/ssl/termix.crt - rm -f /app/data/ssl/openssl.conf - - echo "SSL certificates generated successfully for domain: $DOMAIN" + rm -f /app/data/ssl/openssl.conf + + echo "SSL certificates generated successfully for domain: $DOMAIN" + fi fi echo "Starting nginx..." diff --git a/package.json b/package.json index 393cfc3f..291099a4 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,9 @@ "clean": "npx prettier . --write", "dev": "vite", "dev:https": "cross-env VITE_HTTPS=true vite", - "build": "vite build && tsc -p tsconfig.node.json", + "build": "vite build", + "build:types": "tsc -p tsconfig.node.json", + "build:full": "npm run build && npm run build:types", "build:backend": "tsc -p tsconfig.node.json", "dev:backend": "tsc -p tsconfig.node.json && node ./dist/backend/backend/starter.js", "start": "npm run build:backend && node ./dist/backend/backend/starter.js", diff --git a/src/backend/utils/auto-ssl-setup.ts b/src/backend/utils/auto-ssl-setup.ts index 48df020e..d3bc55b5 100644 --- a/src/backend/utils/auto-ssl-setup.ts +++ b/src/backend/utils/auto-ssl-setup.ts @@ -30,12 +30,30 @@ export class AutoSSLSetup { try { if (await this.isSSLConfigured()) { await this.logCertificateInfo(); + await this.setupEnvironmentVariables(); return; } - await this.generateSSLCertificates(); - - await this.setupEnvironmentVariables(); + // In Docker, certificates might be generated by entrypoint script + // Check if they exist but weren't detected by isSSLConfigured + try { + await fs.access(this.CERT_FILE); + await fs.access(this.KEY_FILE); + + systemLogger.info("SSL certificates found from entrypoint script", { + operation: "ssl_cert_found_entrypoint", + cert_path: this.CERT_FILE, + key_path: this.KEY_FILE, + }); + + await this.logCertificateInfo(); + await this.setupEnvironmentVariables(); + return; + } catch { + // Certificates don't exist, generate them + await this.generateSSLCertificates(); + await this.setupEnvironmentVariables(); + } } catch (error) { systemLogger.error("Failed to initialize SSL configuration", error, { operation: "ssl_auto_init_failed", diff --git a/src/ui/Desktop/Homepage/HomepageAuth.tsx b/src/ui/Desktop/Homepage/HomepageAuth.tsx index f3e1cfb5..11e8ba60 100644 --- a/src/ui/Desktop/Homepage/HomepageAuth.tsx +++ b/src/ui/Desktop/Homepage/HomepageAuth.tsx @@ -222,9 +222,8 @@ export function HomepageAuth({ setTotpCode(""); setTotpTempToken(""); } catch (err: any) { - toast.error( - err?.response?.data?.error || err?.message || t("errors.unknownError"), - ); + const errorMessage = err?.response?.data?.error || err?.message || t("errors.unknownError"); + toast.error(errorMessage); setInternalLoggedIn(false); setLoggedIn(false); setIsAdmin(false); @@ -371,11 +370,8 @@ export function HomepageAuth({ setTotpTempToken(""); toast.success(t("messages.loginSuccess")); } catch (err: any) { - toast.error( - err?.response?.data?.error || - err?.message || - t("errors.invalidTotpCode"), - ); + const errorMessage = err?.response?.data?.error || err?.message || t("errors.invalidTotpCode"); + toast.error(errorMessage); } finally { setTotpLoading(false); } @@ -394,11 +390,8 @@ export function HomepageAuth({ window.location.replace(authUrl); } catch (err: any) { - toast.error( - err?.response?.data?.error || - err?.message || - t("errors.failedOidcLogin"), - ); + const errorMessage = err?.response?.data?.error || err?.message || t("errors.failedOidcLogin"); + toast.error(errorMessage); setOidcLoading(false); } } diff --git a/src/ui/Mobile/Homepage/HomepageAuth.tsx b/src/ui/Mobile/Homepage/HomepageAuth.tsx index 34200baf..9babecbe 100644 --- a/src/ui/Mobile/Homepage/HomepageAuth.tsx +++ b/src/ui/Mobile/Homepage/HomepageAuth.tsx @@ -204,9 +204,8 @@ export function HomepageAuth({ setTotpCode(""); setTotpTempToken(""); } catch (err: any) { - toast.error( - err?.response?.data?.error || err?.message || t("errors.unknownError"), - ); + const errorMessage = err?.response?.data?.error || err?.message || t("errors.unknownError"); + toast.error(errorMessage); setInternalLoggedIn(false); setLoggedIn(false); setIsAdmin(false); @@ -347,11 +346,8 @@ export function HomepageAuth({ setTotpTempToken(""); toast.success(t("messages.loginSuccess")); } catch (err: any) { - toast.error( - err?.response?.data?.error || - err?.message || - t("errors.invalidTotpCode"), - ); + const errorMessage = err?.response?.data?.error || err?.message || t("errors.invalidTotpCode"); + toast.error(errorMessage); } finally { setTotpLoading(false); } @@ -370,11 +366,8 @@ export function HomepageAuth({ window.location.replace(authUrl); } catch (err: any) { - toast.error( - err?.response?.data?.error || - err?.message || - t("errors.failedOidcLogin"), - ); + const errorMessage = err?.response?.data?.error || err?.message || t("errors.failedOidcLogin"); + toast.error(errorMessage); setOidcLoading(false); } } @@ -402,12 +395,12 @@ export function HomepageAuth({ setLoggedIn(true); setIsAdmin(!!meRes.is_admin); setUsername(meRes.username || null); - setUserId(meRes.id || null); + setUserId(meRes.userId || null); setDbError(null); onAuthSuccess({ isAdmin: !!meRes.is_admin, username: meRes.username || null, - userId: meRes.id || null, + userId: meRes.userId || null, }); setInternalLoggedIn(true); window.history.replaceState(