@directus/api 19.3.1 → 20.0.0-rc.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.
- package/dist/app.js +4 -4
- package/dist/auth/drivers/ldap.js +4 -4
- package/dist/auth/drivers/local.js +4 -4
- package/dist/auth/drivers/oauth2.js +4 -4
- package/dist/auth/drivers/openid.js +2 -4
- package/dist/cache.js +3 -0
- package/dist/cli/commands/bootstrap/index.js +8 -2
- package/dist/cli/commands/init/index.js +9 -10
- package/dist/cli/utils/defaults.d.ts +4 -11
- package/dist/cli/utils/defaults.js +7 -1
- package/dist/constants.d.ts +1 -1
- package/dist/controllers/access.d.ts +2 -0
- package/dist/controllers/access.js +148 -0
- package/dist/controllers/auth.js +5 -16
- package/dist/controllers/permissions.js +14 -2
- package/dist/controllers/policies.d.ts +2 -0
- package/dist/controllers/policies.js +169 -0
- package/dist/controllers/roles.js +22 -1
- package/dist/controllers/users.js +0 -55
- package/dist/database/errors/dialects/mysql.js +23 -23
- package/dist/database/get-ast-from-query/get-ast-from-query.d.ts +16 -0
- package/dist/database/get-ast-from-query/get-ast-from-query.js +82 -0
- package/dist/database/get-ast-from-query/lib/convert-wildcards.d.ts +13 -0
- package/dist/database/get-ast-from-query/lib/convert-wildcards.js +69 -0
- package/dist/database/get-ast-from-query/lib/parse-fields.d.ts +15 -0
- package/dist/database/get-ast-from-query/lib/parse-fields.js +190 -0
- package/dist/database/get-ast-from-query/utils/get-deep-query.d.ts +14 -0
- package/dist/database/get-ast-from-query/utils/get-deep-query.js +17 -0
- package/dist/database/get-ast-from-query/utils/get-related-collection.d.ts +2 -0
- package/dist/database/get-ast-from-query/utils/get-related-collection.js +13 -0
- package/dist/database/get-ast-from-query/utils/get-relation.d.ts +2 -0
- package/dist/database/get-ast-from-query/utils/get-relation.js +7 -0
- package/dist/database/helpers/fn/types.d.ts +2 -1
- package/dist/database/helpers/fn/types.js +1 -1
- package/dist/database/helpers/geometry/dialects/mssql.d.ts +1 -1
- package/dist/database/helpers/geometry/dialects/mssql.js +4 -2
- package/dist/database/helpers/geometry/dialects/mysql.js +1 -1
- package/dist/database/helpers/geometry/dialects/oracle.d.ts +1 -1
- package/dist/database/helpers/geometry/dialects/oracle.js +5 -3
- package/dist/database/helpers/geometry/types.d.ts +1 -1
- package/dist/database/helpers/geometry/types.js +4 -2
- package/dist/database/index.js +2 -1
- package/dist/database/migrations/20240619A-permissions-policies.d.ts +3 -0
- package/dist/database/migrations/20240619A-permissions-policies.js +163 -0
- package/dist/database/run-ast/lib/get-db-query.d.ts +4 -0
- package/dist/database/run-ast/lib/get-db-query.js +194 -0
- package/dist/database/run-ast/lib/parse-current-level.d.ts +7 -0
- package/dist/database/run-ast/lib/parse-current-level.js +41 -0
- package/dist/database/run-ast/run-ast.d.ts +7 -0
- package/dist/database/run-ast/run-ast.js +107 -0
- package/dist/database/{run-ast.d.ts → run-ast/types.d.ts} +3 -9
- package/dist/database/run-ast/types.js +1 -0
- package/dist/database/run-ast/utils/apply-case-when.d.ts +16 -0
- package/dist/database/run-ast/utils/apply-case-when.js +26 -0
- package/dist/database/run-ast/utils/apply-parent-filters.d.ts +3 -0
- package/dist/database/run-ast/utils/apply-parent-filters.js +55 -0
- package/dist/database/run-ast/utils/get-column-pre-processor.d.ts +10 -0
- package/dist/database/run-ast/utils/get-column-pre-processor.js +57 -0
- package/dist/database/run-ast/utils/get-field-alias.d.ts +2 -0
- package/dist/database/run-ast/utils/get-field-alias.js +4 -0
- package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.d.ts +5 -0
- package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.js +23 -0
- package/dist/database/run-ast/utils/merge-with-parent-items.d.ts +3 -0
- package/dist/database/run-ast/utils/merge-with-parent-items.js +87 -0
- package/dist/database/run-ast/utils/remove-temporary-fields.d.ts +3 -0
- package/dist/database/run-ast/utils/remove-temporary-fields.js +73 -0
- package/dist/extensions/lib/sandbox/generate-api-extensions-sandbox-entrypoint.d.ts +1 -1
- package/dist/flows.js +3 -4
- package/dist/middleware/authenticate.js +2 -7
- package/dist/middleware/cache.js +1 -1
- package/dist/middleware/cors.js +4 -4
- package/dist/middleware/respond.js +1 -1
- package/dist/permissions/cache.d.ts +2 -0
- package/dist/permissions/cache.js +23 -0
- package/dist/permissions/lib/fetch-permissions.d.ts +10 -0
- package/dist/permissions/lib/fetch-permissions.js +55 -0
- package/dist/permissions/lib/fetch-policies.d.ts +7 -0
- package/dist/permissions/lib/fetch-policies.js +28 -0
- package/dist/permissions/lib/fetch-roles-tree.d.ts +3 -0
- package/dist/permissions/lib/fetch-roles-tree.js +28 -0
- package/dist/{services/permissions → permissions}/lib/with-app-minimal-permissions.d.ts +1 -1
- package/dist/permissions/lib/with-app-minimal-permissions.js +10 -0
- package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.d.ts +7 -0
- package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.js +56 -0
- package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.d.ts +3 -0
- package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.js +16 -0
- package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.d.ts +8 -0
- package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.js +24 -0
- package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.d.ts +9 -0
- package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js +31 -0
- package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.d.ts +16 -0
- package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.js +27 -0
- package/dist/permissions/modules/fetch-global-access/fetch-global-access.d.ts +10 -0
- package/dist/permissions/modules/fetch-global-access/fetch-global-access.js +23 -0
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.d.ts +5 -0
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.js +7 -0
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.d.ts +5 -0
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.js +10 -0
- package/dist/permissions/modules/fetch-global-access/types.d.ts +4 -0
- package/dist/permissions/modules/fetch-global-access/types.js +1 -0
- package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.d.ts +4 -0
- package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.js +27 -0
- package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.d.ts +12 -0
- package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.js +32 -0
- package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.d.ts +4 -0
- package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.js +29 -0
- package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.d.ts +4 -0
- package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.js +49 -0
- package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.d.ts +3 -0
- package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.js +56 -0
- package/dist/permissions/modules/process-ast/lib/field-map-from-ast.d.ts +4 -0
- package/dist/permissions/modules/process-ast/lib/field-map-from-ast.js +8 -0
- package/dist/permissions/modules/process-ast/lib/inject-cases.d.ts +9 -0
- package/dist/permissions/modules/process-ast/lib/inject-cases.js +93 -0
- package/dist/permissions/modules/process-ast/process-ast.d.ts +9 -0
- package/dist/permissions/modules/process-ast/process-ast.js +39 -0
- package/dist/permissions/modules/process-ast/types.d.ts +24 -0
- package/dist/permissions/modules/process-ast/types.js +1 -0
- package/dist/permissions/modules/process-ast/utils/collections-in-field-map.d.ts +2 -0
- package/dist/permissions/modules/process-ast/utils/collections-in-field-map.js +7 -0
- package/dist/permissions/modules/process-ast/utils/dedupe-access.d.ts +12 -0
- package/dist/permissions/modules/process-ast/utils/dedupe-access.js +30 -0
- package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.d.ts +15 -0
- package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.js +50 -0
- package/dist/permissions/modules/process-ast/utils/find-related-collection.d.ts +3 -0
- package/dist/permissions/modules/process-ast/utils/find-related-collection.js +9 -0
- package/dist/permissions/modules/process-ast/utils/flatten-filter.d.ts +3 -0
- package/dist/permissions/modules/process-ast/utils/flatten-filter.js +24 -0
- package/dist/permissions/modules/process-ast/utils/format-a2o-key.d.ts +1 -0
- package/dist/permissions/modules/process-ast/utils/format-a2o-key.js +3 -0
- package/dist/permissions/modules/process-ast/utils/get-info-for-path.d.ts +5 -0
- package/dist/permissions/modules/process-ast/utils/get-info-for-path.js +7 -0
- package/dist/permissions/modules/process-ast/utils/has-item-permissions.d.ts +2 -0
- package/dist/permissions/modules/process-ast/utils/has-item-permissions.js +3 -0
- package/dist/permissions/modules/process-ast/utils/stringify-query-path.d.ts +2 -0
- package/dist/permissions/modules/process-ast/utils/stringify-query-path.js +3 -0
- package/dist/permissions/modules/process-ast/utils/validate-path/create-error.d.ts +3 -0
- package/dist/permissions/modules/process-ast/utils/validate-path/create-error.js +16 -0
- package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.d.ts +2 -0
- package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.js +12 -0
- package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.d.ts +2 -0
- package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.js +28 -0
- package/dist/permissions/modules/process-payload/lib/is-field-nullable.d.ts +5 -0
- package/dist/permissions/modules/process-payload/lib/is-field-nullable.js +12 -0
- package/dist/permissions/modules/process-payload/process-payload.d.ts +13 -0
- package/dist/permissions/modules/process-payload/process-payload.js +77 -0
- package/dist/permissions/modules/validate-access/lib/validate-collection-access.d.ts +12 -0
- package/dist/permissions/modules/validate-access/lib/validate-collection-access.js +11 -0
- package/dist/permissions/modules/validate-access/lib/validate-item-access.d.ts +9 -0
- package/dist/permissions/modules/validate-access/lib/validate-item-access.js +33 -0
- package/dist/permissions/modules/validate-access/validate-access.d.ts +14 -0
- package/dist/permissions/modules/validate-access/validate-access.js +28 -0
- package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.d.ts +1 -0
- package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.js +8 -0
- package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.d.ts +5 -0
- package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.js +10 -0
- package/dist/permissions/types.d.ts +6 -0
- package/dist/permissions/types.js +1 -0
- package/dist/permissions/utils/create-default-accountability.d.ts +2 -0
- package/dist/permissions/utils/create-default-accountability.js +11 -0
- package/dist/permissions/utils/extract-required-dynamic-variable-context.d.ts +8 -0
- package/dist/permissions/utils/extract-required-dynamic-variable-context.js +27 -0
- package/dist/permissions/utils/fetch-dynamic-variable-context.d.ts +9 -0
- package/dist/permissions/utils/fetch-dynamic-variable-context.js +43 -0
- package/dist/permissions/utils/filter-policies-by-ip.d.ts +2 -0
- package/dist/permissions/utils/filter-policies-by-ip.js +15 -0
- package/dist/permissions/utils/get-unaliased-field-key.d.ts +5 -0
- package/dist/permissions/utils/get-unaliased-field-key.js +17 -0
- package/dist/permissions/utils/process-permissions.d.ts +7 -0
- package/dist/permissions/utils/process-permissions.js +9 -0
- package/dist/permissions/utils/with-cache.d.ts +10 -0
- package/dist/permissions/utils/with-cache.js +25 -0
- package/dist/services/access.d.ts +10 -0
- package/dist/services/access.js +43 -0
- package/dist/services/activity.js +22 -10
- package/dist/services/assets.d.ts +2 -3
- package/dist/services/assets.js +10 -5
- package/dist/services/authentication.js +18 -18
- package/dist/services/collections.js +18 -17
- package/dist/services/fields.d.ts +0 -1
- package/dist/services/fields.js +53 -24
- package/dist/services/files.d.ts +0 -4
- package/dist/services/files.js +10 -10
- package/dist/services/flows.d.ts +0 -2
- package/dist/services/flows.js +2 -14
- package/dist/services/graphql/index.d.ts +3 -3
- package/dist/services/graphql/index.js +126 -22
- package/dist/services/graphql/subscription.js +2 -4
- package/dist/services/import-export.js +23 -9
- package/dist/services/index.d.ts +3 -2
- package/dist/services/index.js +3 -2
- package/dist/services/items.d.ts +40 -14
- package/dist/services/items.js +182 -79
- package/dist/services/meta.js +60 -23
- package/dist/services/notifications.d.ts +0 -1
- package/dist/services/notifications.js +0 -7
- package/dist/services/operations.d.ts +0 -2
- package/dist/services/operations.js +2 -14
- package/dist/services/payload.d.ts +9 -10
- package/dist/services/payload.js +35 -19
- package/dist/services/{permissions/index.d.ts → permissions.d.ts} +5 -7
- package/dist/services/{permissions/index.js → permissions.js} +30 -54
- package/dist/services/policies.d.ts +12 -0
- package/dist/services/policies.js +87 -0
- package/dist/services/relations.d.ts +0 -6
- package/dist/services/relations.js +26 -29
- package/dist/services/roles.d.ts +4 -14
- package/dist/services/roles.js +56 -430
- package/dist/services/shares.d.ts +0 -2
- package/dist/services/shares.js +12 -8
- package/dist/services/specifications.d.ts +2 -2
- package/dist/services/specifications.js +39 -27
- package/dist/services/users.d.ts +2 -20
- package/dist/services/users.js +87 -192
- package/dist/services/utils.js +11 -7
- package/dist/services/versions.d.ts +0 -2
- package/dist/services/versions.js +34 -10
- package/dist/telemetry/lib/get-report.js +6 -3
- package/dist/telemetry/types/report.d.ts +4 -0
- package/dist/telemetry/utils/check-user-limits.d.ts +5 -0
- package/dist/telemetry/utils/check-user-limits.js +19 -0
- package/dist/telemetry/utils/get-filesize-sum.d.ts +5 -0
- package/dist/telemetry/utils/get-filesize-sum.js +7 -0
- package/dist/types/ast.d.ts +43 -1
- package/dist/types/items.d.ts +11 -0
- package/dist/utils/apply-query.d.ts +4 -3
- package/dist/utils/apply-query.js +37 -8
- package/dist/utils/fetch-user-count/fetch-access-lookup.d.ts +17 -0
- package/dist/utils/fetch-user-count/fetch-access-lookup.js +22 -0
- package/dist/utils/fetch-user-count/fetch-access-roles.d.ts +16 -0
- package/dist/utils/fetch-user-count/fetch-access-roles.js +37 -0
- package/dist/utils/fetch-user-count/fetch-active-users.d.ts +6 -0
- package/dist/utils/fetch-user-count/fetch-active-users.js +3 -0
- package/dist/utils/fetch-user-count/fetch-user-count.d.ts +12 -0
- package/dist/utils/fetch-user-count/fetch-user-count.js +57 -0
- package/dist/utils/fetch-user-count/get-user-count-query.d.ts +20 -0
- package/dist/utils/fetch-user-count/get-user-count-query.js +17 -0
- package/dist/utils/get-accountability-for-role.js +16 -25
- package/dist/utils/get-accountability-for-token.js +17 -16
- package/dist/utils/get-cache-key.d.ts +1 -1
- package/dist/utils/get-cache-key.js +12 -1
- package/dist/utils/get-column.d.ts +2 -1
- package/dist/utils/get-column.js +1 -0
- package/dist/utils/get-graphql-type.js +1 -0
- package/dist/utils/get-service.d.ts +1 -1
- package/dist/utils/get-service.js +14 -10
- package/dist/utils/reduce-schema.d.ts +4 -6
- package/dist/utils/reduce-schema.js +14 -34
- package/dist/utils/validate-user-count-integrity.d.ts +13 -0
- package/dist/utils/validate-user-count-integrity.js +29 -0
- package/dist/websocket/authenticate.d.ts +0 -2
- package/dist/websocket/authenticate.js +0 -12
- package/dist/websocket/controllers/graphql.js +1 -4
- package/dist/websocket/controllers/hooks.js +4 -0
- package/dist/websocket/controllers/rest.js +0 -2
- package/dist/websocket/handlers/subscribe.js +0 -2
- package/dist/websocket/utils/items.d.ts +1 -1
- package/dist/websocket/utils/items.js +4 -1
- package/package.json +31 -30
- package/dist/database/run-ast.js +0 -450
- package/dist/middleware/check-ip.d.ts +0 -2
- package/dist/middleware/check-ip.js +0 -37
- package/dist/middleware/get-permissions.d.ts +0 -3
- package/dist/middleware/get-permissions.js +0 -10
- package/dist/services/authorization.d.ts +0 -17
- package/dist/services/authorization.js +0 -456
- package/dist/services/permissions/lib/with-app-minimal-permissions.js +0 -13
- package/dist/telemetry/utils/check-increased-user-limits.d.ts +0 -7
- package/dist/telemetry/utils/check-increased-user-limits.js +0 -22
- package/dist/telemetry/utils/get-role-counts-by-roles.d.ts +0 -6
- package/dist/telemetry/utils/get-role-counts-by-roles.js +0 -27
- package/dist/telemetry/utils/get-role-counts-by-users.d.ts +0 -11
- package/dist/telemetry/utils/get-role-counts-by-users.js +0 -34
- package/dist/telemetry/utils/get-user-count.d.ts +0 -8
- package/dist/telemetry/utils/get-user-count.js +0 -33
- package/dist/telemetry/utils/get-user-counts-by-roles.d.ts +0 -7
- package/dist/telemetry/utils/get-user-counts-by-roles.js +0 -35
- package/dist/utils/get-ast-from-query.d.ts +0 -13
- package/dist/utils/get-ast-from-query.js +0 -297
- package/dist/utils/get-permissions.d.ts +0 -2
- package/dist/utils/get-permissions.js +0 -150
- package/dist/utils/merge-permissions-for-share.d.ts +0 -4
- package/dist/utils/merge-permissions-for-share.js +0 -109
- package/dist/utils/merge-permissions.d.ts +0 -3
- package/dist/utils/merge-permissions.js +0 -95
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { parseFilterKey } from '../../utils/parse-filter-key.js';
|
|
2
|
+
/**
|
|
3
|
+
* Derive the unaliased field key from the given AST node.
|
|
4
|
+
*/
|
|
5
|
+
export function getUnaliasedFieldKey(node) {
|
|
6
|
+
switch (node.type) {
|
|
7
|
+
case 'o2m':
|
|
8
|
+
return node.relation.meta.one_field;
|
|
9
|
+
case 'a2o':
|
|
10
|
+
case 'm2o':
|
|
11
|
+
return node.relation.field;
|
|
12
|
+
case 'field':
|
|
13
|
+
case 'functionField':
|
|
14
|
+
// The field name might still include a function, so process that here as well
|
|
15
|
+
return parseFilterKey(node.name).fieldName;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Accountability, Permission } from '@directus/types';
|
|
2
|
+
export interface ProcessPermissionsOptions {
|
|
3
|
+
permissions: Permission[];
|
|
4
|
+
accountability: Pick<Accountability, 'user' | 'role' | 'roles'>;
|
|
5
|
+
permissionsContext: Record<string, any>;
|
|
6
|
+
}
|
|
7
|
+
export declare function processPermissions({ permissions, accountability, permissionsContext }: ProcessPermissionsOptions): Permission[];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { parseFilter, parsePreset } from '@directus/utils';
|
|
2
|
+
export function processPermissions({ permissions, accountability, permissionsContext }) {
|
|
3
|
+
return permissions.map((permission) => {
|
|
4
|
+
permission.permissions = parseFilter(permission.permissions, accountability, permissionsContext);
|
|
5
|
+
permission.validation = parseFilter(permission.validation, accountability, permissionsContext);
|
|
6
|
+
permission.presets = parsePreset(permission.presets, accountability, permissionsContext);
|
|
7
|
+
return permission;
|
|
8
|
+
});
|
|
9
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `pick` parameter can be used to stabilize cache keys, by only using a subset of the available parameters and
|
|
3
|
+
* ensuring key order.
|
|
4
|
+
*
|
|
5
|
+
* If the `pick` function is provided, we pass the picked result to the handler, in order for TypeScript to ensure that
|
|
6
|
+
* the function only relies on the parameters that are used for generating the cache key.
|
|
7
|
+
*
|
|
8
|
+
* @NOTE only uses the first parameter for memoization
|
|
9
|
+
*/
|
|
10
|
+
export declare function withCache<F extends (arg0: Arg0, ...args: any[]) => R, R, Arg0 = Parameters<F>[0]>(namespace: string, handler: F, prepareArg?: (arg0: Arg0) => Arg0): F;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { getSimpleHash } from '@directus/utils';
|
|
2
|
+
import { useCache } from '../cache.js';
|
|
3
|
+
/**
|
|
4
|
+
* The `pick` parameter can be used to stabilize cache keys, by only using a subset of the available parameters and
|
|
5
|
+
* ensuring key order.
|
|
6
|
+
*
|
|
7
|
+
* If the `pick` function is provided, we pass the picked result to the handler, in order for TypeScript to ensure that
|
|
8
|
+
* the function only relies on the parameters that are used for generating the cache key.
|
|
9
|
+
*
|
|
10
|
+
* @NOTE only uses the first parameter for memoization
|
|
11
|
+
*/
|
|
12
|
+
export function withCache(namespace, handler, prepareArg) {
|
|
13
|
+
const cache = useCache();
|
|
14
|
+
return (async (arg0, ...args) => {
|
|
15
|
+
arg0 = prepareArg ? prepareArg(arg0) : arg0;
|
|
16
|
+
const key = namespace + '-' + getSimpleHash(JSON.stringify(arg0));
|
|
17
|
+
const cached = await cache.get(key);
|
|
18
|
+
if (cached !== undefined) {
|
|
19
|
+
return cached;
|
|
20
|
+
}
|
|
21
|
+
const res = await handler(arg0, ...args);
|
|
22
|
+
cache.set(key, res);
|
|
23
|
+
return res;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Item, PrimaryKey } from '@directus/types';
|
|
2
|
+
import type { AbstractServiceOptions, MutationOptions } from '../types/index.js';
|
|
3
|
+
import { ItemsService } from './items.js';
|
|
4
|
+
export declare class AccessService extends ItemsService {
|
|
5
|
+
constructor(options: AbstractServiceOptions);
|
|
6
|
+
private clearCaches;
|
|
7
|
+
createOne(data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey>;
|
|
8
|
+
updateMany(keys: PrimaryKey[], data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
9
|
+
deleteMany(keys: PrimaryKey[], opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { clearSystemCache } from '../cache.js';
|
|
2
|
+
import { UserIntegrityCheckFlag } from '../utils/validate-user-count-integrity.js';
|
|
3
|
+
import { ItemsService } from './items.js';
|
|
4
|
+
export class AccessService extends ItemsService {
|
|
5
|
+
constructor(options) {
|
|
6
|
+
super('directus_access', options);
|
|
7
|
+
}
|
|
8
|
+
async clearCaches(opts) {
|
|
9
|
+
await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
|
|
10
|
+
if (this.cache && opts?.autoPurgeCache !== false) {
|
|
11
|
+
await this.cache.clear();
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
async createOne(data, opts = {}) {
|
|
15
|
+
// Creating a new policy attachments affects the number of admin/app/api users.
|
|
16
|
+
// But it can only add app or admin users, so no need to check the remaining admin users.
|
|
17
|
+
opts.userIntegrityCheckFlags =
|
|
18
|
+
(opts.userIntegrityCheckFlags ?? UserIntegrityCheckFlag.None) | UserIntegrityCheckFlag.UserLimits;
|
|
19
|
+
opts.onRequireUserIntegrityCheck?.(opts.userIntegrityCheckFlags);
|
|
20
|
+
const result = await super.createOne(data, opts);
|
|
21
|
+
// A new policy has been attached to a user or a role, clear the caches
|
|
22
|
+
await this.clearCaches();
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
async updateMany(keys, data, opts = {}) {
|
|
26
|
+
// Updating policy attachments might affect the number of admin/app/api users
|
|
27
|
+
opts.userIntegrityCheckFlags = UserIntegrityCheckFlag.All;
|
|
28
|
+
opts.onRequireUserIntegrityCheck?.(opts.userIntegrityCheckFlags);
|
|
29
|
+
const result = await super.updateMany(keys, data, { ...opts, userIntegrityCheckFlags: UserIntegrityCheckFlag.All });
|
|
30
|
+
// Some policy attachments have been updated, clear the caches
|
|
31
|
+
await this.clearCaches();
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
async deleteMany(keys, opts = {}) {
|
|
35
|
+
// Changes here can affect the number of admin/app/api users
|
|
36
|
+
opts.userIntegrityCheckFlags = UserIntegrityCheckFlag.All;
|
|
37
|
+
opts.onRequireUserIntegrityCheck?.(opts.userIntegrityCheckFlags);
|
|
38
|
+
const result = await super.deleteMany(keys, opts);
|
|
39
|
+
// Some policy attachments have been deleted, clear the caches
|
|
40
|
+
await this.clearCaches();
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -3,11 +3,13 @@ import { useEnv } from '@directus/env';
|
|
|
3
3
|
import { ErrorCode, isDirectusError } from '@directus/errors';
|
|
4
4
|
import { uniq } from 'lodash-es';
|
|
5
5
|
import { useLogger } from '../logger.js';
|
|
6
|
-
import {
|
|
6
|
+
import { fetchRolesTree } from '../permissions/lib/fetch-roles-tree.js';
|
|
7
|
+
import { fetchGlobalAccess } from '../permissions/modules/fetch-global-access/fetch-global-access.js';
|
|
8
|
+
import { validateAccess } from '../permissions/modules/validate-access/validate-access.js';
|
|
9
|
+
import { createDefaultAccountability } from '../permissions/utils/create-default-accountability.js';
|
|
7
10
|
import { isValidUuid } from '../utils/is-valid-uuid.js';
|
|
8
11
|
import { Url } from '../utils/url.js';
|
|
9
12
|
import { userName } from '../utils/user-name.js';
|
|
10
|
-
import { AuthorizationService } from './authorization.js';
|
|
11
13
|
import { ItemsService } from './items.js';
|
|
12
14
|
import { NotificationsService } from './notifications.js';
|
|
13
15
|
import { UsersService } from './users.js';
|
|
@@ -31,19 +33,29 @@ export class ActivityService extends ItemsService {
|
|
|
31
33
|
for (const mention of mentions) {
|
|
32
34
|
const userID = mention.substring(1);
|
|
33
35
|
const user = await this.usersService.readOne(userID, {
|
|
34
|
-
fields: ['id', 'first_name', 'last_name', 'email', 'role
|
|
36
|
+
fields: ['id', 'first_name', 'last_name', 'email', 'role'],
|
|
35
37
|
});
|
|
36
|
-
const
|
|
38
|
+
const roles = await fetchRolesTree(user['role'], this.knex);
|
|
39
|
+
const globalAccess = await fetchGlobalAccess({ user: user['id'], roles, ip: null }, this.knex);
|
|
40
|
+
const accountability = createDefaultAccountability({
|
|
37
41
|
user: userID,
|
|
38
42
|
role: user['role']?.id ?? null,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
};
|
|
42
|
-
accountability.permissions = await getPermissions(accountability, this.schema);
|
|
43
|
-
const authorizationService = new AuthorizationService({ schema: this.schema, accountability });
|
|
43
|
+
roles,
|
|
44
|
+
...globalAccess,
|
|
45
|
+
});
|
|
44
46
|
const usersService = new UsersService({ schema: this.schema, accountability });
|
|
45
47
|
try {
|
|
46
|
-
|
|
48
|
+
if (this.accountability) {
|
|
49
|
+
await validateAccess({
|
|
50
|
+
accountability: this.accountability,
|
|
51
|
+
action: 'read',
|
|
52
|
+
collection: data['collection'],
|
|
53
|
+
primaryKeys: [data['item']],
|
|
54
|
+
}, {
|
|
55
|
+
knex: this.knex,
|
|
56
|
+
schema: this.schema,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
47
59
|
const templateData = await usersService.readByQuery({
|
|
48
60
|
fields: ['id', 'first_name', 'last_name', 'email'],
|
|
49
61
|
filter: { id: { _in: mentions.map((mention) => mention.substring(1)) } },
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
/// <reference types="node" resolution-mode="require"/>
|
|
2
2
|
import type { Range, Stat } from '@directus/storage';
|
|
3
|
-
import type { Accountability } from '@directus/types';
|
|
3
|
+
import type { Accountability, SchemaOverview } from '@directus/types';
|
|
4
4
|
import type { Knex } from 'knex';
|
|
5
5
|
import type { Readable } from 'node:stream';
|
|
6
6
|
import type { AbstractServiceOptions, TransformationSet } from '../types/index.js';
|
|
7
|
-
import { AuthorizationService } from './authorization.js';
|
|
8
7
|
import { FilesService } from './files.js';
|
|
9
8
|
export declare class AssetsService {
|
|
10
9
|
knex: Knex;
|
|
11
10
|
accountability: Accountability | null;
|
|
12
|
-
|
|
11
|
+
schema: SchemaOverview;
|
|
13
12
|
filesService: FilesService;
|
|
14
13
|
constructor(options: AbstractServiceOptions);
|
|
15
14
|
getAsset(id: string, transformation?: TransformationSet, range?: Range): Promise<{
|
package/dist/services/assets.js
CHANGED
|
@@ -8,24 +8,24 @@ import sharp from 'sharp';
|
|
|
8
8
|
import { SUPPORTED_IMAGE_TRANSFORM_FORMATS } from '../constants.js';
|
|
9
9
|
import getDatabase from '../database/index.js';
|
|
10
10
|
import { useLogger } from '../logger.js';
|
|
11
|
+
import { validateAccess } from '../permissions/modules/validate-access/validate-access.js';
|
|
11
12
|
import { getStorage } from '../storage/index.js';
|
|
12
13
|
import { getMilliseconds } from '../utils/get-milliseconds.js';
|
|
13
14
|
import { isValidUuid } from '../utils/is-valid-uuid.js';
|
|
14
15
|
import * as TransformationUtils from '../utils/transformations.js';
|
|
15
|
-
import { AuthorizationService } from './authorization.js';
|
|
16
16
|
import { FilesService } from './files.js';
|
|
17
17
|
const env = useEnv();
|
|
18
18
|
const logger = useLogger();
|
|
19
19
|
export class AssetsService {
|
|
20
20
|
knex;
|
|
21
21
|
accountability;
|
|
22
|
-
|
|
22
|
+
schema;
|
|
23
23
|
filesService;
|
|
24
24
|
constructor(options) {
|
|
25
25
|
this.knex = options.knex || getDatabase();
|
|
26
26
|
this.accountability = options.accountability || null;
|
|
27
|
+
this.schema = options.schema;
|
|
27
28
|
this.filesService = new FilesService({ ...options, accountability: null });
|
|
28
|
-
this.authorizationService = new AuthorizationService(options);
|
|
29
29
|
}
|
|
30
30
|
async getAsset(id, transformation, range) {
|
|
31
31
|
const storage = await getStorage();
|
|
@@ -41,8 +41,13 @@ export class AssetsService {
|
|
|
41
41
|
*/
|
|
42
42
|
if (!isValidUuid(id))
|
|
43
43
|
throw new ForbiddenError();
|
|
44
|
-
if (systemPublicKeys.includes(id) === false && this.accountability
|
|
45
|
-
await
|
|
44
|
+
if (systemPublicKeys.includes(id) === false && this.accountability) {
|
|
45
|
+
await validateAccess({
|
|
46
|
+
accountability: this.accountability,
|
|
47
|
+
action: 'read',
|
|
48
|
+
collection: 'directus_files',
|
|
49
|
+
primaryKeys: [id],
|
|
50
|
+
}, { knex: this.knex, schema: this.schema });
|
|
46
51
|
}
|
|
47
52
|
const file = (await this.filesService.readOne(id, { limit: 1 }));
|
|
48
53
|
const exists = await storage.location(file.storage).exists(file.filename_disk);
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { fetchRolesTree } from '../permissions/lib/fetch-roles-tree.js';
|
|
2
|
+
import { fetchGlobalAccess } from '../permissions/modules/fetch-global-access/fetch-global-access.js';
|
|
1
3
|
import { Action } from '@directus/constants';
|
|
2
4
|
import { useEnv } from '@directus/env';
|
|
3
5
|
import { InvalidCredentialsError, InvalidOtpError, InvalidProviderError, ServiceUnavailableError, UserSuspendedError, } from '@directus/errors';
|
|
@@ -48,10 +50,9 @@ export class AuthenticationService {
|
|
|
48
50
|
throw err;
|
|
49
51
|
}
|
|
50
52
|
const user = await this.knex
|
|
51
|
-
.select('
|
|
52
|
-
.from('directus_users
|
|
53
|
-
.
|
|
54
|
-
.where('u.id', userId)
|
|
53
|
+
.select('id', 'first_name', 'last_name', 'email', 'password', 'status', 'role', 'tfa_secret', 'provider', 'external_identifier', 'auth_data')
|
|
54
|
+
.from('directus_users')
|
|
55
|
+
.where('id', userId)
|
|
55
56
|
.first();
|
|
56
57
|
const updatedPayload = await emitter.emitFilter('auth.login', payload, {
|
|
57
58
|
status: 'pending',
|
|
@@ -138,11 +139,13 @@ export class AuthenticationService {
|
|
|
138
139
|
throw new InvalidOtpError();
|
|
139
140
|
}
|
|
140
141
|
}
|
|
142
|
+
const roles = await fetchRolesTree(user.role, this.knex);
|
|
143
|
+
const globalAccess = await fetchGlobalAccess({ roles, user: user.id, ip: this.accountability?.ip ?? null }, this.knex);
|
|
141
144
|
const tokenPayload = {
|
|
142
145
|
id: user.id,
|
|
143
146
|
role: user.role,
|
|
144
|
-
app_access:
|
|
145
|
-
admin_access:
|
|
147
|
+
app_access: globalAccess.app,
|
|
148
|
+
admin_access: globalAccess.admin,
|
|
146
149
|
};
|
|
147
150
|
const refreshToken = nanoid(64);
|
|
148
151
|
const refreshTokenExpiration = new Date(Date.now() + getMilliseconds(env['REFRESH_TOKEN_TTL'], 0));
|
|
@@ -217,9 +220,7 @@ export class AuthenticationService {
|
|
|
217
220
|
user_provider: 'u.provider',
|
|
218
221
|
user_external_identifier: 'u.external_identifier',
|
|
219
222
|
user_auth_data: 'u.auth_data',
|
|
220
|
-
|
|
221
|
-
role_admin_access: 'r.admin_access',
|
|
222
|
-
role_app_access: 'r.app_access',
|
|
223
|
+
user_role: 'u.role',
|
|
223
224
|
share_id: 'd.id',
|
|
224
225
|
share_item: 'd.item',
|
|
225
226
|
share_role: 'd.role',
|
|
@@ -232,9 +233,6 @@ export class AuthenticationService {
|
|
|
232
233
|
.from('directus_sessions AS s')
|
|
233
234
|
.leftJoin('directus_users AS u', 's.user', 'u.id')
|
|
234
235
|
.leftJoin('directus_shares AS d', 's.share', 'd.id')
|
|
235
|
-
.leftJoin('directus_roles AS r', (join) => {
|
|
236
|
-
join.onIn('r.id', [this.knex.ref('u.role'), this.knex.ref('d.role')]);
|
|
237
|
-
})
|
|
238
236
|
.where('s.token', refreshToken)
|
|
239
237
|
.andWhere('s.expires', '>=', new Date())
|
|
240
238
|
.andWhere((subQuery) => {
|
|
@@ -258,6 +256,8 @@ export class AuthenticationService {
|
|
|
258
256
|
throw new InvalidCredentialsError();
|
|
259
257
|
}
|
|
260
258
|
}
|
|
259
|
+
const roles = await fetchRolesTree(record.user_role, this.knex);
|
|
260
|
+
const globalAccess = await fetchGlobalAccess({ user: record.user_id, roles, ip: this.accountability?.ip ?? null }, this.knex);
|
|
261
261
|
if (record.user_id) {
|
|
262
262
|
const provider = getAuthProvider(record.user_provider);
|
|
263
263
|
await provider.refresh({
|
|
@@ -270,9 +270,9 @@ export class AuthenticationService {
|
|
|
270
270
|
provider: record.user_provider,
|
|
271
271
|
external_identifier: record.user_external_identifier,
|
|
272
272
|
auth_data: record.user_auth_data,
|
|
273
|
-
role: record.
|
|
274
|
-
app_access:
|
|
275
|
-
admin_access:
|
|
273
|
+
role: record.user_role,
|
|
274
|
+
app_access: globalAccess.app,
|
|
275
|
+
admin_access: globalAccess.admin,
|
|
276
276
|
});
|
|
277
277
|
}
|
|
278
278
|
let newRefreshToken = record.session_next_token ?? nanoid(64);
|
|
@@ -280,9 +280,9 @@ export class AuthenticationService {
|
|
|
280
280
|
const refreshTokenExpiration = new Date(Date.now() + getMilliseconds(sessionDuration, 0));
|
|
281
281
|
const tokenPayload = {
|
|
282
282
|
id: record.user_id,
|
|
283
|
-
role: record.
|
|
284
|
-
app_access:
|
|
285
|
-
admin_access:
|
|
283
|
+
role: record.user_role,
|
|
284
|
+
app_access: globalAccess.app,
|
|
285
|
+
admin_access: globalAccess.admin,
|
|
286
286
|
};
|
|
287
287
|
if (options?.session) {
|
|
288
288
|
newRefreshToken = await this.updateStatefulSession(record, refreshToken, newRefreshToken, refreshTokenExpiration);
|
|
@@ -9,6 +9,8 @@ import { ALIAS_TYPES } from '../constants.js';
|
|
|
9
9
|
import { getHelpers } from '../database/helpers/index.js';
|
|
10
10
|
import getDatabase, { getSchemaInspector } from '../database/index.js';
|
|
11
11
|
import emitter from '../emitter.js';
|
|
12
|
+
import { fetchAllowedCollections } from '../permissions/modules/fetch-allowed-collections/fetch-allowed-collections.js';
|
|
13
|
+
import { validateAccess } from '../permissions/modules/validate-access/validate-access.js';
|
|
12
14
|
import { getSchema } from '../utils/get-schema.js';
|
|
13
15
|
import { shouldClearCache } from '../utils/should-clear-cache.js';
|
|
14
16
|
import { transaction } from '../utils/transaction.js';
|
|
@@ -223,11 +225,13 @@ export class CollectionsService {
|
|
|
223
225
|
...meta,
|
|
224
226
|
[item.collection]: item.group,
|
|
225
227
|
}), {});
|
|
226
|
-
let collectionsYouHavePermissionToRead =
|
|
227
|
-
.
|
|
228
|
-
|
|
229
|
-
}
|
|
230
|
-
.
|
|
228
|
+
let collectionsYouHavePermissionToRead = await fetchAllowedCollections({
|
|
229
|
+
accountability: this.accountability,
|
|
230
|
+
action: 'read',
|
|
231
|
+
}, {
|
|
232
|
+
knex: this.knex,
|
|
233
|
+
schema: this.schema,
|
|
234
|
+
});
|
|
231
235
|
for (const collection of collectionsYouHavePermissionToRead) {
|
|
232
236
|
const group = collectionsGroups[collection];
|
|
233
237
|
if (group)
|
|
@@ -279,18 +283,15 @@ export class CollectionsService {
|
|
|
279
283
|
* Read many collections by name
|
|
280
284
|
*/
|
|
281
285
|
async readMany(collectionKeys) {
|
|
282
|
-
if (this.accountability
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}
|
|
286
|
+
if (this.accountability) {
|
|
287
|
+
await Promise.all(collectionKeys.map((collection) => validateAccess({
|
|
288
|
+
accountability: this.accountability,
|
|
289
|
+
action: 'read',
|
|
290
|
+
collection,
|
|
291
|
+
}, {
|
|
292
|
+
schema: this.schema,
|
|
293
|
+
knex: this.knex,
|
|
294
|
+
})));
|
|
294
295
|
}
|
|
295
296
|
const collections = await this.readByQuery();
|
|
296
297
|
return collections.filter(({ collection }) => collectionKeys.includes(collection));
|
|
@@ -17,7 +17,6 @@ export declare class FieldsService {
|
|
|
17
17
|
cache: Keyv<any> | null;
|
|
18
18
|
systemCache: Keyv<any>;
|
|
19
19
|
constructor(options: AbstractServiceOptions);
|
|
20
|
-
private get hasReadAccess();
|
|
21
20
|
readAll(collection?: string): Promise<Field[]>;
|
|
22
21
|
readOne(collection: string, field: string): Promise<Record<string, any>>;
|
|
23
22
|
createField(collection: string, field: Partial<Field> & {
|
package/dist/services/fields.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DEFAULT_NUMERIC_PRECISION, DEFAULT_NUMERIC_SCALE, KNEX_TYPES, REGEX_BETWEEN_PARENS, } from '@directus/constants';
|
|
2
2
|
import { ForbiddenError, InvalidPayloadError } from '@directus/errors';
|
|
3
3
|
import { createInspector } from '@directus/schema';
|
|
4
4
|
import { addFieldFlag, toArray } from '@directus/utils';
|
|
@@ -9,6 +9,9 @@ import { translateDatabaseError } from '../database/errors/translate.js';
|
|
|
9
9
|
import { getHelpers } from '../database/helpers/index.js';
|
|
10
10
|
import getDatabase, { getSchemaInspector } from '../database/index.js';
|
|
11
11
|
import emitter from '../emitter.js';
|
|
12
|
+
import { fetchPermissions } from '../permissions/lib/fetch-permissions.js';
|
|
13
|
+
import { fetchPolicies } from '../permissions/lib/fetch-policies.js';
|
|
14
|
+
import { validateAccess } from '../permissions/modules/validate-access/validate-access.js';
|
|
12
15
|
import getDefaultValue from '../utils/get-default-value.js';
|
|
13
16
|
import { getSystemFieldRowsWithAuthProviders } from '../utils/get-field-system-rows.js';
|
|
14
17
|
import getLocalType from '../utils/get-local-type.js';
|
|
@@ -42,15 +45,17 @@ export class FieldsService {
|
|
|
42
45
|
this.cache = cache;
|
|
43
46
|
this.systemCache = systemCache;
|
|
44
47
|
}
|
|
45
|
-
get hasReadAccess() {
|
|
46
|
-
return !!this.accountability?.permissions?.find((permission) => {
|
|
47
|
-
return permission.collection === 'directus_fields' && permission.action === 'read';
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
48
|
async readAll(collection) {
|
|
51
49
|
let fields;
|
|
52
|
-
if (this.accountability
|
|
53
|
-
|
|
50
|
+
if (this.accountability) {
|
|
51
|
+
await validateAccess({
|
|
52
|
+
accountability: this.accountability,
|
|
53
|
+
action: 'read',
|
|
54
|
+
collection: 'directus_fields',
|
|
55
|
+
}, {
|
|
56
|
+
schema: this.schema,
|
|
57
|
+
knex: this.knex,
|
|
58
|
+
});
|
|
54
59
|
}
|
|
55
60
|
const nonAuthorizedItemsService = new ItemsService('directus_fields', {
|
|
56
61
|
knex: this.knex,
|
|
@@ -119,12 +124,27 @@ export class FieldsService {
|
|
|
119
124
|
const result = [...columnsWithSystem, ...aliasFieldsAsField].filter((field) => knownCollections.includes(field.collection));
|
|
120
125
|
// Filter the result so we only return the fields you have read access to
|
|
121
126
|
if (this.accountability && this.accountability.admin !== true) {
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
127
|
+
const policies = await fetchPolicies(this.accountability, { knex: this.knex, schema: this.schema });
|
|
128
|
+
const permissions = await fetchPermissions(collection
|
|
129
|
+
? {
|
|
130
|
+
action: 'read',
|
|
131
|
+
policies,
|
|
132
|
+
collections: [collection],
|
|
133
|
+
accountability: this.accountability,
|
|
134
|
+
}
|
|
135
|
+
: {
|
|
136
|
+
action: 'read',
|
|
137
|
+
policies,
|
|
138
|
+
accountability: this.accountability,
|
|
139
|
+
}, { knex: this.knex, schema: this.schema });
|
|
125
140
|
const allowedFieldsInCollection = {};
|
|
126
141
|
permissions.forEach((permission) => {
|
|
127
|
-
allowedFieldsInCollection[permission.collection]
|
|
142
|
+
if (!allowedFieldsInCollection[permission.collection]) {
|
|
143
|
+
allowedFieldsInCollection[permission.collection] = new Set();
|
|
144
|
+
}
|
|
145
|
+
for (const field of permission.fields ?? []) {
|
|
146
|
+
allowedFieldsInCollection[permission.collection].add(field);
|
|
147
|
+
}
|
|
128
148
|
});
|
|
129
149
|
if (collection && collection in allowedFieldsInCollection === false) {
|
|
130
150
|
throw new ForbiddenError();
|
|
@@ -133,9 +153,9 @@ export class FieldsService {
|
|
|
133
153
|
if (field.collection in allowedFieldsInCollection === false)
|
|
134
154
|
return false;
|
|
135
155
|
const allowedFields = allowedFieldsInCollection[field.collection];
|
|
136
|
-
if (allowedFields
|
|
156
|
+
if (allowedFields.has('*'))
|
|
137
157
|
return true;
|
|
138
|
-
return allowedFields.
|
|
158
|
+
return allowedFields.has(field.field);
|
|
139
159
|
});
|
|
140
160
|
}
|
|
141
161
|
// Update specific database type overrides
|
|
@@ -152,18 +172,27 @@ export class FieldsService {
|
|
|
152
172
|
}
|
|
153
173
|
async readOne(collection, field) {
|
|
154
174
|
if (this.accountability && this.accountability.admin !== true) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
175
|
+
await validateAccess({
|
|
176
|
+
accountability: this.accountability,
|
|
177
|
+
action: 'read',
|
|
178
|
+
collection,
|
|
179
|
+
}, {
|
|
180
|
+
schema: this.schema,
|
|
181
|
+
knex: this.knex,
|
|
160
182
|
});
|
|
161
|
-
|
|
183
|
+
const policies = await fetchPolicies(this.accountability, { knex: this.knex, schema: this.schema });
|
|
184
|
+
const permissions = await fetchPermissions({ action: 'read', policies, collections: [collection], accountability: this.accountability }, { knex: this.knex, schema: this.schema });
|
|
185
|
+
let hasAccess = false;
|
|
186
|
+
for (const permission of permissions) {
|
|
187
|
+
if (permission.fields) {
|
|
188
|
+
if (permission.fields.includes('*') || permission.fields.includes(field)) {
|
|
189
|
+
hasAccess = true;
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (!hasAccess) {
|
|
162
195
|
throw new ForbiddenError();
|
|
163
|
-
if (permissions.fields.includes('*') === false) {
|
|
164
|
-
const allowedFields = permissions.fields;
|
|
165
|
-
if (allowedFields.includes(field) === false)
|
|
166
|
-
throw new ForbiddenError();
|
|
167
196
|
}
|
|
168
197
|
}
|
|
169
198
|
let column = undefined;
|
package/dist/services/files.d.ts
CHANGED
|
@@ -25,10 +25,6 @@ export declare class FilesService extends ItemsService {
|
|
|
25
25
|
* Useful for associating metadata with existing file in storage
|
|
26
26
|
*/
|
|
27
27
|
createOne(data: Partial<File>, opts?: MutationOptions): Promise<PrimaryKey>;
|
|
28
|
-
/**
|
|
29
|
-
* Delete a file
|
|
30
|
-
*/
|
|
31
|
-
deleteOne(key: PrimaryKey): Promise<PrimaryKey>;
|
|
32
28
|
/**
|
|
33
29
|
* Delete multiple files
|
|
34
30
|
*/
|
package/dist/services/files.js
CHANGED
|
@@ -16,6 +16,7 @@ import url from 'url';
|
|
|
16
16
|
import { SUPPORTED_IMAGE_METADATA_FORMATS } from '../constants.js';
|
|
17
17
|
import emitter from '../emitter.js';
|
|
18
18
|
import { useLogger } from '../logger.js';
|
|
19
|
+
import { validateAccess } from '../permissions/modules/validate-access/validate-access.js';
|
|
19
20
|
import { getAxios } from '../request/index.js';
|
|
20
21
|
import { getStorage } from '../storage/index.js';
|
|
21
22
|
import { parseIptc, parseXmp } from '../utils/parse-image-metadata.js';
|
|
@@ -276,9 +277,15 @@ export class FilesService extends ItemsService {
|
|
|
276
277
|
* Import a single file from an external URL
|
|
277
278
|
*/
|
|
278
279
|
async importOne(importURL, body) {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
280
|
+
if (this.accountability) {
|
|
281
|
+
await validateAccess({
|
|
282
|
+
accountability: this.accountability,
|
|
283
|
+
action: 'create',
|
|
284
|
+
collection: 'directus_files',
|
|
285
|
+
}, {
|
|
286
|
+
knex: this.knex,
|
|
287
|
+
schema: this.schema,
|
|
288
|
+
});
|
|
282
289
|
}
|
|
283
290
|
let fileResponse;
|
|
284
291
|
try {
|
|
@@ -318,13 +325,6 @@ export class FilesService extends ItemsService {
|
|
|
318
325
|
const key = await super.createOne(data, opts);
|
|
319
326
|
return key;
|
|
320
327
|
}
|
|
321
|
-
/**
|
|
322
|
-
* Delete a file
|
|
323
|
-
*/
|
|
324
|
-
async deleteOne(key) {
|
|
325
|
-
await this.deleteMany([key]);
|
|
326
|
-
return key;
|
|
327
|
-
}
|
|
328
328
|
/**
|
|
329
329
|
* Delete multiple files
|
|
330
330
|
*/
|
package/dist/services/flows.d.ts
CHANGED
|
@@ -4,8 +4,6 @@ import { ItemsService } from './items.js';
|
|
|
4
4
|
export declare class FlowsService extends ItemsService<FlowRaw> {
|
|
5
5
|
constructor(options: AbstractServiceOptions);
|
|
6
6
|
createOne(data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey>;
|
|
7
|
-
createMany(data: Partial<Item>[], opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
8
|
-
updateBatch(data: Partial<Item>[], opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
9
7
|
updateMany(keys: PrimaryKey[], data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
10
8
|
deleteMany(keys: PrimaryKey[], opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
11
9
|
}
|
package/dist/services/flows.js
CHANGED
|
@@ -5,34 +5,22 @@ export class FlowsService extends ItemsService {
|
|
|
5
5
|
super('directus_flows', options);
|
|
6
6
|
}
|
|
7
7
|
async createOne(data, opts) {
|
|
8
|
-
const flowManager = getFlowManager();
|
|
9
8
|
const result = await super.createOne(data, opts);
|
|
10
|
-
await flowManager.reload();
|
|
11
|
-
return result;
|
|
12
|
-
}
|
|
13
|
-
async createMany(data, opts) {
|
|
14
|
-
const flowManager = getFlowManager();
|
|
15
|
-
const result = await super.createMany(data, opts);
|
|
16
|
-
await flowManager.reload();
|
|
17
|
-
return result;
|
|
18
|
-
}
|
|
19
|
-
async updateBatch(data, opts) {
|
|
20
9
|
const flowManager = getFlowManager();
|
|
21
|
-
const result = await super.updateBatch(data, opts);
|
|
22
10
|
await flowManager.reload();
|
|
23
11
|
return result;
|
|
24
12
|
}
|
|
25
13
|
async updateMany(keys, data, opts) {
|
|
26
|
-
const flowManager = getFlowManager();
|
|
27
14
|
const result = await super.updateMany(keys, data, opts);
|
|
15
|
+
const flowManager = getFlowManager();
|
|
28
16
|
await flowManager.reload();
|
|
29
17
|
return result;
|
|
30
18
|
}
|
|
31
19
|
async deleteMany(keys, opts) {
|
|
32
|
-
const flowManager = getFlowManager();
|
|
33
20
|
// this is to prevent foreign key constraint error on directus_operations resolve/reject during cascade deletion
|
|
34
21
|
await this.knex('directus_operations').update({ resolve: null, reject: null }).whereIn('flow', keys);
|
|
35
22
|
const result = await super.deleteMany(keys, opts);
|
|
23
|
+
const flowManager = getFlowManager();
|
|
36
24
|
await flowManager.reload();
|
|
37
25
|
return result;
|
|
38
26
|
}
|
|
@@ -20,9 +20,9 @@ export declare class GraphQLService {
|
|
|
20
20
|
/**
|
|
21
21
|
* Generate the GraphQL schema. Pulls from the schema information generated by the get-schema util.
|
|
22
22
|
*/
|
|
23
|
-
getSchema(): GraphQLSchema
|
|
24
|
-
getSchema(type: 'schema'): GraphQLSchema
|
|
25
|
-
getSchema(type: 'sdl'): GraphQLSchema | string
|
|
23
|
+
getSchema(): Promise<GraphQLSchema>;
|
|
24
|
+
getSchema(type: 'schema'): Promise<GraphQLSchema>;
|
|
25
|
+
getSchema(type: 'sdl'): Promise<GraphQLSchema | string>;
|
|
26
26
|
/**
|
|
27
27
|
* Generic resolver that's used for every "regular" items/system query. Converts the incoming GraphQL AST / fragments into
|
|
28
28
|
* Directus' query structure which is then executed by the services.
|