@directus/api 20.0.0-rc.1 → 20.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 (294) hide show
  1. package/dist/app.js +9 -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 +4 -2
  6. package/dist/cache.js +0 -3
  7. package/dist/cli/commands/bootstrap/index.js +3 -8
  8. package/dist/cli/commands/init/index.js +10 -9
  9. package/dist/cli/utils/defaults.d.ts +11 -4
  10. package/dist/cli/utils/defaults.js +1 -7
  11. package/dist/constants.d.ts +9 -1
  12. package/dist/constants.js +10 -0
  13. package/dist/controllers/auth.js +16 -5
  14. package/dist/controllers/permissions.js +2 -14
  15. package/dist/controllers/roles.js +1 -22
  16. package/dist/controllers/{access.d.ts → tus.d.ts} +1 -0
  17. package/dist/controllers/tus.js +72 -0
  18. package/dist/controllers/users.js +55 -0
  19. package/dist/database/helpers/fn/types.d.ts +1 -2
  20. package/dist/database/helpers/fn/types.js +1 -1
  21. package/dist/database/helpers/geometry/dialects/mssql.d.ts +1 -1
  22. package/dist/database/helpers/geometry/dialects/mssql.js +2 -4
  23. package/dist/database/helpers/geometry/dialects/mysql.js +1 -1
  24. package/dist/database/helpers/geometry/dialects/oracle.d.ts +1 -1
  25. package/dist/database/helpers/geometry/dialects/oracle.js +3 -5
  26. package/dist/database/helpers/geometry/types.d.ts +1 -1
  27. package/dist/database/helpers/geometry/types.js +2 -4
  28. package/dist/database/index.js +1 -2
  29. package/dist/database/migrations/20240701A-add-tus-data.js +12 -0
  30. package/dist/database/{run-ast/types.d.ts → run-ast.d.ts} +9 -3
  31. package/dist/database/run-ast.js +458 -0
  32. package/dist/flows.js +4 -3
  33. package/dist/middleware/authenticate.js +7 -2
  34. package/dist/middleware/cache.js +1 -1
  35. package/dist/middleware/check-ip.d.ts +2 -0
  36. package/dist/middleware/check-ip.js +37 -0
  37. package/dist/middleware/get-permissions.d.ts +3 -0
  38. package/dist/middleware/get-permissions.js +10 -0
  39. package/dist/middleware/respond.js +1 -1
  40. package/dist/services/activity.js +10 -22
  41. package/dist/services/assets.d.ts +3 -2
  42. package/dist/services/assets.js +5 -10
  43. package/dist/services/authentication.js +26 -32
  44. package/dist/services/authorization.d.ts +17 -0
  45. package/dist/services/authorization.js +456 -0
  46. package/dist/services/collections.js +17 -18
  47. package/dist/services/fields.d.ts +1 -0
  48. package/dist/services/fields.js +24 -53
  49. package/dist/services/files/lib/extract-metadata.d.ts +3 -0
  50. package/dist/services/files/lib/extract-metadata.js +32 -0
  51. package/dist/services/files/utils/get-metadata.d.ts +5 -0
  52. package/dist/services/files/utils/get-metadata.js +107 -0
  53. package/dist/services/files.d.ts +4 -6
  54. package/dist/services/files.js +27 -140
  55. package/dist/services/graphql/index.d.ts +3 -3
  56. package/dist/services/graphql/index.js +22 -126
  57. package/dist/services/graphql/subscription.js +4 -2
  58. package/dist/services/import-export.js +4 -18
  59. package/dist/services/index.d.ts +2 -3
  60. package/dist/services/index.js +2 -3
  61. package/dist/services/items.d.ts +3 -3
  62. package/dist/services/items.js +44 -115
  63. package/dist/services/meta.js +23 -60
  64. package/dist/services/payload.d.ts +10 -9
  65. package/dist/services/payload.js +3 -18
  66. package/dist/services/{permissions.d.ts → permissions/index.d.ts} +7 -5
  67. package/dist/services/{permissions.js → permissions/index.js} +54 -30
  68. package/dist/{permissions → services/permissions}/lib/with-app-minimal-permissions.d.ts +1 -1
  69. package/dist/services/permissions/lib/with-app-minimal-permissions.js +13 -0
  70. package/dist/services/relations.d.ts +6 -0
  71. package/dist/services/relations.js +29 -26
  72. package/dist/services/roles.d.ts +12 -4
  73. package/dist/services/roles.js +424 -57
  74. package/dist/services/server.js +6 -0
  75. package/dist/services/shares.d.ts +2 -0
  76. package/dist/services/shares.js +8 -12
  77. package/dist/services/specifications.d.ts +2 -2
  78. package/dist/services/specifications.js +27 -39
  79. package/dist/services/tus/data-store.d.ts +36 -0
  80. package/dist/services/tus/data-store.js +216 -0
  81. package/dist/services/tus/index.d.ts +2 -0
  82. package/dist/services/tus/index.js +2 -0
  83. package/dist/services/tus/lockers.d.ts +36 -0
  84. package/dist/services/tus/lockers.js +83 -0
  85. package/dist/services/tus/server.d.ts +8 -0
  86. package/dist/services/tus/server.js +80 -0
  87. package/dist/services/tus/utils/wait-timeout.d.ts +1 -0
  88. package/dist/services/tus/utils/wait-timeout.js +13 -0
  89. package/dist/services/users.d.ts +5 -1
  90. package/dist/services/users.js +161 -78
  91. package/dist/services/utils.js +7 -11
  92. package/dist/services/versions.d.ts +2 -0
  93. package/dist/services/versions.js +10 -34
  94. package/dist/storage/register-locations.js +5 -1
  95. package/dist/telemetry/lib/get-report.js +2 -2
  96. package/dist/telemetry/utils/check-increased-user-limits.d.ts +7 -0
  97. package/dist/telemetry/utils/check-increased-user-limits.js +25 -0
  98. package/dist/telemetry/utils/get-role-counts-by-roles.d.ts +6 -0
  99. package/dist/telemetry/utils/get-role-counts-by-roles.js +27 -0
  100. package/dist/telemetry/utils/get-role-counts-by-users.d.ts +11 -0
  101. package/dist/telemetry/utils/get-role-counts-by-users.js +34 -0
  102. package/dist/telemetry/utils/get-user-count.d.ts +8 -0
  103. package/dist/telemetry/utils/get-user-count.js +33 -0
  104. package/dist/telemetry/utils/get-user-counts-by-roles.d.ts +7 -0
  105. package/dist/telemetry/utils/get-user-counts-by-roles.js +35 -0
  106. package/dist/types/ast.d.ts +1 -43
  107. package/dist/types/items.d.ts +0 -11
  108. package/dist/utils/apply-query.d.ts +3 -4
  109. package/dist/utils/apply-query.js +8 -37
  110. package/dist/utils/get-accountability-for-role.js +25 -16
  111. package/dist/utils/get-accountability-for-token.js +16 -17
  112. package/dist/utils/get-ast-from-query.d.ts +13 -0
  113. package/dist/utils/get-ast-from-query.js +297 -0
  114. package/dist/utils/get-cache-key.d.ts +1 -1
  115. package/dist/utils/get-cache-key.js +1 -12
  116. package/dist/utils/get-column.d.ts +1 -2
  117. package/dist/utils/get-column.js +0 -1
  118. package/dist/utils/get-permissions.d.ts +2 -0
  119. package/dist/utils/get-permissions.js +150 -0
  120. package/dist/utils/get-service.js +1 -5
  121. package/dist/utils/merge-permissions-for-share.d.ts +4 -0
  122. package/dist/utils/merge-permissions-for-share.js +109 -0
  123. package/dist/utils/merge-permissions.d.ts +3 -0
  124. package/dist/utils/merge-permissions.js +95 -0
  125. package/dist/utils/reduce-schema.d.ts +6 -4
  126. package/dist/utils/reduce-schema.js +34 -14
  127. package/dist/utils/verify-session-jwt.js +2 -1
  128. package/dist/websocket/authenticate.d.ts +2 -0
  129. package/dist/websocket/authenticate.js +12 -0
  130. package/dist/websocket/controllers/base.d.ts +1 -1
  131. package/dist/websocket/controllers/base.js +20 -16
  132. package/dist/websocket/controllers/graphql.js +4 -1
  133. package/dist/websocket/controllers/hooks.js +0 -4
  134. package/dist/websocket/controllers/rest.js +2 -0
  135. package/dist/websocket/handlers/subscribe.js +2 -0
  136. package/dist/websocket/utils/items.d.ts +1 -1
  137. package/package.json +39 -37
  138. package/dist/controllers/access.js +0 -148
  139. package/dist/controllers/policies.d.ts +0 -2
  140. package/dist/controllers/policies.js +0 -169
  141. package/dist/database/get-ast-from-query/get-ast-from-query.d.ts +0 -16
  142. package/dist/database/get-ast-from-query/get-ast-from-query.js +0 -82
  143. package/dist/database/get-ast-from-query/lib/convert-wildcards.d.ts +0 -13
  144. package/dist/database/get-ast-from-query/lib/convert-wildcards.js +0 -69
  145. package/dist/database/get-ast-from-query/lib/parse-fields.d.ts +0 -15
  146. package/dist/database/get-ast-from-query/lib/parse-fields.js +0 -190
  147. package/dist/database/get-ast-from-query/utils/get-deep-query.d.ts +0 -14
  148. package/dist/database/get-ast-from-query/utils/get-deep-query.js +0 -17
  149. package/dist/database/get-ast-from-query/utils/get-related-collection.d.ts +0 -2
  150. package/dist/database/get-ast-from-query/utils/get-related-collection.js +0 -13
  151. package/dist/database/get-ast-from-query/utils/get-relation.d.ts +0 -2
  152. package/dist/database/get-ast-from-query/utils/get-relation.js +0 -7
  153. package/dist/database/migrations/20240619A-permissions-policies.js +0 -164
  154. package/dist/database/run-ast/lib/get-db-query.d.ts +0 -4
  155. package/dist/database/run-ast/lib/get-db-query.js +0 -194
  156. package/dist/database/run-ast/lib/parse-current-level.d.ts +0 -7
  157. package/dist/database/run-ast/lib/parse-current-level.js +0 -41
  158. package/dist/database/run-ast/run-ast.d.ts +0 -7
  159. package/dist/database/run-ast/run-ast.js +0 -107
  160. package/dist/database/run-ast/types.js +0 -1
  161. package/dist/database/run-ast/utils/apply-case-when.d.ts +0 -16
  162. package/dist/database/run-ast/utils/apply-case-when.js +0 -26
  163. package/dist/database/run-ast/utils/apply-parent-filters.d.ts +0 -3
  164. package/dist/database/run-ast/utils/apply-parent-filters.js +0 -55
  165. package/dist/database/run-ast/utils/get-column-pre-processor.d.ts +0 -10
  166. package/dist/database/run-ast/utils/get-column-pre-processor.js +0 -57
  167. package/dist/database/run-ast/utils/get-field-alias.d.ts +0 -2
  168. package/dist/database/run-ast/utils/get-field-alias.js +0 -4
  169. package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.d.ts +0 -5
  170. package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.js +0 -23
  171. package/dist/database/run-ast/utils/merge-with-parent-items.d.ts +0 -3
  172. package/dist/database/run-ast/utils/merge-with-parent-items.js +0 -87
  173. package/dist/database/run-ast/utils/remove-temporary-fields.d.ts +0 -3
  174. package/dist/database/run-ast/utils/remove-temporary-fields.js +0 -73
  175. package/dist/permissions/cache.d.ts +0 -2
  176. package/dist/permissions/cache.js +0 -23
  177. package/dist/permissions/lib/fetch-permissions.d.ts +0 -10
  178. package/dist/permissions/lib/fetch-permissions.js +0 -55
  179. package/dist/permissions/lib/fetch-policies.d.ts +0 -7
  180. package/dist/permissions/lib/fetch-policies.js +0 -28
  181. package/dist/permissions/lib/fetch-roles-tree.d.ts +0 -3
  182. package/dist/permissions/lib/fetch-roles-tree.js +0 -28
  183. package/dist/permissions/lib/with-app-minimal-permissions.js +0 -10
  184. package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.d.ts +0 -7
  185. package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.js +0 -56
  186. package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.d.ts +0 -3
  187. package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.js +0 -16
  188. package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.d.ts +0 -8
  189. package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.js +0 -24
  190. package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.d.ts +0 -9
  191. package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js +0 -31
  192. package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.d.ts +0 -16
  193. package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.js +0 -27
  194. package/dist/permissions/modules/fetch-global-access/fetch-global-access.d.ts +0 -10
  195. package/dist/permissions/modules/fetch-global-access/fetch-global-access.js +0 -23
  196. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.d.ts +0 -5
  197. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.js +0 -7
  198. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.d.ts +0 -5
  199. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.js +0 -10
  200. package/dist/permissions/modules/fetch-global-access/types.d.ts +0 -4
  201. package/dist/permissions/modules/fetch-global-access/types.js +0 -1
  202. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.d.ts +0 -4
  203. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.js +0 -27
  204. package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.d.ts +0 -12
  205. package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.js +0 -32
  206. package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.d.ts +0 -4
  207. package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.js +0 -29
  208. package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.d.ts +0 -4
  209. package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.js +0 -49
  210. package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.d.ts +0 -3
  211. package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.js +0 -56
  212. package/dist/permissions/modules/process-ast/lib/field-map-from-ast.d.ts +0 -4
  213. package/dist/permissions/modules/process-ast/lib/field-map-from-ast.js +0 -8
  214. package/dist/permissions/modules/process-ast/lib/inject-cases.d.ts +0 -9
  215. package/dist/permissions/modules/process-ast/lib/inject-cases.js +0 -93
  216. package/dist/permissions/modules/process-ast/process-ast.d.ts +0 -9
  217. package/dist/permissions/modules/process-ast/process-ast.js +0 -39
  218. package/dist/permissions/modules/process-ast/types.d.ts +0 -24
  219. package/dist/permissions/modules/process-ast/types.js +0 -1
  220. package/dist/permissions/modules/process-ast/utils/collections-in-field-map.d.ts +0 -2
  221. package/dist/permissions/modules/process-ast/utils/collections-in-field-map.js +0 -7
  222. package/dist/permissions/modules/process-ast/utils/dedupe-access.d.ts +0 -12
  223. package/dist/permissions/modules/process-ast/utils/dedupe-access.js +0 -30
  224. package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.d.ts +0 -15
  225. package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.js +0 -50
  226. package/dist/permissions/modules/process-ast/utils/find-related-collection.d.ts +0 -3
  227. package/dist/permissions/modules/process-ast/utils/find-related-collection.js +0 -9
  228. package/dist/permissions/modules/process-ast/utils/flatten-filter.d.ts +0 -3
  229. package/dist/permissions/modules/process-ast/utils/flatten-filter.js +0 -24
  230. package/dist/permissions/modules/process-ast/utils/format-a2o-key.d.ts +0 -1
  231. package/dist/permissions/modules/process-ast/utils/format-a2o-key.js +0 -3
  232. package/dist/permissions/modules/process-ast/utils/get-info-for-path.d.ts +0 -5
  233. package/dist/permissions/modules/process-ast/utils/get-info-for-path.js +0 -7
  234. package/dist/permissions/modules/process-ast/utils/has-item-permissions.d.ts +0 -2
  235. package/dist/permissions/modules/process-ast/utils/has-item-permissions.js +0 -3
  236. package/dist/permissions/modules/process-ast/utils/stringify-query-path.d.ts +0 -2
  237. package/dist/permissions/modules/process-ast/utils/stringify-query-path.js +0 -3
  238. package/dist/permissions/modules/process-ast/utils/validate-path/create-error.d.ts +0 -3
  239. package/dist/permissions/modules/process-ast/utils/validate-path/create-error.js +0 -16
  240. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.d.ts +0 -2
  241. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.js +0 -12
  242. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.d.ts +0 -2
  243. package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.js +0 -28
  244. package/dist/permissions/modules/process-payload/lib/is-field-nullable.d.ts +0 -5
  245. package/dist/permissions/modules/process-payload/lib/is-field-nullable.js +0 -12
  246. package/dist/permissions/modules/process-payload/process-payload.d.ts +0 -13
  247. package/dist/permissions/modules/process-payload/process-payload.js +0 -77
  248. package/dist/permissions/modules/validate-access/lib/validate-collection-access.d.ts +0 -12
  249. package/dist/permissions/modules/validate-access/lib/validate-collection-access.js +0 -11
  250. package/dist/permissions/modules/validate-access/lib/validate-item-access.d.ts +0 -9
  251. package/dist/permissions/modules/validate-access/lib/validate-item-access.js +0 -33
  252. package/dist/permissions/modules/validate-access/validate-access.d.ts +0 -14
  253. package/dist/permissions/modules/validate-access/validate-access.js +0 -28
  254. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.d.ts +0 -1
  255. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.js +0 -8
  256. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.d.ts +0 -5
  257. package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.js +0 -10
  258. package/dist/permissions/types.d.ts +0 -6
  259. package/dist/permissions/types.js +0 -1
  260. package/dist/permissions/utils/create-default-accountability.d.ts +0 -2
  261. package/dist/permissions/utils/create-default-accountability.js +0 -11
  262. package/dist/permissions/utils/extract-required-dynamic-variable-context.d.ts +0 -8
  263. package/dist/permissions/utils/extract-required-dynamic-variable-context.js +0 -27
  264. package/dist/permissions/utils/fetch-dynamic-variable-context.d.ts +0 -9
  265. package/dist/permissions/utils/fetch-dynamic-variable-context.js +0 -43
  266. package/dist/permissions/utils/filter-policies-by-ip.d.ts +0 -2
  267. package/dist/permissions/utils/filter-policies-by-ip.js +0 -15
  268. package/dist/permissions/utils/get-unaliased-field-key.d.ts +0 -5
  269. package/dist/permissions/utils/get-unaliased-field-key.js +0 -17
  270. package/dist/permissions/utils/process-permissions.d.ts +0 -7
  271. package/dist/permissions/utils/process-permissions.js +0 -9
  272. package/dist/permissions/utils/with-cache.d.ts +0 -10
  273. package/dist/permissions/utils/with-cache.js +0 -25
  274. package/dist/services/access.d.ts +0 -10
  275. package/dist/services/access.js +0 -43
  276. package/dist/services/policies.d.ts +0 -12
  277. package/dist/services/policies.js +0 -87
  278. package/dist/telemetry/utils/check-user-limits.d.ts +0 -5
  279. package/dist/telemetry/utils/check-user-limits.js +0 -19
  280. package/dist/utils/fetch-user-count/fetch-access-lookup.d.ts +0 -17
  281. package/dist/utils/fetch-user-count/fetch-access-lookup.js +0 -22
  282. package/dist/utils/fetch-user-count/fetch-access-roles.d.ts +0 -16
  283. package/dist/utils/fetch-user-count/fetch-access-roles.js +0 -37
  284. package/dist/utils/fetch-user-count/fetch-active-users.d.ts +0 -6
  285. package/dist/utils/fetch-user-count/fetch-active-users.js +0 -3
  286. package/dist/utils/fetch-user-count/fetch-user-count.d.ts +0 -12
  287. package/dist/utils/fetch-user-count/fetch-user-count.js +0 -57
  288. package/dist/utils/fetch-user-count/get-user-count-query.d.ts +0 -20
  289. package/dist/utils/fetch-user-count/get-user-count-query.js +0 -17
  290. package/dist/utils/validate-user-count-integrity.d.ts +0 -13
  291. package/dist/utils/validate-user-count-integrity.js +0 -29
  292. /package/dist/database/migrations/{20240619A-permissions-policies.d.ts → 20240701A-add-tus-data.d.ts} +0 -0
  293. /package/dist/{utils → services/files/utils}/parse-image-metadata.d.ts +0 -0
  294. /package/dist/{utils → services/files/utils}/parse-image-metadata.js +0 -0
@@ -0,0 +1,95 @@
1
+ import { flatten, intersection, isEqual, merge, omit } from 'lodash-es';
2
+ export function mergePermissions(strategy, ...permissions) {
3
+ const allPermissions = flatten(permissions);
4
+ const mergedPermissions = allPermissions
5
+ .reduce((acc, val) => {
6
+ const key = `${val.collection}__${val.action}__${val.role || '$PUBLIC'}`;
7
+ const current = acc.get(key);
8
+ acc.set(key, current ? mergePermission(strategy, current, val) : val);
9
+ return acc;
10
+ }, new Map())
11
+ .values();
12
+ return Array.from(mergedPermissions);
13
+ }
14
+ export function mergePermission(strategy, currentPerm, newPerm) {
15
+ const logicalKey = `_${strategy}`;
16
+ let permissions = currentPerm.permissions;
17
+ let validation = currentPerm.validation;
18
+ let fields = currentPerm.fields;
19
+ let presets = currentPerm.presets;
20
+ if (newPerm.permissions) {
21
+ if (currentPerm.permissions && Object.keys(currentPerm.permissions)[0] === logicalKey) {
22
+ permissions = {
23
+ [logicalKey]: [
24
+ ...currentPerm.permissions[logicalKey],
25
+ newPerm.permissions,
26
+ ],
27
+ };
28
+ }
29
+ else if (currentPerm.permissions) {
30
+ // Empty {} supersedes other permissions in _OR merge
31
+ if (strategy === 'or' && (isEqual(currentPerm.permissions, {}) || isEqual(newPerm.permissions, {}))) {
32
+ permissions = {};
33
+ }
34
+ else {
35
+ permissions = {
36
+ [logicalKey]: [currentPerm.permissions, newPerm.permissions],
37
+ };
38
+ }
39
+ }
40
+ else {
41
+ permissions = {
42
+ [logicalKey]: [newPerm.permissions],
43
+ };
44
+ }
45
+ }
46
+ if (newPerm.validation) {
47
+ if (currentPerm.validation && Object.keys(currentPerm.validation)[0] === logicalKey) {
48
+ validation = {
49
+ [logicalKey]: [
50
+ ...currentPerm.validation[logicalKey],
51
+ newPerm.validation,
52
+ ],
53
+ };
54
+ }
55
+ else if (currentPerm.validation) {
56
+ // Empty {} supersedes other validations in _OR merge
57
+ if (strategy === 'or' && (isEqual(currentPerm.validation, {}) || isEqual(newPerm.validation, {}))) {
58
+ validation = {};
59
+ }
60
+ else {
61
+ validation = {
62
+ [logicalKey]: [currentPerm.validation, newPerm.validation],
63
+ };
64
+ }
65
+ }
66
+ else {
67
+ validation = {
68
+ [logicalKey]: [newPerm.validation],
69
+ };
70
+ }
71
+ }
72
+ if (newPerm.fields) {
73
+ if (Array.isArray(currentPerm.fields) && strategy === 'or') {
74
+ fields = [...new Set([...currentPerm.fields, ...newPerm.fields])];
75
+ }
76
+ else if (Array.isArray(currentPerm.fields) && strategy === 'and') {
77
+ fields = intersection(currentPerm.fields, newPerm.fields);
78
+ }
79
+ else {
80
+ fields = newPerm.fields;
81
+ }
82
+ if (fields.includes('*'))
83
+ fields = ['*'];
84
+ }
85
+ if (newPerm.presets) {
86
+ presets = merge({}, presets, newPerm.presets);
87
+ }
88
+ return omit({
89
+ ...currentPerm,
90
+ permissions,
91
+ validation,
92
+ fields,
93
+ presets,
94
+ }, ['id', 'system']);
95
+ }
@@ -1,7 +1,9 @@
1
- import type { SchemaOverview } from '@directus/types';
2
- import type { FieldMap } from '../permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js';
1
+ import type { Permission, PermissionsAction, SchemaOverview } from '@directus/types';
3
2
  /**
4
3
  * Reduces the schema based on the included permissions. The resulting object is the schema structure, but with only
5
- * the allowed collections/fields/relations included based on the passed field map.
4
+ * the allowed collections/fields/relations included based on the permissions.
5
+ * @param schema The full project schema
6
+ * @param actions Array of permissions actions (crud)
7
+ * @returns Reduced schema
6
8
  */
7
- export declare function reduceSchema(schema: SchemaOverview, fieldMap: FieldMap): SchemaOverview;
9
+ export declare function reduceSchema(schema: SchemaOverview, permissions: Permission[] | null, actions?: PermissionsAction[]): SchemaOverview;
@@ -1,20 +1,40 @@
1
+ import { uniq } from 'lodash-es';
1
2
  /**
2
3
  * Reduces the schema based on the included permissions. The resulting object is the schema structure, but with only
3
- * the allowed collections/fields/relations included based on the passed field map.
4
+ * the allowed collections/fields/relations included based on the permissions.
5
+ * @param schema The full project schema
6
+ * @param actions Array of permissions actions (crud)
7
+ * @returns Reduced schema
4
8
  */
5
- export function reduceSchema(schema, fieldMap) {
9
+ export function reduceSchema(schema, permissions, actions = ['create', 'read', 'update', 'delete']) {
6
10
  const reduced = {
7
11
  collections: {},
8
12
  relations: [],
9
13
  };
14
+ const allowedFieldsInCollection = permissions
15
+ ?.filter((permission) => actions.includes(permission.action))
16
+ .reduce((acc, permission) => {
17
+ if (!acc[permission.collection]) {
18
+ acc[permission.collection] = [];
19
+ }
20
+ if (permission.fields) {
21
+ acc[permission.collection] = uniq([...acc[permission.collection], ...permission.fields]);
22
+ }
23
+ return acc;
24
+ }, {}) ?? {};
10
25
  for (const [collectionName, collection] of Object.entries(schema.collections)) {
26
+ if (!permissions?.some((permission) => permission.collection === collectionName && actions.includes(permission.action))) {
27
+ continue;
28
+ }
11
29
  const fields = {};
12
30
  for (const [fieldName, field] of Object.entries(schema.collections[collectionName].fields)) {
13
- if (!fieldMap[collectionName]?.includes('*') && !fieldMap[collectionName]?.includes(fieldName)) {
31
+ if (!allowedFieldsInCollection[collectionName]?.includes('*') &&
32
+ !allowedFieldsInCollection[collectionName]?.includes(fieldName)) {
14
33
  continue;
15
34
  }
16
35
  const o2mRelation = schema.relations.find((relation) => relation.related_collection === collectionName && relation.meta?.one_field === fieldName);
17
- if (o2mRelation && !fieldMap[collectionName]) {
36
+ if (o2mRelation &&
37
+ !permissions?.some((permission) => permission.collection === o2mRelation.collection && actions.includes(permission.action))) {
18
38
  continue;
19
39
  }
20
40
  fields[fieldName] = field;
@@ -27,29 +47,29 @@ export function reduceSchema(schema, fieldMap) {
27
47
  reduced.relations = schema.relations.filter((relation) => {
28
48
  let collectionsAllowed = true;
29
49
  let fieldsAllowed = true;
30
- if (Object.keys(fieldMap).includes(relation.collection) === false) {
50
+ if (Object.keys(allowedFieldsInCollection).includes(relation.collection) === false) {
31
51
  collectionsAllowed = false;
32
52
  }
33
53
  if (relation.related_collection &&
34
- (Object.keys(fieldMap).includes(relation.related_collection) === false ||
54
+ (Object.keys(allowedFieldsInCollection).includes(relation.related_collection) === false ||
35
55
  // Ignore legacy permissions with an empty fields array
36
- fieldMap[relation.related_collection]?.length === 0)) {
56
+ allowedFieldsInCollection[relation.related_collection]?.length === 0)) {
37
57
  collectionsAllowed = false;
38
58
  }
39
59
  if (relation.meta?.one_allowed_collections &&
40
- relation.meta.one_allowed_collections.every((collection) => Object.keys(fieldMap).includes(collection)) === false) {
60
+ relation.meta.one_allowed_collections.every((collection) => Object.keys(allowedFieldsInCollection).includes(collection)) === false) {
41
61
  collectionsAllowed = false;
42
62
  }
43
- if (!fieldMap[relation.collection] ||
44
- (fieldMap[relation.collection]?.includes('*') === false &&
45
- fieldMap[relation.collection]?.includes(relation.field) === false)) {
63
+ if (!allowedFieldsInCollection[relation.collection] ||
64
+ (allowedFieldsInCollection[relation.collection]?.includes('*') === false &&
65
+ allowedFieldsInCollection[relation.collection]?.includes(relation.field) === false)) {
46
66
  fieldsAllowed = false;
47
67
  }
48
68
  if (relation.related_collection &&
49
69
  relation.meta?.one_field &&
50
- (!fieldMap[relation.related_collection] ||
51
- (fieldMap[relation.related_collection]?.includes('*') === false &&
52
- fieldMap[relation.related_collection]?.includes(relation.meta?.one_field) === false))) {
70
+ (!allowedFieldsInCollection[relation.related_collection] ||
71
+ (allowedFieldsInCollection[relation.related_collection]?.includes('*') === false &&
72
+ allowedFieldsInCollection[relation.related_collection]?.includes(relation.meta?.one_field) === false))) {
53
73
  fieldsAllowed = false;
54
74
  }
55
75
  return collectionsAllowed && fieldsAllowed;
@@ -12,7 +12,8 @@ export async function verifySessionJWT(payload) {
12
12
  .from('directus_sessions')
13
13
  .where({
14
14
  token: payload['session'],
15
- user: payload['id'],
15
+ user: payload['id'] || null,
16
+ share: payload['share'] || null,
16
17
  })
17
18
  .andWhere('expires', '>=', new Date())
18
19
  .first();
@@ -1,4 +1,6 @@
1
+ import type { Accountability } from '@directus/types';
1
2
  import type { BasicAuthMessage } from './messages.js';
2
3
  import type { AuthenticationState } from './types.js';
3
4
  export declare function authenticateConnection(message: BasicAuthMessage & Record<string, any>): Promise<AuthenticationState>;
5
+ export declare function refreshAccountability(accountability: Accountability | null | undefined): Promise<Accountability>;
4
6
  export declare function authenticationSuccess(uid?: string | number, refresh_token?: string): string;
@@ -1,6 +1,7 @@
1
1
  import { DEFAULT_AUTH_PROVIDER } from '../constants.js';
2
2
  import { AuthenticationService } from '../services/index.js';
3
3
  import { getAccountabilityForToken } from '../utils/get-accountability-for-token.js';
4
+ import { getPermissions } from '../utils/get-permissions.js';
4
5
  import { getSchema } from '../utils/get-schema.js';
5
6
  import { WebSocketError } from './errors.js';
6
7
  import { getExpiresAtForToken } from './utils/get-expires-at-for-token.js';
@@ -32,6 +33,17 @@ export async function authenticateConnection(message) {
32
33
  throw new WebSocketError('auth', 'AUTH_FAILED', 'Authentication failed.', message['uid']);
33
34
  }
34
35
  }
36
+ export async function refreshAccountability(accountability) {
37
+ accountability = accountability ?? {
38
+ role: null,
39
+ user: null,
40
+ admin: false,
41
+ app: false,
42
+ };
43
+ const schema = await getSchema();
44
+ const permissions = await getPermissions(accountability, schema);
45
+ return { ...accountability, permissions };
46
+ }
35
47
  export function authenticationSuccess(uid, refresh_token) {
36
48
  const message = {
37
49
  type: 'auth',
@@ -32,7 +32,7 @@ export default abstract class SocketController {
32
32
  protected getRateLimiter(): RateLimiterAbstract | null;
33
33
  private catchInvalidMessages;
34
34
  protected handleUpgrade(request: IncomingMessage, socket: internal.Duplex, head: Buffer): Promise<void>;
35
- protected handleTokenUpgrade({ request, socket, head }: UpgradeContext, token: string): Promise<void>;
35
+ protected handleTokenUpgrade({ request, socket, head }: UpgradeContext, token: string | null): Promise<void>;
36
36
  protected handleHandshakeUpgrade({ request, socket, head }: UpgradeContext): Promise<void>;
37
37
  createClient(ws: WebSocket, { accountability, expires_at }: AuthenticationState): WebSocketClient;
38
38
  protected parseMessage(data: string): WebSocketMessage;
@@ -101,13 +101,14 @@ export default class SocketController {
101
101
  const cookies = request.headers.cookie ? cookie.parse(request.headers.cookie) : {};
102
102
  const context = { request, socket, head };
103
103
  const sessionCookieName = env['SESSION_COOKIE_NAME'];
104
- if (cookies[sessionCookieName]) {
105
- const token = cookies[sessionCookieName];
106
- await this.handleTokenUpgrade(context, token);
107
- return;
108
- }
109
- if (this.authentication.mode === 'strict') {
110
- const token = query['access_token'];
104
+ if (this.authentication.mode === 'strict' || query['access_token'] || cookies[sessionCookieName]) {
105
+ let token = null;
106
+ if (typeof query['access_token'] === 'string') {
107
+ token = query['access_token'];
108
+ }
109
+ else if (typeof cookies[sessionCookieName] === 'string') {
110
+ token = cookies[sessionCookieName] ?? null;
111
+ }
111
112
  await this.handleTokenUpgrade(context, token);
112
113
  return;
113
114
  }
@@ -122,16 +123,19 @@ export default class SocketController {
122
123
  });
123
124
  }
124
125
  async handleTokenUpgrade({ request, socket, head }, token) {
125
- let accountability, expires_at;
126
- try {
127
- accountability = await getAccountabilityForToken(token);
128
- expires_at = getExpiresAtForToken(token);
129
- }
130
- catch {
131
- accountability = null;
132
- expires_at = null;
126
+ let accountability = null;
127
+ let expires_at = null;
128
+ if (token) {
129
+ try {
130
+ accountability = await getAccountabilityForToken(token);
131
+ expires_at = getExpiresAtForToken(token);
132
+ }
133
+ catch {
134
+ accountability = null;
135
+ expires_at = null;
136
+ }
133
137
  }
134
- if (!accountability || !accountability.user) {
138
+ if (!token || !accountability || !accountability.user) {
135
139
  logger.debug('WebSocket upgrade denied - ' + JSON.stringify(accountability || 'invalid'));
136
140
  socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
137
141
  socket.destroy();
@@ -4,7 +4,7 @@ import { useLogger } from '../../logger.js';
4
4
  import { bindPubSub } from '../../services/graphql/subscription.js';
5
5
  import { GraphQLService } from '../../services/index.js';
6
6
  import { getSchema } from '../../utils/get-schema.js';
7
- import { authenticateConnection } from '../authenticate.js';
7
+ import { authenticateConnection, refreshAccountability } from '../authenticate.js';
8
8
  import { handleWebSocketError } from '../errors.js';
9
9
  import { ConnectionParams, WebSocketMessage } from '../messages.js';
10
10
  import { getMessageType } from '../utils/message.js';
@@ -64,6 +64,9 @@ export class GraphQLSubscriptionController extends SocketController {
64
64
  client.close(CloseCode.Forbidden, 'Forbidden');
65
65
  return;
66
66
  }
67
+ else {
68
+ client.accountability = await refreshAccountability(client.accountability);
69
+ }
67
70
  await cb(JSON.stringify(message));
68
71
  }
69
72
  catch (error) {
@@ -7,23 +7,19 @@ export function registerWebSocketEvents() {
7
7
  actionsRegistered = true;
8
8
  registerActionHooks([
9
9
  'items',
10
- 'access',
11
10
  'activity',
12
11
  'collections',
13
12
  'dashboards',
14
- 'flows',
15
13
  'folders',
16
14
  'notifications',
17
15
  'operations',
18
16
  'panels',
19
17
  'permissions',
20
- 'policies',
21
18
  'presets',
22
19
  'revisions',
23
20
  'roles',
24
21
  'settings',
25
22
  'shares',
26
- 'translations',
27
23
  'users',
28
24
  'versions',
29
25
  'webhooks',
@@ -2,6 +2,7 @@ import { useEnv } from '@directus/env';
2
2
  import { parseJSON } from '@directus/utils';
3
3
  import emitter from '../../emitter.js';
4
4
  import { useLogger } from '../../logger.js';
5
+ import { refreshAccountability } from '../authenticate.js';
5
6
  import { WebSocketError, handleWebSocketError } from '../errors.js';
6
7
  import { WebSocketMessage } from '../messages.js';
7
8
  import SocketController from './base.js';
@@ -19,6 +20,7 @@ export class WebSocketController extends SocketController {
19
20
  client.on('parsed-message', async (message) => {
20
21
  try {
21
22
  message = WebSocketMessage.parse(await emitter.emitFilter('websocket.message', message, { client }));
23
+ client.accountability = await refreshAccountability(client.accountability);
22
24
  emitter.emitAction('websocket.message', { message, client });
23
25
  }
24
26
  catch (error) {
@@ -4,6 +4,7 @@ import { useBus } from '../../bus/index.js';
4
4
  import emitter from '../../emitter.js';
5
5
  import { getSchema } from '../../utils/get-schema.js';
6
6
  import { sanitizeQuery } from '../../utils/sanitize-query.js';
7
+ import { refreshAccountability } from '../authenticate.js';
7
8
  import { WebSocketError, handleWebSocketError } from '../errors.js';
8
9
  import { WebSocketSubscribeMessage } from '../messages.js';
9
10
  import { getPayload } from '../utils/items.js';
@@ -111,6 +112,7 @@ export class SubscribeHandler {
111
112
  continue;
112
113
  }
113
114
  try {
115
+ client.accountability = await refreshAccountability(client.accountability);
114
116
  const result = await getPayload(subscription, client.accountability, schema, event);
115
117
  if (Array.isArray(result?.['data']) && result?.['data']?.length === 0)
116
118
  continue;
@@ -39,5 +39,5 @@ export declare function getFieldsPayload(subscription: PSubscription, accountabi
39
39
  * @param event Event data
40
40
  * @returns the fetched data
41
41
  */
42
- export declare function getItemsPayload(subscription: PSubscription, accountability: Accountability | null, schema: SchemaOverview, event?: WebSocketEvent): Promise<string | number | (string | number)[] | import("@directus/types").Item | import("@directus/types").Item[]>;
42
+ export declare function getItemsPayload(subscription: PSubscription, accountability: Accountability | null, schema: SchemaOverview, event?: WebSocketEvent): Promise<string | number | import("@directus/types").Item | (string | number)[] | import("@directus/types").Item[]>;
43
43
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@directus/api",
3
- "version": "20.0.0-rc.1",
3
+ "version": "20.1.0",
4
4
  "description": "Directus is a real-time API and App dashboard for managing SQL database content",
5
5
  "keywords": [
6
6
  "directus",
@@ -59,11 +59,14 @@
59
59
  ],
60
60
  "dependencies": {
61
61
  "@authenio/samlify-node-xmllint": "2.0.0",
62
- "@aws-sdk/client-ses": "3.568.0",
62
+ "@aws-sdk/client-ses": "3.600.0",
63
63
  "@godaddy/terminus": "4.12.1",
64
64
  "@rollup/plugin-alias": "5.1.0",
65
65
  "@rollup/plugin-node-resolve": "15.2.3",
66
66
  "@rollup/plugin-virtual": "3.0.2",
67
+ "@tus/file-store": "1.3.3",
68
+ "@tus/server": "1.6.0",
69
+ "@tus/utils": "0.2.0",
67
70
  "@types/cookie": "0.6.0",
68
71
  "argon2": "0.40.3",
69
72
  "async": "3.2.5",
@@ -91,16 +94,16 @@
91
94
  "flat": "6.0.1",
92
95
  "fs-extra": "11.2.0",
93
96
  "glob-to-regexp": "0.4.1",
94
- "graphql": "16.8.2",
97
+ "graphql": "16.9.0",
95
98
  "graphql-compose": "9.0.11",
96
99
  "graphql-ws": "5.16.0",
97
100
  "helmet": "7.1.0",
98
101
  "icc": "3.0.0",
99
- "inquirer": "9.2.23",
102
+ "inquirer": "9.3.2",
100
103
  "ioredis": "5.4.1",
101
104
  "ip-matching": "2.1.2",
102
105
  "isolated-vm": "4.7.2",
103
- "joi": "17.13.1",
106
+ "joi": "17.13.3",
104
107
  "js-yaml": "4.1.0",
105
108
  "js2xmlparser": "5.0.0",
106
109
  "json2csv": "5.0.7",
@@ -108,7 +111,7 @@
108
111
  "keyv": "4.5.4",
109
112
  "knex": "3.1.0",
110
113
  "ldapjs": "2.3.3",
111
- "liquidjs": "10.13.1",
114
+ "liquidjs": "10.14.0",
112
115
  "lodash-es": "4.17.21",
113
116
  "marked": "12.0.2",
114
117
  "micromustache": "8.0.3",
@@ -132,7 +135,7 @@
132
135
  "pino-http": "9.0.0",
133
136
  "pino-http-print": "3.1.0",
134
137
  "pino-pretty": "11.2.1",
135
- "qs": "6.12.1",
138
+ "qs": "6.12.2",
136
139
  "rate-limiter-flexible": "5.0.3",
137
140
  "rollup": "4.17.2",
138
141
  "samlify": "2.8.10",
@@ -140,35 +143,35 @@
140
143
  "sharp": "0.33.4",
141
144
  "snappy": "7.2.2",
142
145
  "stream-json": "1.8.0",
143
- "tar": "7.2.0",
146
+ "tar": "7.4.0",
144
147
  "tsx": "4.12.0",
145
148
  "wellknown": "0.5.0",
146
- "ws": "8.17.0",
149
+ "ws": "8.18.0",
147
150
  "zod": "3.23.8",
148
151
  "zod-validation-error": "3.3.0",
149
- "@directus/app": "13.0.0-rc.1",
150
- "@directus/constants": "11.1.0-rc.0",
151
- "@directus/errors": "0.4.0-rc.0",
152
- "@directus/env": "1.1.7-rc.0",
153
- "@directus/extensions-sdk": "11.0.9-rc.0",
154
- "@directus/extensions-registry": "1.0.9-rc.0",
155
- "@directus/extensions": "2.0.0-rc.0",
152
+ "@directus/app": "12.2.1",
153
+ "@directus/constants": "11.0.4",
154
+ "@directus/env": "1.3.0",
155
+ "@directus/extensions": "1.0.9",
156
+ "@directus/extensions-registry": "1.0.9",
156
157
  "@directus/format-title": "10.1.2",
157
- "@directus/memory": "1.1.0-rc.0",
158
- "@directus/pressure": "1.0.21-rc.0",
158
+ "@directus/errors": "0.3.3",
159
+ "@directus/memory": "1.0.10",
160
+ "@directus/extensions-sdk": "11.0.9",
161
+ "@directus/pressure": "1.0.21",
159
162
  "@directus/schema": "11.0.3",
160
163
  "@directus/specs": "10.2.10",
161
- "@directus/storage-driver-azure": "10.0.23-rc.0",
162
- "@directus/storage": "10.0.13",
163
- "@directus/storage-driver-cloudinary": "10.0.23-rc.0",
164
- "@directus/storage-driver-gcs": "10.0.24-rc.0",
165
- "@directus/storage-driver-local": "10.0.20",
166
- "@directus/storage-driver-supabase": "1.0.15-rc.0",
167
- "@directus/system-data": "2.0.0-rc.0",
168
- "@directus/storage-driver-s3": "10.0.24-rc.0",
169
- "@directus/utils": "12.0.0-rc.0",
170
- "@directus/validation": "0.0.18-rc.0",
171
- "directus": "11.0.0-rc.2"
164
+ "@directus/storage-driver-azure": "10.0.23",
165
+ "@directus/storage": "10.1.0",
166
+ "@directus/storage-driver-cloudinary": "10.0.23",
167
+ "@directus/storage-driver-gcs": "10.0.24",
168
+ "@directus/storage-driver-local": "10.1.0",
169
+ "@directus/storage-driver-s3": "10.1.0",
170
+ "@directus/storage-driver-supabase": "1.0.15",
171
+ "@directus/system-data": "1.1.0",
172
+ "@directus/utils": "11.0.10",
173
+ "@directus/validation": "0.0.18",
174
+ "directus": "10.13.1"
172
175
  },
173
176
  "devDependencies": {
174
177
  "@ngneat/falso": "7.2.0",
@@ -182,7 +185,7 @@
182
185
  "@types/destroy": "1.0.3",
183
186
  "@types/encodeurl": "1.0.2",
184
187
  "@types/express": "4.17.21",
185
- "@types/express-serve-static-core": "4.19.3",
188
+ "@types/express-serve-static-core": "4.19.5",
186
189
  "@types/fs-extra": "11.0.4",
187
190
  "@types/glob-to-regexp": "0.4.4",
188
191
  "@types/inquirer": "9.0.7",
@@ -209,17 +212,17 @@
209
212
  "knex-mock-client": "2.0.1",
210
213
  "typescript": "5.4.5",
211
214
  "vitest": "1.5.3",
215
+ "@directus/tsconfig": "1.0.1",
212
216
  "@directus/random": "0.2.8",
213
- "@directus/types": "12.0.0-rc.0",
214
- "@directus/tsconfig": "1.0.1"
217
+ "@directus/types": "11.2.0"
215
218
  },
216
219
  "optionalDependencies": {
217
- "@keyv/redis": "2.8.4",
218
- "mysql2": "3.10.0",
220
+ "@keyv/redis": "2.8.5",
221
+ "mysql": "2.18.1",
219
222
  "nodemailer-mailgun-transport": "2.1.5",
220
223
  "nodemailer-sendgrid": "1.0.3",
221
224
  "oracledb": "6.5.1",
222
- "pg": "8.11.5",
225
+ "pg": "8.12.0",
223
226
  "sqlite3": "5.1.7",
224
227
  "tedious": "18.2.0"
225
228
  },
@@ -230,7 +233,6 @@
230
233
  "build": "tsc --project tsconfig.prod.json && copyfiles \"src/**/*.{yaml,liquid}\" -u 1 dist",
231
234
  "cli": "NODE_ENV=development SERVE_APP=false tsx src/cli/run.ts",
232
235
  "dev": "NODE_ENV=development SERVE_APP=true tsx watch --ignore extensions --clear-screen=false src/start.ts",
233
- "test": "vitest run",
234
- "test:watch": "vitest"
236
+ "test": "vitest --watch=false"
235
237
  }
236
238
  }