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