From db820b30217a8a9c311d083969dcffd061b7d8db Mon Sep 17 00:00:00 2001 From: WardPearce Date: Sat, 14 Feb 2026 00:52:31 +1300 Subject: [PATCH] Proxying request is even more strict --- materialious/src/lib/shared/index.ts | 4 +- materialious/src/routes/(app)/+layout.svelte | 6 +++ .../src/routes/api/poToken/+server.ts | 7 ++- .../routes/api/proxy/[urlToProxy]/+server.ts | 47 ++++++++++++------- .../src/routes/api/user/login/+server.ts | 2 +- 5 files changed, 47 insertions(+), 19 deletions(-) diff --git a/materialious/src/lib/shared/index.ts b/materialious/src/lib/shared/index.ts index 99eb30d8..a2fc8c97 100644 --- a/materialious/src/lib/shared/index.ts +++ b/materialious/src/lib/shared/index.ts @@ -3,6 +3,7 @@ export type IsOwnBackend = { internalAuth: boolean; requireAuth: boolean; registrationAllowed: boolean; + allowAnyProxy: boolean; }; export function isOwnBackend(): IsOwnBackend | null { @@ -12,6 +13,7 @@ export function isOwnBackend(): IsOwnBackend | null { builtWithBackend: true, internalAuth: import.meta.env.VITE_INTERNAL_AUTH !== 'false', requireAuth: import.meta.env.VITE_REQUIRE_AUTH !== 'false', - registrationAllowed: import.meta.env.VITE_REGISTRATION_ALLOWED === 'true' + registrationAllowed: import.meta.env.VITE_REGISTRATION_ALLOWED === 'true', + allowAnyProxy: import.meta.env.VITE_ALLOW_ANY_PROXY === 'true' }; } diff --git a/materialious/src/routes/(app)/+layout.svelte b/materialious/src/routes/(app)/+layout.svelte index 01b24638..18c46daf 100644 --- a/materialious/src/routes/(app)/+layout.svelte +++ b/materialious/src/routes/(app)/+layout.svelte @@ -25,6 +25,7 @@ isAndroidTvStore, playerState, playertheatreModeIsActive, + rawSubscriptionKeyStore, syncPartyPeerStore, themeColorStore } from '$lib/store'; @@ -186,6 +187,11 @@ } function logout() { + if (isOwnBackend()?.internalAuth) { + rawSubscriptionKeyStore.set(undefined); + fetch('/api/user/logout'); + } + authStore.set(null); clearCaches(); goto(resolve('/', {})); diff --git a/materialious/src/routes/api/poToken/+server.ts b/materialious/src/routes/api/poToken/+server.ts index 427d1790..a1ae217f 100644 --- a/materialious/src/routes/api/poToken/+server.ts +++ b/materialious/src/routes/api/poToken/+server.ts @@ -3,6 +3,7 @@ import type { IGetChallengeResponse } from 'youtubei.js'; import BG, { buildURL, GOOG_API_KEY, USER_AGENT, type WebPoSignalOutput } from 'bgutils-js'; import { error } from '@sveltejs/kit'; import z from 'zod'; +import { isOwnBackend } from '$lib/shared/index.js'; const zPoTokenGenSchema = z.object({ requestKey: z.string(), @@ -10,7 +11,11 @@ const zPoTokenGenSchema = z.object({ challenge: z.record(z.any(), z.any()) }); -export async function POST({ request }) { +export async function POST({ request, locals }) { + if (isOwnBackend()?.requireAuth && !locals.userId) { + throw error(401); + } + const data = zPoTokenGenSchema.safeParse(await request.json()); if (!data.success) { diff --git a/materialious/src/routes/api/proxy/[urlToProxy]/+server.ts b/materialious/src/routes/api/proxy/[urlToProxy]/+server.ts index 68c198a1..96717028 100644 --- a/materialious/src/routes/api/proxy/[urlToProxy]/+server.ts +++ b/materialious/src/routes/api/proxy/[urlToProxy]/+server.ts @@ -1,6 +1,7 @@ import { isOwnBackend } from '$lib/shared'; import psl from 'psl'; import { env } from '$env/dynamic/private'; +import { error } from '@sveltejs/kit'; const allowedDomains: string[] = [ 'youtube.com', @@ -27,26 +28,40 @@ dynamicAllowDomains.forEach((domain) => { } }); -async function proxyRequest(request: Request, urlToProxy: string): Promise { +async function proxyRequest( + request: Request, + urlToProxy: string, + userId: string | undefined = undefined +): Promise { const backendRestrictions = isOwnBackend(); if (!backendRestrictions) { // Shouldn't be possible. - return new Response('How did you get here?', { status: 400 }); + throw error(400, 'How did you get here?'); } - if (backendRestrictions.requireAuth) { - return new Response('Auth required', { status: 401 }); + if (backendRestrictions.requireAuth && !userId) { + throw error(401, 'Auth required'); } let urlToProxyObj: URL; try { urlToProxyObj = new URL(decodeURIComponent(urlToProxy)); } catch { - return new Response('Invalid URL', { status: 400 }); + throw error(400, 'Invalid URL'); } if (!allowedDomains.includes(psl.parse(urlToProxyObj.host).domain)) { - return new Response('Invalid URL', { status: 400 }); + // allowAnyProxy allows a instance owner to bypass the whitelist. + // BUT is extremely strict. + // AND I still don't recommend this. + if ( + !backendRestrictions.allowAnyProxy || + !backendRestrictions.requireAuth || + backendRestrictions.registrationAllowed || + !userId + ) { + throw error(400, 'Invalid URL'); + } } if (urlToProxyObj.pathname.includes('v1/player')) { @@ -84,21 +99,21 @@ async function proxyRequest(request: Request, urlToProxy: string): Promise