small optimization on permission checks
Massimo Melina committed
Oct 24, 2025 at 19:38 UTC
7052a6bb37a6b7e6be446f0ae03856598d0fb03e
2 files changed
+7
-7
src/api.auth.ts
+1
-1
@@ -111,7 +111,7 @@ export const refresh_session: ApiHandler = async ({}, ctx) => {
111
const username = getCurrentUsername(ctx)
112
return !ctx.session ? new ApiError(HTTP_SERVER_ERROR) : {
113
username,
114
- expandedUsername: expandUsername(username),
114
+ expandedUsername: Array.from(expandUsername(username)),
115
adminUrl: ctxAdminAccess(ctx) ? ctx.state.revProxyPath + ADMIN_URI : undefined,
116
canChangePassword: accountCanChangePassword(ctx.state.account),
117
requireChangePassword: ctx.state.account?.require_password_change,
src/perm.ts
+6
-6
@@ -30,13 +30,13 @@ export interface Account {
30
interface Accounts { [username:string]: Account }
31
32
// provides the username and all other usernames it inherits based on the 'belongs' attribute. Useful to check permissions
33
-export function expandUsername(who: string): string[] {
34
- const ret = []
33
+export function expandUsername(who: string) {
34
+ const ret = new Set<string>()
35
const q = [who]
36
for (const u of q) {
37
const a = getAccount(u)
38
if (!a || a.disabled) continue
39
- ret.push(u)
39
+ ret.add(u)
40
if (a.belongs)
41
q.push(...a.belongs)
42
}
@@ -45,8 +45,8 @@ export function expandUsername(who: string): string[] {
45
46
// check if current username or any ancestor match the provided usernames
47
export function ctxBelongsTo(ctx: Koa.Context, usernames: string[]) {
48
- return (ctx.state.usernames ||= expandUsername(getCurrentUsername(ctx))) // cache ancestors' usernames inside context state
49
- .some((u: string) => usernames.includes(u))
48
+ const s = ctx.state.usernames ||= expandUsername(getCurrentUsername(ctx))
49
+ return usernames.some(u => s.has(u)) // cache ancestors' usernames inside context state
50
}
51
52
export function getUsernames() {
@@ -227,6 +227,6 @@ export async function changeSrpHelper(account: Account, salt: string, verifier:
227
228
declare module "koa" {
229
interface DefaultState {
230
- usernames?: string[]
230
+ usernames?: Set<string>
231
}
232
}
\ No newline at end of file