mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 04:04:06 -08:00
fix(editor): Handle permission edge cases (empty scopes) (#7723)
This commit is contained in:
parent
9d6a68d1c7
commit
e2ffd397fc
|
@ -1,42 +1,28 @@
|
|||
import type { Scope, ScopeLevels } from './types';
|
||||
|
||||
export type HasScopeMode = 'oneOf' | 'allOf';
|
||||
export interface HasScopeOptions {
|
||||
mode: HasScopeMode;
|
||||
}
|
||||
import type { Scope, ScopeLevels, GlobalScopes, ScopeOptions } from './types';
|
||||
|
||||
export function hasScope(
|
||||
scope: Scope | Scope[],
|
||||
userScopes: GlobalScopes,
|
||||
options?: ScopeOptions,
|
||||
): boolean;
|
||||
export function hasScope(
|
||||
scope: Scope | Scope[],
|
||||
userScopes: ScopeLevels,
|
||||
options?: HasScopeOptions,
|
||||
options?: ScopeOptions,
|
||||
): boolean;
|
||||
export function hasScope(
|
||||
scope: Scope | Scope[],
|
||||
userScopes: Pick<ScopeLevels, 'global'>,
|
||||
options?: HasScopeOptions,
|
||||
): boolean;
|
||||
export function hasScope(
|
||||
scope: Scope | Scope[],
|
||||
userScopes: Omit<ScopeLevels, 'resource'>,
|
||||
options?: HasScopeOptions,
|
||||
): boolean;
|
||||
export function hasScope(
|
||||
scope: Scope | Scope[],
|
||||
userScopes: Pick<ScopeLevels, 'global'> & Partial<ScopeLevels>,
|
||||
options: HasScopeOptions = { mode: 'oneOf' },
|
||||
userScopes: unknown,
|
||||
options: ScopeOptions = { mode: 'oneOf' },
|
||||
): boolean {
|
||||
if (!Array.isArray(scope)) {
|
||||
scope = [scope];
|
||||
}
|
||||
|
||||
const userScopeSet = new Set([
|
||||
...userScopes.global,
|
||||
...(userScopes.project ?? []),
|
||||
...(userScopes.resource ?? []),
|
||||
]);
|
||||
const userScopeSet = new Set(Object.values(userScopes ?? {}).flat());
|
||||
|
||||
if (options.mode === 'allOf') {
|
||||
return scope.every((s) => userScopeSet.has(s));
|
||||
return !!scope.length && scope.every((s) => userScopeSet.has(s));
|
||||
}
|
||||
|
||||
return scope.some((s) => userScopeSet.has(s));
|
||||
|
|
|
@ -34,5 +34,11 @@ export type Scope =
|
|||
| SourceControlScope
|
||||
| ExternalSecretStoreScope;
|
||||
|
||||
export type ScopeLevel = 'global' | 'project' | 'resource';
|
||||
export type ScopeLevels = Record<ScopeLevel, Scope[]>;
|
||||
export type ScopeLevel<T extends 'global' | 'project' | 'resource'> = Record<T, Scope[]>;
|
||||
export type GlobalScopes = ScopeLevel<'global'>;
|
||||
export type ProjectScopes = ScopeLevel<'project'>;
|
||||
export type ResourceScopes = ScopeLevel<'resource'>;
|
||||
export type ScopeLevels = GlobalScopes & (ProjectScopes | (ProjectScopes & ResourceScopes));
|
||||
|
||||
export type ScopeMode = 'oneOf' | 'allOf';
|
||||
export type ScopeOptions = { mode: ScopeMode };
|
||||
|
|
|
@ -80,6 +80,12 @@ describe('hasScope', () => {
|
|||
global: memberPermissions,
|
||||
}),
|
||||
).toBe(false);
|
||||
|
||||
expect(
|
||||
hasScope([], {
|
||||
global: memberPermissions,
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
test('should work with allOf mode', () => {
|
||||
|
@ -112,5 +118,15 @@ describe('hasScope', () => {
|
|||
{ mode: 'allOf' },
|
||||
),
|
||||
).toBe(false);
|
||||
|
||||
expect(
|
||||
hasScope(
|
||||
[],
|
||||
{
|
||||
global: memberPermissions,
|
||||
},
|
||||
{ mode: 'allOf' },
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -21,7 +21,7 @@ import { WithTimestamps, jsonColumnType } from './AbstractEntity';
|
|||
import type { IPersonalizationSurveyAnswers } from '@/Interfaces';
|
||||
import type { AuthIdentity } from './AuthIdentity';
|
||||
import { ownerPermissions, memberPermissions } from '@/permissions/roles';
|
||||
import { hasScope, type HasScopeOptions, type Scope } from '@n8n/permissions';
|
||||
import { hasScope, type ScopeOptions, type Scope } from '@n8n/permissions';
|
||||
|
||||
export const MIN_PASSWORD_LENGTH = 8;
|
||||
|
||||
|
@ -137,16 +137,13 @@ export class User extends WithTimestamps implements IUser {
|
|||
return STATIC_SCOPE_MAP[this.globalRole?.name] ?? [];
|
||||
}
|
||||
|
||||
async hasGlobalScope(
|
||||
scope: Scope | Scope[],
|
||||
hasScopeOptions?: HasScopeOptions,
|
||||
): Promise<boolean> {
|
||||
async hasGlobalScope(scope: Scope | Scope[], scopeOptions?: ScopeOptions): Promise<boolean> {
|
||||
return hasScope(
|
||||
scope,
|
||||
{
|
||||
global: this.globalScopes,
|
||||
},
|
||||
hasScopeOptions,
|
||||
scopeOptions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue