better code: all uri-type parameters shall be named uri*, so to be treated properly

Massimo Melina committed Apr 14, 2023 at 10:26 UTC 10f302c46fbc21bf0c5498054295c096ee792c5e
10 files changed +40 -33
dev-plugins.md
+1 -1
@@ -48,7 +48,7 @@ All the following properties are essentially optional.
48 If you want to execute something in the "upstream" of middlewares, return a function.
49
50 - `unload: function` called when unloading a plugin. This is a good place for example to clearInterval().
51 -- `onDirEntry: ({ entry: DirEntry, listPath: string }) => void | false` by providing this callback you can manipulate the record
51 +- `onDirEntry: ({ entry: DirEntry, listUri: string }) => void | false` by providing this callback you can manipulate the record
52 that is sent to the frontend (`entry`), or you can return false to exclude this entry from the results.
53 - `config: { [key]: FieldDescriptor }` declare a set of admin-configurable values owned by the plugin
54 that will be displayed inside Admin-panel for change. Each property is identified by its key,
frontend/src/menu.ts
+1 -1
@@ -206,7 +206,7 @@ export async function deleteFiles(uris: string[], root: string='') {
206 if (!await confirmDialog(t('delete_confirm', {n}, "Delete {n,plural, one{# item} other{# items}}?")))
207 return false
208 const errors = onlyTruthy(await Promise.all(uris.map(uri =>
209 - apiCall('del', { path: root + uri }).then(() => null, err => ({ uri, err }))
209 + apiCall('del', { uri: root + uri }).then(() => null, err => ({ uri, err }))
210 )))
211 reloadList()
212 const e = errors.length
frontend/src/upload.ts
+3 -3
@@ -379,14 +379,14 @@ export function acceptDropFiles(cb: false | undefined | ((files:File[]) => void)
379 async function createFolder() {
380 const name = await promptDialog(t`Enter folder name`)
381 if (!name) return
382 - const path = location.pathname
382 + const uri = location.pathname
383 try {
384 - await apiCall('create_folder', { path, name })
384 + await apiCall('create_folder', { uri, name })
385 reloadList()
386 return alertDialog(h(() =>
387 h(FlexV, {},
388 h('div', {}, t`Successfully created`),
389 - h(Link, { to: path + name + '/', onClick() {
389 + h(Link, { to: uri + name + '/', onClick() {
390 closeDialog()
391 closeDialog()
392 } }, t('enter_folder', "Enter the folder")),
frontend/src/useFetchList.ts
+1 -1
@@ -48,7 +48,7 @@ export default function useFetchList() {
48 }
49
50 const baseParams = {
51 - path: desiredPath,
51 + uri: desiredPath,
52 search,
53 sse: true,
54 omit: 'c',
plugins/download-counter/plugin.js
+2 -2
@@ -47,8 +47,8 @@ exports.init = async api => {
47 counters[path] = counters[path] + 1 || 1
48 save()
49 },
50 - onDirEntry: ({ entry, listPath }) => {
51 - const path = listPath + entry.n
50 + onDirEntry: ({ entry, listUri }) => {
51 + const path = listUri + entry.n
52 const n = counters[path]
53 if (n)
54 entry.hits = n
plugins/vhosting/plugin.js
+17 -11
@@ -21,26 +21,32 @@ exports.init = api => {
21 const { matches } = api.require('./misc')
22 return {
23 middleware(ctx) {
24 - let toModify = ctx
24 + let params // undefined if we are not going to work on api parameters
25 if (ctx.path.startsWith(api.const.SPECIAL_URI)) { // special uris should be excluded...
26 // ...unless it's a frontend api with a path param
27 - if (!ctx.path.startsWith(api.const.API_URI) || ctx.params.path === undefined) return
27 + if (!ctx.path.startsWith(api.const.API_URI)) return
28 let { referer } = ctx.headers
29 referer &&= new URL(referer).pathname
30 - if (referer?.startsWith(ctx.state.revProxyPath + api.const.ADMIN_URI)) return
31 - toModify = ctx.params
30 + if (referer?.startsWith(ctx.state.revProxyPath + api.const.ADMIN_URI)) return // exclude apis for admin-panel
31 + params = ctx.params
32 }
33 +
34 const hosts = api.getConfig('hosts')
35 if (!hosts?.length) return
35 - for (const row of hosts)
36 - if (matches(ctx.host, row.host)) {
37 - toModify.path = row.root + toModify.path
38 - return
36 + const row = hosts?.find(x => matches(ctx.host, x.host))
37 + if (!row) {
38 + if (api.getConfig('mandatory')) {
39 + ctx.socket.destroy()
40 + return true
41 }
40 - if (api.getConfig('mandatory')) {
41 - ctx.socket.destroy()
42 - return true
42 + return
43 }
44 + if (!params)
45 + ctx.path = row.root + ctx.path
46 + else
47 + for (const [k,v] of Object.entries(params))
48 + if (k.startsWith('uri'))
49 + params[k] = row.root + v
50 }
51 }
52 }
src/api.file_list.ts
+4 -4
@@ -19,8 +19,8 @@ import _ from 'lodash'
19 import { HTTP_BAD_REQUEST, HTTP_FOOL, HTTP_METHOD_NOT_ALLOWED, HTTP_NOT_FOUND } from './const'
20 import Koa from 'koa'
21
22 -export const file_list: ApiHandler = async ({ path, offset, limit, search, omit, sse }, ctx) => {
23 - let node = await urlToNode(path || '/', ctx)
22 +export const file_list: ApiHandler = async ({ uri, offset, limit, search, omit, sse }, ctx) => {
23 + let node = await urlToNode( uri || '/', ctx)
24 const list = new SendListReadable()
25 if (!node)
26 return fail(HTTP_NOT_FOUND)
@@ -31,7 +31,7 @@ export const file_list: ApiHandler = async ({ path, offset, limit, search, omit,
31 return fail(HTTP_FOOL)
32 if (node.default)
33 return (sse ? list.custom : _.identity)({ // sse will wrap the object in a 'custom' message, otherwise we plainly return the object
34 - redirect: path // tell the browser to access the folder (instead of using this api), so it will get the default file
34 + redirect: uri // tell the browser to access the folder (instead of using this api), so it will get the default file
35 })
36 if (!await nodeIsDirectory(node))
37 return fail(HTTP_METHOD_NOT_ALLOWED)
@@ -69,7 +69,7 @@ export const file_list: ApiHandler = async ({ path, offset, limit, search, omit,
69 const entry = await nodeToDirEntry(ctx, sub)
70 if (!entry)
71 continue
72 - const cbParams = { entry, ctx, listPath:path, node:sub }
72 + const cbParams = { entry, ctx, listUri: uri, node: sub }
73 try {
74 if (onDirEntryHandlers.some(cb => cb(cbParams) === false))
75 continue
src/apiMiddleware.ts
+3 -2
@@ -30,8 +30,9 @@ export function apiMiddleware(apis: ApiHandlers) : Koa.Middleware {
30 // we don't rely on SameSite cookie option because it's https-only
31 let res
32 try {
33 - if (params.path)
34 - params.path = removeStarting(ctx.state.revProxyPath, params.path)
33 + for (const [k,v] of Object.entries(params))
34 + if (k.startsWith('uri') && typeof v === 'string')
35 + params[k] = removeStarting(ctx.state.revProxyPath, v)
36 res = csrf && csrf !== params.csrf ? new ApiError(HTTP_UNAUTHORIZED, 'csrf')
37 : await apiFun(params || {}, ctx)
38 }
src/frontEndApis.ts
+6 -6
@@ -36,11 +36,11 @@ export const frontEndApis: ApiHandlers = {
36 })
37 },
38
39 - async create_folder({ path, name }, ctx) {
40 - apiAssertTypes({ string: { path, name } })
39 + async create_folder({ uri, name }, ctx) {
40 + apiAssertTypes({ string: { uri, name } })
41 if (!isValidFileName(name) || dirTraversal(name))
42 return new ApiError(HTTP_BAD_REQUEST, 'bad name')
43 - const parentNode = await urlToNode(path, ctx)
43 + const parentNode = await urlToNode(uri, ctx)
44 if (!parentNode)
45 return new ApiError(HTTP_NOT_FOUND, 'parent not found')
46 if (!hasPermission(parentNode, 'can_upload', ctx))
@@ -54,9 +54,9 @@ export const frontEndApis: ApiHandlers = {
54 }
55 },
56
57 - async del({ path }, ctx) {
58 - apiAssertTypes({ string: { path } })
59 - const node = await urlToNode(path, ctx)
57 + async del({ uri }, ctx) {
58 + apiAssertTypes({ string: { uri } })
59 + const node = await urlToNode(uri, ctx)
60 if (!node)
61 throw new ApiError(HTTP_NOT_FOUND)
62 if (!node.source)
tests/test.ts
+2 -2
@@ -196,8 +196,8 @@ function reqApi(api: string, params: object, test:Tester) {
196 return req(API+api, test, { data: params })
197 }
198
199 -function reqList(path:string, tester:Tester, params?: object) {
200 - return reqApi('file_list', { path, ...params }, tester)
199 +function reqList(uri:string, tester:Tester, params?: object) {
200 + return reqApi('file_list', { uri, ...params }, tester)
201 }
202
203 function isInList(res:any, name:string) {