maskOnly
Massimo Melina committed
May 27, 2023 at 23:37 UTC
2355754e93f65d177e67d579369dbb5eff83c7f2
2 files changed
+20
-13
config.md
+2
@@ -82,6 +82,8 @@ Valid keys in a node are:
82
mime: auto
83
```
84
Rules on top have priority over bottom rules. Inner rules have priority over parent's rules.
85
+ A mask can carry any node property (even property "masks") plus a special property `maskOnly` (optional) to restrict
86
+ the application of the mask to only files or folders, just by specifying exactly `files` or `folders`
87
88
Permissions set on an inner element will override inherited permissions. This means that you can restrict access to folder1,
89
and yet decide to give free access to folder1/subfolder2.
src/vfs.ts
+18
-13
@@ -2,7 +2,17 @@
2
3
import fs from 'fs/promises'
4
import { basename, dirname, join, resolve } from 'path'
5
-import { dirStream, dirTraversal, enforceFinal, getOrSet, isDirectory, typedKeys, makeMatcher, setHidden } from './misc'
5
+import {
6
+ dirStream,
7
+ dirTraversal,
8
+ enforceFinal,
9
+ getOrSet,
10
+ isDirectory,
11
+ typedKeys,
12
+ makeMatcher,
13
+ setHidden,
14
+ onlyTruthy
15
+} from './misc'
16
import Koa from 'koa'
17
import _ from 'lodash'
18
import { defineConfig, setConfig } from './config'
@@ -28,7 +38,7 @@ export interface VfsPerm {
38
can_delete: Who
39
}
40
31
-type Masks = Record<string, VfsNode>
41
+type Masks = Record<string, VfsNode & { maskOnly?: 'files' | 'folders' }>
42
43
export interface VfsNode extends Partial<VfsPerm> {
44
name?: string
@@ -296,18 +306,13 @@ export function masksCouldGivePermission(masks: Masks | undefined, perm: keyof V
306
}
307
308
export function parentMaskApplier(parent: VfsNode) {
299
- const matchers = Object.entries(parent.masks || {}).map(([k, v]) => {
309
+ const matchers = onlyTruthy(Object.entries(parent.masks || {}).map(([k, { maskOnly, ...mods }]) => {
310
k = k.startsWith('**/') ? k.slice(3) : !k.includes('/') ? k : ''
301
- if (!k) return
302
- const m = makeMatcher(k)
303
- return [m, v] as [typeof m, typeof v]
304
- })
305
- return (item: VfsNode, virtualBasename?: string) => {
306
- if (virtualBasename === undefined)
307
- virtualBasename = getNodeName(item)
308
- for (const entry of matchers) {
309
- if (!entry) continue
310
- const [matcher, mods] = entry
311
+ return k && { mods, maskOnly, matcher: makeMatcher(k) }
312
+ }))
313
+ return (item: VfsNode, virtualBasename=getNodeName(item)) => {
314
+ for (const { matcher, mods, maskOnly } of matchers) {
315
+ if (maskOnly === 'folders' && !item.isFolder || maskOnly === 'files' && item.isFolder) continue
316
if (!matcher(virtualBasename)) continue
317
if (item.masks)
318
item.masks = _.merge(_.cloneDeep(mods.masks), item.masks) // item.masks must take precedence