metis-desk/apps/server/src/access.integration.ts
2026-10-10 12:01:58 +02:00

383 lines
11 KiB
TypeScript

import assert from "node:assert/strict";
import type { AccessFieldsDTO, AccessItemDTO, CompanyDTO } from "@metis/companies/common";
import { AccessResponseSchema } from "@metis/companies/common";
export async function verifyAccess(
request: (path: string, body?: unknown, origin?: string, token?: string) => Promise<Response>,
company: CompanyDTO,
other: CompanyDTO
) {
const base = `/access/${company.id}`;
async function create(scope: string, values: AccessFieldsDTO) {
const response = await request(`/access/${scope}`, { values });
assert.equal(response.status, 201, JSON.stringify(await response.clone().json()));
const result = AccessResponseSchema.parse(await response.json());
const item = result.items.at(-1);
assert.ok(item);
assert.equal(item.values.kind, values.kind);
assert.equal(item.id[14], "7");
assert.equal(item.history.length, 1);
return item;
}
async function update(item: AccessItemDTO, values: AccessFieldsDTO) {
const response = await request(`${base}/${item.id}/update`, { values });
assert.equal(response.status, 200, JSON.stringify(await response.clone().json()));
return AccessResponseSchema.parse(await response.json());
}
const system = await create("global", { kind: "system", name: "Directorio", active: true });
const resourceType = await create("global", {
kind: "resource_type",
name: "Carpeta",
active: true,
});
const permission = await create("global", {
kind: "permission",
name: "Modificar",
description: null,
resourceTypeId: resourceType.id,
active: true,
});
const template = await create("global", {
kind: "template",
name: "Administración",
description: "Acceso a documentos",
systemId: system.id,
active: true,
});
assert.equal(
(await request(base, { values: { kind: "system", name: " DIRECTORIO ", active: false } }))
.status,
409
);
assert.equal(
(
await request(base, {
values: { kind: "system", name: "Zoom", active: true, password: "secret" },
})
).status,
400
);
assert.equal(
(
await request(
base,
{ values: { kind: "system", name: "Zoom", active: true } },
"https://wrong.example"
)
).status,
403
);
assert.equal(
(
await request(
base,
{ values: { kind: "system", name: "Zoom", active: true } },
undefined,
"wrong"
)
).status,
403
);
await create(company.id, { kind: "system", name: "ERP propio", active: true });
assert.equal(
(
await request("/access/global", {
values: { kind: "system", name: "ERP PROPIO", active: true },
})
).status,
409
);
const environment = await create(company.id, {
kind: "environment",
name: "Oficina",
systemId: system.id,
active: true,
});
const otherEnvironment = await create(other.id, {
kind: "environment",
name: "Oficina",
systemId: system.id,
active: true,
});
const accountValues: AccessFieldsDTO = {
kind: "account",
systemId: system.id,
environmentId: environment.id,
login: "ana",
usage: "personal",
active: true,
expiresOn: null,
notes: null,
};
const account = await create(company.id, accountValues);
assert.equal((await request(base, { values: accountValues })).status, 409);
assert.equal(
(
await request(base, {
values: {
...accountValues,
systemId: system.id.toUpperCase(),
environmentId: environment.id.toUpperCase(),
},
})
).status,
409
);
assert.equal(
(
await request(base, {
values: { ...accountValues, login: "foreign", environmentId: otherEnvironment.id },
})
).status,
409
);
assert.equal(
(
await request(`${base}/${account.id}/update`, {
values: { ...accountValues, usage: "shared" },
})
).status,
409
);
const renamed = { ...accountValues, login: "ana.garcia" };
const changed = await update(account, renamed);
assert.equal(changed.items.find((item) => item.id === account.id)?.history.length, 2);
const repeated = await update(account, renamed);
assert.equal(repeated.items.find((item) => item.id === account.id)?.history.length, 2);
const person = company.people.find((item) => item.active);
assert.ok(person);
const relationValues: AccessFieldsDTO = {
kind: "account_person",
accountId: account.id,
personId: person.id,
startDate: "2026-01-01",
endDate: null,
configuration: "configured",
};
const relation = await create(company.id, relationValues);
assert.equal((await request(base, { values: relationValues })).status, 409);
const foreignPerson = other.people[0];
if (foreignPerson) {
assert.equal(
(await request(base, { values: { ...relationValues, personId: foreignPerson.id } })).status,
409
);
}
const groupValues: AccessFieldsDTO = {
kind: "group",
name: "Administración",
identifier: "GG_ADMIN",
systemId: system.id,
environmentId: environment.id,
templateId: template.id,
description: "Documentos",
active: true,
};
const group = await create(company.id, groupValues);
const membershipValues: AccessFieldsDTO = {
kind: "membership",
accountId: account.id,
groupId: group.id,
startDate: "2026-01-01",
endDate: null,
configuration: "configured",
};
const membership = await create(company.id, membershipValues);
const resource = await create(company.id, {
kind: "resource",
name: "Documentos",
resourceTypeId: resourceType.id,
systemId: null,
environmentId: null,
reference: "\\\\NAS\\Administracion",
notes: null,
active: true,
});
const grantValues: AccessFieldsDTO = {
kind: "grant",
resourceId: resource.id,
permissionId: permission.id,
accountId: null,
groupId: group.id,
startDate: "2026-01-01",
endDate: null,
configuration: "configured",
};
const grant = await create(company.id, grantValues);
const needValues: AccessFieldsDTO = {
kind: "need",
resourceId: resource.id,
personId: person.id,
permissionIds: [permission.id],
startDate: "2026-01-01",
endDate: null,
notes: null,
};
const need = await create(company.id, needValues);
let response = AccessResponseSchema.parse(await (await request(base)).json());
assert.equal(response.coverage.find((item) => item.needId === need.id)?.covered, false);
assert.ok(
response.reviews.some((item) => item.itemId === grant.id && item.reason === "unjustified")
);
await create(company.id, {
kind: "coverage",
needId: need.id,
grantId: grant.id,
accountPersonId: relation.id,
membershipId: membership.id,
startDate: "2026-01-01",
endDate: null,
});
response = AccessResponseSchema.parse(await (await request(base)).json());
assert.equal(response.coverage.find((item) => item.needId === need.id)?.covered, true);
assert.equal(
response.reviews.some((item) => item.itemId === grant.id && item.reason === "unjustified"),
false
);
const awaitingConfiguration = await update(relation, {
...relationValues,
configuration: "pending",
});
assert.equal(
awaitingConfiguration.coverage.find((item) => item.needId === need.id)?.covered,
false
);
assert.equal(
awaitingConfiguration.reviews.some(
(item) => item.itemId === grant.id && item.reason === "unjustified"
),
false
);
await update(relation, relationValues);
const readPermission = await create("global", {
kind: "permission",
name: "Lectura",
description: null,
resourceTypeId: resourceType.id,
active: true,
});
const differentNeed = await update(need, { ...needValues, permissionIds: [readPermission.id] });
assert.equal(differentNeed.coverage.find((item) => item.needId === need.id)?.covered, false);
assert.ok(
differentNeed.reviews.some((item) => item.itemId === grant.id && item.reason === "unjustified")
);
await update(need, needValues);
const closed = await update(membership, {
...membershipValues,
endDate: "2026-10-03",
configuration: "removal_pending",
});
assert.equal(closed.coverage.find((item) => item.needId === need.id)?.covered, false);
assert.ok(
closed.reviews.some(
(item) => item.itemId === membership.id && item.reason === "pending_removal"
)
);
const removed = await update(membership, {
...membershipValues,
endDate: "2026-10-03",
configuration: "removed",
});
assert.equal(
removed.reviews.some(
(item) => item.itemId === membership.id && item.reason === "pending_removal"
),
false
);
assert.equal(removed.items.find((item) => item.id === membership.id)?.history.length, 3);
assert.equal(
removed.items
.find((item) => item.id === membership.id)
?.history.every((item) => Boolean(item.actorId)),
true
);
const expired = await update(account, { ...renamed, expiresOn: "2000-01-01" });
assert.ok(
expired.reviews.some((item) => item.itemId === account.id && item.reason === "expired")
);
assert.equal(
(await request(base, { values: { ...membershipValues, startDate: "2026-10-03" } })).status,
409
);
const technical = await create(company.id, {
...accountValues,
login: "svc-backup",
usage: "technical",
active: false,
expiresOn: "2000-01-01",
});
await create(company.id, { ...relationValues, accountId: technical.id, configuration: null });
const otherTechnical = await create(company.id, {
...accountValues,
login: "svc-clean",
usage: "technical",
active: true,
});
assert.equal(
(
await request(base, {
values: { ...relationValues, accountId: otherTechnical.id, configuration: "configured" },
})
).status,
400
);
const shared = await create(company.id, { ...accountValues, login: "shared", usage: "shared" });
const sharedResponse = AccessResponseSchema.parse(await (await request(base)).json());
assert.ok(
sharedResponse.reviews.some((item) => item.itemId === shared.id && item.reason === "incomplete")
);
const concurrent = await Promise.all([
request(base, { values: { ...accountValues, login: "concurrent" } }),
request(base, { values: { ...accountValues, login: "concurrent" } }),
]);
assert.deepEqual(concurrent.map((item) => item.status).sort(), [201, 409]);
const otherScope = AccessResponseSchema.parse(
await (await request(`/access/${other.id}`)).json()
);
assert.equal(
otherScope.items.some((item) => item.id === account.id),
false
);
assert.equal(
otherScope.items.some((item) => item.id === system.id),
true
);
const global = AccessResponseSchema.parse(await (await request("/access/global")).json());
assert.equal(
global.items.every((item) => item.companyId === null),
true
);
assert.equal(
(await request(`/access/${other.id}/${account.id}/update`, { values: renamed })).status,
404
);
}