directus 9.5.1 → 9.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/app.js +3 -1
  2. package/dist/auth/drivers/ldap.d.ts +0 -1
  3. package/dist/auth/drivers/ldap.js +54 -60
  4. package/dist/auth/drivers/oauth2.js +3 -0
  5. package/dist/auth/drivers/openid.js +9 -6
  6. package/dist/cache.d.ts +4 -1
  7. package/dist/cache.js +27 -5
  8. package/dist/cli/commands/init/index.js +8 -0
  9. package/dist/cli/commands/schema/apply.d.ts +1 -0
  10. package/dist/cli/commands/schema/apply.js +9 -5
  11. package/dist/cli/index.js +1 -0
  12. package/dist/cli/utils/create-env/env-stub.liquid +1 -0
  13. package/dist/controllers/assets.js +9 -1
  14. package/dist/controllers/utils.js +18 -1
  15. package/dist/database/migrations/20220303A-remove-default-project-color.d.ts +3 -0
  16. package/dist/database/migrations/20220303A-remove-default-project-color.js +22 -0
  17. package/dist/database/run-ast.d.ts +1 -1
  18. package/dist/database/run-ast.js +48 -35
  19. package/dist/database/system-data/app-access-permissions/app-access-permissions.yaml +8 -2
  20. package/dist/database/system-data/fields/collections.yaml +2 -0
  21. package/dist/database/system-data/fields/settings.yaml +19 -3
  22. package/dist/env.js +8 -2
  23. package/dist/exceptions/database/dialects/mysql.js +23 -17
  24. package/dist/extensions.js +0 -2
  25. package/dist/middleware/authenticate.d.ts +5 -3
  26. package/dist/middleware/authenticate.js +22 -39
  27. package/dist/middleware/respond.js +7 -28
  28. package/dist/server.js +5 -2
  29. package/dist/services/authorization.js +2 -1
  30. package/dist/services/collections.js +9 -7
  31. package/dist/services/fields.js +8 -8
  32. package/dist/services/files.js +69 -3
  33. package/dist/services/graphql.js +2 -2
  34. package/dist/services/import-export.d.ts +34 -0
  35. package/dist/services/import-export.js +270 -0
  36. package/dist/services/index.d.ts +2 -1
  37. package/dist/services/index.js +2 -1
  38. package/dist/services/mail/templates/base.liquid +2 -2
  39. package/dist/services/permissions.js +10 -10
  40. package/dist/services/relations.js +11 -4
  41. package/dist/services/utils.js +10 -0
  42. package/dist/utils/apply-query.js +2 -24
  43. package/dist/utils/get-date-formatted.d.ts +1 -0
  44. package/dist/utils/get-date-formatted.js +14 -0
  45. package/dist/utils/get-permissions.js +1 -1
  46. package/dist/utils/get-schema.js +1 -1
  47. package/dist/utils/is-directus-jwt.js +4 -21
  48. package/dist/utils/jwt.d.ts +2 -0
  49. package/dist/utils/jwt.js +49 -0
  50. package/dist/utils/merge-permissions.js +18 -6
  51. package/example.env +1 -0
  52. package/package.json +19 -20
  53. package/dist/__mocks__/cache.d.ts +0 -6
  54. package/dist/__mocks__/cache.js +0 -8
  55. package/dist/services/import.d.ts +0 -13
  56. package/dist/services/import.js +0 -118
@@ -3,15 +3,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ const utils_1 = require("@directus/shared/utils");
6
7
  const lodash_1 = require("lodash");
8
+ const _1 = __importDefault(require("."));
9
+ const helpers_1 = require("../database/helpers");
10
+ const env_1 = __importDefault(require("../env"));
7
11
  const payload_1 = require("../services/payload");
8
12
  const apply_function_to_column_name_1 = require("../utils/apply-function-to-column-name");
9
13
  const apply_query_1 = __importDefault(require("../utils/apply-query"));
10
14
  const get_column_1 = require("../utils/get-column");
11
15
  const strip_function_1 = require("../utils/strip-function");
12
- const utils_1 = require("@directus/shared/utils");
13
- const _1 = __importDefault(require("."));
14
- const helpers_1 = require("../database/helpers");
15
16
  /**
16
17
  * Execute a given AST using Knex. Returns array of items based on requested AST.
17
18
  */
@@ -44,10 +45,33 @@ async function runAST(originalAST, schema, options) {
44
45
  // Apply the `_in` filters to the nested collection batches
45
46
  const nestedNodes = applyParentFilters(schema, nestedCollectionNodes, items);
46
47
  for (const nestedNode of nestedNodes) {
47
- const nestedItems = await runAST(nestedNode, schema, { knex, nested: true });
48
- if (nestedItems) {
49
- // Merge all fetched nested records with the parent items
50
- items = mergeWithParentItems(schema, nestedItems, items, nestedNode);
48
+ let nestedItems = [];
49
+ if (nestedNode.type === 'o2m') {
50
+ let hasMore = true;
51
+ let batchCount = 0;
52
+ while (hasMore) {
53
+ const node = (0, lodash_1.merge)({}, nestedNode, {
54
+ query: { limit: env_1.default.RELATIONAL_BATCH_SIZE, offset: batchCount * env_1.default.RELATIONAL_BATCH_SIZE },
55
+ });
56
+ nestedItems = (await runAST(node, schema, { knex, nested: true }));
57
+ if (nestedItems) {
58
+ items = mergeWithParentItems(schema, nestedItems, items, nestedNode);
59
+ }
60
+ if (!nestedItems || nestedItems.length < env_1.default.RELATIONAL_BATCH_SIZE) {
61
+ hasMore = false;
62
+ }
63
+ batchCount++;
64
+ }
65
+ }
66
+ else {
67
+ const node = (0, lodash_1.merge)({}, nestedNode, {
68
+ query: { limit: -1 },
69
+ });
70
+ nestedItems = (await runAST(node, schema, { knex, nested: true }));
71
+ if (nestedItems) {
72
+ // Merge all fetched nested records with the parent items
73
+ items = mergeWithParentItems(schema, nestedItems, items, nestedNode);
74
+ }
51
75
  }
52
76
  }
53
77
  // During the fetching of data, we have to inject a couple of required fields for the child nesting
@@ -146,13 +170,7 @@ function applyParentFilters(schema, nestedCollectionNodes, parentItem) {
146
170
  if (nestedNode.type === 'm2o') {
147
171
  const foreignField = schema.collections[nestedNode.relation.related_collection].primary;
148
172
  const foreignIds = (0, lodash_1.uniq)(parentItems.map((res) => res[nestedNode.relation.field])).filter((id) => id);
149
- const limit = nestedNode.query.limit;
150
- if (limit === -1) {
151
- (0, lodash_1.merge)(nestedNode, { query: { filter: { [foreignField]: { _in: foreignIds } } } });
152
- }
153
- else {
154
- nestedNode.query.union = [foreignField, foreignIds];
155
- }
173
+ (0, lodash_1.merge)(nestedNode, { query: { filter: { [foreignField]: { _in: foreignIds } } } });
156
174
  }
157
175
  else if (nestedNode.type === 'o2m') {
158
176
  const relatedM2OisFetched = !!nestedNode.children.find((child) => {
@@ -174,13 +192,7 @@ function applyParentFilters(schema, nestedCollectionNodes, parentItem) {
174
192
  }
175
193
  const foreignField = nestedNode.relation.field;
176
194
  const foreignIds = (0, lodash_1.uniq)(parentItems.map((res) => res[nestedNode.parentKey])).filter((id) => id);
177
- const limit = nestedNode.query.limit;
178
- if (limit === -1) {
179
- (0, lodash_1.merge)(nestedNode, { query: { filter: { [foreignField]: { _in: foreignIds } } } });
180
- }
181
- else {
182
- nestedNode.query.union = [foreignField, foreignIds];
183
- }
195
+ (0, lodash_1.merge)(nestedNode, { query: { filter: { [foreignField]: { _in: foreignIds } } } });
184
196
  }
185
197
  else if (nestedNode.type === 'a2o') {
186
198
  const keysPerCollection = {};
@@ -193,20 +205,16 @@ function applyParentFilters(schema, nestedCollectionNodes, parentItem) {
193
205
  for (const relatedCollection of nestedNode.names) {
194
206
  const foreignField = nestedNode.relatedKey[relatedCollection];
195
207
  const foreignIds = (0, lodash_1.uniq)(keysPerCollection[relatedCollection]);
196
- const limit = nestedNode.query[relatedCollection].limit;
197
- if (limit === -1) {
198
- (0, lodash_1.merge)(nestedNode, { query: { [relatedCollection]: { filter: { [foreignField]: { _in: foreignIds } } } } });
199
- }
200
- else {
201
- nestedNode.query[relatedCollection].union = [foreignField, foreignIds];
202
- }
208
+ (0, lodash_1.merge)(nestedNode, {
209
+ query: { [relatedCollection]: { filter: { [foreignField]: { _in: foreignIds } } } },
210
+ });
203
211
  }
204
212
  }
205
213
  }
206
214
  return nestedCollectionNodes;
207
215
  }
208
216
  function mergeWithParentItems(schema, nestedItem, parentItem, nestedNode) {
209
- var _a;
217
+ var _a, _b;
210
218
  const nestedItems = (0, utils_1.toArray)(nestedItem);
211
219
  const parentItems = (0, lodash_1.clone)((0, utils_1.toArray)(parentItem));
212
220
  if (nestedNode.type === 'm2o') {
@@ -220,8 +228,9 @@ function mergeWithParentItems(schema, nestedItem, parentItem, nestedNode) {
220
228
  }
221
229
  else if (nestedNode.type === 'o2m') {
222
230
  for (const parentItem of parentItems) {
223
- const itemChildren = nestedItems
224
- .filter((nestedItem) => {
231
+ if (!parentItem[nestedNode.fieldKey])
232
+ parentItem[nestedNode.fieldKey] = [];
233
+ const itemChildren = nestedItems.filter((nestedItem) => {
225
234
  var _a;
226
235
  if (nestedItem === null)
227
236
  return false;
@@ -230,8 +239,13 @@ function mergeWithParentItems(schema, nestedItem, parentItem, nestedNode) {
230
239
  return (nestedItem[nestedNode.relation.field] ==
231
240
  parentItem[schema.collections[nestedNode.relation.related_collection].primary] ||
232
241
  ((_a = nestedItem[nestedNode.relation.field]) === null || _a === void 0 ? void 0 : _a[schema.collections[nestedNode.relation.related_collection].primary]) == parentItem[schema.collections[nestedNode.relation.related_collection].primary]);
233
- })
234
- .sort((a, b) => {
242
+ });
243
+ parentItem[nestedNode.fieldKey].push(...itemChildren);
244
+ if (nestedNode.query.offset && nestedNode.query.offset >= 0) {
245
+ parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(nestedNode.query.offset);
246
+ }
247
+ parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].slice(0, (_a = nestedNode.query.limit) !== null && _a !== void 0 ? _a : 100);
248
+ parentItem[nestedNode.fieldKey] = parentItem[nestedNode.fieldKey].sort((a, b) => {
235
249
  // This is pre-filled in get-ast-from-query
236
250
  const sortField = nestedNode.query.sort[0];
237
251
  let column = sortField;
@@ -253,12 +267,11 @@ function mergeWithParentItems(schema, nestedItem, parentItem, nestedNode) {
253
267
  return a[column] < b[column] ? 1 : -1;
254
268
  }
255
269
  });
256
- parentItem[nestedNode.fieldKey] = itemChildren.length > 0 ? itemChildren : [];
257
270
  }
258
271
  }
259
272
  else if (nestedNode.type === 'a2o') {
260
273
  for (const parentItem of parentItems) {
261
- if (!((_a = nestedNode.relation.meta) === null || _a === void 0 ? void 0 : _a.one_collection_field)) {
274
+ if (!((_b = nestedNode.relation.meta) === null || _b === void 0 ? void 0 : _b.one_collection_field)) {
262
275
  parentItem[nestedNode.fieldKey] = null;
263
276
  continue;
264
277
  }
@@ -62,14 +62,20 @@
62
62
  permissions:
63
63
  recipient:
64
64
  _eq: $CURRENT_USER
65
- fields: '*'
66
65
 
67
66
  - collection: directus_notifications
68
67
  action: update
69
68
  permissions:
70
69
  recipient:
71
70
  _eq: $CURRENT_USER
72
- fields: 'status'
71
+ fields:
72
+ - status
73
+
74
+ - collection: directus_shares
75
+ action: read
76
+ permissions:
77
+ user_created:
78
+ _eq: $CURRENT_USER
73
79
 
74
80
  - collection: directus_users
75
81
  action: read
@@ -156,6 +156,8 @@ fields:
156
156
  - decimal
157
157
  - integer
158
158
  allowNone: true
159
+ allowPrimaryKey: false
160
+ allowForeignKeys: false
159
161
  width: half
160
162
 
161
163
  - field: accountability_divider
@@ -87,9 +87,25 @@ fields:
87
87
  language: css
88
88
  lineNumber: true
89
89
  template: |
90
- #app, #main-content {
91
- --border-radius-outline: 0px !important;
92
- --border-radius: 0px !important;
90
+ #app, #main-content, body {
91
+ --primary-alt: #F0ECFF !important;
92
+ --primary-10: #F0ECFF !important;
93
+ --primary-25: #D9D0FF !important;
94
+ --primary-50: #B3A1FF !important;
95
+ --primary-75: #8C73FF !important;
96
+ --primary-90: #7557FF !important;
97
+
98
+ --primary: #6644FF !important;
99
+
100
+ --primary-110: #5E41EC !important;
101
+ --primary-125: #523DCF !important;
102
+ --primary-150: #3E369F !important;
103
+ --primary-175: #2B3070 !important;
104
+ --primary-190: #1F2C53 !important;
105
+
106
+ --v-button-background-color: #6644FF !important;
107
+ --v-button-background-color-hover: #5E41EC !important;
108
+ --sidebar-detail-color-active: #5E41EC !important;
93
109
  }
94
110
  width: full
95
111
 
package/dist/env.js CHANGED
@@ -17,6 +17,7 @@ const utils_1 = require("@directus/shared/utils");
17
17
  const acceptedEnvTypes = ['string', 'number', 'regex', 'array'];
18
18
  const defaults = {
19
19
  CONFIG_PATH: path_1.default.resolve(process.cwd(), '.env'),
20
+ HOST: '0.0.0.0',
20
21
  PORT: 8055,
21
22
  PUBLIC_URL: '/',
22
23
  MAX_PAYLOAD_SIZE: '100kb',
@@ -34,8 +35,8 @@ const defaults = {
34
35
  REFRESH_TOKEN_COOKIE_SAME_SITE: 'lax',
35
36
  REFRESH_TOKEN_COOKIE_NAME: 'directus_refresh_token',
36
37
  ROOT_REDIRECT: './admin',
37
- CORS_ENABLED: true,
38
- CORS_ORIGIN: true,
38
+ CORS_ENABLED: false,
39
+ CORS_ORIGIN: false,
39
40
  CORS_METHODS: 'GET,POST,PATCH,DELETE',
40
41
  CORS_ALLOWED_HEADERS: 'Content-Type,Authorization',
41
42
  CORS_EXPOSED_HEADERS: 'Content-Range',
@@ -64,11 +65,15 @@ const defaults = {
64
65
  ASSETS_TRANSFORM_MAX_OPERATIONS: 5,
65
66
  IP_TRUST_PROXY: true,
66
67
  IP_CUSTOM_HEADER: false,
68
+ IMPORT_IP_DENY_LIST: '0.0.0.0',
67
69
  SERVE_APP: true,
70
+ RELATIONAL_BATCH_SIZE: 25000,
71
+ EXPORT_BATCH_SIZE: 5000,
68
72
  };
69
73
  // Allows us to force certain environment variable into a type, instead of relying
70
74
  // on the auto-parsed type in processValues. ref #3705
71
75
  const typeMap = {
76
+ HOST: 'string',
72
77
  PORT: 'string',
73
78
  DB_NAME: 'string',
74
79
  DB_USER: 'string',
@@ -76,6 +81,7 @@ const typeMap = {
76
81
  DB_DATABASE: 'string',
77
82
  DB_PORT: 'number',
78
83
  DB_EXCLUDE_TABLES: 'array',
84
+ IMPORT_IP_DENY_LIST: 'array',
79
85
  };
80
86
  let env = {
81
87
  ...defaults,
@@ -38,6 +38,7 @@ function extractError(error) {
38
38
  }
39
39
  exports.extractError = extractError;
40
40
  function uniqueViolation(error) {
41
+ var _a, _b, _c, _d, _e;
41
42
  const betweenQuotes = /'([^']+)'/g;
42
43
  const matches = error.sqlMessage.match(betweenQuotes);
43
44
  if (!matches)
@@ -49,13 +50,13 @@ function uniqueViolation(error) {
49
50
  */
50
51
  /** MySQL 8+ style error message */
51
52
  if (matches[1].includes('.')) {
52
- const collection = matches[1].slice(1, -1).split('.')[0];
53
+ const collection = (_a = matches[1]) === null || _a === void 0 ? void 0 : _a.slice(1, -1).split('.')[0];
53
54
  let field = null;
54
- const indexName = matches[1].slice(1, -1).split('.')[1];
55
+ const indexName = (_b = matches[1]) === null || _b === void 0 ? void 0 : _b.slice(1, -1).split('.')[1];
55
56
  if ((indexName === null || indexName === void 0 ? void 0 : indexName.startsWith(`${collection}_`)) && indexName.endsWith('_unique')) {
56
- field = indexName.slice(collection.length + 1, -7);
57
+ field = indexName === null || indexName === void 0 ? void 0 : indexName.slice(collection.length + 1, -7);
57
58
  }
58
- const invalid = matches[0].slice(1, -1);
59
+ const invalid = (_c = matches[0]) === null || _c === void 0 ? void 0 : _c.slice(1, -1);
59
60
  return new record_not_unique_1.RecordNotUniqueException(field, {
60
61
  collection,
61
62
  field,
@@ -64,13 +65,13 @@ function uniqueViolation(error) {
64
65
  }
65
66
  else {
66
67
  /** MySQL 5.7 style error message */
67
- const indexName = matches[1].slice(1, -1);
68
+ const indexName = (_d = matches[1]) === null || _d === void 0 ? void 0 : _d.slice(1, -1);
68
69
  const collection = indexName.split('_')[0];
69
70
  let field = null;
70
71
  if ((indexName === null || indexName === void 0 ? void 0 : indexName.startsWith(`${collection}_`)) && indexName.endsWith('_unique')) {
71
- field = indexName.slice(collection.length + 1, -7);
72
+ field = indexName === null || indexName === void 0 ? void 0 : indexName.slice(collection.length + 1, -7);
72
73
  }
73
- const invalid = matches[0].slice(1, -1);
74
+ const invalid = (_e = matches[0]) === null || _e === void 0 ? void 0 : _e.slice(1, -1);
74
75
  return new record_not_unique_1.RecordNotUniqueException(field, {
75
76
  collection,
76
77
  field,
@@ -79,57 +80,61 @@ function uniqueViolation(error) {
79
80
  }
80
81
  }
81
82
  function numericValueOutOfRange(error) {
83
+ var _a, _b;
82
84
  const betweenTicks = /`([^`]+)`/g;
83
85
  const betweenQuotes = /'([^']+)'/g;
84
86
  const tickMatches = error.sql.match(betweenTicks);
85
87
  const quoteMatches = error.sqlMessage.match(betweenQuotes);
86
88
  if (!tickMatches || !quoteMatches)
87
89
  return error;
88
- const collection = tickMatches[0].slice(1, -1);
89
- const field = quoteMatches[0].slice(1, -1);
90
+ const collection = (_a = tickMatches[0]) === null || _a === void 0 ? void 0 : _a.slice(1, -1);
91
+ const field = (_b = quoteMatches[0]) === null || _b === void 0 ? void 0 : _b.slice(1, -1);
90
92
  return new value_out_of_range_1.ValueOutOfRangeException(field, {
91
93
  collection,
92
94
  field,
93
95
  });
94
96
  }
95
97
  function valueLimitViolation(error) {
98
+ var _a, _b;
96
99
  const betweenTicks = /`([^`]+)`/g;
97
100
  const betweenQuotes = /'([^']+)'/g;
98
101
  const tickMatches = error.sql.match(betweenTicks);
99
102
  const quoteMatches = error.sqlMessage.match(betweenQuotes);
100
103
  if (!tickMatches || !quoteMatches)
101
104
  return error;
102
- const collection = tickMatches[0].slice(1, -1);
103
- const field = quoteMatches[0].slice(1, -1);
105
+ const collection = (_a = tickMatches[0]) === null || _a === void 0 ? void 0 : _a.slice(1, -1);
106
+ const field = (_b = quoteMatches[0]) === null || _b === void 0 ? void 0 : _b.slice(1, -1);
104
107
  return new value_too_long_1.ValueTooLongException(field, {
105
108
  collection,
106
109
  field,
107
110
  });
108
111
  }
109
112
  function notNullViolation(error) {
113
+ var _a, _b;
110
114
  const betweenTicks = /`([^`]+)`/g;
111
115
  const betweenQuotes = /'([^']+)'/g;
112
116
  const tickMatches = error.sql.match(betweenTicks);
113
117
  const quoteMatches = error.sqlMessage.match(betweenQuotes);
114
118
  if (!tickMatches || !quoteMatches)
115
119
  return error;
116
- const collection = tickMatches[0].slice(1, -1);
117
- const field = quoteMatches[0].slice(1, -1);
120
+ const collection = (_a = tickMatches[0]) === null || _a === void 0 ? void 0 : _a.slice(1, -1);
121
+ const field = (_b = quoteMatches[0]) === null || _b === void 0 ? void 0 : _b.slice(1, -1);
118
122
  return new not_null_violation_1.NotNullViolationException(field, {
119
123
  collection,
120
124
  field,
121
125
  });
122
126
  }
123
127
  function foreignKeyViolation(error) {
128
+ var _a, _b, _c;
124
129
  const betweenTicks = /`([^`]+)`/g;
125
130
  const betweenParens = /\(([^)]+)\)/g;
126
131
  const tickMatches = error.sqlMessage.match(betweenTicks);
127
132
  const parenMatches = error.sql.match(betweenParens);
128
133
  if (!tickMatches || !parenMatches)
129
134
  return error;
130
- const collection = tickMatches[1].slice(1, -1);
131
- const field = tickMatches[3].slice(1, -1);
132
- const invalid = parenMatches[1].slice(1, -1);
135
+ const collection = (_a = tickMatches[1]) === null || _a === void 0 ? void 0 : _a.slice(1, -1);
136
+ const field = (_b = tickMatches[3]) === null || _b === void 0 ? void 0 : _b.slice(1, -1);
137
+ const invalid = (_c = parenMatches[1]) === null || _c === void 0 ? void 0 : _c.slice(1, -1);
133
138
  return new invalid_foreign_key_1.InvalidForeignKeyException(field, {
134
139
  collection,
135
140
  field,
@@ -137,12 +142,13 @@ function foreignKeyViolation(error) {
137
142
  });
138
143
  }
139
144
  function containsNullValues(error) {
145
+ var _a;
140
146
  const betweenTicks = /`([^`]+)`/g;
141
147
  // Normally, we shouldn't read from the executed SQL. In this case, we're altering a single
142
148
  // column, so we shouldn't have the problem where multiple columns are altered at the same time
143
149
  const tickMatches = error.sql.match(betweenTicks);
144
150
  if (!tickMatches)
145
151
  return error;
146
- const field = tickMatches[1].slice(1, -1);
152
+ const field = (_a = tickMatches[1]) === null || _a === void 0 ? void 0 : _a.slice(1, -1);
147
153
  return new contains_null_values_1.ContainsNullValuesException(field);
148
154
  }
@@ -38,8 +38,6 @@ const get_schema_1 = require("./utils/get-schema");
38
38
  const services = __importStar(require("./services"));
39
39
  const node_cron_1 = require("node-cron");
40
40
  const rollup_1 = require("rollup");
41
- // @TODO Remove this once a new version of @rollup/plugin-virtual has been released
42
- // @ts-expect-error
43
41
  const plugin_virtual_1 = __importDefault(require("@rollup/plugin-virtual"));
44
42
  const plugin_alias_1 = __importDefault(require("@rollup/plugin-alias"));
45
43
  const url_1 = require("./utils/url");
@@ -1,6 +1,8 @@
1
- import { RequestHandler } from 'express';
1
+ /// <reference types="qs" />
2
+ import { NextFunction, Request, Response } from 'express';
2
3
  /**
3
4
  * Verify the passed JWT and assign the user ID and role to `req`
4
5
  */
5
- declare const authenticate: RequestHandler;
6
- export default authenticate;
6
+ export declare const handler: (req: Request, res: Response, next: NextFunction) => Promise<void>;
7
+ declare const _default: import("express").RequestHandler<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
8
+ export default _default;
@@ -1,39 +1,23 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
- }) : (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- o[k2] = m[k];
8
- }));
9
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
- Object.defineProperty(o, "default", { enumerable: true, value: v });
11
- }) : function(o, v) {
12
- o["default"] = v;
13
- });
14
- var __importStar = (this && this.__importStar) || function (mod) {
15
- if (mod && mod.__esModule) return mod;
16
- var result = {};
17
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
- __setModuleDefault(result, mod);
19
- return result;
20
- };
21
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
22
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
23
4
  };
24
5
  Object.defineProperty(exports, "__esModule", { value: true });
25
- const jsonwebtoken_1 = __importStar(require("jsonwebtoken"));
6
+ exports.handler = void 0;
7
+ const lodash_1 = require("lodash");
26
8
  const database_1 = __importDefault(require("../database"));
9
+ const emitter_1 = __importDefault(require("../emitter"));
27
10
  const env_1 = __importDefault(require("../env"));
28
11
  const exceptions_1 = require("../exceptions");
29
12
  const async_handler_1 = __importDefault(require("../utils/async-handler"));
30
13
  const get_ip_from_req_1 = require("../utils/get-ip-from-req");
31
14
  const is_directus_jwt_1 = __importDefault(require("../utils/is-directus-jwt"));
15
+ const jwt_1 = require("../utils/jwt");
32
16
  /**
33
17
  * Verify the passed JWT and assign the user ID and role to `req`
34
18
  */
35
- const authenticate = (0, async_handler_1.default)(async (req, res, next) => {
36
- req.accountability = {
19
+ const handler = async (req, res, next) => {
20
+ const defaultAccountability = {
37
21
  user: null,
38
22
  role: null,
39
23
  admin: false,
@@ -42,23 +26,21 @@ const authenticate = (0, async_handler_1.default)(async (req, res, next) => {
42
26
  userAgent: req.get('user-agent'),
43
27
  };
44
28
  const database = (0, database_1.default)();
29
+ const customAccountability = await emitter_1.default.emitFilter('authenticate', defaultAccountability, {
30
+ req,
31
+ }, {
32
+ database,
33
+ schema: null,
34
+ accountability: null,
35
+ });
36
+ if (customAccountability && (0, lodash_1.isEqual)(customAccountability, defaultAccountability) === false) {
37
+ req.accountability = customAccountability;
38
+ return next();
39
+ }
40
+ req.accountability = defaultAccountability;
45
41
  if (req.token) {
46
42
  if ((0, is_directus_jwt_1.default)(req.token)) {
47
- let payload;
48
- try {
49
- payload = jsonwebtoken_1.default.verify(req.token, env_1.default.SECRET, { issuer: 'directus' });
50
- }
51
- catch (err) {
52
- if (err instanceof jsonwebtoken_1.TokenExpiredError) {
53
- throw new exceptions_1.InvalidCredentialsException('Token expired.');
54
- }
55
- else if (err instanceof jsonwebtoken_1.JsonWebTokenError) {
56
- throw new exceptions_1.InvalidCredentialsException('Token invalid.');
57
- }
58
- else {
59
- throw err;
60
- }
61
- }
43
+ const payload = (0, jwt_1.verifyAccessJWT)(req.token, env_1.default.SECRET);
62
44
  req.accountability.share = payload.share;
63
45
  req.accountability.share_scope = payload.share_scope;
64
46
  req.accountability.user = payload.id;
@@ -87,5 +69,6 @@ const authenticate = (0, async_handler_1.default)(async (req, res, next) => {
87
69
  }
88
70
  }
89
71
  return next();
90
- });
91
- exports.default = authenticate;
72
+ };
73
+ exports.handler = handler;
74
+ exports.default = (0, async_handler_1.default)(exports.handler);
@@ -4,16 +4,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.respond = void 0;
7
- const json2csv_1 = require("json2csv");
8
7
  const ms_1 = __importDefault(require("ms"));
9
- const stream_1 = require("stream");
10
8
  const cache_1 = require("../cache");
11
9
  const env_1 = __importDefault(require("../env"));
12
10
  const async_handler_1 = __importDefault(require("../utils/async-handler"));
13
11
  const get_cache_key_1 = require("../utils/get-cache-key");
14
- const js2xmlparser_1 = require("js2xmlparser");
15
12
  const get_cache_headers_1 = require("../utils/get-cache-headers");
16
13
  const logger_1 = __importDefault(require("../logger"));
14
+ const services_1 = require("../services");
15
+ const get_date_formatted_1 = require("../utils/get-date-formatted");
17
16
  exports.respond = (0, async_handler_1.default)(async (req, res) => {
18
17
  var _a, _b, _c;
19
18
  const { cache } = (0, cache_1.getCache)();
@@ -39,6 +38,7 @@ exports.respond = (0, async_handler_1.default)(async (req, res) => {
39
38
  res.setHeader('Vary', 'Origin, Cache-Control');
40
39
  }
41
40
  if (req.sanitizedQuery.export) {
41
+ const exportService = new services_1.ExportService({ accountability: req.accountability, schema: req.schema });
42
42
  let filename = '';
43
43
  if (req.collection) {
44
44
  filename += req.collection;
@@ -46,32 +46,21 @@ exports.respond = (0, async_handler_1.default)(async (req, res) => {
46
46
  else {
47
47
  filename += 'Export';
48
48
  }
49
- filename += ' ' + getDateFormatted();
49
+ filename += ' ' + (0, get_date_formatted_1.getDateFormatted)();
50
50
  if (req.sanitizedQuery.export === 'json') {
51
51
  res.attachment(`${filename}.json`);
52
52
  res.set('Content-Type', 'application/json');
53
- return res.status(200).send(JSON.stringify(((_a = res.locals.payload) === null || _a === void 0 ? void 0 : _a.data) || null, null, '\t'));
53
+ return res.status(200).send(exportService.transform((_a = res.locals.payload) === null || _a === void 0 ? void 0 : _a.data, 'json'));
54
54
  }
55
55
  if (req.sanitizedQuery.export === 'xml') {
56
56
  res.attachment(`${filename}.xml`);
57
57
  res.set('Content-Type', 'text/xml');
58
- return res.status(200).send((0, js2xmlparser_1.parse)('data', (_b = res.locals.payload) === null || _b === void 0 ? void 0 : _b.data));
58
+ return res.status(200).send(exportService.transform((_b = res.locals.payload) === null || _b === void 0 ? void 0 : _b.data, 'xml'));
59
59
  }
60
60
  if (req.sanitizedQuery.export === 'csv') {
61
61
  res.attachment(`${filename}.csv`);
62
62
  res.set('Content-Type', 'text/csv');
63
- const stream = new stream_1.PassThrough();
64
- if (!((_c = res.locals.payload) === null || _c === void 0 ? void 0 : _c.data) || res.locals.payload.data.length === 0) {
65
- stream.end(Buffer.from(''));
66
- return stream.pipe(res);
67
- }
68
- else {
69
- stream.end(Buffer.from(JSON.stringify(res.locals.payload.data), 'utf-8'));
70
- const json2csv = new json2csv_1.Transform({
71
- transforms: [json2csv_1.transforms.flatten({ separator: '.' })],
72
- });
73
- return stream.pipe(json2csv).pipe(res);
74
- }
63
+ return res.status(200).send(exportService.transform((_c = res.locals.payload) === null || _c === void 0 ? void 0 : _c.data, 'csv'));
75
64
  }
76
65
  }
77
66
  if (Buffer.isBuffer(res.locals.payload)) {
@@ -84,13 +73,3 @@ exports.respond = (0, async_handler_1.default)(async (req, res) => {
84
73
  return res.status(204).end();
85
74
  }
86
75
  });
87
- function getDateFormatted() {
88
- const date = new Date();
89
- let month = String(date.getMonth() + 1);
90
- if (month.length === 1)
91
- month = '0' + month;
92
- let day = String(date.getDate());
93
- if (day.length === 1)
94
- day = '0' + day;
95
- return `${date.getFullYear()}-${month}-${day} at ${date.getHours()}.${date.getMinutes()}.${date.getSeconds()}`;
96
- }
package/dist/server.js CHANGED
@@ -36,8 +36,10 @@ const logger_1 = __importDefault(require("./logger"));
36
36
  const emitter_1 = __importDefault(require("./emitter"));
37
37
  const update_check_1 = __importDefault(require("update-check"));
38
38
  const package_json_1 = __importDefault(require("../package.json"));
39
+ const get_config_from_env_1 = require("./utils/get-config-from-env");
39
40
  async function createServer() {
40
41
  const server = http.createServer(await (0, app_1.default)());
42
+ Object.assign(server, (0, get_config_from_env_1.getConfigFromEnv)('SERVER_'));
41
43
  server.on('request', function (req, res) {
42
44
  const startTime = process.hrtime();
43
45
  const complete = (0, lodash_1.once)(function (finished) {
@@ -124,9 +126,10 @@ async function createServer() {
124
126
  exports.createServer = createServer;
125
127
  async function startServer() {
126
128
  const server = await createServer();
129
+ const host = env_1.default.HOST;
127
130
  const port = env_1.default.PORT;
128
131
  server
129
- .listen(port, () => {
132
+ .listen(port, host, () => {
130
133
  (0, update_check_1.default)(package_json_1.default)
131
134
  .then((update) => {
132
135
  if (update) {
@@ -136,7 +139,7 @@ async function startServer() {
136
139
  .catch(() => {
137
140
  // No need to log/warn here. The update message is only an informative nice-to-have
138
141
  });
139
- logger_1.default.info(`Server started at http://localhost:${port}`);
142
+ logger_1.default.info(`Server started at http://${host}:${port}`);
140
143
  emitter_1.default.emitAction('server.start', { server }, {
141
144
  database: (0, database_1.default)(),
142
145
  schema: null,
@@ -11,6 +11,7 @@ const exceptions_2 = require("@directus/shared/exceptions");
11
11
  const utils_1 = require("@directus/shared/utils");
12
12
  const items_1 = require("./items");
13
13
  const payload_1 = require("./payload");
14
+ const strip_function_1 = require("../utils/strip-function");
14
15
  class AuthorizationService {
15
16
  constructor(options) {
16
17
  this.knex = options.knex || (0, database_1.default)();
@@ -97,7 +98,7 @@ class AuthorizationService {
97
98
  }
98
99
  if (allowedFields.includes('*'))
99
100
  continue;
100
- const fieldKey = childNode.name;
101
+ const fieldKey = (0, strip_function_1.stripFunction)(childNode.name);
101
102
  if (allowedFields.includes(fieldKey) === false) {
102
103
  throw new exceptions_1.ForbiddenException();
103
104
  }