From 14fd56ccd7c9bba8d8b5db1079a9fe4f621c4e22 Mon Sep 17 00:00:00 2001 From: Viren070 Date: Sat, 11 Oct 2025 21:14:41 +0100 Subject: [PATCH] refactor(proxy): rename auth env vars for clarity and consistency and make builtin proxy the default --- .env.sample | 7 +++--- packages/core/src/proxy/builtin.ts | 10 ++++----- packages/core/src/utils/constants.ts | 26 +++++++++++----------- packages/core/src/utils/env.ts | 6 ++--- packages/core/src/utils/startup.ts | 10 ++++----- packages/frontend/src/context/userData.tsx | 3 ++- packages/server/src/routes/api/proxy.ts | 13 +++++++++-- 7 files changed, 43 insertions(+), 32 deletions(-) diff --git a/.env.sample b/.env.sample index c867376e..6ace1ac5 100644 --- a/.env.sample +++ b/.env.sample @@ -61,13 +61,14 @@ DATABASE_URI=sqlite://./data/db.sqlite # # REDIS_URI=redis://your_redis_hostname:6379 -# --- Built-in Proxy --- +# --- Authorisation --- +# Set up credentials for your AIOStreams instance. Currently, this is only used for the built-in proxy. # AIOStreams provides a built-in proxy that can be used to proxy streams as well as proxying NZBs for the Newznab addon. # Define a comma separated list of username:password pairs here to configure the users. e.g. user1:pass1,user2:pass2 -# BUILTIN_PROXY_AUTH= +# AIOSTREAMS_AUTH= # Provide a comma separated list of usernames here (that are also defined above) to control which users are admins. Leaving this blank # or commented out means all users are admins. Admins can currently view proxy stats at /api/v1/proxy/stats?auth=: -# BUILTIN_PROXY_ADMINS= +# AIOSTREAMS_AUTH_ADMINS= # ============================================================================== # BUILT-IN ADDON CONFIGURATION diff --git a/packages/core/src/proxy/builtin.ts b/packages/core/src/proxy/builtin.ts index 0644361b..da2ec02c 100644 --- a/packages/core/src/proxy/builtin.ts +++ b/packages/core/src/proxy/builtin.ts @@ -26,8 +26,8 @@ export class BuiltinProxy extends BaseProxy { } if ( - Env.BUILTIN_PROXY_AUTH?.has(username) && - Env.BUILTIN_PROXY_AUTH?.get(username) !== password + Env.AIOSTREAMS_AUTH?.has(username) && + Env.AIOSTREAMS_AUTH?.get(username) !== password ) { throw new Error('Invalid credentials'); } @@ -36,8 +36,8 @@ export class BuiltinProxy extends BaseProxy { username, password, admin: - Env.BUILTIN_PROXY_ADMINS && Env.BUILTIN_PROXY_ADMINS.length > 0 - ? Env.BUILTIN_PROXY_ADMINS.includes(username) + Env.AIOSTREAMS_AUTH_ADMINS && Env.AIOSTREAMS_AUTH_ADMINS.length > 0 + ? Env.AIOSTREAMS_AUTH_ADMINS.includes(username) : true, }; } @@ -176,7 +176,7 @@ export class BuiltinProxyStats { } public async getAllUserStats(): Promise> { - const users = Env.BUILTIN_PROXY_AUTH?.keys(); + const users = Env.AIOSTREAMS_AUTH?.keys(); const userStats = new Map(); for (const user of users ?? []) { diff --git a/packages/core/src/utils/constants.ts b/packages/core/src/utils/constants.ts index 78dc4200..f7b72e5c 100644 --- a/packages/core/src/utils/constants.ts +++ b/packages/core/src/utils/constants.ts @@ -239,9 +239,9 @@ export const STREMTHRU_SERVICE = 'stremthru' as const; export const BUILTIN_SERVICE = 'builtin' as const; export const PROXY_SERVICES = [ - MEDIAFLOW_SERVICE, - STREMTHRU_SERVICE, BUILTIN_SERVICE, + STREMTHRU_SERVICE, + MEDIAFLOW_SERVICE, ] as const; export type ProxyServiceId = (typeof PROXY_SERVICES)[number]; @@ -254,13 +254,12 @@ export const PROXY_SERVICE_DETAILS: Record< credentialDescription: string; } > = { - [MEDIAFLOW_SERVICE]: { - id: MEDIAFLOW_SERVICE, - name: 'MediaFlow Proxy', - description: - '[MediaFlow Proxy](https://github.com/mhdzumair/mediaflow-proxy) is a high performance proxy server which supports HTTP, HLS, and more.', + [BUILTIN_SERVICE]: { + id: BUILTIN_SERVICE, + name: 'Builtin Proxy', + description: 'A proxy service that is built into the core of AIOStreams', credentialDescription: - 'The value of your MediaFlow Proxy instance `API_PASSWORD` environment variable.', + 'A valid username:password pair for this AIOStreams instance, defined in the `AIOSTREAMS_AUTH` environment variable.', }, [STREMTHRU_SERVICE]: { id: STREMTHRU_SERVICE, @@ -270,12 +269,13 @@ export const PROXY_SERVICE_DETAILS: Record< credentialDescription: 'A valid username:password pair for your StremThru instance, defined in the `STREMTHRU_PROXY_AUTH` environment variable.', }, - [BUILTIN_SERVICE]: { - id: BUILTIN_SERVICE, - name: 'Builtin Proxy', - description: 'A proxy service that is built into the core of AIOStreams', + [MEDIAFLOW_SERVICE]: { + id: MEDIAFLOW_SERVICE, + name: 'MediaFlow Proxy', + description: + '[MediaFlow Proxy](https://github.com/mhdzumair/mediaflow-proxy) is a high performance proxy server which supports HTTP, HLS, and more.', credentialDescription: - 'A valid username:password pair for this AIOStreams instance, defined in the `BUILTIN_PROXY_AUTH` environment variable.', + 'The value of your MediaFlow Proxy instance `API_PASSWORD` environment variable.', }, }; diff --git a/packages/core/src/utils/env.ts b/packages/core/src/utils/env.ts index 03c14c55..9a9bb7bd 100644 --- a/packages/core/src/utils/env.ts +++ b/packages/core/src/utils/env.ts @@ -1607,11 +1607,11 @@ export const Env = cleanEnv(process.env, { desc: 'Default AStream user agent', }), - BUILTIN_PROXY_AUTH: proxyAuth({ + AIOSTREAMS_AUTH: proxyAuth({ default: undefined, - desc: 'Builtin proxy auth', + desc: 'Authorisation credentials for this AIOStreams instance', }), - BUILTIN_PROXY_ADMINS: commaSeparated({ + AIOSTREAMS_AUTH_ADMINS: commaSeparated({ default: undefined, desc: 'Comma separated list of admin usernames. If not set, all users are admins.', }), diff --git a/packages/core/src/utils/startup.ts b/packages/core/src/utils/startup.ts index 213530f0..daf990fb 100644 --- a/packages/core/src/utils/startup.ts +++ b/packages/core/src/utils/startup.ts @@ -529,15 +529,15 @@ const logStartupInfo = () => { }); logSection('BUILT-IN PROXY', '🔧', () => { - if (Env.BUILTIN_PROXY_AUTH) { + if (Env.AIOSTREAMS_AUTH) { logKeyValue('Status:', '✅ Configured'); - const users = Array.from(Env.BUILTIN_PROXY_AUTH.keys()); + const users = Array.from(Env.AIOSTREAMS_AUTH.keys()); if (users.length === 0) { logKeyValue('Users:', '❌ None'); } else { logKeyValue('Users:', ''); for (const user of users) { - const password = Env.BUILTIN_PROXY_AUTH.get(user); + const password = Env.AIOSTREAMS_AUTH.get(user); const masked = password && password.length > 0 ? '*'.repeat(Math.max(4, Math.min(password.length, 12))) @@ -547,8 +547,8 @@ const logStartupInfo = () => { } logKeyValue( 'Admins:', - Env.BUILTIN_PROXY_ADMINS - ? `${Env.BUILTIN_PROXY_ADMINS.join(', ')}` + Env.AIOSTREAMS_AUTH_ADMINS + ? `${Env.AIOSTREAMS_AUTH_ADMINS.join(', ')}` : '⚠️ All users' ); } else { diff --git a/packages/frontend/src/context/userData.tsx b/packages/frontend/src/context/userData.tsx index b460a4d0..51b80041 100644 --- a/packages/frontend/src/context/userData.tsx +++ b/packages/frontend/src/context/userData.tsx @@ -180,7 +180,8 @@ export function UserDataProvider({ children }: { children: React.ReactNode }) { newData.proxy = { ...newData.proxy, enabled: forced.proxy.enabled ?? defaults.proxy?.enabled ?? undefined, - id: (forced.proxy.id ?? defaults.proxy?.id ?? 'mediaflow') as + id: (forced.proxy.id ?? defaults.proxy?.id ?? 'builtin') as + | 'builtin' | 'mediaflow' | 'stremthru' | undefined, diff --git a/packages/server/src/routes/api/proxy.ts b/packages/server/src/routes/api/proxy.ts index d3debedc..86f21065 100644 --- a/packages/server/src/routes/api/proxy.ts +++ b/packages/server/src/routes/api/proxy.ts @@ -184,8 +184,8 @@ router.all( auth = ProxyAuthSchema.parse(JSON.parse(rawAuth)); if ( - !Env.BUILTIN_PROXY_AUTH?.has(auth.username) || - Env.BUILTIN_PROXY_AUTH?.get(auth.username) !== auth.password + !Env.AIOSTREAMS_AUTH?.has(auth.username) || + Env.AIOSTREAMS_AUTH?.get(auth.username) !== auth.password ) { logger.warn(`[${requestId}] Authentication failed`, { username: auth.username, @@ -353,6 +353,15 @@ router.all( contentLength: upstreamResponse?.headers['content-length'], upstreamStatusCode: upstreamResponse?.statusCode, }); + if (!res.headersSent) { + next( + new APIError( + constants.ErrorCode.INTERNAL_SERVER_ERROR, + undefined, + 'Proxy request failed' + ) + ); + } } else { logger.debug(`[${requestId}] Client disconnected (premature close)`, { durationMs: totalDuration,