fix: accessing a protected web-page caused an endless loop, and accessing a protected file didn't use login dialog but http basic authentication

Massimo Melina committed Jun 7, 2024 at 09:45 UTC 6361b3a2cf40ba4d18d221234b5dbd3b7fb5af76
3 files changed +15 -13
src/api.get_file_list.ts
+3 -2
@@ -25,8 +25,9 @@ export const get_file_list: ApiHandler = async ({ uri='/', offset, limit, search
25 admin &&= ctxAdminAccess(ctx) // validate 'admin' flag
26 if (dirTraversal(search))
27 return fail(HTTP_FOOL)
28 - if (await hasDefaultFile(node) || !await nodeIsDirectory(node))
29 - return fail(HTTP_METHOD_NOT_ALLOWED)
28 + if (await hasDefaultFile(node) || !await nodeIsDirectory(node)) // in case of files without permission, we are provided with the frontend, and the location is the file itself
29 + // so we first check if you have a permission problem, to tell frontend to show login, otherwise we fallback to method_not_allowed, as it's proper for files.
30 + return fail(statusCodeForMissingPerm(node, 'can_read', ctx) ? undefined : HTTP_METHOD_NOT_ALLOWED)
31 if (!admin && statusCodeForMissingPerm(node, 'can_list', ctx))
32 return fail()
33 offset = Number(offset)
src/basicWeb.ts
+9 -8
@@ -28,7 +28,7 @@ export function basicWeb(ctx: Koa.Context, node: VfsNode) {
28 return true
29 }
30 const forced = get === 'basic'
31 - if (forced || detectBasicAgent()) {
31 + if (forced || detectBasicAgent(ctx)) {
32 ctx.type = 'html'
33 const force = forced ? '?get=basic' : ''
34 const walker = walkNode(node, { ctx, depth: 0 })
@@ -53,11 +53,12 @@ export function basicWeb(ctx: Koa.Context, node: VfsNode) {
53 return `<a href='${href}'>${label}</a>`
54 }
55
56 - function detectBasicAgent() {
57 - const ua = ctx.get('user-agent')
58 - const v = autoBasic.get()
59 - return v && (/Mozilla\/4|WebKit\/([234]\d\d|5[012]\d|53[0123456])[. ]|Trident|Lynx|Firefox\/(\d|[123]\d)\./.test(ua)
60 - || _.isString(v) && ua.includes(v))
61 - }
56 +}
57 +
58 +export function detectBasicAgent(ctx: Koa.Context) {
59 + const ua = ctx.get('user-agent')
60 + const v = autoBasic.get()
61 + return v && (/Mozilla\/4|WebKit\/([234]\d\d|5[012]\d|53[0123456])[. ]|Trident|Lynx|curl|Firefox\/(\d|[123]\d)\./.test(ua)
62 + || _.isString(v) && ua.includes(v))
63 +}
64
63 -}
\ No newline at end of file
src/serveGuiAndSharedFiles.ts
+3 -3
@@ -16,7 +16,7 @@ import { serveGuiFiles } from './serveGuiFiles'
16 import mount from 'koa-mount'
17 import { baseUrl } from './listen'
18 import { asyncGeneratorToReadable, deleteNode, filterMapGenerator, pathEncode } from './misc'
19 -import { basicWeb } from './basicWeb'
19 +import { basicWeb, detectBasicAgent } from './basicWeb'
20
21 const serveFrontendFiles = serveGuiFiles(process.env.FRONTEND_PROXY, FRONTEND_URI)
22 const serveFrontendPrefixed = mount(FRONTEND_URI.slice(0,-1), serveFrontendFiles)
@@ -104,8 +104,8 @@ export const serveGuiAndSharedFiles: Koa.Middleware = async (ctx, next) => {
104 : !node.source ? sendErrorPage(ctx, HTTP_METHOD_NOT_ALLOWED) // !dir && !source is not supported at this moment
105 : !statusCodeForMissingPerm(node, 'can_read', ctx) ? serveFileNode(ctx, node) // all good
106 : ctx.status !== HTTP_UNAUTHORIZED ? null // all errors don't need extra handling, except unauthorized
107 - : path.endsWith('/') ? (ctx.state.serveApp = true) && serveFrontendFiles(ctx, next) // since this is no dir, final / means we are dealing with default file, for which we still provide fancy login
108 - : (ctx.set('WWW-Authenticate', 'Basic'), sendErrorPage(ctx)) // this is necessary to support standard urls with credentials
107 + : detectBasicAgent(ctx) ? (ctx.set('WWW-Authenticate', 'Basic'), sendErrorPage(ctx))
108 + : (ctx.state.serveApp = true) && serveFrontendFiles(ctx, next) // this is necessary to support standard urls with credentials, as chrome125 will send provided credentials only after attempt a GET without them, and after this error
109 if (!path.endsWith('/'))
110 return ctx.redirect(ctx.state.revProxyPath + ctx.originalUrl.replace(/(\?|$)/, '/$1')) // keep query-string, if any
111 if (statusCodeForMissingPerm(node, 'can_list', ctx)) {