147 lines
4.1 KiB
TypeScript
147 lines
4.1 KiB
TypeScript
/**
|
|
* Permission Utility Functions
|
|
* Supports wildcard permissions (e.g., "invoice:*" grants all invoice actions)
|
|
*/
|
|
|
|
import type { Permission } from './permissions';
|
|
|
|
/**
|
|
* Match a granted permission against a required permission
|
|
* Supports wildcard matching: "resource:*" matches all actions for that resource
|
|
*
|
|
* @example
|
|
* matchesPermission('invoice:*', 'invoice:create') // true
|
|
* matchesPermission('invoice:view', 'invoice:create') // false
|
|
* matchesPermission('invoice:create', 'invoice:create') // true
|
|
*/
|
|
export function matchesPermission(
|
|
grantedPermission: string,
|
|
requiredPermission: string
|
|
): boolean {
|
|
// Direct match
|
|
if (grantedPermission === requiredPermission) {
|
|
return true;
|
|
}
|
|
|
|
// Parse permission format: "resource:action"
|
|
const grantedParts = grantedPermission.split(':');
|
|
const requiredParts = requiredPermission.split(':');
|
|
|
|
// Must have 2 parts
|
|
if (grantedParts.length !== 2 || requiredParts.length !== 2) {
|
|
return false;
|
|
}
|
|
|
|
const [grantedResource, grantedAction] = grantedParts;
|
|
const [requiredResource, requiredAction] = requiredParts;
|
|
|
|
// Resource must match
|
|
if (grantedResource !== requiredResource) {
|
|
return false;
|
|
}
|
|
|
|
// Wildcard grants all actions for the resource
|
|
if (grantedAction === '*') {
|
|
return true;
|
|
}
|
|
|
|
// Action must match
|
|
return grantedAction === requiredAction;
|
|
}
|
|
|
|
/**
|
|
* Check if user has a specific permission
|
|
*
|
|
* @param userPermissions - Array of permissions from backend
|
|
* @param requiredPermission - Permission to check (e.g., "invoice:create")
|
|
* @returns true if user has the permission (directly or via wildcard)
|
|
*/
|
|
export function hasPermission(
|
|
userPermissions: string[],
|
|
requiredPermission: string
|
|
): boolean {
|
|
return userPermissions.some(grantedPermission =>
|
|
matchesPermission(grantedPermission, requiredPermission)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Check if user has ANY of the specified permissions (OR logic)
|
|
*
|
|
* @param userPermissions - Array of permissions from backend
|
|
* @param requiredPermissions - Array of permissions to check
|
|
* @returns true if user has at least one of the permissions
|
|
*
|
|
* @example
|
|
* hasAnyPermission(permissions, ['invoice:create', 'invoice:view'])
|
|
* // true if user has either permission
|
|
*/
|
|
export function hasAnyPermission(
|
|
userPermissions: string[],
|
|
requiredPermissions: string[]
|
|
): boolean {
|
|
if (requiredPermissions.length === 0) {
|
|
return true;
|
|
}
|
|
|
|
return requiredPermissions.some(permission =>
|
|
hasPermission(userPermissions, permission)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Check if user has ALL of the specified permissions (AND logic)
|
|
*
|
|
* @param userPermissions - Array of permissions from backend
|
|
* @param requiredPermissions - Array of permissions to check
|
|
* @returns true if user has all permissions
|
|
*
|
|
* @example
|
|
* hasAllPermissions(permissions, ['invoice:view', 'invoice:create'])
|
|
* // true only if user has both permissions
|
|
*/
|
|
export function hasAllPermissions(
|
|
userPermissions: string[],
|
|
requiredPermissions: string[]
|
|
): boolean {
|
|
if (requiredPermissions.length === 0) {
|
|
return true;
|
|
}
|
|
|
|
return requiredPermissions.every(permission =>
|
|
hasPermission(userPermissions, permission)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Check if user has a specific role
|
|
*
|
|
* @param userRoles - Array of role names from Stytch session
|
|
* @param role - Role to check (e.g., "admin", "manager", "member")
|
|
* @returns true if user has the role
|
|
*/
|
|
export function hasRole(userRoles: string[], role: string): boolean {
|
|
return userRoles.includes(role);
|
|
}
|
|
|
|
/**
|
|
* Check if user has ANY of the specified roles
|
|
*
|
|
* @param userRoles - Array of role names from Stytch session
|
|
* @param roles - Array of roles to check
|
|
* @returns true if user has at least one of the roles
|
|
*/
|
|
export function hasAnyRole(userRoles: string[], roles: string[]): boolean {
|
|
return roles.some(role => userRoles.includes(role));
|
|
}
|
|
|
|
/**
|
|
* Check if user has ALL of the specified roles
|
|
*
|
|
* @param userRoles - Array of role names from Stytch session
|
|
* @param roles - Array of roles to check
|
|
* @returns true if user has all roles
|
|
*/
|
|
export function hasAllRoles(userRoles: string[], roles: string[]): boolean {
|
|
return roles.every(role => userRoles.includes(role));
|
|
}
|