@samitouri / QOSami-HFS / commits / 8e2c6e7a

fix: faulty negative deep masks like "!**/*.png"

Massimo Melina committed Mar 27, 2025 at 12:47 UTC 8e2c6e7a4ed68bc15ed00d1dcc2c66e7924b5e1e
3 files changed +10 -2
src/vfs.ts
+3 -1
@@ -399,6 +399,7 @@ export function masksCouldGivePermission(masks: Masks | undefined, perm: keyof V
399 }
400
401 export function parentMaskApplier(parent: VfsNode) {
402 + // rules are met in the parent.masks object from nearest to farthest, but since we finally apply with _.defaults, the nearest has precedence in the final result
403 const matchers = onlyTruthy(_.map(parent.masks, (mods, k) => {
404 if (!mods) return
405 const mustBeFolder = (() => { // undefined if no restriction is requested
@@ -409,7 +410,8 @@ export function parentMaskApplier(parent: VfsNode) {
410 k = k.slice(0, i) // remove
411 return type === 'folders'
412 })()
412 - k = k.startsWith('**/') ? k.slice(3) : !k.includes('/') ? k : '' // ** globstar matches also zero subfolders, so this mask must be applied here too
413 + const m = /^(!?)\*\*\//.exec(k) // ** globstar matches also zero subfolders, so this mask must be applied here too
414 + k = m ? m[1] + k.slice(m[0].length) : !k.includes('/') ? k : ''
415 return k && { mods, matcher: makeMatcher(k), mustBeFolder }
416 }))
417 return async (item: VfsNode, virtualBasename=basename(getNodeName(item))) => { // we basename for depth>0
tests/config.yaml
+3
@@ -49,6 +49,9 @@ vfs:
49 can_list:
50 - disabled_account
51 - source: tests
52 + masks:
53 + "!**/*.png|files|":
54 + can_see: false
55 - name: renameChild
56 children:
57 - source: tests
tests/test.ts
+4 -1
@@ -111,6 +111,7 @@ describe('basics', () => {
111
112 it('protectFromAbove', req('/protectFromAbove/child/alfa.txt', 403))
113 it('protectFromAbove.list', reqList('/protectFromAbove/child/', { inList:['alfa.txt'] }))
114 + it('inheritNegativeMask', reqList('/tests/page', { outList: ['index.html'] }))
115
116 const zipSize = 13010
117 const zipOfs = 0x1359
@@ -327,7 +328,9 @@ function req(url: string, test:Tester, { baseUrl, throttle, ...requestOptions }:
328 const data = await stream2string(stream)
329 const obj = tryJson(data)
330 if (typeof test === 'object') {
330 - const { status, mime, re, inList, outList, length, permInList } = test
331 + let { status, mime, re, inList, outList, length, permInList } = test
332 + if (inList || outList)
333 + status ||= 200
334 const gotMime = res.headers?.['content-type']
335 const gotStatus = res.statusCode
336 const gotLength = res.headers?.['content-length']