directus 9.4.1 → 9.5.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.
- package/README.md +1 -1
- package/dist/app.js +20 -1
- package/dist/auth/auth.d.ts +2 -1
- package/dist/auth/drivers/ldap.js +2 -1
- package/dist/auth/drivers/local.js +2 -1
- package/dist/auth/drivers/oauth2.js +12 -21
- package/dist/auth/drivers/openid.js +14 -3
- package/dist/cache.js +1 -3
- package/dist/cli/commands/init/questions.d.ts +3 -0
- package/dist/cli/commands/init/questions.js +2 -0
- package/dist/cli/index.js +1 -1
- package/dist/cli/utils/create-db-connection.d.ts +1 -1
- package/dist/cli/utils/create-db-connection.js +11 -1
- package/dist/cli/utils/drivers.d.ts +1 -0
- package/dist/cli/utils/drivers.js +2 -1
- package/dist/controllers/activity.js +2 -1
- package/dist/controllers/auth.js +5 -4
- package/dist/controllers/extensions.js +1 -1
- package/dist/controllers/files.js +3 -0
- package/dist/controllers/utils.js +2 -0
- package/dist/database/helpers/date/index.d.ts +1 -0
- package/dist/database/helpers/date/index.js +3 -1
- package/dist/database/helpers/geometry/index.d.ts +1 -0
- package/dist/database/helpers/geometry/index.js +3 -1
- package/dist/database/helpers/index.d.ts +2 -0
- package/dist/database/helpers/index.js +2 -0
- package/dist/database/helpers/schema/dialects/cockroachdb.d.ts +16 -0
- package/dist/database/helpers/schema/dialects/cockroachdb.js +16 -0
- package/dist/database/helpers/schema/dialects/default.d.ts +3 -0
- package/dist/database/helpers/schema/dialects/default.js +7 -0
- package/dist/database/helpers/schema/dialects/oracle.d.ts +12 -0
- package/dist/database/helpers/schema/dialects/oracle.js +13 -0
- package/dist/database/helpers/schema/index.d.ts +7 -0
- package/dist/database/helpers/schema/index.js +17 -0
- package/dist/database/helpers/schema/types.d.ts +25 -0
- package/dist/database/helpers/schema/types.js +89 -0
- package/dist/database/index.d.ts +1 -1
- package/dist/database/index.js +66 -17
- package/dist/database/migrations/20201105B-change-webhook-url-type.js +6 -25
- package/dist/database/migrations/20210312A-webhooks-collections-text.js +6 -25
- package/dist/database/migrations/20210415A-make-filesize-nullable.js +9 -4
- package/dist/database/migrations/20210506A-rename-interfaces.js +1 -1
- package/dist/database/migrations/20210510A-restructure-relations.js +12 -4
- package/dist/database/migrations/20210525A-add-insights.js +2 -2
- package/dist/database/migrations/20210626A-change-filesize-bigint.js +5 -7
- package/dist/database/migrations/20210903A-add-auth-provider.js +11 -2
- package/dist/database/migrations/20210907A-webhooks-collections-not-null.js +6 -20
- package/dist/database/migrations/20210920A-webhooks-url-not-null.js +10 -14
- package/dist/database/migrations/20211211A-add-shares.js +2 -2
- package/dist/database/migrations/20211230A-add-project-descriptor.d.ts +3 -0
- package/dist/database/migrations/20211230A-add-project-descriptor.js +15 -0
- package/dist/database/migrations/run.js +1 -1
- package/dist/database/run-ast.d.ts +1 -1
- package/dist/database/seeds/01-collections.yaml +1 -0
- package/dist/database/seeds/02-roles.yaml +1 -0
- package/dist/database/seeds/03-users.yaml +1 -0
- package/dist/database/system-data/fields/settings.yaml +11 -1
- package/dist/database/system-data/relations/index.d.ts +1 -1
- package/dist/emitter.d.ts +3 -4
- package/dist/emitter.js +2 -8
- package/dist/env.js +3 -0
- package/dist/exceptions/database/translate.js +1 -0
- package/dist/exceptions/index.d.ts +1 -0
- package/dist/exceptions/index.js +1 -0
- package/dist/exceptions/unsupported-media-type.d.ts +4 -0
- package/dist/exceptions/unsupported-media-type.js +10 -0
- package/dist/extensions.d.ts +14 -8
- package/dist/extensions.js +136 -69
- package/dist/logger.js +22 -1
- package/dist/middleware/authenticate.js +2 -1
- package/dist/middleware/extract-token.js +1 -1
- package/dist/middleware/rate-limiter.js +2 -1
- package/dist/services/assets.js +3 -3
- package/dist/services/authentication.d.ts +2 -2
- package/dist/services/authentication.js +7 -2
- package/dist/services/authorization.d.ts +2 -3
- package/dist/services/collections.d.ts +2 -2
- package/dist/services/collections.js +18 -18
- package/dist/services/fields.d.ts +2 -3
- package/dist/services/fields.js +19 -15
- package/dist/services/graphql.d.ts +3 -2
- package/dist/services/graphql.js +31 -5
- package/dist/services/import.d.ts +2 -2
- package/dist/services/import.js +2 -1
- package/dist/services/items.d.ts +2 -2
- package/dist/services/items.js +22 -18
- package/dist/services/mail/index.d.ts +2 -2
- package/dist/services/meta.d.ts +2 -2
- package/dist/services/payload.d.ts +2 -2
- package/dist/services/payload.js +7 -3
- package/dist/services/relations.d.ts +2 -2
- package/dist/services/server.d.ts +2 -2
- package/dist/services/server.js +1 -0
- package/dist/services/specifications.d.ts +2 -2
- package/dist/services/users.d.ts +2 -3
- package/dist/services/utils.d.ts +2 -2
- package/dist/types/ast.d.ts +1 -2
- package/dist/types/auth.d.ts +1 -3
- package/dist/types/index.d.ts +0 -3
- package/dist/types/index.js +0 -3
- package/dist/types/services.d.ts +1 -3
- package/dist/types/snapshot.d.ts +1 -2
- package/dist/utils/apply-query.d.ts +1 -2
- package/dist/utils/apply-query.js +1 -1
- package/dist/utils/apply-snapshot.d.ts +2 -1
- package/dist/utils/get-ast-from-query.d.ts +2 -3
- package/dist/utils/get-ip-from-req.d.ts +2 -0
- package/dist/utils/get-ip-from-req.js +24 -0
- package/dist/utils/get-local-type.js +1 -1
- package/dist/utils/get-permissions.d.ts +1 -2
- package/dist/utils/get-permissions.js +1 -1
- package/dist/utils/get-relation-type.d.ts +1 -1
- package/dist/utils/get-schema.d.ts +1 -2
- package/dist/utils/get-snapshot.d.ts +2 -1
- package/dist/utils/md.js +1 -1
- package/dist/utils/merge-permissions-for-share.d.ts +1 -2
- package/dist/utils/reduce-schema.d.ts +1 -2
- package/example.env +8 -0
- package/package.json +22 -15
- package/dist/cli/index.test.d.ts +0 -1
- package/dist/cli/index.test.js +0 -58
- package/dist/middleware/cache.test.d.ts +0 -1
- package/dist/middleware/cache.test.js +0 -62
- package/dist/tests/database/migrations/run.test.d.ts +0 -1
- package/dist/tests/database/migrations/run.test.js +0 -29
- package/dist/types/extensions.d.ts +0 -43
- package/dist/types/extensions.js +0 -2
- package/dist/types/relation.d.ts +0 -21
- package/dist/types/relation.js +0 -2
- package/dist/types/schema.d.ts +0 -32
- package/dist/types/schema.js +0 -2
- package/dist/utils/get-cache-key.test.d.ts +0 -1
- package/dist/utils/get-cache-key.test.js +0 -53
package/README.md
CHANGED
package/dist/app.js
CHANGED
|
@@ -27,6 +27,7 @@ const express_1 = __importDefault(require("express"));
|
|
|
27
27
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
28
28
|
const path_1 = __importDefault(require("path"));
|
|
29
29
|
const qs_1 = __importDefault(require("qs"));
|
|
30
|
+
const helmet_1 = __importDefault(require("helmet"));
|
|
30
31
|
const activity_1 = __importDefault(require("./controllers/activity"));
|
|
31
32
|
const assets_1 = __importDefault(require("./controllers/assets"));
|
|
32
33
|
const auth_1 = __importDefault(require("./controllers/auth"));
|
|
@@ -75,6 +76,8 @@ const webhooks_2 = require("./webhooks");
|
|
|
75
76
|
const cache_2 = require("./cache");
|
|
76
77
|
const auth_2 = require("./auth");
|
|
77
78
|
const url_1 = require("./utils/url");
|
|
79
|
+
const get_config_from_env_1 = require("./utils/get-config-from-env");
|
|
80
|
+
const lodash_1 = require("lodash");
|
|
78
81
|
async function createApp() {
|
|
79
82
|
(0, validate_env_1.validateEnv)(['KEY', 'SECRET']);
|
|
80
83
|
if (!new url_1.Url(env_1.default.PUBLIC_URL).isAbsolute()) {
|
|
@@ -96,8 +99,24 @@ async function createApp() {
|
|
|
96
99
|
await extensionManager.initialize();
|
|
97
100
|
const app = (0, express_1.default)();
|
|
98
101
|
app.disable('x-powered-by');
|
|
99
|
-
app.set('trust proxy',
|
|
102
|
+
app.set('trust proxy', env_1.default.IP_TRUST_PROXY);
|
|
100
103
|
app.set('query parser', (str) => qs_1.default.parse(str, { depth: 10 }));
|
|
104
|
+
app.use(helmet_1.default.contentSecurityPolicy((0, lodash_1.merge)({
|
|
105
|
+
useDefaults: true,
|
|
106
|
+
directives: {
|
|
107
|
+
// Unsafe-eval is required for vue3 / vue-i18n / app extensions
|
|
108
|
+
scriptSrc: ["'self'", "'unsafe-eval'"],
|
|
109
|
+
// Even though this is recommended to have enabled, it breaks most local
|
|
110
|
+
// installations. Making this opt-in rather than opt-out is a little more
|
|
111
|
+
// friendly. Ref #10806
|
|
112
|
+
upgradeInsecureRequests: null,
|
|
113
|
+
// These are required for MapLibre
|
|
114
|
+
workerSrc: ["'self'", 'blob:'],
|
|
115
|
+
childSrc: ["'self'", 'blob:'],
|
|
116
|
+
imgSrc: ["'self'", 'data:', 'blob:'],
|
|
117
|
+
connectSrc: ["'self'", 'https://*'],
|
|
118
|
+
},
|
|
119
|
+
}, (0, get_config_from_env_1.getConfigFromEnv)('CONTENT_SECURITY_POLICY_'))));
|
|
101
120
|
await emitter_1.default.emitInit('app.before', { app });
|
|
102
121
|
await emitter_1.default.emitInit('middlewares.before', { app });
|
|
103
122
|
app.use(logger_1.expressLogger);
|
package/dist/auth/auth.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { SchemaOverview } from '@directus/shared/types';
|
|
1
2
|
import { Knex } from 'knex';
|
|
2
|
-
import { AuthDriverOptions,
|
|
3
|
+
import { AuthDriverOptions, User } from '../types';
|
|
3
4
|
export declare abstract class AuthDriver {
|
|
4
5
|
knex: Knex;
|
|
5
6
|
schema: SchemaOverview;
|
|
@@ -26,6 +26,7 @@ exports.createLDAPAuthRouter = exports.LDAPAuthDriver = void 0;
|
|
|
26
26
|
const express_1 = require("express");
|
|
27
27
|
const ldapjs_1 = __importStar(require("ldapjs"));
|
|
28
28
|
const ms_1 = __importDefault(require("ms"));
|
|
29
|
+
const get_ip_from_req_1 = require("../../utils/get-ip-from-req");
|
|
29
30
|
const joi_1 = __importDefault(require("joi"));
|
|
30
31
|
const auth_1 = require("../auth");
|
|
31
32
|
const exceptions_1 = require("../../exceptions");
|
|
@@ -292,7 +293,7 @@ function createLDAPAuthRouter(provider) {
|
|
|
292
293
|
router.post('/', (0, async_handler_1.default)(async (req, res, next) => {
|
|
293
294
|
var _a, _b;
|
|
294
295
|
const accountability = {
|
|
295
|
-
ip: req
|
|
296
|
+
ip: (0, get_ip_from_req_1.getIPFromReq)(req),
|
|
296
297
|
userAgent: req.get('user-agent'),
|
|
297
298
|
role: null,
|
|
298
299
|
};
|
|
@@ -14,6 +14,7 @@ const async_handler_1 = __importDefault(require("../../utils/async-handler"));
|
|
|
14
14
|
const env_1 = __importDefault(require("../../env"));
|
|
15
15
|
const respond_1 = require("../../middleware/respond");
|
|
16
16
|
const constants_1 = require("../../constants");
|
|
17
|
+
const get_ip_from_req_1 = require("../../utils/get-ip-from-req");
|
|
17
18
|
class LocalAuthDriver extends auth_1.AuthDriver {
|
|
18
19
|
async getUserID(payload) {
|
|
19
20
|
if (!payload.email) {
|
|
@@ -50,7 +51,7 @@ function createLocalAuthRouter(provider) {
|
|
|
50
51
|
router.post('/', (0, async_handler_1.default)(async (req, res, next) => {
|
|
51
52
|
var _a;
|
|
52
53
|
const accountability = {
|
|
53
|
-
ip: req
|
|
54
|
+
ip: (0, get_ip_from_req_1.getIPFromReq)(req),
|
|
54
55
|
userAgent: req.get('user-agent'),
|
|
55
56
|
role: null,
|
|
56
57
|
};
|
|
@@ -17,11 +17,12 @@ const respond_1 = require("../../middleware/respond");
|
|
|
17
17
|
const async_handler_1 = __importDefault(require("../../utils/async-handler"));
|
|
18
18
|
const url_1 = require("../../utils/url");
|
|
19
19
|
const logger_1 = __importDefault(require("../../logger"));
|
|
20
|
+
const get_ip_from_req_1 = require("../../utils/get-ip-from-req");
|
|
20
21
|
class OAuth2AuthDriver extends local_1.LocalAuthDriver {
|
|
21
22
|
constructor(options, config) {
|
|
22
23
|
super(options, config);
|
|
23
24
|
const { authorizeUrl, accessUrl, profileUrl, clientId, clientSecret, ...additionalConfig } = config;
|
|
24
|
-
if (!authorizeUrl || !accessUrl || !clientId || !clientSecret || !additionalConfig.provider) {
|
|
25
|
+
if (!authorizeUrl || !accessUrl || !profileUrl || !clientId || !clientSecret || !additionalConfig.provider) {
|
|
25
26
|
throw new exceptions_1.InvalidConfigException('Invalid provider config', { provider: additionalConfig.provider });
|
|
26
27
|
}
|
|
27
28
|
const redirectUrl = new url_1.Url(env_1.default.PUBLIC_URL).addPath('auth', 'login', additionalConfig.provider, 'callback');
|
|
@@ -32,8 +33,7 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
|
|
|
32
33
|
authorization_endpoint: authorizeUrl,
|
|
33
34
|
token_endpoint: accessUrl,
|
|
34
35
|
userinfo_endpoint: profileUrl,
|
|
35
|
-
|
|
36
|
-
issuer: additionalConfig.issuerUrl,
|
|
36
|
+
issuer: additionalConfig.provider,
|
|
37
37
|
});
|
|
38
38
|
this.client = new issuer.Client({
|
|
39
39
|
client_id: clientId,
|
|
@@ -83,16 +83,7 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
|
|
|
83
83
|
let userInfo;
|
|
84
84
|
try {
|
|
85
85
|
tokenSet = await this.client.oauthCallback(this.redirectUrl, { code: payload.code, state: payload.state }, { code_verifier: payload.codeVerifier, state: openid_client_1.generators.codeChallenge(payload.codeVerifier) });
|
|
86
|
-
|
|
87
|
-
if (issuer.metadata.userinfo_endpoint) {
|
|
88
|
-
userInfo = await this.client.userinfo(tokenSet.access_token);
|
|
89
|
-
}
|
|
90
|
-
else if (tokenSet.id_token) {
|
|
91
|
-
userInfo = tokenSet.claims();
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
throw new exceptions_1.InvalidConfigException('OAuth profile URL not defined', { provider: this.config.provider });
|
|
95
|
-
}
|
|
86
|
+
userInfo = await this.client.userinfo(tokenSet.access_token);
|
|
96
87
|
}
|
|
97
88
|
catch (e) {
|
|
98
89
|
throw handleError(e);
|
|
@@ -102,7 +93,7 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
|
|
|
102
93
|
// Fallback to email if explicit identifier not found
|
|
103
94
|
const identifier = (_a = userInfo[identifierKey]) !== null && _a !== void 0 ? _a : email;
|
|
104
95
|
if (!identifier) {
|
|
105
|
-
logger_1.default.warn(`Failed to find user identifier for provider "${this.config.provider}"`);
|
|
96
|
+
logger_1.default.warn(`[OAuth2] Failed to find user identifier for provider "${this.config.provider}"`);
|
|
106
97
|
throw new exceptions_1.InvalidCredentialsException();
|
|
107
98
|
}
|
|
108
99
|
const userId = await this.fetchUserId(identifier);
|
|
@@ -139,7 +130,7 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
|
|
|
139
130
|
authData = JSON.parse(authData);
|
|
140
131
|
}
|
|
141
132
|
catch {
|
|
142
|
-
logger_1.default.warn(`Session data isn't valid JSON: ${authData}`);
|
|
133
|
+
logger_1.default.warn(`[OAuth2] Session data isn't valid JSON: ${authData}`);
|
|
143
134
|
}
|
|
144
135
|
}
|
|
145
136
|
if (authData === null || authData === void 0 ? void 0 : authData.refreshToken) {
|
|
@@ -162,12 +153,12 @@ exports.OAuth2AuthDriver = OAuth2AuthDriver;
|
|
|
162
153
|
const handleError = (e) => {
|
|
163
154
|
if (e instanceof openid_client_1.errors.OPError) {
|
|
164
155
|
if (e.error === 'invalid_grant') {
|
|
165
|
-
logger_1.default.trace(e, `[OAuth2] Invalid grant.`);
|
|
166
156
|
// Invalid token
|
|
157
|
+
logger_1.default.trace(e, `[OAuth2] Invalid grant`);
|
|
167
158
|
return new exceptions_1.InvalidTokenException();
|
|
168
159
|
}
|
|
169
|
-
logger_1.default.trace(e, `[OAuth2] Unknown OP error.`);
|
|
170
160
|
// Server response error
|
|
161
|
+
logger_1.default.trace(e, `[OAuth2] Unknown OP error`);
|
|
171
162
|
return new exceptions_1.ServiceUnavailableException('Service returned unexpected response', {
|
|
172
163
|
service: 'oauth2',
|
|
173
164
|
message: e.error_description,
|
|
@@ -175,10 +166,10 @@ const handleError = (e) => {
|
|
|
175
166
|
}
|
|
176
167
|
else if (e instanceof openid_client_1.errors.RPError) {
|
|
177
168
|
// Internal client error
|
|
178
|
-
logger_1.default.trace(e, `[OAuth2] Unknown RP error
|
|
169
|
+
logger_1.default.trace(e, `[OAuth2] Unknown RP error`);
|
|
179
170
|
return new exceptions_1.InvalidCredentialsException();
|
|
180
171
|
}
|
|
181
|
-
logger_1.default.trace(e, `[OAuth2] Unknown error
|
|
172
|
+
logger_1.default.trace(e, `[OAuth2] Unknown error`);
|
|
182
173
|
return e;
|
|
183
174
|
};
|
|
184
175
|
function createOAuth2AuthRouter(providerName) {
|
|
@@ -210,7 +201,7 @@ function createOAuth2AuthRouter(providerName) {
|
|
|
210
201
|
const { verifier, redirect, prompt } = tokenData;
|
|
211
202
|
const authenticationService = new services_1.AuthenticationService({
|
|
212
203
|
accountability: {
|
|
213
|
-
ip: req
|
|
204
|
+
ip: (0, get_ip_from_req_1.getIPFromReq)(req),
|
|
214
205
|
userAgent: req.get('user-agent'),
|
|
215
206
|
role: null,
|
|
216
207
|
},
|
|
@@ -220,7 +211,7 @@ function createOAuth2AuthRouter(providerName) {
|
|
|
220
211
|
try {
|
|
221
212
|
res.clearCookie(`oauth2.${providerName}`);
|
|
222
213
|
if (!req.query.code || !req.query.state) {
|
|
223
|
-
logger_1.default.warn(`[OAuth2]Couldn't extract OAuth2 code or state from query: ${JSON.stringify(req.query)}`);
|
|
214
|
+
logger_1.default.warn(`[OAuth2] Couldn't extract OAuth2 code or state from query: ${JSON.stringify(req.query)}`);
|
|
224
215
|
}
|
|
225
216
|
authResponse = await authenticationService.login(providerName, {
|
|
226
217
|
code: req.query.code,
|
|
@@ -17,6 +17,7 @@ const respond_1 = require("../../middleware/respond");
|
|
|
17
17
|
const async_handler_1 = __importDefault(require("../../utils/async-handler"));
|
|
18
18
|
const url_1 = require("../../utils/url");
|
|
19
19
|
const logger_1 = __importDefault(require("../../logger"));
|
|
20
|
+
const get_ip_from_req_1 = require("../../utils/get-ip-from-req");
|
|
20
21
|
class OpenIDAuthDriver extends local_1.LocalAuthDriver {
|
|
21
22
|
constructor(options, config) {
|
|
22
23
|
super(options, config);
|
|
@@ -82,6 +83,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
|
|
|
82
83
|
async getUserID(payload) {
|
|
83
84
|
var _a;
|
|
84
85
|
if (!payload.code || !payload.codeVerifier) {
|
|
86
|
+
logger_1.default.trace('[OpenID] No code or codeVerifier in payload');
|
|
85
87
|
throw new exceptions_1.InvalidCredentialsException();
|
|
86
88
|
}
|
|
87
89
|
let tokenSet;
|
|
@@ -105,7 +107,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
|
|
|
105
107
|
// Fallback to email if explicit identifier not found
|
|
106
108
|
const identifier = (_a = userInfo[identifierKey !== null && identifierKey !== void 0 ? identifierKey : 'sub']) !== null && _a !== void 0 ? _a : email;
|
|
107
109
|
if (!identifier) {
|
|
108
|
-
logger_1.default.warn(`Failed to find user identifier for provider "${this.config.provider}"`);
|
|
110
|
+
logger_1.default.warn(`[OpenID] Failed to find user identifier for provider "${this.config.provider}"`);
|
|
109
111
|
throw new exceptions_1.InvalidCredentialsException();
|
|
110
112
|
}
|
|
111
113
|
const userId = await this.fetchUserId(identifier);
|
|
@@ -121,6 +123,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
|
|
|
121
123
|
const isEmailVerified = !requireVerifiedEmail || userInfo.email_verified;
|
|
122
124
|
// Is public registration allowed?
|
|
123
125
|
if (!allowPublicRegistration || !isEmailVerified) {
|
|
126
|
+
logger_1.default.trace(`[OpenID] User doesn't exist, and public registration not allowed for provider "${this.config.provider}"`);
|
|
124
127
|
throw new exceptions_1.InvalidCredentialsException();
|
|
125
128
|
}
|
|
126
129
|
await this.usersService.createOne({
|
|
@@ -144,7 +147,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
|
|
|
144
147
|
authData = JSON.parse(authData);
|
|
145
148
|
}
|
|
146
149
|
catch {
|
|
147
|
-
logger_1.default.warn(`Session data isn't valid JSON: ${authData}`);
|
|
150
|
+
logger_1.default.warn(`[OpenID] Session data isn't valid JSON: ${authData}`);
|
|
148
151
|
}
|
|
149
152
|
}
|
|
150
153
|
if (authData === null || authData === void 0 ? void 0 : authData.refreshToken) {
|
|
@@ -169,9 +172,11 @@ const handleError = (e) => {
|
|
|
169
172
|
if (e instanceof openid_client_1.errors.OPError) {
|
|
170
173
|
if (e.error === 'invalid_grant') {
|
|
171
174
|
// Invalid token
|
|
175
|
+
logger_1.default.trace(e, `[OpenID] Invalid grant`);
|
|
172
176
|
return new exceptions_1.InvalidTokenException();
|
|
173
177
|
}
|
|
174
178
|
// Server response error
|
|
179
|
+
logger_1.default.trace(e, `[OpenID] Unknown OP error`);
|
|
175
180
|
return new exceptions_1.ServiceUnavailableException('Service returned unexpected response', {
|
|
176
181
|
service: 'openid',
|
|
177
182
|
message: e.error_description,
|
|
@@ -179,8 +184,10 @@ const handleError = (e) => {
|
|
|
179
184
|
}
|
|
180
185
|
else if (e instanceof openid_client_1.errors.RPError) {
|
|
181
186
|
// Internal client error
|
|
187
|
+
logger_1.default.trace(e, `[OpenID] Unknown RP error`);
|
|
182
188
|
return new exceptions_1.InvalidCredentialsException();
|
|
183
189
|
}
|
|
190
|
+
logger_1.default.trace(e, `[OpenID] Unknown error`);
|
|
184
191
|
return e;
|
|
185
192
|
};
|
|
186
193
|
function createOpenIDAuthRouter(providerName) {
|
|
@@ -212,7 +219,7 @@ function createOpenIDAuthRouter(providerName) {
|
|
|
212
219
|
const { verifier, redirect, prompt } = tokenData;
|
|
213
220
|
const authenticationService = new services_1.AuthenticationService({
|
|
214
221
|
accountability: {
|
|
215
|
-
ip: req
|
|
222
|
+
ip: (0, get_ip_from_req_1.getIPFromReq)(req),
|
|
216
223
|
userAgent: req.get('user-agent'),
|
|
217
224
|
role: null,
|
|
218
225
|
},
|
|
@@ -247,8 +254,12 @@ function createOpenIDAuthRouter(providerName) {
|
|
|
247
254
|
else if (error instanceof exceptions_1.InvalidTokenException) {
|
|
248
255
|
reason = 'INVALID_TOKEN';
|
|
249
256
|
}
|
|
257
|
+
else {
|
|
258
|
+
logger_1.default.warn(error, `[OpenID] Unexpected error during OpenID login`);
|
|
259
|
+
}
|
|
250
260
|
return res.redirect(`${redirect.split('?')[0]}?reason=${reason}`);
|
|
251
261
|
}
|
|
262
|
+
logger_1.default.warn(error, `[OpenID] Unexpected error during OpenID login`);
|
|
252
263
|
throw error;
|
|
253
264
|
}
|
|
254
265
|
const { accessToken, refreshToken, expires } = authResponse;
|
package/dist/cache.js
CHANGED
|
@@ -49,9 +49,7 @@ function getConfig(store = 'memory', ttl, namespaceSuffix = '') {
|
|
|
49
49
|
};
|
|
50
50
|
if (store === 'redis') {
|
|
51
51
|
const KeyvRedis = require('@keyv/redis');
|
|
52
|
-
config.store = new KeyvRedis(env_1.default.CACHE_REDIS || (0, get_config_from_env_1.getConfigFromEnv)('CACHE_REDIS_')
|
|
53
|
-
commandTimeout: 500,
|
|
54
|
-
});
|
|
52
|
+
config.store = new KeyvRedis(env_1.default.CACHE_REDIS || (0, get_config_from_env_1.getConfigFromEnv)('CACHE_REDIS_'));
|
|
55
53
|
}
|
|
56
54
|
if (store === 'memcache') {
|
|
57
55
|
const KeyvMemcache = require('keyv-memcache');
|
|
@@ -8,6 +8,9 @@ export declare const databaseQuestions: {
|
|
|
8
8
|
pg: (({ client }: {
|
|
9
9
|
client: string;
|
|
10
10
|
}) => Record<string, any>)[];
|
|
11
|
+
cockroachdb: (({ client }: {
|
|
12
|
+
client: string;
|
|
13
|
+
}) => Record<string, any>)[];
|
|
11
14
|
oracledb: (({ client }: {
|
|
12
15
|
client: string;
|
|
13
16
|
}) => Record<string, any>)[];
|
|
@@ -24,6 +24,7 @@ const port = ({ client }) => ({
|
|
|
24
24
|
default() {
|
|
25
25
|
const ports = {
|
|
26
26
|
pg: 5432,
|
|
27
|
+
cockroachdb: 26257,
|
|
27
28
|
mysql: 3306,
|
|
28
29
|
oracledb: 1521,
|
|
29
30
|
mssql: 1433,
|
|
@@ -64,6 +65,7 @@ exports.databaseQuestions = {
|
|
|
64
65
|
sqlite3: [filename],
|
|
65
66
|
mysql: [host, port, database, user, password],
|
|
66
67
|
pg: [host, port, database, user, password, ssl],
|
|
68
|
+
cockroachdb: [host, port, database, user, password, ssl],
|
|
67
69
|
oracledb: [host, port, database, user, password],
|
|
68
70
|
mssql: [host, port, database, user, password, encrypt],
|
|
69
71
|
};
|
package/dist/cli/index.js
CHANGED
|
@@ -22,7 +22,7 @@ const pkg = require('../../package.json');
|
|
|
22
22
|
async function createCli() {
|
|
23
23
|
const program = new commander_1.Command();
|
|
24
24
|
const extensionManager = (0, extensions_1.getExtensionManager)();
|
|
25
|
-
await extensionManager.initialize({ schedule: false });
|
|
25
|
+
await extensionManager.initialize({ schedule: false, watch: false });
|
|
26
26
|
await emitter_1.default.emitInit('cli.before', { program });
|
|
27
27
|
program.name('directus').usage('[command] [options]');
|
|
28
28
|
program.version(pkg.version, '-v, --version');
|
|
@@ -9,4 +9,4 @@ export declare type Credentials = {
|
|
|
9
9
|
ssl?: boolean;
|
|
10
10
|
options__encrypt?: boolean;
|
|
11
11
|
};
|
|
12
|
-
export default function createDBConnection(client: 'sqlite3' | 'mysql' | 'pg' | 'oracledb' | 'mssql', credentials: Credentials): Knex<any, unknown[]>;
|
|
12
|
+
export default function createDBConnection(client: 'sqlite3' | 'mysql' | 'pg' | 'oracledb' | 'mssql' | 'cockroachdb', credentials: Credentials): Knex<any, unknown[]>;
|
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const knex_1 = require("knex");
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const util_1 = require("util");
|
|
8
9
|
function createDBConnection(client, credentials) {
|
|
9
10
|
let connection = {};
|
|
10
11
|
if (client === 'sqlite3') {
|
|
@@ -22,7 +23,7 @@ function createDBConnection(client, credentials) {
|
|
|
22
23
|
user: user,
|
|
23
24
|
password: password,
|
|
24
25
|
};
|
|
25
|
-
if (client === 'pg') {
|
|
26
|
+
if (client === 'pg' || client === 'cockroachdb') {
|
|
26
27
|
const { ssl } = credentials;
|
|
27
28
|
connection['ssl'] = ssl;
|
|
28
29
|
}
|
|
@@ -40,10 +41,19 @@ function createDBConnection(client, credentials) {
|
|
|
40
41
|
extension: 'js',
|
|
41
42
|
directory: path_1.default.resolve(__dirname, '../../database/seeds/'),
|
|
42
43
|
},
|
|
44
|
+
pool: {},
|
|
43
45
|
};
|
|
44
46
|
if (client === 'sqlite3') {
|
|
45
47
|
knexConfig.useNullAsDefault = true;
|
|
46
48
|
}
|
|
49
|
+
if (client === 'cockroachdb') {
|
|
50
|
+
knexConfig.pool.afterCreate = async (conn, callback) => {
|
|
51
|
+
const run = (0, util_1.promisify)(conn.query.bind(conn));
|
|
52
|
+
await run('SET serial_normalization = "sql_sequence"');
|
|
53
|
+
await run('SET default_int_size = 4');
|
|
54
|
+
callback(null, conn);
|
|
55
|
+
};
|
|
56
|
+
}
|
|
47
57
|
const db = (0, knex_1.knex)(knexConfig);
|
|
48
58
|
return db;
|
|
49
59
|
}
|
|
@@ -3,10 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.getDriverForClient = exports.drivers = void 0;
|
|
4
4
|
exports.drivers = {
|
|
5
5
|
pg: 'PostgreSQL / Redshift',
|
|
6
|
+
cockroachdb: 'CockroachDB (Beta)',
|
|
6
7
|
mysql: 'MySQL / MariaDB / Aurora',
|
|
7
8
|
sqlite3: 'SQLite',
|
|
8
9
|
mssql: 'Microsoft SQL Server',
|
|
9
|
-
oracledb: 'Oracle Database
|
|
10
|
+
oracledb: 'Oracle Database',
|
|
10
11
|
};
|
|
11
12
|
function getDriverForClient(client) {
|
|
12
13
|
for (const [key, value] of Object.entries(exports.drivers)) {
|
|
@@ -12,6 +12,7 @@ const validate_batch_1 = require("../middleware/validate-batch");
|
|
|
12
12
|
const services_1 = require("../services");
|
|
13
13
|
const types_1 = require("../types");
|
|
14
14
|
const async_handler_1 = __importDefault(require("../utils/async-handler"));
|
|
15
|
+
const get_ip_from_req_1 = require("../utils/get-ip-from-req");
|
|
15
16
|
const router = express_1.default.Router();
|
|
16
17
|
router.use((0, use_collection_1.default)('directus_activity'));
|
|
17
18
|
const readHandler = (0, async_handler_1.default)(async (req, res, next) => {
|
|
@@ -72,7 +73,7 @@ router.post('/comment', (0, async_handler_1.default)(async (req, res, next) => {
|
|
|
72
73
|
...req.body,
|
|
73
74
|
action: types_1.Action.COMMENT,
|
|
74
75
|
user: (_a = req.accountability) === null || _a === void 0 ? void 0 : _a.user,
|
|
75
|
-
ip: req
|
|
76
|
+
ip: (0, get_ip_from_req_1.getIPFromReq)(req),
|
|
76
77
|
user_agent: req.get('user-agent'),
|
|
77
78
|
});
|
|
78
79
|
try {
|
package/dist/controllers/auth.js
CHANGED
|
@@ -14,6 +14,7 @@ const get_auth_providers_1 = require("../utils/get-auth-providers");
|
|
|
14
14
|
const logger_1 = __importDefault(require("../logger"));
|
|
15
15
|
const drivers_1 = require("../auth/drivers");
|
|
16
16
|
const constants_1 = require("../constants");
|
|
17
|
+
const get_ip_from_req_1 = require("../utils/get-ip-from-req");
|
|
17
18
|
const router = (0, express_1.Router)();
|
|
18
19
|
const authProviders = (0, get_auth_providers_1.getAuthProviders)();
|
|
19
20
|
for (const authProvider of authProviders) {
|
|
@@ -44,7 +45,7 @@ if (!env_1.default.AUTH_DISABLE_DEFAULT) {
|
|
|
44
45
|
router.post('/refresh', (0, async_handler_1.default)(async (req, res, next) => {
|
|
45
46
|
var _a;
|
|
46
47
|
const accountability = {
|
|
47
|
-
ip: req
|
|
48
|
+
ip: (0, get_ip_from_req_1.getIPFromReq)(req),
|
|
48
49
|
userAgent: req.get('user-agent'),
|
|
49
50
|
role: null,
|
|
50
51
|
};
|
|
@@ -79,7 +80,7 @@ router.post('/refresh', (0, async_handler_1.default)(async (req, res, next) => {
|
|
|
79
80
|
router.post('/logout', (0, async_handler_1.default)(async (req, res, next) => {
|
|
80
81
|
var _a;
|
|
81
82
|
const accountability = {
|
|
82
|
-
ip: req
|
|
83
|
+
ip: (0, get_ip_from_req_1.getIPFromReq)(req),
|
|
83
84
|
userAgent: req.get('user-agent'),
|
|
84
85
|
role: null,
|
|
85
86
|
};
|
|
@@ -107,7 +108,7 @@ router.post('/password/request', (0, async_handler_1.default)(async (req, res, n
|
|
|
107
108
|
throw new exceptions_1.InvalidPayloadException(`"email" field is required.`);
|
|
108
109
|
}
|
|
109
110
|
const accountability = {
|
|
110
|
-
ip: req
|
|
111
|
+
ip: (0, get_ip_from_req_1.getIPFromReq)(req),
|
|
111
112
|
userAgent: req.get('user-agent'),
|
|
112
113
|
role: null,
|
|
113
114
|
};
|
|
@@ -134,7 +135,7 @@ router.post('/password/reset', (0, async_handler_1.default)(async (req, res, nex
|
|
|
134
135
|
throw new exceptions_1.InvalidPayloadException(`"password" field is required.`);
|
|
135
136
|
}
|
|
136
137
|
const accountability = {
|
|
137
|
-
ip: req
|
|
138
|
+
ip: (0, get_ip_from_req_1.getIPFromReq)(req),
|
|
138
139
|
userAgent: req.get('user-agent'),
|
|
139
140
|
role: null,
|
|
140
141
|
};
|
|
@@ -16,7 +16,7 @@ router.get('/:type', (0, async_handler_1.default)(async (req, res, next) => {
|
|
|
16
16
|
throw new exceptions_1.RouteNotFoundException(req.path);
|
|
17
17
|
}
|
|
18
18
|
const extensionManager = (0, extensions_1.getExtensionManager)();
|
|
19
|
-
const extensions = extensionManager.
|
|
19
|
+
const extensions = extensionManager.getExtensionsList(type);
|
|
20
20
|
res.locals.payload = {
|
|
21
21
|
data: extensions,
|
|
22
22
|
};
|
|
@@ -93,6 +93,9 @@ const multipartHandler = (0, async_handler_1.default)(async (req, res, next) =>
|
|
|
93
93
|
}
|
|
94
94
|
});
|
|
95
95
|
router.post('/', multipartHandler, (0, async_handler_1.default)(async (req, res, next) => {
|
|
96
|
+
if (req.is('multipart/form-data') === false) {
|
|
97
|
+
throw new exceptions_1.UnsupportedMediaTypeException(`Unsupported Content-Type header`);
|
|
98
|
+
}
|
|
96
99
|
const service = new services_1.FilesService({
|
|
97
100
|
accountability: req.accountability,
|
|
98
101
|
schema: req.schema,
|
|
@@ -66,6 +66,8 @@ router.post('/revert/:revision', (0, async_handler_1.default)(async (req, res, n
|
|
|
66
66
|
next();
|
|
67
67
|
}), respond_1.respond);
|
|
68
68
|
router.post('/import/:collection', collection_exists_1.default, (0, async_handler_1.default)(async (req, res, next) => {
|
|
69
|
+
if (req.is('multipart/form-data') === false)
|
|
70
|
+
throw new exceptions_1.UnsupportedMediaTypeException(`Unsupported Content-Type header`);
|
|
69
71
|
const service = new services_1.ImportService({
|
|
70
72
|
accountability: req.accountability,
|
|
71
73
|
schema: req.schema,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { DateHelperPostgres as postgres } from './dialects/postgres';
|
|
2
2
|
export { DateHelperPostgres as redshift } from './dialects/postgres';
|
|
3
|
+
export { DateHelperPostgres as cockroachdb } from './dialects/postgres';
|
|
3
4
|
export { DateHelperOracle as oracle } from './dialects/oracle';
|
|
4
5
|
export { DateHelperSQLite as sqlite } from './dialects/sqlite';
|
|
5
6
|
export { DateHelperMySQL as mysql } from './dialects/mysql';
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.mssql = exports.mysql = exports.sqlite = exports.oracle = exports.redshift = exports.postgres = void 0;
|
|
3
|
+
exports.mssql = exports.mysql = exports.sqlite = exports.oracle = exports.cockroachdb = exports.redshift = exports.postgres = void 0;
|
|
4
4
|
var postgres_1 = require("./dialects/postgres");
|
|
5
5
|
Object.defineProperty(exports, "postgres", { enumerable: true, get: function () { return postgres_1.DateHelperPostgres; } });
|
|
6
6
|
var postgres_2 = require("./dialects/postgres");
|
|
7
7
|
Object.defineProperty(exports, "redshift", { enumerable: true, get: function () { return postgres_2.DateHelperPostgres; } });
|
|
8
|
+
var postgres_3 = require("./dialects/postgres");
|
|
9
|
+
Object.defineProperty(exports, "cockroachdb", { enumerable: true, get: function () { return postgres_3.DateHelperPostgres; } });
|
|
8
10
|
var oracle_1 = require("./dialects/oracle");
|
|
9
11
|
Object.defineProperty(exports, "oracle", { enumerable: true, get: function () { return oracle_1.DateHelperOracle; } });
|
|
10
12
|
var sqlite_1 = require("./dialects/sqlite");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { GeometryHelperPostgres as postgres } from './dialects/postgres';
|
|
2
|
+
export { GeometryHelperPostgres as cockroachdb } from './dialects/postgres';
|
|
2
3
|
export { GeometryHelperRedshift as redshift } from './dialects/redshift';
|
|
3
4
|
export { GeometryHelperOracle as oracle } from './dialects/oracle';
|
|
4
5
|
export { GeometryHelperSQLite as sqlite } from './dialects/sqlite';
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.mssql = exports.mysql = exports.sqlite = exports.oracle = exports.redshift = exports.postgres = void 0;
|
|
3
|
+
exports.mssql = exports.mysql = exports.sqlite = exports.oracle = exports.redshift = exports.cockroachdb = exports.postgres = void 0;
|
|
4
4
|
var postgres_1 = require("./dialects/postgres");
|
|
5
5
|
Object.defineProperty(exports, "postgres", { enumerable: true, get: function () { return postgres_1.GeometryHelperPostgres; } });
|
|
6
|
+
var postgres_2 = require("./dialects/postgres");
|
|
7
|
+
Object.defineProperty(exports, "cockroachdb", { enumerable: true, get: function () { return postgres_2.GeometryHelperPostgres; } });
|
|
6
8
|
var redshift_1 = require("./dialects/redshift");
|
|
7
9
|
Object.defineProperty(exports, "redshift", { enumerable: true, get: function () { return redshift_1.GeometryHelperRedshift; } });
|
|
8
10
|
var oracle_1 = require("./dialects/oracle");
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { Knex } from 'knex';
|
|
2
2
|
import * as dateHelpers from './date';
|
|
3
3
|
import * as geometryHelpers from './geometry';
|
|
4
|
+
import * as schemaHelpers from './schema';
|
|
4
5
|
export declare function getHelpers(database: Knex): {
|
|
5
6
|
date: dateHelpers.postgres | dateHelpers.oracle | dateHelpers.sqlite | dateHelpers.mysql | dateHelpers.mssql;
|
|
6
7
|
st: geometryHelpers.postgres | geometryHelpers.redshift | geometryHelpers.oracle | geometryHelpers.sqlite | geometryHelpers.mysql | geometryHelpers.mssql;
|
|
8
|
+
schema: schemaHelpers.postgres | schemaHelpers.cockroachdb | schemaHelpers.oracle;
|
|
7
9
|
};
|
|
8
10
|
export declare type Helpers = ReturnType<typeof getHelpers>;
|
|
@@ -23,11 +23,13 @@ exports.getHelpers = void 0;
|
|
|
23
23
|
const __1 = require("..");
|
|
24
24
|
const dateHelpers = __importStar(require("./date"));
|
|
25
25
|
const geometryHelpers = __importStar(require("./geometry"));
|
|
26
|
+
const schemaHelpers = __importStar(require("./schema"));
|
|
26
27
|
function getHelpers(database) {
|
|
27
28
|
const client = (0, __1.getDatabaseClient)(database);
|
|
28
29
|
return {
|
|
29
30
|
date: new dateHelpers[client](database),
|
|
30
31
|
st: new geometryHelpers[client](database),
|
|
32
|
+
schema: new schemaHelpers[client](database),
|
|
31
33
|
};
|
|
32
34
|
}
|
|
33
35
|
exports.getHelpers = getHelpers;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { SchemaHelper } from '../types';
|
|
2
|
+
export declare class SchemaHelperCockroachDb extends SchemaHelper {
|
|
3
|
+
changeToText(table: string, column: string, options?: {
|
|
4
|
+
nullable?: boolean;
|
|
5
|
+
default?: any;
|
|
6
|
+
}): Promise<void>;
|
|
7
|
+
changeToString(table: string, column: string, options?: {
|
|
8
|
+
nullable?: boolean;
|
|
9
|
+
default?: any;
|
|
10
|
+
length?: number;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
changeToInteger(table: string, column: string, options?: {
|
|
13
|
+
nullable?: boolean;
|
|
14
|
+
default?: any;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SchemaHelperCockroachDb = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
class SchemaHelperCockroachDb extends types_1.SchemaHelper {
|
|
6
|
+
async changeToText(table, column, options = {}) {
|
|
7
|
+
await this.changeToTypeByCopy(table, column, options, (builder, column) => builder.text(column));
|
|
8
|
+
}
|
|
9
|
+
async changeToString(table, column, options = {}) {
|
|
10
|
+
await this.changeToTypeByCopy(table, column, options, (builder, column, options) => builder.string(column, options.length));
|
|
11
|
+
}
|
|
12
|
+
async changeToInteger(table, column, options = {}) {
|
|
13
|
+
await this.changeToTypeByCopy(table, column, options, (builder, column) => builder.integer(column));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.SchemaHelperCockroachDb = SchemaHelperCockroachDb;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SchemaHelperDefault = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
class SchemaHelperDefault extends types_1.SchemaHelper {
|
|
6
|
+
}
|
|
7
|
+
exports.SchemaHelperDefault = SchemaHelperDefault;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { SchemaHelper } from '../types';
|
|
2
|
+
export declare class SchemaHelperOracle extends SchemaHelper {
|
|
3
|
+
changeToText(table: string, column: string, options?: {
|
|
4
|
+
nullable?: boolean;
|
|
5
|
+
default?: any;
|
|
6
|
+
}): Promise<void>;
|
|
7
|
+
changeToString(table: string, column: string, options?: {
|
|
8
|
+
nullable?: boolean;
|
|
9
|
+
default?: any;
|
|
10
|
+
length?: number;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
}
|