test: new 'p' in list

Massimo Melina committed Apr 7, 2023 at 16:15 UTC 7436ffa350d84d4b64dcf94cf8d0ea5be5381756
2 files changed +59 -11
tests/config.yaml
+19
@@ -46,6 +46,25 @@ vfs:
46 rename:
47 alfa.txt: renamed1
48 page/gpl.png: renamed2
49 + - name: cantListBut
50 + source: tests
51 + can_list: false
52 + masks:
53 + "*":
54 + can_list: true
55 + - name: cantReadBut
56 + source: tests
57 + can_read: false
58 + masks:
59 + "*":
60 + can_read: true
61 + - name: cantReadButChild
62 + source: tests
63 + can_read: false
64 + children:
65 + - source: tests/alfa.txt
66 + can_read:
67 + - rejetto
68 - name: cantListPage
69 source: tests
70 masks:
tests/test.ts
+40 -11
@@ -5,6 +5,7 @@ import { Done } from 'mocha'
5 import { srpSequence } from '@hfs/shared/srp'
6 import { createReadStream, rmSync } from 'fs'
7 import { join } from 'path'
8 +import _ from 'lodash'
9 /*
10 import { PORT, srv } from '../src'
11
@@ -49,10 +50,20 @@ describe('basics', () => {
50 it('forbidden list.alternative method', reqList('/cantListPageAlt/page/', 403))
51 it('forbidden list.alternative method readable file', req('/cantListPageAlt/page/gpl.png', 200))
52
53 + it('cantListBut', reqList('/cantListBut/', 403))
54 + it('cantListBut.parent', reqList('/', { permInList: { 'cantListBut/': 'l' } }))
55 + it('cantListBut.child masked', reqList('/cantListBut/page', 200))
56 +
57 + it('cantReadBut', reqList('/cantReadBut/', 200))
58 + it('cantReadBut.can', req('/cantReadBut/alfa.txt', 200))
59 + it('cantReadBut.parent', reqList('/', { permInList: { 'cantReadBut/': '!r' } }))
60 + it('cantReadButChild', req('/cantReadButChild/alfa.txt', 401))
61 + it('cantReadButChild.parent', reqList('/', { permInList: { 'cantReadButChild/': 'R' } }))
62 +
63 it('cantReadPage', reqList('/cantReadPage/page', 403))
64 it('cantReadPage.zip', req('/cantReadPage/page/?get=zip', 403, { method:'HEAD' }))
65 it('cantReadPage.file', req('/cantReadPage/page/gpl.png', 403))
55 - it('cantReadPage.parent', reqList('/cantReadPage', 200))
66 + it('cantReadPage.parent', reqList('/cantReadPage', { permInList: { 'page/': 'lr' } }))
67 it('cantReadRealFolder', reqList('/cantReadRealFolder', 403))
68 it('cantReadRealFolder.file', req('/cantReadRealFolder/page/gpl.png', 403))
69
@@ -111,8 +122,9 @@ function testUpload(name: string, tester: Tester, path = 'temp/') {
122 }))
123 }
124
125 +type TesterFunction = ((data: any, fullResponse: any) => boolean)
126 type Tester = number
115 - | ((data: any, fullResponse: any) => boolean | Error)
127 + | TesterFunction
128 | RegExp
129 | {
130 mime?: string
@@ -120,8 +132,10 @@ type Tester = number
132 re?: RegExp
133 inList?: string[]
134 outList?: string[]
135 + permInList?: Record<string, string>
136 empty?: true
137 length?: number
138 + cb?: TesterFunction
139 }
140
141 function req(methodUrl: string, test:Tester, requestOptions: AxiosRequestConfig<any>={}) {
@@ -147,18 +161,25 @@ function req(methodUrl: string, test:Tester, requestOptions: AxiosRequestConfig<
161 if (typeof test === 'number')
162 test = { status: test }
163 if (typeof test === 'object') {
150 - const { status, mime, re, inList, outList, length } = test
164 + const { status, mime, re, inList, outList, length, permInList } = test
165 const gotMime = res.headers?.['content-type']
166 const gotStatus = (res.status|| res.response.status)
167 const gotLength = res.headers?.['content-length']
154 - const err = mime && !gotMime?.startsWith(mime) ? 'expected mime ' + mime + ' got ' + gotMime
155 - : status && gotStatus !== status ? 'expected status ' + status + ' got ' + gotStatus
156 - : re && !(typeof res.data === 'string' && re.test(res.data)) ? 'expected content '+String(re)+' got '+res.data
157 - : inList && !inList.every(x => isInList(res.data, x)) ? 'expected in list '+inList
158 - : outList && !outList.every(x => !isInList(res.data, x)) ? 'expected not in list '+outList
159 - : test.empty && res.data ? 'expected empty body'
160 - : length !== undefined && gotLength !== String(length) ? "expected content-length " + length + " got " + gotLength
161 - : ''
168 + const err = mime && !gotMime?.startsWith(mime) && 'expected mime ' + mime + ' got ' + gotMime
169 + || status && gotStatus !== status && 'expected status ' + status + ' got ' + gotStatus
170 + || re && !(typeof res.data === 'string' && re.test(res.data)) && 'expected content '+String(re)+' got '+res.data
171 + || inList && !inList.every(x => isInList(res.data, x)) && 'expected in list '+inList
172 + || outList && !outList.every(x => !isInList(res.data, x)) && 'expected not in list '+outList
173 + || permInList && findFirst(permInList, (v, k) => {
174 + const got = _.find(res.data.list, { n: k })?.p
175 + const negate = v[0] === '!'
176 + return findFirst(v.slice(negate ? 1 : 0).split(''), char =>
177 + got?.includes(char) === negate ? `expected perm ${v} on ${k}, got ${got}` : undefined)
178 + })
179 + || test.empty && res.data && 'expected empty body'
180 + || length !== undefined && gotLength !== String(length) && "expected content-length " + length + " got " + gotLength
181 + || test.cb?.(res.data, res) === false && 'error'
182 + || ''
183 return done(err && Error(err))
184 }
185 const ok = test(res.data, res)
@@ -182,3 +203,11 @@ function reqList(path:string, tester:Tester, params?: object) {
203 function isInList(res:any, name:string) {
204 return Array.isArray(res?.list) && Boolean((res.list as any[]).find(x => x.n===name))
205 }
206 +
207 +export function findFirst<I, O>(a: I[] | Record<string, I>, cb:(v:I, k: string | number)=>O): any {
208 + if (a) for (const k in a) {
209 + const ret = cb((a as any)[k] as I, k)
210 + if (ret !== undefined)
211 + return ret
212 + }
213 +}
\ No newline at end of file