@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,33 +0,0 @@
|
|
|
1
|
-
import { getAstFromQuery } from '../../../../database/get-ast-from-query/get-ast-from-query.js';
|
|
2
|
-
import { runAst } from '../../../../database/run-ast/run-ast.js';
|
|
3
|
-
import { processAst } from '../../process-ast/process-ast.js';
|
|
4
|
-
export async function validateItemAccess(options, context) {
|
|
5
|
-
const primaryKeyField = context.schema.collections[options.collection]?.primary;
|
|
6
|
-
if (!primaryKeyField) {
|
|
7
|
-
throw new Error(`Cannot find primary key for collection "${options.collection}"`);
|
|
8
|
-
}
|
|
9
|
-
// When we're looking up access to specific items, we have to read them from the database to
|
|
10
|
-
// make sure you are allowed to access them.
|
|
11
|
-
const query = {
|
|
12
|
-
// We don't actually need any of the field data, just want to know if we can read the item as
|
|
13
|
-
// whole or not
|
|
14
|
-
fields: [],
|
|
15
|
-
limit: options.primaryKeys.length,
|
|
16
|
-
filter: {
|
|
17
|
-
[primaryKeyField]: {
|
|
18
|
-
_in: options.primaryKeys,
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
const ast = await getAstFromQuery({
|
|
23
|
-
accountability: options.accountability,
|
|
24
|
-
query,
|
|
25
|
-
collection: options.collection,
|
|
26
|
-
}, context);
|
|
27
|
-
await processAst({ ast, ...options }, context);
|
|
28
|
-
const items = await runAst(ast, context.schema, { knex: context.knex });
|
|
29
|
-
if (items && items.length === options.primaryKeys.length) {
|
|
30
|
-
return true;
|
|
31
|
-
}
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { Accountability, PermissionsAction, PrimaryKey } from '@directus/types';
|
|
2
|
-
import type { Context } from '../../types.js';
|
|
3
|
-
export interface ValidateAccessOptions {
|
|
4
|
-
accountability: Accountability;
|
|
5
|
-
action: PermissionsAction;
|
|
6
|
-
collection: string;
|
|
7
|
-
primaryKeys?: PrimaryKey[];
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Validate if the current user has access to perform action against the given collection and
|
|
11
|
-
* optional primary keys. This is done by reading the item from the database using the access
|
|
12
|
-
* control rules and checking if we got the expected result back
|
|
13
|
-
*/
|
|
14
|
-
export declare function validateAccess(options: ValidateAccessOptions, context: Context): Promise<void>;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { ForbiddenError } from '@directus/errors';
|
|
2
|
-
import { validateCollectionAccess } from './lib/validate-collection-access.js';
|
|
3
|
-
import { validateItemAccess } from './lib/validate-item-access.js';
|
|
4
|
-
/**
|
|
5
|
-
* Validate if the current user has access to perform action against the given collection and
|
|
6
|
-
* optional primary keys. This is done by reading the item from the database using the access
|
|
7
|
-
* control rules and checking if we got the expected result back
|
|
8
|
-
*/
|
|
9
|
-
export async function validateAccess(options, context) {
|
|
10
|
-
if (options.accountability.admin === true) {
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
let access;
|
|
14
|
-
// If primary keys are passed, we have to confirm the access by actually trying to read the items
|
|
15
|
-
// from the database. If no keys are passed, we can simply check if the collection+action combo
|
|
16
|
-
// exists within permissions
|
|
17
|
-
if (options.primaryKeys) {
|
|
18
|
-
access = await validateItemAccess(options, context);
|
|
19
|
-
}
|
|
20
|
-
else {
|
|
21
|
-
access = await validateCollectionAccess(options, context);
|
|
22
|
-
}
|
|
23
|
-
if (!access) {
|
|
24
|
-
throw new ForbiddenError({
|
|
25
|
-
reason: `You don't have permission to "${options.action}" from collection "${options.collection}" or it does not exist.`,
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
}
|
package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-count.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function validateRemainingAdminCount(count: number): void;
|
package/dist/permissions/modules/validate-remaining-admin/validate-remaining-admin-users.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { type FetchUserCountOptions } from '../../../utils/fetch-user-count/fetch-user-count.js';
|
|
2
|
-
import type { Context } from '../../types.js';
|
|
3
|
-
export interface ValidateRemainingAdminUsersOptions extends Pick<FetchUserCountOptions, 'excludeAccessRows' | 'excludePolicies' | 'excludeUsers' | 'excludeRoles'> {
|
|
4
|
-
}
|
|
5
|
-
export declare function validateRemainingAdminUsers(options: ValidateRemainingAdminUsersOptions, context: Context): Promise<void>;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { fetchUserCount } from '../../../utils/fetch-user-count/fetch-user-count.js';
|
|
2
|
-
import { validateRemainingAdminCount } from './validate-remaining-admin-count.js';
|
|
3
|
-
export async function validateRemainingAdminUsers(options, context) {
|
|
4
|
-
const { admin } = await fetchUserCount({
|
|
5
|
-
...options,
|
|
6
|
-
adminOnly: true,
|
|
7
|
-
knex: context.knex,
|
|
8
|
-
});
|
|
9
|
-
validateRemainingAdminCount(admin);
|
|
10
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { Permission } from '@directus/types';
|
|
2
|
-
export interface RequiredPermissionContext {
|
|
3
|
-
$CURRENT_USER: Set<string>;
|
|
4
|
-
$CURRENT_ROLE: Set<string>;
|
|
5
|
-
$CURRENT_ROLES: Set<string>;
|
|
6
|
-
$CURRENT_POLICIES: Set<string>;
|
|
7
|
-
}
|
|
8
|
-
export declare function extractRequiredDynamicVariableContext(permissions: Permission[]): RequiredPermissionContext;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { deepMap } from '@directus/utils';
|
|
2
|
-
export function extractRequiredDynamicVariableContext(permissions) {
|
|
3
|
-
const permissionContext = {
|
|
4
|
-
$CURRENT_USER: new Set(),
|
|
5
|
-
$CURRENT_ROLE: new Set(),
|
|
6
|
-
$CURRENT_ROLES: new Set(),
|
|
7
|
-
$CURRENT_POLICIES: new Set(),
|
|
8
|
-
};
|
|
9
|
-
for (const permission of permissions) {
|
|
10
|
-
deepMap(permission.permissions, extractPermissionData);
|
|
11
|
-
deepMap(permission.validation, extractPermissionData);
|
|
12
|
-
deepMap(permission.presets, extractPermissionData);
|
|
13
|
-
}
|
|
14
|
-
return permissionContext;
|
|
15
|
-
function extractPermissionData(val) {
|
|
16
|
-
for (const placeholder of [
|
|
17
|
-
'$CURRENT_USER',
|
|
18
|
-
'$CURRENT_ROLE',
|
|
19
|
-
'$CURRENT_ROLES',
|
|
20
|
-
'$CURRENT_POLICIES',
|
|
21
|
-
]) {
|
|
22
|
-
if (typeof val === 'string' && val.startsWith(`${placeholder}.`)) {
|
|
23
|
-
permissionContext[placeholder].add(val.replace(`${placeholder}.`, ''));
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { Accountability, Permission } from '@directus/types';
|
|
2
|
-
import type { Context } from '../types.js';
|
|
3
|
-
export declare const fetchDynamicVariableContext: typeof _fetchDynamicVariableContext;
|
|
4
|
-
export interface FetchDynamicVariableContext {
|
|
5
|
-
accountability: Pick<Accountability, 'user' | 'role' | 'roles'>;
|
|
6
|
-
policies: string[];
|
|
7
|
-
permissions: Permission[];
|
|
8
|
-
}
|
|
9
|
-
export declare function _fetchDynamicVariableContext(options: FetchDynamicVariableContext, context: Context): Promise<Record<string, any>>;
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { extractRequiredDynamicVariableContext } from './extract-required-dynamic-variable-context.js';
|
|
2
|
-
import { withCache } from './with-cache.js';
|
|
3
|
-
export const fetchDynamicVariableContext = withCache('permission-dynamic-variables', _fetchDynamicVariableContext, ({ policies, permissions, accountability: { user, role, roles } }) => ({
|
|
4
|
-
policies,
|
|
5
|
-
permissions,
|
|
6
|
-
accountability: {
|
|
7
|
-
user,
|
|
8
|
-
role,
|
|
9
|
-
roles,
|
|
10
|
-
},
|
|
11
|
-
}));
|
|
12
|
-
export async function _fetchDynamicVariableContext(options, context) {
|
|
13
|
-
const { UsersService } = await import('../../services/users.js');
|
|
14
|
-
const { RolesService } = await import('../../services/roles.js');
|
|
15
|
-
const { PoliciesService } = await import('../../services/policies.js');
|
|
16
|
-
const contextData = {};
|
|
17
|
-
const permissionContext = extractRequiredDynamicVariableContext(options.permissions);
|
|
18
|
-
if (options.accountability.user && (permissionContext.$CURRENT_USER?.size ?? 0) > 0) {
|
|
19
|
-
const usersService = new UsersService(context);
|
|
20
|
-
contextData['$CURRENT_USER'] = await usersService.readOne(options.accountability.user, {
|
|
21
|
-
fields: Array.from(permissionContext.$CURRENT_USER),
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
if (options.accountability.role && (permissionContext.$CURRENT_ROLE?.size ?? 0) > 0) {
|
|
25
|
-
const rolesService = new RolesService(context);
|
|
26
|
-
contextData['$CURRENT_ROLE'] = await rolesService.readOne(options.accountability.role, {
|
|
27
|
-
fields: Array.from(permissionContext.$CURRENT_ROLE),
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
if (options.accountability.roles.length > 0 && (permissionContext.$CURRENT_ROLES?.size ?? 0) > 0) {
|
|
31
|
-
const rolesService = new RolesService(context);
|
|
32
|
-
contextData['$CURRENT_ROLES'] = await rolesService.readMany(options.accountability.roles, {
|
|
33
|
-
fields: Array.from(permissionContext.$CURRENT_ROLES),
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
if (options.policies.length > 0 && (permissionContext.$CURRENT_POLICIES?.size ?? 0) > 0) {
|
|
37
|
-
const policiesService = new PoliciesService(context);
|
|
38
|
-
contextData['$CURRENT_POLICIES'] = await policiesService.readMany(options.policies, {
|
|
39
|
-
fields: Array.from(permissionContext.$CURRENT_POLICIES),
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
return contextData;
|
|
43
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { ipInNetworks } from '../../utils/ip-in-networks.js';
|
|
2
|
-
export function filterPoliciesByIp(policies, ip) {
|
|
3
|
-
return policies.filter(({ policy }) => {
|
|
4
|
-
// Keep policies that don't have an ip address allow list configured
|
|
5
|
-
if (!policy.ip_access || policy.ip_access.length === 0) {
|
|
6
|
-
return true;
|
|
7
|
-
}
|
|
8
|
-
// If the client's IP address is unknown, we can't validate it against the allow list and will
|
|
9
|
-
// have to default to the more secure option of preventing access
|
|
10
|
-
if (!ip) {
|
|
11
|
-
return false;
|
|
12
|
-
}
|
|
13
|
-
return ipInNetworks(ip, policy.ip_access);
|
|
14
|
-
});
|
|
15
|
-
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { FieldNode, FunctionFieldNode, NestedCollectionNode } from '../../types/index.js';
|
|
2
|
-
/**
|
|
3
|
-
* Derive the unaliased field key from the given AST node.
|
|
4
|
-
*/
|
|
5
|
-
export declare function getUnaliasedFieldKey(node: NestedCollectionNode | FieldNode | FunctionFieldNode): string;
|
|
@@ -1,17 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
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[];
|
|
@@ -1,9 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
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;
|
|
@@ -1,25 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
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
|
-
}
|
package/dist/services/access.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { Policy, PrimaryKey } from '@directus/types';
|
|
2
|
-
import type { AbstractServiceOptions, MutationOptions } from '../types/index.js';
|
|
3
|
-
import { ItemsService } from './items.js';
|
|
4
|
-
export declare class PoliciesService extends ItemsService<Policy> {
|
|
5
|
-
constructor(options: AbstractServiceOptions);
|
|
6
|
-
private clearCaches;
|
|
7
|
-
private isIpAccessValid;
|
|
8
|
-
private assertValidIpAccess;
|
|
9
|
-
createOne(data: Partial<Policy>, opts?: MutationOptions): Promise<PrimaryKey>;
|
|
10
|
-
updateMany(keys: PrimaryKey[], data: Partial<Policy>, opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
11
|
-
deleteMany(keys: PrimaryKey[], opts?: MutationOptions): Promise<PrimaryKey[]>;
|
|
12
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { InvalidPayloadError } from '@directus/errors';
|
|
2
|
-
import { getMatch } from 'ip-matching';
|
|
3
|
-
import { clearSystemCache } from '../cache.js';
|
|
4
|
-
import { clearCache as clearPermissionsCache } from '../permissions/cache.js';
|
|
5
|
-
import { UserIntegrityCheckFlag } from '../utils/validate-user-count-integrity.js';
|
|
6
|
-
import { ItemsService } from './items.js';
|
|
7
|
-
export class PoliciesService extends ItemsService {
|
|
8
|
-
constructor(options) {
|
|
9
|
-
super('directus_policies', options);
|
|
10
|
-
}
|
|
11
|
-
async clearCaches(opts) {
|
|
12
|
-
await clearSystemCache({ autoPurgeCache: opts?.autoPurgeCache });
|
|
13
|
-
if (this.cache && opts?.autoPurgeCache !== false) {
|
|
14
|
-
await this.cache.clear();
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
isIpAccessValid(value) {
|
|
18
|
-
if (value === undefined)
|
|
19
|
-
return false;
|
|
20
|
-
if (value === null)
|
|
21
|
-
return true;
|
|
22
|
-
if (Array.isArray(value) && value.length === 0)
|
|
23
|
-
return true;
|
|
24
|
-
for (const ip of value) {
|
|
25
|
-
if (typeof ip !== 'string' || ip.includes('*'))
|
|
26
|
-
return false;
|
|
27
|
-
try {
|
|
28
|
-
const match = getMatch(ip);
|
|
29
|
-
if (match.type == 'IPMask')
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
catch {
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return true;
|
|
37
|
-
}
|
|
38
|
-
assertValidIpAccess(partialItem) {
|
|
39
|
-
if ('ip_access' in partialItem && !this.isIpAccessValid(partialItem['ip_access'])) {
|
|
40
|
-
throw new InvalidPayloadError({
|
|
41
|
-
reason: 'IP Access contains an incorrect value. Valid values are: IP addresses, IP ranges and CIDR blocks',
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
async createOne(data, opts = {}) {
|
|
46
|
-
this.assertValidIpAccess(data);
|
|
47
|
-
// A policy has been created, but the attachment to a user/role happens in the AccessService,
|
|
48
|
-
// so no need to check user integrity
|
|
49
|
-
const result = await super.createOne(data, opts);
|
|
50
|
-
// TODO is this necessary? Since the attachment should be handled in the AccessService
|
|
51
|
-
// A new policy has created, clear the permissions cache
|
|
52
|
-
await clearPermissionsCache();
|
|
53
|
-
return result;
|
|
54
|
-
}
|
|
55
|
-
async updateMany(keys, data, opts = {}) {
|
|
56
|
-
this.assertValidIpAccess(data);
|
|
57
|
-
if ('admin_access' in data) {
|
|
58
|
-
let flags = UserIntegrityCheckFlag.RemainingAdmins;
|
|
59
|
-
if (data['admin_access'] === true) {
|
|
60
|
-
// Only need to perform a full user count if the policy allows admin access
|
|
61
|
-
flags |= UserIntegrityCheckFlag.All;
|
|
62
|
-
}
|
|
63
|
-
opts.userIntegrityCheckFlags = (opts.userIntegrityCheckFlags ?? UserIntegrityCheckFlag.None) | flags;
|
|
64
|
-
}
|
|
65
|
-
if ('app_access' in data) {
|
|
66
|
-
opts.userIntegrityCheckFlags =
|
|
67
|
-
(opts.userIntegrityCheckFlags ?? UserIntegrityCheckFlag.None) | UserIntegrityCheckFlag.UserLimits;
|
|
68
|
-
}
|
|
69
|
-
if (opts.userIntegrityCheckFlags)
|
|
70
|
-
opts.onRequireUserIntegrityCheck?.(opts.userIntegrityCheckFlags);
|
|
71
|
-
const result = await super.updateMany(keys, data, opts);
|
|
72
|
-
if ('admin_access' in data || 'app_access' in data || 'ip_access' in data || 'enforce_tfa' in data) {
|
|
73
|
-
// Some relevant properties on policies have been updated, clear the caches
|
|
74
|
-
await this.clearCaches(opts);
|
|
75
|
-
}
|
|
76
|
-
return result;
|
|
77
|
-
}
|
|
78
|
-
async deleteMany(keys, opts = {}) {
|
|
79
|
-
opts.userIntegrityCheckFlags = UserIntegrityCheckFlag.All;
|
|
80
|
-
opts.onRequireUserIntegrityCheck?.(opts.userIntegrityCheckFlags);
|
|
81
|
-
const result = await super.deleteMany(keys, opts);
|
|
82
|
-
// TODO is this necessary? Since the detachment should be handled in the AccessService
|
|
83
|
-
// Some policies have been deleted, clear the permissions cache
|
|
84
|
-
await this.clearCaches(opts);
|
|
85
|
-
return result;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { useEnv } from '@directus/env';
|
|
2
|
-
import { LimitExceededError } from '@directus/errors';
|
|
3
|
-
import {} from '../../utils/fetch-user-count/fetch-user-count.js';
|
|
4
|
-
const env = useEnv();
|
|
5
|
-
/**
|
|
6
|
-
* Ensure that user limits are not reached
|
|
7
|
-
*/
|
|
8
|
-
export async function checkUserLimits(userCounts) {
|
|
9
|
-
if (userCounts.admin > Number(env['USERS_ADMIN_ACCESS_LIMIT'])) {
|
|
10
|
-
throw new LimitExceededError({ category: 'Active Admin users' });
|
|
11
|
-
}
|
|
12
|
-
// Both app and admin users count against the app access limit
|
|
13
|
-
if (userCounts.app + userCounts.admin > Number(env['USERS_APP_ACCESS_LIMIT'])) {
|
|
14
|
-
throw new LimitExceededError({ category: 'Active App users' });
|
|
15
|
-
}
|
|
16
|
-
if (userCounts.api > Number(env['USERS_API_ACCESS_LIMIT'])) {
|
|
17
|
-
throw new LimitExceededError({ category: 'Active API users' });
|
|
18
|
-
}
|
|
19
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { PrimaryKey } from '@directus/types';
|
|
2
|
-
import type { Knex } from 'knex';
|
|
3
|
-
export interface AccessLookup {
|
|
4
|
-
role: string | null;
|
|
5
|
-
user: string | null;
|
|
6
|
-
app_access: boolean | number;
|
|
7
|
-
admin_access: boolean | number;
|
|
8
|
-
}
|
|
9
|
-
export interface FetchAccessLookupOptions {
|
|
10
|
-
excludeAccessRows?: PrimaryKey[];
|
|
11
|
-
excludePolicies?: PrimaryKey[];
|
|
12
|
-
excludeUsers?: PrimaryKey[];
|
|
13
|
-
excludeRoles?: PrimaryKey[];
|
|
14
|
-
adminOnly?: boolean;
|
|
15
|
-
knex: Knex;
|
|
16
|
-
}
|
|
17
|
-
export declare function fetchAccessLookup(options: FetchAccessLookupOptions): Promise<AccessLookup[]>;
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export async function fetchAccessLookup(options) {
|
|
2
|
-
let query = options.knex
|
|
3
|
-
.select('directus_access.role', 'directus_access.user', 'directus_policies.app_access', 'directus_policies.admin_access')
|
|
4
|
-
.from('directus_access')
|
|
5
|
-
.leftJoin('directus_policies', 'directus_access.policy', 'directus_policies.id');
|
|
6
|
-
if (options.excludeAccessRows && options.excludeAccessRows.length > 0) {
|
|
7
|
-
query = query.whereNotIn('directus_access.id', options.excludeAccessRows);
|
|
8
|
-
}
|
|
9
|
-
if (options.excludePolicies && options.excludePolicies.length > 0) {
|
|
10
|
-
query = query.whereNotIn('directus_access.policy', options.excludePolicies);
|
|
11
|
-
}
|
|
12
|
-
if (options.excludeUsers && options.excludeUsers.length > 0) {
|
|
13
|
-
query = query.where((q) => q.whereNotIn('directus_access.user', options.excludeUsers).orWhereNull('directus_access.user'));
|
|
14
|
-
}
|
|
15
|
-
if (options.excludeRoles && options.excludeRoles.length > 0) {
|
|
16
|
-
query = query.where((q) => q.whereNotIn('directus_access.role', options.excludeRoles).orWhereNull('directus_access.role'));
|
|
17
|
-
}
|
|
18
|
-
if (options.adminOnly) {
|
|
19
|
-
query = query.where('directus_policies.admin_access', 1);
|
|
20
|
-
}
|
|
21
|
-
return query;
|
|
22
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { PrimaryKey } from '@directus/types';
|
|
2
|
-
import type { Knex } from 'knex';
|
|
3
|
-
export interface FetchAccessRolesOptions {
|
|
4
|
-
adminRoles: Set<string>;
|
|
5
|
-
appRoles: Set<string>;
|
|
6
|
-
excludeRoles?: PrimaryKey[];
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Return a set of roles that allow app or admin access, if itself or any of its parents do
|
|
10
|
-
*/
|
|
11
|
-
export declare function fetchAccessRoles(options: FetchAccessRolesOptions, context: {
|
|
12
|
-
knex: Knex;
|
|
13
|
-
}): Promise<{
|
|
14
|
-
adminRoles: Set<string>;
|
|
15
|
-
appRoles: Set<string>;
|
|
16
|
-
}>;
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Return a set of roles that allow app or admin access, if itself or any of its parents do
|
|
3
|
-
*/
|
|
4
|
-
export async function fetchAccessRoles(options, context) {
|
|
5
|
-
// Only fetch the roles that have a parent, as otherwise those roles should already be included in at least one of the input set
|
|
6
|
-
const allChildRoles = await context.knex
|
|
7
|
-
.select('id', 'parent')
|
|
8
|
-
.from('directus_roles')
|
|
9
|
-
.whereNotNull('parent')
|
|
10
|
-
.whereNotIn('id', options.excludeRoles ?? []);
|
|
11
|
-
const adminRoles = new Set(options.adminRoles);
|
|
12
|
-
const appRoles = new Set(options.appRoles);
|
|
13
|
-
const remainingRoles = new Set(allChildRoles);
|
|
14
|
-
let hasChanged = remainingRoles.size > 0;
|
|
15
|
-
// This loop accounts for the undefined order in which the roles are returned, as there is the possibility
|
|
16
|
-
// of a role parent not being in the set of roles yet, so we need to iterate over the roles multiple times
|
|
17
|
-
// until no further roles are added to the sets
|
|
18
|
-
while (hasChanged) {
|
|
19
|
-
hasChanged = false;
|
|
20
|
-
for (const role of remainingRoles) {
|
|
21
|
-
if (adminRoles.has(role.parent)) {
|
|
22
|
-
adminRoles.add(role.id);
|
|
23
|
-
remainingRoles.delete(role);
|
|
24
|
-
hasChanged = true;
|
|
25
|
-
}
|
|
26
|
-
if (appRoles.has(role.parent)) {
|
|
27
|
-
appRoles.add(role.id);
|
|
28
|
-
remainingRoles.delete(role);
|
|
29
|
-
hasChanged = true;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return {
|
|
34
|
-
adminRoles,
|
|
35
|
-
appRoles,
|
|
36
|
-
};
|
|
37
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { type FetchAccessLookupOptions } from './fetch-access-lookup.js';
|
|
2
|
-
export interface FetchUserCountOptions extends FetchAccessLookupOptions {
|
|
3
|
-
}
|
|
4
|
-
export interface UserCount {
|
|
5
|
-
admin: number;
|
|
6
|
-
app: number;
|
|
7
|
-
api: number;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Returns counts of all active users in the system grouped by admin, app, and api access
|
|
11
|
-
*/
|
|
12
|
-
export declare function fetchUserCount(options: FetchUserCountOptions): Promise<UserCount>;
|