better code: centralize admin_net check

Massimo Melina committed Jun 21, 2025 at 14:41 UTC a6385bbea021bfd06a9a830367b5e14e1944150e
2 files changed +8 -9
src/adminApis.ts
+6 -6
@@ -177,8 +177,6 @@ export const adminApis = {
177
178 for (const [k, was] of typedEntries(adminApis))
179 (adminApis[k] as any) = ((params, ctx) => {
180 - if (!allowAdmin(ctx))
181 - return new ApiError(HTTP_FORBIDDEN)
180 if (ctxAdminAccess(ctx))
181 return was(params, ctx)
182 const props = { possible: anyAccountCanLoginAdmin() }
@@ -193,8 +191,10 @@ export const favicon = defineConfig('favicon', '')
191 export const title = defineConfig('title', "File server")
192
193 export function ctxAdminAccess(ctx: Koa.Context) {
196 - return !ctx.ips.length // we consider localhost_admin only if no proxy is being used
197 - && localhostAdmin.get() && isLocalHost(ctx)
194 + if (preventAdminAccess(ctx))
195 + return false
196 + // for extra security, skip localhost_admin via proxy, even tho this prevents using it with local proxies, which is legit in principle
197 + return !ctx.ips.length && localhostAdmin.get() && isLocalHost(ctx)
198 || ctx.state.account && accountCanLoginAdmin(ctx.state.account)
199 }
200
@@ -213,6 +213,6 @@ export function anyAccountCanLoginAdmin() {
213 return Boolean(_.find(accounts.get(), accountCanLoginAdmin))
214 }
215
216 -export function allowAdmin(ctx: Koa.Context) {
217 - return isLocalHost(ctx) || adminNet.compiled()(ctx.ip)
216 +export function preventAdminAccess(ctx: Koa.Context) {
217 + return !isLocalHost(ctx) && !adminNet.compiled()(ctx.ip)
218 }
\ No newline at end of file
src/serveGuiAndSharedFiles.ts
+2 -3
@@ -13,7 +13,7 @@ import { Writable } from 'stream'
13 import { serveFile, serveFileNode } from './serveFile'
14 import { BUILD_TIMESTAMP, DEV, MIME_AUTO, VERSION } from './const'
15 import { zipStreamFromFolder } from './zip'
16 -import { allowAdmin, favicon } from './adminApis'
16 +import { preventAdminAccess, favicon } from './adminApis'
17 import { serveGuiFiles } from './serveGuiFiles'
18 import mount from 'koa-mount'
19 import { baseUrl } from './listen'
@@ -42,8 +42,7 @@ export const serveGuiAndSharedFiles: Koa.Middleware = async (ctx, next) => {
42 if (path.length === ADMIN_URI.length - 1 && ADMIN_URI.startsWith(path))
43 return ctx.redirect(ctx.state.revProxyPath + ADMIN_URI)
44 if (path.startsWith(ADMIN_URI))
45 - return allowAdmin(ctx) ? serveAdminPrefixed(ctx,next)
46 - : sendErrorPage(ctx, HTTP_FORBIDDEN)
45 + return preventAdminAccess(ctx) ? sendErrorPage(ctx, HTTP_FORBIDDEN) : serveAdminPrefixed(ctx, next)
46 if (path.startsWith(ICONS_URI)) {
47 const a = path.substring(ICONS_URI.length).split('/')
48 const iconName = a.at(-1)