mirror of https://github.com/buster-so/buster.git
reset permission stuff
This commit is contained in:
parent
273008adc6
commit
3cdd0bfa57
|
@ -79,7 +79,7 @@ export const checkIfAssetIsEditable = async ({
|
|||
assetType: AssetType;
|
||||
organizationId: string;
|
||||
workspaceSharing: WorkspaceSharing;
|
||||
requiredRole?: AssetPermissionRole | AssetPermissionRole[];
|
||||
requiredRole?: AssetPermissionRole;
|
||||
}) => {
|
||||
const assetPermissionResult = await checkPermission({
|
||||
userId: user.id,
|
||||
|
|
|
@ -33,11 +33,9 @@ export function getPermissionCacheKey(
|
|||
userId: string,
|
||||
assetId: string,
|
||||
assetType: AssetType,
|
||||
requiredRole: AssetPermissionRole | AssetPermissionRole[]
|
||||
requiredRole: AssetPermissionRole
|
||||
): CacheKey {
|
||||
// Normalize and sort roles for consistent cache keys
|
||||
const roles = Array.isArray(requiredRole) ? [...requiredRole].sort() : [requiredRole];
|
||||
return `${userId}:${assetId}:${assetType}:${roles.join(',')}`;
|
||||
return `${userId}:${assetId}:${assetType}:${requiredRole}`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -47,7 +45,7 @@ export function getCachedPermission(
|
|||
userId: string,
|
||||
assetId: string,
|
||||
assetType: AssetType,
|
||||
requiredRole: AssetPermissionRole | AssetPermissionRole[]
|
||||
requiredRole: AssetPermissionRole
|
||||
): AssetPermissionResult | undefined {
|
||||
const key = getPermissionCacheKey(userId, assetId, assetType, requiredRole);
|
||||
const cached = permissionCache.get(key);
|
||||
|
@ -68,7 +66,7 @@ export function setCachedPermission(
|
|||
userId: string,
|
||||
assetId: string,
|
||||
assetType: AssetType,
|
||||
requiredRole: AssetPermissionRole | AssetPermissionRole[],
|
||||
requiredRole: AssetPermissionRole,
|
||||
result: AssetPermissionResult
|
||||
): void {
|
||||
const key = getPermissionCacheKey(userId, assetId, assetType, requiredRole);
|
||||
|
@ -198,13 +196,18 @@ export function invalidateUser(userId: string) {
|
|||
* Invalidate all cached entries for a user-asset combination
|
||||
*/
|
||||
export function invalidateUserAsset(userId: string, assetId: string, assetType: AssetType) {
|
||||
// Invalidate all permission cache entries for this user-asset combination
|
||||
// Since we now support arrays, we need to invalidate all possible combinations
|
||||
// The simplest approach is to invalidate all entries containing the user-asset-type pattern
|
||||
for (const key of Array.from(permissionCache.keys())) {
|
||||
if (key.startsWith(`${userId}:${assetId}:${assetType}:`)) {
|
||||
permissionCache.delete(key);
|
||||
}
|
||||
// Invalidate all permission levels for this user-asset combination
|
||||
const permissionRoles: AssetPermissionRole[] = [
|
||||
'owner',
|
||||
'full_access',
|
||||
'can_edit',
|
||||
'can_filter',
|
||||
'can_view',
|
||||
];
|
||||
|
||||
for (const role of permissionRoles) {
|
||||
const key = getPermissionCacheKey(userId, assetId, assetType, role);
|
||||
permissionCache.delete(key);
|
||||
}
|
||||
|
||||
// Invalidate cascading cache
|
||||
|
|
|
@ -205,7 +205,7 @@ describe('Asset Permission Checks', () => {
|
|||
'user123',
|
||||
'asset123',
|
||||
'dashboard_file',
|
||||
['can_view'],
|
||||
'can_view',
|
||||
{ hasAccess: false }
|
||||
);
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
import type { User } from '@buster/database/queries';
|
||||
import type { AssetType } from '@buster/database/schema-types';
|
||||
import type { AssetPermissionRole, OrganizationMembership, WorkspaceSharing } from '../types';
|
||||
import { getHighestPermission, isPermissionSufficientForAny } from '../types/asset-permissions';
|
||||
import { getHighestPermission, isPermissionSufficient } from '../types/asset-permissions';
|
||||
import { getCachedPermission, setCachedPermission } from './cache';
|
||||
import { checkCascadingPermissions } from './cascading-permissions';
|
||||
|
||||
|
@ -14,7 +14,7 @@ export interface AssetPermissionCheck {
|
|||
userId: string;
|
||||
assetId: string;
|
||||
assetType: AssetType;
|
||||
requiredRole: AssetPermissionRole | AssetPermissionRole[];
|
||||
requiredRole: AssetPermissionRole;
|
||||
organizationId?: string;
|
||||
workspaceSharing?: WorkspaceSharing;
|
||||
}
|
||||
|
@ -31,12 +31,8 @@ export interface AssetPermissionResult {
|
|||
export async function checkPermission(check: AssetPermissionCheck): Promise<AssetPermissionResult> {
|
||||
const { userId, assetId, assetType, requiredRole, organizationId, workspaceSharing } = check;
|
||||
|
||||
// Normalize requiredRole to an array for consistent handling
|
||||
const requiredRoles = Array.isArray(requiredRole) ? requiredRole : [requiredRole];
|
||||
|
||||
// Check cache first (using serialized array as key)
|
||||
const cached = getCachedPermission(userId, assetId, assetType, requiredRoles);
|
||||
|
||||
// Check cache first
|
||||
const cached = getCachedPermission(userId, assetId, assetType, requiredRole);
|
||||
if (cached !== undefined) {
|
||||
return cached;
|
||||
}
|
||||
|
@ -60,8 +56,8 @@ export async function checkPermission(check: AssetPermissionCheck): Promise<Asse
|
|||
const dbResult = await checkDbAssetPermission(dbParams);
|
||||
|
||||
if (dbResult.hasAccess && dbResult.role) {
|
||||
// Check if the role is sufficient for any of the required roles
|
||||
if (isPermissionSufficientForAny(dbResult.role, requiredRoles)) {
|
||||
// Check if the role is sufficient
|
||||
if (isPermissionSufficient(dbResult.role, requiredRole)) {
|
||||
const result: AssetPermissionResult = {
|
||||
hasAccess: true,
|
||||
effectiveRole: dbResult.role,
|
||||
|
@ -69,7 +65,7 @@ export async function checkPermission(check: AssetPermissionCheck): Promise<Asse
|
|||
if (dbResult.accessPath !== undefined) {
|
||||
result.accessPath = dbResult.accessPath;
|
||||
}
|
||||
setCachedPermission(userId, assetId, assetType, requiredRoles, result);
|
||||
setCachedPermission(userId, assetId, assetType, requiredRole, result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -80,21 +76,20 @@ export async function checkPermission(check: AssetPermissionCheck): Promise<Asse
|
|||
|
||||
if (isOrgMember) {
|
||||
const workspaceRole = mapWorkspaceSharingToRole(workspaceSharing);
|
||||
if (workspaceRole && isPermissionSufficientForAny(workspaceRole, requiredRoles)) {
|
||||
if (workspaceRole && isPermissionSufficient(workspaceRole, requiredRole)) {
|
||||
const result = {
|
||||
hasAccess: true,
|
||||
effectiveRole: workspaceRole,
|
||||
accessPath: 'workspace_sharing' as const,
|
||||
};
|
||||
setCachedPermission(userId, assetId, assetType, requiredRoles, result);
|
||||
setCachedPermission(userId, assetId, assetType, requiredRole, result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check cascading permissions for specific asset types
|
||||
// Only check if any of the required roles is 'can_view' (cascading only provides view access)
|
||||
if (requiredRoles.includes('can_view')) {
|
||||
if (requiredRole === 'can_view') {
|
||||
// Create a user object for cascading permissions check
|
||||
const user: Pick<User, 'id'> = { id: userId };
|
||||
const hasCascadingAccess = await checkCascadingPermissions(assetId, assetType, user as User);
|
||||
|
@ -104,13 +99,13 @@ export async function checkPermission(check: AssetPermissionCheck): Promise<Asse
|
|||
effectiveRole: 'can_view' as AssetPermissionRole,
|
||||
accessPath: 'cascading' as const,
|
||||
};
|
||||
setCachedPermission(userId, assetId, assetType, requiredRoles, result);
|
||||
setCachedPermission(userId, assetId, assetType, requiredRole, result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
const result = { hasAccess: false };
|
||||
setCachedPermission(userId, assetId, assetType, requiredRoles, result);
|
||||
setCachedPermission(userId, assetId, assetType, requiredRole, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -154,24 +149,18 @@ export function computeEffectivePermission(
|
|||
* Map workspace sharing level to permission role
|
||||
*/
|
||||
function mapWorkspaceSharingToRole(workspaceSharing: WorkspaceSharing): AssetPermissionRole | null {
|
||||
if (workspaceSharing === 'can_view') {
|
||||
return 'can_view';
|
||||
switch (workspaceSharing) {
|
||||
case 'can_view':
|
||||
return 'can_view';
|
||||
case 'can_edit':
|
||||
return 'can_edit';
|
||||
case 'full_access':
|
||||
return 'full_access';
|
||||
case 'none':
|
||||
return null;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
if (workspaceSharing === 'can_edit') {
|
||||
return 'can_edit';
|
||||
}
|
||||
|
||||
if (workspaceSharing === 'full_access') {
|
||||
return 'full_access';
|
||||
}
|
||||
|
||||
if (workspaceSharing === 'none') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const _exhaustiveCheck: never = workspaceSharing;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -204,7 +204,7 @@ export async function hasAssetPermission(params: {
|
|||
userId: string;
|
||||
assetId: string;
|
||||
assetType: AssetType;
|
||||
requiredRole: AssetPermissionRole | AssetPermissionRole[];
|
||||
requiredRole: AssetPermissionRole;
|
||||
organizationId?: string;
|
||||
workspaceSharing?: WorkspaceSharing;
|
||||
}): Promise<boolean> {
|
||||
|
|
Loading…
Reference in New Issue