mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
The setup wizard and the admin sign-in set their session cookies by two different rules. The wizard matches Secure to the request - X-Forwarded- Proto from the proxy, else the URL scheme - because browsers drop Secure cookies on plain HTTP and an unconditional Secure broke setup over HTTP. The admin cookie kept `secure: NODE_ENV === 'production'`, so on the same HTTP deployment the wizard worked and admin sign-in failed silently: the cookie was set, the browser threw it away, every call came back 401. Both now share one helper, lib/security/request-protocol.ts, and the admin route passes its request in. Behind a TLS proxy that forwards the proto nothing changes: the cookie is Secure as before. Callers that pass no request keep the production default.
23 lines
1.1 KiB
TypeScript
23 lines
1.1 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { isHttpsRequest } from '@/lib/security/request-protocol';
|
|
|
|
const req = (url: string, headers: Record<string, string> = {}) => new Request(url, { headers });
|
|
|
|
describe('isHttpsRequest', () => {
|
|
it('trusts the proxy header over the scheme the app itself sees', () => {
|
|
// The app always sees plain HTTP behind a TLS-terminating proxy.
|
|
expect(isHttpsRequest(req('http://webmail.internal:3000/api/admin/auth', { 'x-forwarded-proto': 'https' }))).toBe(true);
|
|
expect(isHttpsRequest(req('https://webmail.internal/api/admin/auth', { 'x-forwarded-proto': 'http' }))).toBe(false);
|
|
});
|
|
|
|
it('reads the first hop of a comma-separated forwarded list, case-insensitively', () => {
|
|
expect(isHttpsRequest(req('http://x/', { 'x-forwarded-proto': 'HTTPS, http' }))).toBe(true);
|
|
expect(isHttpsRequest(req('http://x/', { 'x-forwarded-proto': ' http ,https' }))).toBe(false);
|
|
});
|
|
|
|
it('falls back to the request URL without a proxy', () => {
|
|
expect(isHttpsRequest(req('https://localhost:3000/'))).toBe(true);
|
|
expect(isHttpsRequest(req('http://localhost:3000/'))).toBe(false);
|
|
});
|
|
});
|