directus 9.2.1 → 9.4.1

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 (93) hide show
  1. package/dist/app.js +5 -3
  2. package/dist/auth/auth.d.ts +4 -6
  3. package/dist/auth/auth.js +5 -9
  4. package/dist/auth/drivers/ldap.d.ts +3 -3
  5. package/dist/auth/drivers/ldap.js +6 -2
  6. package/dist/auth/drivers/local.d.ts +2 -2
  7. package/dist/auth/drivers/local.js +5 -12
  8. package/dist/auth/drivers/oauth2.d.ts +3 -3
  9. package/dist/auth/drivers/oauth2.js +2 -3
  10. package/dist/auth/drivers/openid.d.ts +3 -3
  11. package/dist/auth/drivers/openid.js +2 -3
  12. package/dist/cli/commands/bootstrap/index.js +3 -2
  13. package/dist/cli/commands/init/index.js +3 -7
  14. package/dist/cli/commands/schema/apply.js +1 -1
  15. package/dist/cli/utils/defaults.d.ts +11 -0
  16. package/dist/cli/utils/defaults.js +14 -0
  17. package/dist/constants.d.ts +8 -0
  18. package/dist/constants.js +16 -2
  19. package/dist/controllers/shares.d.ts +2 -0
  20. package/dist/controllers/shares.js +212 -0
  21. package/dist/controllers/users.js +21 -9
  22. package/dist/database/migrations/20211211A-add-shares.d.ts +3 -0
  23. package/dist/database/migrations/20211211A-add-shares.js +38 -0
  24. package/dist/database/run-ast.js +5 -5
  25. package/dist/database/system-data/app-access-permissions/app-access-permissions.yaml +0 -15
  26. package/dist/database/system-data/app-access-permissions/index.d.ts +1 -0
  27. package/dist/database/system-data/app-access-permissions/index.js +4 -2
  28. package/dist/database/system-data/app-access-permissions/schema-access-permissions.yaml +17 -0
  29. package/dist/database/system-data/collections/collections.yaml +3 -0
  30. package/dist/database/system-data/fields/_defaults.yaml +2 -0
  31. package/dist/database/system-data/fields/sessions.yaml +1 -1
  32. package/dist/database/system-data/fields/settings.yaml +9 -0
  33. package/dist/database/system-data/fields/shares.yaml +77 -0
  34. package/dist/database/system-data/fields/users.yaml +1 -1
  35. package/dist/database/system-data/relations/relations.yaml +15 -0
  36. package/dist/emitter.d.ts +3 -2
  37. package/dist/emitter.js +13 -6
  38. package/dist/env.js +1 -1
  39. package/dist/exceptions/index.d.ts +1 -0
  40. package/dist/exceptions/index.js +1 -0
  41. package/dist/exceptions/unexpected-response.d.ts +4 -0
  42. package/dist/exceptions/unexpected-response.js +10 -0
  43. package/dist/extensions.d.ts +1 -0
  44. package/dist/extensions.js +10 -4
  45. package/dist/middleware/authenticate.js +5 -15
  46. package/dist/middleware/check-ip.js +9 -6
  47. package/dist/middleware/respond.js +4 -1
  48. package/dist/services/activity.d.ts +2 -1
  49. package/dist/services/activity.js +2 -2
  50. package/dist/services/authentication.d.ts +2 -7
  51. package/dist/services/authentication.js +81 -41
  52. package/dist/services/authorization.js +3 -3
  53. package/dist/services/collections.d.ts +1 -2
  54. package/dist/services/collections.js +2 -2
  55. package/dist/services/files.d.ts +2 -2
  56. package/dist/services/files.js +14 -8
  57. package/dist/services/graphql.js +20 -5
  58. package/dist/services/index.d.ts +1 -0
  59. package/dist/services/index.js +1 -0
  60. package/dist/services/items.d.ts +1 -15
  61. package/dist/services/notifications.d.ts +2 -2
  62. package/dist/services/permissions.d.ts +2 -2
  63. package/dist/services/roles.d.ts +2 -2
  64. package/dist/services/shares.d.ts +17 -0
  65. package/dist/services/shares.js +135 -0
  66. package/dist/services/specifications.js +1 -1
  67. package/dist/services/users.d.ts +2 -2
  68. package/dist/services/users.js +8 -6
  69. package/dist/services/webhooks.d.ts +2 -2
  70. package/dist/tests/database/migrations/run.test.d.ts +1 -0
  71. package/dist/tests/database/migrations/run.test.js +29 -0
  72. package/dist/types/ast.d.ts +3 -3
  73. package/dist/types/auth.d.ts +31 -0
  74. package/dist/types/extensions.d.ts +2 -0
  75. package/dist/types/items.d.ts +14 -0
  76. package/dist/utils/apply-query.d.ts +0 -38
  77. package/dist/utils/apply-query.js +66 -67
  78. package/dist/utils/apply-snapshot.js +69 -14
  79. package/dist/utils/get-ast-from-query.js +3 -3
  80. package/dist/utils/get-default-value.js +3 -1
  81. package/dist/utils/get-permissions.d.ts +2 -2
  82. package/dist/utils/get-permissions.js +117 -72
  83. package/dist/utils/get-relation-type.d.ts +1 -1
  84. package/dist/utils/get-relation-type.js +1 -1
  85. package/dist/utils/merge-permissions-for-share.d.ts +5 -0
  86. package/dist/utils/merge-permissions-for-share.js +116 -0
  87. package/dist/utils/merge-permissions.d.ts +13 -1
  88. package/dist/utils/merge-permissions.js +27 -19
  89. package/dist/utils/reduce-schema.d.ts +2 -2
  90. package/dist/utils/reduce-schema.js +7 -7
  91. package/dist/utils/user-name.js +3 -0
  92. package/example.env +1 -1
  93. package/package.json +14 -13
package/dist/app.js CHANGED
@@ -51,6 +51,7 @@ const settings_1 = __importDefault(require("./controllers/settings"));
51
51
  const users_1 = __importDefault(require("./controllers/users"));
52
52
  const utils_1 = __importDefault(require("./controllers/utils"));
53
53
  const webhooks_1 = __importDefault(require("./controllers/webhooks"));
54
+ const shares_1 = __importDefault(require("./controllers/shares"));
54
55
  const database_1 = require("./database");
55
56
  const emitter_1 = __importDefault(require("./emitter"));
56
57
  const env_1 = __importDefault(require("./env"));
@@ -112,14 +113,14 @@ async function createApp() {
112
113
  });
113
114
  app.use((0, cookie_parser_1.default)());
114
115
  app.use(extract_token_1.default);
115
- app.use((req, res, next) => {
116
+ app.use((_req, res, next) => {
116
117
  res.setHeader('X-Powered-By', 'Directus');
117
118
  next();
118
119
  });
119
120
  if (env_1.default.CORS_ENABLED === true) {
120
121
  app.use(cors_1.default);
121
122
  }
122
- app.get('/', (req, res, next) => {
123
+ app.get('/', (_req, res, next) => {
123
124
  if (env_1.default.ROOT_REDIRECT) {
124
125
  res.redirect(env_1.default.ROOT_REDIRECT);
125
126
  }
@@ -133,7 +134,7 @@ async function createApp() {
133
134
  // Set the App's base path according to the APIs public URL
134
135
  const html = await fs_extra_1.default.readFile(adminPath, 'utf8');
135
136
  const htmlWithBase = html.replace(/<base \/>/, `<base href="${adminUrl.toString({ rootRelative: true })}/" />`);
136
- const noCacheIndexHtmlHandler = (req, res) => {
137
+ const noCacheIndexHtmlHandler = (_req, res) => {
137
138
  res.setHeader('Cache-Control', 'no-cache');
138
139
  res.send(htmlWithBase);
139
140
  };
@@ -173,6 +174,7 @@ async function createApp() {
173
174
  app.use('/roles', roles_1.default);
174
175
  app.use('/server', server_1.default);
175
176
  app.use('/settings', settings_1.default);
177
+ app.use('/shares', shares_1.default);
176
178
  app.use('/users', users_1.default);
177
179
  app.use('/utils', utils_1.default);
178
180
  app.use('/webhooks', webhooks_1.default);
@@ -1,5 +1,5 @@
1
1
  import { Knex } from 'knex';
2
- import { AuthDriverOptions, SchemaOverview, User, SessionData } from '../types';
2
+ import { AuthDriverOptions, SchemaOverview, User } from '../types';
3
3
  export declare abstract class AuthDriver {
4
4
  knex: Knex;
5
5
  schema: SchemaOverview;
@@ -28,20 +28,18 @@ export declare abstract class AuthDriver {
28
28
  * @throws InvalidCredentialsException
29
29
  * @returns Data to be stored with the session
30
30
  */
31
- login(_user: User, _payload: Record<string, any>): Promise<SessionData>;
31
+ login(_user: User, _payload: Record<string, any>): Promise<void>;
32
32
  /**
33
33
  * Handle user session refresh
34
34
  *
35
35
  * @param _user User information
36
- * @param _sessionData Session data
37
36
  * @throws InvalidCredentialsException
38
37
  */
39
- refresh(_user: User, sessionData: SessionData): Promise<SessionData>;
38
+ refresh(_user: User): Promise<void>;
40
39
  /**
41
40
  * Handle user session termination
42
41
  *
43
42
  * @param _user User information
44
- * @param _sessionData Session data
45
43
  */
46
- logout(_user: User, _sessionData: SessionData): Promise<void>;
44
+ logout(_user: User): Promise<void>;
47
45
  }
package/dist/auth/auth.js CHANGED
@@ -15,28 +15,24 @@ class AuthDriver {
15
15
  * @returns Data to be stored with the session
16
16
  */
17
17
  async login(_user, _payload) {
18
- /* Optional, though should probably be set */
19
- return null;
18
+ return;
20
19
  }
21
20
  /**
22
21
  * Handle user session refresh
23
22
  *
24
23
  * @param _user User information
25
- * @param _sessionData Session data
26
24
  * @throws InvalidCredentialsException
27
25
  */
28
- async refresh(_user, sessionData) {
29
- /* Optional */
30
- return sessionData;
26
+ async refresh(_user) {
27
+ return;
31
28
  }
32
29
  /**
33
30
  * Handle user session termination
34
31
  *
35
32
  * @param _user User information
36
- * @param _sessionData Session data
37
33
  */
38
- async logout(_user, _sessionData) {
39
- /* Optional */
34
+ async logout(_user) {
35
+ return;
40
36
  }
41
37
  }
42
38
  exports.AuthDriver = AuthDriver;
@@ -1,7 +1,7 @@
1
1
  import { Router } from 'express';
2
2
  import { Client } from 'ldapjs';
3
3
  import { AuthDriver } from '../auth';
4
- import { AuthDriverOptions, User, SessionData } from '../../types';
4
+ import { AuthDriverOptions, User } from '../../types';
5
5
  import { UsersService } from '../../services';
6
6
  export declare class LDAPAuthDriver extends AuthDriver {
7
7
  bindClient: Client;
@@ -15,7 +15,7 @@ export declare class LDAPAuthDriver extends AuthDriver {
15
15
  private fetchUserId;
16
16
  getUserID(payload: Record<string, any>): Promise<string>;
17
17
  verify(user: User, password?: string): Promise<void>;
18
- login(user: User, payload: Record<string, any>): Promise<SessionData>;
19
- refresh(user: User): Promise<SessionData>;
18
+ login(user: User, payload: Record<string, any>): Promise<void>;
19
+ refresh(user: User): Promise<void>;
20
20
  }
21
21
  export declare function createLDAPAuthRouter(provider: string): Router;
@@ -87,6 +87,12 @@ class LDAPAuthDriver extends auth_1.AuthDriver {
87
87
  }
88
88
  });
89
89
  });
90
+ res.on('end', (result) => {
91
+ if ((result === null || result === void 0 ? void 0 : result.status) === 0) {
92
+ // Handle edge case with IBM systems where authenticated bind user could not fetch their DN
93
+ reject(new exceptions_1.UnexpectedResponseException('Failed to find bind user record'));
94
+ }
95
+ });
90
96
  });
91
97
  });
92
98
  }
@@ -254,7 +260,6 @@ class LDAPAuthDriver extends auth_1.AuthDriver {
254
260
  }
255
261
  async login(user, payload) {
256
262
  await this.verify(user, payload.password);
257
- return null;
258
263
  }
259
264
  async refresh(user) {
260
265
  await this.validateBindClient();
@@ -262,7 +267,6 @@ class LDAPAuthDriver extends auth_1.AuthDriver {
262
267
  if ((userInfo === null || userInfo === void 0 ? void 0 : userInfo.userAccountControl) && userInfo.userAccountControl & INVALID_ACCOUNT_FLAGS) {
263
268
  throw new exceptions_1.InvalidCredentialsException();
264
269
  }
265
- return null;
266
270
  }
267
271
  }
268
272
  exports.LDAPAuthDriver = LDAPAuthDriver;
@@ -1,9 +1,9 @@
1
1
  import { Router } from 'express';
2
2
  import { AuthDriver } from '../auth';
3
- import { User, SessionData } from '../../types';
3
+ import { User } from '../../types';
4
4
  export declare class LocalAuthDriver extends AuthDriver {
5
5
  getUserID(payload: Record<string, any>): Promise<string>;
6
6
  verify(user: User, password?: string): Promise<void>;
7
- login(user: User, payload: Record<string, any>): Promise<SessionData>;
7
+ login(user: User, payload: Record<string, any>): Promise<void>;
8
8
  }
9
9
  export declare function createLocalAuthRouter(provider: string): Router;
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.createLocalAuthRouter = exports.LocalAuthDriver = void 0;
7
7
  const express_1 = require("express");
8
8
  const argon2_1 = __importDefault(require("argon2"));
9
- const ms_1 = __importDefault(require("ms"));
10
9
  const joi_1 = __importDefault(require("joi"));
11
10
  const auth_1 = require("../auth");
12
11
  const exceptions_1 = require("../../exceptions");
@@ -14,6 +13,7 @@ const services_1 = require("../../services");
14
13
  const async_handler_1 = __importDefault(require("../../utils/async-handler"));
15
14
  const env_1 = __importDefault(require("../../env"));
16
15
  const respond_1 = require("../../middleware/respond");
16
+ const constants_1 = require("../../constants");
17
17
  class LocalAuthDriver extends auth_1.AuthDriver {
18
18
  async getUserID(payload) {
19
19
  if (!payload.email) {
@@ -36,20 +36,19 @@ class LocalAuthDriver extends auth_1.AuthDriver {
36
36
  }
37
37
  async login(user, payload) {
38
38
  await this.verify(user, payload.password);
39
- return null;
40
39
  }
41
40
  }
42
41
  exports.LocalAuthDriver = LocalAuthDriver;
43
42
  function createLocalAuthRouter(provider) {
44
43
  const router = (0, express_1.Router)();
45
- const loginSchema = joi_1.default.object({
44
+ const userLoginSchema = joi_1.default.object({
46
45
  email: joi_1.default.string().email().required(),
47
46
  password: joi_1.default.string().required(),
48
47
  mode: joi_1.default.string().valid('cookie', 'json'),
49
48
  otp: joi_1.default.string(),
50
49
  }).unknown();
51
50
  router.post('/', (0, async_handler_1.default)(async (req, res, next) => {
52
- var _a, _b;
51
+ var _a;
53
52
  const accountability = {
54
53
  ip: req.ip,
55
54
  userAgent: req.get('user-agent'),
@@ -59,7 +58,7 @@ function createLocalAuthRouter(provider) {
59
58
  accountability: accountability,
60
59
  schema: req.schema,
61
60
  });
62
- const { error } = loginSchema.validate(req.body);
61
+ const { error } = userLoginSchema.validate(req.body);
63
62
  if (error) {
64
63
  throw new exceptions_1.InvalidPayloadException(error.message);
65
64
  }
@@ -72,13 +71,7 @@ function createLocalAuthRouter(provider) {
72
71
  payload.data.refresh_token = refreshToken;
73
72
  }
74
73
  if (mode === 'cookie') {
75
- res.cookie(env_1.default.REFRESH_TOKEN_COOKIE_NAME, refreshToken, {
76
- httpOnly: true,
77
- domain: env_1.default.REFRESH_TOKEN_COOKIE_DOMAIN,
78
- maxAge: (0, ms_1.default)(env_1.default.REFRESH_TOKEN_TTL),
79
- secure: (_b = env_1.default.REFRESH_TOKEN_COOKIE_SECURE) !== null && _b !== void 0 ? _b : false,
80
- sameSite: env_1.default.REFRESH_TOKEN_COOKIE_SAME_SITE || 'strict',
81
- });
74
+ res.cookie(env_1.default.REFRESH_TOKEN_COOKIE_NAME, refreshToken, constants_1.COOKIE_OPTIONS);
82
75
  }
83
76
  res.locals.payload = payload;
84
77
  return next();
@@ -2,7 +2,7 @@ import { Router } from 'express';
2
2
  import { Client } from 'openid-client';
3
3
  import { LocalAuthDriver } from './local';
4
4
  import { UsersService } from '../../services';
5
- import { AuthDriverOptions, User, SessionData } from '../../types';
5
+ import { AuthDriverOptions, User } from '../../types';
6
6
  export declare class OAuth2AuthDriver extends LocalAuthDriver {
7
7
  client: Client;
8
8
  redirectUrl: string;
@@ -13,7 +13,7 @@ export declare class OAuth2AuthDriver extends LocalAuthDriver {
13
13
  generateAuthUrl(codeVerifier: string, prompt?: boolean): string;
14
14
  private fetchUserId;
15
15
  getUserID(payload: Record<string, any>): Promise<string>;
16
- login(user: User): Promise<SessionData>;
17
- refresh(user: User, sessionData: SessionData): Promise<SessionData>;
16
+ login(user: User): Promise<void>;
17
+ refresh(user: User): Promise<void>;
18
18
  }
19
19
  export declare function createOAuth2AuthRouter(providerName: string): Router;
@@ -130,9 +130,9 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
130
130
  return (await this.fetchUserId(identifier));
131
131
  }
132
132
  async login(user) {
133
- return this.refresh(user, null);
133
+ return this.refresh(user);
134
134
  }
135
- async refresh(user, sessionData) {
135
+ async refresh(user) {
136
136
  let authData = user.auth_data;
137
137
  if (typeof authData === 'string') {
138
138
  try {
@@ -156,7 +156,6 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
156
156
  throw handleError(e);
157
157
  }
158
158
  }
159
- return sessionData;
160
159
  }
161
160
  }
162
161
  exports.OAuth2AuthDriver = OAuth2AuthDriver;
@@ -2,7 +2,7 @@ import { Router } from 'express';
2
2
  import { Client } from 'openid-client';
3
3
  import { LocalAuthDriver } from './local';
4
4
  import { UsersService } from '../../services';
5
- import { AuthDriverOptions, User, SessionData } from '../../types';
5
+ import { AuthDriverOptions, User } from '../../types';
6
6
  export declare class OpenIDAuthDriver extends LocalAuthDriver {
7
7
  client: Promise<Client>;
8
8
  redirectUrl: string;
@@ -13,7 +13,7 @@ export declare class OpenIDAuthDriver extends LocalAuthDriver {
13
13
  generateAuthUrl(codeVerifier: string, prompt?: boolean): Promise<string>;
14
14
  private fetchUserId;
15
15
  getUserID(payload: Record<string, any>): Promise<string>;
16
- login(user: User): Promise<SessionData>;
17
- refresh(user: User, sessionData: SessionData): Promise<SessionData>;
16
+ login(user: User): Promise<void>;
17
+ refresh(user: User): Promise<void>;
18
18
  }
19
19
  export declare function createOpenIDAuthRouter(providerName: string): Router;
@@ -135,9 +135,9 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
135
135
  return (await this.fetchUserId(identifier));
136
136
  }
137
137
  async login(user) {
138
- return this.refresh(user, null);
138
+ return this.refresh(user);
139
139
  }
140
- async refresh(user, sessionData) {
140
+ async refresh(user) {
141
141
  let authData = user.auth_data;
142
142
  if (typeof authData === 'string') {
143
143
  try {
@@ -162,7 +162,6 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
162
162
  throw handleError(e);
163
163
  }
164
164
  }
165
- return sessionData;
166
165
  }
167
166
  }
168
167
  exports.OpenIDAuthDriver = OpenIDAuthDriver;
@@ -30,6 +30,7 @@ const logger_1 = __importDefault(require("../../../logger"));
30
30
  const get_schema_1 = require("../../../utils/get-schema");
31
31
  const services_1 = require("../../../services");
32
32
  const database_1 = __importStar(require("../../../database"));
33
+ const defaults_1 = require("../../utils/defaults");
33
34
  async function bootstrap({ skipAdminInit }) {
34
35
  logger_1.default.info('Initializing bootstrap...');
35
36
  const database = (0, database_1.default)();
@@ -75,7 +76,7 @@ async function waitForDatabase(database) {
75
76
  async function createDefaultAdmin(schema) {
76
77
  logger_1.default.info('Setting up first admin role...');
77
78
  const rolesService = new services_1.RolesService({ schema });
78
- const role = await rolesService.createOne({ name: 'Admin', admin_access: true });
79
+ const role = await rolesService.createOne(defaults_1.defaultAdminRole);
79
80
  logger_1.default.info('Adding first admin user...');
80
81
  const usersService = new services_1.UsersService({ schema });
81
82
  let adminEmail = env_1.default.ADMIN_EMAIL;
@@ -88,5 +89,5 @@ async function createDefaultAdmin(schema) {
88
89
  adminPassword = (0, nanoid_1.nanoid)(12);
89
90
  logger_1.default.info(`No admin password provided. Defaulting to "${adminPassword}"`);
90
91
  }
91
- await usersService.createOne({ email: adminEmail, password: adminPassword, role });
92
+ await usersService.createOne({ email: adminEmail, password: adminPassword, role, ...defaults_1.defaultAdminUser });
92
93
  }
@@ -15,6 +15,7 @@ const create_env_1 = __importDefault(require("../../utils/create-env"));
15
15
  const drivers_1 = require("../../utils/drivers");
16
16
  const questions_1 = require("./questions");
17
17
  const generate_hash_1 = require("../../../utils/generate-hash");
18
+ const defaults_1 = require("../../utils/defaults");
18
19
  async function init() {
19
20
  const rootPath = process.cwd();
20
21
  const { client } = await inquirer_1.default.prompt([
@@ -79,19 +80,14 @@ async function init() {
79
80
  const roleID = (0, uuid_1.v4)();
80
81
  await db('directus_roles').insert({
81
82
  id: roleID,
82
- name: 'Administrator',
83
- icon: 'verified',
84
- admin_access: true,
85
- description: 'Initial administrative role with unrestricted App/API access',
83
+ ...defaults_1.defaultAdminRole,
86
84
  });
87
85
  await db('directus_users').insert({
88
86
  id: userID,
89
- status: 'active',
90
87
  email: firstUser.email,
91
88
  password: firstUser.password,
92
- first_name: 'Admin',
93
- last_name: 'User',
94
89
  role: roleID,
90
+ ...defaults_1.defaultAdminUser,
95
91
  });
96
92
  await db.destroy();
97
93
  process.stdout.write(`\nYour project has been created at ${chalk_1.default.green(rootPath)}.\n`);
@@ -135,7 +135,7 @@ async function apply(snapshotPath, options) {
135
135
  else {
136
136
  continue;
137
137
  }
138
- // Related collection doesn't exist for m2a relationship types
138
+ // Related collection doesn't exist for a2o relationship types
139
139
  if (related_collection) {
140
140
  message += `-> ${related_collection}`;
141
141
  }
@@ -0,0 +1,11 @@
1
+ export declare const defaultAdminRole: {
2
+ name: string;
3
+ icon: string;
4
+ admin_access: boolean;
5
+ description: string;
6
+ };
7
+ export declare const defaultAdminUser: {
8
+ status: string;
9
+ first_name: string;
10
+ last_name: string;
11
+ };
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultAdminUser = exports.defaultAdminRole = void 0;
4
+ exports.defaultAdminRole = {
5
+ name: 'Administrator',
6
+ icon: 'verified',
7
+ admin_access: true,
8
+ description: '$t:admin_description',
9
+ };
10
+ exports.defaultAdminUser = {
11
+ status: 'active',
12
+ first_name: 'Admin',
13
+ last_name: 'User',
14
+ };
@@ -5,3 +5,11 @@ export declare const FILTER_VARIABLES: string[];
5
5
  export declare const ALIAS_TYPES: string[];
6
6
  export declare const DEFAULT_AUTH_PROVIDER = "default";
7
7
  export declare const COLUMN_TRANSFORMS: string[];
8
+ export declare const UUID_REGEX = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
9
+ export declare const COOKIE_OPTIONS: {
10
+ httpOnly: boolean;
11
+ domain: any;
12
+ maxAge: number;
13
+ secure: any;
14
+ sameSite: "lax" | "strict" | "none";
15
+ };
package/dist/constants.js CHANGED
@@ -1,6 +1,12 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ var _a;
2
6
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.COLUMN_TRANSFORMS = exports.DEFAULT_AUTH_PROVIDER = exports.ALIAS_TYPES = exports.FILTER_VARIABLES = exports.ASSET_TRANSFORM_QUERY_KEYS = exports.SYSTEM_ASSET_ALLOW_LIST = void 0;
7
+ exports.COOKIE_OPTIONS = exports.UUID_REGEX = exports.COLUMN_TRANSFORMS = exports.DEFAULT_AUTH_PROVIDER = exports.ALIAS_TYPES = exports.FILTER_VARIABLES = exports.ASSET_TRANSFORM_QUERY_KEYS = exports.SYSTEM_ASSET_ALLOW_LIST = void 0;
8
+ const env_1 = __importDefault(require("./env"));
9
+ const ms_1 = __importDefault(require("ms"));
4
10
  exports.SYSTEM_ASSET_ALLOW_LIST = [
5
11
  {
6
12
  key: 'system-small-cover',
@@ -38,6 +44,14 @@ exports.ASSET_TRANSFORM_QUERY_KEYS = [
38
44
  'withoutEnlargement',
39
45
  ];
40
46
  exports.FILTER_VARIABLES = ['$NOW', '$CURRENT_USER', '$CURRENT_ROLE'];
41
- exports.ALIAS_TYPES = ['alias', 'o2m', 'm2m', 'm2a', 'files', 'translations'];
47
+ exports.ALIAS_TYPES = ['alias', 'o2m', 'm2m', 'm2a', 'o2a', 'files', 'translations'];
42
48
  exports.DEFAULT_AUTH_PROVIDER = 'default';
43
49
  exports.COLUMN_TRANSFORMS = ['year', 'month', 'day', 'weekday', 'hour', 'minute', 'second'];
50
+ exports.UUID_REGEX = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}';
51
+ exports.COOKIE_OPTIONS = {
52
+ httpOnly: true,
53
+ domain: env_1.default.REFRESH_TOKEN_COOKIE_DOMAIN,
54
+ maxAge: (0, ms_1.default)(env_1.default.REFRESH_TOKEN_TTL),
55
+ secure: (_a = env_1.default.REFRESH_TOKEN_COOKIE_SECURE) !== null && _a !== void 0 ? _a : false,
56
+ sameSite: env_1.default.REFRESH_TOKEN_COOKIE_SAME_SITE || 'strict',
57
+ };
@@ -0,0 +1,2 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
@@ -0,0 +1,212 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const express_1 = __importDefault(require("express"));
7
+ const exceptions_1 = require("../exceptions");
8
+ const respond_1 = require("../middleware/respond");
9
+ const use_collection_1 = __importDefault(require("../middleware/use-collection"));
10
+ const validate_batch_1 = require("../middleware/validate-batch");
11
+ const services_1 = require("../services");
12
+ const async_handler_1 = __importDefault(require("../utils/async-handler"));
13
+ const constants_1 = require("../constants");
14
+ const joi_1 = __importDefault(require("joi"));
15
+ const env_1 = __importDefault(require("../env"));
16
+ const router = express_1.default.Router();
17
+ router.use((0, use_collection_1.default)('directus_shares'));
18
+ const sharedLoginSchema = joi_1.default.object({
19
+ share: joi_1.default.string().required(),
20
+ password: joi_1.default.string(),
21
+ }).unknown();
22
+ router.post('/auth', (0, async_handler_1.default)(async (req, res, next) => {
23
+ // This doesn't use accountability, as the user isn't logged in at this point
24
+ const service = new services_1.SharesService({
25
+ schema: req.schema,
26
+ });
27
+ const { error } = sharedLoginSchema.validate(req.body);
28
+ if (error) {
29
+ throw new exceptions_1.InvalidPayloadException(error.message);
30
+ }
31
+ const { accessToken, refreshToken, expires } = await service.login(req.body);
32
+ res.cookie(env_1.default.REFRESH_TOKEN_COOKIE_NAME, refreshToken, constants_1.COOKIE_OPTIONS);
33
+ res.locals.payload = { data: { access_token: accessToken, expires } };
34
+ return next();
35
+ }), respond_1.respond);
36
+ const sharedInviteSchema = joi_1.default.object({
37
+ share: joi_1.default.string().required(),
38
+ emails: joi_1.default.array().items(joi_1.default.string()),
39
+ }).unknown();
40
+ router.post('/invite', (0, async_handler_1.default)(async (req, res, next) => {
41
+ const service = new services_1.SharesService({
42
+ schema: req.schema,
43
+ accountability: req.accountability,
44
+ });
45
+ const { error } = sharedInviteSchema.validate(req.body);
46
+ if (error) {
47
+ throw new exceptions_1.InvalidPayloadException(error.message);
48
+ }
49
+ await service.invite(req.body);
50
+ return next();
51
+ }), respond_1.respond);
52
+ router.post('/', (0, async_handler_1.default)(async (req, res, next) => {
53
+ const service = new services_1.SharesService({
54
+ accountability: req.accountability,
55
+ schema: req.schema,
56
+ });
57
+ const savedKeys = [];
58
+ if (Array.isArray(req.body)) {
59
+ const keys = await service.createMany(req.body);
60
+ savedKeys.push(...keys);
61
+ }
62
+ else {
63
+ const key = await service.createOne(req.body);
64
+ savedKeys.push(key);
65
+ }
66
+ try {
67
+ if (Array.isArray(req.body)) {
68
+ const items = await service.readMany(savedKeys, req.sanitizedQuery);
69
+ res.locals.payload = { data: items };
70
+ }
71
+ else {
72
+ const item = await service.readOne(savedKeys[0], req.sanitizedQuery);
73
+ res.locals.payload = { data: item };
74
+ }
75
+ }
76
+ catch (error) {
77
+ if (error instanceof exceptions_1.ForbiddenException) {
78
+ return next();
79
+ }
80
+ throw error;
81
+ }
82
+ return next();
83
+ }), respond_1.respond);
84
+ const readHandler = (0, async_handler_1.default)(async (req, res, next) => {
85
+ const service = new services_1.SharesService({
86
+ accountability: req.accountability,
87
+ schema: req.schema,
88
+ });
89
+ const records = await service.readByQuery(req.sanitizedQuery);
90
+ res.locals.payload = { data: records || null };
91
+ return next();
92
+ });
93
+ router.get('/', (0, validate_batch_1.validateBatch)('read'), readHandler, respond_1.respond);
94
+ router.search('/', (0, validate_batch_1.validateBatch)('read'), readHandler, respond_1.respond);
95
+ router.get(`/info/:pk(${constants_1.UUID_REGEX})`, (0, async_handler_1.default)(async (req, res, next) => {
96
+ const service = new services_1.SharesService({
97
+ schema: req.schema,
98
+ });
99
+ const record = await service.readOne(req.params.pk, {
100
+ fields: ['id', 'collection', 'item', 'password', 'max_uses', 'times_used', 'date_start', 'date_end'],
101
+ filter: {
102
+ _and: [
103
+ {
104
+ _or: [
105
+ {
106
+ date_start: {
107
+ _lte: new Date().toISOString(),
108
+ },
109
+ },
110
+ {
111
+ date_start: {
112
+ _null: true,
113
+ },
114
+ },
115
+ ],
116
+ },
117
+ {
118
+ _or: [
119
+ {
120
+ date_end: {
121
+ _gte: new Date().toISOString(),
122
+ },
123
+ },
124
+ {
125
+ date_end: {
126
+ _null: true,
127
+ },
128
+ },
129
+ ],
130
+ },
131
+ ],
132
+ },
133
+ });
134
+ res.locals.payload = { data: record || null };
135
+ return next();
136
+ }), respond_1.respond);
137
+ router.get(`/:pk(${constants_1.UUID_REGEX})`, (0, async_handler_1.default)(async (req, res, next) => {
138
+ const service = new services_1.SharesService({
139
+ accountability: req.accountability,
140
+ schema: req.schema,
141
+ });
142
+ const record = await service.readOne(req.params.pk, req.sanitizedQuery);
143
+ res.locals.payload = { data: record || null };
144
+ return next();
145
+ }), respond_1.respond);
146
+ router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handler_1.default)(async (req, res, next) => {
147
+ const service = new services_1.SharesService({
148
+ accountability: req.accountability,
149
+ schema: req.schema,
150
+ });
151
+ let keys = [];
152
+ if (req.body.keys) {
153
+ keys = await service.updateMany(req.body.keys, req.body.data);
154
+ }
155
+ else {
156
+ keys = await service.updateByQuery(req.body.query, req.body.data);
157
+ }
158
+ try {
159
+ const result = await service.readMany(keys, req.sanitizedQuery);
160
+ res.locals.payload = { data: result };
161
+ }
162
+ catch (error) {
163
+ if (error instanceof exceptions_1.ForbiddenException) {
164
+ return next();
165
+ }
166
+ throw error;
167
+ }
168
+ return next();
169
+ }), respond_1.respond);
170
+ router.patch(`/:pk(${constants_1.UUID_REGEX})`, (0, async_handler_1.default)(async (req, res, next) => {
171
+ const service = new services_1.SharesService({
172
+ accountability: req.accountability,
173
+ schema: req.schema,
174
+ });
175
+ const primaryKey = await service.updateOne(req.params.pk, req.body);
176
+ try {
177
+ const item = await service.readOne(primaryKey, req.sanitizedQuery);
178
+ res.locals.payload = { data: item || null };
179
+ }
180
+ catch (error) {
181
+ if (error instanceof exceptions_1.ForbiddenException) {
182
+ return next();
183
+ }
184
+ throw error;
185
+ }
186
+ return next();
187
+ }), respond_1.respond);
188
+ router.delete('/', (0, async_handler_1.default)(async (req, _res, next) => {
189
+ const service = new services_1.SharesService({
190
+ accountability: req.accountability,
191
+ schema: req.schema,
192
+ });
193
+ if (Array.isArray(req.body)) {
194
+ await service.deleteMany(req.body);
195
+ }
196
+ else if (req.body.keys) {
197
+ await service.deleteMany(req.body.keys);
198
+ }
199
+ else {
200
+ await service.deleteByQuery(req.body.query);
201
+ }
202
+ return next();
203
+ }), respond_1.respond);
204
+ router.delete(`/:pk(${constants_1.UUID_REGEX})`, (0, async_handler_1.default)(async (req, _res, next) => {
205
+ const service = new services_1.SharesService({
206
+ accountability: req.accountability,
207
+ schema: req.schema,
208
+ });
209
+ await service.deleteOne(req.params.pk);
210
+ return next();
211
+ }), respond_1.respond);
212
+ exports.default = router;