@directus/api 21.0.0 → 22.1.0

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 (299) hide show
  1. package/dist/app.js +4 -4
  2. package/dist/auth/drivers/ldap.js +4 -4
  3. package/dist/auth/drivers/local.js +4 -4
  4. package/dist/auth/drivers/oauth2.js +4 -4
  5. package/dist/auth/drivers/openid.js +2 -4
  6. package/dist/cache.js +3 -0
  7. package/dist/cli/commands/bootstrap/index.js +8 -2
  8. package/dist/cli/commands/init/index.js +9 -10
  9. package/dist/cli/commands/init/questions.d.ts +7 -6
  10. package/dist/cli/commands/init/questions.js +2 -2
  11. package/dist/cli/utils/create-env/index.d.ts +2 -2
  12. package/dist/cli/utils/create-env/index.js +3 -1
  13. package/dist/cli/utils/defaults.d.ts +4 -11
  14. package/dist/cli/utils/defaults.js +7 -1
  15. package/dist/cli/utils/drivers.js +1 -1
  16. package/dist/constants.d.ts +1 -1
  17. package/dist/controllers/access.d.ts +2 -0
  18. package/dist/controllers/access.js +148 -0
  19. package/dist/controllers/auth.js +5 -16
  20. package/dist/controllers/permissions.js +14 -2
  21. package/dist/controllers/policies.d.ts +2 -0
  22. package/dist/controllers/policies.js +169 -0
  23. package/dist/controllers/roles.js +22 -1
  24. package/dist/controllers/tus.js +14 -26
  25. package/dist/controllers/users.js +0 -55
  26. package/dist/database/get-ast-from-query/get-ast-from-query.d.ts +16 -0
  27. package/dist/database/get-ast-from-query/get-ast-from-query.js +82 -0
  28. package/dist/database/get-ast-from-query/lib/convert-wildcards.d.ts +13 -0
  29. package/dist/database/get-ast-from-query/lib/convert-wildcards.js +69 -0
  30. package/dist/database/get-ast-from-query/lib/parse-fields.d.ts +15 -0
  31. package/dist/database/get-ast-from-query/lib/parse-fields.js +200 -0
  32. package/dist/database/get-ast-from-query/utils/get-deep-query.d.ts +14 -0
  33. package/dist/database/get-ast-from-query/utils/get-deep-query.js +17 -0
  34. package/dist/database/get-ast-from-query/utils/get-related-collection.d.ts +2 -0
  35. package/dist/database/get-ast-from-query/utils/get-related-collection.js +13 -0
  36. package/dist/database/get-ast-from-query/utils/get-relation.d.ts +2 -0
  37. package/dist/database/get-ast-from-query/utils/get-relation.js +7 -0
  38. package/dist/database/helpers/fn/types.d.ts +2 -1
  39. package/dist/database/helpers/fn/types.js +1 -1
  40. package/dist/database/helpers/geometry/dialects/mssql.d.ts +1 -1
  41. package/dist/database/helpers/geometry/dialects/mssql.js +4 -2
  42. package/dist/database/helpers/geometry/dialects/mysql.js +1 -1
  43. package/dist/database/helpers/geometry/dialects/oracle.d.ts +1 -1
  44. package/dist/database/helpers/geometry/dialects/oracle.js +5 -3
  45. package/dist/database/helpers/geometry/types.d.ts +1 -1
  46. package/dist/database/helpers/geometry/types.js +4 -2
  47. package/dist/database/helpers/index.d.ts +3 -3
  48. package/dist/database/helpers/schema/dialects/cockroachdb.d.ts +2 -1
  49. package/dist/database/helpers/schema/dialects/cockroachdb.js +4 -0
  50. package/dist/database/helpers/schema/dialects/mssql.d.ts +2 -1
  51. package/dist/database/helpers/schema/dialects/mssql.js +4 -0
  52. package/dist/database/helpers/schema/dialects/oracle.d.ts +2 -1
  53. package/dist/database/helpers/schema/dialects/oracle.js +4 -0
  54. package/dist/database/helpers/schema/dialects/postgres.d.ts +2 -1
  55. package/dist/database/helpers/schema/dialects/postgres.js +4 -0
  56. package/dist/database/helpers/schema/types.d.ts +5 -0
  57. package/dist/database/helpers/schema/types.js +3 -0
  58. package/dist/database/helpers/schema/utils/preprocess-bindings.d.ts +8 -0
  59. package/dist/database/helpers/schema/utils/preprocess-bindings.js +30 -0
  60. package/dist/database/index.js +6 -1
  61. package/dist/database/migrations/20210519A-add-system-fk-triggers.js +3 -2
  62. package/dist/database/migrations/20230721A-require-shares-fields.js +3 -5
  63. package/dist/database/migrations/20240716A-update-files-date-fields.js +3 -7
  64. package/dist/{utils/merge-permissions.d.ts → database/migrations/20240806A-permissions-policies.d.ts} +4 -1
  65. package/dist/database/migrations/20240806A-permissions-policies.js +352 -0
  66. package/dist/database/run-ast/lib/get-db-query.d.ts +4 -0
  67. package/dist/database/run-ast/lib/get-db-query.js +218 -0
  68. package/dist/database/run-ast/lib/parse-current-level.d.ts +7 -0
  69. package/dist/database/run-ast/lib/parse-current-level.js +41 -0
  70. package/dist/database/run-ast/run-ast.d.ts +7 -0
  71. package/dist/database/run-ast/run-ast.js +107 -0
  72. package/dist/database/{run-ast.d.ts → run-ast/types.d.ts} +3 -9
  73. package/dist/database/run-ast/types.js +1 -0
  74. package/dist/database/run-ast/utils/apply-case-when.d.ts +16 -0
  75. package/dist/database/run-ast/utils/apply-case-when.js +27 -0
  76. package/dist/database/run-ast/utils/apply-parent-filters.d.ts +3 -0
  77. package/dist/database/run-ast/utils/apply-parent-filters.js +55 -0
  78. package/dist/database/run-ast/utils/get-column-pre-processor.d.ts +10 -0
  79. package/dist/database/run-ast/utils/get-column-pre-processor.js +57 -0
  80. package/dist/database/run-ast/utils/get-field-alias.d.ts +2 -0
  81. package/dist/database/run-ast/utils/get-field-alias.js +4 -0
  82. package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.d.ts +5 -0
  83. package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.js +23 -0
  84. package/dist/database/run-ast/utils/merge-with-parent-items.d.ts +3 -0
  85. package/dist/database/run-ast/utils/merge-with-parent-items.js +87 -0
  86. package/dist/database/run-ast/utils/remove-temporary-fields.d.ts +3 -0
  87. package/dist/database/run-ast/utils/remove-temporary-fields.js +73 -0
  88. package/dist/database/run-ast/utils/with-preprocess-bindings.d.ts +2 -0
  89. package/dist/database/run-ast/utils/with-preprocess-bindings.js +14 -0
  90. package/dist/flows.js +3 -4
  91. package/dist/middleware/authenticate.js +2 -7
  92. package/dist/middleware/cache.js +1 -1
  93. package/dist/middleware/respond.js +1 -1
  94. package/dist/permissions/cache.d.ts +2 -0
  95. package/dist/permissions/cache.js +23 -0
  96. package/dist/permissions/lib/fetch-permissions.d.ts +11 -0
  97. package/dist/permissions/lib/fetch-permissions.js +56 -0
  98. package/dist/permissions/lib/fetch-policies.d.ts +14 -0
  99. package/dist/permissions/lib/fetch-policies.js +43 -0
  100. package/dist/permissions/lib/fetch-roles-tree.d.ts +3 -0
  101. package/dist/permissions/lib/fetch-roles-tree.js +28 -0
  102. package/dist/{services/permissions → permissions}/lib/with-app-minimal-permissions.d.ts +1 -1
  103. package/dist/permissions/lib/with-app-minimal-permissions.js +10 -0
  104. package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.d.ts +7 -0
  105. package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.js +56 -0
  106. package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.d.ts +3 -0
  107. package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.js +16 -0
  108. package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.d.ts +8 -0
  109. package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.js +24 -0
  110. package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.d.ts +9 -0
  111. package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js +31 -0
  112. package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.d.ts +16 -0
  113. package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.js +27 -0
  114. package/dist/permissions/modules/fetch-global-access/fetch-global-access.d.ts +10 -0
  115. package/dist/permissions/modules/fetch-global-access/fetch-global-access.js +23 -0
  116. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.d.ts +5 -0
  117. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.js +7 -0
  118. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.d.ts +5 -0
  119. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.js +10 -0
  120. package/dist/permissions/modules/fetch-global-access/types.d.ts +4 -0
  121. package/dist/permissions/modules/fetch-global-access/types.js +1 -0
  122. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.d.ts +4 -0
  123. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.js +27 -0
  124. package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.d.ts +12 -0
  125. package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.js +32 -0
  126. package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.d.ts +4 -0
  127. package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.js +29 -0
  128. package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.d.ts +4 -0
  129. package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.js +49 -0
  130. package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.d.ts +3 -0
  131. package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.js +56 -0
  132. package/dist/permissions/modules/process-ast/lib/field-map-from-ast.d.ts +4 -0
  133. package/dist/permissions/modules/process-ast/lib/field-map-from-ast.js +8 -0
  134. package/dist/permissions/modules/process-ast/lib/inject-cases.d.ts +9 -0
  135. package/dist/permissions/modules/process-ast/lib/inject-cases.js +93 -0
  136. package/dist/permissions/modules/process-ast/process-ast.d.ts +9 -0
  137. package/dist/permissions/modules/process-ast/process-ast.js +39 -0
  138. package/dist/permissions/modules/process-ast/types.d.ts +18 -0
  139. package/dist/permissions/modules/process-ast/types.js +1 -0
  140. package/dist/permissions/modules/process-ast/utils/collections-in-field-map.d.ts +2 -0
  141. package/dist/permissions/modules/process-ast/utils/collections-in-field-map.js +7 -0
  142. package/dist/permissions/modules/process-ast/utils/dedupe-access.d.ts +12 -0
  143. package/dist/permissions/modules/process-ast/utils/dedupe-access.js +30 -0
  144. package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.d.ts +15 -0
  145. package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.js +60 -0
  146. package/dist/permissions/modules/process-ast/utils/find-related-collection.d.ts +3 -0
  147. package/dist/permissions/modules/process-ast/utils/find-related-collection.js +9 -0
  148. package/dist/permissions/modules/process-ast/utils/flatten-filter.d.ts +3 -0
  149. package/dist/permissions/modules/process-ast/utils/flatten-filter.js +34 -0
  150. package/dist/permissions/modules/process-ast/utils/format-a2o-key.d.ts +1 -0
  151. package/dist/permissions/modules/process-ast/utils/format-a2o-key.js +3 -0
  152. package/dist/permissions/modules/process-ast/utils/get-info-for-path.d.ts +5 -0
  153. package/dist/permissions/modules/process-ast/utils/get-info-for-path.js +7 -0
  154. package/dist/permissions/modules/process-ast/utils/has-item-permissions.d.ts +2 -0
  155. package/dist/permissions/modules/process-ast/utils/has-item-permissions.js +3 -0
  156. package/dist/permissions/modules/process-ast/utils/stringify-query-path.d.ts +2 -0
  157. package/dist/permissions/modules/process-ast/utils/stringify-query-path.js +3 -0
  158. package/dist/permissions/modules/process-ast/utils/validate-path/create-error.d.ts +3 -0
  159. package/dist/permissions/modules/process-ast/utils/validate-path/create-error.js +16 -0
  160. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.d.ts +2 -0
  161. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.js +12 -0
  162. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.d.ts +2 -0
  163. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.js +28 -0
  164. package/dist/permissions/modules/process-payload/lib/is-field-nullable.d.ts +5 -0
  165. package/dist/permissions/modules/process-payload/lib/is-field-nullable.js +12 -0
  166. package/dist/permissions/modules/process-payload/process-payload.d.ts +13 -0
  167. package/dist/permissions/modules/process-payload/process-payload.js +77 -0
  168. package/dist/permissions/modules/validate-access/lib/validate-collection-access.d.ts +12 -0
  169. package/dist/permissions/modules/validate-access/lib/validate-collection-access.js +11 -0
  170. package/dist/permissions/modules/validate-access/lib/validate-item-access.d.ts +9 -0
  171. package/dist/permissions/modules/validate-access/lib/validate-item-access.js +33 -0
  172. package/dist/permissions/modules/validate-access/validate-access.d.ts +14 -0
  173. package/dist/permissions/modules/validate-access/validate-access.js +28 -0
  174. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.d.ts +1 -0
  175. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.js +8 -0
  176. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.d.ts +5 -0
  177. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.js +10 -0
  178. package/dist/permissions/types.d.ts +6 -0
  179. package/dist/permissions/types.js +1 -0
  180. package/dist/permissions/utils/create-default-accountability.d.ts +2 -0
  181. package/dist/permissions/utils/create-default-accountability.js +11 -0
  182. package/dist/permissions/utils/extract-required-dynamic-variable-context.d.ts +8 -0
  183. package/dist/permissions/utils/extract-required-dynamic-variable-context.js +27 -0
  184. package/dist/permissions/utils/fetch-dynamic-variable-context.d.ts +9 -0
  185. package/dist/permissions/utils/fetch-dynamic-variable-context.js +43 -0
  186. package/dist/permissions/utils/filter-policies-by-ip.d.ts +2 -0
  187. package/dist/permissions/utils/filter-policies-by-ip.js +15 -0
  188. package/dist/permissions/utils/get-unaliased-field-key.d.ts +5 -0
  189. package/dist/permissions/utils/get-unaliased-field-key.js +17 -0
  190. package/dist/permissions/utils/process-permissions.d.ts +7 -0
  191. package/dist/permissions/utils/process-permissions.js +9 -0
  192. package/dist/permissions/utils/with-cache.d.ts +10 -0
  193. package/dist/permissions/utils/with-cache.js +25 -0
  194. package/dist/server.js +17 -4
  195. package/dist/services/access.d.ts +10 -0
  196. package/dist/services/access.js +43 -0
  197. package/dist/services/activity.js +22 -10
  198. package/dist/services/assets.d.ts +2 -3
  199. package/dist/services/assets.js +10 -5
  200. package/dist/services/authentication.js +18 -18
  201. package/dist/services/collections.js +18 -17
  202. package/dist/services/fields.d.ts +0 -1
  203. package/dist/services/fields.js +54 -25
  204. package/dist/services/files.js +10 -3
  205. package/dist/services/graphql/index.d.ts +3 -3
  206. package/dist/services/graphql/index.js +126 -22
  207. package/dist/services/graphql/subscription.js +2 -4
  208. package/dist/services/import-export.d.ts +3 -1
  209. package/dist/services/import-export.js +67 -9
  210. package/dist/services/index.d.ts +3 -2
  211. package/dist/services/index.js +3 -2
  212. package/dist/services/items.js +115 -44
  213. package/dist/services/meta.js +60 -23
  214. package/dist/services/notifications.js +14 -6
  215. package/dist/services/payload.d.ts +9 -10
  216. package/dist/services/payload.js +18 -3
  217. package/dist/services/{permissions/index.d.ts → permissions.d.ts} +5 -7
  218. package/dist/services/{permissions/index.js → permissions.js} +30 -54
  219. package/dist/services/policies.d.ts +12 -0
  220. package/dist/services/policies.js +87 -0
  221. package/dist/services/relations.d.ts +0 -6
  222. package/dist/services/relations.js +27 -30
  223. package/dist/services/roles.d.ts +4 -12
  224. package/dist/services/roles.js +57 -424
  225. package/dist/services/shares.d.ts +0 -2
  226. package/dist/services/shares.js +12 -8
  227. package/dist/services/specifications.d.ts +2 -2
  228. package/dist/services/specifications.js +39 -27
  229. package/dist/services/users.d.ts +1 -5
  230. package/dist/services/users.js +78 -161
  231. package/dist/services/utils.js +11 -7
  232. package/dist/services/versions.d.ts +0 -2
  233. package/dist/services/versions.js +34 -10
  234. package/dist/telemetry/lib/get-report.js +2 -2
  235. package/dist/telemetry/utils/check-user-limits.d.ts +5 -0
  236. package/dist/telemetry/utils/check-user-limits.js +19 -0
  237. package/dist/types/ast.d.ts +43 -1
  238. package/dist/types/database.d.ts +1 -1
  239. package/dist/types/items.d.ts +11 -0
  240. package/dist/utils/apply-query.d.ts +11 -7
  241. package/dist/utils/apply-query.js +69 -11
  242. package/dist/utils/fetch-user-count/fetch-access-lookup.d.ts +19 -0
  243. package/dist/utils/fetch-user-count/fetch-access-lookup.js +23 -0
  244. package/dist/utils/fetch-user-count/fetch-access-roles.d.ts +16 -0
  245. package/dist/utils/fetch-user-count/fetch-access-roles.js +37 -0
  246. package/dist/utils/fetch-user-count/fetch-active-users.d.ts +6 -0
  247. package/dist/utils/fetch-user-count/fetch-active-users.js +3 -0
  248. package/dist/utils/fetch-user-count/fetch-user-count.d.ts +12 -0
  249. package/dist/utils/fetch-user-count/fetch-user-count.js +64 -0
  250. package/dist/utils/fetch-user-count/get-user-count-query.d.ts +20 -0
  251. package/dist/utils/fetch-user-count/get-user-count-query.js +17 -0
  252. package/dist/utils/get-accountability-for-role.js +16 -25
  253. package/dist/utils/get-accountability-for-token.js +17 -16
  254. package/dist/utils/get-address.d.ts +5 -0
  255. package/dist/utils/get-address.js +13 -0
  256. package/dist/utils/get-cache-key.d.ts +1 -1
  257. package/dist/utils/get-cache-key.js +12 -1
  258. package/dist/utils/get-column.d.ts +2 -1
  259. package/dist/utils/get-column.js +1 -0
  260. package/dist/utils/get-service.js +5 -1
  261. package/dist/utils/reduce-schema.d.ts +4 -6
  262. package/dist/utils/reduce-schema.js +16 -32
  263. package/dist/utils/sanitize-schema.d.ts +1 -1
  264. package/dist/utils/transaction.js +28 -11
  265. package/dist/utils/validate-user-count-integrity.d.ts +13 -0
  266. package/dist/utils/validate-user-count-integrity.js +29 -0
  267. package/dist/websocket/authenticate.d.ts +0 -2
  268. package/dist/websocket/authenticate.js +0 -12
  269. package/dist/websocket/controllers/graphql.js +3 -7
  270. package/dist/websocket/controllers/hooks.js +4 -0
  271. package/dist/websocket/controllers/rest.js +2 -5
  272. package/dist/websocket/handlers/subscribe.js +0 -2
  273. package/dist/websocket/utils/items.d.ts +1 -1
  274. package/package.json +31 -30
  275. package/dist/database/run-ast.js +0 -458
  276. package/dist/middleware/check-ip.d.ts +0 -2
  277. package/dist/middleware/check-ip.js +0 -37
  278. package/dist/middleware/get-permissions.d.ts +0 -3
  279. package/dist/middleware/get-permissions.js +0 -10
  280. package/dist/services/authorization.d.ts +0 -17
  281. package/dist/services/authorization.js +0 -456
  282. package/dist/services/permissions/lib/with-app-minimal-permissions.js +0 -13
  283. package/dist/telemetry/utils/check-increased-user-limits.d.ts +0 -7
  284. package/dist/telemetry/utils/check-increased-user-limits.js +0 -25
  285. package/dist/telemetry/utils/get-role-counts-by-roles.d.ts +0 -6
  286. package/dist/telemetry/utils/get-role-counts-by-roles.js +0 -27
  287. package/dist/telemetry/utils/get-role-counts-by-users.d.ts +0 -11
  288. package/dist/telemetry/utils/get-role-counts-by-users.js +0 -34
  289. package/dist/telemetry/utils/get-user-count.d.ts +0 -8
  290. package/dist/telemetry/utils/get-user-count.js +0 -33
  291. package/dist/telemetry/utils/get-user-counts-by-roles.d.ts +0 -7
  292. package/dist/telemetry/utils/get-user-counts-by-roles.js +0 -35
  293. package/dist/utils/get-ast-from-query.d.ts +0 -13
  294. package/dist/utils/get-ast-from-query.js +0 -297
  295. package/dist/utils/get-permissions.d.ts +0 -2
  296. package/dist/utils/get-permissions.js +0 -150
  297. package/dist/utils/merge-permissions-for-share.d.ts +0 -4
  298. package/dist/utils/merge-permissions-for-share.js +0 -109
  299. package/dist/utils/merge-permissions.js +0 -95
@@ -1,12 +1,10 @@
1
- import type { Item, ItemPermissions, PermissionsAction, PrimaryKey, Query } from '@directus/types';
2
- import type Keyv from 'keyv';
3
- import type { AbstractServiceOptions, MutationOptions } from '../../types/index.js';
4
- import type { QueryOptions } from '../items.js';
5
- import { ItemsService } from '../items.js';
1
+ import type { Item, ItemPermissions, PrimaryKey, Query } from '@directus/types';
2
+ import type { AbstractServiceOptions, MutationOptions } from '../types/index.js';
3
+ import type { QueryOptions } from './items.js';
4
+ import { ItemsService } from './items.js';
6
5
  export declare class PermissionsService extends ItemsService {
7
- systemCache: Keyv<any>;
8
6
  constructor(options: AbstractServiceOptions);
9
- getAllowedFields(action: PermissionsAction, collection?: string): Record<string, string[]>;
7
+ private clearCaches;
10
8
  readByQuery(query: Query, opts?: QueryOptions): Promise<Partial<Item>[]>;
11
9
  createOne(data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey>;
12
10
  createMany(data: Partial<Item>[], opts?: MutationOptions): Promise<PrimaryKey[]>;
@@ -1,32 +1,17 @@
1
1
  import { ForbiddenError } from '@directus/errors';
2
- import { clearSystemCache, getCache } from '../../cache.js';
3
- import { AuthorizationService } from '../authorization.js';
4
- import { ItemsService } from '../items.js';
5
- import { withAppMinimalPermissions } from './lib/with-app-minimal-permissions.js';
2
+ import { clearSystemCache } from '../cache.js';
3
+ import { withAppMinimalPermissions } from '../permissions/lib/with-app-minimal-permissions.js';
4
+ import { validateAccess } from '../permissions/modules/validate-access/validate-access.js';
5
+ import { ItemsService } from './items.js';
6
6
  export class PermissionsService extends ItemsService {
7
- systemCache;
8
7
  constructor(options) {
9
8
  super('directus_permissions', options);
10
- const { systemCache } = getCache();
11
- this.systemCache = systemCache;
12
9
  }
13
- getAllowedFields(action, collection) {
14
- const results = this.accountability?.permissions?.filter((permission) => {
15
- let matchesCollection = true;
16
- if (collection) {
17
- matchesCollection = permission.collection === collection;
18
- }
19
- const matchesAction = permission.action === action;
20
- return collection ? matchesCollection && matchesAction : matchesAction;
21
- }) ?? [];
22
- const fieldsPerCollection = {};
23
- for (const result of results) {
24
- const { collection, fields } = result;
25
- if (!fieldsPerCollection[collection])
26
- fieldsPerCollection[collection] = [];
27
- fieldsPerCollection[collection].push(...(fields ?? []));
10
+ async clearCaches(opts) {
11
+ await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
12
+ if (this.cache && opts?.autoPurgeCache !== false) {
13
+ await this.cache.clear();
28
14
  }
29
- return fieldsPerCollection;
30
15
  }
31
16
  async readByQuery(query, opts) {
32
17
  const result = (await super.readByQuery(query, opts));
@@ -34,50 +19,32 @@ export class PermissionsService extends ItemsService {
34
19
  }
35
20
  async createOne(data, opts) {
36
21
  const res = await super.createOne(data, opts);
37
- await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
38
- if (this.cache && opts?.autoPurgeCache !== false) {
39
- await this.cache.clear();
40
- }
22
+ await this.clearCaches(opts);
41
23
  return res;
42
24
  }
43
25
  async createMany(data, opts) {
44
26
  const res = await super.createMany(data, opts);
45
- await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
46
- if (this.cache && opts?.autoPurgeCache !== false) {
47
- await this.cache.clear();
48
- }
27
+ await this.clearCaches(opts);
49
28
  return res;
50
29
  }
51
30
  async updateBatch(data, opts) {
52
31
  const res = await super.updateBatch(data, opts);
53
- await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
54
- if (this.cache && opts?.autoPurgeCache !== false) {
55
- await this.cache.clear();
56
- }
32
+ await this.clearCaches(opts);
57
33
  return res;
58
34
  }
59
35
  async updateMany(keys, data, opts) {
60
36
  const res = await super.updateMany(keys, data, opts);
61
- await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
62
- if (this.cache && opts?.autoPurgeCache !== false) {
63
- await this.cache.clear();
64
- }
37
+ await this.clearCaches(opts);
65
38
  return res;
66
39
  }
67
40
  async upsertMany(payloads, opts) {
68
41
  const res = await super.upsertMany(payloads, opts);
69
- await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
70
- if (this.cache && opts?.autoPurgeCache !== false) {
71
- await this.cache.clear();
72
- }
42
+ await this.clearCaches(opts);
73
43
  return res;
74
44
  }
75
45
  async deleteMany(keys, opts) {
76
46
  const res = await super.deleteMany(keys, opts);
77
- await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
78
- if (this.cache && opts?.autoPurgeCache !== false) {
79
- await this.cache.clear();
80
- }
47
+ await this.clearCaches(opts);
81
48
  return res;
82
49
  }
83
50
  async getItemPermissions(collection, primaryKey) {
@@ -115,16 +82,25 @@ export class PermissionsService extends ItemsService {
115
82
  updateAction = 'create';
116
83
  }
117
84
  }
118
- const authorizationService = new AuthorizationService({
119
- knex: this.knex,
120
- accountability: this.accountability,
121
- schema: this.schema,
122
- });
123
85
  await Promise.all(Object.keys(itemPermissions).map((key) => {
124
86
  const action = key;
125
87
  const checkAction = action === 'update' ? updateAction : action;
126
- return authorizationService
127
- .checkAccess(checkAction, collection, primaryKey)
88
+ if (!this.accountability) {
89
+ itemPermissions[action].access = true;
90
+ return Promise.resolve();
91
+ }
92
+ const opts = {
93
+ accountability: this.accountability,
94
+ action: checkAction,
95
+ collection,
96
+ };
97
+ if (primaryKey) {
98
+ opts.primaryKeys = [primaryKey];
99
+ }
100
+ return validateAccess(opts, {
101
+ schema: this.schema,
102
+ knex: this.knex,
103
+ })
128
104
  .then(() => (itemPermissions[action].access = true))
129
105
  .catch(() => { });
130
106
  }));
@@ -0,0 +1,12 @@
1
+ import type { Policy, PrimaryKey } from '@directus/types';
2
+ import type { AbstractServiceOptions, MutationOptions } from '../types/index.js';
3
+ import { ItemsService } from './items.js';
4
+ export declare class PoliciesService extends ItemsService<Policy> {
5
+ constructor(options: AbstractServiceOptions);
6
+ private clearCaches;
7
+ private isIpAccessValid;
8
+ private assertValidIpAccess;
9
+ createOne(data: Partial<Policy>, opts?: MutationOptions): Promise<PrimaryKey>;
10
+ updateMany(keys: PrimaryKey[], data: Partial<Policy>, opts?: MutationOptions): Promise<PrimaryKey[]>;
11
+ deleteMany(keys: PrimaryKey[], opts?: MutationOptions): Promise<PrimaryKey[]>;
12
+ }
@@ -0,0 +1,87 @@
1
+ import { InvalidPayloadError } from '@directus/errors';
2
+ import { getMatch } from 'ip-matching';
3
+ import { clearSystemCache } from '../cache.js';
4
+ import { clearCache as clearPermissionsCache } from '../permissions/cache.js';
5
+ import { UserIntegrityCheckFlag } from '../utils/validate-user-count-integrity.js';
6
+ import { ItemsService } from './items.js';
7
+ export class PoliciesService extends ItemsService {
8
+ constructor(options) {
9
+ super('directus_policies', options);
10
+ }
11
+ async clearCaches(opts) {
12
+ await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
13
+ if (this.cache && opts?.autoPurgeCache !== false) {
14
+ await this.cache.clear();
15
+ }
16
+ }
17
+ isIpAccessValid(value) {
18
+ if (value === undefined)
19
+ return false;
20
+ if (value === null)
21
+ return true;
22
+ if (Array.isArray(value) && value.length === 0)
23
+ return true;
24
+ for (const ip of value) {
25
+ if (typeof ip !== 'string' || ip.includes('*'))
26
+ return false;
27
+ try {
28
+ const match = getMatch(ip);
29
+ if (match.type == 'IPMask')
30
+ return false;
31
+ }
32
+ catch {
33
+ return false;
34
+ }
35
+ }
36
+ return true;
37
+ }
38
+ assertValidIpAccess(partialItem) {
39
+ if ('ip_access' in partialItem && !this.isIpAccessValid(partialItem['ip_access'])) {
40
+ throw new InvalidPayloadError({
41
+ reason: 'IP Access contains an incorrect value. Valid values are: IP addresses, IP ranges and CIDR blocks',
42
+ });
43
+ }
44
+ }
45
+ async createOne(data, opts = {}) {
46
+ this.assertValidIpAccess(data);
47
+ // A policy has been created, but the attachment to a user/role happens in the AccessService,
48
+ // so no need to check user integrity
49
+ const result = await super.createOne(data, opts);
50
+ // TODO is this necessary? Since the attachment should be handled in the AccessService
51
+ // A new policy has created, clear the permissions cache
52
+ await clearPermissionsCache();
53
+ return result;
54
+ }
55
+ async updateMany(keys, data, opts = {}) {
56
+ this.assertValidIpAccess(data);
57
+ if ('admin_access' in data) {
58
+ let flags = UserIntegrityCheckFlag.RemainingAdmins;
59
+ if (data['admin_access'] === true) {
60
+ // Only need to perform a full user count if the policy allows admin access
61
+ flags |= UserIntegrityCheckFlag.All;
62
+ }
63
+ opts.userIntegrityCheckFlags = (opts.userIntegrityCheckFlags ?? UserIntegrityCheckFlag.None) | flags;
64
+ }
65
+ if ('app_access' in data) {
66
+ opts.userIntegrityCheckFlags =
67
+ (opts.userIntegrityCheckFlags ?? UserIntegrityCheckFlag.None) | UserIntegrityCheckFlag.UserLimits;
68
+ }
69
+ if (opts.userIntegrityCheckFlags)
70
+ opts.onRequireUserIntegrityCheck?.(opts.userIntegrityCheckFlags);
71
+ const result = await super.updateMany(keys, data, opts);
72
+ if ('admin_access' in data || 'app_access' in data || 'ip_access' in data || 'enforce_tfa' in data) {
73
+ // Some relevant properties on policies have been updated, clear the caches
74
+ await this.clearCaches(opts);
75
+ }
76
+ return result;
77
+ }
78
+ async deleteMany(keys, opts = {}) {
79
+ opts.userIntegrityCheckFlags = UserIntegrityCheckFlag.All;
80
+ opts.onRequireUserIntegrityCheck?.(opts.userIntegrityCheckFlags);
81
+ const result = await super.deleteMany(keys, opts);
82
+ // TODO is this necessary? Since the detachment should be handled in the AccessService
83
+ // Some policies have been deleted, clear the permissions cache
84
+ await this.clearCaches(opts);
85
+ return result;
86
+ }
87
+ }
@@ -5,10 +5,8 @@ import type { Knex } from 'knex';
5
5
  import type { Helpers } from '../database/helpers/index.js';
6
6
  import type { AbstractServiceOptions, MutationOptions } from '../types/index.js';
7
7
  import { ItemsService, type QueryOptions } from './items.js';
8
- import { PermissionsService } from './permissions/index.js';
9
8
  export declare class RelationsService {
10
9
  knex: Knex;
11
- permissionsService: PermissionsService;
12
10
  schemaInspector: SchemaInspector;
13
11
  accountability: Accountability | null;
14
12
  schema: SchemaOverview;
@@ -34,10 +32,6 @@ export declare class RelationsService {
34
32
  * Delete an existing relationship
35
33
  */
36
34
  deleteOne(collection: string, field: string, opts?: MutationOptions): Promise<void>;
37
- /**
38
- * Whether or not the current user has read access to relations
39
- */
40
- private get hasReadAccess();
41
35
  /**
42
36
  * Combine raw schema foreign key information with Directus relations meta rows to form final
43
37
  * Relation objects
@@ -1,3 +1,4 @@
1
+ import { useEnv } from '@directus/env';
1
2
  import { ForbiddenError, InvalidPayloadError } from '@directus/errors';
2
3
  import { createInspector } from '@directus/schema';
3
4
  import { systemRelationRows } from '@directus/system-data';
@@ -6,16 +7,16 @@ import { clearSystemCache, getCache, getCacheValue, setCacheValue } from '../cac
6
7
  import { getHelpers } from '../database/helpers/index.js';
7
8
  import getDatabase, { getSchemaInspector } from '../database/index.js';
8
9
  import emitter from '../emitter.js';
10
+ import { fetchAllowedFieldMap } from '../permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js';
11
+ import { fetchAllowedFields } from '../permissions/modules/fetch-allowed-fields/fetch-allowed-fields.js';
12
+ import { validateAccess } from '../permissions/modules/validate-access/validate-access.js';
9
13
  import { getDefaultIndexName } from '../utils/get-default-index-name.js';
10
14
  import { getSchema } from '../utils/get-schema.js';
11
15
  import { transaction } from '../utils/transaction.js';
12
16
  import { ItemsService } from './items.js';
13
- import { PermissionsService } from './permissions/index.js';
14
- import { useEnv } from '@directus/env';
15
17
  const env = useEnv();
16
18
  export class RelationsService {
17
19
  knex;
18
- permissionsService;
19
20
  schemaInspector;
20
21
  accountability;
21
22
  schema;
@@ -25,7 +26,6 @@ export class RelationsService {
25
26
  helpers;
26
27
  constructor(options) {
27
28
  this.knex = options.knex || getDatabase();
28
- this.permissionsService = new PermissionsService(options);
29
29
  this.schemaInspector = options.knex ? createInspector(options.knex) : getSchemaInspector();
30
30
  this.schema = options.schema;
31
31
  this.accountability = options.accountability || null;
@@ -59,8 +59,15 @@ export class RelationsService {
59
59
  return foreignKeys;
60
60
  }
61
61
  async readAll(collection, opts) {
62
- if (this.accountability && this.accountability.admin !== true && this.hasReadAccess === false) {
63
- throw new ForbiddenError();
62
+ if (this.accountability) {
63
+ await validateAccess({
64
+ accountability: this.accountability,
65
+ action: 'read',
66
+ collection: 'directus_relations',
67
+ }, {
68
+ knex: this.knex,
69
+ schema: this.schema,
70
+ });
64
71
  }
65
72
  const metaReadQuery = {
66
73
  limit: -1,
@@ -86,18 +93,17 @@ export class RelationsService {
86
93
  }
87
94
  async readOne(collection, field) {
88
95
  if (this.accountability && this.accountability.admin !== true) {
89
- if (this.hasReadAccess === false) {
90
- throw new ForbiddenError();
91
- }
92
- const permissions = this.accountability.permissions?.find((permission) => {
93
- return permission.action === 'read' && permission.collection === collection;
96
+ await validateAccess({
97
+ accountability: this.accountability,
98
+ action: 'read',
99
+ collection: 'directus_relations',
100
+ }, {
101
+ schema: this.schema,
102
+ knex: this.knex,
94
103
  });
95
- if (!permissions || !permissions.fields)
104
+ const allowedFields = await fetchAllowedFields({ collection, action: 'read', accountability: this.accountability }, { schema: this.schema, knex: this.knex });
105
+ if (allowedFields.includes('*') === false && allowedFields.includes(field) === false) {
96
106
  throw new ForbiddenError();
97
- if (permissions.fields.includes('*') === false) {
98
- const allowedFields = permissions.fields;
99
- if (allowedFields.includes(field) === false)
100
- throw new ForbiddenError();
101
107
  }
102
108
  }
103
109
  const metaRow = await this.relationsItemService.readByQuery({
@@ -379,14 +385,6 @@ export class RelationsService {
379
385
  }
380
386
  }
381
387
  }
382
- /**
383
- * Whether or not the current user has read access to relations
384
- */
385
- get hasReadAccess() {
386
- return !!this.accountability?.permissions?.find((permission) => {
387
- return permission.collection === 'directus_relations' && permission.action === 'read';
388
- });
389
- }
390
388
  /**
391
389
  * Combine raw schema foreign key information with Directus relations meta rows to form final
392
390
  * Relation objects
@@ -435,12 +433,11 @@ export class RelationsService {
435
433
  async filterForbidden(relations) {
436
434
  if (this.accountability === null || this.accountability?.admin === true)
437
435
  return relations;
438
- const allowedCollections = this.accountability.permissions
439
- ?.filter((permission) => {
440
- return permission.action === 'read';
441
- })
442
- .map(({ collection }) => collection) ?? [];
443
- const allowedFields = this.permissionsService.getAllowedFields('read');
436
+ const allowedFields = await fetchAllowedFieldMap({
437
+ accountability: this.accountability,
438
+ action: 'read',
439
+ }, { schema: this.schema, knex: this.knex });
440
+ const allowedCollections = Object.keys(allowedFields);
444
441
  relations = toArray(relations);
445
442
  return relations.filter((relation) => {
446
443
  let collectionsAllowed = true;
@@ -1,18 +1,10 @@
1
- import type { Item, PrimaryKey, Query } from '@directus/types';
1
+ import type { Item, PrimaryKey } from '@directus/types';
2
2
  import type { AbstractServiceOptions, MutationOptions } from '../types/index.js';
3
3
  import { ItemsService } from './items.js';
4
4
  export declare class RolesService extends ItemsService {
5
5
  constructor(options: AbstractServiceOptions);
6
- private checkForOtherAdminRoles;
7
- private checkForOtherAdminUsers;
8
- private isIpAccessValid;
9
- private assertValidIpAccess;
10
- private getRoleAccessType;
11
- createOne(data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey>;
12
- createMany(data: Partial<Item>[], opts?: MutationOptions): Promise<PrimaryKey[]>;
13
- updateOne(key: PrimaryKey, data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey>;
14
- updateBatch(data: Partial<Item>[], opts?: MutationOptions): Promise<PrimaryKey[]>;
15
6
  updateMany(keys: PrimaryKey[], data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey[]>;
16
- updateByQuery(query: Query, data: Partial<Item>, opts?: MutationOptions | undefined): Promise<PrimaryKey[]>;
17
- deleteMany(keys: PrimaryKey[]): Promise<PrimaryKey[]>;
7
+ deleteMany(keys: PrimaryKey[], opts?: MutationOptions): Promise<PrimaryKey[]>;
8
+ private validateRoleNesting;
9
+ private clearCaches;
18
10
  }