directus 9.7.1 → 9.8.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/cache.js +2 -2
- package/dist/database/helpers/date/dialects/default.d.ts +3 -0
- package/dist/database/helpers/date/dialects/default.js +7 -0
- package/dist/database/helpers/date/dialects/sqlite.d.ts +0 -9
- package/dist/database/helpers/date/dialects/sqlite.js +0 -24
- package/dist/database/helpers/date/index.d.ts +6 -6
- package/dist/database/helpers/date/index.js +13 -13
- package/dist/database/helpers/date/types.d.ts +0 -9
- package/dist/database/helpers/{date → fn}/dialects/mssql.d.ts +3 -2
- package/dist/database/helpers/{date → fn}/dialects/mssql.js +14 -3
- package/dist/database/helpers/{date → fn}/dialects/mysql.d.ts +3 -2
- package/dist/database/helpers/{date → fn}/dialects/mysql.js +14 -3
- package/dist/database/helpers/{date → fn}/dialects/oracle.d.ts +3 -2
- package/dist/database/helpers/{date → fn}/dialects/oracle.js +14 -3
- package/dist/database/helpers/{date → fn}/dialects/postgres.d.ts +3 -2
- package/dist/database/helpers/{date → fn}/dialects/postgres.js +14 -3
- package/dist/database/helpers/fn/dialects/sqlite.d.ts +13 -0
- package/dist/database/helpers/fn/dialects/sqlite.js +42 -0
- package/dist/database/helpers/fn/index.d.ts +7 -0
- package/dist/database/helpers/fn/index.js +17 -0
- package/dist/database/helpers/fn/types.d.ts +18 -0
- package/dist/database/helpers/fn/types.js +27 -0
- package/dist/database/helpers/index.d.ts +4 -1
- package/dist/database/helpers/index.js +7 -1
- package/dist/database/migrations/20220308A-add-bookmark-icon-and-color.d.ts +3 -0
- package/dist/database/migrations/20220308A-add-bookmark-icon-and-color.js +17 -0
- package/dist/database/migrations/20220322A-rename-field-typecast-flags.js +6 -2
- package/dist/database/migrations/20220323A-add-field-validation.d.ts +3 -0
- package/dist/database/migrations/20220323A-add-field-validation.js +17 -0
- package/dist/database/migrations/20220325A-fix-typecast-flags.d.ts +3 -0
- package/dist/database/migrations/20220325A-fix-typecast-flags.js +49 -0
- package/dist/database/migrations/20220325B-add-default-language.d.ts +3 -0
- package/dist/database/migrations/20220325B-add-default-language.js +28 -0
- package/dist/database/run-ast.js +4 -2
- package/dist/database/system-data/fields/activity.yaml +4 -4
- package/dist/database/system-data/fields/fields.yaml +9 -0
- package/dist/database/system-data/fields/presets.yaml +14 -0
- package/dist/database/system-data/fields/settings.yaml +13 -1
- package/dist/logger.js +2 -1
- package/dist/services/activity.js +4 -1
- package/dist/services/authorization.d.ts +1 -1
- package/dist/services/authorization.js +128 -44
- package/dist/services/collections.js +222 -198
- package/dist/services/fields.js +184 -173
- package/dist/services/payload.js +8 -6
- package/dist/services/relations.js +93 -81
- package/dist/services/server.js +1 -0
- package/dist/services/shares.js +2 -1
- package/dist/services/users.js +3 -1
- package/dist/utils/apply-query.js +21 -3
- package/dist/utils/get-column.d.ts +6 -5
- package/dist/utils/get-column.js +16 -8
- package/dist/utils/get-schema.d.ts +1 -1
- package/dist/utils/get-schema.js +15 -10
- package/dist/utils/track.js +3 -2
- package/dist/utils/url.d.ts +1 -1
- package/dist/utils/url.js +1 -1
- package/dist/utils/validate-storage.js +3 -1
- package/package.json +12 -12
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.down = exports.up = void 0;
|
|
4
|
+
const helpers_1 = require("../helpers");
|
|
5
|
+
async function up(knex) {
|
|
6
|
+
const helper = (0, helpers_1.getHelpers)(knex).schema;
|
|
7
|
+
await knex.schema.alterTable('directus_settings', (table) => {
|
|
8
|
+
table.string('default_language').notNullable().defaultTo('en-US');
|
|
9
|
+
});
|
|
10
|
+
await helper.changeToString('directus_users', 'language', {
|
|
11
|
+
nullable: true,
|
|
12
|
+
default: null,
|
|
13
|
+
length: 255,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
exports.up = up;
|
|
17
|
+
async function down(knex) {
|
|
18
|
+
const helper = (0, helpers_1.getHelpers)(knex).schema;
|
|
19
|
+
await knex.schema.alterTable('directus_settings', (table) => {
|
|
20
|
+
table.dropColumn('default_language');
|
|
21
|
+
});
|
|
22
|
+
await helper.changeToString('directus_users', 'language', {
|
|
23
|
+
nullable: true,
|
|
24
|
+
default: 'en-US',
|
|
25
|
+
length: 255,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
exports.down = down;
|
package/dist/database/run-ast.js
CHANGED
|
@@ -151,7 +151,7 @@ function getColumnPreprocessor(knex, schema, table) {
|
|
|
151
151
|
if (field.type.startsWith('geometry')) {
|
|
152
152
|
return helpers.st.asText(table, field.field);
|
|
153
153
|
}
|
|
154
|
-
return (0, get_column_1.getColumn)(knex, table, fieldNode.name, alias);
|
|
154
|
+
return (0, get_column_1.getColumn)(knex, table, fieldNode.name, alias, schema);
|
|
155
155
|
};
|
|
156
156
|
}
|
|
157
157
|
function getDBQuery(schema, knex, table, fieldNodes, query) {
|
|
@@ -244,7 +244,9 @@ function mergeWithParentItems(schema, nestedItem, parentItem, nestedNode) {
|
|
|
244
244
|
if (nestedNode.query.offset && nestedNode.query.offset >= 0) {
|
|
245
245
|
parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(nestedNode.query.offset);
|
|
246
246
|
}
|
|
247
|
-
|
|
247
|
+
if (nestedNode.query.limit !== -1) {
|
|
248
|
+
parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(0, (_a = nestedNode.query.limit) !== null && _a !== void 0 ? _a : 100);
|
|
249
|
+
}
|
|
248
250
|
parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].sort((a, b) => {
|
|
249
251
|
// This is pre-filled in get-ast-from-query
|
|
250
252
|
const sortField = nestedNode.query.sort[0];
|
|
@@ -46,19 +46,19 @@ fields:
|
|
|
46
46
|
width: half
|
|
47
47
|
|
|
48
48
|
- field: comment
|
|
49
|
-
display: formatted-
|
|
49
|
+
display: formatted-value
|
|
50
50
|
display_options:
|
|
51
|
-
|
|
51
|
+
color: 'var(--foreground-subdued)'
|
|
52
52
|
width: half
|
|
53
53
|
|
|
54
54
|
- field: user_agent
|
|
55
|
-
display: formatted-
|
|
55
|
+
display: formatted-value
|
|
56
56
|
display_options:
|
|
57
57
|
font: monospace
|
|
58
58
|
width: half
|
|
59
59
|
|
|
60
60
|
- field: ip
|
|
61
|
-
display: formatted-
|
|
61
|
+
display: formatted-value
|
|
62
62
|
display_options:
|
|
63
63
|
font: monospace
|
|
64
64
|
width: half
|
|
@@ -15,9 +15,17 @@ fields:
|
|
|
15
15
|
|
|
16
16
|
- field: role
|
|
17
17
|
width: half
|
|
18
|
+
special: m2o
|
|
19
|
+
display: related-values
|
|
20
|
+
display_options:
|
|
21
|
+
template: '{{ name }}'
|
|
18
22
|
|
|
19
23
|
- field: user
|
|
20
24
|
width: half
|
|
25
|
+
special: m2o
|
|
26
|
+
display: related-values
|
|
27
|
+
display_options:
|
|
28
|
+
template: '{{ email }}'
|
|
21
29
|
|
|
22
30
|
- field: id
|
|
23
31
|
width: half
|
|
@@ -25,6 +33,12 @@ fields:
|
|
|
25
33
|
- field: bookmark
|
|
26
34
|
width: half
|
|
27
35
|
|
|
36
|
+
- field: icon
|
|
37
|
+
width: half
|
|
38
|
+
|
|
39
|
+
- field: color
|
|
40
|
+
width: half
|
|
41
|
+
|
|
28
42
|
- field: search
|
|
29
43
|
width: half
|
|
30
44
|
|
|
@@ -32,7 +32,18 @@ fields:
|
|
|
32
32
|
translations:
|
|
33
33
|
language: en-US
|
|
34
34
|
translations: Website
|
|
35
|
-
width:
|
|
35
|
+
width: half
|
|
36
|
+
|
|
37
|
+
- field: default_language
|
|
38
|
+
interface: system-language
|
|
39
|
+
options:
|
|
40
|
+
iconRight: language
|
|
41
|
+
placeholder: en-US
|
|
42
|
+
includeProjectDefault: false
|
|
43
|
+
translations:
|
|
44
|
+
language: en-US
|
|
45
|
+
translations: Default Language
|
|
46
|
+
width: half
|
|
36
47
|
|
|
37
48
|
- field: branding_divider
|
|
38
49
|
interface: presentation-divider
|
|
@@ -380,4 +391,5 @@ fields:
|
|
|
380
391
|
placeholder: $t:fields.directus_settings.attribution_placeholder
|
|
381
392
|
|
|
382
393
|
- field: translation_strings
|
|
394
|
+
special: cast-json
|
|
383
395
|
hidden: true
|
package/dist/logger.js
CHANGED
|
@@ -28,6 +28,7 @@ const pino_http_1 = __importStar(require("pino-http"));
|
|
|
28
28
|
const get_config_from_env_1 = require("./utils/get-config-from-env");
|
|
29
29
|
const url_1 = require("url");
|
|
30
30
|
const env_1 = __importDefault(require("./env"));
|
|
31
|
+
const utils_1 = require("@directus/shared/utils");
|
|
31
32
|
const pinoOptions = {
|
|
32
33
|
level: env_1.default.LOG_LEVEL || 'info',
|
|
33
34
|
redact: {
|
|
@@ -43,7 +44,7 @@ const loggerEnvConfig = (0, get_config_from_env_1.getConfigFromEnv)('LOGGER_', '
|
|
|
43
44
|
// Expose custom log levels into formatter function
|
|
44
45
|
if (loggerEnvConfig.levels) {
|
|
45
46
|
const customLogLevels = {};
|
|
46
|
-
for (const el of loggerEnvConfig.levels
|
|
47
|
+
for (const el of (0, utils_1.toArray)(loggerEnvConfig.levels)) {
|
|
47
48
|
const key_val = el.split(':');
|
|
48
49
|
customLogLevels[key_val[0].trim()] = key_val[1].trim();
|
|
49
50
|
}
|
|
@@ -16,6 +16,7 @@ const user_name_1 = require("../utils/user-name");
|
|
|
16
16
|
const lodash_1 = require("lodash");
|
|
17
17
|
const env_1 = __importDefault(require("../env"));
|
|
18
18
|
const uuid_validate_1 = __importDefault(require("uuid-validate"));
|
|
19
|
+
const url_1 = require("../utils/url");
|
|
19
20
|
class ActivityService extends items_1.ItemsService {
|
|
20
21
|
constructor(options) {
|
|
21
22
|
super('directus_activity', options);
|
|
@@ -70,7 +71,9 @@ ${(0, user_name_1.userName)(sender)} has mentioned you in a comment:
|
|
|
70
71
|
|
|
71
72
|
${comment}
|
|
72
73
|
|
|
73
|
-
<a href="${env_1.default.PUBLIC_URL
|
|
74
|
+
<a href="${new url_1.Url(env_1.default.PUBLIC_URL)
|
|
75
|
+
.addPath('admin', 'content', data.collection, data.item)
|
|
76
|
+
.toString()}">Click here to view.</a>
|
|
74
77
|
`;
|
|
75
78
|
await this.notificationsService.createOne({
|
|
76
79
|
recipient: userID,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { Accountability, PermissionsAction, SchemaOverview } from '@directus/shared/types';
|
|
1
2
|
import { Knex } from 'knex';
|
|
2
3
|
import { AbstractServiceOptions, AST, Item, PrimaryKey } from '../types';
|
|
3
|
-
import { PermissionsAction, Accountability, SchemaOverview } from '@directus/shared/types';
|
|
4
4
|
import { PayloadService } from './payload';
|
|
5
5
|
export declare class AuthorizationService {
|
|
6
6
|
knex: Knex;
|
|
@@ -4,14 +4,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.AuthorizationService = void 0;
|
|
7
|
+
const exceptions_1 = require("@directus/shared/exceptions");
|
|
8
|
+
const utils_1 = require("@directus/shared/utils");
|
|
7
9
|
const lodash_1 = require("lodash");
|
|
8
10
|
const database_1 = __importDefault(require("../database"));
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const utils_1 = require("@directus/shared/utils");
|
|
11
|
+
const exceptions_2 = require("../exceptions");
|
|
12
|
+
const strip_function_1 = require("../utils/strip-function");
|
|
12
13
|
const items_1 = require("./items");
|
|
13
14
|
const payload_1 = require("./payload");
|
|
14
|
-
const strip_function_1 = require("../utils/strip-function");
|
|
15
15
|
class AuthorizationService {
|
|
16
16
|
constructor(options) {
|
|
17
17
|
this.knex = options.knex || (0, database_1.default)();
|
|
@@ -32,7 +32,7 @@ class AuthorizationService {
|
|
|
32
32
|
// If the permissions don't match the collections, you don't have permission to read all of them
|
|
33
33
|
const uniqueCollectionsRequestedCount = (0, lodash_1.uniq)(collectionsRequested.map(({ collection }) => collection)).length;
|
|
34
34
|
if (uniqueCollectionsRequestedCount !== permissionsForCollections.length) {
|
|
35
|
-
throw new
|
|
35
|
+
throw new exceptions_2.ForbiddenException();
|
|
36
36
|
}
|
|
37
37
|
validateFields(ast);
|
|
38
38
|
validateFilterPermissions(ast, this.schema, this.accountability);
|
|
@@ -88,7 +88,7 @@ class AuthorizationService {
|
|
|
88
88
|
continue;
|
|
89
89
|
for (const column of Object.values(aliasMap)) {
|
|
90
90
|
if (allowedFields.includes(column) === false)
|
|
91
|
-
throw new
|
|
91
|
+
throw new exceptions_2.ForbiddenException();
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
}
|
|
@@ -101,65 +101,137 @@ class AuthorizationService {
|
|
|
101
101
|
continue;
|
|
102
102
|
const fieldKey = (0, strip_function_1.stripFunction)(childNode.name);
|
|
103
103
|
if (allowedFields.includes(fieldKey) === false) {
|
|
104
|
-
throw new
|
|
104
|
+
throw new exceptions_2.ForbiddenException();
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
function validateFilterPermissions(ast, schema, accountability) {
|
|
110
110
|
var _a, _b, _c, _d, _e;
|
|
111
|
+
let requiredFieldPermissions = {};
|
|
111
112
|
if (ast.type !== 'field') {
|
|
112
113
|
if (ast.type === 'a2o') {
|
|
113
114
|
for (const collection of Object.keys(ast.children)) {
|
|
114
|
-
|
|
115
|
+
requiredFieldPermissions = mergeRequiredFieldPermissions(requiredFieldPermissions, extractRequiredFieldPermissions(collection, (_c = (_b = (_a = ast.query) === null || _a === void 0 ? void 0 : _a[collection]) === null || _b === void 0 ? void 0 : _b.filter) !== null && _c !== void 0 ? _c : {}));
|
|
115
116
|
for (const child of ast.children[collection]) {
|
|
116
|
-
|
|
117
|
+
// Always add relational field as a deep child may have a filter
|
|
118
|
+
if (child.type !== 'field') {
|
|
119
|
+
(requiredFieldPermissions[collection] || (requiredFieldPermissions[collection] = new Set())).add(child.fieldKey);
|
|
120
|
+
}
|
|
121
|
+
requiredFieldPermissions = mergeRequiredFieldPermissions(requiredFieldPermissions, validateFilterPermissions(child, schema, accountability));
|
|
117
122
|
}
|
|
118
123
|
}
|
|
119
124
|
}
|
|
120
125
|
else {
|
|
121
|
-
|
|
126
|
+
requiredFieldPermissions = mergeRequiredFieldPermissions(requiredFieldPermissions, extractRequiredFieldPermissions(ast.name, (_e = (_d = ast.query) === null || _d === void 0 ? void 0 : _d.filter) !== null && _e !== void 0 ? _e : {}));
|
|
122
127
|
for (const child of ast.children) {
|
|
123
|
-
|
|
128
|
+
// Always add relational field as a deep child may have a filter
|
|
129
|
+
if (child.type !== 'field') {
|
|
130
|
+
(requiredFieldPermissions[ast.name] || (requiredFieldPermissions[ast.name] = new Set())).add(child.fieldKey);
|
|
131
|
+
}
|
|
132
|
+
requiredFieldPermissions = mergeRequiredFieldPermissions(requiredFieldPermissions, validateFilterPermissions(child, schema, accountability));
|
|
124
133
|
}
|
|
125
134
|
}
|
|
126
135
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if (
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
if (ast.type === 'root') {
|
|
137
|
+
// Validate all required permissions once at the root level
|
|
138
|
+
checkFieldPermissions(requiredFieldPermissions);
|
|
139
|
+
}
|
|
140
|
+
return requiredFieldPermissions;
|
|
141
|
+
function extractRequiredFieldPermissions(collection, filter, parentCollection, parentField) {
|
|
142
|
+
return (0, lodash_1.reduce)(filter, function (result, filterValue, filterKey) {
|
|
143
|
+
if (filterKey.startsWith('_')) {
|
|
144
|
+
if (filterKey === '_and' || filterKey === '_or') {
|
|
145
|
+
if ((0, lodash_1.isArray)(filterValue)) {
|
|
146
|
+
for (const filter of filterValue) {
|
|
147
|
+
const requiredPermissions = extractRequiredFieldPermissions(collection, filter, parentCollection, parentField);
|
|
148
|
+
result = mergeRequiredFieldPermissions(result, requiredPermissions);
|
|
149
|
+
}
|
|
139
150
|
}
|
|
151
|
+
return result;
|
|
140
152
|
}
|
|
153
|
+
// Filter value is not a filter, so we should skip it
|
|
154
|
+
return result;
|
|
141
155
|
}
|
|
142
156
|
else {
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
allowedFields.includes(key) === false) {
|
|
146
|
-
throw new exceptions_1.ForbiddenException();
|
|
157
|
+
if (collection) {
|
|
158
|
+
(result[collection] || (result[collection] = new Set())).add(filterKey);
|
|
147
159
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
(relation.
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
160
|
+
else {
|
|
161
|
+
const relation = schema.relations.find((relation) => {
|
|
162
|
+
var _a;
|
|
163
|
+
return ((relation.collection === parentCollection && relation.field === parentField) ||
|
|
164
|
+
(relation.related_collection === parentCollection && ((_a = relation.meta) === null || _a === void 0 ? void 0 : _a.one_field) === parentField));
|
|
165
|
+
});
|
|
166
|
+
if (relation) {
|
|
167
|
+
if (relation.related_collection === parentCollection) {
|
|
168
|
+
(result[relation.collection] || (result[relation.collection] = new Set())).add(filterKey);
|
|
169
|
+
parentCollection = relation.collection;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
(result[relation.related_collection] || (result[relation.related_collection] = new Set())).add(filterKey);
|
|
173
|
+
parentCollection = relation.related_collection;
|
|
174
|
+
}
|
|
157
175
|
}
|
|
158
176
|
else {
|
|
159
|
-
|
|
177
|
+
// Filter key not found in parent collection
|
|
178
|
+
throw new exceptions_2.ForbiddenException();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (typeof filterValue === 'object') {
|
|
182
|
+
// Parent collection is undefined when we process the top level filter
|
|
183
|
+
if (!parentCollection)
|
|
184
|
+
parentCollection = collection;
|
|
185
|
+
for (const [childFilterKey, childFilterValue] of Object.entries(filterValue)) {
|
|
186
|
+
if (childFilterKey.startsWith('_')) {
|
|
187
|
+
if (childFilterKey === '_and' || childFilterKey === '_or') {
|
|
188
|
+
if ((0, lodash_1.isArray)(childFilterValue)) {
|
|
189
|
+
for (const filter of childFilterValue) {
|
|
190
|
+
const requiredPermissions = extractRequiredFieldPermissions('', filter, parentCollection, filterKey);
|
|
191
|
+
result = mergeRequiredFieldPermissions(result, requiredPermissions);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
const requiredPermissions = extractRequiredFieldPermissions('', filterValue, parentCollection, filterKey);
|
|
198
|
+
result = mergeRequiredFieldPermissions(result, requiredPermissions);
|
|
199
|
+
}
|
|
160
200
|
}
|
|
161
201
|
}
|
|
162
202
|
}
|
|
203
|
+
return result;
|
|
204
|
+
}, {});
|
|
205
|
+
}
|
|
206
|
+
function mergeRequiredFieldPermissions(current, child) {
|
|
207
|
+
for (const collection of Object.keys(child)) {
|
|
208
|
+
if (!current[collection]) {
|
|
209
|
+
current[collection] = child[collection];
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
current[collection] = new Set([...current[collection], ...child[collection]]);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return current;
|
|
216
|
+
}
|
|
217
|
+
function checkFieldPermissions(requiredPermissions) {
|
|
218
|
+
var _a;
|
|
219
|
+
if ((accountability === null || accountability === void 0 ? void 0 : accountability.admin) === true)
|
|
220
|
+
return;
|
|
221
|
+
for (const collection of Object.keys(requiredPermissions)) {
|
|
222
|
+
const permission = (_a = accountability === null || accountability === void 0 ? void 0 : accountability.permissions) === null || _a === void 0 ? void 0 : _a.find((permission) => permission.collection === collection && permission.action === 'read');
|
|
223
|
+
if (!permission || !permission.fields)
|
|
224
|
+
throw new exceptions_2.ForbiddenException();
|
|
225
|
+
const allowedFields = permission.fields;
|
|
226
|
+
if (allowedFields.includes('*'))
|
|
227
|
+
continue;
|
|
228
|
+
// Allow legacy permissions with an empty fields array, where id can be accessed
|
|
229
|
+
if (allowedFields.length === 0)
|
|
230
|
+
allowedFields.push('id');
|
|
231
|
+
for (const field of requiredPermissions[collection]) {
|
|
232
|
+
if (!allowedFields.includes(field))
|
|
233
|
+
throw new exceptions_2.ForbiddenException();
|
|
234
|
+
}
|
|
163
235
|
}
|
|
164
236
|
}
|
|
165
237
|
}
|
|
@@ -222,20 +294,24 @@ class AuthorizationService {
|
|
|
222
294
|
return permission.collection === collection && permission.action === action;
|
|
223
295
|
});
|
|
224
296
|
if (!permission)
|
|
225
|
-
throw new
|
|
297
|
+
throw new exceptions_2.ForbiddenException();
|
|
226
298
|
// Check if you have permission to access the fields you're trying to access
|
|
227
299
|
const allowedFields = permission.fields || [];
|
|
228
300
|
if (allowedFields.includes('*') === false) {
|
|
229
301
|
const keysInData = Object.keys(payload);
|
|
230
302
|
const invalidKeys = keysInData.filter((fieldKey) => allowedFields.includes(fieldKey) === false);
|
|
231
303
|
if (invalidKeys.length > 0) {
|
|
232
|
-
throw new
|
|
304
|
+
throw new exceptions_2.ForbiddenException();
|
|
233
305
|
}
|
|
234
306
|
}
|
|
235
307
|
}
|
|
236
308
|
const preset = (_e = permission.presets) !== null && _e !== void 0 ? _e : {};
|
|
237
309
|
const payloadWithPresets = (0, lodash_1.merge)({}, preset, payload);
|
|
310
|
+
const fieldValidationRules = Object.values(this.schema.collections[collection].fields)
|
|
311
|
+
.map((field) => field.validation)
|
|
312
|
+
.filter((v) => v);
|
|
238
313
|
const hasValidationRules = (0, lodash_1.isNil)(permission.validation) === false && Object.keys((_f = permission.validation) !== null && _f !== void 0 ? _f : {}).length > 0;
|
|
314
|
+
const hasFieldValidationRules = fieldValidationRules && fieldValidationRules.length > 0;
|
|
239
315
|
const requiredColumns = [];
|
|
240
316
|
for (const field of Object.values(this.schema.collections[collection].fields)) {
|
|
241
317
|
const specials = (_g = field === null || field === void 0 ? void 0 : field.special) !== null && _g !== void 0 ? _g : [];
|
|
@@ -245,7 +321,7 @@ class AuthorizationService {
|
|
|
245
321
|
requiredColumns.push(field);
|
|
246
322
|
}
|
|
247
323
|
}
|
|
248
|
-
if (hasValidationRules === false && requiredColumns.length === 0) {
|
|
324
|
+
if (hasValidationRules === false && hasFieldValidationRules === false && requiredColumns.length === 0) {
|
|
249
325
|
return payloadWithPresets;
|
|
250
326
|
}
|
|
251
327
|
if (requiredColumns.length > 0) {
|
|
@@ -265,8 +341,16 @@ class AuthorizationService {
|
|
|
265
341
|
});
|
|
266
342
|
}
|
|
267
343
|
}
|
|
344
|
+
if (hasFieldValidationRules) {
|
|
345
|
+
if (permission.validation) {
|
|
346
|
+
permission.validation = { _and: [permission.validation, ...fieldValidationRules] };
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
permission.validation = { _and: fieldValidationRules };
|
|
350
|
+
}
|
|
351
|
+
}
|
|
268
352
|
const validationErrors = [];
|
|
269
|
-
validationErrors.push(...(0, lodash_1.flatten)((0, utils_1.validatePayload)(permission.validation, payloadWithPresets).map((error) => error.details.map((details) => new
|
|
353
|
+
validationErrors.push(...(0, lodash_1.flatten)((0, utils_1.validatePayload)(permission.validation, payloadWithPresets).map((error) => error.details.map((details) => new exceptions_1.FailedValidationException(details)))));
|
|
270
354
|
if (validationErrors.length > 0)
|
|
271
355
|
throw validationErrors;
|
|
272
356
|
return payloadWithPresets;
|
|
@@ -286,14 +370,14 @@ class AuthorizationService {
|
|
|
286
370
|
if (Array.isArray(pk)) {
|
|
287
371
|
const result = await itemsService.readMany(pk, { ...query, limit: pk.length }, { permissionsAction: action });
|
|
288
372
|
if (!result)
|
|
289
|
-
throw new
|
|
373
|
+
throw new exceptions_2.ForbiddenException();
|
|
290
374
|
if (result.length !== pk.length)
|
|
291
|
-
throw new
|
|
375
|
+
throw new exceptions_2.ForbiddenException();
|
|
292
376
|
}
|
|
293
377
|
else {
|
|
294
378
|
const result = await itemsService.readOne(pk, query, { permissionsAction: action });
|
|
295
379
|
if (!result)
|
|
296
|
-
throw new
|
|
380
|
+
throw new exceptions_2.ForbiddenException();
|
|
297
381
|
}
|
|
298
382
|
}
|
|
299
383
|
}
|