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

Code before:
import type { Knex } from 'knex';
import { randomUUID } from 'node:crypto';
import { processChunk, toBoolean } from '@directus/utils';
import { flatten, intersection, isEqual, merge, omit } from 'lodash-es';
import { fetchPolicies } from '../../permissions/lib/fetch-policies.js';
import { fetchPermissions } from '../../permissions/lib/fetch-permissions.js';
import { getSchema } from '../../utils/get-schema.js';
import { fetchRolesTree } from '../../permissions/lib/fetch-roles-tree.js';

import type { LogicalFilterAND, LogicalFilterOR, Permission } from '@directus/types';

type RoleAccess = {
	app_access: boolean;
	admin_access: boolean;
	ip_access: string | null;
	enforce_tfa: boolean;
};

// Addapted from https://github.com/directus/directus/blob/141b8adbf4dd8e06530a7929f34e3fc68a522053/api/src/utils/merge-permissions.ts#L4
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;

Review comment (security):
```suggestion
// Adapted from https://github.com/directus/directus/blob/141b8adbf4dd8e06530a7929f34e3fc68a522053/api/src/utils/merge-permissions.ts#L4
```

Code after:
import { processChunk, toBoolean } from '@directus/utils';
import type { Knex } from 'knex';
import { flatten, intersection, isEqual, merge, omit, uniq } from 'lodash-es';
import { randomUUID } from 'node:crypto';
import { fetchPermissions } from '../../permissions/lib/fetch-permissions.js';
import { fetchPolicies } from '../../permissions/lib/fetch-policies.js';
import { fetchRolesTree } from '../../permissions/lib/fetch-roles-tree.js';
import { getSchema } from '../../utils/get-schema.js';

import type { LogicalFilterAND, LogicalFilterOR, Permission } from '@directus/types';

type RoleAccess = {
	app_access: boolean;
	admin_access: boolean;
	ip_access: string | null;
	enforce_tfa: boolean;
};

// Adapted from https://github.com/directus/directus/blob/141b8adbf4dd8e06530a7929f34e3fc68a522053/api/src/utils/merge-permissions.ts#L4
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) {