@ozdao/martyrs 0.2.563 → 0.2.565
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/dist/abac-BPl9Bmf9.js +1527 -0
- package/dist/builder.js +51 -39
- package/dist/{common.schema-GFSlNJo7.js → common.schema-DswiUXKB.js} +1 -1
- package/dist/community.server.js +48 -9
- package/dist/core.server.js +6 -4
- package/dist/{crud-C7FSTUes.js → crud-q1ye5IhV.js} +7 -7
- package/dist/events.server.js +3 -3
- package/dist/gallery.server.js +2 -2
- package/dist/inventory.server.js +4 -6
- package/dist/{main-CmjWiDVF.js → main-B9o1iBAZ.js} +1279 -1287
- package/dist/marketplace.server.js +1 -1
- package/dist/martyrs/src/components/Button/Button.vue2.js +33 -42
- package/dist/martyrs/src/components/Button/Button.vue2.js.map +1 -1
- package/dist/martyrs/src/components/EditImages/{EditImages.vue.js → EditImages.vue2.js} +2 -2
- package/dist/martyrs/src/components/EditImages/EditImages.vue2.js.map +1 -0
- package/dist/martyrs/src/components/Feed/Feed.vue.js +1 -1
- package/dist/martyrs/src/components/FieldPhone/FieldPhone.vue.js +1 -1
- package/dist/martyrs/src/components/FieldPhone/FieldPhone.vue.js.map +1 -1
- package/dist/martyrs/src/components/Loader/Loader.vue.js +1 -2
- package/dist/martyrs/src/components/Loader/Loader.vue.js.map +1 -1
- package/dist/martyrs/src/components/Menu/{Menu.vue.js → Menu.vue2.js} +2 -2
- package/dist/martyrs/src/components/Menu/Menu.vue2.js.map +1 -0
- package/dist/martyrs/src/components/Tab/{Tab.vue.js → Tab.vue2.js} +2 -2
- package/dist/martyrs/src/components/Tab/Tab.vue2.js.map +1 -0
- package/dist/martyrs/src/components/Tree/Tree.vue.js +6 -3
- package/dist/martyrs/src/components/Tree/Tree.vue.js.map +1 -1
- package/dist/martyrs/src/modules/auth/auth.client.js +10 -7
- package/dist/martyrs/src/modules/auth/auth.client.js.map +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/EnterPassword.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/Invite.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/ProfileBlogposts.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/ResetPassword.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/SignIn.vue.js +12 -12
- package/dist/martyrs/src/modules/auth/views/components/pages/SignIn.vue.js.map +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/SignUp.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/router/auth.router.js +116 -0
- package/dist/martyrs/src/modules/auth/views/router/auth.router.js.map +1 -0
- package/dist/martyrs/src/modules/auth/views/router/users.router.js +180 -0
- package/dist/martyrs/src/modules/auth/views/router/users.router.js.map +1 -0
- package/dist/martyrs/src/modules/backoffice/components/partials/Sidebar.vue.js +3 -3
- package/dist/martyrs/src/modules/backoffice/components/partials/Sidebar.vue.js.map +1 -1
- package/dist/martyrs/src/modules/core/locales/en.js +45 -0
- package/dist/martyrs/src/modules/core/locales/en.js.map +1 -1
- package/dist/martyrs/src/modules/core/locales/ru.js +45 -0
- package/dist/martyrs/src/modules/core/locales/ru.js.map +1 -1
- package/dist/martyrs/src/modules/core/views/classes/i18n.manager.js +9 -0
- package/dist/martyrs/src/modules/core/views/classes/i18n.manager.js.map +1 -1
- package/dist/martyrs/src/modules/core/views/components/sections/{Filters.vue.js → Filters.vue2.js} +2 -2
- package/dist/martyrs/src/modules/core/views/components/sections/Filters.vue2.js.map +1 -0
- package/dist/martyrs/src/modules/core/views/components/sections/SectionPageTitle.vue.js +1 -1
- package/dist/martyrs/src/modules/core/views/mixins/mixins.js +1 -2
- package/dist/martyrs/src/modules/core/views/mixins/mixins.js.map +1 -1
- package/dist/martyrs/src/modules/core/views/router/addRoutes.js +6 -1
- package/dist/martyrs/src/modules/core/views/router/addRoutes.js.map +1 -1
- package/dist/martyrs/src/modules/events/components/pages/EditEvent.vue.js +1 -1
- package/dist/martyrs/src/modules/events/components/pages/Event.vue.js +1 -1
- package/dist/martyrs/src/modules/events/components/pages/EventsBackoffice.vue.js +1 -1
- package/dist/martyrs/src/modules/gallery/components/sections/BackofficeGallery.vue.js +1 -1
- package/dist/martyrs/src/modules/inventory/components/pages/InventoryEdit.vue.js +2 -2
- package/dist/martyrs/src/modules/inventory/components/pages/InventoryEdit.vue.js.map +1 -1
- package/dist/martyrs/src/modules/marketplace/views/components/pages/Marketplace.vue.js +1 -1
- package/dist/martyrs/src/modules/marketplace/views/store/marketplace.js +0 -16
- package/dist/martyrs/src/modules/marketplace/views/store/marketplace.js.map +1 -1
- package/dist/martyrs/src/modules/notifications/components/elements/NotificationBadge.vue.js +4 -4
- package/dist/martyrs/src/modules/notifications/components/elements/NotificationBadge.vue.js.map +1 -1
- package/dist/martyrs/src/modules/notifications/components/pages/Notifications.vue.js +1 -1
- package/dist/martyrs/src/modules/orders/components/elements/FieldSubscribeNewsletter.vue.js +3 -0
- package/dist/martyrs/src/modules/orders/components/elements/FieldSubscribeNewsletter.vue.js.map +1 -1
- package/dist/martyrs/src/modules/orders/components/pages/OrderCreateBackoffice.vue.js +1 -1
- package/dist/martyrs/src/modules/orders/components/pages/Orders.vue.js +1 -1
- package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/blocks/CardOrganization.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/blocks/CardOrganization.vue.js.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/Organization.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/OrganizationBackoffice.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/OrganizationEdit.vue.js +2 -2
- package/dist/martyrs/src/modules/organizations/components/pages/OrganizationEdit.vue.js.map +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/Organizations.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/sections/Organizations.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/blocks/CardCategory.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/blocks/CardCategory.vue.js.map +1 -1
- package/dist/martyrs/src/modules/products/components/blocks/CardProduct.vue.js +15 -2
- package/dist/martyrs/src/modules/products/components/blocks/CardProduct.vue.js.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/Categories.vue.js +9 -6
- package/dist/martyrs/src/modules/products/components/pages/Categories.vue.js.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js +4 -3
- package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/Product.vue.js +11 -2
- package/dist/martyrs/src/modules/products/components/pages/Product.vue.js.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.js +2 -2
- package/dist/martyrs/src/modules/products/components/pages/Products.vue.js +2 -2
- package/dist/martyrs/src/modules/products/components/sections/EditVariants.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/sections/SectionProduct.vue.js +11 -8
- package/dist/martyrs/src/modules/products/components/sections/SectionProduct.vue.js.map +1 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/Gant/GanttToolbar.vue.js +1 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/Rents.vue.js +1 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/RentsEdit.vue.js +210 -60
- package/dist/martyrs/src/modules/rents/views/components/pages/RentsEdit.vue.js.map +1 -1
- package/dist/martyrs/src/modules/spots/components/pages/Map.vue.js +3 -3
- package/dist/martyrs/src/modules/spots/components/pages/Map.vue.js.map +1 -1
- package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.js +1 -1
- package/dist/martyrs.css +1 -1
- package/dist/martyrs.es.js +1 -1
- package/dist/music.server.js +11 -12
- package/dist/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/utils.js +1 -1
- package/dist/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/utils.js +1 -1
- package/dist/notifications.server.js +0 -3
- package/dist/orders.server.js +5 -6
- package/dist/organizations.server.js +9 -10
- package/dist/products.server.js +27 -26
- package/dist/{queryProcessor-CBQgZycY.js → queryProcessor-C_5Iipam.js} +4 -1
- package/dist/rents.server.js +2 -3
- package/dist/spots.server.js +1 -1
- package/dist/style.css +38 -23
- package/dist/{web-cNKIl_cL.js → web-BF3ijvEr.js} +1 -1
- package/package.json +1 -1
- package/src/builder/modes/ssr.rspack.dev.js +4 -3
- package/src/builder/rspack/rspack.config.api.js +15 -4
- package/src/builder/rspack/rspack.config.base.js +3 -3
- package/src/builder/rspack/rspack.config.ssr.client.js +28 -28
- package/src/builder/templates/page.js +2 -2
- package/src/components/Button/Button.vue +50 -37
- package/src/components/FieldPhone/FieldPhone.vue +1 -1
- package/src/components/Loader/Loader.vue +1 -1
- package/src/components/Tree/Tree.vue +6 -3
- package/src/modules/PROCESS.md +0 -0
- package/src/modules/TASKS.MD +17 -0
- package/src/modules/auth/auth.client.js +11 -7
- package/src/modules/auth/views/components/pages/SignIn.vue +1 -1
- package/src/modules/auth/views/router/auth.router.js +94 -0
- package/src/modules/auth/views/router/users.router.js +153 -0
- package/src/modules/backoffice/components/partials/Sidebar.vue +7 -7
- package/src/modules/community/community.server.js +8 -0
- package/src/modules/community/policies/blog.policies.js +55 -0
- package/src/modules/community/routes/blog.routes.js +1 -1
- package/src/modules/community/routes/comments.routes.js +1 -1
- package/src/modules/community/routes/reactions.routes.js +1 -4
- package/src/modules/core/controllers/classes/abac/abac.adapter.express.js +206 -124
- package/src/modules/core/controllers/classes/abac/abac.adapter.ws.js +203 -50
- package/src/modules/core/controllers/classes/abac/abac.core.js +127 -36
- package/src/modules/core/controllers/classes/abac/abac.fields.js +144 -179
- package/src/modules/core/controllers/classes/abac/abac.js +201 -10
- package/src/modules/core/controllers/classes/abac/abac.policies.js +147 -57
- package/src/modules/core/controllers/classes/crud/crud.policies.js +5 -5
- package/src/modules/core/controllers/policies/core.policies.js +5 -2
- package/src/modules/core/controllers/utils/queryProcessor.js +4 -1
- package/src/modules/core/core.server.js +1 -0
- package/src/modules/core/locales/en.js +45 -0
- package/src/modules/core/locales/ru.js +45 -0
- package/src/modules/core/models/schemas/common.schema.js +1 -1
- package/src/modules/core/views/classes/i18n.manager.js +13 -0
- package/src/modules/core/views/components/sections/filters/FilterPrice.vue +81 -0
- package/src/modules/core/views/mixins/mixins.js +1 -2
- package/src/modules/core/views/router/addRoutes.js +6 -1
- package/src/modules/events/routes/events.routes.js +1 -1
- package/src/modules/inventory/components/pages/InventoryEdit.vue +3 -3
- package/src/modules/inventory/policies/inventory.policies.js +1 -1
- package/src/modules/inventory/routes/inventory.routes.js +1 -1
- package/src/modules/marketplace/marketplace.router.js +66 -0
- package/src/modules/marketplace/views/components/layouts/Marketplace.vue +363 -0
- package/src/modules/marketplace/views/components/pages/Catalog.vue +73 -0
- package/src/modules/marketplace/views/store/marketplace.js +0 -16
- package/src/modules/music/controllers/stream.controller.js +1 -1
- package/src/modules/music/music.server.js +1 -1
- package/src/modules/music/policies/music.policies.js +3 -2
- package/src/modules/music/router/library.router.js +26 -0
- package/src/modules/music/router/music.router.js +176 -0
- package/src/modules/notifications/components/elements/NotificationBadge.vue +5 -6
- package/src/modules/notifications/notifications.server.js +1 -3
- package/src/modules/orders/components/elements/FieldSubscribeNewsletter.vue +5 -0
- package/src/modules/orders/orders.server.js +0 -1
- package/src/modules/organizations/components/blocks/CardOrganization.vue +2 -2
- package/src/modules/organizations/components/pages/DepartmentEdit.vue +2 -2
- package/src/modules/organizations/components/pages/OrganizationEdit.vue +2 -2
- package/src/modules/organizations/policies/organizations.policies.js +12 -6
- package/src/modules/organizations/routes/organizations.routes.js +1 -3
- package/src/modules/products/components/blocks/CardCategory.vue +1 -1
- package/src/modules/products/components/blocks/CardProduct.vue +16 -2
- package/src/modules/products/components/pages/Categories.vue +9 -6
- package/src/modules/products/components/pages/CategoryEdit.vue +8 -4
- package/src/modules/products/components/pages/Product.vue +11 -5
- package/src/modules/products/components/sections/SectionProduct.vue +11 -7
- package/src/modules/products/controllers/categories.controller.js +32 -27
- package/src/modules/products/routes/categories.routes.js +1 -1
- package/src/modules/rents/controllers/routes/rents.routes.js +1 -1
- package/src/modules/rents/views/components/pages/RentsEdit.vue +208 -49
- package/src/modules/spots/components/pages/Map.vue +2 -2
- package/dist/abac-DYoheWuc.js +0 -1031
- package/dist/core.abac-DUPBnlk6.js +0 -298
- package/dist/core.logger-C3q8A9dl.js +0 -51
- package/dist/martyrs/src/components/EditImages/EditImages.vue.js.map +0 -1
- package/dist/martyrs/src/components/Menu/Menu.vue.js.map +0 -1
- package/dist/martyrs/src/components/Tab/Tab.vue.js.map +0 -1
- package/dist/martyrs/src/modules/auth/auth.router.js +0 -342
- package/dist/martyrs/src/modules/auth/auth.router.js.map +0 -1
- package/dist/martyrs/src/modules/core/views/components/sections/Filters.vue.js.map +0 -1
- package/src/modules/auth/auth.router.js +0 -262
- package/src/modules/core/controllers/classes/abac/v2/abac-core-fixed.js +0 -313
- package/src/modules/core/controllers/classes/abac/v2/abac-express-fixed.js +0 -276
- package/src/modules/core/controllers/classes/abac/v2/abac-fields-fixed.js +0 -425
- package/src/modules/core/controllers/classes/abac/v2/abac-main-fixed.js +0 -295
- package/src/modules/core/controllers/classes/abac/v2/abac-policies-fixed.js +0 -316
- package/src/modules/core/controllers/classes/abac/v2/abac-ws-fixed.js +0 -237
- package/src/modules/core/controllers/classes/core.abac.js +0 -310
- package/src/modules/core/controllers/classes/core.crud.js +0 -89
- package/src/modules/governance/reactcode/eslint.config.js +0 -28
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
// @martyrs/src/modules/core/controllers/classes/core.abac.js
|
|
2
|
-
import Cache from '@martyrs/src/modules/core/controllers/classes/core.cache.js';
|
|
3
|
-
import Logger from '@martyrs/src/modules/core/controllers/classes/core.logger.js';
|
|
4
|
-
|
|
5
|
-
import ABACCore from './abac/abac.core.js';
|
|
6
|
-
import ABACPolicies from './abac/abac.policies.js';
|
|
7
|
-
import ABACFields from './abac/abac.fields.js';
|
|
8
|
-
|
|
9
|
-
import ABACExpressAdapter from './abac/abac.adapter.express.js';
|
|
10
|
-
import ABACWebSocketAdapter from './abac/abac.adapter.ws.js';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @typedef {Object} ABACOptions
|
|
14
|
-
* @property {boolean} [strictMode=false] - Строгий режим (undefined = deny)
|
|
15
|
-
* @property {boolean} [defaultDeny=false] - Запрет по умолчанию
|
|
16
|
-
* @property {string} [serviceKey] - Ключ для сервисных запросов
|
|
17
|
-
* @property {boolean} [enableAudit=true] - Включить аудит
|
|
18
|
-
* @property {boolean} [cacheEnabled=true] - Включить кэширование
|
|
19
|
-
* @property {number} [cacheTTL=300] - TTL кэша в секундах
|
|
20
|
-
* @property {number} [concurrencyLimit=10] - Лимит параллельных политик
|
|
21
|
-
* @property {Object} [logger] - Кастомный логгер
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* @typedef {Object} ABACContext
|
|
26
|
-
* @property {string|null} user - ID пользователя
|
|
27
|
-
* @property {string} action - Действие (read, create, update, delete, etc)
|
|
28
|
-
* @property {string} resource - Тип ресурса
|
|
29
|
-
* @property {Object} [currentResource] - Загруженный ресурс
|
|
30
|
-
* @property {string} [resourceId] - ID ресурса
|
|
31
|
-
* @property {Object} data - Данные запроса
|
|
32
|
-
* @property {Object} [data.body] - Body запроса (Express)
|
|
33
|
-
* @property {Object} [data.query] - Query параметры (Express)
|
|
34
|
-
* @property {Object} [data.params] - Route параметры (Express)
|
|
35
|
-
* @property {Object} [req] - Express request
|
|
36
|
-
* @property {Object} [socket] - WebSocket соединение
|
|
37
|
-
* @property {Object} [params] - Route параметры
|
|
38
|
-
* @property {boolean} [skipFieldPolicies=false] - Пропустить проверку полей
|
|
39
|
-
* @property {Object} [options] - Дополнительные опции
|
|
40
|
-
*/
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* @typedef {Object} ABACResult
|
|
44
|
-
* @property {boolean} allow - Разрешен ли доступ
|
|
45
|
-
* @property {string} reason - Причина решения
|
|
46
|
-
* @property {Array} [policies] - Примененные политики
|
|
47
|
-
*/
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* @typedef {Object} FieldsResult
|
|
51
|
-
* @property {Object} allowed - Разрешенные данные
|
|
52
|
-
* @property {Array} denied - Запрещенные поля
|
|
53
|
-
* @property {Array} errors - Ошибки валидации
|
|
54
|
-
* @property {Object} transformed - Трансформированные данные
|
|
55
|
-
*/
|
|
56
|
-
|
|
57
|
-
class GlobalABAC {
|
|
58
|
-
constructor(db, options = {}) {
|
|
59
|
-
this.db = db;
|
|
60
|
-
|
|
61
|
-
/** @type {ABACOptions} */
|
|
62
|
-
this.options = {
|
|
63
|
-
strictMode: false,
|
|
64
|
-
defaultDeny: false,
|
|
65
|
-
serviceKey: process.env.SERVICE_KEY,
|
|
66
|
-
enableAudit: true,
|
|
67
|
-
cacheEnabled: true,
|
|
68
|
-
cacheTTL: 300,
|
|
69
|
-
concurrencyLimit: 10,
|
|
70
|
-
...options,
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
// Инициализация компонентов
|
|
74
|
-
this.cache = new Cache({ ttlSeconds: this.options.cacheTTL });
|
|
75
|
-
this.logger = this.options.logger || new Logger(db);
|
|
76
|
-
|
|
77
|
-
// Инициализация модулей
|
|
78
|
-
this.core = new ABACCore(this);
|
|
79
|
-
this.policies = new ABACPolicies(this);
|
|
80
|
-
this.fields = new ABACFields(this);
|
|
81
|
-
this.express = new ABACExpressAdapter(this);
|
|
82
|
-
this.websocket = new ABACWebSocketAdapter(this);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Регистрация глобальной политики
|
|
87
|
-
* @param {string} name - Имя политики
|
|
88
|
-
* @param {Function} policyFn - Функция политики (context) => boolean|{allow, force, reason}
|
|
89
|
-
* @param {Object} [metadata] - Метаданные политики
|
|
90
|
-
* @param {string} [metadata.type='dynamic'] - Тип (static|dynamic)
|
|
91
|
-
* @param {number} [metadata.priority=0] - Приоритет
|
|
92
|
-
* @returns {GlobalABAC}
|
|
93
|
-
*/
|
|
94
|
-
registerGlobalPolicy(name, policyFn, metadata = {}) {
|
|
95
|
-
return this.policies.registerGlobalPolicy(name, policyFn, metadata);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Регистрация политики для ресурса
|
|
100
|
-
* @param {string} resourceName - Имя ресурса
|
|
101
|
-
* @param {Function} policyFn - Функция политики
|
|
102
|
-
* @param {Object} [options] - Опции
|
|
103
|
-
* @param {string} [options.modelName] - Имя модели в БД
|
|
104
|
-
* @returns {GlobalABAC}
|
|
105
|
-
*/
|
|
106
|
-
registerResourcePolicy(resourceName, policyFn, options = {}) {
|
|
107
|
-
return this.policies.registerResourcePolicy(resourceName, policyFn, options);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Регистрация политики полей
|
|
112
|
-
* @param {string} resourceName - Имя ресурса
|
|
113
|
-
* @param {Object} config - Конфигурация полей
|
|
114
|
-
* @returns {GlobalABAC}
|
|
115
|
-
*
|
|
116
|
-
* @example
|
|
117
|
-
* abac.registerFieldsPolicy('user', {
|
|
118
|
-
* 'email': { access: 'deny', actions: ['update'] },
|
|
119
|
-
* 'password': { access: 'deny', actions: '*', rule: 'remove' },
|
|
120
|
-
* 'profile.*': {
|
|
121
|
-
* access: async (ctx) => ctx.user === ctx.currentResource?.id,
|
|
122
|
-
* transform: (value) => sanitize(value)
|
|
123
|
-
* }
|
|
124
|
-
* });
|
|
125
|
-
*/
|
|
126
|
-
registerFieldsPolicy(resourceName, config) {
|
|
127
|
-
return this.fields.registerFieldsPolicy(resourceName, config);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Регистрация расширения контекста
|
|
132
|
-
* @param {string} moduleName - Имя модуля
|
|
133
|
-
* @param {Function} extensionFn - Функция расширения (context) => void
|
|
134
|
-
* @returns {GlobalABAC}
|
|
135
|
-
*/
|
|
136
|
-
registerExtension(moduleName, extensionFn) {
|
|
137
|
-
return this.policies.registerExtension(moduleName, extensionFn);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Проверка доступа
|
|
142
|
-
* @param {ABACContext|Object} context - Контекст проверки
|
|
143
|
-
* @param {Object} [customPolicies] - Дополнительные политики
|
|
144
|
-
* @returns {Promise<ABACResult>}
|
|
145
|
-
*/
|
|
146
|
-
async checkAccess(context, customPolicies = {}) {
|
|
147
|
-
return this.core.checkAccess(context, customPolicies);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Проверка доступа к полям
|
|
152
|
-
* @param {ABACContext|Object} context - Контекст
|
|
153
|
-
* @param {Object} data - Данные для проверки
|
|
154
|
-
* @param {string} [action] - Действие
|
|
155
|
-
* @returns {Promise<FieldsResult>}
|
|
156
|
-
*/
|
|
157
|
-
async checkFields(context, data, action = null) {
|
|
158
|
-
return this.fields.checkFields(context, data, action);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Проверка конкретных политик
|
|
163
|
-
* @param {ABACContext|Object} context - Контекст
|
|
164
|
-
* @param {string[]} policyNames - Имена политик
|
|
165
|
-
* @param {Object} [customPolicies] - Дополнительные политики
|
|
166
|
-
* @returns {Promise<ABACResult>}
|
|
167
|
-
*/
|
|
168
|
-
async checkPolicies(context, policyNames = [], customPolicies = {}) {
|
|
169
|
-
return this.policies.checkPolicies(context, policyNames, customPolicies);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Express middleware для проверки доступа
|
|
174
|
-
* @param {string} resource - Ресурс
|
|
175
|
-
* @param {string} action - Действие
|
|
176
|
-
* @param {Object} [options] - Опции
|
|
177
|
-
* @returns {Function|Function[]} Middleware функция(и)
|
|
178
|
-
*/
|
|
179
|
-
middleware(resource, action, options = {}) {
|
|
180
|
-
return this.express.middleware(resource, action, options);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Express middleware для проверки политик
|
|
185
|
-
* @param {string[]} policyNames - Имена политик
|
|
186
|
-
* @param {Object} [customPolicies] - Дополнительные политики
|
|
187
|
-
* @param {Object} [options] - Опции
|
|
188
|
-
* @returns {Function} Middleware функция
|
|
189
|
-
*/
|
|
190
|
-
policyMiddleware(policyNames = [], customPolicies = {}, options = {}) {
|
|
191
|
-
return this.express.policyMiddleware(policyNames, customPolicies, options);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Express middleware для проверки полей
|
|
196
|
-
* @param {string} resource - Ресурс
|
|
197
|
-
* @param {Object} [options] - Опции
|
|
198
|
-
* @returns {Function} Middleware функция
|
|
199
|
-
*/
|
|
200
|
-
fieldsMiddleware(resource, options = {}) {
|
|
201
|
-
return this.express.fieldsMiddleware(resource, options);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* WebSocket handler
|
|
206
|
-
* @param {string} moduleName - Имя модуля
|
|
207
|
-
* @param {Object} [options] - Опции
|
|
208
|
-
* @returns {Function} Handler функция
|
|
209
|
-
*/
|
|
210
|
-
wsHandler(moduleName, options = {}) {
|
|
211
|
-
return this.websocket.handler(moduleName, options);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Получение модели ресурса из БД
|
|
216
|
-
* @param {string} resourceName - Имя ресурса
|
|
217
|
-
* @returns {Object|null} Mongoose модель или null
|
|
218
|
-
*/
|
|
219
|
-
getResourceModel(resourceName) {
|
|
220
|
-
const resourcePolicy = this.policies.resources.get(resourceName);
|
|
221
|
-
if (!resourcePolicy) return null;
|
|
222
|
-
|
|
223
|
-
const modelName = resourcePolicy.modelName || resourceName;
|
|
224
|
-
return this.db[modelName] || null;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Очистка кэша
|
|
229
|
-
* @param {Object} [options] - Опции очистки
|
|
230
|
-
* @param {string} [options.user] - Очистить для пользователя
|
|
231
|
-
* @param {string} [options.resource] - Очистить для ресурса
|
|
232
|
-
* @param {string} [options.policy] - Очистить для политики
|
|
233
|
-
*/
|
|
234
|
-
async clearCache(options = {}) {
|
|
235
|
-
if (options.user) {
|
|
236
|
-
await this.cache.invalidateTag(`user_${options.user}`);
|
|
237
|
-
}
|
|
238
|
-
if (options.resource) {
|
|
239
|
-
await this.cache.invalidateTag(`resource_${options.resource}`);
|
|
240
|
-
}
|
|
241
|
-
if (options.policy) {
|
|
242
|
-
await this.cache.invalidateTag(`policy_${options.policy}`);
|
|
243
|
-
}
|
|
244
|
-
if (!options.user && !options.resource && !options.policy) {
|
|
245
|
-
await this.cache.clear();
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* Получение статистики
|
|
251
|
-
* @returns {Object} Статистика системы
|
|
252
|
-
*/
|
|
253
|
-
getStats() {
|
|
254
|
-
return {
|
|
255
|
-
policies: {
|
|
256
|
-
global: this.policies.global.size,
|
|
257
|
-
resources: this.policies.resources.size,
|
|
258
|
-
extensions: this.policies.extensions.size
|
|
259
|
-
},
|
|
260
|
-
fields: {
|
|
261
|
-
configs: this.fields.configs.size
|
|
262
|
-
},
|
|
263
|
-
cache: {
|
|
264
|
-
size: this.cache.size,
|
|
265
|
-
hits: this.cache.hits,
|
|
266
|
-
misses: this.cache.misses
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// Экспорт синглтона
|
|
273
|
-
let instance = null;
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Получение экземпляра ABAC
|
|
277
|
-
* @param {Object} db - База данных
|
|
278
|
-
* @param {ABACOptions} [options] - Опции
|
|
279
|
-
* @returns {GlobalABAC}
|
|
280
|
-
*/
|
|
281
|
-
export const getInstance = (db, options) => {
|
|
282
|
-
if (!instance) {
|
|
283
|
-
instance = new GlobalABAC(db, options);
|
|
284
|
-
}
|
|
285
|
-
return instance;
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Сброс экземпляра (для тестов)
|
|
290
|
-
*/
|
|
291
|
-
export const resetInstance = () => {
|
|
292
|
-
instance = null;
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
export default { getInstance, resetInstance };
|
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
// @martyrs/src/modules/core/controllers/classes/abac/abac.policies.js
|
|
2
|
-
export default class ABACPolicies {
|
|
3
|
-
constructor(abac) {
|
|
4
|
-
this.abac = abac;
|
|
5
|
-
this.global = new Map();
|
|
6
|
-
this.resources = new Map();
|
|
7
|
-
this.extensions = new Map();
|
|
8
|
-
this.priorities = {
|
|
9
|
-
static: [],
|
|
10
|
-
dynamic: [],
|
|
11
|
-
extensions: []
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Регистрация глобальной политики
|
|
17
|
-
*/
|
|
18
|
-
registerGlobalPolicy(name, policyFn, metadata = {}) {
|
|
19
|
-
if (typeof policyFn !== 'function') {
|
|
20
|
-
throw new Error(`Global policy "${name}" must be a function`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const policy = {
|
|
24
|
-
fn: policyFn,
|
|
25
|
-
type: metadata.type || 'dynamic',
|
|
26
|
-
priority: metadata.priority || 0,
|
|
27
|
-
...metadata
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
this.global.set(name, policy);
|
|
31
|
-
this.updatePriorities();
|
|
32
|
-
return this.abac;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Регистрация политики ресурса
|
|
37
|
-
*/
|
|
38
|
-
registerResourcePolicy(resourceName, policyFn, options = {}) {
|
|
39
|
-
if (typeof policyFn !== 'function') {
|
|
40
|
-
throw new Error(`Resource policy for "${resourceName}" must be a function`);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
this.resources.set(resourceName, {
|
|
44
|
-
fn: policyFn,
|
|
45
|
-
modelName: options.modelName || options.model || resourceName,
|
|
46
|
-
...options
|
|
47
|
-
});
|
|
48
|
-
return this.abac;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Регистрация расширения
|
|
53
|
-
*/
|
|
54
|
-
registerExtension(moduleName, extensionFn) {
|
|
55
|
-
if (typeof extensionFn !== 'function') {
|
|
56
|
-
throw new Error(`Extension "${moduleName}" must be a function`);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
this.extensions.set(moduleName, extensionFn);
|
|
60
|
-
this.updatePriorities();
|
|
61
|
-
return this.abac;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Обновление приоритетов с сортировкой
|
|
66
|
-
*/
|
|
67
|
-
updatePriorities() {
|
|
68
|
-
this.priorities = {
|
|
69
|
-
static: [],
|
|
70
|
-
dynamic: [],
|
|
71
|
-
extensions: []
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
// Группируем и сортируем по приоритету
|
|
75
|
-
for (const [name, policy] of this.global) {
|
|
76
|
-
const type = policy.type || 'dynamic';
|
|
77
|
-
this.priorities[type].push([name, policy]);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Сортировка по приоритету (выше = раньше)
|
|
81
|
-
this.priorities.static.sort((a, b) => (b[1].priority || 0) - (a[1].priority || 0));
|
|
82
|
-
this.priorities.dynamic.sort((a, b) => (b[1].priority || 0) - (a[1].priority || 0));
|
|
83
|
-
|
|
84
|
-
// Добавляем расширения
|
|
85
|
-
this.priorities.extensions = Array.from(this.extensions.entries());
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Основная логика оценки политик
|
|
90
|
-
*/
|
|
91
|
-
async evaluate(context, customPolicies = {}) {
|
|
92
|
-
const core = this.abac.core;
|
|
93
|
-
|
|
94
|
-
// Структура для отслеживания результатов
|
|
95
|
-
const evaluation = {
|
|
96
|
-
hasForceAllow: false,
|
|
97
|
-
hasForceDisallow: false,
|
|
98
|
-
hasDeny: false,
|
|
99
|
-
denyReason: '',
|
|
100
|
-
allowReason: '',
|
|
101
|
-
appliedPolicies: []
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
// Функция для обработки результата политики
|
|
105
|
-
const processResult = (name, result) => {
|
|
106
|
-
evaluation.appliedPolicies.push({ name, result });
|
|
107
|
-
|
|
108
|
-
if (result.force) {
|
|
109
|
-
if (result.allow) {
|
|
110
|
-
evaluation.hasForceAllow = true;
|
|
111
|
-
evaluation.allowReason = result.reason;
|
|
112
|
-
} else {
|
|
113
|
-
evaluation.hasForceDisallow = true;
|
|
114
|
-
evaluation.denyReason = result.reason;
|
|
115
|
-
}
|
|
116
|
-
} else if (!result.allow) {
|
|
117
|
-
evaluation.hasDeny = true;
|
|
118
|
-
if (!evaluation.denyReason) {
|
|
119
|
-
evaluation.denyReason = result.reason;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
// Функция для проверки force флагов
|
|
125
|
-
const checkForceFlags = () => {
|
|
126
|
-
if (evaluation.hasForceDisallow) {
|
|
127
|
-
return {
|
|
128
|
-
allow: false,
|
|
129
|
-
reason: evaluation.denyReason || 'FORCE_DENIED_BY_POLICY',
|
|
130
|
-
policies: evaluation.appliedPolicies
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (evaluation.hasForceAllow) {
|
|
135
|
-
return {
|
|
136
|
-
allow: true,
|
|
137
|
-
reason: evaluation.allowReason || 'FORCE_ALLOWED_BY_POLICY',
|
|
138
|
-
policies: evaluation.appliedPolicies
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return null;
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
// 1. Static политики (с early exit)
|
|
146
|
-
const staticResults = await core.executePoliciesLimited(
|
|
147
|
-
this.priorities.static,
|
|
148
|
-
context,
|
|
149
|
-
true // останавливаемся на deny
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
for (const { name, result, error } of staticResults) {
|
|
153
|
-
if (!error) {
|
|
154
|
-
processResult(name, result);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
let forceResult = checkForceFlags();
|
|
159
|
-
if (forceResult) return forceResult;
|
|
160
|
-
|
|
161
|
-
// 2. Dynamic политики + custom
|
|
162
|
-
const dynamicPolicies = [...this.priorities.dynamic];
|
|
163
|
-
|
|
164
|
-
// Добавляем кастомные политики
|
|
165
|
-
for (const [name, fn] of Object.entries(customPolicies)) {
|
|
166
|
-
dynamicPolicies.push([name, { fn, type: 'dynamic' }]);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const dynamicResults = await core.executePoliciesLimited(
|
|
170
|
-
dynamicPolicies,
|
|
171
|
-
context,
|
|
172
|
-
false
|
|
173
|
-
);
|
|
174
|
-
|
|
175
|
-
for (const { name, result, error } of dynamicResults) {
|
|
176
|
-
if (!error) {
|
|
177
|
-
processResult(name, result);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
forceResult = checkForceFlags();
|
|
182
|
-
if (forceResult) return forceResult;
|
|
183
|
-
|
|
184
|
-
// 3. Resource-specific политика
|
|
185
|
-
const resourcePolicy = this.resources.get(context.resource);
|
|
186
|
-
|
|
187
|
-
if (resourcePolicy) {
|
|
188
|
-
const results = await core.executePoliciesLimited(
|
|
189
|
-
[[`RESOURCE_${context.resource}`, resourcePolicy]],
|
|
190
|
-
context
|
|
191
|
-
);
|
|
192
|
-
|
|
193
|
-
if (!results[0].error) {
|
|
194
|
-
processResult(`RESOURCE_${context.resource}`, results[0].result);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
forceResult = checkForceFlags();
|
|
198
|
-
if (forceResult) return forceResult;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// Проверяем накопленный deny
|
|
202
|
-
if (evaluation.hasDeny) {
|
|
203
|
-
return {
|
|
204
|
-
allow: false,
|
|
205
|
-
reason: evaluation.denyReason || 'DENIED_BY_POLICY',
|
|
206
|
-
policies: evaluation.appliedPolicies
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// 4. Extensions (последний шанс разрешить)
|
|
211
|
-
const extensionResults = await core.executePoliciesLimited(
|
|
212
|
-
this.priorities.extensions,
|
|
213
|
-
context
|
|
214
|
-
);
|
|
215
|
-
|
|
216
|
-
for (const { name, result } of extensionResults) {
|
|
217
|
-
processResult(name, result);
|
|
218
|
-
if (result.allow) {
|
|
219
|
-
return {
|
|
220
|
-
allow: true,
|
|
221
|
-
reason: result.reason,
|
|
222
|
-
policies: evaluation.appliedPolicies
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Финальное решение
|
|
228
|
-
const defaultAllow = !this.abac.options.defaultDeny;
|
|
229
|
-
return {
|
|
230
|
-
allow: defaultAllow,
|
|
231
|
-
reason: defaultAllow ? 'DEFAULT_ALLOW' : 'DEFAULT_DENY',
|
|
232
|
-
policies: evaluation.appliedPolicies
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Проверка конкретных политик
|
|
238
|
-
*/
|
|
239
|
-
async checkPolicies(rawContext, policyNames = [], customPolicies = {}) {
|
|
240
|
-
const context = this.abac.core.normalizeContext(rawContext);
|
|
241
|
-
const policies = this.getPoliciesByNames(policyNames, customPolicies);
|
|
242
|
-
|
|
243
|
-
const results = await this.abac.core.executePoliciesLimited(
|
|
244
|
-
Object.entries(policies),
|
|
245
|
-
context,
|
|
246
|
-
this.abac.options.strictMode
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
// Структурированный анализ результатов
|
|
250
|
-
const evaluation = {
|
|
251
|
-
passed: [],
|
|
252
|
-
failed: [],
|
|
253
|
-
errors: []
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
for (const { name, result, error } of results) {
|
|
257
|
-
if (error) {
|
|
258
|
-
evaluation.errors.push({ name, error: error.message });
|
|
259
|
-
continue;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
if (result.force) {
|
|
263
|
-
return {
|
|
264
|
-
allow: result.allow,
|
|
265
|
-
reason: result.reason,
|
|
266
|
-
evaluation
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
if (result.allow) {
|
|
271
|
-
evaluation.passed.push(name);
|
|
272
|
-
} else {
|
|
273
|
-
evaluation.failed.push({ name, reason: result.reason });
|
|
274
|
-
|
|
275
|
-
if (this.abac.options.strictMode) {
|
|
276
|
-
return {
|
|
277
|
-
allow: false,
|
|
278
|
-
reason: result.reason,
|
|
279
|
-
evaluation
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
const allPassed = evaluation.failed.length === 0 && evaluation.errors.length === 0;
|
|
286
|
-
|
|
287
|
-
return {
|
|
288
|
-
allow: allPassed,
|
|
289
|
-
reason: allPassed ? 'POLICIES_PASSED' : `FAILED: ${evaluation.failed[0]?.name}`,
|
|
290
|
-
evaluation
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Получение политик по именам
|
|
296
|
-
*/
|
|
297
|
-
getPoliciesByNames(names, customPolicies = {}) {
|
|
298
|
-
const policies = {};
|
|
299
|
-
|
|
300
|
-
for (const name of names) {
|
|
301
|
-
if (this.global.has(name)) {
|
|
302
|
-
policies[name] = this.global.get(name);
|
|
303
|
-
} else if (this.extensions.has(name)) {
|
|
304
|
-
policies[name] = { fn: this.extensions.get(name), type: 'extension' };
|
|
305
|
-
} else if (this.resources.has(name)) {
|
|
306
|
-
policies[name] = this.resources.get(name);
|
|
307
|
-
} else {
|
|
308
|
-
this.abac.logger?.warn('Policy not found', { name });
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// Добавляем кастомные
|
|
313
|
-
Object.assign(policies, customPolicies);
|
|
314
|
-
return policies;
|
|
315
|
-
}
|
|
316
|
-
}
|