@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
|
@@ -9,23 +9,70 @@ import ABACFields from './abac.fields.js';
|
|
|
9
9
|
import ABACExpressAdapter from './abac.adapter.express.js';
|
|
10
10
|
import ABACWebSocketAdapter from './abac.adapter.ws.js';
|
|
11
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
|
+
|
|
12
57
|
class GlobalABAC {
|
|
13
58
|
constructor(db, options = {}) {
|
|
14
59
|
this.db = db;
|
|
60
|
+
|
|
61
|
+
/** @type {ABACOptions} */
|
|
15
62
|
this.options = {
|
|
16
63
|
strictMode: false,
|
|
17
64
|
defaultDeny: false,
|
|
18
65
|
serviceKey: process.env.SERVICE_KEY,
|
|
19
66
|
enableAudit: true,
|
|
20
67
|
cacheEnabled: true,
|
|
21
|
-
cacheTTL: 300,
|
|
68
|
+
cacheTTL: 300,
|
|
22
69
|
concurrencyLimit: 10,
|
|
23
70
|
...options,
|
|
24
71
|
};
|
|
25
72
|
|
|
26
73
|
// Инициализация компонентов
|
|
27
74
|
this.cache = new Cache({ ttlSeconds: this.options.cacheTTL });
|
|
28
|
-
this.logger = options.
|
|
75
|
+
this.logger = this.options.logger || new Logger(db);
|
|
29
76
|
|
|
30
77
|
// Инициализация модулей
|
|
31
78
|
this.core = new ABACCore(this);
|
|
@@ -35,53 +82,140 @@ class GlobalABAC {
|
|
|
35
82
|
this.websocket = new ABACWebSocketAdapter(this);
|
|
36
83
|
}
|
|
37
84
|
|
|
38
|
-
|
|
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
|
+
*/
|
|
39
94
|
registerGlobalPolicy(name, policyFn, metadata = {}) {
|
|
40
95
|
return this.policies.registerGlobalPolicy(name, policyFn, metadata);
|
|
41
96
|
}
|
|
42
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Регистрация политики для ресурса
|
|
100
|
+
* @param {string} resourceName - Имя ресурса
|
|
101
|
+
* @param {Function} policyFn - Функция политики
|
|
102
|
+
* @param {Object} [options] - Опции
|
|
103
|
+
* @param {string} [options.modelName] - Имя модели в БД
|
|
104
|
+
* @returns {GlobalABAC}
|
|
105
|
+
*/
|
|
43
106
|
registerResourcePolicy(resourceName, policyFn, options = {}) {
|
|
44
107
|
return this.policies.registerResourcePolicy(resourceName, policyFn, options);
|
|
45
108
|
}
|
|
46
109
|
|
|
47
|
-
|
|
48
|
-
|
|
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);
|
|
49
128
|
}
|
|
50
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Регистрация расширения контекста
|
|
132
|
+
* @param {string} moduleName - Имя модуля
|
|
133
|
+
* @param {Function} extensionFn - Функция расширения (context) => void
|
|
134
|
+
* @returns {GlobalABAC}
|
|
135
|
+
*/
|
|
51
136
|
registerExtension(moduleName, extensionFn) {
|
|
52
137
|
return this.policies.registerExtension(moduleName, extensionFn);
|
|
53
138
|
}
|
|
54
139
|
|
|
55
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Проверка доступа
|
|
142
|
+
* @param {ABACContext|Object} context - Контекст проверки
|
|
143
|
+
* @param {Object} [customPolicies] - Дополнительные политики
|
|
144
|
+
* @returns {Promise<ABACResult>}
|
|
145
|
+
*/
|
|
56
146
|
async checkAccess(context, customPolicies = {}) {
|
|
57
147
|
return this.core.checkAccess(context, customPolicies);
|
|
58
148
|
}
|
|
59
149
|
|
|
60
|
-
|
|
61
|
-
|
|
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);
|
|
62
159
|
}
|
|
63
160
|
|
|
161
|
+
/**
|
|
162
|
+
* Проверка конкретных политик
|
|
163
|
+
* @param {ABACContext|Object} context - Контекст
|
|
164
|
+
* @param {string[]} policyNames - Имена политик
|
|
165
|
+
* @param {Object} [customPolicies] - Дополнительные политики
|
|
166
|
+
* @returns {Promise<ABACResult>}
|
|
167
|
+
*/
|
|
64
168
|
async checkPolicies(context, policyNames = [], customPolicies = {}) {
|
|
65
169
|
return this.policies.checkPolicies(context, policyNames, customPolicies);
|
|
66
170
|
}
|
|
67
171
|
|
|
68
|
-
|
|
172
|
+
/**
|
|
173
|
+
* Express middleware для проверки доступа
|
|
174
|
+
* @param {string} resource - Ресурс
|
|
175
|
+
* @param {string} action - Действие
|
|
176
|
+
* @param {Object} [options] - Опции
|
|
177
|
+
* @returns {Function|Function[]} Middleware функция(и)
|
|
178
|
+
*/
|
|
69
179
|
middleware(resource, action, options = {}) {
|
|
70
180
|
return this.express.middleware(resource, action, options);
|
|
71
181
|
}
|
|
72
182
|
|
|
183
|
+
/**
|
|
184
|
+
* Express middleware для проверки политик
|
|
185
|
+
* @param {string[]} policyNames - Имена политик
|
|
186
|
+
* @param {Object} [customPolicies] - Дополнительные политики
|
|
187
|
+
* @param {Object} [options] - Опции
|
|
188
|
+
* @returns {Function} Middleware функция
|
|
189
|
+
*/
|
|
73
190
|
policyMiddleware(policyNames = [], customPolicies = {}, options = {}) {
|
|
74
191
|
return this.express.policyMiddleware(policyNames, customPolicies, options);
|
|
75
192
|
}
|
|
76
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Express middleware для проверки полей
|
|
196
|
+
* @param {string} resource - Ресурс
|
|
197
|
+
* @param {Object} [options] - Опции
|
|
198
|
+
* @returns {Function} Middleware функция
|
|
199
|
+
*/
|
|
77
200
|
fieldsMiddleware(resource, options = {}) {
|
|
78
201
|
return this.express.fieldsMiddleware(resource, options);
|
|
79
202
|
}
|
|
80
203
|
|
|
204
|
+
/**
|
|
205
|
+
* WebSocket handler
|
|
206
|
+
* @param {string} moduleName - Имя модуля
|
|
207
|
+
* @param {Object} [options] - Опции
|
|
208
|
+
* @returns {Function} Handler функция
|
|
209
|
+
*/
|
|
81
210
|
wsHandler(moduleName, options = {}) {
|
|
82
211
|
return this.websocket.handler(moduleName, options);
|
|
83
212
|
}
|
|
84
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Получение модели ресурса из БД
|
|
216
|
+
* @param {string} resourceName - Имя ресурса
|
|
217
|
+
* @returns {Object|null} Mongoose модель или null
|
|
218
|
+
*/
|
|
85
219
|
getResourceModel(resourceName) {
|
|
86
220
|
const resourcePolicy = this.policies.resources.get(resourceName);
|
|
87
221
|
if (!resourcePolicy) return null;
|
|
@@ -89,11 +223,61 @@ class GlobalABAC {
|
|
|
89
223
|
const modelName = resourcePolicy.modelName || resourceName;
|
|
90
224
|
return this.db[modelName] || null;
|
|
91
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
|
+
}
|
|
92
270
|
}
|
|
93
271
|
|
|
94
272
|
// Экспорт синглтона
|
|
95
273
|
let instance = null;
|
|
96
274
|
|
|
275
|
+
/**
|
|
276
|
+
* Получение экземпляра ABAC
|
|
277
|
+
* @param {Object} db - База данных
|
|
278
|
+
* @param {ABACOptions} [options] - Опции
|
|
279
|
+
* @returns {GlobalABAC}
|
|
280
|
+
*/
|
|
97
281
|
export const getInstance = (db, options) => {
|
|
98
282
|
if (!instance) {
|
|
99
283
|
instance = new GlobalABAC(db, options);
|
|
@@ -101,4 +285,11 @@ export const getInstance = (db, options) => {
|
|
|
101
285
|
return instance;
|
|
102
286
|
};
|
|
103
287
|
|
|
104
|
-
|
|
288
|
+
/**
|
|
289
|
+
* Сброс экземпляра (для тестов)
|
|
290
|
+
*/
|
|
291
|
+
export const resetInstance = () => {
|
|
292
|
+
instance = null;
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
export default { getInstance, resetInstance };
|
|
@@ -12,6 +12,9 @@ export default class ABACPolicies {
|
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Регистрация глобальной политики
|
|
17
|
+
*/
|
|
15
18
|
registerGlobalPolicy(name, policyFn, metadata = {}) {
|
|
16
19
|
if (typeof policyFn !== 'function') {
|
|
17
20
|
throw new Error(`Global policy "${name}" must be a function`);
|
|
@@ -20,6 +23,7 @@ export default class ABACPolicies {
|
|
|
20
23
|
const policy = {
|
|
21
24
|
fn: policyFn,
|
|
22
25
|
type: metadata.type || 'dynamic',
|
|
26
|
+
priority: metadata.priority || 0,
|
|
23
27
|
...metadata
|
|
24
28
|
};
|
|
25
29
|
|
|
@@ -28,6 +32,9 @@ export default class ABACPolicies {
|
|
|
28
32
|
return this.abac;
|
|
29
33
|
}
|
|
30
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Регистрация политики ресурса
|
|
37
|
+
*/
|
|
31
38
|
registerResourcePolicy(resourceName, policyFn, options = {}) {
|
|
32
39
|
if (typeof policyFn !== 'function') {
|
|
33
40
|
throw new Error(`Resource policy for "${resourceName}" must be a function`);
|
|
@@ -41,6 +48,9 @@ export default class ABACPolicies {
|
|
|
41
48
|
return this.abac;
|
|
42
49
|
}
|
|
43
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Регистрация расширения
|
|
53
|
+
*/
|
|
44
54
|
registerExtension(moduleName, extensionFn) {
|
|
45
55
|
if (typeof extensionFn !== 'function') {
|
|
46
56
|
throw new Error(`Extension "${moduleName}" must be a function`);
|
|
@@ -51,97 +61,127 @@ export default class ABACPolicies {
|
|
|
51
61
|
return this.abac;
|
|
52
62
|
}
|
|
53
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Обновление приоритетов с сортировкой
|
|
66
|
+
*/
|
|
54
67
|
updatePriorities() {
|
|
55
|
-
// Группируем политики по типам
|
|
56
68
|
this.priorities = {
|
|
57
69
|
static: [],
|
|
58
70
|
dynamic: [],
|
|
59
71
|
extensions: []
|
|
60
72
|
};
|
|
61
73
|
|
|
74
|
+
// Группируем и сортируем по приоритету
|
|
62
75
|
for (const [name, policy] of this.global) {
|
|
63
76
|
const type = policy.type || 'dynamic';
|
|
64
77
|
this.priorities[type].push([name, policy]);
|
|
65
78
|
}
|
|
66
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
|
+
|
|
67
84
|
// Добавляем расширения
|
|
68
85
|
this.priorities.extensions = Array.from(this.extensions.entries());
|
|
69
86
|
}
|
|
70
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Основная логика оценки политик
|
|
90
|
+
*/
|
|
71
91
|
async evaluate(context, customPolicies = {}) {
|
|
72
92
|
const core = this.abac.core;
|
|
73
93
|
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
94
|
+
// Структура для отслеживания результатов
|
|
95
|
+
const evaluation = {
|
|
96
|
+
hasForceAllow: false,
|
|
97
|
+
hasForceDisallow: false,
|
|
98
|
+
hasDeny: false,
|
|
99
|
+
denyReason: '',
|
|
100
|
+
allowReason: '',
|
|
101
|
+
appliedPolicies: []
|
|
102
|
+
};
|
|
80
103
|
|
|
81
104
|
// Функция для обработки результата политики
|
|
82
|
-
const processResult = (result) => {
|
|
105
|
+
const processResult = (name, result) => {
|
|
106
|
+
evaluation.appliedPolicies.push({ name, result });
|
|
107
|
+
|
|
83
108
|
if (result.force) {
|
|
84
109
|
if (result.allow) {
|
|
85
|
-
hasForceAllow = true;
|
|
86
|
-
allowReason = result.reason;
|
|
110
|
+
evaluation.hasForceAllow = true;
|
|
111
|
+
evaluation.allowReason = result.reason;
|
|
87
112
|
} else {
|
|
88
|
-
hasForceDisallow = true;
|
|
89
|
-
denyReason = result.reason;
|
|
113
|
+
evaluation.hasForceDisallow = true;
|
|
114
|
+
evaluation.denyReason = result.reason;
|
|
90
115
|
}
|
|
91
116
|
} else if (!result.allow) {
|
|
92
|
-
hasDeny = true;
|
|
93
|
-
if (!denyReason)
|
|
117
|
+
evaluation.hasDeny = true;
|
|
118
|
+
if (!evaluation.denyReason) {
|
|
119
|
+
evaluation.denyReason = result.reason;
|
|
120
|
+
}
|
|
94
121
|
}
|
|
95
122
|
};
|
|
96
123
|
|
|
97
124
|
// Функция для проверки force флагов
|
|
98
125
|
const checkForceFlags = () => {
|
|
99
|
-
if (hasForceDisallow) {
|
|
126
|
+
if (evaluation.hasForceDisallow) {
|
|
100
127
|
return {
|
|
101
128
|
allow: false,
|
|
102
|
-
reason: denyReason || 'FORCE_DENIED_BY_POLICY',
|
|
129
|
+
reason: evaluation.denyReason || 'FORCE_DENIED_BY_POLICY',
|
|
130
|
+
policies: evaluation.appliedPolicies
|
|
103
131
|
};
|
|
104
132
|
}
|
|
105
133
|
|
|
106
|
-
if (hasForceAllow) {
|
|
134
|
+
if (evaluation.hasForceAllow) {
|
|
107
135
|
return {
|
|
108
136
|
allow: true,
|
|
109
|
-
reason: allowReason || 'FORCE_ALLOWED_BY_POLICY',
|
|
137
|
+
reason: evaluation.allowReason || 'FORCE_ALLOWED_BY_POLICY',
|
|
138
|
+
policies: evaluation.appliedPolicies
|
|
110
139
|
};
|
|
111
140
|
}
|
|
112
141
|
|
|
113
142
|
return null;
|
|
114
143
|
};
|
|
115
144
|
|
|
116
|
-
//
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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);
|
|
125
155
|
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
let forceResult = checkForceFlags();
|
|
159
|
+
if (forceResult) return forceResult;
|
|
126
160
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
+
);
|
|
132
174
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
processResult(result);
|
|
175
|
+
for (const { name, result, error } of dynamicResults) {
|
|
176
|
+
if (!error) {
|
|
177
|
+
processResult(name, result);
|
|
137
178
|
}
|
|
138
|
-
|
|
139
|
-
// Проверяем force флаги после каждого этапа
|
|
140
|
-
const forceResult = checkForceFlags();
|
|
141
|
-
if (forceResult) return forceResult;
|
|
142
179
|
}
|
|
180
|
+
|
|
181
|
+
forceResult = checkForceFlags();
|
|
182
|
+
if (forceResult) return forceResult;
|
|
143
183
|
|
|
144
|
-
//
|
|
184
|
+
// 3. Resource-specific политика
|
|
145
185
|
const resourcePolicy = this.resources.get(context.resource);
|
|
146
186
|
|
|
147
187
|
if (resourcePolicy) {
|
|
@@ -151,31 +191,36 @@ export default class ABACPolicies {
|
|
|
151
191
|
);
|
|
152
192
|
|
|
153
193
|
if (!results[0].error) {
|
|
154
|
-
processResult(results[0].result);
|
|
194
|
+
processResult(`RESOURCE_${context.resource}`, results[0].result);
|
|
155
195
|
}
|
|
156
196
|
|
|
157
|
-
|
|
158
|
-
const forceResult = checkForceFlags();
|
|
197
|
+
forceResult = checkForceFlags();
|
|
159
198
|
if (forceResult) return forceResult;
|
|
160
199
|
}
|
|
161
200
|
|
|
162
|
-
// Проверяем накопленный deny
|
|
163
|
-
if (hasDeny) {
|
|
201
|
+
// Проверяем накопленный deny
|
|
202
|
+
if (evaluation.hasDeny) {
|
|
164
203
|
return {
|
|
165
204
|
allow: false,
|
|
166
|
-
reason: denyReason || 'DENIED_BY_POLICY',
|
|
205
|
+
reason: evaluation.denyReason || 'DENIED_BY_POLICY',
|
|
206
|
+
policies: evaluation.appliedPolicies
|
|
167
207
|
};
|
|
168
208
|
}
|
|
169
209
|
|
|
170
|
-
//
|
|
210
|
+
// 4. Extensions (последний шанс разрешить)
|
|
171
211
|
const extensionResults = await core.executePoliciesLimited(
|
|
172
212
|
this.priorities.extensions,
|
|
173
213
|
context
|
|
174
214
|
);
|
|
175
215
|
|
|
176
|
-
for (const { result } of extensionResults) {
|
|
216
|
+
for (const { name, result } of extensionResults) {
|
|
217
|
+
processResult(name, result);
|
|
177
218
|
if (result.allow) {
|
|
178
|
-
return {
|
|
219
|
+
return {
|
|
220
|
+
allow: true,
|
|
221
|
+
reason: result.reason,
|
|
222
|
+
policies: evaluation.appliedPolicies
|
|
223
|
+
};
|
|
179
224
|
}
|
|
180
225
|
}
|
|
181
226
|
|
|
@@ -184,10 +229,13 @@ export default class ABACPolicies {
|
|
|
184
229
|
return {
|
|
185
230
|
allow: defaultAllow,
|
|
186
231
|
reason: defaultAllow ? 'DEFAULT_ALLOW' : 'DEFAULT_DENY',
|
|
232
|
+
policies: evaluation.appliedPolicies
|
|
187
233
|
};
|
|
188
234
|
}
|
|
189
235
|
|
|
190
|
-
|
|
236
|
+
/**
|
|
237
|
+
* Проверка конкретных политик
|
|
238
|
+
*/
|
|
191
239
|
async checkPolicies(rawContext, policyNames = [], customPolicies = {}) {
|
|
192
240
|
const context = this.abac.core.normalizeContext(rawContext);
|
|
193
241
|
const policies = this.getPoliciesByNames(policyNames, customPolicies);
|
|
@@ -198,17 +246,54 @@ export default class ABACPolicies {
|
|
|
198
246
|
this.abac.options.strictMode
|
|
199
247
|
);
|
|
200
248
|
|
|
201
|
-
//
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
+
}
|
|
206
282
|
}
|
|
207
283
|
}
|
|
208
284
|
|
|
209
|
-
|
|
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
|
+
};
|
|
210
292
|
}
|
|
211
293
|
|
|
294
|
+
/**
|
|
295
|
+
* Получение политик по именам
|
|
296
|
+
*/
|
|
212
297
|
getPoliciesByNames(names, customPolicies = {}) {
|
|
213
298
|
const policies = {};
|
|
214
299
|
|
|
@@ -217,9 +302,14 @@ export default class ABACPolicies {
|
|
|
217
302
|
policies[name] = this.global.get(name);
|
|
218
303
|
} else if (this.extensions.has(name)) {
|
|
219
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 });
|
|
220
309
|
}
|
|
221
310
|
}
|
|
222
311
|
|
|
312
|
+
// Добавляем кастомные
|
|
223
313
|
Object.assign(policies, customPolicies);
|
|
224
314
|
return policies;
|
|
225
315
|
}
|
|
@@ -83,9 +83,9 @@ export default class CRUDPolicies {
|
|
|
83
83
|
action,
|
|
84
84
|
req,
|
|
85
85
|
data: {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
params: req.params
|
|
86
|
+
body: req.body || {},
|
|
87
|
+
query: req.query || {},
|
|
88
|
+
params: req.params || {}
|
|
89
89
|
},
|
|
90
90
|
params: req.params
|
|
91
91
|
};
|
|
@@ -152,8 +152,8 @@ export default class CRUDPolicies {
|
|
|
152
152
|
action: 'read',
|
|
153
153
|
req,
|
|
154
154
|
data: {
|
|
155
|
-
|
|
156
|
-
params: req.params
|
|
155
|
+
query: req.query || {},
|
|
156
|
+
params: req.params || {}
|
|
157
157
|
},
|
|
158
158
|
params: req.params
|
|
159
159
|
};
|
|
@@ -44,9 +44,12 @@ export default (function initializeDefaultPolicies(abacAccessControl) {
|
|
|
44
44
|
let { user, action, data, currentResource, options } = context;
|
|
45
45
|
const ObjectId = abacAccessControl.db.mongoose.Types.ObjectId;
|
|
46
46
|
// Для create операций с владением пользователя
|
|
47
|
-
if (action === 'create' && data.owner?.type === 'user') {
|
|
47
|
+
if (action === 'create' && data.body?.owner?.type === 'user') {
|
|
48
|
+
const ownerTarget = data.body.owner.target;
|
|
49
|
+
const creatorTarget = data.body.creator?.target;
|
|
50
|
+
|
|
48
51
|
// Проверяем, что пользователь создает ресурс от своего имени
|
|
49
|
-
if (
|
|
52
|
+
if (ownerTarget === user && creatorTarget === user) {
|
|
50
53
|
return { allow: true, force: false };
|
|
51
54
|
} else {
|
|
52
55
|
return {
|