replaced maskOnly with new syntax to enable user to configure same mask separately for files and folders
Massimo Melina committed
Dec 29, 2024 at 11:37 UTC
91b84583b56b418cb1045ce88a67a6960314b067
3 files changed
+27
-13
config.md
+3
-2
@@ -172,8 +172,9 @@ Valid keys in a node are:
172
mime: auto
173
```
174
Rules on top have priority over bottom rules. Inner rules have priority over parent's rules.
175
- A mask can carry any node property (even property "masks") plus a special property `maskOnly` (optional) to restrict
176
- the application of the mask to only files or folders, just by specifying exactly `files` or `folders`
175
+ A mask can carry any node property (even property "masks" itself).
176
+ If the mask ends with `|files|`, then it will match only files and not folders.
177
+ You can get the opposite effect with suffix `|folders|`.
178
179
Permissions set on an inner element will override inherited permissions. This means that you can restrict access to folder1,
180
and yet decide to give free access to folder1/subfolder2.
src/vfs.ts
+20
-5
@@ -18,7 +18,7 @@ import fswin from 'fswin'
18
19
const showHiddenFiles = defineConfig('show_hidden_files', false)
20
21
-type Masks = Record<string, VfsNode & { maskOnly?: 'files' | 'folders' }>
21
+type Masks = Record<string, VfsNode>
22
23
export interface VfsNodeStored extends VfsPerms {
24
name?: string
@@ -168,6 +168,14 @@ export async function getNodeByName(name: string, parent: VfsNode) {
168
export let vfs: VfsNode = {}
169
defineConfig<VfsNode>('vfs', {}).sub(data =>
170
vfs = (function recur(node) {
171
+ const {masks} = node
172
+ _.each(masks, (v: any, mask) => { // legacy pre-0.56: convert from property to key suffix
173
+ if (v.maskOnly) {
174
+ masks![`${mask}|${v.maskOnly}|`] = v = _.omit(v, 'maskOnly')
175
+ delete masks![mask]
176
+ }
177
+ recur(v)
178
+ })
179
if (node.children)
180
for (const c of node.children)
181
recur(c)
@@ -346,11 +354,18 @@ export function masksCouldGivePermission(masks: Masks | undefined, perm: keyof V
354
}
355
356
export function parentMaskApplier(parent: VfsNode) {
349
- const matchers = onlyTruthy(_.map(parent.masks, (v, k) => {
357
+ const matchers = onlyTruthy(_.map(parent.masks, (mods, k) => {
358
+ if (!mods) return
359
+ const mustBeFolder = (() => { // undefined if no restriction is requested
360
+ if (k.at(-1) !== '|') return // parse special flag syntax as suffix |FLAG| inside the key. This allows specifying different flags with the same mask using separate keys. To avoid syntax conflicts with the rest of the file-mask, we look for an ending pipe, as it has no practical use. Ending-pipe was preferred over starting-pipe to leave the rest of the logic (inheritMasks) untouched.
361
+ const i = k.lastIndexOf('|', k.length - 2)
362
+ if (i < 0) return
363
+ const type = k.slice(i + 1, -1)
364
+ k = k.slice(0, i) // remove
365
+ return type === 'folders'
366
+ })()
367
k = k.startsWith('**/') ? k.slice(3) : !k.includes('/') ? k : '' // ** globstar matches also zero subfolders, so this mask must be applied here too
351
- const { maskOnly, ...mods } = v || {}
352
- // k is stored into the object for debugging purposes
353
- return k && { k, mods, matcher: makeMatcher(k), mustBeFolder: maskOnly && (maskOnly === 'folders') }
368
+ return k && { mods, matcher: makeMatcher(k), mustBeFolder }
369
}))
370
return async (item: VfsNode, virtualBasename=getNodeName(item)) => {
371
let isFolder: boolean | undefined = undefined
tests/config.yaml
+4
-6
@@ -109,17 +109,15 @@ vfs:
109
- name: hi
110
source: tests
111
masks:
112
- "**/*":
113
- maskOnly: files
114
- can_list: false
115
- can_read: false
112
"*/page":
113
can_list: false
114
+ "**/*|files|":
115
+ can_list: false
116
+ can_read: false
117
- name: cantSeeThisButChildrenMasks
118
can_see: false
119
masks:
121
- "*":
122
- maskOnly: folders
120
+ "*|folders|":
121
can_see: true
122
children:
123
- name: hi