plugins: api.ctxBelongsTo
Massimo Melina committed
Dec 16, 2024 at 15:19 UTC
65efd864aa6079119392f7581b5062d8692e1afc
4 files changed
+19
-12
dev-plugins.md
+4
-1
@@ -239,7 +239,9 @@ The `api` object you get as parameter of the `init` contains the following:
239
240
- `i18n(ctx: Context): Promise<{ t }>` if you need to translate messages inside http body, without the GUI, use this function
241
to instantiate translation for the language of the browser. You can then use the `t` function as documented in [dedicated section](Internationalization-i18n).
242
-
242
+
243
+- `ctxBelongsTo(ctx: Context, accounts: strings[]): boolean` check if the current username, or any group it belongs to, matches the provided accounts list.
244
+
245
- `misc` many functions and constants available in [misc.ts](https://github.com/rejetto/hfs/blob/main/src/misc.ts).
246
These are not documented, probably never will, and are subject to change without notifications,
247
but you can study the sources if you are interested in using them. It's just a shorter version of `api.require('./misc')`
@@ -708,6 +710,7 @@ If you want to override a text regardless of the language, use the special langu
710
- api.i18n
711
- frontend event: newListEntries
712
- HFS.fileShowComponents
713
+ - api.ctxBelongsTo
714
- 9.6 (v0.54.0)
715
- frontend event: showPlay
716
- api.addBlock
src/perm.ts
+9
-2
@@ -1,11 +1,13 @@
1
// This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3
import _ from 'lodash'
4
-import { HTTP_BAD_REQUEST, objRenameKey, objSameKeys, setHidden, typedEntries, wantArray } from './misc'
4
+import { getOrSet, HTTP_BAD_REQUEST, objRenameKey, objSameKeys, setHidden, typedEntries, wantArray } from './misc'
5
import { defineConfig, saveConfigAsap } from './config'
6
import { createVerifierAndSalt, SRPParameters, SRPRoutines } from 'tssrp6a'
7
import events from './events'
8
import { ApiError } from './apiMiddleware'
9
+import { getCurrentUsername } from './auth'
10
+import Koa from 'koa'
11
12
export interface Account {
13
// we consider all the following fields, when falsy, as equivalent to be missing. If this changes in the future, please adjust addAccount and setAccount
@@ -39,6 +41,12 @@ export function expandUsername(who: string): string[] {
41
return ret
42
}
43
44
+// check if current username or any ancestor match the provided usernames
45
+export function ctxBelongsTo(ctx: Koa.Context, usernames: string[]) {
46
+ return getOrSet(ctx.state, 'usernames', () => expandUsername(getCurrentUsername(ctx))) // cache ancestors' usernames inside context state
47
+ .some((u: string) => usernames.includes(u))
48
+}
49
+
50
export function getAccount(username:string, normalize=true) : Account | undefined {
51
if (normalize)
52
username = normalizeUsername(username)
@@ -198,7 +206,6 @@ export function accountCanLoginAdmin(account: Account) {
206
return accountCanLogin(account) && Boolean(getFromAccount(account, a => a.admin))
207
}
208
201
-
209
export async function changeSrpHelper(account: Account, salt: string, verifier: string) {
210
if (!salt || !verifier)
211
return new ApiError(HTTP_BAD_REQUEST, 'missing parameters')
src/plugins.ts
+2
@@ -29,6 +29,7 @@ import { app } from './index'
29
import { addBlock } from './block'
30
import { getLangData } from './lang'
31
import { i18nFromTranslations } from './i18n'
32
+import { ctxBelongsTo } from './perm'
33
34
export const PATH = 'plugins'
35
export const DISABLING_SUFFIX = '-disabled'
@@ -121,6 +122,7 @@ async function initPlugin<T>(pl: any, morePassedToInit?: T) {
122
notifyClient,
123
addBlock,
124
misc,
125
+ ctxBelongsTo,
126
...morePassedToInit
127
})
128
return Object.assign(pl, typeof res === 'function' ? { unload: res } : res)
src/vfs.ts
+4
-9
@@ -3,7 +3,7 @@
3
import fs from 'fs/promises'
4
import { basename, dirname, join, resolve } from 'path'
5
import {
6
- dirStream, getOrSet, makeMatcher, setHidden, onlyTruthy, isValidFileName, throw_, VfsPerms, Who,
6
+ dirStream, makeMatcher, setHidden, onlyTruthy, isValidFileName, throw_, VfsPerms, Who,
7
isWhoObject, WHO_ANY_ACCOUNT, defaultPerms, PERM_KEYS, removeStarting, HTTP_SERVER_ERROR, try_
8
} from './misc'
9
import Koa from 'koa'
@@ -11,7 +11,7 @@ import _ from 'lodash'
11
import { defineConfig, setConfig } from './config'
12
import { HTTP_FORBIDDEN, HTTP_UNAUTHORIZED, IS_MAC, IS_WINDOWS } from './const'
13
import events from './events'
14
-import { expandUsername } from './perm'
14
+import { ctxBelongsTo } from './perm'
15
import { getCurrentUsername } from './auth'
16
import { Stats } from 'node:fs'
17
import fswin from 'fswin'
@@ -249,13 +249,8 @@ export function statusCodeForMissingPerm(node: VfsNode, perm: keyof VfsPerms, ct
249
cur = who
250
} while (1)
251
252
- if (Array.isArray(who)) {
253
- const arr = who // shut up ts
254
- // check if I or any ancestor match `who`, but cache ancestors' usernames inside context state
255
- const some = getOrSet(ctx.state, 'usernames', () => expandUsername(getCurrentUsername(ctx)))
256
- .some((u: string) => arr.includes(u))
257
- return some ? 0 : HTTP_UNAUTHORIZED
258
- }
252
+ if (Array.isArray(who))
253
+ return ctxBelongsTo(ctx, who) ? 0 : HTTP_UNAUTHORIZED
254
return typeof who === 'boolean' ? (who ? 0 : HTTP_FORBIDDEN)
255
: who === WHO_ANY_ACCOUNT ? (getCurrentUsername(ctx) ? 0 : HTTP_UNAUTHORIZED)
256
: throw_(Error(`invalid permission: ${perm}=${try_(() => JSON.stringify(who))}`))