mirror of
https://github.com/Unleash/unleash.git
synced 2025-09-24 17:51:14 +02:00
https://linear.app/unleash/issue/2-1155/refactor-permissions - Our `rbac-middleware` now supports multiple OR permissions; - Drops non-specific permissions (e.g. CRUD API token permissions without specifying the token type); - Makes our permission descriptions consistent; - Drops our higher-level permissions that basically mean ADMIN (e.g. ADMIN token permissions) in favor of `ADMIN` permission in order to avoid privilege escalations; This PR may help with https://linear.app/unleash/issue/2-1144/discover-potential-privilege-escalations as it may prevent privilege escalations altogether. There's some UI permission logic around this, but in the future https://linear.app/unleash/issue/2-1156/adapt-api-tokens-creation-ui-to-new-permissions could take it a bit further by adapting the creation of tokens as well. --------- Co-authored-by: Gastón Fournier <gaston@getunleash.io>
88 lines
2.2 KiB
TypeScript
88 lines
2.2 KiB
TypeScript
import { ReactElement, ReactNode, useMemo } from 'react';
|
|
import AccessContext, { IAccessContext } from 'contexts/AccessContext';
|
|
import { ADMIN, SKIP_CHANGE_REQUEST } from './permissions';
|
|
import { IPermission } from 'interfaces/user';
|
|
import { useAuthPermissions } from 'hooks/api/getters/useAuth/useAuthPermissions';
|
|
|
|
interface IAccessProviderProps {
|
|
children: ReactNode;
|
|
}
|
|
|
|
export const AccessProvider = ({
|
|
children,
|
|
}: IAccessProviderProps): ReactElement => {
|
|
const { permissions } = useAuthPermissions();
|
|
|
|
const value: IAccessContext = useMemo(
|
|
() => ({
|
|
isAdmin: checkAdmin(permissions),
|
|
hasAccess: hasAccess.bind(null, permissions),
|
|
}),
|
|
[permissions]
|
|
);
|
|
|
|
return (
|
|
<AccessContext.Provider value={value}>
|
|
{children}
|
|
</AccessContext.Provider>
|
|
);
|
|
};
|
|
|
|
export const checkAdmin = (permissions: IPermission[] | undefined): boolean => {
|
|
if (!permissions) {
|
|
return false;
|
|
}
|
|
|
|
return permissions.some(p => {
|
|
return p.permission === ADMIN;
|
|
});
|
|
};
|
|
|
|
export const hasAccess = (
|
|
permissions: IPermission[] | undefined,
|
|
permission: string | string[],
|
|
project?: string,
|
|
environment?: string
|
|
): boolean => {
|
|
if (!permissions) {
|
|
return false;
|
|
}
|
|
const permissionsToCheck = Array.isArray(permission)
|
|
? permission
|
|
: [permission];
|
|
|
|
return permissions.some(p =>
|
|
permissionsToCheck.some(permissionToCheck =>
|
|
checkPermission(p, permissionToCheck, project, environment)
|
|
)
|
|
);
|
|
};
|
|
|
|
const checkPermission = (
|
|
p: IPermission,
|
|
permission: string,
|
|
project?: string,
|
|
environment?: string
|
|
): boolean => {
|
|
if (!permission) {
|
|
console.warn(`Missing permission for AccessProvider: ${permission}`);
|
|
return false;
|
|
}
|
|
|
|
if (p.permission === ADMIN && permission !== SKIP_CHANGE_REQUEST) {
|
|
return true;
|
|
}
|
|
|
|
if (
|
|
p.permission === permission &&
|
|
(p.project === project || p.project === '*') &&
|
|
(!p.environment ||
|
|
p.environment === environment ||
|
|
p.environment === '*')
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
return p.permission === permission && !p.project && !p.environment;
|
|
};
|