directus 9.23.3 → 9.23.4

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 (113) hide show
  1. package/dist/app.js +12 -12
  2. package/dist/auth/drivers/ldap.js +22 -22
  3. package/dist/auth/drivers/local.js +7 -7
  4. package/dist/auth/drivers/oauth2.js +27 -25
  5. package/dist/auth/drivers/openid.js +32 -30
  6. package/dist/auth/drivers/saml.js +10 -10
  7. package/dist/auth.js +4 -3
  8. package/dist/cache.js +16 -11
  9. package/dist/cli/commands/bootstrap/index.js +5 -4
  10. package/dist/cli/utils/create-db-connection.js +1 -1
  11. package/dist/cli/utils/create-env/index.js +1 -1
  12. package/dist/constants.d.ts +1 -0
  13. package/dist/constants.js +6 -5
  14. package/dist/controllers/activity.js +9 -9
  15. package/dist/controllers/assets.js +19 -18
  16. package/dist/controllers/auth.js +13 -13
  17. package/dist/controllers/collections.js +10 -10
  18. package/dist/controllers/dashboards.js +9 -9
  19. package/dist/controllers/extensions.js +3 -3
  20. package/dist/controllers/fields.js +16 -16
  21. package/dist/controllers/files.js +16 -15
  22. package/dist/controllers/flows.js +11 -11
  23. package/dist/controllers/folders.js +9 -9
  24. package/dist/controllers/graphql.js +6 -6
  25. package/dist/controllers/items.js +17 -17
  26. package/dist/controllers/notifications.js +9 -9
  27. package/dist/controllers/operations.js +9 -9
  28. package/dist/controllers/panels.js +9 -9
  29. package/dist/controllers/permissions.js +9 -9
  30. package/dist/controllers/presets.js +9 -9
  31. package/dist/controllers/relations.js +10 -10
  32. package/dist/controllers/revisions.js +3 -3
  33. package/dist/controllers/roles.js +9 -9
  34. package/dist/controllers/schema.js +5 -5
  35. package/dist/controllers/server.js +7 -7
  36. package/dist/controllers/settings.js +2 -2
  37. package/dist/controllers/shares.js +13 -13
  38. package/dist/controllers/users.js +16 -16
  39. package/dist/controllers/utils.js +5 -5
  40. package/dist/controllers/webhooks.js +9 -9
  41. package/dist/database/helpers/fn/types.d.ts +0 -1
  42. package/dist/database/helpers/fn/types.js +0 -2
  43. package/dist/database/helpers/index.d.ts +3 -3
  44. package/dist/database/index.js +5 -5
  45. package/dist/database/migrations/20210805B-change-image-metadata-structure.js +15 -15
  46. package/dist/database/migrations/run.js +1 -1
  47. package/dist/database/run-ast.js +4 -4
  48. package/dist/database/system-data/collections/index.js +2 -2
  49. package/dist/database/system-data/fields/index.js +3 -3
  50. package/dist/env.js +1 -1
  51. package/dist/extensions.js +10 -10
  52. package/dist/flows.js +33 -31
  53. package/dist/logger.d.ts +1 -0
  54. package/dist/logger.js +32 -32
  55. package/dist/mailer.js +16 -16
  56. package/dist/messenger.js +4 -4
  57. package/dist/middleware/authenticate.js +1 -1
  58. package/dist/middleware/cache.js +11 -11
  59. package/dist/middleware/collection-exists.js +3 -3
  60. package/dist/middleware/cors.js +7 -7
  61. package/dist/middleware/error-handler.js +2 -2
  62. package/dist/middleware/extract-token.js +2 -2
  63. package/dist/middleware/graphql.js +12 -6
  64. package/dist/middleware/rate-limiter-global.js +5 -5
  65. package/dist/middleware/rate-limiter-ip.js +2 -2
  66. package/dist/middleware/respond.js +16 -16
  67. package/dist/middleware/sanitize-query.js +1 -1
  68. package/dist/operations/exec/index.js +2 -2
  69. package/dist/rate-limiter.js +1 -1
  70. package/dist/request/validate-ip.js +2 -2
  71. package/dist/server.js +4 -4
  72. package/dist/services/activity.js +14 -14
  73. package/dist/services/assets.js +6 -6
  74. package/dist/services/authentication.js +9 -9
  75. package/dist/services/collections.js +9 -9
  76. package/dist/services/fields.js +5 -5
  77. package/dist/services/files.js +12 -12
  78. package/dist/services/graphql/index.js +100 -98
  79. package/dist/services/import-export.js +6 -6
  80. package/dist/services/items.js +6 -6
  81. package/dist/services/mail/index.js +5 -5
  82. package/dist/services/meta.js +1 -0
  83. package/dist/services/notifications.js +4 -4
  84. package/dist/services/revisions.js +3 -3
  85. package/dist/services/roles.js +5 -5
  86. package/dist/services/server.js +27 -27
  87. package/dist/services/shares.js +9 -9
  88. package/dist/services/specifications.js +5 -3
  89. package/dist/services/users.d.ts +1 -5
  90. package/dist/services/users.js +24 -27
  91. package/dist/storage/register-locations.js +1 -1
  92. package/dist/utils/apply-query.js +2 -1
  93. package/dist/utils/dynamic-import.js +1 -1
  94. package/dist/utils/generate-hash.js +1 -1
  95. package/dist/utils/get-ast-from-query.js +1 -1
  96. package/dist/utils/get-auth-providers.js +1 -1
  97. package/dist/utils/get-cache-headers.js +3 -3
  98. package/dist/utils/get-collection-from-alias.js +1 -0
  99. package/dist/utils/get-default-value.js +1 -1
  100. package/dist/utils/get-ip-from-req.js +2 -2
  101. package/dist/utils/get-permissions.js +11 -11
  102. package/dist/utils/get-schema.js +2 -2
  103. package/dist/utils/is-url-allowed.js +5 -2
  104. package/dist/utils/sanitize-query.js +26 -26
  105. package/dist/utils/should-skip-cache.js +2 -2
  106. package/dist/utils/track.js +16 -16
  107. package/dist/utils/validate-query.js +1 -1
  108. package/dist/utils/validate-storage.js +8 -8
  109. package/dist/webhooks.js +2 -2
  110. package/package.json +13 -13
  111. package/dist/utils/redact-header-cookies.d.ts +0 -1
  112. package/dist/utils/redact-header-cookies.js +0 -11
  113. /package/dist/{utils/redact-header-cookies.test.d.ts → logger.test.d.ts} +0 -0
@@ -205,7 +205,7 @@ class ItemsService {
205
205
  }
206
206
  }
207
207
  }
208
- if (this.cache && env_1.default.CACHE_AUTO_PURGE && opts?.autoPurgeCache !== false) {
208
+ if (this.cache && env_1.default['CACHE_AUTO_PURGE'] && opts?.autoPurgeCache !== false) {
209
209
  await this.cache.clear();
210
210
  }
211
211
  return primaryKey;
@@ -242,7 +242,7 @@ class ItemsService {
242
242
  }
243
243
  }
244
244
  }
245
- if (this.cache && env_1.default.CACHE_AUTO_PURGE && opts?.autoPurgeCache !== false) {
245
+ if (this.cache && env_1.default['CACHE_AUTO_PURGE'] && opts?.autoPurgeCache !== false) {
246
246
  await this.cache.clear();
247
247
  }
248
248
  return primaryKeys;
@@ -381,7 +381,7 @@ class ItemsService {
381
381
  });
382
382
  }
383
383
  finally {
384
- if (this.cache && env_1.default.CACHE_AUTO_PURGE && opts?.autoPurgeCache !== false) {
384
+ if (this.cache && env_1.default['CACHE_AUTO_PURGE'] && opts?.autoPurgeCache !== false) {
385
385
  await this.cache.clear();
386
386
  }
387
387
  }
@@ -506,7 +506,7 @@ class ItemsService {
506
506
  }
507
507
  }
508
508
  });
509
- if (this.cache && env_1.default.CACHE_AUTO_PURGE && opts?.autoPurgeCache !== false) {
509
+ if (this.cache && env_1.default['CACHE_AUTO_PURGE'] && opts?.autoPurgeCache !== false) {
510
510
  await this.cache.clear();
511
511
  }
512
512
  if (opts?.emitEvents !== false) {
@@ -581,7 +581,7 @@ class ItemsService {
581
581
  }
582
582
  return primaryKeys;
583
583
  });
584
- if (this.cache && env_1.default.CACHE_AUTO_PURGE && opts?.autoPurgeCache !== false) {
584
+ if (this.cache && env_1.default['CACHE_AUTO_PURGE'] && opts?.autoPurgeCache !== false) {
585
585
  await this.cache.clear();
586
586
  }
587
587
  return primaryKeys;
@@ -648,7 +648,7 @@ class ItemsService {
648
648
  })));
649
649
  }
650
650
  });
651
- if (this.cache && env_1.default.CACHE_AUTO_PURGE && opts?.autoPurgeCache !== false) {
651
+ if (this.cache && env_1.default['CACHE_AUTO_PURGE'] && opts?.autoPurgeCache !== false) {
652
652
  await this.cache.clear();
653
653
  }
654
654
  if (opts?.emitEvents !== false) {
@@ -14,7 +14,7 @@ const logger_1 = __importDefault(require("../../logger"));
14
14
  const mailer_1 = __importDefault(require("../../mailer"));
15
15
  const url_1 = require("../../utils/url");
16
16
  const liquidEngine = new liquidjs_1.Liquid({
17
- root: [path_1.default.resolve(env_1.default.EXTENSIONS_PATH, 'templates'), path_1.default.resolve(__dirname, 'templates')],
17
+ root: [path_1.default.resolve(env_1.default['EXTENSIONS_PATH'], 'templates'), path_1.default.resolve(__dirname, 'templates')],
18
18
  extname: '.liquid',
19
19
  });
20
20
  class MailService {
@@ -27,7 +27,7 @@ class MailService {
27
27
  this.accountability = opts.accountability || null;
28
28
  this.knex = opts?.knex || (0, database_1.default)();
29
29
  this.mailer = (0, mailer_1.default)();
30
- if (env_1.default.EMAIL_VERIFY_SETUP) {
30
+ if (env_1.default['EMAIL_VERIFY_SETUP']) {
31
31
  this.mailer.verify((error) => {
32
32
  if (error) {
33
33
  logger_1.default.warn(`Email connection failed:`);
@@ -40,7 +40,7 @@ class MailService {
40
40
  const { template, ...emailOptions } = options;
41
41
  let { html } = options;
42
42
  const defaultTemplateData = await this.getDefaultTemplateData();
43
- const from = `${defaultTemplateData.projectName} <${options.from || env_1.default.EMAIL_FROM}>`;
43
+ const from = `${defaultTemplateData.projectName} <${options.from || env_1.default['EMAIL_FROM']}>`;
44
44
  if (template) {
45
45
  let templateData = template.data;
46
46
  templateData = {
@@ -60,7 +60,7 @@ class MailService {
60
60
  return info;
61
61
  }
62
62
  async renderTemplate(template, variables) {
63
- const customTemplatePath = path_1.default.resolve(env_1.default.EXTENSIONS_PATH, 'templates', template + '.liquid');
63
+ const customTemplatePath = path_1.default.resolve(env_1.default['EXTENSIONS_PATH'], 'templates', template + '.liquid');
64
64
  const systemTemplatePath = path_1.default.join(__dirname, 'templates', template + '.liquid');
65
65
  const templatePath = (await fs_extra_1.default.pathExists(customTemplatePath)) ? customTemplatePath : systemTemplatePath;
66
66
  if ((await fs_extra_1.default.pathExists(templatePath)) === false) {
@@ -82,7 +82,7 @@ class MailService {
82
82
  projectUrl: projectInfo?.project_url || '',
83
83
  };
84
84
  function getProjectLogoURL(logoID) {
85
- const projectLogoUrl = new url_1.Url(env_1.default.PUBLIC_URL);
85
+ const projectLogoUrl = new url_1.Url(env_1.default['PUBLIC_URL']);
86
86
  if (logoID) {
87
87
  projectLogoUrl.addPath('assets', logoID);
88
88
  }
@@ -25,6 +25,7 @@ class MetaService {
25
25
  return this.totalCount(collection);
26
26
  if (metaVal === 'filter_count')
27
27
  return this.filterCount(collection, query);
28
+ return undefined;
28
29
  }));
29
30
  return results.reduce((metaObject, value, index) => {
30
31
  return {
@@ -36,16 +36,16 @@ class NotificationsService extends items_1.ItemsService {
36
36
  const user = await this.usersService.readOne(data.recipient, {
37
37
  fields: ['id', 'email', 'email_notifications', 'role.app_access'],
38
38
  });
39
- const manageUserAccountUrl = new url_1.Url(env_1.default.PUBLIC_URL).addPath('admin', 'users', user.id).toString();
39
+ const manageUserAccountUrl = new url_1.Url(env_1.default['PUBLIC_URL']).addPath('admin', 'users', user['id']).toString();
40
40
  const html = data.message ? (0, md_1.md)(data.message) : '';
41
- if (user.email && user.email_notifications === true) {
41
+ if (user['email'] && user['email_notifications'] === true) {
42
42
  try {
43
43
  await this.mailService.send({
44
44
  template: {
45
45
  name: 'base',
46
- data: user.role?.app_access ? { url: manageUserAccountUrl, html } : { html },
46
+ data: user['role']?.app_access ? { url: manageUserAccountUrl, html } : { html },
47
47
  },
48
- to: user.email,
48
+ to: user['email'],
49
49
  subject: data.subject,
50
50
  });
51
51
  }
@@ -11,14 +11,14 @@ class RevisionsService extends index_1.ItemsService {
11
11
  const revision = await super.readOne(pk);
12
12
  if (!revision)
13
13
  throw new exceptions_1.ForbiddenException();
14
- if (!revision.data)
14
+ if (!revision['data'])
15
15
  throw new exceptions_1.InvalidPayloadException(`Revision doesn't contain data to revert to`);
16
- const service = new index_1.ItemsService(revision.collection, {
16
+ const service = new index_1.ItemsService(revision['collection'], {
17
17
  accountability: this.accountability,
18
18
  knex: this.knex,
19
19
  schema: this.schema,
20
20
  });
21
- await service.updateOne(revision.item, revision.data);
21
+ await service.updateOne(revision['item'], revision['data']);
22
22
  }
23
23
  }
24
24
  exports.RevisionsService = RevisionsService;
@@ -29,10 +29,10 @@ class RolesService extends items_1.ItemsService {
29
29
  // The users that will now be in this new non-admin role
30
30
  let userKeys = [];
31
31
  if (Array.isArray(users)) {
32
- userKeys = users.map((user) => (typeof user === 'string' ? user : user.id)).filter((id) => id);
32
+ userKeys = users.map((user) => (typeof user === 'string' ? user : user['id'])).filter((id) => id);
33
33
  }
34
34
  else {
35
- userKeys = users.update.map((user) => user.id).filter((id) => id);
35
+ userKeys = users.update.map((user) => user['id']).filter((id) => id);
36
36
  }
37
37
  const usersThatWereInRoleBefore = (await this.knex.select('id').from('directus_users').where('role', '=', key)).map((user) => user.id);
38
38
  const usersThatAreRemoved = usersThatWereInRoleBefore.filter((id) => Array.isArray(users) ? userKeys.includes(id) === false : users.delete.includes(id) === true);
@@ -58,7 +58,7 @@ class RolesService extends items_1.ItemsService {
58
58
  async updateOne(key, data, opts) {
59
59
  try {
60
60
  if ('users' in data) {
61
- await this.checkForOtherAdminUsers(key, data.users);
61
+ await this.checkForOtherAdminUsers(key, data['users']);
62
62
  }
63
63
  }
64
64
  catch (err) {
@@ -69,7 +69,7 @@ class RolesService extends items_1.ItemsService {
69
69
  async updateBatch(data, opts) {
70
70
  const primaryKeyField = this.schema.collections[this.collection].primary;
71
71
  const keys = data.map((item) => item[primaryKeyField]);
72
- const setsToNoAdmin = data.some((item) => item.admin_access === false);
72
+ const setsToNoAdmin = data.some((item) => item['admin_access'] === false);
73
73
  try {
74
74
  if (setsToNoAdmin) {
75
75
  await this.checkForOtherAdminRoles(keys);
@@ -82,7 +82,7 @@ class RolesService extends items_1.ItemsService {
82
82
  }
83
83
  async updateMany(keys, data, opts) {
84
84
  try {
85
- if ('admin_access' in data && data.admin_access === false) {
85
+ if ('admin_access' in data && data['admin_access'] === false) {
86
86
  await this.checkForOtherAdminRoles(keys);
87
87
  }
88
88
  }
@@ -70,40 +70,40 @@ class ServerService {
70
70
  'custom_css',
71
71
  ],
72
72
  });
73
- info.project = projectInfo;
73
+ info['project'] = projectInfo;
74
74
  if (this.accountability?.user) {
75
- if (env_1.default.RATE_LIMITER_ENABLED) {
76
- info.rateLimit = {
77
- points: env_1.default.RATE_LIMITER_POINTS,
78
- duration: env_1.default.RATE_LIMITER_DURATION,
75
+ if (env_1.default['RATE_LIMITER_ENABLED']) {
76
+ info['rateLimit'] = {
77
+ points: env_1.default['RATE_LIMITER_POINTS'],
78
+ duration: env_1.default['RATE_LIMITER_DURATION'],
79
79
  };
80
80
  }
81
81
  else {
82
- info.rateLimit = false;
82
+ info['rateLimit'] = false;
83
83
  }
84
- if (env_1.default.RATE_LIMITER_GLOBAL_ENABLED) {
85
- info.rateLimitGlobal = {
86
- points: env_1.default.RATE_LIMITER_GLOBAL_POINTS,
87
- duration: env_1.default.RATE_LIMITER_GLOBAL_DURATION,
84
+ if (env_1.default['RATE_LIMITER_GLOBAL_ENABLED']) {
85
+ info['rateLimitGlobal'] = {
86
+ points: env_1.default['RATE_LIMITER_GLOBAL_POINTS'],
87
+ duration: env_1.default['RATE_LIMITER_GLOBAL_DURATION'],
88
88
  };
89
89
  }
90
90
  else {
91
- info.rateLimitGlobal = false;
91
+ info['rateLimitGlobal'] = false;
92
92
  }
93
- info.flows = {
94
- execAllowedModules: env_1.default.FLOWS_EXEC_ALLOWED_MODULES ? (0, utils_1.toArray)(env_1.default.FLOWS_EXEC_ALLOWED_MODULES) : [],
93
+ info['flows'] = {
94
+ execAllowedModules: env_1.default['FLOWS_EXEC_ALLOWED_MODULES'] ? (0, utils_1.toArray)(env_1.default['FLOWS_EXEC_ALLOWED_MODULES']) : [],
95
95
  };
96
96
  }
97
97
  if (this.accountability?.admin === true) {
98
98
  const { osType, osVersion } = (0, get_os_info_1.getOSInfo)();
99
- info.directus = {
99
+ info['directus'] = {
100
100
  version: package_json_1.version,
101
101
  };
102
- info.node = {
102
+ info['node'] = {
103
103
  version: process.versions.node,
104
104
  uptime: Math.round(process.uptime()),
105
105
  };
106
- info.os = {
106
+ info['os'] = {
107
107
  type: osType,
108
108
  version: osVersion,
109
109
  uptime: Math.round(os_1.default.uptime()),
@@ -118,7 +118,7 @@ class ServerService {
118
118
  const data = {
119
119
  status: 'ok',
120
120
  releaseId: package_json_1.version,
121
- serviceId: env_1.default.KEY,
121
+ serviceId: env_1.default['KEY'],
122
122
  checks: (0, lodash_1.merge)(...(await Promise.all([
123
123
  testDatabase(),
124
124
  testCache(),
@@ -153,7 +153,7 @@ class ServerService {
153
153
  }
154
154
  async function testDatabase() {
155
155
  const database = (0, database_1.default)();
156
- const client = env_1.default.DB_CLIENT;
156
+ const client = env_1.default['DB_CLIENT'];
157
157
  const checks = {};
158
158
  // Response time
159
159
  // ----------------------------------------------------------------------------------------
@@ -163,7 +163,7 @@ class ServerService {
163
163
  componentType: 'datastore',
164
164
  observedUnit: 'ms',
165
165
  observedValue: 0,
166
- threshold: env_1.default.DB_HEALTHCHECK_THRESHOLD ? +env_1.default.DB_HEALTHCHECK_THRESHOLD : 150,
166
+ threshold: env_1.default['DB_HEALTHCHECK_THRESHOLD'] ? +env_1.default['DB_HEALTHCHECK_THRESHOLD'] : 150,
167
167
  },
168
168
  ];
169
169
  const startTime = perf_hooks_1.performance.now();
@@ -197,7 +197,7 @@ class ServerService {
197
197
  return checks;
198
198
  }
199
199
  async function testCache() {
200
- if (env_1.default.CACHE_ENABLED !== true) {
200
+ if (env_1.default['CACHE_ENABLED'] !== true) {
201
201
  return {};
202
202
  }
203
203
  const { cache } = (0, cache_1.getCache)();
@@ -208,7 +208,7 @@ class ServerService {
208
208
  componentType: 'cache',
209
209
  observedValue: 0,
210
210
  observedUnit: 'ms',
211
- threshold: env_1.default.CACHE_HEALTHCHECK_THRESHOLD ? +env_1.default.CACHE_HEALTHCHECK_THRESHOLD : 150,
211
+ threshold: env_1.default['CACHE_HEALTHCHECK_THRESHOLD'] ? +env_1.default['CACHE_HEALTHCHECK_THRESHOLD'] : 150,
212
212
  },
213
213
  ],
214
214
  };
@@ -232,7 +232,7 @@ class ServerService {
232
232
  return checks;
233
233
  }
234
234
  async function testRateLimiter() {
235
- if (env_1.default.RATE_LIMITER_ENABLED !== true) {
235
+ if (env_1.default['RATE_LIMITER_ENABLED'] !== true) {
236
236
  return {};
237
237
  }
238
238
  const checks = {
@@ -242,7 +242,7 @@ class ServerService {
242
242
  componentType: 'ratelimiter',
243
243
  observedValue: 0,
244
244
  observedUnit: 'ms',
245
- threshold: env_1.default.RATE_LIMITER_HEALTHCHECK_THRESHOLD ? +env_1.default.RATE_LIMITER_HEALTHCHECK_THRESHOLD : 150,
245
+ threshold: env_1.default['RATE_LIMITER_HEALTHCHECK_THRESHOLD'] ? +env_1.default['RATE_LIMITER_HEALTHCHECK_THRESHOLD'] : 150,
246
246
  },
247
247
  ],
248
248
  };
@@ -266,7 +266,7 @@ class ServerService {
266
266
  return checks;
267
267
  }
268
268
  async function testRateLimiterGlobal() {
269
- if (env_1.default.RATE_LIMITER_GLOBAL_ENABLED !== true) {
269
+ if (env_1.default['RATE_LIMITER_GLOBAL_ENABLED'] !== true) {
270
270
  return {};
271
271
  }
272
272
  const checks = {
@@ -276,8 +276,8 @@ class ServerService {
276
276
  componentType: 'ratelimiter',
277
277
  observedValue: 0,
278
278
  observedUnit: 'ms',
279
- threshold: env_1.default.RATE_LIMITER_GLOBAL_HEALTHCHECK_THRESHOLD
280
- ? +env_1.default.RATE_LIMITER_GLOBAL_HEALTHCHECK_THRESHOLD
279
+ threshold: env_1.default['RATE_LIMITER_GLOBAL_HEALTHCHECK_THRESHOLD']
280
+ ? +env_1.default['RATE_LIMITER_GLOBAL_HEALTHCHECK_THRESHOLD']
281
281
  : 150,
282
282
  },
283
283
  ],
@@ -305,7 +305,7 @@ class ServerService {
305
305
  async function testStorage() {
306
306
  const storage = await (0, storage_1.getStorage)();
307
307
  const checks = {};
308
- for (const location of (0, utils_1.toArray)(env_1.default.STORAGE_LOCATIONS)) {
308
+ for (const location of (0, utils_1.toArray)(env_1.default['STORAGE_LOCATIONS'])) {
309
309
  const disk = storage.location(location);
310
310
  const envThresholdKey = `STORAGE_${location}_HEALTHCHECK_THRESHOLD`.toUpperCase();
311
311
  checks[`storage:${location}:responseTime`] = [
@@ -27,7 +27,7 @@ class SharesService extends items_1.ItemsService {
27
27
  });
28
28
  }
29
29
  async createOne(data, opts) {
30
- await this.authorizationService.checkAccess('share', data.collection, data.item);
30
+ await this.authorizationService.checkAccess('share', data['collection'], data['item']);
31
31
  return super.createOne(data, opts);
32
32
  }
33
33
  async login(payload) {
@@ -45,7 +45,7 @@ class SharesService extends items_1.ItemsService {
45
45
  share_password: 'password',
46
46
  })
47
47
  .from('directus_shares')
48
- .where('id', payload.share)
48
+ .where('id', payload['share'])
49
49
  .andWhere((subQuery) => {
50
50
  subQuery.whereNull('date_end').orWhere('date_end', '>=', new Date());
51
51
  })
@@ -59,7 +59,7 @@ class SharesService extends items_1.ItemsService {
59
59
  if (!record) {
60
60
  throw new exceptions_1.InvalidCredentialsException();
61
61
  }
62
- if (record.share_password && !(await argon2_1.default.verify(record.share_password, payload.password))) {
62
+ if (record.share_password && !(await argon2_1.default.verify(record.share_password, payload['password']))) {
63
63
  throw new exceptions_1.InvalidCredentialsException();
64
64
  }
65
65
  await this.knex('directus_shares')
@@ -75,12 +75,12 @@ class SharesService extends items_1.ItemsService {
75
75
  collection: record.share_collection,
76
76
  },
77
77
  };
78
- const accessToken = jsonwebtoken_1.default.sign(tokenPayload, env_1.default.SECRET, {
79
- expiresIn: env_1.default.ACCESS_TOKEN_TTL,
78
+ const accessToken = jsonwebtoken_1.default.sign(tokenPayload, env_1.default['SECRET'], {
79
+ expiresIn: env_1.default['ACCESS_TOKEN_TTL'],
80
80
  issuer: 'directus',
81
81
  });
82
82
  const refreshToken = nanoid(64);
83
- const refreshTokenExpiration = new Date(Date.now() + (0, get_milliseconds_1.getMilliseconds)(env_1.default.REFRESH_TOKEN_TTL, 0));
83
+ const refreshTokenExpiration = new Date(Date.now() + (0, get_milliseconds_1.getMilliseconds)(env_1.default['REFRESH_TOKEN_TTL'], 0));
84
84
  await this.knex('directus_sessions').insert({
85
85
  token: refreshToken,
86
86
  expires: refreshTokenExpiration,
@@ -93,7 +93,7 @@ class SharesService extends items_1.ItemsService {
93
93
  return {
94
94
  accessToken,
95
95
  refreshToken,
96
- expires: (0, get_milliseconds_1.getMilliseconds)(env_1.default.ACCESS_TOKEN_TTL),
96
+ expires: (0, get_milliseconds_1.getMilliseconds)(env_1.default['ACCESS_TOKEN_TTL']),
97
97
  };
98
98
  }
99
99
  /**
@@ -115,9 +115,9 @@ class SharesService extends items_1.ItemsService {
115
115
  const message = `
116
116
  Hello!
117
117
 
118
- ${(0, user_name_1.userName)(userInfo)} has invited you to view an item in ${share.collection}.
118
+ ${(0, user_name_1.userName)(userInfo)} has invited you to view an item in ${share['collection']}.
119
119
 
120
- [Open](${new url_1.Url(env_1.default.PUBLIC_URL).addPath('admin', 'shared', payload.share).toString()})
120
+ [Open](${new url_1.Url(env_1.default['PUBLIC_URL']).addPath('admin', 'shared', payload.share).toString()})
121
121
  `;
122
122
  for (const email of payload.emails) {
123
123
  await mailService.send({
@@ -74,7 +74,7 @@ class OASSpecsService {
74
74
  },
75
75
  servers: [
76
76
  {
77
- url: env_1.default.PUBLIC_URL,
77
+ url: env_1.default['PUBLIC_URL'],
78
78
  description: 'Your current Directus instance.',
79
79
  },
80
80
  ],
@@ -168,7 +168,7 @@ class OASSpecsService {
168
168
  paths[`/items/${collection}`][method] = (0, lodash_1.mergeWith)((0, lodash_1.cloneDeep)(listBase[method]), {
169
169
  description: listBase[method].description.replace('item', collection + ' item'),
170
170
  tags: [tag.name],
171
- parameters: 'parameters' in listBase ? this.filterCollectionFromParams(listBase['parameters']) : [],
171
+ parameters: 'parameters' in listBase ? this.filterCollectionFromParams(listBase.parameters) : [],
172
172
  operationId: `${this.getActionForMethod(method)}${tag.name}`,
173
173
  requestBody: ['get', 'delete'].includes(method)
174
174
  ? undefined
@@ -213,6 +213,7 @@ class OASSpecsService {
213
213
  }, (obj, src) => {
214
214
  if (Array.isArray(obj))
215
215
  return obj.concat(src);
216
+ return undefined;
216
217
  });
217
218
  }
218
219
  if (detailBase[method]) {
@@ -220,7 +221,7 @@ class OASSpecsService {
220
221
  description: detailBase[method].description.replace('item', collection + ' item'),
221
222
  tags: [tag.name],
222
223
  operationId: `${this.getActionForMethod(method)}Single${tag.name}`,
223
- parameters: 'parameters' in detailBase ? this.filterCollectionFromParams(detailBase['parameters']) : [],
224
+ parameters: 'parameters' in detailBase ? this.filterCollectionFromParams(detailBase.parameters) : [],
224
225
  requestBody: ['get', 'delete'].includes(method)
225
226
  ? undefined
226
227
  : {
@@ -252,6 +253,7 @@ class OASSpecsService {
252
253
  }, (obj, src) => {
253
254
  if (Array.isArray(obj))
254
255
  return obj.concat(src);
256
+ return undefined;
255
257
  });
256
258
  }
257
259
  }
@@ -1,11 +1,7 @@
1
- import type { Accountability, Query, SchemaOverview } from '@directus/shared/types';
2
- import type { Knex } from 'knex';
1
+ import type { Query } from '@directus/shared/types';
3
2
  import type { AbstractServiceOptions, Item, MutationOptions, PrimaryKey } from '../types';
4
3
  import { ItemsService } from './items';
5
4
  export declare class UsersService extends ItemsService {
6
- knex: Knex;
7
- accountability: Accountability | null;
8
- schema: SchemaOverview;
9
5
  constructor(options: AbstractServiceOptions);
10
6
  /**
11
7
  * User email has to be unique case-insensitive. This is an additional check to make sure that
@@ -20,9 +20,6 @@ const items_1 = require("./items");
20
20
  const mail_1 = require("./mail");
21
21
  const settings_1 = require("./settings");
22
22
  class UsersService extends items_1.ItemsService {
23
- knex;
24
- accountability;
25
- schema;
26
23
  constructor(options) {
27
24
  super('directus_users', options);
28
25
  this.knex = options.knex || (0, database_1.default)();
@@ -131,8 +128,8 @@ class UsersService extends items_1.ItemsService {
131
128
  * Create multiple new users
132
129
  */
133
130
  async createMany(data, opts) {
134
- const emails = data.map((payload) => payload.email).filter((email) => email);
135
- const passwords = data.map((payload) => payload.password).filter((password) => password);
131
+ const emails = data['map']((payload) => payload['email']).filter((email) => email);
132
+ const passwords = data['map']((payload) => payload['password']).filter((password) => password);
136
133
  try {
137
134
  if (emails.length) {
138
135
  await this.checkUniqueEmails(emails);
@@ -182,44 +179,44 @@ class UsersService extends items_1.ItemsService {
182
179
  */
183
180
  async updateMany(keys, data, opts) {
184
181
  try {
185
- if (data.role) {
186
- // data.role will be an object with id with GraphQL mutations
187
- const roleId = data.role?.id ?? data.role;
182
+ if (data['role']) {
183
+ // data['role'] will be an object with id with GraphQL mutations
184
+ const roleId = data['role']?.id ?? data['role'];
188
185
  const newRole = await this.knex.select('admin_access').from('directus_roles').where('id', roleId).first();
189
186
  if (!newRole?.admin_access) {
190
187
  await this.checkRemainingAdminExistence(keys);
191
188
  }
192
189
  }
193
- if (data.status !== undefined && data.status !== 'active') {
190
+ if (data['status'] !== undefined && data['status'] !== 'active') {
194
191
  await this.checkRemainingActiveAdmin(keys);
195
192
  }
196
- if (data.email) {
193
+ if (data['email']) {
197
194
  if (keys.length > 1) {
198
195
  throw new record_not_unique_1.RecordNotUniqueException('email', {
199
196
  collection: 'directus_users',
200
197
  field: 'email',
201
- invalid: data.email,
198
+ invalid: data['email'],
202
199
  });
203
200
  }
204
- await this.checkUniqueEmails([data.email], keys[0]);
201
+ await this.checkUniqueEmails([data['email']], keys[0]);
205
202
  }
206
- if (data.password) {
207
- await this.checkPasswordPolicy([data.password]);
203
+ if (data['password']) {
204
+ await this.checkPasswordPolicy([data['password']]);
208
205
  }
209
- if (data.tfa_secret !== undefined) {
206
+ if (data['tfa_secret'] !== undefined) {
210
207
  throw new exceptions_2.InvalidPayloadException(`You can't change the "tfa_secret" value manually.`);
211
208
  }
212
- if (data.provider !== undefined) {
209
+ if (data['provider'] !== undefined) {
213
210
  if (this.accountability && this.accountability.admin !== true) {
214
211
  throw new exceptions_2.InvalidPayloadException(`You can't change the "provider" value manually.`);
215
212
  }
216
- data.auth_data = null;
213
+ data['auth_data'] = null;
217
214
  }
218
- if (data.external_identifier !== undefined) {
215
+ if (data['external_identifier'] !== undefined) {
219
216
  if (this.accountability && this.accountability.admin !== true) {
220
217
  throw new exceptions_2.InvalidPayloadException(`You can't change the "external_identifier" value manually.`);
221
218
  }
222
- data.auth_data = null;
219
+ data['auth_data'] = null;
223
220
  }
224
221
  }
225
222
  catch (err) {
@@ -266,7 +263,7 @@ class UsersService extends items_1.ItemsService {
266
263
  async inviteUser(email, role, url, subject) {
267
264
  const opts = {};
268
265
  try {
269
- if (url && (0, is_url_allowed_1.default)(url, env_1.default.USER_INVITE_URL_ALLOW_LIST) === false) {
266
+ if (url && (0, is_url_allowed_1.default)(url, env_1.default['USER_INVITE_URL_ALLOW_LIST']) === false) {
270
267
  throw new exceptions_2.InvalidPayloadException(`Url "${url}" can't be used to invite users.`);
271
268
  }
272
269
  }
@@ -280,9 +277,9 @@ class UsersService extends items_1.ItemsService {
280
277
  });
281
278
  for (const email of emails) {
282
279
  const payload = { email, scope: 'invite' };
283
- const token = jsonwebtoken_1.default.sign(payload, env_1.default.SECRET, { expiresIn: '7d', issuer: 'directus' });
280
+ const token = jsonwebtoken_1.default.sign(payload, env_1.default['SECRET'], { expiresIn: '7d', issuer: 'directus' });
284
281
  const subjectLine = subject ?? "You've been invited";
285
- const inviteURL = url ? new url_1.Url(url) : new url_1.Url(env_1.default.PUBLIC_URL).addPath('admin', 'accept-invite');
282
+ const inviteURL = url ? new url_1.Url(url) : new url_1.Url(env_1.default['PUBLIC_URL']).addPath('admin', 'accept-invite');
286
283
  inviteURL.setQuery('token', token);
287
284
  // Create user first to verify uniqueness
288
285
  await this.createOne({ email, role, status: 'invited' }, opts);
@@ -300,7 +297,7 @@ class UsersService extends items_1.ItemsService {
300
297
  }
301
298
  }
302
299
  async acceptInvite(token, password) {
303
- const { email, scope } = jsonwebtoken_1.default.verify(token, env_1.default.SECRET, { issuer: 'directus' });
300
+ const { email, scope } = jsonwebtoken_1.default.verify(token, env_1.default['SECRET'], { issuer: 'directus' });
304
301
  if (scope !== 'invite')
305
302
  throw new exceptions_2.ForbiddenException();
306
303
  const user = await this.knex.select('id', 'status').from('directus_users').where({ email }).first();
@@ -326,7 +323,7 @@ class UsersService extends items_1.ItemsService {
326
323
  await (0, stall_1.stall)(STALL_TIME, timeStart);
327
324
  throw new exceptions_2.ForbiddenException();
328
325
  }
329
- if (url && (0, is_url_allowed_1.default)(url, env_1.default.PASSWORD_RESET_URL_ALLOW_LIST) === false) {
326
+ if (url && (0, is_url_allowed_1.default)(url, env_1.default['PASSWORD_RESET_URL_ALLOW_LIST']) === false) {
330
327
  throw new exceptions_2.InvalidPayloadException(`Url "${url}" can't be used to reset passwords.`);
331
328
  }
332
329
  const mailService = new mail_1.MailService({
@@ -335,10 +332,10 @@ class UsersService extends items_1.ItemsService {
335
332
  accountability: this.accountability,
336
333
  });
337
334
  const payload = { email, scope: 'password-reset', hash: (0, utils_1.getSimpleHash)('' + user.password) };
338
- const token = jsonwebtoken_1.default.sign(payload, env_1.default.SECRET, { expiresIn: '1d', issuer: 'directus' });
335
+ const token = jsonwebtoken_1.default.sign(payload, env_1.default['SECRET'], { expiresIn: '1d', issuer: 'directus' });
339
336
  const acceptURL = url
340
337
  ? new url_1.Url(url).setQuery('token', token).toString()
341
- : new url_1.Url(env_1.default.PUBLIC_URL).addPath('admin', 'reset-password').setQuery('token', token);
338
+ : new url_1.Url(env_1.default['PUBLIC_URL']).addPath('admin', 'reset-password').setQuery('token', token);
342
339
  const subjectLine = subject ? subject : 'Password Reset Request';
343
340
  await mailService.send({
344
341
  to: email,
@@ -354,7 +351,7 @@ class UsersService extends items_1.ItemsService {
354
351
  await (0, stall_1.stall)(STALL_TIME, timeStart);
355
352
  }
356
353
  async resetPassword(token, password) {
357
- const { email, scope, hash } = jsonwebtoken_1.default.verify(token, env_1.default.SECRET, { issuer: 'directus' });
354
+ const { email, scope, hash } = jsonwebtoken_1.default.verify(token, env_1.default['SECRET'], { issuer: 'directus' });
358
355
  if (scope !== 'password-reset' || !hash)
359
356
  throw new exceptions_2.ForbiddenException();
360
357
  const opts = {};
@@ -6,7 +6,7 @@ const env_1 = require("../env");
6
6
  const get_config_from_env_1 = require("../utils/get-config-from-env");
7
7
  const registerLocations = async (storage) => {
8
8
  const env = (0, env_1.getEnv)();
9
- const locations = (0, utils_1.toArray)(env.STORAGE_LOCATIONS);
9
+ const locations = (0, utils_1.toArray)(env['STORAGE_LOCATIONS']);
10
10
  locations.forEach((location) => {
11
11
  location = location.trim();
12
12
  const driverConfig = (0, get_config_from_env_1.getConfigFromEnv)(`STORAGE_${location.toUpperCase()}_`);
@@ -171,6 +171,7 @@ function applySort(knex, schema, rootQuery, rootSort, collection, aliasMap, retu
171
171
  // Clears the order if any, eg: from MSSQL offset
172
172
  rootQuery.clear('order');
173
173
  rootQuery.orderBy(sortRecords);
174
+ return undefined;
174
175
  }
175
176
  exports.applySort = applySort;
176
177
  function applyLimit(knex, rootQuery, limit) {
@@ -337,7 +338,7 @@ function applyFilter(knex, schema, rootQuery, rootFilter, collection, aliasMap)
337
338
  }
338
339
  if (operator === '_nempty' || (operator === '_empty' && compareValue === false)) {
339
340
  dbQuery[logical].andWhere((query) => {
340
- query.whereNotNull(key).orWhere(key, '!=', '');
341
+ query.whereNotNull(key).andWhere(key, '!=', '');
341
342
  });
342
343
  }
343
344
  // The following fields however, require a value to be run. If no value is passed, we
@@ -2,6 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.dynamicImport = void 0;
4
4
  const dynamicImport = async (mod) => {
5
- return process.env.VITEST ? await import(mod) : require(mod);
5
+ return process.env['VITEST'] ? await import(mod) : require(mod);
6
6
  };
7
7
  exports.dynamicImport = dynamicImport;
@@ -10,7 +10,7 @@ function generateHash(stringToHash) {
10
10
  const argon2HashConfigOptions = (0, get_config_from_env_1.getConfigFromEnv)('HASH_', 'HASH_RAW'); // Disallow the HASH_RAW option, see https://github.com/directus/directus/discussions/7670#discussioncomment-1255805
11
11
  // associatedData, if specified, must be passed as a Buffer to argon2.hash, see https://github.com/ranisalt/node-argon2/wiki/Options#associateddata
12
12
  'associatedData' in argon2HashConfigOptions &&
13
- (argon2HashConfigOptions.associatedData = Buffer.from(argon2HashConfigOptions.associatedData));
13
+ (argon2HashConfigOptions['associatedData'] = Buffer.from(argon2HashConfigOptions['associatedData']));
14
14
  return argon2_1.default.hash(stringToHash, argon2HashConfigOptions);
15
15
  }
16
16
  exports.generateHash = generateHash;