@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.
Files changed (207) hide show
  1. package/dist/abac-BPl9Bmf9.js +1527 -0
  2. package/dist/builder.js +51 -39
  3. package/dist/{common.schema-GFSlNJo7.js → common.schema-DswiUXKB.js} +1 -1
  4. package/dist/community.server.js +48 -9
  5. package/dist/core.server.js +6 -4
  6. package/dist/{crud-C7FSTUes.js → crud-q1ye5IhV.js} +7 -7
  7. package/dist/events.server.js +3 -3
  8. package/dist/gallery.server.js +2 -2
  9. package/dist/inventory.server.js +4 -6
  10. package/dist/{main-CmjWiDVF.js → main-B9o1iBAZ.js} +1279 -1287
  11. package/dist/marketplace.server.js +1 -1
  12. package/dist/martyrs/src/components/Button/Button.vue2.js +33 -42
  13. package/dist/martyrs/src/components/Button/Button.vue2.js.map +1 -1
  14. package/dist/martyrs/src/components/EditImages/{EditImages.vue.js → EditImages.vue2.js} +2 -2
  15. package/dist/martyrs/src/components/EditImages/EditImages.vue2.js.map +1 -0
  16. package/dist/martyrs/src/components/Feed/Feed.vue.js +1 -1
  17. package/dist/martyrs/src/components/FieldPhone/FieldPhone.vue.js +1 -1
  18. package/dist/martyrs/src/components/FieldPhone/FieldPhone.vue.js.map +1 -1
  19. package/dist/martyrs/src/components/Loader/Loader.vue.js +1 -2
  20. package/dist/martyrs/src/components/Loader/Loader.vue.js.map +1 -1
  21. package/dist/martyrs/src/components/Menu/{Menu.vue.js → Menu.vue2.js} +2 -2
  22. package/dist/martyrs/src/components/Menu/Menu.vue2.js.map +1 -0
  23. package/dist/martyrs/src/components/Tab/{Tab.vue.js → Tab.vue2.js} +2 -2
  24. package/dist/martyrs/src/components/Tab/Tab.vue2.js.map +1 -0
  25. package/dist/martyrs/src/components/Tree/Tree.vue.js +6 -3
  26. package/dist/martyrs/src/components/Tree/Tree.vue.js.map +1 -1
  27. package/dist/martyrs/src/modules/auth/auth.client.js +10 -7
  28. package/dist/martyrs/src/modules/auth/auth.client.js.map +1 -1
  29. package/dist/martyrs/src/modules/auth/views/components/pages/EnterPassword.vue.js +1 -1
  30. package/dist/martyrs/src/modules/auth/views/components/pages/Invite.vue.js +1 -1
  31. package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.js +1 -1
  32. package/dist/martyrs/src/modules/auth/views/components/pages/ProfileBlogposts.vue.js +1 -1
  33. package/dist/martyrs/src/modules/auth/views/components/pages/ResetPassword.vue.js +1 -1
  34. package/dist/martyrs/src/modules/auth/views/components/pages/SignIn.vue.js +12 -12
  35. package/dist/martyrs/src/modules/auth/views/components/pages/SignIn.vue.js.map +1 -1
  36. package/dist/martyrs/src/modules/auth/views/components/pages/SignUp.vue.js +1 -1
  37. package/dist/martyrs/src/modules/auth/views/router/auth.router.js +116 -0
  38. package/dist/martyrs/src/modules/auth/views/router/auth.router.js.map +1 -0
  39. package/dist/martyrs/src/modules/auth/views/router/users.router.js +180 -0
  40. package/dist/martyrs/src/modules/auth/views/router/users.router.js.map +1 -0
  41. package/dist/martyrs/src/modules/backoffice/components/partials/Sidebar.vue.js +3 -3
  42. package/dist/martyrs/src/modules/backoffice/components/partials/Sidebar.vue.js.map +1 -1
  43. package/dist/martyrs/src/modules/core/locales/en.js +45 -0
  44. package/dist/martyrs/src/modules/core/locales/en.js.map +1 -1
  45. package/dist/martyrs/src/modules/core/locales/ru.js +45 -0
  46. package/dist/martyrs/src/modules/core/locales/ru.js.map +1 -1
  47. package/dist/martyrs/src/modules/core/views/classes/i18n.manager.js +9 -0
  48. package/dist/martyrs/src/modules/core/views/classes/i18n.manager.js.map +1 -1
  49. package/dist/martyrs/src/modules/core/views/components/sections/{Filters.vue.js → Filters.vue2.js} +2 -2
  50. package/dist/martyrs/src/modules/core/views/components/sections/Filters.vue2.js.map +1 -0
  51. package/dist/martyrs/src/modules/core/views/components/sections/SectionPageTitle.vue.js +1 -1
  52. package/dist/martyrs/src/modules/core/views/mixins/mixins.js +1 -2
  53. package/dist/martyrs/src/modules/core/views/mixins/mixins.js.map +1 -1
  54. package/dist/martyrs/src/modules/core/views/router/addRoutes.js +6 -1
  55. package/dist/martyrs/src/modules/core/views/router/addRoutes.js.map +1 -1
  56. package/dist/martyrs/src/modules/events/components/pages/EditEvent.vue.js +1 -1
  57. package/dist/martyrs/src/modules/events/components/pages/Event.vue.js +1 -1
  58. package/dist/martyrs/src/modules/events/components/pages/EventsBackoffice.vue.js +1 -1
  59. package/dist/martyrs/src/modules/gallery/components/sections/BackofficeGallery.vue.js +1 -1
  60. package/dist/martyrs/src/modules/inventory/components/pages/InventoryEdit.vue.js +2 -2
  61. package/dist/martyrs/src/modules/inventory/components/pages/InventoryEdit.vue.js.map +1 -1
  62. package/dist/martyrs/src/modules/marketplace/views/components/pages/Marketplace.vue.js +1 -1
  63. package/dist/martyrs/src/modules/marketplace/views/store/marketplace.js +0 -16
  64. package/dist/martyrs/src/modules/marketplace/views/store/marketplace.js.map +1 -1
  65. package/dist/martyrs/src/modules/notifications/components/elements/NotificationBadge.vue.js +4 -4
  66. package/dist/martyrs/src/modules/notifications/components/elements/NotificationBadge.vue.js.map +1 -1
  67. package/dist/martyrs/src/modules/notifications/components/pages/Notifications.vue.js +1 -1
  68. package/dist/martyrs/src/modules/orders/components/elements/FieldSubscribeNewsletter.vue.js +3 -0
  69. package/dist/martyrs/src/modules/orders/components/elements/FieldSubscribeNewsletter.vue.js.map +1 -1
  70. package/dist/martyrs/src/modules/orders/components/pages/OrderCreateBackoffice.vue.js +1 -1
  71. package/dist/martyrs/src/modules/orders/components/pages/Orders.vue.js +1 -1
  72. package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.js +1 -1
  73. package/dist/martyrs/src/modules/organizations/components/blocks/CardOrganization.vue.js +1 -1
  74. package/dist/martyrs/src/modules/organizations/components/blocks/CardOrganization.vue.js.map +1 -1
  75. package/dist/martyrs/src/modules/organizations/components/pages/Organization.vue.js +1 -1
  76. package/dist/martyrs/src/modules/organizations/components/pages/OrganizationBackoffice.vue.js +1 -1
  77. package/dist/martyrs/src/modules/organizations/components/pages/OrganizationEdit.vue.js +2 -2
  78. package/dist/martyrs/src/modules/organizations/components/pages/OrganizationEdit.vue.js.map +1 -1
  79. package/dist/martyrs/src/modules/organizations/components/pages/Organizations.vue.js +1 -1
  80. package/dist/martyrs/src/modules/organizations/components/sections/Organizations.vue.js +1 -1
  81. package/dist/martyrs/src/modules/products/components/blocks/CardCategory.vue.js +1 -1
  82. package/dist/martyrs/src/modules/products/components/blocks/CardCategory.vue.js.map +1 -1
  83. package/dist/martyrs/src/modules/products/components/blocks/CardProduct.vue.js +15 -2
  84. package/dist/martyrs/src/modules/products/components/blocks/CardProduct.vue.js.map +1 -1
  85. package/dist/martyrs/src/modules/products/components/pages/Categories.vue.js +9 -6
  86. package/dist/martyrs/src/modules/products/components/pages/Categories.vue.js.map +1 -1
  87. package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js +4 -3
  88. package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js.map +1 -1
  89. package/dist/martyrs/src/modules/products/components/pages/Product.vue.js +11 -2
  90. package/dist/martyrs/src/modules/products/components/pages/Product.vue.js.map +1 -1
  91. package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.js +2 -2
  92. package/dist/martyrs/src/modules/products/components/pages/Products.vue.js +2 -2
  93. package/dist/martyrs/src/modules/products/components/sections/EditVariants.vue.js +1 -1
  94. package/dist/martyrs/src/modules/products/components/sections/SectionProduct.vue.js +11 -8
  95. package/dist/martyrs/src/modules/products/components/sections/SectionProduct.vue.js.map +1 -1
  96. package/dist/martyrs/src/modules/rents/views/components/pages/Gant/GanttToolbar.vue.js +1 -1
  97. package/dist/martyrs/src/modules/rents/views/components/pages/Rents.vue.js +1 -1
  98. package/dist/martyrs/src/modules/rents/views/components/pages/RentsEdit.vue.js +210 -60
  99. package/dist/martyrs/src/modules/rents/views/components/pages/RentsEdit.vue.js.map +1 -1
  100. package/dist/martyrs/src/modules/spots/components/pages/Map.vue.js +3 -3
  101. package/dist/martyrs/src/modules/spots/components/pages/Map.vue.js.map +1 -1
  102. package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.js +1 -1
  103. package/dist/martyrs.css +1 -1
  104. package/dist/martyrs.es.js +1 -1
  105. package/dist/music.server.js +11 -12
  106. package/dist/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/utils.js +1 -1
  107. package/dist/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/utils.js +1 -1
  108. package/dist/notifications.server.js +0 -3
  109. package/dist/orders.server.js +5 -6
  110. package/dist/organizations.server.js +9 -10
  111. package/dist/products.server.js +27 -26
  112. package/dist/{queryProcessor-CBQgZycY.js → queryProcessor-C_5Iipam.js} +4 -1
  113. package/dist/rents.server.js +2 -3
  114. package/dist/spots.server.js +1 -1
  115. package/dist/style.css +38 -23
  116. package/dist/{web-cNKIl_cL.js → web-BF3ijvEr.js} +1 -1
  117. package/package.json +1 -1
  118. package/src/builder/modes/ssr.rspack.dev.js +4 -3
  119. package/src/builder/rspack/rspack.config.api.js +15 -4
  120. package/src/builder/rspack/rspack.config.base.js +3 -3
  121. package/src/builder/rspack/rspack.config.ssr.client.js +28 -28
  122. package/src/builder/templates/page.js +2 -2
  123. package/src/components/Button/Button.vue +50 -37
  124. package/src/components/FieldPhone/FieldPhone.vue +1 -1
  125. package/src/components/Loader/Loader.vue +1 -1
  126. package/src/components/Tree/Tree.vue +6 -3
  127. package/src/modules/PROCESS.md +0 -0
  128. package/src/modules/TASKS.MD +17 -0
  129. package/src/modules/auth/auth.client.js +11 -7
  130. package/src/modules/auth/views/components/pages/SignIn.vue +1 -1
  131. package/src/modules/auth/views/router/auth.router.js +94 -0
  132. package/src/modules/auth/views/router/users.router.js +153 -0
  133. package/src/modules/backoffice/components/partials/Sidebar.vue +7 -7
  134. package/src/modules/community/community.server.js +8 -0
  135. package/src/modules/community/policies/blog.policies.js +55 -0
  136. package/src/modules/community/routes/blog.routes.js +1 -1
  137. package/src/modules/community/routes/comments.routes.js +1 -1
  138. package/src/modules/community/routes/reactions.routes.js +1 -4
  139. package/src/modules/core/controllers/classes/abac/abac.adapter.express.js +206 -124
  140. package/src/modules/core/controllers/classes/abac/abac.adapter.ws.js +203 -50
  141. package/src/modules/core/controllers/classes/abac/abac.core.js +127 -36
  142. package/src/modules/core/controllers/classes/abac/abac.fields.js +144 -179
  143. package/src/modules/core/controllers/classes/abac/abac.js +201 -10
  144. package/src/modules/core/controllers/classes/abac/abac.policies.js +147 -57
  145. package/src/modules/core/controllers/classes/crud/crud.policies.js +5 -5
  146. package/src/modules/core/controllers/policies/core.policies.js +5 -2
  147. package/src/modules/core/controllers/utils/queryProcessor.js +4 -1
  148. package/src/modules/core/core.server.js +1 -0
  149. package/src/modules/core/locales/en.js +45 -0
  150. package/src/modules/core/locales/ru.js +45 -0
  151. package/src/modules/core/models/schemas/common.schema.js +1 -1
  152. package/src/modules/core/views/classes/i18n.manager.js +13 -0
  153. package/src/modules/core/views/components/sections/filters/FilterPrice.vue +81 -0
  154. package/src/modules/core/views/mixins/mixins.js +1 -2
  155. package/src/modules/core/views/router/addRoutes.js +6 -1
  156. package/src/modules/events/routes/events.routes.js +1 -1
  157. package/src/modules/inventory/components/pages/InventoryEdit.vue +3 -3
  158. package/src/modules/inventory/policies/inventory.policies.js +1 -1
  159. package/src/modules/inventory/routes/inventory.routes.js +1 -1
  160. package/src/modules/marketplace/marketplace.router.js +66 -0
  161. package/src/modules/marketplace/views/components/layouts/Marketplace.vue +363 -0
  162. package/src/modules/marketplace/views/components/pages/Catalog.vue +73 -0
  163. package/src/modules/marketplace/views/store/marketplace.js +0 -16
  164. package/src/modules/music/controllers/stream.controller.js +1 -1
  165. package/src/modules/music/music.server.js +1 -1
  166. package/src/modules/music/policies/music.policies.js +3 -2
  167. package/src/modules/music/router/library.router.js +26 -0
  168. package/src/modules/music/router/music.router.js +176 -0
  169. package/src/modules/notifications/components/elements/NotificationBadge.vue +5 -6
  170. package/src/modules/notifications/notifications.server.js +1 -3
  171. package/src/modules/orders/components/elements/FieldSubscribeNewsletter.vue +5 -0
  172. package/src/modules/orders/orders.server.js +0 -1
  173. package/src/modules/organizations/components/blocks/CardOrganization.vue +2 -2
  174. package/src/modules/organizations/components/pages/DepartmentEdit.vue +2 -2
  175. package/src/modules/organizations/components/pages/OrganizationEdit.vue +2 -2
  176. package/src/modules/organizations/policies/organizations.policies.js +12 -6
  177. package/src/modules/organizations/routes/organizations.routes.js +1 -3
  178. package/src/modules/products/components/blocks/CardCategory.vue +1 -1
  179. package/src/modules/products/components/blocks/CardProduct.vue +16 -2
  180. package/src/modules/products/components/pages/Categories.vue +9 -6
  181. package/src/modules/products/components/pages/CategoryEdit.vue +8 -4
  182. package/src/modules/products/components/pages/Product.vue +11 -5
  183. package/src/modules/products/components/sections/SectionProduct.vue +11 -7
  184. package/src/modules/products/controllers/categories.controller.js +32 -27
  185. package/src/modules/products/routes/categories.routes.js +1 -1
  186. package/src/modules/rents/controllers/routes/rents.routes.js +1 -1
  187. package/src/modules/rents/views/components/pages/RentsEdit.vue +208 -49
  188. package/src/modules/spots/components/pages/Map.vue +2 -2
  189. package/dist/abac-DYoheWuc.js +0 -1031
  190. package/dist/core.abac-DUPBnlk6.js +0 -298
  191. package/dist/core.logger-C3q8A9dl.js +0 -51
  192. package/dist/martyrs/src/components/EditImages/EditImages.vue.js.map +0 -1
  193. package/dist/martyrs/src/components/Menu/Menu.vue.js.map +0 -1
  194. package/dist/martyrs/src/components/Tab/Tab.vue.js.map +0 -1
  195. package/dist/martyrs/src/modules/auth/auth.router.js +0 -342
  196. package/dist/martyrs/src/modules/auth/auth.router.js.map +0 -1
  197. package/dist/martyrs/src/modules/core/views/components/sections/Filters.vue.js.map +0 -1
  198. package/src/modules/auth/auth.router.js +0 -262
  199. package/src/modules/core/controllers/classes/abac/v2/abac-core-fixed.js +0 -313
  200. package/src/modules/core/controllers/classes/abac/v2/abac-express-fixed.js +0 -276
  201. package/src/modules/core/controllers/classes/abac/v2/abac-fields-fixed.js +0 -425
  202. package/src/modules/core/controllers/classes/abac/v2/abac-main-fixed.js +0 -295
  203. package/src/modules/core/controllers/classes/abac/v2/abac-policies-fixed.js +0 -316
  204. package/src/modules/core/controllers/classes/abac/v2/abac-ws-fixed.js +0 -237
  205. package/src/modules/core/controllers/classes/core.abac.js +0 -310
  206. package/src/modules/core/controllers/classes/core.crud.js +0 -89
  207. package/src/modules/governance/reactcode/eslint.config.js +0 -28
@@ -1,313 +0,0 @@
1
- // @martyrs/src/modules/core/controllers/classes/abac/abac.core.js
2
- export default class ABACCore {
3
- constructor(abac) {
4
- this.abac = abac;
5
- this.runningPolicies = new Map();
6
- }
7
-
8
- /**
9
- * Нормализация контекста
10
- */
11
- normalizeContext(input) {
12
- const context = {
13
- user: null,
14
- action: null,
15
- resource: null,
16
- currentResource: null,
17
- resourceId: null, // Добавляем ID ресурса для кэша
18
- data: {},
19
- req: null,
20
- socket: null,
21
- params: {},
22
- _cache: new Map(),
23
- _abac: this.abac,
24
- skipFieldPolicies: input.skipFieldPolicies || false,
25
- };
26
-
27
- if (input.req) {
28
- // Express context - НЕ смешиваем body и query!
29
- context.user = input.user || input.req.userId;
30
- context.data = {
31
- body: input.req.body || {},
32
- query: input.req.query || {},
33
- params: input.req.params || {},
34
- };
35
- context.params = input.req.params;
36
- context.req = input.req;
37
-
38
- // Извлекаем ID ресурса для кэша
39
- context.resourceId = input.req.params?._id ||
40
- input.req.params?.id ||
41
- input.req.body?._id ||
42
- input.req.body?.id;
43
- } else if (input.socket) {
44
- // WebSocket context
45
- context.user = input.user || input.socket.userId;
46
- context.socket = input.socket;
47
- context.data = input.data || {};
48
- context.resourceId = input.data?._id || input.data?.id;
49
- }
50
-
51
- // Merge остальные поля (но не перезаписываем data)
52
- return Object.assign(context, {
53
- ...input,
54
- data: context.data // Сохраняем структурированную data
55
- });
56
- }
57
-
58
- /**
59
- * Выполнение политики с кэшированием
60
- */
61
- async executePolicyWithCache(policyName, policyFn, context) {
62
- // Проверяем контекстный кэш
63
- const contextCacheKey = `${policyName}_${context.action}`;
64
- if (context._cache.has(contextCacheKey)) {
65
- return context._cache.get(contextCacheKey);
66
- }
67
-
68
- // Улучшенный глобальный кэш-ключ с ID ресурса
69
- const globalCacheKey = this._buildCacheKey(policyName, context);
70
-
71
- if (this.abac.options.cacheEnabled) {
72
- const cached = await this.abac.cache.get(globalCacheKey);
73
- if (cached !== undefined) {
74
- context._cache.set(contextCacheKey, cached);
75
- return cached;
76
- }
77
- }
78
-
79
- // Выполняем политику
80
- const result = await policyFn(context);
81
-
82
- // Сохраняем в кэш
83
- context._cache.set(contextCacheKey, result);
84
- if (this.abac.options.cacheEnabled) {
85
- const tags = [
86
- `user_${context.user}`,
87
- `resource_${context.resource}`,
88
- `policy_${policyName}`
89
- ];
90
-
91
- if (context.resourceId) {
92
- tags.push(`resourceId_${context.resourceId}`);
93
- }
94
-
95
- await this.abac.cache.setWithTags(globalCacheKey, result, tags);
96
- }
97
-
98
- return result;
99
- }
100
-
101
- /**
102
- * Построение ключа кэша с учетом ID ресурса
103
- * @private
104
- */
105
- _buildCacheKey(policyName, context) {
106
- const parts = [
107
- 'policy',
108
- policyName,
109
- context.user,
110
- context.resource,
111
- context.action
112
- ];
113
-
114
- if (context.resourceId) {
115
- parts.push(context.resourceId);
116
- }
117
-
118
- return parts.join('_');
119
- }
120
-
121
- /**
122
- * Выполнение политик с ограничением параллельности
123
- */
124
- async executePoliciesLimited(policies, context, stopOnDeny = false) {
125
- const results = [];
126
- const limit = this.abac.options.concurrencyLimit;
127
-
128
- // Разбиваем на батчи
129
- const batches = [];
130
- for (let i = 0; i < policies.length; i += limit) {
131
- batches.push(policies.slice(i, i + limit));
132
- }
133
-
134
- for (const batch of batches) {
135
- const batchPromises = batch.map(async ([name, policy]) => {
136
- try {
137
- const policyFn = typeof policy === 'function' ? policy : policy.fn;
138
- const result = await this.executePolicyWithCache(name, policyFn, context);
139
- return { name, result: this.normalizeResult(result, name) };
140
- } catch (error) {
141
- this.abac.logger?.error('Policy execution error', {
142
- policy: name,
143
- error: error.message,
144
- stack: error.stack
145
- });
146
-
147
- return {
148
- name,
149
- result: {
150
- allow: !this.abac.options.strictMode,
151
- reason: `POLICY_ERROR_${name.toUpperCase()}`
152
- },
153
- error
154
- };
155
- }
156
- });
157
-
158
- const batchResults = await Promise.all(batchPromises);
159
- results.push(...batchResults);
160
-
161
- // Проверяем нужно ли остановиться
162
- if (stopOnDeny) {
163
- const shouldStop = batchResults.some(r => !r.result.allow || r.result.force);
164
- if (shouldStop) break;
165
- }
166
- }
167
-
168
- return results;
169
- }
170
-
171
- /**
172
- * Нормализация результата политики
173
- */
174
- normalizeResult(result, policyName) {
175
- if (this.abac.options.strictMode && result === undefined) {
176
- return {
177
- allow: false,
178
- force: false,
179
- reason: `UNDEFINED_IN_STRICT_MODE_${policyName.toUpperCase()}`
180
- };
181
- }
182
-
183
- if (result && typeof result === 'object' && ('allow' in result || 'force' in result)) {
184
- return {
185
- allow: result.allow !== undefined ? !!result.allow : true,
186
- force: !!result.force,
187
- reason: result.reason || `POLICY_${policyName.toUpperCase()}`,
188
- };
189
- }
190
-
191
- if (result === true) {
192
- return {
193
- allow: true,
194
- force: false,
195
- reason: `ALLOWED_BY_${policyName.toUpperCase()}`
196
- };
197
- }
198
- if (result === false) {
199
- return {
200
- allow: false,
201
- force: false,
202
- reason: `DENIED_BY_${policyName.toUpperCase()}`
203
- };
204
- }
205
-
206
- return {
207
- allow: !this.abac.options.strictMode,
208
- force: false,
209
- reason: `NEUTRAL_${policyName.toUpperCase()}`
210
- };
211
- }
212
-
213
- /**
214
- * Основной метод проверки доступа
215
- */
216
- async checkAccess(rawContext, customPolicies = {}) {
217
- const startTime = Date.now();
218
- const context = this.normalizeContext(rawContext);
219
-
220
- // Проверка сервисного запроса
221
- if (context.isServiceRequest) {
222
- return { allow: true, reason: 'SERVICE_REQUEST_ALLOWED' };
223
- }
224
-
225
- // Проверка аутентификации
226
- if (!context.user && !context.options?.allowUnauthenticated) {
227
- return { allow: false, reason: 'UNAUTHENTICATED_ACCESS_DENIED' };
228
- }
229
-
230
- // Предзагрузка ресурса
231
- if (!context.currentResource) {
232
- await this.loadResource(context);
233
- }
234
-
235
- // Выполнение политик
236
- const result = await this.abac.policies.evaluate(context, customPolicies);
237
-
238
- // Аудит
239
- if (this.abac.options.enableAudit) {
240
- await this.audit(context, result, Date.now() - startTime);
241
- }
242
-
243
- return result;
244
- }
245
-
246
- /**
247
- * Загрузка ресурса
248
- */
249
- async loadResource(context) {
250
- const resourceModel = this.abac.getResourceModel(context.resource);
251
- if (!resourceModel) return;
252
-
253
- try {
254
- let currentResource;
255
- // Ищем ID в структурированной data
256
- const id = context.resourceId ||
257
- context.data?.body?._id ||
258
- context.data?.params?._id;
259
-
260
- if (id) {
261
- currentResource = await resourceModel.findById(id);
262
- } else if (context.data?.body?.url || context.data?.params?.url) {
263
- const url = context.data.body?.url || context.data.params?.url;
264
- currentResource = await resourceModel.findOne({ url });
265
- }
266
-
267
- if (currentResource) {
268
- context.currentResource = currentResource;
269
- context.resourceModel = resourceModel;
270
- context.resourceId = currentResource._id?.toString();
271
- }
272
- } catch (error) {
273
- this.abac.logger?.error('Resource loading error', {
274
- resource: context.resource,
275
- error: error.message
276
- });
277
- }
278
- }
279
-
280
- /**
281
- * Структурированный аудит
282
- */
283
- async audit(context, result, duration) {
284
- try {
285
- const auditEntry = {
286
- type: 'ACCESS_CHECK',
287
- timestamp: new Date().toISOString(),
288
- user: context.user,
289
- resource: context.resource,
290
- resourceId: context.resourceId,
291
- action: context.action,
292
- result: result.allow,
293
- reason: result.reason,
294
- duration: duration,
295
- ip: context.req?.ip,
296
- userAgent: context.req?.get?.('user-agent'),
297
- metadata: context.auditMetadata || {}
298
- };
299
-
300
- // Используем структурированное логирование
301
- await this.abac.logger.info('Access check', auditEntry);
302
-
303
- // Если критическое действие - дополнительный алерт
304
- if (['delete', 'admin', 'export'].includes(context.action)) {
305
- await this.abac.logger.warn('Critical action attempt', auditEntry);
306
- }
307
- } catch (error) {
308
- this.abac.logger?.error('Audit logging error', {
309
- error: error.message
310
- });
311
- }
312
- }
313
- }
@@ -1,276 +0,0 @@
1
- // @martyrs/src/modules/core/controllers/classes/abac/abac.adapter.express.js
2
- export default class ABACExpressAdapter {
3
- constructor(abac) {
4
- this.abac = abac;
5
- }
6
-
7
- /**
8
- * Основной middleware - разделен на составные части
9
- */
10
- middleware(resource, action, options = {}) {
11
- const middlewares = [];
12
-
13
- // 1. Access control
14
- middlewares.push(this._accessMiddleware(resource, action, options));
15
-
16
- // 2. Field validation (если включена)
17
- if (options.checkFields) {
18
- middlewares.push(this._fieldsValidationMiddleware(resource, action, options));
19
- }
20
-
21
- return middlewares;
22
- }
23
-
24
- /**
25
- * Middleware проверки доступа
26
- * @private
27
- */
28
- _accessMiddleware(resource, action, options = {}) {
29
- return async (req, res, next) => {
30
- try {
31
- const context = this._buildContext(req, resource, action, options);
32
- const accessResult = await this.abac.checkAccess(context, context.customPolicies);
33
-
34
- if (!accessResult.allow) {
35
- return this._sendAccessDenied(res, accessResult.reason);
36
- }
37
-
38
- // Сохраняем результат для последующих middleware
39
- req.abacContext = context;
40
- req.abacAccessResult = accessResult;
41
- next();
42
- } catch (error) {
43
- this.abac.logger?.error('ABAC middleware error', {
44
- resource,
45
- action,
46
- error: error.message,
47
- stack: error.stack
48
- });
49
- return this._sendError(res);
50
- }
51
- };
52
- }
53
-
54
- /**
55
- * Middleware проверки полей
56
- * @private
57
- */
58
- _fieldsValidationMiddleware(resource, action, options = {}) {
59
- return async (req, res, next) => {
60
- try {
61
- const context = req.abacContext || this._buildContext(req, resource, action, options);
62
- const fieldsResult = await this.abac.checkFields(context, req.body, action);
63
-
64
- if (fieldsResult.errors.length > 0 && options.strictFieldsMode) {
65
- return this._sendFieldError(res, fieldsResult.errors);
66
- }
67
-
68
- // Заменяем body отфильтрованными данными
69
- req.body = fieldsResult.allowed;
70
- req.abacFieldsResult = fieldsResult;
71
-
72
- next();
73
- } catch (error) {
74
- this.abac.logger?.error('Fields middleware error', {
75
- resource,
76
- action,
77
- error: error.message
78
- });
79
-
80
- if (options.passErrors) {
81
- next(error);
82
- } else {
83
- return this._sendError(res);
84
- }
85
- }
86
- };
87
- }
88
-
89
- /**
90
- * Построение контекста
91
- * @private
92
- */
93
- _buildContext(req, resource, action, options = {}) {
94
- return {
95
- user: req.userId,
96
- resource,
97
- action,
98
- req,
99
- // НЕ смешиваем body и query - передаем структурированно
100
- data: {
101
- body: req.body || {},
102
- query: req.query || {},
103
- params: req.params || {}
104
- },
105
- params: req.params,
106
- customPolicies: options.policies || {},
107
- options
108
- };
109
- }
110
-
111
- /**
112
- * Policy middleware
113
- */
114
- policyMiddleware(policyNames = [], customPolicies = {}, options = {}) {
115
- return async (req, res, next) => {
116
- try {
117
- const context = this._buildContext(
118
- req,
119
- options.resource || 'custom',
120
- options.action || 'access',
121
- options
122
- );
123
-
124
- const result = await this.abac.checkPolicies(context, policyNames, customPolicies);
125
-
126
- if (!result.allow) {
127
- return this._sendPolicyDenied(res, result.reason);
128
- }
129
-
130
- req.abacPolicyResult = result;
131
- next();
132
- } catch (error) {
133
- this.abac.logger?.error('Policy middleware error', {
134
- policies: policyNames,
135
- error: error.message
136
- });
137
- return this._sendError(res);
138
- }
139
- };
140
- }
141
-
142
- /**
143
- * Fields middleware для проверки/трансформации полей
144
- */
145
- fieldsMiddleware(resource, options = {}) {
146
- return async (req, res, next) => {
147
- try {
148
- // Определяем action из метода запроса
149
- const action = options.action || this._getActionFromMethod(req.method);
150
- const context = this._buildContext(req, resource, action, options);
151
-
152
- // Определяем какие данные проверять
153
- let dataToCheck = this._getDataToCheck(req, res, options);
154
-
155
- const fieldsResult = await this.abac.checkFields(context, dataToCheck, action);
156
-
157
- // Обработка ошибок
158
- if (fieldsResult.errors.length > 0) {
159
- if (options.strictMode) {
160
- return this._sendFieldError(res, fieldsResult.errors);
161
- }
162
- // В нестрогом режиме логируем ошибки
163
- this.abac.logger?.warn('Field validation errors', {
164
- resource,
165
- action,
166
- errors: fieldsResult.errors
167
- });
168
- }
169
-
170
- // Применяем результаты
171
- this._applyFieldsResult(req, res, options, fieldsResult);
172
-
173
- // Сохраняем результат
174
- req.abacFieldsResult = fieldsResult;
175
-
176
- next();
177
- } catch (error) {
178
- this.abac.logger?.error('Fields middleware error', {
179
- resource,
180
- error: error.message
181
- });
182
-
183
- if (options.passErrors) {
184
- next(error);
185
- } else {
186
- return this._sendError(res);
187
- }
188
- }
189
- };
190
- }
191
-
192
- /**
193
- * Получение action из HTTP метода
194
- * @private
195
- */
196
- _getActionFromMethod(method) {
197
- const methodActionMap = {
198
- 'GET': 'read',
199
- 'POST': 'create',
200
- 'PUT': 'update',
201
- 'PATCH': 'update',
202
- 'DELETE': 'delete'
203
- };
204
- return methodActionMap[method] || 'access';
205
- }
206
-
207
- /**
208
- * Определение данных для проверки
209
- * @private
210
- */
211
- _getDataToCheck(req, res, options) {
212
- if (req.method === 'GET' && options.checkQuery) {
213
- return req.query;
214
- }
215
-
216
- if (options.checkResponse && res.locals.data) {
217
- return res.locals.data;
218
- }
219
-
220
- return req.body;
221
- }
222
-
223
- /**
224
- * Применение результатов проверки полей
225
- * @private
226
- */
227
- _applyFieldsResult(req, res, options, fieldsResult) {
228
- if (req.method === 'GET' && options.checkQuery) {
229
- req.query = fieldsResult.allowed;
230
- } else if (options.checkResponse && res.locals.data) {
231
- res.locals.data = fieldsResult.transformed || fieldsResult.allowed;
232
- } else {
233
- req.body = fieldsResult.allowed;
234
- }
235
- }
236
-
237
- /**
238
- * Отправка ошибок - унифицированные методы
239
- * @private
240
- */
241
- _sendAccessDenied(res, reason) {
242
- return res.status(403).json({
243
- error: {
244
- code: 'ACCESS_DENIED',
245
- message: reason
246
- }
247
- });
248
- }
249
-
250
- _sendPolicyDenied(res, reason) {
251
- return res.status(403).json({
252
- error: {
253
- code: 'POLICY_DENIED',
254
- message: reason
255
- }
256
- });
257
- }
258
-
259
- _sendFieldError(res, errors) {
260
- return res.status(400).json({
261
- error: {
262
- code: 'FIELD_VALIDATION_ERROR',
263
- fields: errors
264
- }
265
- });
266
- }
267
-
268
- _sendError(res) {
269
- return res.status(500).json({
270
- error: {
271
- code: 'INTERNAL_ERROR',
272
- message: 'Access control error'
273
- }
274
- });
275
- }
276
- }