fix: folders 'read' permission in file_list was not considering inner elements

Massimo Melina committed Apr 7, 2023 at 13:09 UTC cd2deb972a0d5875bf0d145e71d96a3249c4001b
2 files changed +20 -20
src/api.file_list.ts
+15 -8
@@ -3,11 +3,13 @@
3 import {
4 getNodeName,
5 hasPermission,
6 + masksCouldGivePermission,
7 nodeIsDirectory,
8 statusCodeForMissingPerm,
9 urlToNode,
9 - VfsNode, VfsPerm,
10 - walkNode, WHO_NO_ONE
10 + VfsNode,
11 + walkNode,
12 + WHO_NO_ONE
13 } from './vfs'
14 import { ApiError, ApiHandler, SendListReadable } from './apiMiddleware'
15 import { stat } from 'fs/promises'
@@ -106,22 +108,27 @@ async function nodeToDirEntry(ctx: Koa.Context, node: VfsNode): Promise<DirEntry
108 const st = await stat(source)
109 const folder = st.isDirectory()
110 const { ctime, mtime } = st
111 + const pl = node.can_list === WHO_NO_ONE ? 'l'
112 + : !hasPermission(node, 'can_list', ctx) ? 'L'
113 + : ''
114 + // no download here, but maybe inside?
115 + const pr = node.can_read === WHO_NO_ONE && !(folder && filesInsideCould()) ? 'r'
116 + : !hasPermission(node, 'can_read', ctx) ? 'R'
117 + : ''
118 return {
119 n: name + (folder ? '/' : ''),
120 c: ctime,
121 m: Math.abs(+mtime-+ctime) < 1000 ? undefined : mtime,
122 s: folder ? undefined : st.size,
114 - p: (['can_read', 'can_list'] as (keyof VfsPerm)[]).map(perm2letter).join('')
115 - || undefined
123 + p: (pr + pl) || undefined
124 }
125 }
126 catch {
127 return null
128 }
129
122 - function perm2letter(k: keyof VfsPerm) {
123 - return node[k] === WHO_NO_ONE ? k[4]!
124 - : hasPermission(node, k, ctx) ? ''
125 - : k[4]!.toUpperCase()
130 + function filesInsideCould(n: VfsNode=node): boolean | undefined {
131 + return masksCouldGivePermission(n.masks, 'can_read')
132 + || n.children?.some(c => c.can_read || filesInsideCould(c)) // we count on the boolean-compliant nature of the permission type here
133 }
134 }
src/vfs.ts
+5 -12
@@ -228,20 +228,13 @@ export async function* walkNode(parent:VfsNode, ctx?: Koa.Context, depth:number=
228 item.isTemp = true
229 return item
230 }
231 +}
232
232 - function masksCouldGivePermission(masks: Masks | undefined) {
233 - if (!masks) return false
234 - for (const [,props] of Object.entries(masks)) {
235 - const v = props[requiredPerm!]
236 - if (v && (!ctx || matchWho(v, ctx))) // without ctx we can't say, so it could
237 - return true
238 - if (masksCouldGivePermission(props.masks))
239 - return true
240 - }
241 - return false
242 - }
243 -
233 +export function masksCouldGivePermission(masks: Masks | undefined, perm: keyof VfsPerm): boolean {
234 + return masks !== undefined && Object.values(masks).some(props =>
235 + props[perm] || masksCouldGivePermission(props.masks, perm))
236 }
237 +
238 function applyMasks(item: VfsNode, parent: VfsNode, virtualBasename: string) {
239 const { masks } = parent
240 if (!masks) return