39948-vm/backend/src/services/access-policy-audit.js
2026-06-28 21:29:29 +02:00

154 lines
4.3 KiB
JavaScript

const db = require('../db/models');
class AccessPolicyAuditService {
static async findViolations(options = {}) {
const transaction = options.transaction;
const publicRoles = await db.roles.findAll({
where: { name: 'Public' },
include: [{ association: 'permissions' }],
transaction,
});
const publicRolePermissions = publicRoles.flatMap((role) =>
(role.permissions || []).map((permission) => ({
roleId: role.id,
permissionId: permission.id,
permissionName: permission.name,
})),
);
const publicUsersWithCustomPermissions = await db.users.findAll({
attributes: ['id', 'email'],
include: [
{
association: 'app_role',
attributes: ['id', 'name'],
where: { name: 'Public' },
required: true,
},
{
association: 'custom_permissions',
attributes: ['id', 'name'],
required: true,
},
],
transaction,
});
const productionPresentationAccessForNonPublicUsers =
await db.production_presentation_access.findAll({
attributes: ['id', 'userId', 'projectId'],
include: [
{
association: 'user',
attributes: ['id', 'email'],
required: true,
include: [
{
association: 'app_role',
attributes: ['id', 'name'],
required: false,
},
],
},
{
association: 'project',
attributes: ['id', 'name', 'slug'],
required: false,
},
],
transaction,
});
const nonPublicGrants =
productionPresentationAccessForNonPublicUsers.filter(
(grant) => grant.user?.app_role?.name !== 'Public',
);
return {
publicRolePermissions: publicRolePermissions.map((entry) => ({
roleId: entry.roleId,
id: entry.permissionId,
name: entry.permissionName,
})),
publicUsersWithCustomPermissions: publicUsersWithCustomPermissions.map(
(user) => ({
id: user.id,
email: user.email,
customPermissions: (user.custom_permissions || []).map(
(permission) => ({
id: permission.id,
name: permission.name,
}),
),
}),
),
productionPresentationAccessForNonPublicUsers: nonPublicGrants.map(
(grant) => ({
id: grant.id,
userId: grant.userId,
userEmail: grant.user?.email || null,
userRole: grant.user?.app_role?.name || null,
projectId: grant.projectId,
projectSlug: grant.project?.slug || null,
}),
),
};
}
static hasViolations(report) {
return (
report.publicRolePermissions.length > 0 ||
report.publicUsersWithCustomPermissions.length > 0 ||
report.productionPresentationAccessForNonPublicUsers.length > 0
);
}
static async cleanupViolations(options = {}) {
const transaction = options.transaction;
const report = await this.findViolations({ transaction });
const publicRoleIds = [
...new Set(
report.publicRolePermissions
.map((permission) => permission.roleId)
.filter(Boolean),
),
];
for (const publicRoleId of publicRoleIds) {
const publicRole = await db.roles.findByPk(publicRoleId, { transaction });
if (publicRole) {
await publicRole.setPermissions([], { transaction });
}
}
for (const userReport of report.publicUsersWithCustomPermissions) {
const user = await db.users.findByPk(userReport.id, { transaction });
await user.setCustom_permissions([], { transaction });
}
const grantIds = report.productionPresentationAccessForNonPublicUsers.map(
(grant) => grant.id,
);
if (grantIds.length > 0) {
await db.production_presentation_access.destroy({
where: { id: { [db.Sequelize.Op.in]: grantIds } },
transaction,
});
}
return {
before: report,
removedPublicRolePermissions: report.publicRolePermissions.length,
clearedPublicUserCustomPermissions:
report.publicUsersWithCustomPermissions.length,
removedNonPublicProductionPresentationGrants: grantIds.length,
};
}
}
module.exports = AccessPolicyAuditService;