diff --git a/package.json b/package.json index 2ff4bf9e..9d5f6881 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "media-streamer", - "version": "0.6.0", + "version": "0.6.1", "private": true, "type": "module", "scripts": { diff --git a/src/app/i/[code]/route.test.ts b/src/app/i/[code]/route.test.ts index 7bd20803..683b3b62 100644 --- a/src/app/i/[code]/route.test.ts +++ b/src/app/i/[code]/route.test.ts @@ -22,6 +22,14 @@ describe('/i/', () => { ); }); + it('answers with the public host, not the container address behind nginx', async () => { + const res = await GET( + new NextRequest('http://localhost:3000/i/ABCDEFGHJK', { headers: { host: 'bittorrented.com' } }), + { params: Promise.resolve({ code: 'ABCDEFGHJK' }) } + ); + expect(res.headers.get('location')).toBe('https://bittorrented.com/signup?invite=ABCDE-FGHJK'); + }); + it('sends a malformed code to the invite-only screen', async () => { expect((await go('/i/nope')).location).toBe('https://bittorrented.com/invite-only'); }); diff --git a/src/app/i/[code]/route.ts b/src/app/i/[code]/route.ts index d42ec385..6494c80a 100644 --- a/src/app/i/[code]/route.ts +++ b/src/app/i/[code]/route.ts @@ -12,10 +12,17 @@ import { formatInviteCode, isInviteCodeShape, normalizeInviteCode } from '@/lib/ export const dynamic = 'force-dynamic'; +/** The public origin: behind nginx, request.url is the container's localhost:3000. */ +function origin(request: NextRequest): string { + const host = request.headers.get('x-forwarded-host') ?? request.headers.get('host') ?? request.nextUrl.host; + const proto = host.startsWith('localhost') || host.startsWith('127.') ? 'http' : 'https'; + return `${proto}://${host}`; +} + export async function GET(request: NextRequest, { params }: { params: Promise<{ code: string }> }): Promise { const { code: raw } = await params; const code = normalizeInviteCode(decodeURIComponent(raw ?? '')); - const target = new URL(isInviteCodeShape(code) ? '/signup' : '/invite-only', request.url); + const target = new URL(isInviteCodeShape(code) ? '/signup' : '/invite-only', origin(request)); if (isInviteCodeShape(code)) target.searchParams.set('invite', formatInviteCode(code)); const ref = request.nextUrl.searchParams.get('ref'); if (ref && /^[a-zA-Z0-9_-]{1,64}$/.test(ref)) target.searchParams.set('ref', ref);