Repository: directus/directus
File: api/src/database/migrations/20240710A-permissions-policies.ts (TypeScript)

Code before:
export function mergePermissions(strategy: 'and' | 'or', ...permissions: Permission[][]) {
	const allPermissions = flatten(permissions);

	const mergedPermissions = allPermissions
		.reduce((acc, val) => {
			const key = `${val.collection}__${val.action}`;
			const current = acc.get(key);
			acc.set(key, current ? mergePermission(strategy, current, val) : val);
			return acc;
		}, new Map())
		.values();

	return Array.from(mergedPermissions);
}

export function mergePermission(
	strategy: 'and' | 'or',
	currentPerm: Permission,
	newPerm: Permission,
): Omit<Permission, 'id' | 'system'> {
	const logicalKey = `_${strategy}` as keyof LogicalFilterOR | keyof LogicalFilterAND;

	let permissions = currentPerm.permissions;
	let validation = currentPerm.validation;
	let fields = currentPerm.fields;
	let presets = currentPerm.presets;

	if (newPerm.permissions) {
		if (currentPerm.permissions && Object.keys(currentPerm.permissions)[0] === logicalKey) {
			permissions = {
				[logicalKey]: [
					...(currentPerm.permissions as LogicalFilterOR & LogicalFilterAND)[logicalKey],
					newPerm.permissions,
				],
			} as LogicalFilterAND | LogicalFilterOR;
		} else if (currentPerm.permissions) {
			// Empty {} supersedes other permissions in _OR merge
			if (strategy === 'or' && (isEqual(currentPerm.permissions, {}) || isEqual(newPerm.permissions, {}))) {
				permissions = {};
			} else {
				permissions = {
					[logicalKey]: [currentPerm.permissions, newPerm.permissions],
				} as LogicalFilterAND | LogicalFilterOR;
			}
		} else {
			permissions = {
				[logicalKey]: [newPerm.permissions],
			} as LogicalFilterAND | LogicalFilterOR;
		}
	}


Review comment (security):
```suggestion
	let { permissions, validation, fields, presets } = currentPerm.permissions;
```

Code after:
export function mergePermissions(strategy: 'and' | 'or', ...permissions: Permission[][]) {
	const allPermissions = flatten(permissions);

	const mergedPermissions = allPermissions
		.reduce((acc, val) => {
			const key = `${val.collection}__${val.action}`;
			const current = acc.get(key);
			acc.set(key, current ? mergePermission(strategy, current, val) : val);
			return acc;
		}, new Map())
		.values();

	return Array.from(mergedPermissions);
}

export function mergePermission(
	strategy: 'and' | 'or',
	currentPerm: Permission,
	newPerm: Permission,
): Omit<Permission, 'id' | 'system'> {
	const logicalKey = `_${strategy}` as keyof LogicalFilterOR | keyof LogicalFilterAND;

	let { permissions, validation, fields, presets } = currentPerm;

	if (newPerm.permissions) {
		if (currentPerm.permissions && Object.keys(currentPerm.permissions)[0] === logicalKey) {
			permissions = {
				[logicalKey]: [
					...(currentPerm.permissions as LogicalFilterOR & LogicalFilterAND)[logicalKey],
					newPerm.permissions,
				],
			} as LogicalFilterAND | LogicalFilterOR;
		} else if (currentPerm.permissions) {
			// Empty {} supersedes other permissions in _OR merge
			if (strategy === 'or' && (isEqual(currentPerm.permissions, {}) || isEqual(newPerm.permissions, {}))) {
				permissions = {};
			} else {
				permissions = {
					[logicalKey]: [currentPerm.permissions, newPerm.permissions],
				} as LogicalFilterAND | LogicalFilterOR;
			}
		} else {
			permissions = {
				[logicalKey]: [newPerm.permissions],
			} as LogicalFilterAND | LogicalFilterOR;
		}
	}

	if (newPerm.validation) {
		if (currentPerm.validation && Object.keys(currentPerm.validation)[0] === logicalKey) {
			validation = {