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.
- package/dist/app.js +15 -15
- package/dist/auth/drivers/ldap.js +22 -22
- package/dist/auth/drivers/local.js +7 -7
- package/dist/auth/drivers/oauth2.js +27 -25
- package/dist/auth/drivers/openid.js +32 -30
- package/dist/auth/drivers/saml.js +10 -10
- package/dist/auth.js +4 -3
- package/dist/cache.js +16 -11
- package/dist/cli/commands/bootstrap/index.js +5 -4
- package/dist/cli/utils/create-db-connection.js +1 -1
- package/dist/cli/utils/create-env/index.js +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +6 -5
- package/dist/controllers/activity.js +10 -10
- package/dist/controllers/assets.js +19 -18
- package/dist/controllers/auth.js +16 -16
- package/dist/controllers/collections.js +11 -11
- package/dist/controllers/dashboards.js +11 -11
- package/dist/controllers/extensions.js +3 -3
- package/dist/controllers/fields.js +17 -17
- package/dist/controllers/files.js +18 -17
- package/dist/controllers/flows.js +13 -13
- package/dist/controllers/folders.js +11 -11
- package/dist/controllers/graphql.js +6 -6
- package/dist/controllers/items.js +19 -19
- package/dist/controllers/notifications.js +11 -11
- package/dist/controllers/operations.js +11 -11
- package/dist/controllers/panels.js +11 -11
- package/dist/controllers/permissions.js +11 -11
- package/dist/controllers/presets.js +11 -11
- package/dist/controllers/relations.js +11 -11
- package/dist/controllers/revisions.js +3 -3
- package/dist/controllers/roles.js +11 -11
- package/dist/controllers/schema.js +5 -5
- package/dist/controllers/server.js +7 -7
- package/dist/controllers/settings.js +2 -2
- package/dist/controllers/shares.js +14 -14
- package/dist/controllers/users.js +16 -16
- package/dist/controllers/utils.js +7 -7
- package/dist/controllers/webhooks.js +11 -11
- package/dist/database/helpers/fn/types.d.ts +0 -1
- package/dist/database/helpers/fn/types.js +0 -2
- package/dist/database/helpers/index.d.ts +3 -3
- package/dist/database/index.js +5 -5
- package/dist/database/migrations/20210805B-change-image-metadata-structure.js +15 -15
- package/dist/database/migrations/run.js +1 -1
- package/dist/database/run-ast.js +6 -6
- package/dist/database/system-data/collections/index.js +2 -2
- package/dist/database/system-data/fields/index.js +3 -3
- package/dist/env.js +1 -1
- package/dist/exceptions/database/dialects/mssql.js +2 -2
- package/dist/exceptions/database/dialects/mysql.js +6 -6
- package/dist/exceptions/database/record-not-unique.d.ts +1 -1
- package/dist/extensions.js +10 -10
- package/dist/flows.js +33 -31
- package/dist/logger.d.ts +1 -0
- package/dist/logger.js +32 -32
- package/dist/mailer.js +16 -16
- package/dist/messenger.js +4 -4
- package/dist/middleware/authenticate.d.ts +1 -1
- package/dist/middleware/authenticate.js +2 -2
- package/dist/middleware/cache.js +11 -11
- package/dist/middleware/collection-exists.js +4 -4
- package/dist/middleware/cors.js +8 -8
- package/dist/middleware/error-handler.js +2 -2
- package/dist/middleware/extract-token.js +3 -3
- package/dist/middleware/get-permissions.js +1 -1
- package/dist/middleware/graphql.js +12 -6
- package/dist/middleware/rate-limiter-global.js +5 -5
- package/dist/middleware/rate-limiter-ip.js +2 -2
- package/dist/middleware/respond.js +16 -16
- package/dist/middleware/sanitize-query.js +1 -1
- package/dist/middleware/schema.js +1 -1
- package/dist/middleware/use-collection.js +1 -1
- package/dist/middleware/validate-batch.js +1 -1
- package/dist/operations/exec/index.js +2 -2
- package/dist/rate-limiter.js +1 -1
- package/dist/request/validate-ip.js +2 -2
- package/dist/server.js +4 -4
- package/dist/services/activity.js +14 -14
- package/dist/services/assets.js +6 -6
- package/dist/services/authentication.js +9 -9
- package/dist/services/collections.js +9 -9
- package/dist/services/fields.js +5 -5
- package/dist/services/files.js +18 -18
- package/dist/services/graphql/index.js +170 -116
- package/dist/services/import-export.js +6 -6
- package/dist/services/items.js +6 -6
- package/dist/services/mail/index.js +5 -5
- package/dist/services/meta.js +1 -0
- package/dist/services/notifications.js +4 -4
- package/dist/services/relations.js +4 -4
- package/dist/services/revisions.js +3 -3
- package/dist/services/roles.js +5 -5
- package/dist/services/server.js +27 -27
- package/dist/services/shares.js +9 -9
- package/dist/services/specifications.js +5 -3
- package/dist/services/users.d.ts +1 -5
- package/dist/services/users.js +24 -27
- package/dist/storage/register-locations.js +1 -1
- package/dist/utils/apply-diff.js +12 -12
- package/dist/utils/apply-query.js +3 -2
- package/dist/utils/dynamic-import.js +1 -1
- package/dist/utils/generate-hash.js +1 -1
- package/dist/utils/get-ast-from-query.js +2 -2
- package/dist/utils/get-auth-providers.js +1 -1
- package/dist/utils/get-cache-headers.js +3 -3
- package/dist/utils/get-collection-from-alias.js +1 -0
- package/dist/utils/get-column-path.js +2 -1
- package/dist/utils/get-default-value.js +1 -1
- package/dist/utils/get-ip-from-req.js +2 -2
- package/dist/utils/get-permissions.js +11 -11
- package/dist/utils/get-schema.js +5 -5
- package/dist/utils/get-snapshot-diff.js +1 -1
- package/dist/utils/is-url-allowed.js +5 -2
- package/dist/utils/parse-image-metadata.js +3 -3
- package/dist/utils/reduce-schema.js +5 -5
- package/dist/utils/sanitize-query.js +26 -26
- package/dist/utils/should-skip-cache.js +13 -4
- package/dist/utils/strip-function.js +1 -1
- package/dist/utils/telemetry.d.ts +1 -0
- package/dist/utils/telemetry.js +30 -0
- package/dist/utils/validate-keys.js +1 -1
- package/dist/utils/validate-query.js +1 -1
- package/dist/utils/validate-storage.js +8 -8
- package/dist/webhooks.js +2 -2
- package/package.json +13 -13
- package/dist/utils/redact-header-cookies.d.ts +0 -1
- package/dist/utils/redact-header-cookies.js +0 -11
- package/dist/utils/track.d.ts +0 -1
- package/dist/utils/track.js +0 -81
- /package/dist/{utils/redact-header-cookies.test.d.ts → logger.test.d.ts} +0 -0
package/dist/extensions.js
CHANGED
|
@@ -64,7 +64,7 @@ function getExtensionManager() {
|
|
|
64
64
|
exports.getExtensionManager = getExtensionManager;
|
|
65
65
|
const defaultOptions = {
|
|
66
66
|
schedule: true,
|
|
67
|
-
watch: env_1.default
|
|
67
|
+
watch: env_1.default['EXTENSIONS_AUTO_RELOAD'] && env_1.default['NODE_ENV'] !== 'development',
|
|
68
68
|
};
|
|
69
69
|
class ExtensionManager {
|
|
70
70
|
isLoaded = false;
|
|
@@ -189,7 +189,7 @@ class ExtensionManager {
|
|
|
189
189
|
}
|
|
190
190
|
async load() {
|
|
191
191
|
try {
|
|
192
|
-
await (0, node_1.ensureExtensionDirs)(env_1.default
|
|
192
|
+
await (0, node_1.ensureExtensionDirs)(env_1.default['EXTENSIONS_PATH'], constants_1.NESTED_EXTENSION_TYPES);
|
|
193
193
|
this.extensions = await this.getExtensions();
|
|
194
194
|
}
|
|
195
195
|
catch (err) {
|
|
@@ -200,7 +200,7 @@ class ExtensionManager {
|
|
|
200
200
|
await this.registerEndpoints();
|
|
201
201
|
await this.registerOperations();
|
|
202
202
|
await this.registerBundles();
|
|
203
|
-
if (env_1.default
|
|
203
|
+
if (env_1.default['SERVE_APP']) {
|
|
204
204
|
this.appExtensions = await this.generateExtensionBundle();
|
|
205
205
|
}
|
|
206
206
|
this.isLoaded = true;
|
|
@@ -208,7 +208,7 @@ class ExtensionManager {
|
|
|
208
208
|
async unload() {
|
|
209
209
|
this.unregisterApiExtensions();
|
|
210
210
|
this.apiEmitter.offAll();
|
|
211
|
-
if (env_1.default
|
|
211
|
+
if (env_1.default['SERVE_APP']) {
|
|
212
212
|
this.appExtensions = null;
|
|
213
213
|
}
|
|
214
214
|
this.isLoaded = false;
|
|
@@ -217,7 +217,7 @@ class ExtensionManager {
|
|
|
217
217
|
if (!this.watcher) {
|
|
218
218
|
logger_1.default.info('Watching extensions for changes...');
|
|
219
219
|
const localExtensionPaths = constants_1.NESTED_EXTENSION_TYPES.flatMap((type) => {
|
|
220
|
-
const typeDir = path_1.default.posix.join((0, node_1.pathToRelativeUrl)(env_1.default
|
|
220
|
+
const typeDir = path_1.default.posix.join((0, node_1.pathToRelativeUrl)(env_1.default['EXTENSIONS_PATH']), (0, utils_1.pluralize)(type));
|
|
221
221
|
if ((0, utils_1.isIn)(type, constants_1.HYBRID_EXTENSION_TYPES)) {
|
|
222
222
|
return [path_1.default.posix.join(typeDir, '*', 'app.js'), path_1.default.posix.join(typeDir, '*', 'api.js')];
|
|
223
223
|
}
|
|
@@ -256,10 +256,10 @@ class ExtensionManager {
|
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
258
|
async getExtensions() {
|
|
259
|
-
const packageExtensions = await (0, node_1.getPackageExtensions)(env_1.default
|
|
260
|
-
const localPackageExtensions = await (0, node_1.resolvePackageExtensions)(env_1.default
|
|
261
|
-
const localExtensions = await (0, node_1.getLocalExtensions)(env_1.default
|
|
262
|
-
return [...packageExtensions, ...localPackageExtensions, ...localExtensions].filter((extension) => env_1.default
|
|
259
|
+
const packageExtensions = await (0, node_1.getPackageExtensions)(env_1.default['PACKAGE_FILE_LOCATION']);
|
|
260
|
+
const localPackageExtensions = await (0, node_1.resolvePackageExtensions)(env_1.default['EXTENSIONS_PATH']);
|
|
261
|
+
const localExtensions = await (0, node_1.getLocalExtensions)(env_1.default['EXTENSIONS_PATH']);
|
|
262
|
+
return [...packageExtensions, ...localPackageExtensions, ...localExtensions].filter((extension) => env_1.default['SERVE_APP'] || constants_1.APP_EXTENSION_TYPES.includes(extension.type) === false);
|
|
263
263
|
}
|
|
264
264
|
async generateExtensionBundle() {
|
|
265
265
|
const sharedDepsMapping = await this.getSharedDepsMapping(constants_1.APP_SHARED_DEPS);
|
|
@@ -292,7 +292,7 @@ class ExtensionManager {
|
|
|
292
292
|
const depRegex = new RegExp(`${(0, lodash_1.escapeRegExp)(dep.replace(/\//g, '_'))}\\.[0-9a-f]{8}\\.entry\\.js`);
|
|
293
293
|
const depName = appDir.find((file) => depRegex.test(file));
|
|
294
294
|
if (depName) {
|
|
295
|
-
const depUrl = new url_1.Url(env_1.default
|
|
295
|
+
const depUrl = new url_1.Url(env_1.default['PUBLIC_URL']).addPath('admin', 'assets', depName);
|
|
296
296
|
depsMapping[dep] = depUrl.toString({ rootRelative: true });
|
|
297
297
|
}
|
|
298
298
|
else {
|
package/dist/flows.js
CHANGED
|
@@ -77,7 +77,7 @@ class FlowManager {
|
|
|
77
77
|
this.reloadQueue = new job_queue_1.JobQueue();
|
|
78
78
|
const messenger = (0, messenger_1.getMessenger)();
|
|
79
79
|
messenger.subscribe('flows', (event) => {
|
|
80
|
-
if (event
|
|
80
|
+
if (event['type'] === 'reload') {
|
|
81
81
|
this.reloadQueue.enqueue(async () => {
|
|
82
82
|
if (this.isLoaded) {
|
|
83
83
|
await this.unload();
|
|
@@ -132,13 +132,13 @@ class FlowManager {
|
|
|
132
132
|
for (const flow of flowTrees) {
|
|
133
133
|
if (flow.trigger === 'event') {
|
|
134
134
|
let events = [];
|
|
135
|
-
if (flow.options?.scope) {
|
|
136
|
-
events = (0, utils_1.toArray)(flow.options
|
|
135
|
+
if (flow.options?.['scope']) {
|
|
136
|
+
events = (0, utils_1.toArray)(flow.options['scope'])
|
|
137
137
|
.map((scope) => {
|
|
138
138
|
if (['items.create', 'items.update', 'items.delete'].includes(scope)) {
|
|
139
|
-
if (!flow.options?.collections)
|
|
139
|
+
if (!flow.options?.['collections'])
|
|
140
140
|
return [];
|
|
141
|
-
return (0, utils_1.toArray)(flow.options
|
|
141
|
+
return (0, utils_1.toArray)(flow.options['collections']).map((collection) => {
|
|
142
142
|
if (collection.startsWith('directus_')) {
|
|
143
143
|
const action = scope.split('.')[1];
|
|
144
144
|
return collection.substring(9) + '.' + action;
|
|
@@ -150,11 +150,11 @@ class FlowManager {
|
|
|
150
150
|
})
|
|
151
151
|
.flat();
|
|
152
152
|
}
|
|
153
|
-
if (flow.options
|
|
153
|
+
if (flow.options['type'] === 'filter') {
|
|
154
154
|
const handler = (payload, meta, context) => this.executeFlow(flow, { payload, ...meta }, {
|
|
155
|
-
accountability: context
|
|
156
|
-
database: context
|
|
157
|
-
getSchema: context
|
|
155
|
+
accountability: context['accountability'],
|
|
156
|
+
database: context['database'],
|
|
157
|
+
getSchema: context['schema'] ? () => context['schema'] : get_schema_1.getSchema,
|
|
158
158
|
});
|
|
159
159
|
events.forEach((event) => emitter_1.default.onFilter(event, handler));
|
|
160
160
|
this.triggerHandlers.push({
|
|
@@ -162,11 +162,11 @@ class FlowManager {
|
|
|
162
162
|
events: events.map((event) => ({ type: 'filter', name: event, handler })),
|
|
163
163
|
});
|
|
164
164
|
}
|
|
165
|
-
else if (flow.options
|
|
165
|
+
else if (flow.options['type'] === 'action') {
|
|
166
166
|
const handler = (meta, context) => this.executeFlow(flow, meta, {
|
|
167
|
-
accountability: context
|
|
167
|
+
accountability: context['accountability'],
|
|
168
168
|
database: (0, database_1.default)(),
|
|
169
|
-
getSchema: context
|
|
169
|
+
getSchema: context['schema'] ? () => context['schema'] : get_schema_1.getSchema,
|
|
170
170
|
});
|
|
171
171
|
events.forEach((event) => emitter_1.default.onAction(event, handler));
|
|
172
172
|
this.triggerHandlers.push({
|
|
@@ -176,8 +176,8 @@ class FlowManager {
|
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
else if (flow.trigger === 'schedule') {
|
|
179
|
-
if ((0, node_cron_1.validate)(flow.options
|
|
180
|
-
const task = (0, node_cron_1.schedule)(flow.options
|
|
179
|
+
if ((0, node_cron_1.validate)(flow.options['cron'])) {
|
|
180
|
+
const task = (0, node_cron_1.schedule)(flow.options['cron'], async () => {
|
|
181
181
|
try {
|
|
182
182
|
await this.executeFlow(flow);
|
|
183
183
|
}
|
|
@@ -188,7 +188,7 @@ class FlowManager {
|
|
|
188
188
|
this.triggerHandlers.push({ id: flow.id, events: [{ type: flow.trigger, task }] });
|
|
189
189
|
}
|
|
190
190
|
else {
|
|
191
|
-
logger_1.default.warn(`Couldn't register cron trigger. Provided cron is invalid: ${flow.options
|
|
191
|
+
logger_1.default.warn(`Couldn't register cron trigger. Provided cron is invalid: ${flow.options['cron']}`);
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
else if (flow.trigger === 'operation') {
|
|
@@ -197,22 +197,23 @@ class FlowManager {
|
|
|
197
197
|
}
|
|
198
198
|
else if (flow.trigger === 'webhook') {
|
|
199
199
|
const handler = (data, context) => {
|
|
200
|
-
if (flow.options
|
|
200
|
+
if (flow.options['async']) {
|
|
201
201
|
this.executeFlow(flow, data, context);
|
|
202
|
+
return undefined;
|
|
202
203
|
}
|
|
203
204
|
else {
|
|
204
205
|
return this.executeFlow(flow, data, context);
|
|
205
206
|
}
|
|
206
207
|
};
|
|
207
|
-
const method = flow.options?.method ?? 'GET';
|
|
208
|
+
const method = flow.options?.['method'] ?? 'GET';
|
|
208
209
|
// Default return to $last for webhooks
|
|
209
|
-
flow.options
|
|
210
|
+
flow.options['return'] = flow.options['return'] ?? '$last';
|
|
210
211
|
this.webhookFlowHandlers[`${method}-${flow.id}`] = handler;
|
|
211
212
|
}
|
|
212
213
|
else if (flow.trigger === 'manual') {
|
|
213
214
|
const handler = (data, context) => {
|
|
214
|
-
const enabledCollections = flow.options?.collections ?? [];
|
|
215
|
-
const targetCollection = data?.body.collection;
|
|
215
|
+
const enabledCollections = flow.options?.['collections'] ?? [];
|
|
216
|
+
const targetCollection = data?.['body'].collection;
|
|
216
217
|
if (!targetCollection) {
|
|
217
218
|
logger_1.default.warn(`Manual trigger requires "collection" to be specified in the payload`);
|
|
218
219
|
throw new exceptions.ForbiddenException();
|
|
@@ -225,15 +226,16 @@ class FlowManager {
|
|
|
225
226
|
logger_1.default.warn(`Specified collection must be one of: ${enabledCollections.join(', ')}.`);
|
|
226
227
|
throw new exceptions.ForbiddenException();
|
|
227
228
|
}
|
|
228
|
-
if (flow.options
|
|
229
|
+
if (flow.options['async']) {
|
|
229
230
|
this.executeFlow(flow, data, context);
|
|
231
|
+
return undefined;
|
|
230
232
|
}
|
|
231
233
|
else {
|
|
232
234
|
return this.executeFlow(flow, data, context);
|
|
233
235
|
}
|
|
234
236
|
};
|
|
235
237
|
// Default return to $last for manual
|
|
236
|
-
flow.options
|
|
238
|
+
flow.options['return'] = '$last';
|
|
237
239
|
this.webhookFlowHandlers[`POST-${flow.id}`] = handler;
|
|
238
240
|
}
|
|
239
241
|
}
|
|
@@ -261,13 +263,13 @@ class FlowManager {
|
|
|
261
263
|
this.isLoaded = false;
|
|
262
264
|
}
|
|
263
265
|
async executeFlow(flow, data = null, context = {}) {
|
|
264
|
-
const database = context
|
|
265
|
-
const schema = context
|
|
266
|
+
const database = context['database'] ?? (0, database_1.default)();
|
|
267
|
+
const schema = context['schema'] ?? (await (0, get_schema_1.getSchema)({ database }));
|
|
266
268
|
const keyedData = {
|
|
267
269
|
[TRIGGER_KEY]: data,
|
|
268
270
|
[LAST_KEY]: data,
|
|
269
|
-
[ACCOUNTABILITY_KEY]: context?.accountability ?? null,
|
|
270
|
-
[ENV_KEY]: (0, lodash_1.pick)(env_1.default, env_1.default
|
|
271
|
+
[ACCOUNTABILITY_KEY]: context?.['accountability'] ?? null,
|
|
272
|
+
[ENV_KEY]: (0, lodash_1.pick)(env_1.default, env_1.default['FLOWS_ENV_ALLOW_LIST'] ? (0, utils_1.toArray)(env_1.default['FLOWS_ENV_ALLOW_LIST']) : []),
|
|
271
273
|
};
|
|
272
274
|
let nextOperation = flow.operation;
|
|
273
275
|
let lastOperationStatus = 'unknown';
|
|
@@ -285,7 +287,7 @@ class FlowManager {
|
|
|
285
287
|
knex: database,
|
|
286
288
|
schema: schema,
|
|
287
289
|
});
|
|
288
|
-
const accountability = context?.accountability;
|
|
290
|
+
const accountability = context?.['accountability'];
|
|
289
291
|
const activity = await activityService.createOne({
|
|
290
292
|
action: types_1.Action.RUN,
|
|
291
293
|
user: accountability?.user ?? null,
|
|
@@ -311,14 +313,14 @@ class FlowManager {
|
|
|
311
313
|
});
|
|
312
314
|
}
|
|
313
315
|
}
|
|
314
|
-
if (flow.trigger === 'event' && flow.options
|
|
316
|
+
if (flow.trigger === 'event' && flow.options['type'] === 'filter' && lastOperationStatus === 'reject') {
|
|
315
317
|
throw keyedData[LAST_KEY];
|
|
316
318
|
}
|
|
317
|
-
if (flow.options
|
|
319
|
+
if (flow.options['return'] === '$all') {
|
|
318
320
|
return keyedData;
|
|
319
321
|
}
|
|
320
|
-
else if (flow.options
|
|
321
|
-
return (0, micromustache_1.get)(keyedData, flow.options
|
|
322
|
+
else if (flow.options['return']) {
|
|
323
|
+
return (0, micromustache_1.get)(keyedData, flow.options['return']);
|
|
322
324
|
}
|
|
323
325
|
return undefined;
|
|
324
326
|
}
|
package/dist/logger.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/// <reference types="qs" />
|
|
2
2
|
import { LoggerOptions } from 'pino';
|
|
3
3
|
import type { RequestHandler } from 'express';
|
|
4
|
+
export declare const httpLoggerOptions: LoggerOptions;
|
|
4
5
|
declare const logger: import("pino").Logger<LoggerOptions & Record<string, any>>;
|
|
5
6
|
export declare const expressLogger: RequestHandler<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
|
|
6
7
|
export default logger;
|
package/dist/logger.js
CHANGED
|
@@ -26,30 +26,30 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.expressLogger = void 0;
|
|
29
|
+
exports.expressLogger = exports.httpLoggerOptions = void 0;
|
|
30
30
|
const utils_1 = require("@directus/shared/utils");
|
|
31
31
|
const lodash_1 = require("lodash");
|
|
32
32
|
const pino_1 = __importDefault(require("pino"));
|
|
33
33
|
const pino_http_1 = __importStar(require("pino-http"));
|
|
34
34
|
const url_1 = require("url");
|
|
35
35
|
const env_1 = __importDefault(require("./env"));
|
|
36
|
+
const constants_1 = require("./constants");
|
|
36
37
|
const get_config_from_env_1 = require("./utils/get-config-from-env");
|
|
37
|
-
const redact_header_cookies_1 = require("./utils/redact-header-cookies");
|
|
38
38
|
const pinoOptions = {
|
|
39
|
-
level: env_1.default
|
|
39
|
+
level: env_1.default['LOG_LEVEL'] || 'info',
|
|
40
40
|
redact: {
|
|
41
|
-
paths: ['req.headers.authorization',
|
|
42
|
-
censor:
|
|
41
|
+
paths: ['req.headers.authorization', 'req.headers.cookie'],
|
|
42
|
+
censor: constants_1.REDACT_TEXT,
|
|
43
43
|
},
|
|
44
44
|
};
|
|
45
|
-
|
|
46
|
-
level: env_1.default
|
|
45
|
+
exports.httpLoggerOptions = {
|
|
46
|
+
level: env_1.default['LOG_LEVEL'] || 'info',
|
|
47
47
|
redact: {
|
|
48
|
-
paths: ['req.headers.authorization',
|
|
49
|
-
censor:
|
|
48
|
+
paths: ['req.headers.authorization', 'req.headers.cookie'],
|
|
49
|
+
censor: constants_1.REDACT_TEXT,
|
|
50
50
|
},
|
|
51
51
|
};
|
|
52
|
-
if (env_1.default
|
|
52
|
+
if (env_1.default['LOG_STYLE'] !== 'raw') {
|
|
53
53
|
pinoOptions.transport = {
|
|
54
54
|
target: 'pino-pretty',
|
|
55
55
|
options: {
|
|
@@ -57,7 +57,7 @@ if (env_1.default.LOG_STYLE !== 'raw') {
|
|
|
57
57
|
sync: true,
|
|
58
58
|
},
|
|
59
59
|
};
|
|
60
|
-
httpLoggerOptions.transport = {
|
|
60
|
+
exports.httpLoggerOptions.transport = {
|
|
61
61
|
target: 'pino-http-print',
|
|
62
62
|
options: {
|
|
63
63
|
all: true,
|
|
@@ -70,11 +70,26 @@ if (env_1.default.LOG_STYLE !== 'raw') {
|
|
|
70
70
|
},
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
|
+
if (env_1.default['LOG_STYLE'] === 'raw') {
|
|
74
|
+
exports.httpLoggerOptions.redact = {
|
|
75
|
+
paths: ['req.headers.authorization', 'req.headers.cookie', 'res.headers'],
|
|
76
|
+
censor: (value, pathParts) => {
|
|
77
|
+
const path = pathParts.join('.');
|
|
78
|
+
if (path === 'res.headers') {
|
|
79
|
+
if ('set-cookie' in value) {
|
|
80
|
+
value['set-cookie'] = constants_1.REDACT_TEXT;
|
|
81
|
+
}
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
return constants_1.REDACT_TEXT;
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
73
88
|
const loggerEnvConfig = (0, get_config_from_env_1.getConfigFromEnv)('LOGGER_', 'LOGGER_HTTP');
|
|
74
89
|
// Expose custom log levels into formatter function
|
|
75
|
-
if (loggerEnvConfig
|
|
90
|
+
if (loggerEnvConfig['levels']) {
|
|
76
91
|
const customLogLevels = {};
|
|
77
|
-
for (const el of (0, utils_1.toArray)(loggerEnvConfig
|
|
92
|
+
for (const el of (0, utils_1.toArray)(loggerEnvConfig['levels'])) {
|
|
78
93
|
const key_val = el.split(':');
|
|
79
94
|
customLogLevels[key_val[0].trim()] = key_val[1].trim();
|
|
80
95
|
}
|
|
@@ -86,7 +101,7 @@ if (loggerEnvConfig.levels) {
|
|
|
86
101
|
};
|
|
87
102
|
},
|
|
88
103
|
};
|
|
89
|
-
httpLoggerOptions.formatters = {
|
|
104
|
+
exports.httpLoggerOptions.formatters = {
|
|
90
105
|
level(label, number) {
|
|
91
106
|
return {
|
|
92
107
|
severity: customLogLevels[label] || 'info',
|
|
@@ -94,41 +109,26 @@ if (loggerEnvConfig.levels) {
|
|
|
94
109
|
};
|
|
95
110
|
},
|
|
96
111
|
};
|
|
97
|
-
delete loggerEnvConfig
|
|
112
|
+
delete loggerEnvConfig['levels'];
|
|
98
113
|
}
|
|
99
114
|
const logger = (0, pino_1.default)((0, lodash_1.merge)(pinoOptions, loggerEnvConfig));
|
|
100
115
|
const httpLoggerEnvConfig = (0, get_config_from_env_1.getConfigFromEnv)('LOGGER_HTTP', ['LOGGER_HTTP_LOGGER']);
|
|
101
116
|
exports.expressLogger = (0, pino_http_1.default)({
|
|
102
|
-
logger: (0, pino_1.default)((0, lodash_1.merge)(httpLoggerOptions, loggerEnvConfig)),
|
|
117
|
+
logger: (0, pino_1.default)((0, lodash_1.merge)(exports.httpLoggerOptions, loggerEnvConfig)),
|
|
103
118
|
...httpLoggerEnvConfig,
|
|
104
119
|
serializers: {
|
|
105
120
|
req(request) {
|
|
106
121
|
const output = pino_http_1.stdSerializers.req(request);
|
|
107
122
|
output.url = redactQuery(output.url);
|
|
108
|
-
if (output.headers?.cookie) {
|
|
109
|
-
output.headers.cookie = (0, redact_header_cookies_1.redactHeaderCookie)(output.headers.cookie, [
|
|
110
|
-
'access_token',
|
|
111
|
-
`${env_1.default.REFRESH_TOKEN_COOKIE_NAME}`,
|
|
112
|
-
]);
|
|
113
|
-
}
|
|
114
123
|
return output;
|
|
115
124
|
},
|
|
116
|
-
res(response) {
|
|
117
|
-
if (response.headers?.['set-cookie']) {
|
|
118
|
-
response.headers['set-cookie'] = (0, redact_header_cookies_1.redactHeaderCookie)(response.headers['set-cookie'], [
|
|
119
|
-
'access_token',
|
|
120
|
-
`${env_1.default.REFRESH_TOKEN_COOKIE_NAME}`,
|
|
121
|
-
]);
|
|
122
|
-
}
|
|
123
|
-
return response;
|
|
124
|
-
},
|
|
125
125
|
},
|
|
126
126
|
});
|
|
127
127
|
exports.default = logger;
|
|
128
128
|
function redactQuery(originalPath) {
|
|
129
129
|
const url = new url_1.URL(originalPath, 'http://example.com/');
|
|
130
130
|
if (url.searchParams.has('access_token')) {
|
|
131
|
-
url.searchParams.set('access_token',
|
|
131
|
+
url.searchParams.set('access_token', constants_1.REDACT_TEXT);
|
|
132
132
|
}
|
|
133
133
|
return url.pathname + url.search;
|
|
134
134
|
}
|
package/dist/mailer.js
CHANGED
|
@@ -11,12 +11,12 @@ let transporter;
|
|
|
11
11
|
function getMailer() {
|
|
12
12
|
if (transporter)
|
|
13
13
|
return transporter;
|
|
14
|
-
const transportName = env_1.default
|
|
14
|
+
const transportName = env_1.default['EMAIL_TRANSPORT'].toLowerCase();
|
|
15
15
|
if (transportName === 'sendmail') {
|
|
16
16
|
transporter = nodemailer_1.default.createTransport({
|
|
17
17
|
sendmail: true,
|
|
18
|
-
newline: env_1.default
|
|
19
|
-
path: env_1.default
|
|
18
|
+
newline: env_1.default['EMAIL_SENDMAIL_NEW_LINE'] || 'unix',
|
|
19
|
+
path: env_1.default['EMAIL_SENDMAIL_PATH'] || '/usr/sbin/sendmail',
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
22
|
else if (transportName === 'ses') {
|
|
@@ -29,20 +29,20 @@ function getMailer() {
|
|
|
29
29
|
}
|
|
30
30
|
else if (transportName === 'smtp') {
|
|
31
31
|
let auth = false;
|
|
32
|
-
if (env_1.default
|
|
32
|
+
if (env_1.default['EMAIL_SMTP_USER'] || env_1.default['EMAIL_SMTP_PASSWORD']) {
|
|
33
33
|
auth = {
|
|
34
|
-
user: env_1.default
|
|
35
|
-
pass: env_1.default
|
|
34
|
+
user: env_1.default['EMAIL_SMTP_USER'],
|
|
35
|
+
pass: env_1.default['EMAIL_SMTP_PASSWORD'],
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
const tls = (0, get_config_from_env_1.getConfigFromEnv)('EMAIL_SMTP_TLS_');
|
|
39
39
|
transporter = nodemailer_1.default.createTransport({
|
|
40
|
-
name: env_1.default
|
|
41
|
-
pool: env_1.default
|
|
42
|
-
host: env_1.default
|
|
43
|
-
port: env_1.default
|
|
44
|
-
secure: env_1.default
|
|
45
|
-
ignoreTLS: env_1.default
|
|
40
|
+
name: env_1.default['EMAIL_SMTP_NAME'],
|
|
41
|
+
pool: env_1.default['EMAIL_SMTP_POOL'],
|
|
42
|
+
host: env_1.default['EMAIL_SMTP_HOST'],
|
|
43
|
+
port: env_1.default['EMAIL_SMTP_PORT'],
|
|
44
|
+
secure: env_1.default['EMAIL_SMTP_SECURE'],
|
|
45
|
+
ignoreTLS: env_1.default['EMAIL_SMTP_IGNORE_TLS'],
|
|
46
46
|
auth,
|
|
47
47
|
tls,
|
|
48
48
|
});
|
|
@@ -51,16 +51,16 @@ function getMailer() {
|
|
|
51
51
|
const mg = require('nodemailer-mailgun-transport');
|
|
52
52
|
transporter = nodemailer_1.default.createTransport(mg({
|
|
53
53
|
auth: {
|
|
54
|
-
api_key: env_1.default
|
|
55
|
-
domain: env_1.default
|
|
54
|
+
api_key: env_1.default['EMAIL_MAILGUN_API_KEY'],
|
|
55
|
+
domain: env_1.default['EMAIL_MAILGUN_DOMAIN'],
|
|
56
56
|
},
|
|
57
|
-
host: env_1.default
|
|
57
|
+
host: env_1.default['EMAIL_MAILGUN_HOST'] || 'api.mailgun.net',
|
|
58
58
|
}));
|
|
59
59
|
}
|
|
60
60
|
else if (transportName === 'sendgrid') {
|
|
61
61
|
const sg = require('nodemailer-sendgrid');
|
|
62
62
|
transporter = nodemailer_1.default.createTransport(sg({
|
|
63
|
-
apiKey: env_1.default
|
|
63
|
+
apiKey: env_1.default['EMAIL_SENDGRID_API_KEY'],
|
|
64
64
|
}));
|
|
65
65
|
}
|
|
66
66
|
else {
|
package/dist/messenger.js
CHANGED
|
@@ -30,9 +30,9 @@ class MessengerRedis {
|
|
|
30
30
|
sub;
|
|
31
31
|
constructor() {
|
|
32
32
|
const config = (0, get_config_from_env_1.getConfigFromEnv)('MESSENGER_REDIS');
|
|
33
|
-
this.pub = new ioredis_1.default(env_1.default
|
|
34
|
-
this.sub = new ioredis_1.default(env_1.default
|
|
35
|
-
this.namespace = env_1.default
|
|
33
|
+
this.pub = new ioredis_1.default(env_1.default['MESSENGER_REDIS'] ?? config);
|
|
34
|
+
this.sub = new ioredis_1.default(env_1.default['MESSENGER_REDIS'] ?? config);
|
|
35
|
+
this.namespace = env_1.default['MESSENGER_NAMESPACE'] ?? 'directus';
|
|
36
36
|
}
|
|
37
37
|
publish(channel, payload) {
|
|
38
38
|
this.pub.publish(`${this.namespace}:${channel}`, JSON.stringify(payload));
|
|
@@ -55,7 +55,7 @@ let messenger;
|
|
|
55
55
|
function getMessenger() {
|
|
56
56
|
if (messenger)
|
|
57
57
|
return messenger;
|
|
58
|
-
if (env_1.default
|
|
58
|
+
if (env_1.default['MESSENGER_STORE'] === 'redis') {
|
|
59
59
|
messenger = new MessengerRedis();
|
|
60
60
|
}
|
|
61
61
|
else {
|
|
@@ -3,6 +3,6 @@ import type { NextFunction, Request, Response } from 'express';
|
|
|
3
3
|
/**
|
|
4
4
|
* Verify the passed JWT and assign the user ID and role to `req`
|
|
5
5
|
*/
|
|
6
|
-
export declare const handler: (req: Request,
|
|
6
|
+
export declare const handler: (req: Request, _res: Response, next: NextFunction) => Promise<void>;
|
|
7
7
|
declare const _default: (req: Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: NextFunction) => Promise<void>;
|
|
8
8
|
export default _default;
|
|
@@ -16,7 +16,7 @@ const jwt_1 = require("../utils/jwt");
|
|
|
16
16
|
/**
|
|
17
17
|
* Verify the passed JWT and assign the user ID and role to `req`
|
|
18
18
|
*/
|
|
19
|
-
const handler = async (req,
|
|
19
|
+
const handler = async (req, _res, next) => {
|
|
20
20
|
const defaultAccountability = {
|
|
21
21
|
user: null,
|
|
22
22
|
role: null,
|
|
@@ -45,7 +45,7 @@ const handler = async (req, res, next) => {
|
|
|
45
45
|
req.accountability = defaultAccountability;
|
|
46
46
|
if (req.token) {
|
|
47
47
|
if ((0, is_directus_jwt_1.default)(req.token)) {
|
|
48
|
-
const payload = (0, jwt_1.verifyAccessJWT)(req.token, env_1.default
|
|
48
|
+
const payload = (0, jwt_1.verifyAccessJWT)(req.token, env_1.default['SECRET']);
|
|
49
49
|
req.accountability.role = payload.role;
|
|
50
50
|
req.accountability.admin = payload.admin_access === true || payload.admin_access == 1;
|
|
51
51
|
req.accountability.app = payload.app_access === true || payload.app_access == 1;
|
package/dist/middleware/cache.js
CHANGED
|
@@ -14,13 +14,13 @@ const checkCacheMiddleware = (0, async_handler_1.default)(async (req, res, next)
|
|
|
14
14
|
const { cache } = (0, cache_1.getCache)();
|
|
15
15
|
if (req.method.toLowerCase() !== 'get' && req.originalUrl?.startsWith('/graphql') === false)
|
|
16
16
|
return next();
|
|
17
|
-
if (env_1.default
|
|
17
|
+
if (env_1.default['CACHE_ENABLED'] !== true)
|
|
18
18
|
return next();
|
|
19
19
|
if (!cache)
|
|
20
20
|
return next();
|
|
21
21
|
if ((0, should_skip_cache_1.shouldSkipCache)(req)) {
|
|
22
|
-
if (env_1.default
|
|
23
|
-
res.setHeader(`${env_1.default
|
|
22
|
+
if (env_1.default['CACHE_STATUS_HEADER'])
|
|
23
|
+
res.setHeader(`${env_1.default['CACHE_STATUS_HEADER']}`, 'MISS');
|
|
24
24
|
return next();
|
|
25
25
|
}
|
|
26
26
|
const key = (0, get_cache_key_1.getCacheKey)(req);
|
|
@@ -30,8 +30,8 @@ const checkCacheMiddleware = (0, async_handler_1.default)(async (req, res, next)
|
|
|
30
30
|
}
|
|
31
31
|
catch (err) {
|
|
32
32
|
logger_1.default.warn(err, `[cache] Couldn't read key ${key}. ${err.message}`);
|
|
33
|
-
if (env_1.default
|
|
34
|
-
res.setHeader(`${env_1.default
|
|
33
|
+
if (env_1.default['CACHE_STATUS_HEADER'])
|
|
34
|
+
res.setHeader(`${env_1.default['CACHE_STATUS_HEADER']}`, 'MISS');
|
|
35
35
|
return next();
|
|
36
36
|
}
|
|
37
37
|
if (cachedData) {
|
|
@@ -41,20 +41,20 @@ const checkCacheMiddleware = (0, async_handler_1.default)(async (req, res, next)
|
|
|
41
41
|
}
|
|
42
42
|
catch (err) {
|
|
43
43
|
logger_1.default.warn(err, `[cache] Couldn't read key ${`${key}__expires_at`}. ${err.message}`);
|
|
44
|
-
if (env_1.default
|
|
45
|
-
res.setHeader(`${env_1.default
|
|
44
|
+
if (env_1.default['CACHE_STATUS_HEADER'])
|
|
45
|
+
res.setHeader(`${env_1.default['CACHE_STATUS_HEADER']}`, 'MISS');
|
|
46
46
|
return next();
|
|
47
47
|
}
|
|
48
48
|
const cacheTTL = cacheExpiryDate ? cacheExpiryDate - Date.now() : undefined;
|
|
49
49
|
res.setHeader('Cache-Control', (0, get_cache_headers_1.getCacheControlHeader)(req, cacheTTL, true, true));
|
|
50
50
|
res.setHeader('Vary', 'Origin, Cache-Control');
|
|
51
|
-
if (env_1.default
|
|
52
|
-
res.setHeader(`${env_1.default
|
|
51
|
+
if (env_1.default['CACHE_STATUS_HEADER'])
|
|
52
|
+
res.setHeader(`${env_1.default['CACHE_STATUS_HEADER']}`, 'HIT');
|
|
53
53
|
return res.json(cachedData);
|
|
54
54
|
}
|
|
55
55
|
else {
|
|
56
|
-
if (env_1.default
|
|
57
|
-
res.setHeader(`${env_1.default
|
|
56
|
+
if (env_1.default['CACHE_STATUS_HEADER'])
|
|
57
|
+
res.setHeader(`${env_1.default['CACHE_STATUS_HEADER']}`, 'MISS');
|
|
58
58
|
return next();
|
|
59
59
|
}
|
|
60
60
|
});
|
|
@@ -9,13 +9,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
9
9
|
const collections_1 = require("../database/system-data/collections");
|
|
10
10
|
const exceptions_1 = require("../exceptions");
|
|
11
11
|
const async_handler_1 = __importDefault(require("../utils/async-handler"));
|
|
12
|
-
const collectionExists = (0, async_handler_1.default)(async (req,
|
|
13
|
-
if (!req.params
|
|
12
|
+
const collectionExists = (0, async_handler_1.default)(async (req, _res, next) => {
|
|
13
|
+
if (!req.params['collection'])
|
|
14
14
|
return next();
|
|
15
|
-
if (req.params
|
|
15
|
+
if (req.params['collection'] in req.schema.collections === false) {
|
|
16
16
|
throw new exceptions_1.ForbiddenException();
|
|
17
17
|
}
|
|
18
|
-
req.collection = req.params
|
|
18
|
+
req.collection = req.params['collection'];
|
|
19
19
|
if (req.collection.startsWith('directus_')) {
|
|
20
20
|
const systemRow = collections_1.systemCollectionRows.find((collection) => {
|
|
21
21
|
return collection?.collection === req.collection;
|
package/dist/middleware/cors.js
CHANGED
|
@@ -5,15 +5,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const cors_1 = __importDefault(require("cors"));
|
|
7
7
|
const env_1 = __importDefault(require("../env"));
|
|
8
|
-
let corsMiddleware = (
|
|
9
|
-
if (env_1.default
|
|
8
|
+
let corsMiddleware = (_req, _res, next) => next();
|
|
9
|
+
if (env_1.default['CORS_ENABLED'] === true) {
|
|
10
10
|
corsMiddleware = (0, cors_1.default)({
|
|
11
|
-
origin: env_1.default
|
|
12
|
-
methods: env_1.default
|
|
13
|
-
allowedHeaders: env_1.default
|
|
14
|
-
exposedHeaders: env_1.default
|
|
15
|
-
credentials: env_1.default
|
|
16
|
-
maxAge: env_1.default
|
|
11
|
+
origin: env_1.default['CORS_ORIGIN'] || true,
|
|
12
|
+
methods: env_1.default['CORS_METHODS'] || 'GET,POST,PATCH,DELETE',
|
|
13
|
+
allowedHeaders: env_1.default['CORS_ALLOWED_HEADERS'],
|
|
14
|
+
exposedHeaders: env_1.default['CORS_EXPOSED_HEADERS'],
|
|
15
|
+
credentials: env_1.default['CORS_CREDENTIALS'] || undefined,
|
|
16
|
+
maxAge: env_1.default['CORS_MAX_AGE'] || undefined,
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
19
|
exports.default = corsMiddleware;
|
|
@@ -32,7 +32,7 @@ const errorHandler = (err, req, res, _next) => {
|
|
|
32
32
|
res.status(status);
|
|
33
33
|
}
|
|
34
34
|
for (const err of errors) {
|
|
35
|
-
if (env_1.default
|
|
35
|
+
if (env_1.default['NODE_ENV'] === 'development') {
|
|
36
36
|
err.extensions = {
|
|
37
37
|
...(err.extensions || {}),
|
|
38
38
|
stack: err.stack,
|
|
@@ -49,7 +49,7 @@ const errorHandler = (err, req, res, _next) => {
|
|
|
49
49
|
},
|
|
50
50
|
});
|
|
51
51
|
if (err instanceof exceptions_2.MethodNotAllowedException) {
|
|
52
|
-
res.header('Allow', err.extensions
|
|
52
|
+
res.header('Allow', err.extensions['allow'].join(', '));
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
else {
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
* and store in req.token
|
|
9
9
|
*/
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
const extractToken = (req,
|
|
11
|
+
const extractToken = (req, _res, next) => {
|
|
12
12
|
let token = null;
|
|
13
|
-
if (req.query && req.query
|
|
14
|
-
token = req.query
|
|
13
|
+
if (req.query && req.query['access_token']) {
|
|
14
|
+
token = req.query['access_token'];
|
|
15
15
|
}
|
|
16
16
|
if (req.headers && req.headers.authorization) {
|
|
17
17
|
const parts = req.headers.authorization.split(' ');
|
|
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const async_handler_1 = __importDefault(require("../utils/async-handler"));
|
|
7
7
|
const get_permissions_1 = require("../utils/get-permissions");
|
|
8
|
-
const getPermissions = (0, async_handler_1.default)(async (req,
|
|
8
|
+
const getPermissions = (0, async_handler_1.default)(async (req, _res, next) => {
|
|
9
9
|
if (!req.accountability) {
|
|
10
10
|
throw new Error('getPermissions middleware needs to be called after authenticate');
|
|
11
11
|
}
|