allow masks to support | without having to surround with parenthesis

Massimo Melina committed Mar 23, 2023 at 21:17 UTC 25ef194ce462dd6fb19086d5052973b0ec387df6
6 files changed +17 -19
plugins/vhosting/plugin.js
+2 -2
@@ -18,7 +18,7 @@ exports.config = {
18 }
19
20 exports.init = api => {
21 - const { isMatch } = api.require('micromatch')
21 + const { matches } = api.require('./misc')
22 return {
23 middleware(ctx) {
24 let toModify = ctx
@@ -33,7 +33,7 @@ exports.init = api => {
33 const hosts = api.getConfig('hosts')
34 if (!hosts?.length) return
35 for (const row of hosts)
36 - if (isMatch(ctx.host, row.host)) {
36 + if (matches(ctx.host, row.host)) {
37 toModify.path = row.root + toModify.path
38 return
39 }
src/api.vfs.ts
+2 -3
@@ -5,12 +5,11 @@ import _ from 'lodash'
5 import { stat } from 'fs/promises'
6 import { ApiError, ApiHandlers } from './apiMiddleware'
7 import { dirname, join, resolve } from 'path'
8 -import { dirStream, isWindowsDrive, newObj } from './misc'
8 +import { dirStream, isWindowsDrive, matches, newObj } from './misc'
9 import {
10 IS_WINDOWS,
11 HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR, HTTP_CONFLICT, HTTP_NOT_ACCEPTABLE,
12 } from './const'
13 -import { isMatch } from 'micromatch'
13 import { getDrives } from './util-os'
14 import { Stats } from 'fs'
15
@@ -173,7 +172,7 @@ const apis: ApiHandlers = {
172 return
173 try {
174 if (!isDir)
176 - if (!files || fileMask && !isMatch(name, fileMask))
175 + if (!files || fileMask && !matches(name, fileMask))
176 continue
177 const stats = await stat(join(path, name))
178 yield {
src/misc.ts
+5 -5
@@ -172,15 +172,15 @@ export function isLocalHost(c: Connection | Koa.Context) {
172 return ip && (ip === '::1' || ip.endsWith('127.0.0.1'))
173 }
174
175 -export function matchesNet(ip: Koa.Context | string, mask: string, emptyReturns=false) {
176 - if (!mask)
177 - return emptyReturns
175 +export function matchesNet(ip: Koa.Context | string, mask: string, emptyMaskReturns=false) {
176 if (typeof ip !== 'string')
177 ip = ip.ip
180 - return matches(ip, mask)
178 + return matches(ip, mask, emptyMaskReturns)
179 }
180
183 -function matches(s: string, mask: string) {
181 +export function matches(s: string, mask: string, emptyMaskReturns=false) {
182 + if (!mask)
183 + return emptyMaskReturns
184 return isMatch(s, '(' + mask + ')') // adding () will allow us to use the pipe at root level
185 }
186
src/serveFile.ts
+4 -4
@@ -14,7 +14,7 @@ import {
14 import { getNodeName, MIME_AUTO, VfsNode } from './vfs'
15 import mimetypes from 'mime-types'
16 import { defineConfig } from './config'
17 -import { isMatch } from 'micromatch'
17 +import { matches } from './misc'
18 import _ from 'lodash'
19 import path from 'path'
20 import { promisify } from 'util'
@@ -25,12 +25,12 @@ export function serveFileNode(ctx: Koa.Context, node: VfsNode) {
25 const { source, mime } = node
26 const name = getNodeName(node)
27 const mimeString = typeof mime === 'string' ? mime
28 - : _.find(mime, (val,mask) => isMatch(name, mask))
28 + : _.find(mime, (val,mask) => matches(name, mask))
29 const allowed = allowedReferer.get()
30 if (allowed) {
31 const ref = /\/\/([^:/]+)/.exec(ctx.get('referer'))?.[1] // extract host from url
32 if (ref && ref !== host() // automatic accept if referer is basically the hosting domain
33 - && !isMatch(ref, allowed))
33 + && !matches(ref, allowed))
34 return ctx.status = HTTP_FORBIDDEN
35
36 function host() {
@@ -51,7 +51,7 @@ export async function serveFile(ctx: Koa.Context, source:string, mime?:string, c
51 const fn = path.basename(source)
52 if ('dl' in ctx.params) // please, download
53 ctx.attachment(fn)
54 - mime = mime ?? _.find(mimeCfg.get(), (v,k) => k>'' && isMatch(fn, k)) // isMatch throws on an empty string
54 + mime = mime ?? _.find(mimeCfg.get(), (v,k) => matches(fn, k, ))
55 if (mime === MIME_AUTO)
56 mime = mimetypes.lookup(source) || ''
57 if (mime)
src/vfs.ts
+3 -4
@@ -2,8 +2,7 @@
2
3 import fs from 'fs/promises'
4 import { basename, dirname, join, resolve } from 'path'
5 -import { isMatch } from 'micromatch'
6 -import { dirStream, dirTraversal, enforceFinal, getOrSet, isDirectory, typedKeys } from './misc'
5 +import { matches, dirStream, dirTraversal, enforceFinal, getOrSet, isDirectory, typedKeys } from './misc'
6 import Koa from 'koa'
7 import _ from 'lodash'
8 import { defineConfig, setConfig } from './config'
@@ -246,8 +245,8 @@ function applyMasks(item: VfsNode, parent: VfsNode, virtualBasename: string) {
245 const { masks } = parent
246 if (!masks) return
247 for (const [k,v] of Object.entries(masks))
249 - if (k.startsWith('**/') && isMatch(virtualBasename, k.slice(3))
250 - || !k.includes('/') && isMatch(virtualBasename, k))
248 + if (k.startsWith('**/') && matches(virtualBasename, k.slice(3))
249 + || !k.includes('/') && matches(virtualBasename, k))
250 _.defaults(item, v)
251 }
252
tests/config.yaml
+1 -1
@@ -62,7 +62,7 @@ vfs:
62 - name: cantReadPage
63 source: tests
64 masks:
65 - (page|*.ts|*.yaml):
65 + page|*.ts|*.yaml:
66 can_read: false
67 can_list: false
68 - name: cantReadRealFolder