directus 9.5.0 → 9.6.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 (38) hide show
  1. package/dist/auth/drivers/ldap.d.ts +0 -1
  2. package/dist/auth/drivers/ldap.js +54 -60
  3. package/dist/auth/drivers/openid.js +6 -6
  4. package/dist/cli/commands/init/index.js +8 -0
  5. package/dist/cli/utils/create-env/env-stub.liquid +1 -0
  6. package/dist/controllers/files.js +4 -1
  7. package/dist/database/index.js +33 -4
  8. package/dist/database/migrations/20220303A-remove-default-project-color.d.ts +3 -0
  9. package/dist/database/migrations/20220303A-remove-default-project-color.js +22 -0
  10. package/dist/database/run-ast.d.ts +1 -1
  11. package/dist/database/run-ast.js +42 -35
  12. package/dist/database/system-data/app-access-permissions/app-access-permissions.yaml +8 -2
  13. package/dist/database/system-data/fields/collections.yaml +2 -0
  14. package/dist/database/system-data/fields/settings.yaml +19 -3
  15. package/dist/env.js +3 -0
  16. package/dist/extensions.js +0 -2
  17. package/dist/middleware/authenticate.d.ts +5 -3
  18. package/dist/middleware/authenticate.js +22 -39
  19. package/dist/middleware/extract-token.js +1 -1
  20. package/dist/server.js +5 -2
  21. package/dist/services/authorization.js +2 -1
  22. package/dist/services/collections.js +25 -27
  23. package/dist/services/fields.js +16 -16
  24. package/dist/services/mail/templates/base.liquid +2 -2
  25. package/dist/services/payload.js +7 -3
  26. package/dist/services/relations.js +4 -0
  27. package/dist/services/utils.js +10 -0
  28. package/dist/utils/apply-query.js +2 -24
  29. package/dist/utils/get-permissions.js +1 -1
  30. package/dist/utils/is-directus-jwt.js +4 -21
  31. package/dist/utils/jwt.d.ts +2 -0
  32. package/dist/utils/jwt.js +49 -0
  33. package/dist/utils/md.js +1 -1
  34. package/dist/utils/merge-permissions.js +18 -6
  35. package/example.env +1 -0
  36. package/package.json +24 -22
  37. package/dist/__mocks__/cache.d.ts +0 -6
  38. package/dist/__mocks__/cache.js +0 -8
@@ -1,39 +1,23 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
- }) : (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- o[k2] = m[k];
8
- }));
9
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
- Object.defineProperty(o, "default", { enumerable: true, value: v });
11
- }) : function(o, v) {
12
- o["default"] = v;
13
- });
14
- var __importStar = (this && this.__importStar) || function (mod) {
15
- if (mod && mod.__esModule) return mod;
16
- var result = {};
17
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
- __setModuleDefault(result, mod);
19
- return result;
20
- };
21
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
22
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
23
4
  };
24
5
  Object.defineProperty(exports, "__esModule", { value: true });
25
- const jsonwebtoken_1 = __importStar(require("jsonwebtoken"));
6
+ exports.handler = void 0;
7
+ const lodash_1 = require("lodash");
26
8
  const database_1 = __importDefault(require("../database"));
9
+ const emitter_1 = __importDefault(require("../emitter"));
27
10
  const env_1 = __importDefault(require("../env"));
28
11
  const exceptions_1 = require("../exceptions");
29
12
  const async_handler_1 = __importDefault(require("../utils/async-handler"));
30
13
  const get_ip_from_req_1 = require("../utils/get-ip-from-req");
31
14
  const is_directus_jwt_1 = __importDefault(require("../utils/is-directus-jwt"));
15
+ const jwt_1 = require("../utils/jwt");
32
16
  /**
33
17
  * Verify the passed JWT and assign the user ID and role to `req`
34
18
  */
35
- const authenticate = (0, async_handler_1.default)(async (req, res, next) => {
36
- req.accountability = {
19
+ const handler = async (req, res, next) => {
20
+ const defaultAccountability = {
37
21
  user: null,
38
22
  role: null,
39
23
  admin: false,
@@ -42,23 +26,21 @@ const authenticate = (0, async_handler_1.default)(async (req, res, next) => {
42
26
  userAgent: req.get('user-agent'),
43
27
  };
44
28
  const database = (0, database_1.default)();
29
+ const customAccountability = await emitter_1.default.emitFilter('authenticate', defaultAccountability, {
30
+ req,
31
+ }, {
32
+ database,
33
+ schema: null,
34
+ accountability: null,
35
+ });
36
+ if (customAccountability && (0, lodash_1.isEqual)(customAccountability, defaultAccountability) === false) {
37
+ req.accountability = customAccountability;
38
+ return next();
39
+ }
40
+ req.accountability = defaultAccountability;
45
41
  if (req.token) {
46
42
  if ((0, is_directus_jwt_1.default)(req.token)) {
47
- let payload;
48
- try {
49
- payload = jsonwebtoken_1.default.verify(req.token, env_1.default.SECRET, { issuer: 'directus' });
50
- }
51
- catch (err) {
52
- if (err instanceof jsonwebtoken_1.TokenExpiredError) {
53
- throw new exceptions_1.InvalidCredentialsException('Token expired.');
54
- }
55
- else if (err instanceof jsonwebtoken_1.JsonWebTokenError) {
56
- throw new exceptions_1.InvalidCredentialsException('Token invalid.');
57
- }
58
- else {
59
- throw err;
60
- }
61
- }
43
+ const payload = (0, jwt_1.verifyAccessJWT)(req.token, env_1.default.SECRET);
62
44
  req.accountability.share = payload.share;
63
45
  req.accountability.share_scope = payload.share_scope;
64
46
  req.accountability.user = payload.id;
@@ -87,5 +69,6 @@ const authenticate = (0, async_handler_1.default)(async (req, res, next) => {
87
69
  }
88
70
  }
89
71
  return next();
90
- });
91
- exports.default = authenticate;
72
+ };
73
+ exports.handler = handler;
74
+ exports.default = (0, async_handler_1.default)(exports.handler);
@@ -15,7 +15,7 @@ const extractToken = (req, res, next) => {
15
15
  }
16
16
  if (req.headers && req.headers.authorization) {
17
17
  const parts = req.headers.authorization.split(' ');
18
- if (parts.length === 2 && parts[0] === 'Bearer') {
18
+ if (parts.length === 2 && parts[0].toLowerCase() === 'bearer') {
19
19
  token = parts[1];
20
20
  }
21
21
  }
package/dist/server.js CHANGED
@@ -36,8 +36,10 @@ const logger_1 = __importDefault(require("./logger"));
36
36
  const emitter_1 = __importDefault(require("./emitter"));
37
37
  const update_check_1 = __importDefault(require("update-check"));
38
38
  const package_json_1 = __importDefault(require("../package.json"));
39
+ const get_config_from_env_1 = require("./utils/get-config-from-env");
39
40
  async function createServer() {
40
41
  const server = http.createServer(await (0, app_1.default)());
42
+ Object.assign(server, (0, get_config_from_env_1.getConfigFromEnv)('SERVER_'));
41
43
  server.on('request', function (req, res) {
42
44
  const startTime = process.hrtime();
43
45
  const complete = (0, lodash_1.once)(function (finished) {
@@ -124,9 +126,10 @@ async function createServer() {
124
126
  exports.createServer = createServer;
125
127
  async function startServer() {
126
128
  const server = await createServer();
129
+ const host = env_1.default.HOST;
127
130
  const port = env_1.default.PORT;
128
131
  server
129
- .listen(port, () => {
132
+ .listen(port, host, () => {
130
133
  (0, update_check_1.default)(package_json_1.default)
131
134
  .then((update) => {
132
135
  if (update) {
@@ -136,7 +139,7 @@ async function startServer() {
136
139
  .catch(() => {
137
140
  // No need to log/warn here. The update message is only an informative nice-to-have
138
141
  });
139
- logger_1.default.info(`Server started at http://localhost:${port}`);
142
+ logger_1.default.info(`Server started at http://${host}:${port}`);
140
143
  emitter_1.default.emitAction('server.start', { server }, {
141
144
  database: (0, database_1.default)(),
142
145
  schema: null,
@@ -11,6 +11,7 @@ const exceptions_2 = require("@directus/shared/exceptions");
11
11
  const utils_1 = require("@directus/shared/utils");
12
12
  const items_1 = require("./items");
13
13
  const payload_1 = require("./payload");
14
+ const strip_function_1 = require("../utils/strip-function");
14
15
  class AuthorizationService {
15
16
  constructor(options) {
16
17
  this.knex = options.knex || (0, database_1.default)();
@@ -97,7 +98,7 @@ class AuthorizationService {
97
98
  }
98
99
  if (allowedFields.includes('*'))
99
100
  continue;
100
- const fieldKey = childNode.name;
101
+ const fieldKey = (0, strip_function_1.stripFunction)(childNode.name);
101
102
  if (allowedFields.includes(fieldKey) === false) {
102
103
  throw new exceptions_1.ForbiddenException();
103
104
  }
@@ -66,24 +66,7 @@ class CollectionsService {
66
66
  // permission problems. This might not work reliably in MySQL, as it doesn't support DDL in
67
67
  // transactions.
68
68
  await this.knex.transaction(async (trx) => {
69
- if (payload.meta) {
70
- const collectionItemsService = new items_1.ItemsService('directus_collections', {
71
- knex: trx,
72
- accountability: this.accountability,
73
- schema: this.schema,
74
- });
75
- await collectionItemsService.createOne({
76
- ...payload.meta,
77
- collection: payload.collection,
78
- });
79
- }
80
69
  if (payload.schema) {
81
- const fieldsService = new fields_1.FieldsService({ knex: trx, schema: this.schema });
82
- const fieldItemsService = new items_1.ItemsService('directus_fields', {
83
- knex: trx,
84
- accountability: this.accountability,
85
- schema: this.schema,
86
- });
87
70
  // Directus heavily relies on the primary key of a collection, so we have to make sure that
88
71
  // every collection that is created has a primary key. If no primary key field is created
89
72
  // while making the collection, we default to an auto incremented id named `id`
@@ -114,18 +97,33 @@ class CollectionsService {
114
97
  }
115
98
  return field;
116
99
  });
117
- await trx.transaction(async (schemaTrx) => {
118
- await schemaTrx.schema.createTable(payload.collection, (table) => {
119
- for (const field of payload.fields) {
120
- if (field.type && constants_1.ALIAS_TYPES.includes(field.type) === false) {
121
- fieldsService.addColumnToTable(table, field);
122
- }
100
+ const fieldsService = new fields_1.FieldsService({ knex: trx, schema: this.schema });
101
+ await trx.schema.createTable(payload.collection, (table) => {
102
+ for (const field of payload.fields) {
103
+ if (field.type && constants_1.ALIAS_TYPES.includes(field.type) === false) {
104
+ fieldsService.addColumnToTable(table, field);
123
105
  }
124
- });
106
+ }
107
+ });
108
+ const fieldItemsService = new items_1.ItemsService('directus_fields', {
109
+ knex: trx,
110
+ accountability: this.accountability,
111
+ schema: this.schema,
125
112
  });
126
113
  const fieldPayloads = payload.fields.filter((field) => field.meta).map((field) => field.meta);
127
114
  await fieldItemsService.createMany(fieldPayloads);
128
115
  }
116
+ if (payload.meta) {
117
+ const collectionItemsService = new items_1.ItemsService('directus_collections', {
118
+ knex: trx,
119
+ accountability: this.accountability,
120
+ schema: this.schema,
121
+ });
122
+ await collectionItemsService.createOne({
123
+ ...payload.meta,
124
+ collection: payload.collection,
125
+ });
126
+ }
129
127
  return payload.collection;
130
128
  });
131
129
  if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
@@ -318,6 +316,9 @@ class CollectionsService {
318
316
  }
319
317
  await this.knex.transaction(async (trx) => {
320
318
  var _a;
319
+ if (collectionToBeDeleted.schema) {
320
+ await trx.schema.dropTable(collectionKey);
321
+ }
321
322
  // Make sure this collection isn't used as a group in any other collections
322
323
  await trx('directus_collections').update({ group: null }).where({ group: collectionKey });
323
324
  if (collectionToBeDeleted.meta) {
@@ -373,9 +374,6 @@ class CollectionsService {
373
374
  .update({ one_allowed_collections: newAllowedCollections })
374
375
  .where({ id: relation.meta.id });
375
376
  }
376
- await trx.transaction(async (schemaTrx) => {
377
- await schemaTrx.schema.dropTable(collectionKey);
378
- });
379
377
  }
380
378
  });
381
379
  if (this.cache && env_1.default.CACHE_AUTO_PURGE && (opts === null || opts === void 0 ? void 0 : opts.autoPurgeCache) !== false) {
@@ -224,10 +224,8 @@ class FieldsService {
224
224
  this.addColumnToTable(table, hookAdjustedField);
225
225
  }
226
226
  else {
227
- await trx.transaction(async (schemaTrx) => {
228
- await schemaTrx.schema.alterTable(collection, (table) => {
229
- this.addColumnToTable(table, hookAdjustedField);
230
- });
227
+ await trx.schema.alterTable(collection, (table) => {
228
+ this.addColumnToTable(table, hookAdjustedField);
231
229
  });
232
230
  }
233
231
  }
@@ -327,6 +325,13 @@ class FieldsService {
327
325
  });
328
326
  await this.knex.transaction(async (trx) => {
329
327
  var _a, _b;
328
+ if (this.schema.collections[collection] &&
329
+ field in this.schema.collections[collection].fields &&
330
+ this.schema.collections[collection].fields[field].alias === false) {
331
+ await trx.schema.table(collection, (table) => {
332
+ table.dropColumn(field);
333
+ });
334
+ }
330
335
  const relations = this.schema.relations.filter((relation) => {
331
336
  var _a;
332
337
  return ((relation.collection === collection && relation.field === field) ||
@@ -386,15 +391,6 @@ class FieldsService {
386
391
  .where({ group: metaRow.field, collection: metaRow.collection });
387
392
  }
388
393
  await trx('directus_fields').delete().where({ collection, field });
389
- if (this.schema.collections[collection] &&
390
- field in this.schema.collections[collection].fields &&
391
- this.schema.collections[collection].fields[field].alias === false) {
392
- await trx.transaction(async (schemaTrx) => {
393
- await schemaTrx.schema.table(collection, (table) => {
394
- table.dropColumn(field);
395
- });
396
- });
397
- }
398
394
  });
399
395
  if (this.cache && env_1.default.CACHE_AUTO_PURGE) {
400
396
  await this.cache.clear();
@@ -456,11 +452,15 @@ class FieldsService {
456
452
  column.defaultTo(field.schema.default_value);
457
453
  }
458
454
  }
459
- if (((_g = field.schema) === null || _g === void 0 ? void 0 : _g.is_nullable) !== undefined && field.schema.is_nullable === false) {
460
- column.notNullable();
455
+ if (((_g = field.schema) === null || _g === void 0 ? void 0 : _g.is_nullable) === false) {
456
+ if (!alter || alter.is_nullable === true) {
457
+ column.notNullable();
458
+ }
461
459
  }
462
460
  else {
463
- column.nullable();
461
+ if (!alter || alter.is_nullable === false) {
462
+ column.nullable();
463
+ }
464
464
  }
465
465
  if ((_h = field.schema) === null || _h === void 0 ? void 0 : _h.is_primary_key) {
466
466
  column.primary().notNullable();
@@ -35,7 +35,7 @@ a[x-apple-data-detectors] {
35
35
  line-height: inherit !important;
36
36
  }
37
37
  body a {
38
- color: #00C897;
38
+ color: #6644ff;
39
39
  text-decoration: none;
40
40
  }
41
41
  hr {
@@ -74,7 +74,7 @@ hr {
74
74
  color: #FFFFFF !important;
75
75
  }
76
76
  .link {
77
- color: #00c897 !important;
77
+ color: #6644ff !important;
78
78
  }
79
79
  .button {
80
80
  background-color:#0BA582 !important;
@@ -100,12 +100,16 @@ class PayloadService {
100
100
  return value;
101
101
  },
102
102
  async csv({ action, value }) {
103
- if (!value)
103
+ if (Array.isArray(value) === false && typeof value !== 'string')
104
104
  return;
105
- if (action === 'read' && Array.isArray(value) === false)
105
+ if (action === 'read' && Array.isArray(value) === false) {
106
+ if (value === '')
107
+ return [];
106
108
  return value.split(',');
107
- if (Array.isArray(value))
109
+ }
110
+ if (Array.isArray(value)) {
108
111
  return value.join(',');
112
+ }
109
113
  return value;
110
114
  },
111
115
  };
@@ -135,6 +135,10 @@ class RelationsService {
135
135
  if (relation.field in this.schema.collections[relation.collection].fields === false) {
136
136
  throw new exceptions_1.InvalidPayloadException(`Field "${relation.field}" doesn't exist in collection "${relation.collection}"`);
137
137
  }
138
+ // A primary key should not be a foreign key
139
+ if (this.schema.collections[relation.collection].primary === relation.field) {
140
+ throw new exceptions_1.InvalidPayloadException(`Field "${relation.field}" in collection "${relation.collection}" is a primary key`);
141
+ }
138
142
  if (relation.related_collection && relation.related_collection in this.schema.collections === false) {
139
143
  throw new exceptions_1.InvalidPayloadException(`Collection "${relation.related_collection}" doesn't exist`);
140
144
  }
@@ -7,6 +7,7 @@ exports.UtilsService = void 0;
7
7
  const database_1 = __importDefault(require("../database"));
8
8
  const collections_1 = require("../database/system-data/collections");
9
9
  const exceptions_1 = require("../exceptions");
10
+ const emitter_1 = __importDefault(require("../emitter"));
10
11
  class UtilsService {
11
12
  constructor(options) {
12
13
  this.knex = options.knex || (0, database_1.default)();
@@ -98,6 +99,15 @@ class UtilsService {
98
99
  .andWhere(sortField, '<=', sourceSortValue)
99
100
  .andWhereNot({ [primaryKeyField]: item });
100
101
  }
102
+ emitter_1.default.emitAction(['items.sort', `${collection}.items.sort`], {
103
+ collection,
104
+ item,
105
+ to,
106
+ }, {
107
+ database: this.knex,
108
+ schema: this.schema,
109
+ accountability: this.accountability,
110
+ });
101
111
  }
102
112
  }
103
113
  exports.UtilsService = UtilsService;
@@ -48,29 +48,7 @@ function applyQuery(knex, collection, dbQuery, query, schema, subQuery = false)
48
48
  if (query.aggregate) {
49
49
  applyAggregate(dbQuery, query.aggregate, collection);
50
50
  }
51
- if (query.union && query.union[1].length > 0) {
52
- const [field, keys] = query.union;
53
- const queries = keys.map((key) => {
54
- const unionFilter = { [field]: { _eq: key } };
55
- let filter = (0, lodash_1.cloneDeep)(query.filter);
56
- if (filter) {
57
- if ('_and' in filter) {
58
- filter._and.push(unionFilter);
59
- }
60
- else {
61
- filter = {
62
- _and: [filter, unionFilter],
63
- };
64
- }
65
- }
66
- else {
67
- filter = unionFilter;
68
- }
69
- return knex.select('*').from(applyFilter(knex, schema, dbQuery.clone(), filter, collection, subQuery).as('foo'));
70
- });
71
- dbQuery = knex.unionAll(queries);
72
- }
73
- else if (query.filter) {
51
+ if (query.filter) {
74
52
  applyFilter(knex, schema, dbQuery, query.filter, collection, subQuery);
75
53
  }
76
54
  return dbQuery;
@@ -234,7 +212,7 @@ function applyFilter(knex, schema, rootQuery, rootFilter, collection, subQuery =
234
212
  applyFilterToQuery(`${collection}.${filterPath[0]}`, filterOperator, filterValue, logical);
235
213
  }
236
214
  }
237
- else if (subQuery === false) {
215
+ else if (subQuery === false || filterPath.length > 1) {
238
216
  if (!relation)
239
217
  continue;
240
218
  let pkField = `${collection}.${schema.collections[relation.related_collection].primary}`;
@@ -145,7 +145,7 @@ function processPermissions(accountability, permissions, filterContext) {
145
145
  return permissions.map((permission) => {
146
146
  permission.permissions = (0, utils_1.parseFilter)(permission.permissions, accountability, filterContext);
147
147
  permission.validation = (0, utils_1.parseFilter)(permission.validation, accountability, filterContext);
148
- permission.presets = (0, utils_1.parseFilter)(permission.presets, accountability, filterContext);
148
+ permission.presets = (0, utils_1.parsePreset)(permission.presets, accountability, filterContext);
149
149
  return permission;
150
150
  });
151
151
  }
@@ -3,37 +3,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const atob_1 = __importDefault(require("atob"));
7
- const logger_1 = __importDefault(require("../logger"));
6
+ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
8
7
  /**
9
8
  * Check if a given string conforms to the structure of a JWT
10
9
  * and whether it is issued by Directus.
11
10
  */
12
11
  function isDirectusJWT(string) {
13
- const parts = string.split('.');
14
- // JWTs have the structure header.payload.signature
15
- if (parts.length !== 3)
16
- return false;
17
- // Check if all segments are base64 encoded
18
- try {
19
- (0, atob_1.default)(parts[0]);
20
- (0, atob_1.default)(parts[1]);
21
- (0, atob_1.default)(parts[2]);
22
- }
23
- catch (err) {
24
- logger_1.default.error(err);
25
- return false;
26
- }
27
- // Check if the header and payload are valid JSON
28
12
  try {
29
- JSON.parse((0, atob_1.default)(parts[0]));
30
- const payload = JSON.parse((0, atob_1.default)(parts[1]));
31
- if (payload.iss !== 'directus')
13
+ const payload = jsonwebtoken_1.default.decode(string, { json: true });
14
+ if ((payload === null || payload === void 0 ? void 0 : payload.iss) !== 'directus')
32
15
  return false;
16
+ return true;
33
17
  }
34
18
  catch {
35
19
  return false;
36
20
  }
37
- return true;
38
21
  }
39
22
  exports.default = isDirectusJWT;
@@ -0,0 +1,2 @@
1
+ import { DirectusTokenPayload } from '../types';
2
+ export declare function verifyAccessJWT(token: string, secret: string): DirectusTokenPayload;
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
11
+ }) : function(o, v) {
12
+ o["default"] = v;
13
+ });
14
+ var __importStar = (this && this.__importStar) || function (mod) {
15
+ if (mod && mod.__esModule) return mod;
16
+ var result = {};
17
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
+ __setModuleDefault(result, mod);
19
+ return result;
20
+ };
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.verifyAccessJWT = void 0;
23
+ const jsonwebtoken_1 = __importStar(require("jsonwebtoken"));
24
+ const exceptions_1 = require("../exceptions");
25
+ function verifyAccessJWT(token, secret) {
26
+ let payload;
27
+ try {
28
+ payload = jsonwebtoken_1.default.verify(token, secret, {
29
+ issuer: 'directus',
30
+ });
31
+ }
32
+ catch (err) {
33
+ if (err instanceof jsonwebtoken_1.TokenExpiredError) {
34
+ throw new exceptions_1.InvalidTokenException('Token expired.');
35
+ }
36
+ else if (err instanceof jsonwebtoken_1.JsonWebTokenError) {
37
+ throw new exceptions_1.InvalidTokenException('Token invalid.');
38
+ }
39
+ else {
40
+ throw new exceptions_1.ServiceUnavailableException(`Couldn't verify token.`, { service: 'jwt' });
41
+ }
42
+ }
43
+ const { id, role, app_access, admin_access, share, share_scope } = payload;
44
+ if (role === undefined || app_access === undefined || admin_access === undefined) {
45
+ throw new exceptions_1.InvalidTokenException('Invalid token payload.');
46
+ }
47
+ return { id, role, app_access, admin_access, share, share_scope };
48
+ }
49
+ exports.verifyAccessJWT = verifyAccessJWT;
package/dist/utils/md.js CHANGED
@@ -10,6 +10,6 @@ const sanitize_html_1 = __importDefault(require("sanitize-html"));
10
10
  * Render and sanitize a markdown string
11
11
  */
12
12
  function md(str) {
13
- return (0, sanitize_html_1.default)((0, marked_1.parse)(str));
13
+ return (0, sanitize_html_1.default)((0, marked_1.marked)(str));
14
14
  }
15
15
  exports.md = md;
@@ -31,9 +31,15 @@ function mergePermission(strategy, currentPerm, newPerm) {
31
31
  };
32
32
  }
33
33
  else if (currentPerm.permissions) {
34
- permissions = {
35
- [logicalKey]: [currentPerm.permissions, newPerm.permissions],
36
- };
34
+ // Empty {} supersedes other permissions in _OR merge
35
+ if (strategy === 'or' && ((0, lodash_1.isEqual)(currentPerm.permissions, {}) || (0, lodash_1.isEqual)(newPerm.permissions, {}))) {
36
+ permissions = {};
37
+ }
38
+ else {
39
+ permissions = {
40
+ [logicalKey]: [currentPerm.permissions, newPerm.permissions],
41
+ };
42
+ }
37
43
  }
38
44
  else {
39
45
  permissions = {
@@ -51,9 +57,15 @@ function mergePermission(strategy, currentPerm, newPerm) {
51
57
  };
52
58
  }
53
59
  else if (currentPerm.validation) {
54
- validation = {
55
- [logicalKey]: [currentPerm.validation, newPerm.validation],
56
- };
60
+ // Empty {} supersedes other validations in _OR merge
61
+ if (strategy === 'or' && ((0, lodash_1.isEqual)(currentPerm.validation, {}) || (0, lodash_1.isEqual)(newPerm.validation, {}))) {
62
+ validation = {};
63
+ }
64
+ else {
65
+ validation = {
66
+ [logicalKey]: [currentPerm.validation, newPerm.validation],
67
+ };
68
+ }
57
69
  }
58
70
  else {
59
71
  validation = {
package/example.env CHANGED
@@ -1,6 +1,7 @@
1
1
  ####################################################################################################
2
2
  # General
3
3
 
4
+ HOST="0.0.0.0"
4
5
  PORT=8055
5
6
  PUBLIC_URL="http://localhost:8055"
6
7
  LOG_LEVEL="info"