@directus/api 21.0.0-rc.0 → 21.0.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 +5 -5
- 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 +4 -2
- package/dist/cache.d.ts +0 -1
- package/dist/cache.js +7 -25
- package/dist/cli/commands/bootstrap/index.js +2 -8
- package/dist/cli/commands/init/index.js +10 -9
- package/dist/cli/utils/defaults.d.ts +11 -4
- package/dist/cli/utils/defaults.js +1 -7
- package/dist/constants.d.ts +1 -1
- package/dist/controllers/auth.js +16 -5
- package/dist/controllers/permissions.js +2 -14
- package/dist/controllers/roles.js +1 -22
- package/dist/controllers/tus.js +27 -13
- package/dist/controllers/users.js +55 -0
- package/dist/database/helpers/fn/types.d.ts +1 -2
- 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 +2 -4
- 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 +3 -5
- package/dist/database/helpers/geometry/types.d.ts +1 -1
- package/dist/database/helpers/geometry/types.js +2 -4
- package/dist/database/index.js +11 -8
- package/dist/database/migrations/20240305A-change-useragent-type.js +1 -1
- package/dist/database/migrations/20240716A-update-files-date-fields.js +33 -0
- package/dist/database/{run-ast/types.d.ts → run-ast.d.ts} +9 -3
- package/dist/database/run-ast.js +458 -0
- package/dist/flows.js +4 -3
- package/dist/logger/index.js +1 -1
- package/dist/middleware/authenticate.js +7 -2
- package/dist/middleware/cache.js +1 -1
- package/dist/middleware/check-ip.d.ts +2 -0
- package/dist/middleware/check-ip.js +37 -0
- package/dist/middleware/error-handler.d.ts +2 -2
- package/dist/middleware/error-handler.js +54 -51
- package/dist/middleware/get-permissions.d.ts +3 -0
- package/dist/middleware/get-permissions.js +10 -0
- package/dist/middleware/respond.js +1 -1
- package/dist/services/activity.js +10 -22
- package/dist/services/assets.d.ts +3 -2
- package/dist/services/assets.js +7 -15
- package/dist/services/authentication.js +18 -18
- package/dist/services/authorization.d.ts +17 -0
- package/dist/services/authorization.js +456 -0
- package/dist/services/collections.js +17 -18
- package/dist/services/fields.d.ts +4 -0
- package/dist/services/fields.js +53 -58
- package/dist/services/files/lib/get-sharp-instance.d.ts +2 -0
- package/dist/services/files/lib/get-sharp-instance.js +10 -0
- package/dist/services/files/utils/get-metadata.js +7 -6
- package/dist/services/files.js +8 -10
- package/dist/services/graphql/index.d.ts +3 -3
- package/dist/services/graphql/index.js +22 -126
- package/dist/services/graphql/subscription.js +4 -2
- package/dist/services/import-export.js +4 -18
- package/dist/services/index.d.ts +2 -3
- package/dist/services/index.js +2 -3
- package/dist/services/items.js +44 -115
- package/dist/services/mail/index.d.ts +1 -1
- package/dist/services/mail/index.js +9 -1
- package/dist/services/meta.js +23 -60
- package/dist/services/notifications.js +6 -14
- package/dist/services/payload.d.ts +10 -9
- package/dist/services/payload.js +3 -18
- package/dist/services/{permissions.d.ts → permissions/index.d.ts} +7 -5
- package/dist/services/{permissions.js → permissions/index.js} +54 -30
- package/dist/{permissions → services/permissions}/lib/with-app-minimal-permissions.d.ts +1 -1
- package/dist/services/permissions/lib/with-app-minimal-permissions.js +13 -0
- package/dist/services/relations.d.ts +9 -1
- package/dist/services/relations.js +56 -31
- package/dist/services/roles.d.ts +12 -4
- package/dist/services/roles.js +424 -57
- package/dist/services/shares.d.ts +2 -0
- package/dist/services/shares.js +8 -12
- package/dist/services/specifications.d.ts +2 -2
- package/dist/services/specifications.js +27 -39
- package/dist/services/tus/data-store.js +4 -5
- package/dist/services/tus/server.d.ts +1 -1
- package/dist/services/tus/server.js +9 -2
- package/dist/services/users.d.ts +5 -1
- package/dist/services/users.js +161 -78
- package/dist/services/utils.js +7 -11
- package/dist/services/versions.d.ts +2 -0
- package/dist/services/versions.js +10 -34
- package/dist/telemetry/lib/get-report.js +2 -2
- package/dist/telemetry/utils/check-increased-user-limits.d.ts +7 -0
- package/dist/telemetry/utils/check-increased-user-limits.js +25 -0
- package/dist/telemetry/utils/get-role-counts-by-roles.d.ts +6 -0
- package/dist/telemetry/utils/get-role-counts-by-roles.js +27 -0
- package/dist/telemetry/utils/get-role-counts-by-users.d.ts +11 -0
- package/dist/telemetry/utils/get-role-counts-by-users.js +34 -0
- package/dist/telemetry/utils/get-user-count.d.ts +8 -0
- package/dist/telemetry/utils/get-user-count.js +33 -0
- package/dist/telemetry/utils/get-user-counts-by-roles.d.ts +7 -0
- package/dist/telemetry/utils/get-user-counts-by-roles.js +35 -0
- package/dist/types/ast.d.ts +1 -43
- package/dist/types/items.d.ts +0 -11
- package/dist/utils/apply-query.d.ts +3 -4
- package/dist/utils/apply-query.js +16 -39
- package/dist/utils/get-accountability-for-role.js +25 -16
- package/dist/utils/get-accountability-for-token.js +16 -17
- package/dist/utils/get-ast-from-query.d.ts +13 -0
- package/dist/utils/get-ast-from-query.js +297 -0
- package/dist/utils/get-cache-key.d.ts +1 -1
- package/dist/utils/get-cache-key.js +1 -12
- package/dist/utils/get-column.d.ts +1 -2
- package/dist/utils/get-column.js +0 -1
- package/dist/utils/get-permissions.d.ts +2 -0
- package/dist/utils/get-permissions.js +150 -0
- package/dist/utils/get-schema.js +3 -3
- package/dist/utils/get-service.js +1 -5
- package/dist/utils/merge-permissions-for-share.d.ts +4 -0
- package/dist/utils/merge-permissions-for-share.js +109 -0
- package/dist/utils/merge-permissions.d.ts +3 -0
- package/dist/utils/merge-permissions.js +95 -0
- package/dist/utils/reduce-schema.d.ts +6 -4
- package/dist/utils/reduce-schema.js +32 -16
- package/dist/websocket/authenticate.d.ts +2 -0
- package/dist/websocket/authenticate.js +12 -0
- package/dist/websocket/controllers/graphql.js +4 -1
- package/dist/websocket/controllers/hooks.js +0 -4
- package/dist/websocket/controllers/rest.js +2 -0
- package/dist/websocket/handlers/subscribe.js +2 -0
- package/dist/websocket/utils/items.d.ts +1 -1
- package/package.json +36 -37
- package/dist/controllers/access.d.ts +0 -2
- package/dist/controllers/access.js +0 -148
- package/dist/controllers/policies.d.ts +0 -2
- package/dist/controllers/policies.js +0 -169
- package/dist/database/get-ast-from-query/get-ast-from-query.d.ts +0 -16
- package/dist/database/get-ast-from-query/get-ast-from-query.js +0 -82
- package/dist/database/get-ast-from-query/lib/convert-wildcards.d.ts +0 -13
- package/dist/database/get-ast-from-query/lib/convert-wildcards.js +0 -69
- package/dist/database/get-ast-from-query/lib/parse-fields.d.ts +0 -15
- package/dist/database/get-ast-from-query/lib/parse-fields.js +0 -190
- package/dist/database/get-ast-from-query/utils/get-deep-query.d.ts +0 -14
- package/dist/database/get-ast-from-query/utils/get-deep-query.js +0 -17
- package/dist/database/get-ast-from-query/utils/get-related-collection.d.ts +0 -2
- package/dist/database/get-ast-from-query/utils/get-related-collection.js +0 -13
- package/dist/database/get-ast-from-query/utils/get-relation.d.ts +0 -2
- package/dist/database/get-ast-from-query/utils/get-relation.js +0 -7
- package/dist/database/migrations/20240710A-permissions-policies.js +0 -169
- package/dist/database/run-ast/lib/get-db-query.d.ts +0 -4
- package/dist/database/run-ast/lib/get-db-query.js +0 -208
- package/dist/database/run-ast/lib/parse-current-level.d.ts +0 -7
- package/dist/database/run-ast/lib/parse-current-level.js +0 -41
- package/dist/database/run-ast/run-ast.d.ts +0 -7
- package/dist/database/run-ast/run-ast.js +0 -107
- package/dist/database/run-ast/types.js +0 -1
- package/dist/database/run-ast/utils/apply-case-when.d.ts +0 -16
- package/dist/database/run-ast/utils/apply-case-when.js +0 -26
- package/dist/database/run-ast/utils/apply-parent-filters.d.ts +0 -3
- package/dist/database/run-ast/utils/apply-parent-filters.js +0 -55
- package/dist/database/run-ast/utils/get-column-pre-processor.d.ts +0 -10
- package/dist/database/run-ast/utils/get-column-pre-processor.js +0 -57
- package/dist/database/run-ast/utils/get-field-alias.d.ts +0 -2
- package/dist/database/run-ast/utils/get-field-alias.js +0 -4
- package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.d.ts +0 -5
- package/dist/database/run-ast/utils/get-inner-query-column-pre-processor.js +0 -23
- package/dist/database/run-ast/utils/merge-with-parent-items.d.ts +0 -3
- package/dist/database/run-ast/utils/merge-with-parent-items.js +0 -87
- package/dist/database/run-ast/utils/remove-temporary-fields.d.ts +0 -3
- package/dist/database/run-ast/utils/remove-temporary-fields.js +0 -73
- package/dist/permissions/cache.d.ts +0 -2
- package/dist/permissions/cache.js +0 -23
- package/dist/permissions/lib/fetch-permissions.d.ts +0 -10
- package/dist/permissions/lib/fetch-permissions.js +0 -55
- package/dist/permissions/lib/fetch-policies.d.ts +0 -7
- package/dist/permissions/lib/fetch-policies.js +0 -28
- package/dist/permissions/lib/fetch-roles-tree.d.ts +0 -3
- package/dist/permissions/lib/fetch-roles-tree.js +0 -28
- package/dist/permissions/lib/with-app-minimal-permissions.js +0 -10
- package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.d.ts +0 -7
- package/dist/permissions/modules/fetch-accountability-collection-access/fetch-accountability-collection-access.js +0 -56
- package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.d.ts +0 -3
- package/dist/permissions/modules/fetch-accountability-policy-globals/fetch-accountability-policy-globals.js +0 -16
- package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.d.ts +0 -8
- package/dist/permissions/modules/fetch-allowed-collections/fetch-allowed-collections.js +0 -24
- package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.d.ts +0 -9
- package/dist/permissions/modules/fetch-allowed-field-map/fetch-allowed-field-map.js +0 -31
- package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.d.ts +0 -16
- package/dist/permissions/modules/fetch-allowed-fields/fetch-allowed-fields.js +0 -27
- package/dist/permissions/modules/fetch-global-access/fetch-global-access.d.ts +0 -10
- package/dist/permissions/modules/fetch-global-access/fetch-global-access.js +0 -23
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.d.ts +0 -5
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.js +0 -7
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.d.ts +0 -5
- package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.js +0 -10
- package/dist/permissions/modules/fetch-global-access/types.d.ts +0 -4
- package/dist/permissions/modules/fetch-global-access/types.js +0 -1
- package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.d.ts +0 -4
- package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.js +0 -27
- package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.d.ts +0 -12
- package/dist/permissions/modules/fetch-inconsistent-field-map/fetch-inconsistent-field-map.js +0 -32
- package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.d.ts +0 -4
- package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.js +0 -29
- package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.d.ts +0 -4
- package/dist/permissions/modules/process-ast/lib/extract-fields-from-children.js +0 -49
- package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.d.ts +0 -3
- package/dist/permissions/modules/process-ast/lib/extract-fields-from-query.js +0 -56
- package/dist/permissions/modules/process-ast/lib/field-map-from-ast.d.ts +0 -4
- package/dist/permissions/modules/process-ast/lib/field-map-from-ast.js +0 -8
- package/dist/permissions/modules/process-ast/lib/inject-cases.d.ts +0 -9
- package/dist/permissions/modules/process-ast/lib/inject-cases.js +0 -93
- package/dist/permissions/modules/process-ast/process-ast.d.ts +0 -9
- package/dist/permissions/modules/process-ast/process-ast.js +0 -39
- package/dist/permissions/modules/process-ast/types.d.ts +0 -24
- package/dist/permissions/modules/process-ast/types.js +0 -1
- package/dist/permissions/modules/process-ast/utils/collections-in-field-map.d.ts +0 -2
- package/dist/permissions/modules/process-ast/utils/collections-in-field-map.js +0 -7
- package/dist/permissions/modules/process-ast/utils/dedupe-access.d.ts +0 -12
- package/dist/permissions/modules/process-ast/utils/dedupe-access.js +0 -30
- package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.d.ts +0 -15
- package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.js +0 -50
- package/dist/permissions/modules/process-ast/utils/find-related-collection.d.ts +0 -3
- package/dist/permissions/modules/process-ast/utils/find-related-collection.js +0 -9
- package/dist/permissions/modules/process-ast/utils/flatten-filter.d.ts +0 -3
- package/dist/permissions/modules/process-ast/utils/flatten-filter.js +0 -34
- package/dist/permissions/modules/process-ast/utils/format-a2o-key.d.ts +0 -1
- package/dist/permissions/modules/process-ast/utils/format-a2o-key.js +0 -3
- package/dist/permissions/modules/process-ast/utils/get-info-for-path.d.ts +0 -5
- package/dist/permissions/modules/process-ast/utils/get-info-for-path.js +0 -7
- package/dist/permissions/modules/process-ast/utils/has-item-permissions.d.ts +0 -2
- package/dist/permissions/modules/process-ast/utils/has-item-permissions.js +0 -3
- package/dist/permissions/modules/process-ast/utils/stringify-query-path.d.ts +0 -2
- package/dist/permissions/modules/process-ast/utils/stringify-query-path.js +0 -3
- package/dist/permissions/modules/process-ast/utils/validate-path/create-error.d.ts +0 -3
- package/dist/permissions/modules/process-ast/utils/validate-path/create-error.js +0 -16
- package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.d.ts +0 -2
- package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-existence.js +0 -12
- package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.d.ts +0 -2
- package/dist/permissions/modules/process-ast/utils/validate-path/validate-path-permissions.js +0 -28
- package/dist/permissions/modules/process-payload/lib/is-field-nullable.d.ts +0 -5
- package/dist/permissions/modules/process-payload/lib/is-field-nullable.js +0 -12
- package/dist/permissions/modules/process-payload/process-payload.d.ts +0 -13
- package/dist/permissions/modules/process-payload/process-payload.js +0 -77
- package/dist/permissions/modules/validate-access/lib/validate-collection-access.d.ts +0 -12
- package/dist/permissions/modules/validate-access/lib/validate-collection-access.js +0 -11
- package/dist/permissions/modules/validate-access/lib/validate-item-access.d.ts +0 -9
- package/dist/permissions/modules/validate-access/lib/validate-item-access.js +0 -33
- package/dist/permissions/modules/validate-access/validate-access.d.ts +0 -14
- package/dist/permissions/modules/validate-access/validate-access.js +0 -28
- package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.d.ts +0 -1
- package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.js +0 -8
- package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.d.ts +0 -5
- package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.js +0 -10
- package/dist/permissions/types.d.ts +0 -6
- package/dist/permissions/types.js +0 -1
- package/dist/permissions/utils/create-default-accountability.d.ts +0 -2
- package/dist/permissions/utils/create-default-accountability.js +0 -11
- package/dist/permissions/utils/extract-required-dynamic-variable-context.d.ts +0 -8
- package/dist/permissions/utils/extract-required-dynamic-variable-context.js +0 -27
- package/dist/permissions/utils/fetch-dynamic-variable-context.d.ts +0 -9
- package/dist/permissions/utils/fetch-dynamic-variable-context.js +0 -43
- package/dist/permissions/utils/filter-policies-by-ip.d.ts +0 -2
- package/dist/permissions/utils/filter-policies-by-ip.js +0 -15
- package/dist/permissions/utils/get-unaliased-field-key.d.ts +0 -5
- package/dist/permissions/utils/get-unaliased-field-key.js +0 -17
- package/dist/permissions/utils/process-permissions.d.ts +0 -7
- package/dist/permissions/utils/process-permissions.js +0 -9
- package/dist/permissions/utils/with-cache.d.ts +0 -10
- package/dist/permissions/utils/with-cache.js +0 -25
- package/dist/services/access.d.ts +0 -10
- package/dist/services/access.js +0 -43
- package/dist/services/policies.d.ts +0 -12
- package/dist/services/policies.js +0 -87
- package/dist/telemetry/utils/check-user-limits.d.ts +0 -5
- package/dist/telemetry/utils/check-user-limits.js +0 -19
- package/dist/utils/fetch-user-count/fetch-access-lookup.d.ts +0 -17
- package/dist/utils/fetch-user-count/fetch-access-lookup.js +0 -22
- package/dist/utils/fetch-user-count/fetch-access-roles.d.ts +0 -16
- package/dist/utils/fetch-user-count/fetch-access-roles.js +0 -37
- package/dist/utils/fetch-user-count/fetch-active-users.d.ts +0 -6
- package/dist/utils/fetch-user-count/fetch-active-users.js +0 -3
- package/dist/utils/fetch-user-count/fetch-user-count.d.ts +0 -12
- package/dist/utils/fetch-user-count/fetch-user-count.js +0 -57
- package/dist/utils/fetch-user-count/get-user-count-query.d.ts +0 -20
- package/dist/utils/fetch-user-count/get-user-count-query.js +0 -17
- package/dist/utils/validate-user-count-integrity.d.ts +0 -13
- package/dist/utils/validate-user-count-integrity.js +0 -29
- /package/dist/database/migrations/{20240710A-permissions-policies.d.ts → 20240716A-update-files-date-fields.d.ts} +0 -0
|
@@ -1,40 +1,38 @@
|
|
|
1
|
-
import { ErrorCode,
|
|
2
|
-
import { isObject
|
|
1
|
+
import { ErrorCode, InternalServerError, isDirectusError } from '@directus/errors';
|
|
2
|
+
import { isObject } from '@directus/utils';
|
|
3
3
|
import { getNodeEnv } from '@directus/utils/node';
|
|
4
4
|
import getDatabase from '../database/index.js';
|
|
5
5
|
import emitter from '../emitter.js';
|
|
6
6
|
import { useLogger } from '../logger/index.js';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const errorHandler = (err, req, res, _next) => {
|
|
7
|
+
const FALLBACK_ERROR = new InternalServerError();
|
|
8
|
+
export const errorHandler = asyncErrorHandler(async (err, req, res) => {
|
|
10
9
|
const logger = useLogger();
|
|
11
|
-
let
|
|
12
|
-
errors: [],
|
|
13
|
-
};
|
|
14
|
-
const errors = toArray(err);
|
|
10
|
+
let errors = [];
|
|
15
11
|
let status = null;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
};
|
|
23
|
-
}
|
|
12
|
+
// It can be assumed that at least one error is given
|
|
13
|
+
const receivedErrors = Array.isArray(err) ? err : [err];
|
|
14
|
+
for (const error of receivedErrors) {
|
|
15
|
+
// In dev mode, if available, expose stack trace under error's extensions data
|
|
16
|
+
if (getNodeEnv() === 'development' && error instanceof Error && error.stack) {
|
|
17
|
+
(error.extensions ??= {})['stack'] = error.stack;
|
|
24
18
|
}
|
|
25
19
|
if (isDirectusError(error)) {
|
|
26
20
|
logger.debug(error);
|
|
27
|
-
if (
|
|
21
|
+
if (status === null) {
|
|
22
|
+
// Use current error status as response status
|
|
28
23
|
status = error.status;
|
|
29
24
|
}
|
|
30
25
|
else if (status !== error.status) {
|
|
31
|
-
status
|
|
26
|
+
// Fallback if status has already been set by a preceding error
|
|
27
|
+
// and doesn't match the current one
|
|
28
|
+
status = FALLBACK_ERROR.status;
|
|
32
29
|
}
|
|
33
|
-
|
|
30
|
+
errors.push({
|
|
34
31
|
message: error.message,
|
|
35
32
|
extensions: {
|
|
36
|
-
code: error.code,
|
|
37
33
|
...(error.extensions ?? {}),
|
|
34
|
+
// Expose error code under error's extensions data
|
|
35
|
+
code: error.code,
|
|
38
36
|
},
|
|
39
37
|
});
|
|
40
38
|
if (isDirectusError(error, ErrorCode.MethodNotAllowed)) {
|
|
@@ -43,45 +41,50 @@ const errorHandler = (err, req, res, _next) => {
|
|
|
43
41
|
}
|
|
44
42
|
else {
|
|
45
43
|
logger.error(error);
|
|
46
|
-
status =
|
|
44
|
+
status = FALLBACK_ERROR.status;
|
|
47
45
|
if (req.accountability?.admin === true) {
|
|
48
46
|
const localError = isObject(error) ? error : {};
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
},
|
|
47
|
+
// Use 'message' prop if available, otherwise if 'error' is a string use that
|
|
48
|
+
const message = (typeof localError['message'] === 'string' ? localError['message'] : null) ??
|
|
49
|
+
(typeof error === 'string' ? error : null);
|
|
50
|
+
errors = [
|
|
51
|
+
{
|
|
52
|
+
message: message || FALLBACK_ERROR.message,
|
|
53
|
+
extensions: {
|
|
54
|
+
code: FALLBACK_ERROR.code,
|
|
55
|
+
...(localError['extensions'] ?? {}),
|
|
58
56
|
},
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
},
|
|
58
|
+
];
|
|
61
59
|
}
|
|
62
60
|
else {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
{
|
|
66
|
-
message: 'An unexpected error occurred.',
|
|
67
|
-
extensions: {
|
|
68
|
-
code: 'INTERNAL_SERVER_ERROR',
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
],
|
|
72
|
-
};
|
|
61
|
+
// Don't expose unknown errors to non-admin users
|
|
62
|
+
errors = [{ message: FALLBACK_ERROR.message, extensions: { code: FALLBACK_ERROR.code } }];
|
|
73
63
|
}
|
|
74
64
|
}
|
|
75
65
|
}
|
|
76
|
-
res.status(status ??
|
|
77
|
-
emitter
|
|
78
|
-
.emitFilter('request.error', payload.errors, {}, {
|
|
66
|
+
res.status(status ?? FALLBACK_ERROR.status);
|
|
67
|
+
const updatedErrors = await emitter.emitFilter('request.error', errors, {}, {
|
|
79
68
|
database: getDatabase(),
|
|
80
69
|
schema: req.schema,
|
|
81
70
|
accountability: req.accountability ?? null,
|
|
82
|
-
})
|
|
83
|
-
.then((updatedErrors) => {
|
|
84
|
-
return res.json({ ...payload, errors: updatedErrors });
|
|
85
71
|
});
|
|
86
|
-
};
|
|
87
|
-
|
|
72
|
+
return res.json({ errors: updatedErrors });
|
|
73
|
+
});
|
|
74
|
+
function asyncErrorHandler(fn) {
|
|
75
|
+
return (err, req, res, next) => fn(err, req, res, next).catch((error) => {
|
|
76
|
+
// To be on the safe side and ensure this doesn't lead to an unhandled (potentially crashing) error
|
|
77
|
+
try {
|
|
78
|
+
const logger = useLogger();
|
|
79
|
+
logger.error(error, 'Unexpected error in error handler');
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// Ignore
|
|
83
|
+
}
|
|
84
|
+
// Delegate to default error handler to close the connection
|
|
85
|
+
if (res.headersSent)
|
|
86
|
+
return next(err);
|
|
87
|
+
res.status(FALLBACK_ERROR.status);
|
|
88
|
+
return res.json({ errors: [{ message: FALLBACK_ERROR.message, extensions: { code: FALLBACK_ERROR.code } }] });
|
|
89
|
+
});
|
|
90
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import asyncHandler from '../utils/async-handler.js';
|
|
2
|
+
import { getPermissions as getPermissionsUtil } from '../utils/get-permissions.js';
|
|
3
|
+
const getPermissions = asyncHandler(async (req, _res, next) => {
|
|
4
|
+
if (!req.accountability) {
|
|
5
|
+
throw new Error('getPermissions middleware needs to be called after authenticate');
|
|
6
|
+
}
|
|
7
|
+
req.accountability.permissions = await getPermissionsUtil(req.accountability, req.schema);
|
|
8
|
+
return next();
|
|
9
|
+
});
|
|
10
|
+
export default getPermissions;
|
|
@@ -25,7 +25,7 @@ export const respond = asyncHandler(async (req, res) => {
|
|
|
25
25
|
!req.sanitizedQuery.export &&
|
|
26
26
|
res.locals['cache'] !== false &&
|
|
27
27
|
exceedsMaxSize === false) {
|
|
28
|
-
const key =
|
|
28
|
+
const key = getCacheKey(req);
|
|
29
29
|
try {
|
|
30
30
|
await setCacheValue(cache, key, res.locals['payload'], getMilliseconds(env['CACHE_TTL']));
|
|
31
31
|
await setCacheValue(cache, `${key}__expires_at`, { exp: Date.now() + getMilliseconds(env['CACHE_TTL'], 0) });
|
|
@@ -3,13 +3,11 @@ 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/index.js';
|
|
6
|
-
import {
|
|
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';
|
|
6
|
+
import { getPermissions } from '../utils/get-permissions.js';
|
|
10
7
|
import { isValidUuid } from '../utils/is-valid-uuid.js';
|
|
11
8
|
import { Url } from '../utils/url.js';
|
|
12
9
|
import { userName } from '../utils/user-name.js';
|
|
10
|
+
import { AuthorizationService } from './authorization.js';
|
|
13
11
|
import { ItemsService } from './items.js';
|
|
14
12
|
import { NotificationsService } from './notifications.js';
|
|
15
13
|
import { UsersService } from './users.js';
|
|
@@ -33,29 +31,19 @@ export class ActivityService extends ItemsService {
|
|
|
33
31
|
for (const mention of mentions) {
|
|
34
32
|
const userID = mention.substring(1);
|
|
35
33
|
const user = await this.usersService.readOne(userID, {
|
|
36
|
-
fields: ['id', 'first_name', 'last_name', 'email', 'role'],
|
|
34
|
+
fields: ['id', 'first_name', 'last_name', 'email', 'role.id', 'role.admin_access', 'role.app_access'],
|
|
37
35
|
});
|
|
38
|
-
const
|
|
39
|
-
const globalAccess = await fetchGlobalAccess({ user: user['id'], roles, ip: null }, this.knex);
|
|
40
|
-
const accountability = createDefaultAccountability({
|
|
36
|
+
const accountability = {
|
|
41
37
|
user: userID,
|
|
42
38
|
role: user['role']?.id ?? null,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
39
|
+
admin: user['role']?.admin_access ?? null,
|
|
40
|
+
app: user['role']?.app_access ?? null,
|
|
41
|
+
};
|
|
42
|
+
accountability.permissions = await getPermissions(accountability, this.schema);
|
|
43
|
+
const authorizationService = new AuthorizationService({ schema: this.schema, accountability });
|
|
46
44
|
const usersService = new UsersService({ schema: this.schema, accountability });
|
|
47
45
|
try {
|
|
48
|
-
|
|
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
|
-
}
|
|
46
|
+
await authorizationService.checkAccess('read', data['collection'], data['item']);
|
|
59
47
|
const templateData = await usersService.readByQuery({
|
|
60
48
|
fields: ['id', 'first_name', 'last_name', 'email'],
|
|
61
49
|
filter: { id: { _in: mentions.map((mention) => mention.substring(1)) } },
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
/// <reference types="node" resolution-mode="require"/>
|
|
2
2
|
import type { Range, Stat } from '@directus/storage';
|
|
3
|
-
import type { Accountability
|
|
3
|
+
import type { Accountability } 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';
|
|
7
8
|
import { FilesService } from './files.js';
|
|
8
9
|
export declare class AssetsService {
|
|
9
10
|
knex: Knex;
|
|
10
11
|
accountability: Accountability | null;
|
|
11
|
-
|
|
12
|
+
authorizationService: AuthorizationService;
|
|
12
13
|
filesService: FilesService;
|
|
13
14
|
constructor(options: AbstractServiceOptions);
|
|
14
15
|
getAsset(id: string, transformation?: TransformationSet, range?: Range): Promise<{
|
package/dist/services/assets.js
CHANGED
|
@@ -8,24 +8,25 @@ 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/index.js';
|
|
11
|
-
import { validateAccess } from '../permissions/modules/validate-access/validate-access.js';
|
|
12
11
|
import { getStorage } from '../storage/index.js';
|
|
13
12
|
import { getMilliseconds } from '../utils/get-milliseconds.js';
|
|
14
13
|
import { isValidUuid } from '../utils/is-valid-uuid.js';
|
|
15
14
|
import * as TransformationUtils from '../utils/transformations.js';
|
|
15
|
+
import { AuthorizationService } from './authorization.js';
|
|
16
16
|
import { FilesService } from './files.js';
|
|
17
|
+
import { getSharpInstance } from './files/lib/get-sharp-instance.js';
|
|
17
18
|
const env = useEnv();
|
|
18
19
|
const logger = useLogger();
|
|
19
20
|
export class AssetsService {
|
|
20
21
|
knex;
|
|
21
22
|
accountability;
|
|
22
|
-
|
|
23
|
+
authorizationService;
|
|
23
24
|
filesService;
|
|
24
25
|
constructor(options) {
|
|
25
26
|
this.knex = options.knex || getDatabase();
|
|
26
27
|
this.accountability = options.accountability || null;
|
|
27
|
-
this.schema = options.schema;
|
|
28
28
|
this.filesService = new FilesService({ ...options, accountability: null });
|
|
29
|
+
this.authorizationService = new AuthorizationService(options);
|
|
29
30
|
}
|
|
30
31
|
async getAsset(id, transformation, range) {
|
|
31
32
|
const storage = await getStorage();
|
|
@@ -41,13 +42,8 @@ export class AssetsService {
|
|
|
41
42
|
*/
|
|
42
43
|
if (!isValidUuid(id))
|
|
43
44
|
throw new ForbiddenError();
|
|
44
|
-
if (systemPublicKeys.includes(id) === false && this.accountability) {
|
|
45
|
-
await
|
|
46
|
-
accountability: this.accountability,
|
|
47
|
-
action: 'read',
|
|
48
|
-
collection: 'directus_files',
|
|
49
|
-
primaryKeys: [id],
|
|
50
|
-
}, { knex: this.knex, schema: this.schema });
|
|
45
|
+
if (systemPublicKeys.includes(id) === false && this.accountability?.admin !== true) {
|
|
46
|
+
await this.authorizationService.checkAccess('read', 'directus_files', id);
|
|
51
47
|
}
|
|
52
48
|
const file = (await this.filesService.readOne(id, { limit: 1 }));
|
|
53
49
|
const exists = await storage.location(file.storage).exists(file.filename_disk);
|
|
@@ -121,11 +117,7 @@ export class AssetsService {
|
|
|
121
117
|
});
|
|
122
118
|
}
|
|
123
119
|
const readStream = await storage.location(file.storage).read(file.filename_disk, range);
|
|
124
|
-
const transformer =
|
|
125
|
-
limitInputPixels: Math.pow(env['ASSETS_TRANSFORM_IMAGE_MAX_DIMENSION'], 2),
|
|
126
|
-
sequentialRead: true,
|
|
127
|
-
failOn: env['ASSETS_INVALID_IMAGE_SENSITIVITY_LEVEL'],
|
|
128
|
-
});
|
|
120
|
+
const transformer = getSharpInstance();
|
|
129
121
|
transformer.timeout({
|
|
130
122
|
seconds: clamp(Math.round(getMilliseconds(env['ASSETS_TRANSFORM_TIMEOUT'], 0) / 1000), 1, 3600),
|
|
131
123
|
});
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { fetchRolesTree } from '../permissions/lib/fetch-roles-tree.js';
|
|
2
|
-
import { fetchGlobalAccess } from '../permissions/modules/fetch-global-access/fetch-global-access.js';
|
|
3
1
|
import { Action } from '@directus/constants';
|
|
4
2
|
import { useEnv } from '@directus/env';
|
|
5
3
|
import { InvalidCredentialsError, InvalidOtpError, ServiceUnavailableError, UserSuspendedError, } from '@directus/errors';
|
|
@@ -50,9 +48,10 @@ export class AuthenticationService {
|
|
|
50
48
|
throw err;
|
|
51
49
|
}
|
|
52
50
|
const user = await this.knex
|
|
53
|
-
.select('id', 'first_name', 'last_name', 'email', 'password', 'status', 'role', 'tfa_secret', 'provider', 'external_identifier', 'auth_data')
|
|
54
|
-
.from('directus_users')
|
|
55
|
-
.
|
|
51
|
+
.select('u.id', 'u.first_name', 'u.last_name', 'u.email', 'u.password', 'u.status', 'u.role', 'r.admin_access', 'r.app_access', 'u.tfa_secret', 'u.provider', 'u.external_identifier', 'u.auth_data')
|
|
52
|
+
.from('directus_users as u')
|
|
53
|
+
.leftJoin('directus_roles as r', 'u.role', 'r.id')
|
|
54
|
+
.where('u.id', userId)
|
|
56
55
|
.first();
|
|
57
56
|
const updatedPayload = await emitter.emitFilter('auth.login', payload, {
|
|
58
57
|
status: 'pending',
|
|
@@ -129,13 +128,11 @@ export class AuthenticationService {
|
|
|
129
128
|
throw new InvalidOtpError();
|
|
130
129
|
}
|
|
131
130
|
}
|
|
132
|
-
const roles = await fetchRolesTree(user.role, this.knex);
|
|
133
|
-
const globalAccess = await fetchGlobalAccess({ roles, user: user.id, ip: this.accountability?.ip ?? null }, this.knex);
|
|
134
131
|
const tokenPayload = {
|
|
135
132
|
id: user.id,
|
|
136
133
|
role: user.role,
|
|
137
|
-
app_access:
|
|
138
|
-
admin_access:
|
|
134
|
+
app_access: user.app_access,
|
|
135
|
+
admin_access: user.admin_access,
|
|
139
136
|
};
|
|
140
137
|
const refreshToken = nanoid(64);
|
|
141
138
|
const refreshTokenExpiration = new Date(Date.now() + getMilliseconds(env['REFRESH_TOKEN_TTL'], 0));
|
|
@@ -210,7 +207,9 @@ export class AuthenticationService {
|
|
|
210
207
|
user_provider: 'u.provider',
|
|
211
208
|
user_external_identifier: 'u.external_identifier',
|
|
212
209
|
user_auth_data: 'u.auth_data',
|
|
213
|
-
|
|
210
|
+
role_id: 'r.id',
|
|
211
|
+
role_admin_access: 'r.admin_access',
|
|
212
|
+
role_app_access: 'r.app_access',
|
|
214
213
|
share_id: 'd.id',
|
|
215
214
|
share_item: 'd.item',
|
|
216
215
|
share_role: 'd.role',
|
|
@@ -223,6 +222,9 @@ export class AuthenticationService {
|
|
|
223
222
|
.from('directus_sessions AS s')
|
|
224
223
|
.leftJoin('directus_users AS u', 's.user', 'u.id')
|
|
225
224
|
.leftJoin('directus_shares AS d', 's.share', 'd.id')
|
|
225
|
+
.leftJoin('directus_roles AS r', (join) => {
|
|
226
|
+
join.onIn('r.id', [this.knex.ref('u.role'), this.knex.ref('d.role')]);
|
|
227
|
+
})
|
|
226
228
|
.where('s.token', refreshToken)
|
|
227
229
|
.andWhere('s.expires', '>=', new Date())
|
|
228
230
|
.andWhere((subQuery) => {
|
|
@@ -246,8 +248,6 @@ export class AuthenticationService {
|
|
|
246
248
|
throw new InvalidCredentialsError();
|
|
247
249
|
}
|
|
248
250
|
}
|
|
249
|
-
const roles = await fetchRolesTree(record.user_role, this.knex);
|
|
250
|
-
const globalAccess = await fetchGlobalAccess({ user: record.user_id, roles, ip: this.accountability?.ip ?? null }, this.knex);
|
|
251
251
|
if (record.user_id) {
|
|
252
252
|
const provider = getAuthProvider(record.user_provider);
|
|
253
253
|
await provider.refresh({
|
|
@@ -260,9 +260,9 @@ export class AuthenticationService {
|
|
|
260
260
|
provider: record.user_provider,
|
|
261
261
|
external_identifier: record.user_external_identifier,
|
|
262
262
|
auth_data: record.user_auth_data,
|
|
263
|
-
role: record.
|
|
264
|
-
app_access:
|
|
265
|
-
admin_access:
|
|
263
|
+
role: record.role_id,
|
|
264
|
+
app_access: record.role_app_access,
|
|
265
|
+
admin_access: record.role_admin_access,
|
|
266
266
|
});
|
|
267
267
|
}
|
|
268
268
|
let newRefreshToken = record.session_next_token ?? nanoid(64);
|
|
@@ -270,9 +270,9 @@ export class AuthenticationService {
|
|
|
270
270
|
const refreshTokenExpiration = new Date(Date.now() + getMilliseconds(sessionDuration, 0));
|
|
271
271
|
const tokenPayload = {
|
|
272
272
|
id: record.user_id,
|
|
273
|
-
role: record.
|
|
274
|
-
app_access:
|
|
275
|
-
admin_access:
|
|
273
|
+
role: record.role_id,
|
|
274
|
+
app_access: record.role_app_access,
|
|
275
|
+
admin_access: record.role_admin_access,
|
|
276
276
|
};
|
|
277
277
|
if (options?.session) {
|
|
278
278
|
newRefreshToken = await this.updateStatefulSession(record, refreshToken, newRefreshToken, refreshTokenExpiration);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Accountability, Item, PermissionsAction, PrimaryKey, SchemaOverview } from '@directus/types';
|
|
2
|
+
import type { Knex } from 'knex';
|
|
3
|
+
import type { AST, AbstractServiceOptions } from '../types/index.js';
|
|
4
|
+
import { PayloadService } from './payload.js';
|
|
5
|
+
export declare class AuthorizationService {
|
|
6
|
+
knex: Knex;
|
|
7
|
+
accountability: Accountability | null;
|
|
8
|
+
payloadService: PayloadService;
|
|
9
|
+
schema: SchemaOverview;
|
|
10
|
+
constructor(options: AbstractServiceOptions);
|
|
11
|
+
processAST(ast: AST, action?: PermissionsAction): Promise<AST>;
|
|
12
|
+
/**
|
|
13
|
+
* Checks if the provided payload matches the configured permissions, and adds the presets to the payload.
|
|
14
|
+
*/
|
|
15
|
+
validatePayload(action: PermissionsAction, collection: string, data: Partial<Item>): Partial<Item>;
|
|
16
|
+
checkAccess(action: PermissionsAction, collection: string, pk?: PrimaryKey | PrimaryKey[]): Promise<void>;
|
|
17
|
+
}
|