Merge pull request #744 from mauriceboe/fix/health-endpoint-force-https-redirect

fix: skip FORCE_HTTPS redirect for /api/health endpoint
This commit is contained in:
Julien G.
2026-04-19 14:31:28 +02:00
committed by GitHub
3 changed files with 22 additions and 5 deletions
+4 -3
View File
@@ -1,15 +1,16 @@
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
const isTestEnv = typeof navigator !== 'undefined' && /jsdom/i.test(navigator.userAgent ?? '')
// Zählt beim Mount von 0 auf target hoch. Feste Dauer mit ease-out-quint. // Zählt beim Mount von 0 auf target hoch. Feste Dauer mit ease-out-quint.
export function useCountUp(target: number, duration = 800): number { export function useCountUp(target: number, duration = 800): number {
const [value, setValue] = useState(0) const [value, setValue] = useState(() => isTestEnv || target <= 0 ? target : 0)
const startRef = useRef<number | null>(null) const startRef = useRef<number | null>(null)
const frameRef = useRef<number | null>(null) const frameRef = useRef<number | null>(null)
useEffect(() => { useEffect(() => {
const reduced = window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches ?? false const reduced = window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches ?? false
const isJsdom = typeof navigator !== 'undefined' && /jsdom/i.test(navigator.userAgent ?? '') if (reduced || isTestEnv || target <= 0) { setValue(target); return }
if (reduced || isJsdom || target <= 0) { setValue(target); return }
startRef.current = null startRef.current = null
const step = (now: number) => { const step = (now: number) => {
+1
View File
@@ -112,6 +112,7 @@ export function createApp(): express.Application {
if (shouldForceHttps) { if (shouldForceHttps) {
app.use((req: Request, res: Response, next: NextFunction) => { app.use((req: Request, res: Response, next: NextFunction) => {
if (req.path === '/api/health') return next();
if (req.secure || req.headers['x-forwarded-proto'] === 'https') return next(); if (req.secure || req.headers['x-forwarded-proto'] === 'https') return next();
res.redirect(301, 'https://' + req.headers.host + req.url); res.redirect(301, 'https://' + req.headers.host + req.url);
}); });
+17 -2
View File
@@ -94,8 +94,22 @@ describe('Photo endpoint auth', () => {
}); });
describe('Force HTTPS redirect', () => { describe('Force HTTPS redirect', () => {
it('MISC-004 — FORCE_HTTPS redirect sends 301 for HTTP requests', async () => { it('MISC-004 — FORCE_HTTPS redirect sends 301 for HTTP requests on non-health paths', async () => {
// createApp() reads FORCE_HTTPS at call time, so we need a fresh app instance // createApp() reads FORCE_HTTPS at call time, so we need a fresh app instance
process.env.FORCE_HTTPS = 'true';
let httpsApp: Express;
try {
httpsApp = createApp();
} finally {
delete process.env.FORCE_HTTPS;
}
const res = await request(httpsApp)
.get('/api/addons')
.set('X-Forwarded-Proto', 'http');
expect(res.status).toBe(301);
});
it('MISC-008 — FORCE_HTTPS does not redirect /api/health (probes must reach it over HTTP)', async () => {
process.env.FORCE_HTTPS = 'true'; process.env.FORCE_HTTPS = 'true';
let httpsApp: Express; let httpsApp: Express;
try { try {
@@ -106,7 +120,8 @@ describe('Force HTTPS redirect', () => {
const res = await request(httpsApp) const res = await request(httpsApp)
.get('/api/health') .get('/api/health')
.set('X-Forwarded-Proto', 'http'); .set('X-Forwarded-Proto', 'http');
expect(res.status).toBe(301); expect(res.status).toBe(200);
expect(res.body.status).toBe('ok');
}); });
it('MISC-004 — no redirect when FORCE_HTTPS is not set', async () => { it('MISC-004 — no redirect when FORCE_HTTPS is not set', async () => {