directus 9.23.3 → 9.24.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 (132) hide show
  1. package/dist/app.js +15 -15
  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 +10 -10
  15. package/dist/controllers/assets.js +19 -18
  16. package/dist/controllers/auth.js +16 -16
  17. package/dist/controllers/collections.js +11 -11
  18. package/dist/controllers/dashboards.js +11 -11
  19. package/dist/controllers/extensions.js +3 -3
  20. package/dist/controllers/fields.js +17 -17
  21. package/dist/controllers/files.js +18 -17
  22. package/dist/controllers/flows.js +13 -13
  23. package/dist/controllers/folders.js +11 -11
  24. package/dist/controllers/graphql.js +6 -6
  25. package/dist/controllers/items.js +19 -19
  26. package/dist/controllers/notifications.js +11 -11
  27. package/dist/controllers/operations.js +11 -11
  28. package/dist/controllers/panels.js +11 -11
  29. package/dist/controllers/permissions.js +11 -11
  30. package/dist/controllers/presets.js +11 -11
  31. package/dist/controllers/relations.js +11 -11
  32. package/dist/controllers/revisions.js +3 -3
  33. package/dist/controllers/roles.js +11 -11
  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 +14 -14
  38. package/dist/controllers/users.js +16 -16
  39. package/dist/controllers/utils.js +7 -7
  40. package/dist/controllers/webhooks.js +11 -11
  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 +6 -6
  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/exceptions/database/dialects/mssql.js +2 -2
  52. package/dist/exceptions/database/dialects/mysql.js +6 -6
  53. package/dist/exceptions/database/record-not-unique.d.ts +1 -1
  54. package/dist/extensions.js +10 -10
  55. package/dist/flows.js +33 -31
  56. package/dist/logger.d.ts +1 -0
  57. package/dist/logger.js +32 -32
  58. package/dist/mailer.js +16 -16
  59. package/dist/messenger.js +4 -4
  60. package/dist/middleware/authenticate.d.ts +1 -1
  61. package/dist/middleware/authenticate.js +2 -2
  62. package/dist/middleware/cache.js +11 -11
  63. package/dist/middleware/collection-exists.js +4 -4
  64. package/dist/middleware/cors.js +8 -8
  65. package/dist/middleware/error-handler.js +2 -2
  66. package/dist/middleware/extract-token.js +3 -3
  67. package/dist/middleware/get-permissions.js +1 -1
  68. package/dist/middleware/graphql.js +12 -6
  69. package/dist/middleware/rate-limiter-global.js +5 -5
  70. package/dist/middleware/rate-limiter-ip.js +2 -2
  71. package/dist/middleware/respond.js +16 -16
  72. package/dist/middleware/sanitize-query.js +1 -1
  73. package/dist/middleware/schema.js +1 -1
  74. package/dist/middleware/use-collection.js +1 -1
  75. package/dist/middleware/validate-batch.js +1 -1
  76. package/dist/operations/exec/index.js +2 -2
  77. package/dist/rate-limiter.js +1 -1
  78. package/dist/request/validate-ip.js +2 -2
  79. package/dist/server.js +4 -4
  80. package/dist/services/activity.js +14 -14
  81. package/dist/services/assets.js +6 -6
  82. package/dist/services/authentication.js +9 -9
  83. package/dist/services/collections.js +9 -9
  84. package/dist/services/fields.js +5 -5
  85. package/dist/services/files.js +18 -18
  86. package/dist/services/graphql/index.js +170 -116
  87. package/dist/services/import-export.js +6 -6
  88. package/dist/services/items.js +6 -6
  89. package/dist/services/mail/index.js +5 -5
  90. package/dist/services/meta.js +1 -0
  91. package/dist/services/notifications.js +4 -4
  92. package/dist/services/relations.js +4 -4
  93. package/dist/services/revisions.js +3 -3
  94. package/dist/services/roles.js +5 -5
  95. package/dist/services/server.js +27 -27
  96. package/dist/services/shares.js +9 -9
  97. package/dist/services/specifications.js +5 -3
  98. package/dist/services/users.d.ts +1 -5
  99. package/dist/services/users.js +24 -27
  100. package/dist/storage/register-locations.js +1 -1
  101. package/dist/utils/apply-diff.js +12 -12
  102. package/dist/utils/apply-query.js +3 -2
  103. package/dist/utils/dynamic-import.js +1 -1
  104. package/dist/utils/generate-hash.js +1 -1
  105. package/dist/utils/get-ast-from-query.js +2 -2
  106. package/dist/utils/get-auth-providers.js +1 -1
  107. package/dist/utils/get-cache-headers.js +3 -3
  108. package/dist/utils/get-collection-from-alias.js +1 -0
  109. package/dist/utils/get-column-path.js +2 -1
  110. package/dist/utils/get-default-value.js +1 -1
  111. package/dist/utils/get-ip-from-req.js +2 -2
  112. package/dist/utils/get-permissions.js +11 -11
  113. package/dist/utils/get-schema.js +5 -5
  114. package/dist/utils/get-snapshot-diff.js +1 -1
  115. package/dist/utils/is-url-allowed.js +5 -2
  116. package/dist/utils/parse-image-metadata.js +3 -3
  117. package/dist/utils/reduce-schema.js +5 -5
  118. package/dist/utils/sanitize-query.js +26 -26
  119. package/dist/utils/should-skip-cache.js +13 -4
  120. package/dist/utils/strip-function.js +1 -1
  121. package/dist/utils/telemetry.d.ts +1 -0
  122. package/dist/utils/telemetry.js +30 -0
  123. package/dist/utils/validate-keys.js +1 -1
  124. package/dist/utils/validate-query.js +1 -1
  125. package/dist/utils/validate-storage.js +8 -8
  126. package/dist/webhooks.js +2 -2
  127. package/package.json +13 -13
  128. package/dist/utils/redact-header-cookies.d.ts +0 -1
  129. package/dist/utils/redact-header-cookies.js +0 -11
  130. package/dist/utils/track.d.ts +0 -1
  131. package/dist/utils/track.js +0 -81
  132. /package/dist/{utils/redact-header-cookies.test.d.ts → logger.test.d.ts} +0 -0
package/dist/app.js CHANGED
@@ -81,7 +81,7 @@ const lodash_1 = require("lodash");
81
81
  const auth_2 = require("./auth");
82
82
  const cache_2 = require("./cache");
83
83
  const get_config_from_env_1 = require("./utils/get-config-from-env");
84
- const track_1 = require("./utils/track");
84
+ const telemetry_1 = require("./utils/telemetry");
85
85
  const url_1 = require("./utils/url");
86
86
  const validate_env_1 = require("./utils/validate-env");
87
87
  const validate_storage_1 = require("./utils/validate-storage");
@@ -89,7 +89,7 @@ const webhooks_2 = require("./webhooks");
89
89
  async function createApp() {
90
90
  const helmet = await import('helmet');
91
91
  (0, validate_env_1.validateEnv)(['KEY', 'SECRET']);
92
- if (!new url_1.Url(env_1.default.PUBLIC_URL).isAbsolute()) {
92
+ if (!new url_1.Url(env_1.default['PUBLIC_URL']).isAbsolute()) {
93
93
  logger_1.default.warn('PUBLIC_URL should be a full URL');
94
94
  }
95
95
  await (0, validate_storage_1.validateStorage)();
@@ -110,7 +110,7 @@ async function createApp() {
110
110
  await flowManager.initialize();
111
111
  const app = (0, express_1.default)();
112
112
  app.disable('x-powered-by');
113
- app.set('trust proxy', env_1.default.IP_TRUST_PROXY);
113
+ app.set('trust proxy', env_1.default['IP_TRUST_PROXY']);
114
114
  app.set('query parser', (str) => qs_1.default.parse(str, { depth: 10 }));
115
115
  app.use(helmet.contentSecurityPolicy((0, lodash_1.merge)({
116
116
  useDefaults: true,
@@ -130,7 +130,7 @@ async function createApp() {
130
130
  connectSrc: ["'self'", 'https://*'],
131
131
  },
132
132
  }, (0, get_config_from_env_1.getConfigFromEnv)('CONTENT_SECURITY_POLICY_'))));
133
- if (env_1.default.HSTS_ENABLED) {
133
+ if (env_1.default['HSTS_ENABLED']) {
134
134
  app.use(helmet.hsts((0, get_config_from_env_1.getConfigFromEnv)('HSTS_', ['HSTS_ENABLED'])));
135
135
  }
136
136
  await emitter_1.default.emitInit('app.before', { app });
@@ -140,12 +140,12 @@ async function createApp() {
140
140
  res.setHeader('X-Powered-By', 'Directus');
141
141
  next();
142
142
  });
143
- if (env_1.default.CORS_ENABLED === true) {
143
+ if (env_1.default['CORS_ENABLED'] === true) {
144
144
  app.use(cors_1.default);
145
145
  }
146
146
  app.use((req, res, next) => {
147
147
  express_1.default.json({
148
- limit: env_1.default.MAX_PAYLOAD_SIZE,
148
+ limit: env_1.default['MAX_PAYLOAD_SIZE'],
149
149
  })(req, res, (err) => {
150
150
  if (err) {
151
151
  return next(new exceptions_1.InvalidPayloadException(err.message));
@@ -156,8 +156,8 @@ async function createApp() {
156
156
  app.use((0, cookie_parser_1.default)());
157
157
  app.use(extract_token_1.default);
158
158
  app.get('/', (_req, res, next) => {
159
- if (env_1.default.ROOT_REDIRECT) {
160
- res.redirect(env_1.default.ROOT_REDIRECT);
159
+ if (env_1.default['ROOT_REDIRECT']) {
160
+ res.redirect(env_1.default['ROOT_REDIRECT']);
161
161
  }
162
162
  else {
163
163
  next();
@@ -166,11 +166,11 @@ async function createApp() {
166
166
  app.get('/robots.txt', (_, res) => {
167
167
  res.set('Content-Type', 'text/plain');
168
168
  res.status(200);
169
- res.send(env_1.default.ROBOTS_TXT);
169
+ res.send(env_1.default['ROBOTS_TXT']);
170
170
  });
171
- if (env_1.default.SERVE_APP) {
171
+ if (env_1.default['SERVE_APP']) {
172
172
  const adminPath = require.resolve('@directus/app');
173
- const adminUrl = new url_1.Url(env_1.default.PUBLIC_URL).addPath('admin');
173
+ const adminUrl = new url_1.Url(env_1.default['PUBLIC_URL']).addPath('admin');
174
174
  const embeds = extensionManager.getEmbeds();
175
175
  // Set the App's base path according to the APIs public URL
176
176
  const html = await fs_extra_1.default.readFile(adminPath, 'utf8');
@@ -192,13 +192,13 @@ async function createApp() {
192
192
  app.use('/admin/*', sendHtml);
193
193
  }
194
194
  // use the rate limiter - all routes for now
195
- if (env_1.default.RATE_LIMITER_GLOBAL_ENABLED === true) {
195
+ if (env_1.default['RATE_LIMITER_GLOBAL_ENABLED'] === true) {
196
196
  app.use(rate_limiter_global_1.default);
197
197
  }
198
- if (env_1.default.RATE_LIMITER_ENABLED === true) {
198
+ if (env_1.default['RATE_LIMITER_ENABLED'] === true) {
199
199
  app.use(rate_limiter_ip_1.default);
200
200
  }
201
- app.get('/server/ping', (req, res) => res.send('pong'));
201
+ app.get('/server/ping', (_req, res) => res.send('pong'));
202
202
  app.use(authenticate_1.default);
203
203
  app.use(check_ip_1.checkIP);
204
204
  app.use(sanitize_query_1.default);
@@ -243,7 +243,7 @@ async function createApp() {
243
243
  await emitter_1.default.emitInit('routes.after', { app });
244
244
  // Register all webhooks
245
245
  await (0, webhooks_2.init)();
246
- (0, track_1.track)('serverStarted');
246
+ (0, telemetry_1.collectTelemetry)();
247
247
  await emitter_1.default.emitInit('app.after', { app });
248
248
  return app;
249
249
  }
@@ -55,10 +55,10 @@ class LDAPAuthDriver extends auth_1.AuthDriver {
55
55
  bindPassword === undefined ||
56
56
  !userDn ||
57
57
  !provider ||
58
- (!clientUrl && !config.client?.socketPath)) {
58
+ (!clientUrl && !config['client']?.socketPath)) {
59
59
  throw new exceptions_1.InvalidConfigException('Invalid provider config', { provider });
60
60
  }
61
- const clientConfig = typeof config.client === 'object' ? config.client : {};
61
+ const clientConfig = typeof config['client'] === 'object' ? config['client'] : {};
62
62
  this.bindClient = ldapjs_1.default.createClient({ url: clientUrl, reconnect: true, ...clientConfig });
63
63
  this.bindClient.on('error', (err) => {
64
64
  logger_1.default.warn(err);
@@ -122,8 +122,8 @@ class LDAPAuthDriver extends auth_1.AuthDriver {
122
122
  }
123
123
  res.on('searchEntry', ({ object }) => {
124
124
  const user = {
125
- dn: object.dn,
126
- userAccountControl: Number(getEntryValue(object.userAccountControl) ?? 0),
125
+ dn: object['dn'],
126
+ userAccountControl: Number(getEntryValue(object['userAccountControl']) ?? 0),
127
127
  };
128
128
  const firstName = getEntryValue(object[firstNameAttribute]);
129
129
  if (firstName)
@@ -134,7 +134,7 @@ class LDAPAuthDriver extends auth_1.AuthDriver {
134
134
  const email = getEntryValue(object[mailAttribute]);
135
135
  if (email)
136
136
  user.email = email;
137
- const uid = getEntryValue(object.uid);
137
+ const uid = getEntryValue(object['uid']);
138
138
  if (uid)
139
139
  user.uid = uid;
140
140
  resolve(user);
@@ -162,11 +162,11 @@ class LDAPAuthDriver extends auth_1.AuthDriver {
162
162
  return;
163
163
  }
164
164
  res.on('searchEntry', ({ object }) => {
165
- if (typeof object.cn === 'object') {
166
- userGroups = [...userGroups, ...object.cn];
165
+ if (typeof object['cn'] === 'object') {
166
+ userGroups = [...userGroups, ...object['cn']];
167
167
  }
168
- else if (object.cn) {
169
- userGroups.push(object.cn);
168
+ else if (object['cn']) {
169
+ userGroups.push(object['cn']);
170
170
  }
171
171
  });
172
172
  res.on('error', (err) => {
@@ -187,14 +187,14 @@ class LDAPAuthDriver extends auth_1.AuthDriver {
187
187
  return user?.id;
188
188
  }
189
189
  async getUserID(payload) {
190
- if (!payload.identifier) {
190
+ if (!payload['identifier']) {
191
191
  throw new exceptions_1.InvalidCredentialsException();
192
192
  }
193
193
  await this.validateBindClient();
194
194
  const { userDn, userScope, userAttribute, groupDn, groupScope, groupAttribute, defaultRoleId } = this.config;
195
195
  const userInfo = await this.fetchUserInfo(userDn, new ldapjs_1.EqualityFilter({
196
196
  attribute: userAttribute ?? 'cn',
197
- value: payload.identifier,
197
+ value: payload['identifier'],
198
198
  }), userScope ?? 'one');
199
199
  if (!userInfo?.dn) {
200
200
  throw new exceptions_1.InvalidCredentialsException();
@@ -229,7 +229,7 @@ class LDAPAuthDriver extends auth_1.AuthDriver {
229
229
  }
230
230
  try {
231
231
  await this.usersService.createOne({
232
- provider: this.config.provider,
232
+ provider: this.config['provider'],
233
233
  first_name: userInfo.firstName,
234
234
  last_name: userInfo.lastName,
235
235
  email: userInfo.email,
@@ -251,9 +251,9 @@ class LDAPAuthDriver extends auth_1.AuthDriver {
251
251
  throw new exceptions_1.InvalidCredentialsException();
252
252
  }
253
253
  return new Promise((resolve, reject) => {
254
- const clientConfig = typeof this.config.client === 'object' ? this.config.client : {};
254
+ const clientConfig = typeof this.config['client'] === 'object' ? this.config['client'] : {};
255
255
  const client = ldapjs_1.default.createClient({
256
- url: this.config.clientUrl,
256
+ url: this.config['clientUrl'],
257
257
  ...clientConfig,
258
258
  reconnect: false,
259
259
  });
@@ -272,7 +272,7 @@ class LDAPAuthDriver extends auth_1.AuthDriver {
272
272
  });
273
273
  }
274
274
  async login(user, payload) {
275
- await this.verify(user, payload.password);
275
+ await this.verify(user, payload['password']);
276
276
  }
277
277
  async refresh(user) {
278
278
  await this.validateBindClient();
@@ -330,18 +330,18 @@ function createLDAPAuthRouter(provider) {
330
330
  data: { access_token: accessToken, expires },
331
331
  };
332
332
  if (mode === 'json') {
333
- payload.data.refresh_token = refreshToken;
333
+ payload['data']['refresh_token'] = refreshToken;
334
334
  }
335
335
  if (mode === 'cookie') {
336
- res.cookie(env_1.default.REFRESH_TOKEN_COOKIE_NAME, refreshToken, {
336
+ res.cookie(env_1.default['REFRESH_TOKEN_COOKIE_NAME'], refreshToken, {
337
337
  httpOnly: true,
338
- domain: env_1.default.REFRESH_TOKEN_COOKIE_DOMAIN,
339
- maxAge: (0, get_milliseconds_1.getMilliseconds)(env_1.default.REFRESH_TOKEN_TTL),
340
- secure: env_1.default.REFRESH_TOKEN_COOKIE_SECURE ?? false,
341
- sameSite: env_1.default.REFRESH_TOKEN_COOKIE_SAME_SITE || 'strict',
338
+ domain: env_1.default['REFRESH_TOKEN_COOKIE_DOMAIN'],
339
+ maxAge: (0, get_milliseconds_1.getMilliseconds)(env_1.default['REFRESH_TOKEN_TTL']),
340
+ secure: env_1.default['REFRESH_TOKEN_COOKIE_SECURE'] ?? false,
341
+ sameSite: env_1.default['REFRESH_TOKEN_COOKIE_SAME_SITE'] || 'strict',
342
342
  });
343
343
  }
344
- res.locals.payload = payload;
344
+ res.locals['payload'] = payload;
345
345
  return next();
346
346
  }), respond_1.respond);
347
347
  return router;
@@ -19,13 +19,13 @@ const stall_1 = require("../../utils/stall");
19
19
  const auth_1 = require("../auth");
20
20
  class LocalAuthDriver extends auth_1.AuthDriver {
21
21
  async getUserID(payload) {
22
- if (!payload.email) {
22
+ if (!payload['email']) {
23
23
  throw new exceptions_1.InvalidCredentialsException();
24
24
  }
25
25
  const user = await this.knex
26
26
  .select('id')
27
27
  .from('directus_users')
28
- .whereRaw('LOWER(??) = ?', ['email', payload.email.toLowerCase()])
28
+ .whereRaw('LOWER(??) = ?', ['email', payload['email'].toLowerCase()])
29
29
  .first();
30
30
  if (!user) {
31
31
  throw new exceptions_1.InvalidCredentialsException();
@@ -38,7 +38,7 @@ class LocalAuthDriver extends auth_1.AuthDriver {
38
38
  }
39
39
  }
40
40
  async login(user, payload) {
41
- await this.verify(user, payload.password);
41
+ await this.verify(user, payload['password']);
42
42
  }
43
43
  }
44
44
  exports.LocalAuthDriver = LocalAuthDriver;
@@ -51,7 +51,7 @@ function createLocalAuthRouter(provider) {
51
51
  otp: joi_1.default.string(),
52
52
  }).unknown();
53
53
  router.post('/', (0, async_handler_1.default)(async (req, res, next) => {
54
- const STALL_TIME = env_1.default.LOGIN_STALL_TIME;
54
+ const STALL_TIME = env_1.default['LOGIN_STALL_TIME'];
55
55
  const timeStart = perf_hooks_1.performance.now();
56
56
  const accountability = {
57
57
  ip: (0, get_ip_from_req_1.getIPFromReq)(req),
@@ -78,12 +78,12 @@ function createLocalAuthRouter(provider) {
78
78
  data: { access_token: accessToken, expires },
79
79
  };
80
80
  if (mode === 'json') {
81
- payload.data.refresh_token = refreshToken;
81
+ payload['data']['refresh_token'] = refreshToken;
82
82
  }
83
83
  if (mode === 'cookie') {
84
- res.cookie(env_1.default.REFRESH_TOKEN_COOKIE_NAME, refreshToken, constants_1.COOKIE_OPTIONS);
84
+ res.cookie(env_1.default['REFRESH_TOKEN_COOKIE_NAME'], refreshToken, constants_1.COOKIE_OPTIONS);
85
85
  }
86
- res.locals.payload = payload;
86
+ res.locals['payload'] = payload;
87
87
  return next();
88
88
  }), respond_1.respond);
89
89
  return router;
@@ -54,10 +54,10 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
54
54
  constructor(options, config) {
55
55
  super(options, config);
56
56
  const { authorizeUrl, accessUrl, profileUrl, clientId, clientSecret, ...additionalConfig } = config;
57
- if (!authorizeUrl || !accessUrl || !profileUrl || !clientId || !clientSecret || !additionalConfig.provider) {
58
- throw new exceptions_2.InvalidConfigException('Invalid provider config', { provider: additionalConfig.provider });
57
+ if (!authorizeUrl || !accessUrl || !profileUrl || !clientId || !clientSecret || !additionalConfig['provider']) {
58
+ throw new exceptions_2.InvalidConfigException('Invalid provider config', { provider: additionalConfig['provider'] });
59
59
  }
60
- const redirectUrl = new url_1.Url(env_1.default.PUBLIC_URL).addPath('auth', 'login', additionalConfig.provider, 'callback');
60
+ const redirectUrl = new url_1.Url(env_1.default['PUBLIC_URL']).addPath('auth', 'login', additionalConfig['provider'], 'callback');
61
61
  this.redirectUrl = redirectUrl.toString();
62
62
  this.usersService = new services_1.UsersService({ knex: this.knex, schema: this.schema });
63
63
  this.config = additionalConfig;
@@ -65,9 +65,9 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
65
65
  authorization_endpoint: authorizeUrl,
66
66
  token_endpoint: accessUrl,
67
67
  userinfo_endpoint: profileUrl,
68
- issuer: additionalConfig.provider,
68
+ issuer: additionalConfig['provider'],
69
69
  });
70
- const clientOptionsOverrides = (0, get_config_from_env_1.getConfigFromEnv)(`AUTH_${config.provider.toUpperCase()}_CLIENT_`, [`AUTH_${config.provider.toUpperCase()}_CLIENT_ID`, `AUTH_${config.provider.toUpperCase()}_CLIENT_SECRET`], 'underscore');
70
+ const clientOptionsOverrides = (0, get_config_from_env_1.getConfigFromEnv)(`AUTH_${config['provider'].toUpperCase()}_CLIENT_`, [`AUTH_${config['provider'].toUpperCase()}_CLIENT_ID`, `AUTH_${config['provider'].toUpperCase()}_CLIENT_SECRET`], 'underscore');
71
71
  this.client = new issuer.Client({
72
72
  client_id: clientId,
73
73
  client_secret: clientSecret,
@@ -82,9 +82,9 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
82
82
  generateAuthUrl(codeVerifier, prompt = false) {
83
83
  try {
84
84
  const codeChallenge = openid_client_1.generators.codeChallenge(codeVerifier);
85
- const paramsConfig = typeof this.config.params === 'object' ? this.config.params : {};
85
+ const paramsConfig = typeof this.config['params'] === 'object' ? this.config['params'] : {};
86
86
  return this.client.authorizationUrl({
87
- scope: this.config.scope ?? 'email',
87
+ scope: this.config['scope'] ?? 'email',
88
88
  access_type: 'offline',
89
89
  prompt: prompt ? 'consent' : undefined,
90
90
  ...paramsConfig,
@@ -107,14 +107,14 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
107
107
  return user?.id;
108
108
  }
109
109
  async getUserID(payload) {
110
- if (!payload.code || !payload.codeVerifier || !payload.state) {
110
+ if (!payload['code'] || !payload['codeVerifier'] || !payload['state']) {
111
111
  logger_1.default.warn('[OAuth2] No code, codeVerifier or state in payload');
112
112
  throw new exceptions_2.InvalidCredentialsException();
113
113
  }
114
114
  let tokenSet;
115
115
  let userInfo;
116
116
  try {
117
- tokenSet = await this.client.oauthCallback(this.redirectUrl, { code: payload.code, state: payload.state }, { code_verifier: payload.codeVerifier, state: openid_client_1.generators.codeChallenge(payload.codeVerifier) });
117
+ tokenSet = await this.client.oauthCallback(this.redirectUrl, { code: payload['code'], state: payload['state'] }, { code_verifier: payload['codeVerifier'], state: openid_client_1.generators.codeChallenge(payload['codeVerifier']) });
118
118
  userInfo = await this.client.userinfo(tokenSet.access_token);
119
119
  }
120
120
  catch (e) {
@@ -148,11 +148,11 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
148
148
  try {
149
149
  await this.usersService.createOne({
150
150
  provider,
151
- first_name: userInfo[this.config.firstNameKey],
152
- last_name: userInfo[this.config.lastNameKey],
151
+ first_name: userInfo[this.config['firstNameKey']],
152
+ last_name: userInfo[this.config['lastNameKey']],
153
153
  email: email,
154
154
  external_identifier: identifier,
155
- role: this.config.defaultRoleId,
155
+ role: this.config['defaultRoleId'],
156
156
  auth_data: tokenSet.refresh_token && JSON.stringify({ refreshToken: tokenSet.refresh_token }),
157
157
  });
158
158
  }
@@ -178,9 +178,9 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
178
178
  logger_1.default.warn(`[OAuth2] Session data isn't valid JSON: ${authData}`);
179
179
  }
180
180
  }
181
- if (authData?.refreshToken) {
181
+ if (authData?.['refreshToken']) {
182
182
  try {
183
- const tokenSet = await this.client.refresh(authData.refreshToken);
183
+ const tokenSet = await this.client.refresh(authData['refreshToken']);
184
184
  // Update user refreshToken if provided
185
185
  if (tokenSet.refresh_token) {
186
186
  await this.usersService.updateOne(user.id, {
@@ -222,8 +222,8 @@ function createOAuth2AuthRouter(providerName) {
222
222
  router.get('/', (req, res) => {
223
223
  const provider = (0, auth_1.getAuthProvider)(providerName);
224
224
  const codeVerifier = provider.generateCodeVerifier();
225
- const prompt = !!req.query.prompt;
226
- const token = jsonwebtoken_1.default.sign({ verifier: codeVerifier, redirect: req.query.redirect, prompt }, env_1.default.SECRET, {
225
+ const prompt = !!req.query['prompt'];
226
+ const token = jsonwebtoken_1.default.sign({ verifier: codeVerifier, redirect: req.query['redirect'], prompt }, env_1.default['SECRET'], {
227
227
  expiresIn: '5m',
228
228
  issuer: 'directus',
229
229
  });
@@ -239,7 +239,9 @@ function createOAuth2AuthRouter(providerName) {
239
239
  router.get('/callback', (0, async_handler_1.default)(async (req, res, next) => {
240
240
  let tokenData;
241
241
  try {
242
- tokenData = jsonwebtoken_1.default.verify(req.cookies[`oauth2.${providerName}`], env_1.default.SECRET, { issuer: 'directus' });
242
+ tokenData = jsonwebtoken_1.default.verify(req.cookies[`oauth2.${providerName}`], env_1.default['SECRET'], {
243
+ issuer: 'directus',
244
+ });
243
245
  }
244
246
  catch (e) {
245
247
  logger_1.default.warn(e, `[OAuth2] Couldn't verify OAuth2 cookie`);
@@ -264,9 +266,9 @@ function createOAuth2AuthRouter(providerName) {
264
266
  try {
265
267
  res.clearCookie(`oauth2.${providerName}`);
266
268
  authResponse = await authenticationService.login(providerName, {
267
- code: req.query.code,
269
+ code: req.query['code'],
268
270
  codeVerifier: verifier,
269
- state: req.query.state,
271
+ state: req.query['state'],
270
272
  });
271
273
  }
272
274
  catch (error) {
@@ -289,16 +291,16 @@ function createOAuth2AuthRouter(providerName) {
289
291
  }
290
292
  const { accessToken, refreshToken, expires } = authResponse;
291
293
  if (redirect) {
292
- res.cookie(env_1.default.REFRESH_TOKEN_COOKIE_NAME, refreshToken, {
294
+ res.cookie(env_1.default['REFRESH_TOKEN_COOKIE_NAME'], refreshToken, {
293
295
  httpOnly: true,
294
- domain: env_1.default.REFRESH_TOKEN_COOKIE_DOMAIN,
295
- maxAge: (0, get_milliseconds_1.getMilliseconds)(env_1.default.REFRESH_TOKEN_TTL),
296
- secure: env_1.default.REFRESH_TOKEN_COOKIE_SECURE ?? false,
297
- sameSite: env_1.default.REFRESH_TOKEN_COOKIE_SAME_SITE || 'strict',
296
+ domain: env_1.default['REFRESH_TOKEN_COOKIE_DOMAIN'],
297
+ maxAge: (0, get_milliseconds_1.getMilliseconds)(env_1.default['REFRESH_TOKEN_TTL']),
298
+ secure: env_1.default['REFRESH_TOKEN_COOKIE_SECURE'] ?? false,
299
+ sameSite: env_1.default['REFRESH_TOKEN_COOKIE_SAME_SITE'] || 'strict',
298
300
  });
299
301
  return res.redirect(redirect);
300
302
  }
301
- res.locals.payload = {
303
+ res.locals['payload'] = {
302
304
  data: { access_token: accessToken, refresh_token: refreshToken, expires },
303
305
  };
304
306
  next();
@@ -54,21 +54,21 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
54
54
  constructor(options, config) {
55
55
  super(options, config);
56
56
  const { issuerUrl, clientId, clientSecret, ...additionalConfig } = config;
57
- if (!issuerUrl || !clientId || !clientSecret || !additionalConfig.provider) {
58
- throw new exceptions_2.InvalidConfigException('Invalid provider config', { provider: additionalConfig.provider });
57
+ if (!issuerUrl || !clientId || !clientSecret || !additionalConfig['provider']) {
58
+ throw new exceptions_2.InvalidConfigException('Invalid provider config', { provider: additionalConfig['provider'] });
59
59
  }
60
- const redirectUrl = new url_1.Url(env_1.default.PUBLIC_URL).addPath('auth', 'login', additionalConfig.provider, 'callback');
61
- const clientOptionsOverrides = (0, get_config_from_env_1.getConfigFromEnv)(`AUTH_${config.provider.toUpperCase()}_CLIENT_`, [`AUTH_${config.provider.toUpperCase()}_CLIENT_ID`, `AUTH_${config.provider.toUpperCase()}_CLIENT_SECRET`], 'underscore');
60
+ const redirectUrl = new url_1.Url(env_1.default['PUBLIC_URL']).addPath('auth', 'login', additionalConfig['provider'], 'callback');
61
+ const clientOptionsOverrides = (0, get_config_from_env_1.getConfigFromEnv)(`AUTH_${config['provider'].toUpperCase()}_CLIENT_`, [`AUTH_${config['provider'].toUpperCase()}_CLIENT_ID`, `AUTH_${config['provider'].toUpperCase()}_CLIENT_SECRET`], 'underscore');
62
62
  this.redirectUrl = redirectUrl.toString();
63
63
  this.usersService = new services_1.UsersService({ knex: this.knex, schema: this.schema });
64
64
  this.config = additionalConfig;
65
65
  this.client = new Promise((resolve, reject) => {
66
66
  openid_client_1.Issuer.discover(issuerUrl)
67
67
  .then((issuer) => {
68
- const supportedTypes = issuer.metadata.response_types_supported;
68
+ const supportedTypes = issuer.metadata['response_types_supported'];
69
69
  if (!supportedTypes?.includes('code')) {
70
70
  reject(new exceptions_2.InvalidConfigException('OpenID provider does not support required code flow', {
71
- provider: additionalConfig.provider,
71
+ provider: additionalConfig['provider'],
72
72
  }));
73
73
  }
74
74
  resolve(new issuer.Client({
@@ -92,9 +92,9 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
92
92
  try {
93
93
  const client = await this.client;
94
94
  const codeChallenge = openid_client_1.generators.codeChallenge(codeVerifier);
95
- const paramsConfig = typeof this.config.params === 'object' ? this.config.params : {};
95
+ const paramsConfig = typeof this.config['params'] === 'object' ? this.config['params'] : {};
96
96
  return client.authorizationUrl({
97
- scope: this.config.scope ?? 'openid profile email',
97
+ scope: this.config['scope'] ?? 'openid profile email',
98
98
  access_type: 'offline',
99
99
  prompt: prompt ? 'consent' : undefined,
100
100
  ...paramsConfig,
@@ -118,7 +118,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
118
118
  return user?.id;
119
119
  }
120
120
  async getUserID(payload) {
121
- if (!payload.code || !payload.codeVerifier || !payload.state) {
121
+ if (!payload['code'] || !payload['codeVerifier'] || !payload['state']) {
122
122
  logger_1.default.warn('[OpenID] No code, codeVerifier or state in payload');
123
123
  throw new exceptions_2.InvalidCredentialsException();
124
124
  }
@@ -126,10 +126,10 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
126
126
  let userInfo;
127
127
  try {
128
128
  const client = await this.client;
129
- const codeChallenge = openid_client_1.generators.codeChallenge(payload.codeVerifier);
130
- tokenSet = await client.callback(this.redirectUrl, { code: payload.code, state: payload.state }, { code_verifier: payload.codeVerifier, state: codeChallenge, nonce: codeChallenge });
129
+ const codeChallenge = openid_client_1.generators.codeChallenge(payload['codeVerifier']);
130
+ tokenSet = await client.callback(this.redirectUrl, { code: payload['code'], state: payload['state'] }, { code_verifier: payload['codeVerifier'], state: codeChallenge, nonce: codeChallenge });
131
131
  userInfo = tokenSet.claims();
132
- if (client.issuer.metadata.userinfo_endpoint) {
132
+ if (client.issuer.metadata['userinfo_endpoint']) {
133
133
  userInfo = {
134
134
  ...userInfo,
135
135
  ...(await client.userinfo(tokenSet.access_token)),
@@ -142,7 +142,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
142
142
  // Flatten response to support dot indexes
143
143
  userInfo = (0, flat_1.default)(userInfo);
144
144
  const { provider, identifierKey, allowPublicRegistration, requireVerifiedEmail } = this.config;
145
- const email = userInfo.email ? String(userInfo.email) : undefined;
145
+ const email = userInfo['email'] ? String(userInfo['email']) : undefined;
146
146
  // Fallback to email if explicit identifier not found
147
147
  const identifier = userInfo[identifierKey ?? 'sub'] ? String(userInfo[identifierKey ?? 'sub']) : email;
148
148
  if (!identifier) {
@@ -159,7 +159,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
159
159
  }
160
160
  return userId;
161
161
  }
162
- const isEmailVerified = !requireVerifiedEmail || userInfo.email_verified;
162
+ const isEmailVerified = !requireVerifiedEmail || userInfo['email_verified'];
163
163
  // Is public registration allowed?
164
164
  if (!allowPublicRegistration || !isEmailVerified) {
165
165
  logger_1.default.warn(`[OpenID] User doesn't exist, and public registration not allowed for provider "${provider}"`);
@@ -168,11 +168,11 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
168
168
  try {
169
169
  await this.usersService.createOne({
170
170
  provider,
171
- first_name: userInfo.given_name,
172
- last_name: userInfo.family_name,
171
+ first_name: userInfo['given_name'],
172
+ last_name: userInfo['family_name'],
173
173
  email: email,
174
174
  external_identifier: identifier,
175
- role: this.config.defaultRoleId,
175
+ role: this.config['defaultRoleId'],
176
176
  auth_data: tokenSet.refresh_token && JSON.stringify({ refreshToken: tokenSet.refresh_token }),
177
177
  });
178
178
  }
@@ -198,10 +198,10 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
198
198
  logger_1.default.warn(`[OpenID] Session data isn't valid JSON: ${authData}`);
199
199
  }
200
200
  }
201
- if (authData?.refreshToken) {
201
+ if (authData?.['refreshToken']) {
202
202
  try {
203
203
  const client = await this.client;
204
- const tokenSet = await client.refresh(authData.refreshToken);
204
+ const tokenSet = await client.refresh(authData['refreshToken']);
205
205
  // Update user refreshToken if provided
206
206
  if (tokenSet.refresh_token) {
207
207
  await this.usersService.updateOne(user.id, {
@@ -243,8 +243,8 @@ function createOpenIDAuthRouter(providerName) {
243
243
  router.get('/', (0, async_handler_1.default)(async (req, res) => {
244
244
  const provider = (0, auth_1.getAuthProvider)(providerName);
245
245
  const codeVerifier = provider.generateCodeVerifier();
246
- const prompt = !!req.query.prompt;
247
- const token = jsonwebtoken_1.default.sign({ verifier: codeVerifier, redirect: req.query.redirect, prompt }, env_1.default.SECRET, {
246
+ const prompt = !!req.query['prompt'];
247
+ const token = jsonwebtoken_1.default.sign({ verifier: codeVerifier, redirect: req.query['redirect'], prompt }, env_1.default['SECRET'], {
248
248
  expiresIn: '5m',
249
249
  issuer: 'directus',
250
250
  });
@@ -260,7 +260,9 @@ function createOpenIDAuthRouter(providerName) {
260
260
  router.get('/callback', (0, async_handler_1.default)(async (req, res, next) => {
261
261
  let tokenData;
262
262
  try {
263
- tokenData = jsonwebtoken_1.default.verify(req.cookies[`openid.${providerName}`], env_1.default.SECRET, { issuer: 'directus' });
263
+ tokenData = jsonwebtoken_1.default.verify(req.cookies[`openid.${providerName}`], env_1.default['SECRET'], {
264
+ issuer: 'directus',
265
+ });
264
266
  }
265
267
  catch (e) {
266
268
  logger_1.default.warn(e, `[OpenID] Couldn't verify OpenID cookie`);
@@ -285,9 +287,9 @@ function createOpenIDAuthRouter(providerName) {
285
287
  try {
286
288
  res.clearCookie(`openid.${providerName}`);
287
289
  authResponse = await authenticationService.login(providerName, {
288
- code: req.query.code,
290
+ code: req.query['code'],
289
291
  codeVerifier: verifier,
290
- state: req.query.state,
292
+ state: req.query['state'],
291
293
  });
292
294
  }
293
295
  catch (error) {
@@ -311,16 +313,16 @@ function createOpenIDAuthRouter(providerName) {
311
313
  }
312
314
  const { accessToken, refreshToken, expires } = authResponse;
313
315
  if (redirect) {
314
- res.cookie(env_1.default.REFRESH_TOKEN_COOKIE_NAME, refreshToken, {
316
+ res.cookie(env_1.default['REFRESH_TOKEN_COOKIE_NAME'], refreshToken, {
315
317
  httpOnly: true,
316
- domain: env_1.default.REFRESH_TOKEN_COOKIE_DOMAIN,
317
- maxAge: (0, get_milliseconds_1.getMilliseconds)(env_1.default.REFRESH_TOKEN_TTL),
318
- secure: env_1.default.REFRESH_TOKEN_COOKIE_SECURE ?? false,
319
- sameSite: env_1.default.REFRESH_TOKEN_COOKIE_SAME_SITE || 'strict',
318
+ domain: env_1.default['REFRESH_TOKEN_COOKIE_DOMAIN'],
319
+ maxAge: (0, get_milliseconds_1.getMilliseconds)(env_1.default['REFRESH_TOKEN_TTL']),
320
+ secure: env_1.default['REFRESH_TOKEN_COOKIE_SECURE'] ?? false,
321
+ sameSite: env_1.default['REFRESH_TOKEN_COOKIE_SAME_SITE'] || 'strict',
320
322
  });
321
323
  return res.redirect(redirect);
322
324
  }
323
- res.locals.payload = {
325
+ res.locals['payload'] = {
324
326
  data: { access_token: accessToken, refresh_token: refreshToken, expires },
325
327
  };
326
328
  next();
@@ -53,8 +53,8 @@ class SAMLAuthDriver extends local_1.LocalAuthDriver {
53
53
  super(options, config);
54
54
  this.config = config;
55
55
  this.usersService = new services_1.UsersService({ knex: this.knex, schema: this.schema });
56
- this.sp = samlify.ServiceProvider((0, get_config_from_env_1.getConfigFromEnv)(`AUTH_${config.provider.toUpperCase()}_SP`));
57
- this.idp = samlify.IdentityProvider((0, get_config_from_env_1.getConfigFromEnv)(`AUTH_${config.provider.toUpperCase()}_IDP`));
56
+ this.sp = samlify.ServiceProvider((0, get_config_from_env_1.getConfigFromEnv)(`AUTH_${config['provider'].toUpperCase()}_SP`));
57
+ this.idp = samlify.IdentityProvider((0, get_config_from_env_1.getConfigFromEnv)(`AUTH_${config['provider'].toUpperCase()}_IDP`));
58
58
  }
59
59
  async fetchUserID(identifier) {
60
60
  const user = await this.knex
@@ -84,7 +84,7 @@ class SAMLAuthDriver extends local_1.LocalAuthDriver {
84
84
  last_name: lastName,
85
85
  email: email,
86
86
  external_identifier: identifier.toLowerCase(),
87
- role: this.config.defaultRoleId,
87
+ role: this.config['defaultRoleId'],
88
88
  });
89
89
  }
90
90
  catch (error) {
@@ -111,8 +111,8 @@ function createSAMLAuthRouter(providerName) {
111
111
  const { sp, idp } = (0, auth_1.getAuthProvider)(providerName);
112
112
  const { context: url } = await sp.createLoginRequest(idp, 'redirect');
113
113
  const parsedUrl = new URL(url);
114
- if (req.query.redirect) {
115
- parsedUrl.searchParams.append('RelayState', req.query.redirect);
114
+ if (req.query['redirect']) {
115
+ parsedUrl.searchParams.append('RelayState', req.query['redirect']);
116
116
  }
117
117
  return res.redirect(parsedUrl.toString());
118
118
  }));
@@ -120,11 +120,11 @@ function createSAMLAuthRouter(providerName) {
120
120
  const { sp, idp } = (0, auth_1.getAuthProvider)(providerName);
121
121
  const { context } = await sp.createLogoutRequest(idp, 'redirect', req.body);
122
122
  const authService = new services_1.AuthenticationService({ accountability: req.accountability, schema: req.schema });
123
- if (req.cookies[env_1.default.REFRESH_TOKEN_COOKIE_NAME]) {
124
- const currentRefreshToken = req.cookies[env_1.default.REFRESH_TOKEN_COOKIE_NAME];
123
+ if (req.cookies[env_1.default['REFRESH_TOKEN_COOKIE_NAME']]) {
124
+ const currentRefreshToken = req.cookies[env_1.default['REFRESH_TOKEN_COOKIE_NAME']];
125
125
  if (currentRefreshToken) {
126
126
  await authService.logout(currentRefreshToken);
127
- res.clearCookie(env_1.default.REFRESH_TOKEN_COOKIE_NAME, constants_1.COOKIE_OPTIONS);
127
+ res.clearCookie(env_1.default['REFRESH_TOKEN_COOKIE_NAME'], constants_1.COOKIE_OPTIONS);
128
128
  }
129
129
  }
130
130
  return res.redirect(context);
@@ -136,7 +136,7 @@ function createSAMLAuthRouter(providerName) {
136
136
  const { extract } = await sp.parseLoginResponse(idp, 'post', req);
137
137
  const authService = new services_1.AuthenticationService({ accountability: req.accountability, schema: req.schema });
138
138
  const { accessToken, refreshToken, expires } = await authService.login(providerName, extract.attributes);
139
- res.locals.payload = {
139
+ res.locals['payload'] = {
140
140
  data: {
141
141
  access_token: accessToken,
142
142
  refresh_token: refreshToken,
@@ -144,7 +144,7 @@ function createSAMLAuthRouter(providerName) {
144
144
  },
145
145
  };
146
146
  if (relayState) {
147
- res.cookie(env_1.default.REFRESH_TOKEN_COOKIE_NAME, refreshToken, constants_1.COOKIE_OPTIONS);
147
+ res.cookie(env_1.default['REFRESH_TOKEN_COOKIE_NAME'], refreshToken, constants_1.COOKIE_OPTIONS);
148
148
  return res.redirect(relayState);
149
149
  }
150
150
  return next();