@oondemand/oon-core-back 0.3.73 → 0.3.75
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/api/access.routes.js +353 -0
- package/src/api/auth.routes.js +39 -34
- package/src/boot/createApp.js +2 -2
- package/src/core/define.js +5 -1
- package/src/core/factories/modelRouter.js +18 -15
- package/src/core/middlewares/auth.js +35 -2
- package/src/core/middlewares/permissions.js +37 -0
- package/src/core/middlewares/rbac.js +38 -10
- package/src/core/rbac/identityProvider.js +66 -0
- package/src/core/rbac/policy.js +168 -0
- package/src/core/rbac/storage.js +387 -0
- package/src/index.js +8 -0
- package/src/manifest/appManifest.js +26 -104
- package/src/manifest/rbacManifest.js +89 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
CORE_PERMISSIONS,
|
|
5
|
+
isPermission,
|
|
6
|
+
isRoleCode,
|
|
7
|
+
} = require("../core/rbac/policy");
|
|
8
|
+
|
|
9
|
+
function isPlainObject(value) {
|
|
10
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function validateRbac(rbac, issues) {
|
|
14
|
+
if (rbac === undefined) return;
|
|
15
|
+
if (!isPlainObject(rbac)) {
|
|
16
|
+
issues.push({ path: "rbac", message: "deve ser um objeto." });
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const allowedKeys = new Set(["roles", "permissions", "invitationTtlHours"]);
|
|
21
|
+
for (const key of Object.keys(rbac)) {
|
|
22
|
+
if (!allowedKeys.has(key)) issues.push({ path: `rbac.${key}`, message: "propriedade não suportada." });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const customPermissions = Array.isArray(rbac.permissions) ? rbac.permissions : [];
|
|
26
|
+
if (rbac.permissions !== undefined && !Array.isArray(rbac.permissions)) {
|
|
27
|
+
issues.push({ path: "rbac.permissions", message: "deve ser uma lista." });
|
|
28
|
+
}
|
|
29
|
+
const seenPermissions = new Set();
|
|
30
|
+
customPermissions.forEach((permission, index) => {
|
|
31
|
+
if (!isPermission(permission) || permission === "*") {
|
|
32
|
+
issues.push({ path: `rbac.permissions[${index}]`, message: "deve usar o formato recurso.acao." });
|
|
33
|
+
} else if (seenPermissions.has(permission)) {
|
|
34
|
+
issues.push({ path: `rbac.permissions[${index}]`, message: `permissão duplicada: ${permission}.` });
|
|
35
|
+
}
|
|
36
|
+
seenPermissions.add(permission);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (!Array.isArray(rbac.roles) || !rbac.roles.length) {
|
|
40
|
+
issues.push({ path: "rbac.roles", message: "deve conter ao menos um perfil." });
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const catalog = new Set([...CORE_PERMISSIONS, ...customPermissions]);
|
|
45
|
+
const seenRoles = new Set();
|
|
46
|
+
let adminCount = 0;
|
|
47
|
+
rbac.roles.forEach((role, index) => {
|
|
48
|
+
const base = `rbac.roles[${index}]`;
|
|
49
|
+
if (!isPlainObject(role)) {
|
|
50
|
+
issues.push({ path: base, message: "deve ser um objeto." });
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const allowedRoleKeys = new Set(["code", "name", "description", "permissions", "admin"]);
|
|
54
|
+
for (const key of Object.keys(role)) {
|
|
55
|
+
if (!allowedRoleKeys.has(key)) issues.push({ path: `${base}.${key}`, message: "propriedade não suportada." });
|
|
56
|
+
}
|
|
57
|
+
if (!isRoleCode(role.code)) issues.push({ path: `${base}.code`, message: "deve ser um código estável em minúsculas." });
|
|
58
|
+
if (seenRoles.has(role.code)) issues.push({ path: `${base}.code`, message: `perfil duplicado: ${role.code}.` });
|
|
59
|
+
seenRoles.add(role.code);
|
|
60
|
+
if (typeof role.name !== "string" || !role.name.trim()) issues.push({ path: `${base}.name`, message: "é obrigatório." });
|
|
61
|
+
if (role.admin !== undefined && typeof role.admin !== "boolean") issues.push({ path: `${base}.admin`, message: "deve ser booleano." });
|
|
62
|
+
if (!Array.isArray(role.permissions)) {
|
|
63
|
+
issues.push({ path: `${base}.permissions`, message: "deve ser uma lista." });
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const seenRolePermissions = new Set();
|
|
67
|
+
role.permissions.forEach((permission, permissionIndex) => {
|
|
68
|
+
const path = `${base}.permissions[${permissionIndex}]`;
|
|
69
|
+
if (!isPermission(permission)) issues.push({ path, message: "permissão inválida." });
|
|
70
|
+
else if (permission !== "*" && !catalog.has(permission)) issues.push({ path, message: `permissão não declarada: ${permission}.` });
|
|
71
|
+
if (seenRolePermissions.has(permission)) issues.push({ path, message: `permissão duplicada: ${permission}.` });
|
|
72
|
+
seenRolePermissions.add(permission);
|
|
73
|
+
});
|
|
74
|
+
if (role.permissions.includes("*") && role.admin !== true) {
|
|
75
|
+
issues.push({ path: `${base}.admin`, message: "deve ser true quando o perfil usa wildcard (*)." });
|
|
76
|
+
}
|
|
77
|
+
if (role.admin === true || role.permissions.includes("*")) adminCount += 1;
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
if (!adminCount) issues.push({ path: "rbac.roles", message: "deve existir ao menos um perfil administrativo." });
|
|
81
|
+
|
|
82
|
+
if (rbac.invitationTtlHours !== undefined) {
|
|
83
|
+
if (!Number.isInteger(rbac.invitationTtlHours) || rbac.invitationTtlHours < 1 || rbac.invitationTtlHours > 720) {
|
|
84
|
+
issues.push({ path: "rbac.invitationTtlHours", message: "deve ser inteiro entre 1 e 720 horas." });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = { validateRbac };
|