kuzzle 2.19.2 → 2.19.5
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/lib/api/controllers/adminController.js +94 -80
- package/lib/api/controllers/authController.js +239 -212
- package/lib/api/controllers/baseController.js +89 -51
- package/lib/api/controllers/bulkController.js +62 -49
- package/lib/api/controllers/clusterController.js +6 -8
- package/lib/api/controllers/collectionController.js +140 -129
- package/lib/api/controllers/debugController.d.ts +2 -2
- package/lib/api/controllers/debugController.js +33 -31
- package/lib/api/controllers/documentController.js +365 -274
- package/lib/api/controllers/index.js +13 -13
- package/lib/api/controllers/indexController.js +46 -50
- package/lib/api/controllers/memoryStorageController.js +410 -360
- package/lib/api/controllers/realtimeController.js +37 -36
- package/lib/api/controllers/securityController.js +553 -412
- package/lib/api/controllers/serverController.js +111 -104
- package/lib/api/documentExtractor.js +75 -68
- package/lib/api/funnel.js +411 -312
- package/lib/api/httpRoutes.js +1493 -324
- package/lib/api/openapi/OpenApiManager.d.ts +1 -1
- package/lib/api/openapi/OpenApiManager.js +22 -22
- package/lib/api/openapi/components/document/count.yaml +1 -1
- package/lib/api/openapi/components/document/create.yaml +2 -2
- package/lib/api/openapi/components/document/delete.yaml +1 -1
- package/lib/api/openapi/components/document/deleteByQuery.yaml +1 -1
- package/lib/api/openapi/components/document/exists.yaml +1 -1
- package/lib/api/openapi/components/document/get.yaml +2 -2
- package/lib/api/openapi/components/document/index.js +12 -12
- package/lib/api/openapi/components/document/replace.yaml +1 -1
- package/lib/api/openapi/components/document/scroll.yaml +1 -1
- package/lib/api/openapi/components/document/validate.yaml +1 -1
- package/lib/api/openapi/components/index.d.ts +2 -2
- package/lib/api/openapi/components/index.js +1 -1
- package/lib/api/openapi/components/security/index.js +1 -1
- package/lib/api/openapi/components/security/upsertUser.yaml +2 -3
- package/lib/api/openapi/index.d.ts +1 -1
- package/lib/api/openapi/openApiGenerator.d.ts +1 -1
- package/lib/api/openapi/openApiGenerator.js +7 -7
- package/lib/api/rateLimiter.js +12 -13
- package/lib/api/request/index.d.ts +4 -4
- package/lib/api/request/kuzzleRequest.d.ts +9 -9
- package/lib/api/request/kuzzleRequest.js +91 -90
- package/lib/api/request/requestContext.d.ts +2 -2
- package/lib/api/request/requestContext.js +17 -17
- package/lib/api/request/requestInput.d.ts +1 -1
- package/lib/api/request/requestInput.js +19 -19
- package/lib/api/request/requestResponse.d.ts +4 -4
- package/lib/api/request/requestResponse.js +31 -33
- package/lib/cluster/command.js +48 -44
- package/lib/cluster/idCardHandler.d.ts +1 -1
- package/lib/cluster/idCardHandler.js +15 -15
- package/lib/cluster/index.js +2 -2
- package/lib/cluster/node.js +301 -269
- package/lib/cluster/publisher.js +45 -46
- package/lib/cluster/state.d.ts +5 -5
- package/lib/cluster/state.js +8 -8
- package/lib/cluster/subscriber.js +163 -113
- package/lib/cluster/workers/IDCardRenewer.js +33 -32
- package/lib/config/default.config.d.ts +1 -1
- package/lib/config/default.config.js +212 -171
- package/lib/config/documentEventAliases.js +6 -6
- package/lib/config/index.js +161 -98
- package/lib/config/sdkCompatibility.json +8 -8
- package/lib/core/auth/formatProcessing.js +7 -7
- package/lib/core/auth/passportResponse.js +7 -7
- package/lib/core/auth/passportWrapper.js +34 -30
- package/lib/core/auth/tokenManager.d.ts +2 -2
- package/lib/core/auth/tokenManager.js +11 -10
- package/lib/core/backend/applicationManager.d.ts +1 -1
- package/lib/core/backend/applicationManager.js +2 -2
- package/lib/core/backend/backend.d.ts +4 -4
- package/lib/core/backend/backend.js +34 -31
- package/lib/core/backend/backendCluster.d.ts +8 -9
- package/lib/core/backend/backendCluster.js +8 -8
- package/lib/core/backend/backendConfig.d.ts +2 -2
- package/lib/core/backend/backendConfig.js +3 -3
- package/lib/core/backend/backendController.d.ts +2 -2
- package/lib/core/backend/backendController.js +9 -10
- package/lib/core/backend/backendErrors.d.ts +3 -3
- package/lib/core/backend/backendErrors.js +2 -1
- package/lib/core/backend/backendHook.d.ts +3 -3
- package/lib/core/backend/backendHook.js +5 -5
- package/lib/core/backend/backendImport.d.ts +3 -3
- package/lib/core/backend/backendImport.js +23 -23
- package/lib/core/backend/backendOpenApi.d.ts +2 -2
- package/lib/core/backend/backendOpenApi.js +16 -16
- package/lib/core/backend/backendPipe.d.ts +3 -3
- package/lib/core/backend/backendPipe.js +6 -6
- package/lib/core/backend/backendPlugin.d.ts +4 -4
- package/lib/core/backend/backendPlugin.js +14 -14
- package/lib/core/backend/backendStorage.d.ts +2 -2
- package/lib/core/backend/backendStorage.js +1 -2
- package/lib/core/backend/backendVault.d.ts +2 -2
- package/lib/core/backend/backendVault.js +3 -3
- package/lib/core/backend/index.d.ts +14 -14
- package/lib/core/backend/internalLogger.d.ts +1 -1
- package/lib/core/backend/internalLogger.js +5 -5
- package/lib/core/cache/cacheDbEnum.js +4 -4
- package/lib/core/cache/cacheEngine.js +79 -85
- package/lib/core/network/accessLogger.js +126 -120
- package/lib/core/network/clientConnection.js +5 -5
- package/lib/core/network/context.js +8 -8
- package/lib/core/network/entryPoint.js +100 -85
- package/lib/core/network/httpRouter/index.js +63 -60
- package/lib/core/network/httpRouter/routeHandler.js +18 -19
- package/lib/core/network/httpRouter/routePart.js +23 -19
- package/lib/core/network/protocolManifest.js +3 -3
- package/lib/core/network/protocols/httpMessage.js +8 -10
- package/lib/core/network/protocols/httpwsProtocol.js +305 -250
- package/lib/core/network/protocols/internalProtocol.js +27 -24
- package/lib/core/network/protocols/mqttProtocol.js +106 -96
- package/lib/core/network/protocols/protocol.js +20 -17
- package/lib/core/network/router.js +56 -46
- package/lib/core/plugin/plugin.js +151 -120
- package/lib/core/plugin/pluginContext.d.ts +7 -7
- package/lib/core/plugin/pluginContext.js +48 -44
- package/lib/core/plugin/pluginManifest.js +13 -12
- package/lib/core/plugin/pluginRepository.js +26 -27
- package/lib/core/plugin/pluginsManager.js +425 -304
- package/lib/core/plugin/privilegedContext.js +3 -3
- package/lib/core/realtime/actionEnum.js +1 -1
- package/lib/core/realtime/channel.d.ts +1 -1
- package/lib/core/realtime/channel.js +22 -22
- package/lib/core/realtime/connectionRooms.d.ts +1 -1
- package/lib/core/realtime/hotelClerk.d.ts +2 -2
- package/lib/core/realtime/hotelClerk.js +53 -50
- package/lib/core/realtime/index.js +5 -5
- package/lib/core/realtime/notification/document.js +25 -25
- package/lib/core/realtime/notification/index.js +4 -4
- package/lib/core/realtime/notification/server.js +3 -3
- package/lib/core/realtime/notification/user.js +4 -4
- package/lib/core/realtime/notifier.js +113 -75
- package/lib/core/realtime/room.d.ts +1 -1
- package/lib/core/realtime/subscription.d.ts +1 -1
- package/lib/core/realtime/subscription.js +1 -1
- package/lib/core/security/index.js +8 -8
- package/lib/core/security/profileRepository.d.ts +6 -6
- package/lib/core/security/profileRepository.js +48 -45
- package/lib/core/security/roleRepository.js +127 -115
- package/lib/core/security/securityLoader.js +70 -63
- package/lib/core/security/tokenRepository.js +132 -118
- package/lib/core/security/userRepository.js +104 -88
- package/lib/core/shared/KoncordeWrapper.d.ts +1 -1
- package/lib/core/shared/KoncordeWrapper.js +3 -1
- package/lib/core/shared/abstractManifest.js +22 -23
- package/lib/core/shared/repository.js +69 -67
- package/lib/core/shared/sdk/embeddedSdk.d.ts +2 -2
- package/lib/core/shared/sdk/embeddedSdk.js +36 -32
- package/lib/core/shared/sdk/funnelProtocol.d.ts +1 -1
- package/lib/core/shared/sdk/funnelProtocol.js +11 -11
- package/lib/core/shared/sdk/impersonatedSdk.js +19 -18
- package/lib/core/shared/store.js +127 -32
- package/lib/core/statistics/index.js +2 -2
- package/lib/core/statistics/statistics.js +99 -85
- package/lib/core/storage/clientAdapter.js +219 -136
- package/lib/core/storage/indexCache.js +3 -3
- package/lib/core/storage/storageEngine.js +10 -13
- package/lib/core/storage/storeScopeEnum.js +3 -3
- package/lib/core/validation/baseType.js +12 -10
- package/lib/core/validation/index.js +2 -2
- package/lib/core/validation/types/anything.js +4 -4
- package/lib/core/validation/types/boolean.js +7 -7
- package/lib/core/validation/types/date.js +165 -131
- package/lib/core/validation/types/email.js +18 -21
- package/lib/core/validation/types/enum.js +34 -21
- package/lib/core/validation/types/geoPoint.js +7 -7
- package/lib/core/validation/types/geoShape.js +148 -125
- package/lib/core/validation/types/integer.js +9 -9
- package/lib/core/validation/types/ipAddress.js +17 -19
- package/lib/core/validation/types/numeric.js +36 -29
- package/lib/core/validation/types/object.js +19 -19
- package/lib/core/validation/types/string.js +36 -29
- package/lib/core/validation/types/url.js +17 -19
- package/lib/core/validation/validation.js +422 -378
- package/lib/kerror/codes/1-services.json +7 -1
- package/lib/kerror/codes/4-plugin.json +2 -2
- package/lib/kerror/codes/index.js +85 -63
- package/lib/kerror/errors/badRequestError.d.ts +1 -1
- package/lib/kerror/errors/externalServiceError.d.ts +1 -1
- package/lib/kerror/errors/forbiddenError.d.ts +1 -1
- package/lib/kerror/errors/gatewayTimeoutError.d.ts +1 -1
- package/lib/kerror/errors/index.d.ts +15 -15
- package/lib/kerror/errors/internalError.d.ts +1 -1
- package/lib/kerror/errors/kuzzleError.d.ts +1 -1
- package/lib/kerror/errors/multipleErrorsError.d.ts +1 -1
- package/lib/kerror/errors/multipleErrorsError.js +1 -1
- package/lib/kerror/errors/notFoundError.d.ts +1 -1
- package/lib/kerror/errors/partialError.d.ts +1 -1
- package/lib/kerror/errors/partialError.js +1 -1
- package/lib/kerror/errors/pluginImplementationError.d.ts +1 -1
- package/lib/kerror/errors/pluginImplementationError.js +2 -1
- package/lib/kerror/errors/preconditionError.d.ts +1 -1
- package/lib/kerror/errors/serviceUnavailableError.d.ts +1 -1
- package/lib/kerror/errors/sizeLimitError.d.ts +1 -1
- package/lib/kerror/errors/tooManyRequestsError.d.ts +1 -1
- package/lib/kerror/errors/unauthorizedError.d.ts +1 -1
- package/lib/kerror/index.d.ts +3 -3
- package/lib/kerror/index.js +17 -16
- package/lib/kuzzle/dumpGenerator.js +130 -114
- package/lib/kuzzle/event/kuzzleEventEmitter.js +96 -70
- package/lib/kuzzle/event/pipeRunner.js +26 -25
- package/lib/kuzzle/event/waterfall.js +13 -15
- package/lib/kuzzle/index.js +2 -2
- package/lib/kuzzle/internalIndexHandler.js +80 -59
- package/lib/kuzzle/kuzzle.js +99 -99
- package/lib/kuzzle/kuzzleStateEnum.js +1 -1
- package/lib/kuzzle/log.js +23 -18
- package/lib/kuzzle/vault.js +34 -19
- package/lib/model/security/profile.d.ts +3 -3
- package/lib/model/security/profile.js +38 -37
- package/lib/model/security/rights.js +5 -5
- package/lib/model/security/role.d.ts +3 -3
- package/lib/model/security/role.js +25 -26
- package/lib/model/security/token.d.ts +1 -1
- package/lib/model/security/token.js +4 -4
- package/lib/model/security/user.d.ts +2 -2
- package/lib/model/security/user.js +9 -9
- package/lib/model/storage/apiKey.js +43 -33
- package/lib/model/storage/baseModel.js +49 -45
- package/lib/service/cache/redis.js +60 -55
- package/lib/service/service.js +17 -17
- package/lib/service/storage/elasticsearch.js +839 -755
- package/lib/service/storage/esWrapper.js +103 -86
- package/lib/service/storage/queryTranslator.js +52 -59
- package/lib/types/Controller.d.ts +3 -3
- package/lib/types/ControllerDefinition.d.ts +3 -3
- package/lib/types/DebugModule.d.ts +3 -2
- package/lib/types/DebugModule.js +1 -1
- package/lib/types/EventHandler.d.ts +31 -1
- package/lib/types/Global.d.ts +1 -1
- package/lib/types/HttpStream.d.ts +2 -1
- package/lib/types/HttpStream.js +7 -5
- package/lib/types/Kuzzle.d.ts +1 -1
- package/lib/types/KuzzleDocument.d.ts +1 -1
- package/lib/types/OpenApiDefinition.d.ts +1 -1
- package/lib/types/PasswordPolicy.d.ts +1 -1
- package/lib/types/Plugin.d.ts +8 -8
- package/lib/types/Plugin.js +2 -2
- package/lib/types/Policy.d.ts +1 -1
- package/lib/types/RequestPayload.d.ts +1 -1
- package/lib/types/ResponsePayload.d.ts +1 -1
- package/lib/types/Token.d.ts +1 -1
- package/lib/types/User.d.ts +1 -1
- package/lib/types/config/DumpConfiguration.d.ts +8 -8
- package/lib/types/config/HttpConfiguration.d.ts +1 -1
- package/lib/types/config/KuzzleConfiguration.d.ts +1 -1
- package/lib/types/config/LimitsConfiguration.d.ts +8 -8
- package/lib/types/config/PluginsConfiguration.d.ts +4 -4
- package/lib/types/config/SecurityConfiguration.d.ts +62 -62
- package/lib/types/config/ServerConfiguration.d.ts +55 -55
- package/lib/types/config/ServicesConfiguration.d.ts +2 -2
- package/lib/types/config/internalCache/InternalCacheRedisConfiguration.d.ts +10 -10
- package/lib/types/config/publicCache/PublicCacheRedisConfiguration.d.ts +3 -3
- package/lib/types/config/storageEngine/StorageEngineElasticsearchConfiguration.d.ts +194 -110
- package/lib/types/errors/ErrorDefinition.d.ts +1 -1
- package/lib/types/errors/ErrorDomains.d.ts +1 -1
- package/lib/types/events/EventGenericDocument.d.ts +26 -0
- package/lib/types/events/EventGenericDocument.js +3 -0
- package/lib/types/index.d.ts +39 -38
- package/lib/types/index.js +1 -0
- package/lib/types/realtime/RealtimeScope.d.ts +1 -1
- package/lib/types/realtime/RealtimeUsers.d.ts +1 -1
- package/lib/util/assertType.js +13 -11
- package/lib/util/async.d.ts +1 -0
- package/lib/util/async.js +61 -0
- package/lib/util/asyncStore.js +19 -21
- package/lib/util/bufferedPassThrough.d.ts +3 -2
- package/lib/util/bufferedPassThrough.js +4 -4
- package/lib/util/bytes.js +9 -13
- package/lib/util/crypto.js +1 -1
- package/lib/util/debug.js +5 -5
- package/lib/util/deprecate.js +24 -21
- package/lib/util/didYouMean.js +7 -7
- package/lib/util/dump-collection.d.ts +2 -2
- package/lib/util/dump-collection.js +26 -26
- package/lib/util/esRequest.d.ts +1 -0
- package/lib/util/esRequest.js +62 -0
- package/lib/util/extractFields.js +24 -25
- package/lib/util/inflector.js +5 -5
- package/lib/util/koncordeCompat.d.ts +2 -2
- package/lib/util/koncordeCompat.js +5 -5
- package/lib/util/memoize.js +3 -5
- package/lib/util/mutex.d.ts +19 -1
- package/lib/util/mutex.js +39 -12
- package/lib/util/name-generator.js +1331 -1331
- package/lib/util/promback.js +8 -10
- package/lib/util/readYamlFile.d.ts +1 -1
- package/lib/util/readYamlFile.js +1 -1
- package/lib/util/requestAssertions.js +34 -34
- package/lib/util/safeObject.js +5 -5
- package/lib/util/stackTrace.js +20 -22
- package/lib/util/wildcard.js +15 -15
- package/package.json +28 -29
- package/npm-shrinkwrap.json +0 -19422
package/lib/api/funnel.js
CHANGED
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
* limitations under the License.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
"use strict";
|
|
23
23
|
|
|
24
|
-
const Bluebird = require(
|
|
25
|
-
const Deque = require(
|
|
26
|
-
const Cookie = require(
|
|
24
|
+
const Bluebird = require("bluebird");
|
|
25
|
+
const Deque = require("denque");
|
|
26
|
+
const Cookie = require("cookie");
|
|
27
27
|
|
|
28
|
-
const kuzzleStateEnum = require(
|
|
29
|
-
const { KuzzleError } = require(
|
|
28
|
+
const kuzzleStateEnum = require("../kuzzle/kuzzleStateEnum");
|
|
29
|
+
const { KuzzleError } = require("../kerror/errors");
|
|
30
30
|
const {
|
|
31
31
|
AdminController,
|
|
32
32
|
AuthController,
|
|
@@ -40,20 +40,20 @@ const {
|
|
|
40
40
|
RealtimeController,
|
|
41
41
|
SecurityController,
|
|
42
42
|
ServerController,
|
|
43
|
-
} = require(
|
|
44
|
-
const { documentEventAliases } = require(
|
|
45
|
-
const DocumentExtractor = require(
|
|
46
|
-
const sdkCompatibility = require(
|
|
47
|
-
const RateLimiter = require(
|
|
48
|
-
const kerror = require(
|
|
43
|
+
} = require("./controllers");
|
|
44
|
+
const { documentEventAliases } = require("../config/documentEventAliases");
|
|
45
|
+
const DocumentExtractor = require("./documentExtractor");
|
|
46
|
+
const sdkCompatibility = require("../config/sdkCompatibility");
|
|
47
|
+
const RateLimiter = require("./rateLimiter");
|
|
48
|
+
const kerror = require("../kerror");
|
|
49
49
|
|
|
50
|
-
const debug = require(
|
|
51
|
-
const processError = kerror.wrap(
|
|
52
|
-
const { has } = require(
|
|
50
|
+
const debug = require("../util/debug")("kuzzle:funnel");
|
|
51
|
+
const processError = kerror.wrap("api", "process");
|
|
52
|
+
const { has } = require("../util/safeObject");
|
|
53
53
|
|
|
54
54
|
// Actions of the auth controller that does not necessite to verify the token
|
|
55
55
|
// when cookie auth is active
|
|
56
|
-
const SKIP_TOKEN_VERIF_ACTIONS = [
|
|
56
|
+
const SKIP_TOKEN_VERIF_ACTIONS = ["login", "checkToken", "logout"];
|
|
57
57
|
|
|
58
58
|
/**
|
|
59
59
|
* @class PendingRequest
|
|
@@ -62,7 +62,7 @@ const SKIP_TOKEN_VERIF_ACTIONS = ['login', 'checkToken', 'logout'];
|
|
|
62
62
|
* @param {Object} context
|
|
63
63
|
*/
|
|
64
64
|
class PendingRequest {
|
|
65
|
-
constructor
|
|
65
|
+
constructor(request, fn, context) {
|
|
66
66
|
this.request = request;
|
|
67
67
|
this.fn = fn;
|
|
68
68
|
this.context = context;
|
|
@@ -73,7 +73,7 @@ class PendingRequest {
|
|
|
73
73
|
* @class Funnel
|
|
74
74
|
*/
|
|
75
75
|
class Funnel {
|
|
76
|
-
constructor
|
|
76
|
+
constructor() {
|
|
77
77
|
this.overloaded = false;
|
|
78
78
|
this.concurrentRequests = 0;
|
|
79
79
|
this.controllers = new Map();
|
|
@@ -90,7 +90,7 @@ class Funnel {
|
|
|
90
90
|
this.sdkCompatibility = sdkCompatibility;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
init
|
|
93
|
+
init() {
|
|
94
94
|
/**
|
|
95
95
|
* Returns true if the controller is one of Kuzzle native's one
|
|
96
96
|
*
|
|
@@ -98,48 +98,47 @@ class Funnel {
|
|
|
98
98
|
*
|
|
99
99
|
* @returns {Boolean}
|
|
100
100
|
*/
|
|
101
|
-
global.kuzzle.onAsk(
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
global.kuzzle.onAsk("kuzzle:api:funnel:controller:isNative", (name) =>
|
|
102
|
+
this.isNativeController(name)
|
|
103
|
+
);
|
|
104
104
|
|
|
105
105
|
/**
|
|
106
106
|
* Returns inner metrics from the Funnel
|
|
107
|
-
* @returns {Object}
|
|
107
|
+
* @returns {Object}
|
|
108
108
|
*/
|
|
109
|
-
global.kuzzle.onAsk(
|
|
110
|
-
'kuzzle:api:funnel:metrics',
|
|
111
|
-
() => this.metrics());
|
|
109
|
+
global.kuzzle.onAsk("kuzzle:api:funnel:metrics", () => this.metrics());
|
|
112
110
|
|
|
113
111
|
this.rateLimiter.init();
|
|
114
112
|
|
|
115
|
-
this.controllers.set(
|
|
116
|
-
this.controllers.set(
|
|
117
|
-
this.controllers.set(
|
|
118
|
-
this.controllers.set(
|
|
119
|
-
this.controllers.set(
|
|
120
|
-
this.controllers.set(
|
|
121
|
-
this.controllers.set(
|
|
122
|
-
this.controllers.set(
|
|
123
|
-
this.controllers.set(
|
|
124
|
-
this.controllers.set(
|
|
125
|
-
this.controllers.set(
|
|
113
|
+
this.controllers.set("auth", new AuthController());
|
|
114
|
+
this.controllers.set("bulk", new BulkController());
|
|
115
|
+
this.controllers.set("cluster", new ClusterController());
|
|
116
|
+
this.controllers.set("collection", new CollectionController());
|
|
117
|
+
this.controllers.set("debug", new DebugController());
|
|
118
|
+
this.controllers.set("document", new DocumentController());
|
|
119
|
+
this.controllers.set("index", new IndexController());
|
|
120
|
+
this.controllers.set("realtime", new RealtimeController());
|
|
121
|
+
this.controllers.set("security", new SecurityController());
|
|
122
|
+
this.controllers.set("server", new ServerController());
|
|
123
|
+
this.controllers.set("admin", new AdminController());
|
|
126
124
|
|
|
127
125
|
const msController = new MemoryStorageController();
|
|
128
|
-
this.controllers.set(
|
|
129
|
-
this.controllers.set(
|
|
126
|
+
this.controllers.set("memoryStorage", msController);
|
|
127
|
+
this.controllers.set("ms", msController);
|
|
130
128
|
|
|
131
|
-
const initPromises = Array.from(this.controllers.keys())
|
|
132
|
-
|
|
129
|
+
const initPromises = Array.from(this.controllers.keys()).map((ctrl) =>
|
|
130
|
+
this.controllers.get(ctrl).init()
|
|
131
|
+
);
|
|
133
132
|
|
|
134
133
|
return Bluebird.all(initPromises);
|
|
135
134
|
}
|
|
136
135
|
|
|
137
|
-
loadDocumentEventAliases
|
|
136
|
+
loadDocumentEventAliases() {
|
|
138
137
|
this.documentEventAliases = documentEventAliases;
|
|
139
138
|
this.documentEventAliases.mirrorList = {};
|
|
140
139
|
|
|
141
|
-
Object.keys(documentEventAliases.list).forEach(alias => {
|
|
142
|
-
documentEventAliases.list[alias].forEach(aliasOf => {
|
|
140
|
+
Object.keys(documentEventAliases.list).forEach((alias) => {
|
|
141
|
+
documentEventAliases.list[alias].forEach((aliasOf) => {
|
|
143
142
|
this.documentEventAliases.mirrorList[aliasOf] = alias;
|
|
144
143
|
});
|
|
145
144
|
});
|
|
@@ -170,35 +169,41 @@ class Funnel {
|
|
|
170
169
|
* @returns {Boolean} - A boolean telling whether the request has been
|
|
171
170
|
* immediately executed or not.
|
|
172
171
|
*/
|
|
173
|
-
throttle
|
|
172
|
+
throttle(fn, context, request) {
|
|
174
173
|
if (global.kuzzle.state === kuzzleStateEnum.SHUTTING_DOWN) {
|
|
175
|
-
throw processError.get(
|
|
174
|
+
throw processError.get("shutting_down");
|
|
176
175
|
}
|
|
177
176
|
|
|
178
177
|
if (global.kuzzle.state === kuzzleStateEnum.NOT_ENOUGH_NODES) {
|
|
179
|
-
throw processError.get(
|
|
178
|
+
throw processError.get("not_enough_nodes");
|
|
180
179
|
}
|
|
181
180
|
|
|
182
181
|
if (this.overloaded) {
|
|
183
182
|
const now = Date.now();
|
|
184
183
|
|
|
185
|
-
if (
|
|
186
|
-
|
|
184
|
+
if (
|
|
185
|
+
this.pendingRequestsQueue.length >
|
|
186
|
+
global.kuzzle.config.limits.requestsBufferWarningThreshold &&
|
|
187
|
+
(this.lastWarningTime === 0 || this.lastWarningTime < now - 500)
|
|
187
188
|
) {
|
|
188
|
-
const overloadPercentage =
|
|
189
|
-
|
|
190
|
-
this.pendingRequestsQueue.length /
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
global.kuzzle.emit(
|
|
194
|
-
global.kuzzle.log.warn(
|
|
189
|
+
const overloadPercentage =
|
|
190
|
+
Math.round(
|
|
191
|
+
(10000 * this.pendingRequestsQueue.length) /
|
|
192
|
+
global.kuzzle.config.limits.requestsBufferSize
|
|
193
|
+
) / 100;
|
|
194
|
+
global.kuzzle.emit("core:overload", overloadPercentage);
|
|
195
|
+
global.kuzzle.log.warn(
|
|
196
|
+
`[!WARNING!] Kuzzle overloaded: ${overloadPercentage}%. Delaying requests...`
|
|
197
|
+
);
|
|
195
198
|
|
|
196
199
|
this.overloadWarned = true;
|
|
197
200
|
this.lastWarningTime = now;
|
|
198
201
|
}
|
|
199
202
|
}
|
|
200
203
|
|
|
201
|
-
if (
|
|
204
|
+
if (
|
|
205
|
+
this.concurrentRequests < global.kuzzle.config.limits.concurrentRequests
|
|
206
|
+
) {
|
|
202
207
|
if (this.pendingRequestsById.has(request.internalId)) {
|
|
203
208
|
this.pendingRequestsById.delete(request.internalId);
|
|
204
209
|
}
|
|
@@ -218,20 +223,24 @@ class Funnel {
|
|
|
218
223
|
2- the number of cached requests is equal to the requestsBufferSize property.
|
|
219
224
|
The request is then discarded and an error is returned to the sender
|
|
220
225
|
*/
|
|
221
|
-
if (
|
|
222
|
-
|
|
223
|
-
global.kuzzle.
|
|
226
|
+
if (
|
|
227
|
+
this.pendingRequestsQueue.length >=
|
|
228
|
+
global.kuzzle.config.limits.requestsBufferSize
|
|
229
|
+
) {
|
|
230
|
+
const error = processError.get("overloaded");
|
|
231
|
+
global.kuzzle.emit("log:error", error);
|
|
224
232
|
global.kuzzle.log.error(error);
|
|
225
233
|
throw error;
|
|
226
234
|
}
|
|
227
235
|
|
|
228
|
-
if (!
|
|
236
|
+
if (!this.pendingRequestsById.has(request.internalId)) {
|
|
229
237
|
this.pendingRequestsById.set(
|
|
230
238
|
request.internalId,
|
|
231
|
-
new PendingRequest(request, fn, context)
|
|
239
|
+
new PendingRequest(request, fn, context)
|
|
240
|
+
);
|
|
232
241
|
this.pendingRequestsQueue.push(request.internalId);
|
|
233
242
|
|
|
234
|
-
if (!
|
|
243
|
+
if (!this.overloaded) {
|
|
235
244
|
this.overloaded = true;
|
|
236
245
|
|
|
237
246
|
/*
|
|
@@ -263,129 +272,180 @@ class Funnel {
|
|
|
263
272
|
* @param {Function} callback
|
|
264
273
|
* @returns {Number} -1: request delayed, 0: request processing, 1: error
|
|
265
274
|
*/
|
|
266
|
-
execute
|
|
267
|
-
if (!
|
|
275
|
+
execute(request, callback) {
|
|
276
|
+
if (!request.input.controller || !request.input.controller.length) {
|
|
268
277
|
callback(
|
|
269
|
-
kerror.get(
|
|
270
|
-
request
|
|
278
|
+
kerror.get("api", "assert", "missing_argument", "controller"),
|
|
279
|
+
request
|
|
280
|
+
);
|
|
271
281
|
return 1;
|
|
272
282
|
}
|
|
273
283
|
|
|
274
|
-
if (!
|
|
284
|
+
if (!request.input.action || !request.input.action.length) {
|
|
275
285
|
callback(
|
|
276
|
-
kerror.get(
|
|
277
|
-
request
|
|
286
|
+
kerror.get("api", "assert", "missing_argument", "action"),
|
|
287
|
+
request
|
|
288
|
+
);
|
|
278
289
|
return 1;
|
|
279
290
|
}
|
|
280
291
|
|
|
281
292
|
// If there is a body, retrieve the targets if any
|
|
282
|
-
const targets = request.getArray(
|
|
293
|
+
const targets = request.getArray("targets", []);
|
|
283
294
|
/**
|
|
284
295
|
* Only index and collection as a pair or the targets parameter is allowed at the same time
|
|
285
296
|
* otherwise we throw an error because we don't know which one to use to verify the rights
|
|
286
297
|
*/
|
|
287
|
-
if (
|
|
288
|
-
&&
|
|
289
|
-
|
|
298
|
+
if (
|
|
299
|
+
targets.length > 0 &&
|
|
300
|
+
(request.input.args.index || request.input.args.collection)
|
|
290
301
|
) {
|
|
291
302
|
callback(
|
|
292
|
-
kerror.get(
|
|
293
|
-
|
|
303
|
+
kerror.get(
|
|
304
|
+
"api",
|
|
305
|
+
"assert",
|
|
306
|
+
"mutually_exclusive",
|
|
307
|
+
"index, collection",
|
|
308
|
+
"targets"
|
|
309
|
+
),
|
|
310
|
+
request
|
|
311
|
+
);
|
|
294
312
|
return 1;
|
|
295
313
|
}
|
|
296
314
|
|
|
297
|
-
if (
|
|
298
|
-
|
|
299
|
-
|
|
315
|
+
if (
|
|
316
|
+
request.input.headers &&
|
|
317
|
+
has(request.input.headers, "origin") &&
|
|
318
|
+
!this._isOriginAuthorized(request.input.headers.origin)
|
|
300
319
|
) {
|
|
301
|
-
debug(
|
|
320
|
+
debug(
|
|
321
|
+
"Reject request, unauthorized origin %s",
|
|
322
|
+
request.input.headers.origin
|
|
323
|
+
);
|
|
302
324
|
return this._executeError(
|
|
303
|
-
kerror.get(
|
|
325
|
+
kerror.get(
|
|
326
|
+
"api",
|
|
327
|
+
"process",
|
|
328
|
+
"unauthorized_origin",
|
|
329
|
+
request.input.headers.origin
|
|
330
|
+
),
|
|
304
331
|
request,
|
|
305
332
|
true,
|
|
306
|
-
callback
|
|
333
|
+
callback
|
|
334
|
+
);
|
|
307
335
|
}
|
|
308
336
|
|
|
309
337
|
try {
|
|
310
|
-
const executing = this.throttle(
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
debug('Starting request %s:%s [%s]: %j', req.input.controller, req.input.action, req.id, req.input);
|
|
320
|
-
|
|
321
|
-
global.kuzzle.asyncStore.run(() => {
|
|
322
|
-
|
|
323
|
-
global.kuzzle.asyncStore.set('REQUEST', req);
|
|
324
|
-
global.kuzzle.pipe('request:beforeExecution', req)
|
|
325
|
-
.then(modifiedRequest => {
|
|
338
|
+
const executing = this.throttle(
|
|
339
|
+
(req) => {
|
|
340
|
+
// if the connection is closed there is no need to execute the request
|
|
341
|
+
// => discarding it
|
|
342
|
+
if (!global.kuzzle.router.isConnectionAlive(req.context)) {
|
|
343
|
+
debug("Client connection dead: dropping request: %a", req.input);
|
|
344
|
+
callback(processError.get("connection_dropped"), req);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
326
347
|
|
|
327
|
-
|
|
348
|
+
debug(
|
|
349
|
+
"Starting request %s:%s [%s]: %j",
|
|
350
|
+
req.input.controller,
|
|
351
|
+
req.input.action,
|
|
352
|
+
req.id,
|
|
353
|
+
req.input
|
|
354
|
+
);
|
|
328
355
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
356
|
+
global.kuzzle.asyncStore.run(() => {
|
|
357
|
+
global.kuzzle.asyncStore.set("REQUEST", req);
|
|
358
|
+
global.kuzzle
|
|
359
|
+
.pipe("request:beforeExecution", req)
|
|
360
|
+
.then((modifiedRequest) => {
|
|
361
|
+
let _request;
|
|
362
|
+
|
|
363
|
+
return this.checkRights(modifiedRequest)
|
|
364
|
+
.then((newModifiedRequest) => {
|
|
365
|
+
_request = newModifiedRequest;
|
|
366
|
+
return this.rateLimiter.isAllowed(_request);
|
|
367
|
+
})
|
|
368
|
+
.then((allowed) => {
|
|
369
|
+
if (!allowed) {
|
|
370
|
+
if (
|
|
371
|
+
request.input.controller === "auth" &&
|
|
372
|
+
request.input.action === "login"
|
|
373
|
+
) {
|
|
374
|
+
throw processError.get("too_many_logins_requests");
|
|
375
|
+
}
|
|
376
|
+
throw processError.get("too_many_requests");
|
|
338
377
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
378
|
+
|
|
379
|
+
return this.processRequest(_request);
|
|
380
|
+
})
|
|
381
|
+
.then((processResult) => {
|
|
382
|
+
debug(
|
|
383
|
+
"Request %s successfully executed. Result: %a",
|
|
384
|
+
modifiedRequest.id,
|
|
385
|
+
processResult
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
return global.kuzzle
|
|
389
|
+
.pipe("request:afterExecution", {
|
|
390
|
+
request: _request,
|
|
391
|
+
result: processResult,
|
|
392
|
+
success: true,
|
|
393
|
+
})
|
|
394
|
+
.then((pipeEvent) => {
|
|
395
|
+
callback(null, pipeEvent.result);
|
|
396
|
+
|
|
397
|
+
// disables a bluebird warning in dev. mode triggered when
|
|
398
|
+
// a promise is created and not returned
|
|
399
|
+
return null;
|
|
400
|
+
});
|
|
401
|
+
})
|
|
402
|
+
.catch((err) => {
|
|
403
|
+
debug(
|
|
404
|
+
"Error processing request %s: %a",
|
|
405
|
+
modifiedRequest.id,
|
|
406
|
+
err
|
|
407
|
+
);
|
|
408
|
+
return global.kuzzle
|
|
409
|
+
.pipe("request:afterExecution", {
|
|
410
|
+
error: err,
|
|
411
|
+
request: modifiedRequest,
|
|
412
|
+
success: false,
|
|
413
|
+
})
|
|
414
|
+
.then((pipeEvent) =>
|
|
415
|
+
this._executeError(
|
|
416
|
+
pipeEvent.error,
|
|
417
|
+
pipeEvent.request,
|
|
418
|
+
true,
|
|
419
|
+
callback
|
|
420
|
+
)
|
|
421
|
+
);
|
|
422
|
+
});
|
|
423
|
+
})
|
|
424
|
+
.catch((err) => {
|
|
425
|
+
debug("Error processing request %s: %a", req.id, err);
|
|
426
|
+
return global.kuzzle
|
|
427
|
+
.pipe("request:afterExecution", {
|
|
428
|
+
error: err,
|
|
429
|
+
request: req,
|
|
430
|
+
success: false,
|
|
431
|
+
})
|
|
432
|
+
.then((pipeEvent) =>
|
|
433
|
+
this._executeError(
|
|
434
|
+
pipeEvent.error,
|
|
435
|
+
pipeEvent.request,
|
|
436
|
+
true,
|
|
437
|
+
callback
|
|
438
|
+
)
|
|
439
|
+
);
|
|
440
|
+
});
|
|
441
|
+
});
|
|
442
|
+
},
|
|
443
|
+
this,
|
|
444
|
+
request
|
|
445
|
+
);
|
|
385
446
|
|
|
386
447
|
return executing ? 0 : -1;
|
|
387
|
-
}
|
|
388
|
-
catch (error) {
|
|
448
|
+
} catch (error) {
|
|
389
449
|
request.setError(error);
|
|
390
450
|
callback(error, request);
|
|
391
451
|
return 1;
|
|
@@ -398,14 +458,13 @@ class Funnel {
|
|
|
398
458
|
*
|
|
399
459
|
* @param {KuzzleError|*} err
|
|
400
460
|
*/
|
|
401
|
-
handleErrorDump
|
|
461
|
+
handleErrorDump(err) {
|
|
402
462
|
const handledErrors = global.kuzzle.config.dump.handledErrors;
|
|
403
463
|
|
|
404
464
|
if (global.kuzzle.config.dump.enabled && handledErrors.enabled) {
|
|
405
465
|
setImmediate(() => {
|
|
406
|
-
const errorType =
|
|
407
|
-
err.name :
|
|
408
|
-
typeof err;
|
|
466
|
+
const errorType =
|
|
467
|
+
typeof err === "object" && err.name ? err.name : typeof err;
|
|
409
468
|
|
|
410
469
|
if (handledErrors.whitelist.indexOf(errorType) > -1) {
|
|
411
470
|
const now = Date.now();
|
|
@@ -413,28 +472,32 @@ class Funnel {
|
|
|
413
472
|
// JSON.stringify(new NativeError()) === '{}'
|
|
414
473
|
// i.e. Error, SyntaxError, TypeError, ReferenceError, etc.
|
|
415
474
|
global.kuzzle.log.error(
|
|
416
|
-
err instanceof Error && !
|
|
475
|
+
err instanceof Error && !(err instanceof KuzzleError)
|
|
417
476
|
? `${err.message}\n${err.stack}`
|
|
418
|
-
: err
|
|
477
|
+
: err
|
|
478
|
+
);
|
|
419
479
|
|
|
420
|
-
if (
|
|
421
|
-
|
|
480
|
+
if (
|
|
481
|
+
!this.lastDumpedErrors[errorType] ||
|
|
482
|
+
this.lastDumpedErrors[errorType] < now - handledErrors.minInterval
|
|
422
483
|
) {
|
|
423
484
|
// simplify error message to use it in folder dump name
|
|
424
485
|
let errorMessage = err.message;
|
|
425
486
|
|
|
426
|
-
if (errorMessage.indexOf(
|
|
427
|
-
errorMessage = errorMessage.split(
|
|
487
|
+
if (errorMessage.indexOf("\n") > -1) {
|
|
488
|
+
errorMessage = errorMessage.split("\n")[0];
|
|
428
489
|
}
|
|
429
490
|
|
|
430
491
|
errorMessage = errorMessage
|
|
431
492
|
.toLowerCase()
|
|
432
|
-
.replace(/[^a-zA-Z0-9-_]/g,
|
|
433
|
-
.split(
|
|
434
|
-
.filter(value => value !==
|
|
435
|
-
.join(
|
|
436
|
-
|
|
437
|
-
global.kuzzle.dump(
|
|
493
|
+
.replace(/[^a-zA-Z0-9-_]/g, "-")
|
|
494
|
+
.split("-")
|
|
495
|
+
.filter((value) => value !== "")
|
|
496
|
+
.join("-");
|
|
497
|
+
|
|
498
|
+
global.kuzzle.dump(
|
|
499
|
+
`handled-${errorType.toLocaleLowerCase()}-${errorMessage}`
|
|
500
|
+
);
|
|
438
501
|
}
|
|
439
502
|
|
|
440
503
|
this.lastDumpedErrors[errorType] = now;
|
|
@@ -449,15 +512,12 @@ class Funnel {
|
|
|
449
512
|
* @param {Request} request
|
|
450
513
|
* @returns {Promise<Request>}
|
|
451
514
|
*/
|
|
452
|
-
async checkRights
|
|
453
|
-
if (
|
|
454
|
-
&&
|
|
515
|
+
async checkRights(request) {
|
|
516
|
+
if (
|
|
517
|
+
!global.kuzzle.config.http.cookieAuthentication &&
|
|
518
|
+
request.getBoolean("cookieAuth")
|
|
455
519
|
) {
|
|
456
|
-
throw kerror.get(
|
|
457
|
-
'security',
|
|
458
|
-
'cookie',
|
|
459
|
-
'unsupported'
|
|
460
|
-
);
|
|
520
|
+
throw kerror.get("security", "cookie", "unsupported");
|
|
461
521
|
}
|
|
462
522
|
|
|
463
523
|
let skipTokenVerification = false;
|
|
@@ -465,35 +525,35 @@ class Funnel {
|
|
|
465
525
|
// When a request is made with cookieAuth set to true
|
|
466
526
|
// We try to use the auth token cookie if present as auth token
|
|
467
527
|
// otherwise check for auth token as input
|
|
468
|
-
if (request.input.headers && has(request.input.headers,
|
|
528
|
+
if (request.input.headers && has(request.input.headers, "cookie")) {
|
|
469
529
|
let cookie;
|
|
470
530
|
try {
|
|
471
531
|
cookie = Cookie.parse(request.input.headers.cookie);
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
throw kerror.get('security', 'cookie', 'invalid');
|
|
532
|
+
} catch (error) {
|
|
533
|
+
throw kerror.get("security", "cookie", "invalid");
|
|
475
534
|
}
|
|
476
535
|
|
|
477
536
|
// if cookie is present and not null, and a token is present we should throw because we don't know which one to use
|
|
478
|
-
if (cookie.authToken && cookie.authToken !==
|
|
479
|
-
if (!
|
|
480
|
-
throw kerror.get(
|
|
537
|
+
if (cookie.authToken && cookie.authToken !== "null") {
|
|
538
|
+
if (!global.kuzzle.config.http.cookieAuthentication) {
|
|
539
|
+
throw kerror.get("security", "cookie", "unsupported");
|
|
481
540
|
}
|
|
482
541
|
|
|
483
542
|
if (request.input.jwt) {
|
|
484
543
|
throw kerror.get(
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
544
|
+
"security",
|
|
545
|
+
"token",
|
|
546
|
+
"verification_error",
|
|
547
|
+
"Both token and cookie are present, could not decide which one to use"
|
|
489
548
|
);
|
|
490
549
|
}
|
|
491
550
|
|
|
492
551
|
request.input.jwt = cookie.authToken;
|
|
493
552
|
|
|
494
|
-
skipTokenVerification =
|
|
495
|
-
|
|
496
|
-
|
|
553
|
+
skipTokenVerification =
|
|
554
|
+
request.getBoolean("cookieAuth") &&
|
|
555
|
+
request.input.controller === "auth" &&
|
|
556
|
+
SKIP_TOKEN_VERIF_ACTIONS.includes(request.input.action);
|
|
497
557
|
}
|
|
498
558
|
}
|
|
499
559
|
|
|
@@ -503,58 +563,68 @@ class Funnel {
|
|
|
503
563
|
const token = skipTokenVerification ? null : request.input.jwt;
|
|
504
564
|
|
|
505
565
|
request.context.token = await global.kuzzle.ask(
|
|
506
|
-
|
|
507
|
-
token
|
|
508
|
-
|
|
509
|
-
catch (error) {
|
|
510
|
-
await global.kuzzle.pipe(
|
|
566
|
+
"core:security:token:verify",
|
|
567
|
+
token
|
|
568
|
+
);
|
|
569
|
+
} catch (error) {
|
|
570
|
+
await global.kuzzle.pipe("request:onUnauthorized", request);
|
|
511
571
|
throw error;
|
|
512
572
|
}
|
|
513
573
|
|
|
514
574
|
const userId = request.context.token.userId;
|
|
515
575
|
|
|
516
576
|
request.context.user = await global.kuzzle.ask(
|
|
517
|
-
|
|
518
|
-
userId
|
|
577
|
+
"core:security:user:get",
|
|
578
|
+
userId
|
|
579
|
+
);
|
|
519
580
|
|
|
520
581
|
// If we have a token, link the connection with the token,
|
|
521
582
|
// this way the connection can be notified when the token has expired.
|
|
522
|
-
if (
|
|
583
|
+
if (
|
|
584
|
+
global.kuzzle.config.internal.notifiableProtocols.includes(
|
|
585
|
+
request.context.connection.protocol
|
|
586
|
+
)
|
|
587
|
+
) {
|
|
523
588
|
global.kuzzle.tokenManager.link(
|
|
524
589
|
request.context.token,
|
|
525
|
-
request.context.connection.id
|
|
590
|
+
request.context.connection.id
|
|
591
|
+
);
|
|
526
592
|
}
|
|
527
593
|
|
|
528
|
-
if (!
|
|
594
|
+
if (!(await request.context.user.isActionAllowed(request))) {
|
|
529
595
|
// anonymous user => 401 (Unauthorized) error
|
|
530
596
|
// logged-in user with insufficient permissions => 403 (Forbidden) error
|
|
531
597
|
const error = kerror.get(
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
userId ===
|
|
598
|
+
"security",
|
|
599
|
+
"rights",
|
|
600
|
+
userId === "-1" ? "unauthorized" : "forbidden",
|
|
535
601
|
request.input.controller,
|
|
536
602
|
request.input.action,
|
|
537
|
-
request.context.user._id
|
|
603
|
+
request.context.user._id
|
|
604
|
+
);
|
|
538
605
|
|
|
539
606
|
request.setError(error);
|
|
540
607
|
|
|
541
|
-
await global.kuzzle.pipe(
|
|
608
|
+
await global.kuzzle.pipe("request:onUnauthorized", request);
|
|
542
609
|
throw error;
|
|
543
610
|
}
|
|
544
611
|
|
|
545
|
-
if (
|
|
546
|
-
&&
|
|
547
|
-
|
|
612
|
+
if (
|
|
613
|
+
global.kuzzle.config.plugins.common.failsafeMode &&
|
|
614
|
+
!this._isLogin(request) &&
|
|
615
|
+
!request.context.user.profileIds.includes("admin")
|
|
548
616
|
) {
|
|
549
|
-
await global.kuzzle.pipe(
|
|
550
|
-
throw kerror.get(
|
|
617
|
+
await global.kuzzle.pipe("request:onUnauthorized", request);
|
|
618
|
+
throw kerror.get("security", "rights", "failsafe_mode_admin_only");
|
|
551
619
|
}
|
|
552
620
|
|
|
553
|
-
return global.kuzzle.pipe(
|
|
621
|
+
return global.kuzzle.pipe("request:onAuthorized", request);
|
|
554
622
|
}
|
|
555
623
|
|
|
556
|
-
_isLogin
|
|
557
|
-
return
|
|
624
|
+
_isLogin(request) {
|
|
625
|
+
return (
|
|
626
|
+
request.input.controller === "auth" && request.input.action === "login"
|
|
627
|
+
);
|
|
558
628
|
}
|
|
559
629
|
|
|
560
630
|
/**
|
|
@@ -564,7 +634,7 @@ class Funnel {
|
|
|
564
634
|
* @param {Request} request
|
|
565
635
|
* @returns {Promise}
|
|
566
636
|
*/
|
|
567
|
-
async processRequest
|
|
637
|
+
async processRequest(request) {
|
|
568
638
|
const controller = this.getController(request);
|
|
569
639
|
|
|
570
640
|
global.kuzzle.statistics.startRequest(request);
|
|
@@ -574,40 +644,42 @@ class Funnel {
|
|
|
574
644
|
|
|
575
645
|
try {
|
|
576
646
|
await this._checkSdkVersion(_request);
|
|
577
|
-
_request = await this.performDocumentAlias(_request,
|
|
647
|
+
_request = await this.performDocumentAlias(_request, "before");
|
|
578
648
|
_request = await global.kuzzle.pipe(
|
|
579
|
-
this.getEventName(_request,
|
|
580
|
-
_request
|
|
649
|
+
this.getEventName(_request, "before"),
|
|
650
|
+
_request
|
|
651
|
+
);
|
|
581
652
|
|
|
582
653
|
const responseData = await doAction(controller, _request);
|
|
583
654
|
|
|
584
|
-
_request.setResult(
|
|
585
|
-
|
|
586
|
-
|
|
655
|
+
_request.setResult(responseData, {
|
|
656
|
+
status: _request.status === 102 ? 200 : _request.status,
|
|
657
|
+
});
|
|
587
658
|
|
|
588
|
-
if (
|
|
659
|
+
if (
|
|
660
|
+
!this.isNativeController(_request.input.controller) &&
|
|
661
|
+
!_request.response.raw
|
|
662
|
+
) {
|
|
589
663
|
// check if the plugin response can be serialized
|
|
590
664
|
try {
|
|
591
665
|
JSON.stringify(responseData);
|
|
592
|
-
}
|
|
593
|
-
catch (e) {
|
|
666
|
+
} catch (e) {
|
|
594
667
|
_request.setResult(null);
|
|
595
|
-
throw kerror.get(
|
|
668
|
+
throw kerror.get("plugin", "controller", "unserializable_response");
|
|
596
669
|
}
|
|
597
670
|
}
|
|
598
671
|
|
|
599
672
|
_request = await global.kuzzle.pipe(
|
|
600
|
-
this.getEventName(_request,
|
|
601
|
-
_request
|
|
673
|
+
this.getEventName(_request, "after"),
|
|
674
|
+
_request
|
|
675
|
+
);
|
|
602
676
|
|
|
603
|
-
_request = await this.performDocumentAlias(_request,
|
|
604
|
-
_request = await global.kuzzle.pipe(
|
|
677
|
+
_request = await this.performDocumentAlias(_request, "after");
|
|
678
|
+
_request = await global.kuzzle.pipe("request:onSuccess", _request);
|
|
605
679
|
global.kuzzle.statistics.completedRequest(_request);
|
|
606
|
-
}
|
|
607
|
-
catch (error) {
|
|
680
|
+
} catch (error) {
|
|
608
681
|
return this.handleProcessRequestError(_request, _request, error);
|
|
609
|
-
}
|
|
610
|
-
finally {
|
|
682
|
+
} finally {
|
|
611
683
|
this.concurrentRequests--;
|
|
612
684
|
}
|
|
613
685
|
|
|
@@ -624,23 +696,29 @@ class Funnel {
|
|
|
624
696
|
*
|
|
625
697
|
* @returns {Promise<KuzzleRequest>}
|
|
626
698
|
*/
|
|
627
|
-
async performDocumentAlias
|
|
699
|
+
async performDocumentAlias(request, prefix) {
|
|
628
700
|
const { controller, action } = request.input;
|
|
629
701
|
const mustTrigger =
|
|
630
|
-
controller ===
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
702
|
+
controller === "document" &&
|
|
703
|
+
this.documentEventAliases.mirrorList[action] &&
|
|
704
|
+
(prefix !== "before" ||
|
|
705
|
+
!this.documentEventAliases.notBefore.includes(action));
|
|
634
706
|
|
|
635
|
-
if (!
|
|
707
|
+
if (!mustTrigger) {
|
|
636
708
|
return request;
|
|
637
709
|
}
|
|
638
710
|
|
|
639
711
|
const alias = this.documentEventAliases.mirrorList[action];
|
|
640
|
-
const event = `${this.documentEventAliases.namespace}:${prefix}${capitalize(
|
|
712
|
+
const event = `${this.documentEventAliases.namespace}:${prefix}${capitalize(
|
|
713
|
+
alias
|
|
714
|
+
)}`;
|
|
641
715
|
const extractor = new DocumentExtractor(request);
|
|
642
716
|
|
|
643
|
-
const documents = await global.kuzzle.pipe(
|
|
717
|
+
const documents = await global.kuzzle.pipe(
|
|
718
|
+
event,
|
|
719
|
+
extractor.extract(),
|
|
720
|
+
request
|
|
721
|
+
);
|
|
644
722
|
|
|
645
723
|
return extractor.insert(documents);
|
|
646
724
|
}
|
|
@@ -656,24 +734,24 @@ class Funnel {
|
|
|
656
734
|
* @param {Request} request
|
|
657
735
|
* @returns {Promise}
|
|
658
736
|
*/
|
|
659
|
-
async executePluginRequest
|
|
737
|
+
async executePluginRequest(request) {
|
|
660
738
|
try {
|
|
661
739
|
return await doAction(this.getController(request), request);
|
|
662
|
-
}
|
|
663
|
-
catch (e) {
|
|
740
|
+
} catch (e) {
|
|
664
741
|
this.handleErrorDump(e);
|
|
665
742
|
throw e;
|
|
666
743
|
}
|
|
667
744
|
}
|
|
668
745
|
|
|
669
|
-
async handleProcessRequestError
|
|
746
|
+
async handleProcessRequestError(modifiedRequest, request, error) {
|
|
670
747
|
let _error = this._wrapError(request, error);
|
|
671
748
|
modifiedRequest.setError(_error);
|
|
672
749
|
|
|
673
750
|
try {
|
|
674
751
|
const updated = await global.kuzzle.pipe(
|
|
675
|
-
this.getEventName(modifiedRequest,
|
|
676
|
-
modifiedRequest
|
|
752
|
+
this.getEventName(modifiedRequest, "error"),
|
|
753
|
+
modifiedRequest
|
|
754
|
+
);
|
|
677
755
|
|
|
678
756
|
// If there is no pipe attached on this event, the same request is
|
|
679
757
|
// passed in resolve and we should reject it
|
|
@@ -682,8 +760,7 @@ class Funnel {
|
|
|
682
760
|
}
|
|
683
761
|
// Pipe recovered from the error: returned the new result
|
|
684
762
|
return updated;
|
|
685
|
-
}
|
|
686
|
-
catch (err) {
|
|
763
|
+
} catch (err) {
|
|
687
764
|
_error = this._wrapError(request, err);
|
|
688
765
|
}
|
|
689
766
|
|
|
@@ -692,15 +769,17 @@ class Funnel {
|
|
|
692
769
|
global.kuzzle.statistics.failedRequest(request);
|
|
693
770
|
|
|
694
771
|
try {
|
|
695
|
-
const updated = await global.kuzzle.pipe(
|
|
772
|
+
const updated = await global.kuzzle.pipe(
|
|
773
|
+
"request:onError",
|
|
774
|
+
modifiedRequest
|
|
775
|
+
);
|
|
696
776
|
|
|
697
777
|
if (updated === modifiedRequest) {
|
|
698
778
|
throw modifiedRequest.error;
|
|
699
779
|
}
|
|
700
780
|
|
|
701
781
|
return updated;
|
|
702
|
-
}
|
|
703
|
-
catch (err) {
|
|
782
|
+
} catch (err) {
|
|
704
783
|
throw this._wrapError(request, err);
|
|
705
784
|
}
|
|
706
785
|
}
|
|
@@ -713,10 +792,10 @@ class Funnel {
|
|
|
713
792
|
* @param {string} prefix - event prefix
|
|
714
793
|
* @returns {string} event name
|
|
715
794
|
*/
|
|
716
|
-
getEventName
|
|
795
|
+
getEventName(request, prefix) {
|
|
717
796
|
const event =
|
|
718
|
-
request.input.controller ===
|
|
719
|
-
?
|
|
797
|
+
request.input.controller === "memoryStorage"
|
|
798
|
+
? "ms"
|
|
720
799
|
: request.input.controller;
|
|
721
800
|
|
|
722
801
|
return `${event}:${prefix}${capitalize(request.input.action)}`;
|
|
@@ -727,7 +806,7 @@ class Funnel {
|
|
|
727
806
|
*
|
|
728
807
|
* @returns {number}
|
|
729
808
|
*/
|
|
730
|
-
get remainingRequests
|
|
809
|
+
get remainingRequests() {
|
|
731
810
|
return this.concurrentRequests + this.pendingRequestsQueue.length;
|
|
732
811
|
}
|
|
733
812
|
|
|
@@ -738,8 +817,11 @@ class Funnel {
|
|
|
738
817
|
* @returns {Object} controller object
|
|
739
818
|
* @throws {BadRequestError} If the asked controller or action is unknown
|
|
740
819
|
*/
|
|
741
|
-
getController
|
|
742
|
-
for (const controllers of [
|
|
820
|
+
getController(request) {
|
|
821
|
+
for (const controllers of [
|
|
822
|
+
this.controllers,
|
|
823
|
+
global.kuzzle.pluginsManager.controllers,
|
|
824
|
+
]) {
|
|
743
825
|
const controller = controllers.get(request.input.controller);
|
|
744
826
|
|
|
745
827
|
if (controller) {
|
|
@@ -747,11 +829,15 @@ class Funnel {
|
|
|
747
829
|
return controller;
|
|
748
830
|
}
|
|
749
831
|
|
|
750
|
-
throw processError.get(
|
|
832
|
+
throw processError.get(
|
|
833
|
+
"action_not_found",
|
|
834
|
+
request.input.controller,
|
|
835
|
+
request.input.action
|
|
836
|
+
);
|
|
751
837
|
}
|
|
752
838
|
}
|
|
753
839
|
|
|
754
|
-
throw processError.get(
|
|
840
|
+
throw processError.get("controller_not_found", request.input.controller);
|
|
755
841
|
}
|
|
756
842
|
|
|
757
843
|
/**
|
|
@@ -759,7 +845,7 @@ class Funnel {
|
|
|
759
845
|
* @param {String} controller
|
|
760
846
|
* @returns {Boolean}
|
|
761
847
|
*/
|
|
762
|
-
isNativeController
|
|
848
|
+
isNativeController(controller) {
|
|
763
849
|
return this.controllers.has(controller);
|
|
764
850
|
}
|
|
765
851
|
|
|
@@ -767,7 +853,7 @@ class Funnel {
|
|
|
767
853
|
* Returns inner metrics from the Funnel
|
|
768
854
|
* @returns {Object}
|
|
769
855
|
*/
|
|
770
|
-
metrics
|
|
856
|
+
metrics() {
|
|
771
857
|
return {
|
|
772
858
|
concurrentRequests: this.concurrentRequests,
|
|
773
859
|
pendingRequests: this.pendingRequestsQueue.length,
|
|
@@ -782,25 +868,29 @@ class Funnel {
|
|
|
782
868
|
*
|
|
783
869
|
* @throws
|
|
784
870
|
*/
|
|
785
|
-
_checkSdkVersion
|
|
786
|
-
if (!
|
|
871
|
+
_checkSdkVersion(request) {
|
|
872
|
+
if (!global.kuzzle.config.server.strictSdkVersion) {
|
|
787
873
|
return;
|
|
788
874
|
}
|
|
789
875
|
|
|
790
|
-
const sdkVersion =
|
|
876
|
+
const sdkVersion =
|
|
877
|
+
request.input.volatile && request.input.volatile.sdkVersion;
|
|
791
878
|
const sdkName = request.input.volatile && request.input.volatile.sdkName;
|
|
792
879
|
|
|
793
880
|
// sdkVersion property is only used by Kuzzle v1 SDKs
|
|
794
881
|
if (sdkVersion) {
|
|
795
|
-
throw processError.get(
|
|
882
|
+
throw processError.get(
|
|
883
|
+
"incompatible_sdk_version",
|
|
884
|
+
sdkVersion,
|
|
885
|
+
"Kuzzle v2"
|
|
886
|
+
);
|
|
796
887
|
}
|
|
797
888
|
|
|
798
|
-
if (!
|
|
889
|
+
if (!sdkName || typeof sdkName !== "string") {
|
|
799
890
|
return;
|
|
800
891
|
}
|
|
801
892
|
|
|
802
|
-
const
|
|
803
|
-
separatorIdx = sdkName.indexOf('@'),
|
|
893
|
+
const separatorIdx = sdkName.indexOf("@"),
|
|
804
894
|
name = sdkName.substr(0, separatorIdx),
|
|
805
895
|
version = sdkName.substr(separatorIdx + 1);
|
|
806
896
|
|
|
@@ -809,14 +899,16 @@ class Funnel {
|
|
|
809
899
|
}
|
|
810
900
|
|
|
811
901
|
const requirements = this.sdkCompatibility[name];
|
|
812
|
-
if (!
|
|
902
|
+
if (!requirements) {
|
|
813
903
|
return;
|
|
814
904
|
}
|
|
815
905
|
|
|
816
|
-
if (!
|
|
817
|
-
const hint = `min: ${requirements.min ||
|
|
906
|
+
if (!satisfiesMajor(version, requirements)) {
|
|
907
|
+
const hint = `min: ${requirements.min || "none"}, max: ${
|
|
908
|
+
requirements.max || "none"
|
|
909
|
+
}`;
|
|
818
910
|
|
|
819
|
-
throw processError.get(
|
|
911
|
+
throw processError.get("incompatible_sdk_version", version, hint);
|
|
820
912
|
}
|
|
821
913
|
}
|
|
822
914
|
|
|
@@ -830,14 +922,13 @@ class Funnel {
|
|
|
830
922
|
* @returns {null}
|
|
831
923
|
* @private
|
|
832
924
|
*/
|
|
833
|
-
_executeError
|
|
925
|
+
_executeError(error, request, asError, callback) {
|
|
834
926
|
request.setError(error);
|
|
835
927
|
|
|
836
928
|
if (asError) {
|
|
837
929
|
callback(error, request);
|
|
838
930
|
this.handleErrorDump(error);
|
|
839
|
-
}
|
|
840
|
-
else {
|
|
931
|
+
} else {
|
|
841
932
|
callback(null, request);
|
|
842
933
|
}
|
|
843
934
|
|
|
@@ -848,26 +939,32 @@ class Funnel {
|
|
|
848
939
|
* Background task. Checks if there are any requests in cache, and replay them
|
|
849
940
|
* if Kuzzle is not overloaded anymore,
|
|
850
941
|
*/
|
|
851
|
-
_playPendingRequests
|
|
942
|
+
_playPendingRequests() {
|
|
852
943
|
// If there is room to play bufferized requests, do it now. If not, retry later
|
|
853
944
|
const quantityToInject = Math.min(
|
|
854
945
|
this.pendingRequestsQueue.length,
|
|
855
|
-
global.kuzzle.config.limits.concurrentRequests - this.concurrentRequests
|
|
946
|
+
global.kuzzle.config.limits.concurrentRequests - this.concurrentRequests
|
|
947
|
+
);
|
|
856
948
|
|
|
857
949
|
if (quantityToInject > 0) {
|
|
858
950
|
for (let i = 0; i < quantityToInject; i++) {
|
|
859
|
-
const pendingItem =
|
|
860
|
-
this.
|
|
951
|
+
const pendingItem = this.pendingRequestsById.get(
|
|
952
|
+
this.pendingRequestsQueue.peekFront()
|
|
953
|
+
);
|
|
861
954
|
|
|
862
955
|
try {
|
|
863
|
-
if (
|
|
956
|
+
if (
|
|
957
|
+
this.throttle(
|
|
958
|
+
pendingItem.fn,
|
|
959
|
+
pendingItem.context,
|
|
960
|
+
pendingItem.request
|
|
961
|
+
)
|
|
962
|
+
) {
|
|
864
963
|
this.pendingRequestsQueue.shift();
|
|
865
|
-
}
|
|
866
|
-
else {
|
|
964
|
+
} else {
|
|
867
965
|
break;
|
|
868
966
|
}
|
|
869
|
-
}
|
|
870
|
-
catch (error) {
|
|
967
|
+
} catch (error) {
|
|
871
968
|
break;
|
|
872
969
|
}
|
|
873
970
|
}
|
|
@@ -875,17 +972,19 @@ class Funnel {
|
|
|
875
972
|
|
|
876
973
|
if (this.pendingRequestsQueue.length > 0) {
|
|
877
974
|
setTimeout(() => this._playPendingRequests(), 0);
|
|
878
|
-
}
|
|
879
|
-
else {
|
|
975
|
+
} else {
|
|
880
976
|
const now = Date.now();
|
|
881
977
|
// No request remaining in cache => stop the background task and return to normal behavior
|
|
882
978
|
this.overloaded = false;
|
|
883
979
|
|
|
884
|
-
if (
|
|
885
|
-
|
|
980
|
+
if (
|
|
981
|
+
this.overloadWarned &&
|
|
982
|
+
(this.lastOverloadTime === 0 || this.lastOverloadTime < now - 500)
|
|
886
983
|
) {
|
|
887
984
|
this.overloadWarned = false;
|
|
888
|
-
global.kuzzle.log.info(
|
|
985
|
+
global.kuzzle.log.info(
|
|
986
|
+
"End of overloaded state. Resuming normal activity."
|
|
987
|
+
);
|
|
889
988
|
this.lastOverloadTime = now;
|
|
890
989
|
}
|
|
891
990
|
}
|
|
@@ -897,14 +996,15 @@ class Funnel {
|
|
|
897
996
|
* @param {Error} error
|
|
898
997
|
* @returns {KuzzleError}
|
|
899
998
|
*/
|
|
900
|
-
_wrapError
|
|
901
|
-
if (!
|
|
999
|
+
_wrapError(request, error) {
|
|
1000
|
+
if (!this.isNativeController(request) && !(error instanceof KuzzleError)) {
|
|
902
1001
|
return kerror.getFrom(
|
|
903
1002
|
error,
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
error.message
|
|
1003
|
+
"plugin",
|
|
1004
|
+
"runtime",
|
|
1005
|
+
"unexpected_error",
|
|
1006
|
+
error.message
|
|
1007
|
+
);
|
|
908
1008
|
}
|
|
909
1009
|
|
|
910
1010
|
return error;
|
|
@@ -915,10 +1015,10 @@ class Funnel {
|
|
|
915
1015
|
* @param {string} origin
|
|
916
1016
|
* @returns
|
|
917
1017
|
*/
|
|
918
|
-
_isOriginAuthorized
|
|
1018
|
+
_isOriginAuthorized(origin) {
|
|
919
1019
|
const httpConfig = global.kuzzle.config.http;
|
|
920
1020
|
|
|
921
|
-
if (!
|
|
1021
|
+
if (!origin) {
|
|
922
1022
|
return true;
|
|
923
1023
|
}
|
|
924
1024
|
|
|
@@ -943,7 +1043,7 @@ class Funnel {
|
|
|
943
1043
|
* @param {string} string
|
|
944
1044
|
* @returns {string}
|
|
945
1045
|
*/
|
|
946
|
-
function capitalize
|
|
1046
|
+
function capitalize(string) {
|
|
947
1047
|
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
948
1048
|
}
|
|
949
1049
|
|
|
@@ -958,16 +1058,17 @@ function capitalize (string) {
|
|
|
958
1058
|
* @param {Request} request
|
|
959
1059
|
* @returns {Promise}
|
|
960
1060
|
*/
|
|
961
|
-
function doAction
|
|
1061
|
+
function doAction(controller, request) {
|
|
962
1062
|
const ret = controller[request.input.action](request);
|
|
963
1063
|
|
|
964
|
-
if (!
|
|
1064
|
+
if (!ret || typeof ret.then !== "function") {
|
|
965
1065
|
return kerror.reject(
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
1066
|
+
"plugin",
|
|
1067
|
+
"controller",
|
|
1068
|
+
"invalid_action_response",
|
|
969
1069
|
request.input.controller,
|
|
970
|
-
request.input.action
|
|
1070
|
+
request.input.action
|
|
1071
|
+
);
|
|
971
1072
|
}
|
|
972
1073
|
|
|
973
1074
|
return ret;
|
|
@@ -982,9 +1083,8 @@ function doAction (controller, request) {
|
|
|
982
1083
|
*
|
|
983
1084
|
* @returns {Boolean}
|
|
984
1085
|
*/
|
|
985
|
-
function satisfiesMajor
|
|
986
|
-
let
|
|
987
|
-
maxRequirement = true,
|
|
1086
|
+
function satisfiesMajor(version, requirements) {
|
|
1087
|
+
let maxRequirement = true,
|
|
988
1088
|
minRequirement = true;
|
|
989
1089
|
|
|
990
1090
|
if (requirements.min) {
|
|
@@ -998,5 +1098,4 @@ function satisfiesMajor (version, requirements) {
|
|
|
998
1098
|
return maxRequirement && minRequirement;
|
|
999
1099
|
}
|
|
1000
1100
|
|
|
1001
|
-
|
|
1002
1101
|
module.exports = Funnel;
|