kuzzle 2.16.11 → 2.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/controllers/adminController.js +3 -3
- package/lib/api/controllers/authController.js +11 -11
- package/lib/api/controllers/baseController.js +60 -3
- package/lib/api/controllers/clusterController.js +1 -1
- package/lib/api/controllers/collectionController.js +7 -5
- package/lib/api/controllers/documentController.js +130 -17
- package/lib/api/controllers/indexController.js +1 -1
- package/lib/api/controllers/memoryStorageController.js +39 -38
- package/lib/api/controllers/realtimeController.js +1 -1
- package/lib/api/controllers/securityController.js +49 -49
- package/lib/api/controllers/serverController.js +73 -27
- package/lib/api/documentExtractor.js +3 -3
- package/lib/api/funnel.js +40 -21
- package/lib/api/httpRoutes.js +9 -4
- package/lib/api/openapi/OpenApiManager.d.ts +11 -0
- package/lib/api/openapi/OpenApiManager.js +96 -0
- package/lib/api/openapi/{document → components/document}/count.yaml +2 -2
- package/lib/api/openapi/{document → components/document}/create.yaml +2 -2
- package/lib/api/openapi/{document → components/document}/createOrReplace.yaml +2 -2
- package/lib/api/openapi/{document → components/document}/delete.yaml +1 -1
- package/lib/api/openapi/{document → components/document}/deleteByQuery.yaml +2 -2
- package/lib/api/openapi/{document → components/document}/exists.yaml +1 -1
- package/lib/api/openapi/{document → components/document}/get.yaml +1 -1
- package/lib/api/openapi/{document → components/document}/index.d.ts +2 -0
- package/lib/api/openapi/{document → components/document}/index.js +7 -2
- package/lib/api/openapi/{document → components/document}/replace.yaml +2 -2
- package/lib/api/openapi/{document → components/document}/scroll.yaml +1 -1
- package/lib/api/openapi/{document → components/document}/update.yaml +2 -2
- package/lib/api/openapi/components/document/validate.yaml +42 -0
- package/lib/api/openapi/components/index.d.ts +2 -0
- package/lib/api/openapi/components/index.js +18 -0
- package/lib/api/openapi/{payloads.yaml → components/payloads.yaml} +0 -0
- package/lib/api/openapi/index.d.ts +1 -2
- package/lib/api/openapi/index.js +1 -5
- package/lib/api/openapi/openApiGenerator.d.ts +7 -0
- package/lib/api/openapi/openApiGenerator.js +133 -0
- package/lib/api/request/kuzzleRequest.js +4 -0
- package/lib/cluster/node.js +9 -9
- package/lib/cluster/publisher.js +1 -1
- package/lib/cluster/subscriber.js +1 -1
- package/lib/cluster/workers/IDCardRenewer.js +2 -2
- package/lib/config/default.config.js +1 -0
- package/lib/config/index.js +6 -6
- package/lib/core/auth/passportResponse.js +6 -6
- package/lib/core/auth/passportWrapper.js +5 -5
- package/lib/core/backend/backend.d.ts +5 -1
- package/lib/core/backend/backend.js +12 -8
- package/lib/core/backend/backendConfig.d.ts +5 -1
- package/lib/core/backend/backendConfig.js +4 -0
- package/lib/core/backend/backendOpenApi.d.ts +9 -0
- package/lib/core/backend/backendOpenApi.js +69 -0
- package/lib/core/backend/index.d.ts +1 -0
- package/lib/core/backend/index.js +1 -0
- package/lib/core/network/accessLogger.js +6 -6
- package/lib/core/network/clientConnection.js +1 -1
- package/lib/core/network/entryPoint.js +5 -5
- package/lib/core/network/httpRouter/index.js +5 -5
- package/lib/core/network/httpRouter/routeHandler.js +3 -3
- package/lib/core/network/httpRouter/routePart.js +5 -5
- package/lib/core/network/protocolManifest.js +1 -1
- package/lib/core/network/protocols/httpMessage.js +2 -2
- package/lib/core/network/protocols/httpwsProtocol.js +205 -48
- package/lib/core/network/protocols/mqttProtocol.js +3 -3
- package/lib/core/network/protocols/protocol.js +3 -3
- package/lib/core/network/router.js +7 -6
- package/lib/core/plugin/plugin.js +38 -64
- package/lib/core/plugin/pluginManifest.js +3 -3
- package/lib/core/plugin/pluginRepository.js +5 -5
- package/lib/core/plugin/pluginsManager.js +29 -28
- package/lib/core/realtime/notification/server.js +1 -1
- package/lib/core/realtime/notification/user.js +1 -1
- package/lib/core/realtime/notifier.js +5 -5
- package/lib/core/security/index.js +1 -1
- package/lib/core/security/profileRepository.d.ts +176 -0
- package/lib/core/security/profileRepository.js +426 -443
- package/lib/core/security/roleRepository.js +16 -16
- package/lib/core/security/securityLoader.js +2 -2
- package/lib/core/security/tokenRepository.js +11 -11
- package/lib/core/security/userRepository.js +8 -8
- package/lib/core/shared/abstractManifest.js +4 -4
- package/lib/core/shared/repository.js +5 -5
- package/lib/core/shared/sdk/funnelProtocol.js +1 -1
- package/lib/core/shared/sdk/impersonatedSdk.js +1 -1
- package/lib/core/shared/store.js +30 -23
- package/lib/core/statistics/statistics.js +17 -17
- package/lib/core/storage/clientAdapter.js +45 -10
- package/lib/core/validation/baseType.js +5 -5
- package/lib/core/validation/types/anything.js +1 -1
- package/lib/core/validation/types/boolean.js +2 -2
- package/lib/core/validation/types/date.js +9 -9
- package/lib/core/validation/types/email.js +5 -5
- package/lib/core/validation/types/enum.js +6 -6
- package/lib/core/validation/types/geoPoint.js +2 -2
- package/lib/core/validation/types/geoShape.js +28 -25
- package/lib/core/validation/types/integer.js +4 -4
- package/lib/core/validation/types/ipAddress.js +7 -6
- package/lib/core/validation/types/numeric.js +4 -4
- package/lib/core/validation/types/object.js +5 -5
- package/lib/core/validation/types/string.js +5 -5
- package/lib/core/validation/types/url.js +7 -6
- package/lib/core/validation/validation.js +95 -84
- package/lib/kerror/codes/1-services.json +12 -0
- package/lib/kerror/codes/2-api.json +12 -0
- package/lib/kerror/codes/3-network.json +12 -0
- package/lib/kerror/codes/4-plugin.json +6 -0
- package/lib/kerror/codes/index.js +11 -11
- package/lib/kerror/index.js +1 -1
- package/lib/kuzzle/dumpGenerator.js +3 -3
- package/lib/kuzzle/event/kuzzleEventEmitter.js +4 -4
- package/lib/kuzzle/event/pipeRunner.js +1 -1
- package/lib/kuzzle/event/waterfall.js +6 -6
- package/lib/kuzzle/kuzzle.js +36 -5
- package/lib/kuzzle/log.js +3 -3
- package/lib/kuzzle/vault.js +3 -3
- package/lib/model/security/profile.d.ts +54 -0
- package/lib/model/security/profile.js +174 -233
- package/lib/model/security/rights.js +1 -1
- package/lib/model/security/role.d.ts +40 -0
- package/lib/model/security/role.js +159 -191
- package/lib/model/security/user.d.ts +29 -0
- package/lib/model/security/user.js +84 -52
- package/lib/model/storage/apiKey.js +2 -2
- package/lib/model/storage/baseModel.js +3 -3
- package/lib/service/cache/redis.js +7 -7
- package/lib/service/storage/elasticsearch.js +152 -90
- package/lib/service/storage/esWrapper.js +2 -3
- package/lib/types/ControllerDefinition.d.ts +3 -3
- package/lib/types/ControllerRights.d.ts +22 -0
- package/lib/types/ControllerRights.js +23 -0
- package/lib/types/HttpStream.d.ts +32 -0
- package/lib/types/HttpStream.js +70 -0
- package/lib/types/OpenApiDefinition.d.ts +43 -0
- package/lib/types/{config/StorageService/StorageServiceElasticsearchConfiguration.js → OpenApiDefinition.js} +1 -1
- package/lib/types/Policy.d.ts +25 -0
- package/lib/types/{InternalLogger.js → Policy.js} +2 -2
- package/lib/types/PolicyRestrictions.d.ts +21 -0
- package/lib/types/PolicyRestrictions.js +23 -0
- package/lib/types/Target.d.ts +15 -0
- package/lib/types/Target.js +23 -0
- package/lib/types/config/KuzzleConfiguration.d.ts +4 -0
- package/lib/types/config/ServicesConfiguration.d.ts +2 -2
- package/lib/types/config/{StorageService/StorageServiceElasticsearchConfiguration.d.ts → storageEngine/StorageEngineElasticsearchConfiguration.d.ts} +10 -3
- package/lib/types/config/storageEngine/StorageEngineElasticsearchConfiguration.js +3 -0
- package/lib/types/index.d.ts +7 -1
- package/lib/types/index.js +7 -1
- package/lib/util/array.d.ts +11 -0
- package/lib/util/array.js +57 -0
- package/lib/util/assertType.js +6 -6
- package/lib/util/bufferedPassThrough.d.ts +76 -0
- package/lib/util/bufferedPassThrough.js +161 -0
- package/lib/util/deprecate.js +7 -5
- package/lib/util/didYouMean.js +1 -1
- package/lib/util/dump-collection.d.ts +3 -0
- package/lib/util/dump-collection.js +265 -0
- package/lib/util/extractFields.js +2 -2
- package/lib/util/inflector.d.ts +8 -0
- package/lib/util/inflector.js +16 -0
- package/lib/util/requestAssertions.js +7 -7
- package/lib/util/wildcard.js +55 -0
- package/package-lock.json +538 -78
- package/package.json +5 -3
- package/lib/api/openApiGenerator.d.ts +0 -7
- package/lib/api/openApiGenerator.js +0 -197
- package/lib/types/InternalLogger.d.ts +0 -25
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/*
|
|
2
3
|
* Kuzzle, a backend software, self-hostable and ready to use
|
|
3
4
|
* to power modern apps
|
|
@@ -18,202 +19,169 @@
|
|
|
18
19
|
* See the License for the specific language governing permissions and
|
|
19
20
|
* limitations under the License.
|
|
20
21
|
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
22
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
23
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.Role = void 0;
|
|
27
|
+
const kerror_1 = __importDefault(require("../../kerror"));
|
|
28
|
+
const safeObject_1 = require("../../util/safeObject");
|
|
29
|
+
const array_1 = require("../../util/array");
|
|
30
|
+
const assertionError = kerror_1.default.wrap('api', 'assert');
|
|
29
31
|
/**
|
|
30
32
|
* @class Role
|
|
31
33
|
*/
|
|
32
34
|
class Role {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
Object
|
|
111
|
-
.entries(this.controllers)
|
|
112
|
-
.forEach(entry => this.validateControllerRights(...entry));
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Verifies that a controller rights definition is correct
|
|
117
|
-
*
|
|
118
|
-
* @param {Array.<string, Object>}
|
|
119
|
-
* @throws If the controller definition is invalid
|
|
120
|
-
*/
|
|
121
|
-
validateControllerRights (name, controller) {
|
|
122
|
-
if (!isPlainObject(controller)) {
|
|
123
|
-
throw assertionError.get('invalid_type', name, 'object');
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (Object.keys(controller).length === 0) {
|
|
127
|
-
throw assertionError.get('empty_argument', name);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (!has(controller, 'actions')) {
|
|
131
|
-
throw assertionError.get('missing_argument', name);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (!isPlainObject(controller.actions)) {
|
|
135
|
-
throw assertionError.get('invalid_type', `${name}.actions`, 'object');
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (Object.keys(controller.actions).length === 0) {
|
|
139
|
-
throw assertionError.get('empty_argument', `${name}.actions`);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
for (const [actionName, action] of Object.entries(controller.actions)) {
|
|
143
|
-
if (typeof action !== 'boolean') {
|
|
144
|
-
throw assertionError.get('invalid_type', `${name}.actions.${actionName}`, 'boolean');
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Checks if current role allows to log in
|
|
151
|
-
*
|
|
152
|
-
* @returns {boolean}
|
|
153
|
-
*/
|
|
154
|
-
canLogIn () {
|
|
155
|
-
for (const controllerKey of ['auth', '*']) {
|
|
156
|
-
if (this.controllers[controllerKey]) {
|
|
157
|
-
const controller = this.controllers[controllerKey];
|
|
158
|
-
|
|
159
|
-
for (const actionKey of ['login', '*']) {
|
|
160
|
-
const action = controller.actions[actionKey];
|
|
161
|
-
|
|
162
|
-
if (typeof action === 'boolean' && action) {
|
|
35
|
+
constructor() {
|
|
36
|
+
this.controllers = {};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* @param {Request} request
|
|
40
|
+
* @returns {boolean}
|
|
41
|
+
*/
|
|
42
|
+
isActionAllowed(request) {
|
|
43
|
+
if (!global.kuzzle) {
|
|
44
|
+
throw kerror_1.default.get('security', 'role', 'uninitialized', this._id);
|
|
45
|
+
}
|
|
46
|
+
if (this.controllers === undefined || this.controllers === null) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
let controllerRights;
|
|
50
|
+
// @deprecated - the "memoryStorage" alias should be removed in the next
|
|
51
|
+
// major version
|
|
52
|
+
// Handles the memory storage controller aliases: ms, memoryStorage
|
|
53
|
+
if ((request.input.controller === 'ms' || request.input.controller === 'memoryStorage')
|
|
54
|
+
&& (this.controllers.ms || this.controllers.memoryStorage)) {
|
|
55
|
+
controllerRights = this.controllers.ms || this.controllers.memoryStorage;
|
|
56
|
+
}
|
|
57
|
+
else if ((0, safeObject_1.has)(this.controllers, request.input.controller)) {
|
|
58
|
+
controllerRights = this.controllers[request.input.controller];
|
|
59
|
+
}
|
|
60
|
+
else if (this.controllers['*'] !== undefined) {
|
|
61
|
+
controllerRights = this.controllers['*'];
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
if (controllerRights.actions === undefined) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
let actionRights;
|
|
70
|
+
if ((0, safeObject_1.has)(controllerRights.actions, request.input.action)) {
|
|
71
|
+
actionRights = controllerRights.actions[request.input.action];
|
|
72
|
+
}
|
|
73
|
+
else if (controllerRights.actions['*'] !== undefined) {
|
|
74
|
+
actionRights = controllerRights.actions['*'];
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
if (typeof actionRights !== 'boolean' || !actionRights) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* @returns {Promise}
|
|
86
|
+
*/
|
|
87
|
+
async validateDefinition() {
|
|
88
|
+
if (this.controllers === undefined || this.controllers === null) {
|
|
89
|
+
throw assertionError.get('missing_argument', `${this._id}.controllers`);
|
|
90
|
+
}
|
|
91
|
+
if (!(0, safeObject_1.isPlainObject)(this.controllers)) {
|
|
92
|
+
throw assertionError.get('invalid_type', `${this._id}.controllers`, 'object');
|
|
93
|
+
}
|
|
94
|
+
if (Object.keys(this.controllers).length === 0) {
|
|
95
|
+
throw assertionError.get('empty_argument', `${this._id}.controllers`);
|
|
96
|
+
}
|
|
97
|
+
Object
|
|
98
|
+
.entries(this.controllers)
|
|
99
|
+
.forEach(entry => this.validateControllerRights(...entry));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* @param {String} index
|
|
103
|
+
* @param {String} collection
|
|
104
|
+
* @param {Map<string, string[]>} restrictedTo Restricted indexes
|
|
105
|
+
* @returns {Boolean} resolves to a Boolean value
|
|
106
|
+
*/
|
|
107
|
+
checkRestrictions(index, collection, restrictedTo) {
|
|
108
|
+
// If no restrictions, we allow the action:
|
|
109
|
+
if (!restrictedTo || restrictedTo.size === 0) {
|
|
163
110
|
return true;
|
|
164
|
-
}
|
|
165
111
|
}
|
|
166
|
-
|
|
112
|
+
// If the request's action does not refer to an index, restrictions are
|
|
113
|
+
// useless for this action (=> ignore them)
|
|
114
|
+
if (!index) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
// If the index is not in the restrictions, the action is not allowed
|
|
118
|
+
if (!restrictedTo.has(index)) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
const collections = restrictedTo.get(index);
|
|
122
|
+
// if no collections given on the restriction, the action is allowed for all
|
|
123
|
+
// collections:
|
|
124
|
+
if (!collections || collections.length === 0) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
// Find collection index in array
|
|
128
|
+
// If the collection is not in the array, the action is not allowed
|
|
129
|
+
// The array must be sorted for binary search to work
|
|
130
|
+
const indexOfCollection = (0, array_1.binarySearch)(collections, (collectionName) => {
|
|
131
|
+
if (collection > collectionName) {
|
|
132
|
+
return 1;
|
|
133
|
+
}
|
|
134
|
+
return collection < collectionName ? -1 : 0;
|
|
135
|
+
});
|
|
136
|
+
return indexOfCollection > -1; // Collection found
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Verifies that a controller rights definition is correct
|
|
140
|
+
*
|
|
141
|
+
* @param {Array.<string, Object>}
|
|
142
|
+
* @throws If the controller definition is invalid
|
|
143
|
+
*/
|
|
144
|
+
validateControllerRights(name, controller) {
|
|
145
|
+
if (!(0, safeObject_1.isPlainObject)(controller)) {
|
|
146
|
+
throw assertionError.get('invalid_type', name, 'object');
|
|
147
|
+
}
|
|
148
|
+
if (Object.keys(controller).length === 0) {
|
|
149
|
+
throw assertionError.get('empty_argument', name);
|
|
150
|
+
}
|
|
151
|
+
if (!(0, safeObject_1.has)(controller, 'actions')) {
|
|
152
|
+
throw assertionError.get('missing_argument', name);
|
|
153
|
+
}
|
|
154
|
+
if (!(0, safeObject_1.isPlainObject)(controller.actions)) {
|
|
155
|
+
throw assertionError.get('invalid_type', `${name}.actions`, 'object');
|
|
156
|
+
}
|
|
157
|
+
if (Object.keys(controller.actions).length === 0) {
|
|
158
|
+
throw assertionError.get('empty_argument', `${name}.actions`);
|
|
159
|
+
}
|
|
160
|
+
for (const [actionName, action] of Object.entries(controller.actions)) {
|
|
161
|
+
if (typeof action !== 'boolean') {
|
|
162
|
+
throw assertionError.get('invalid_type', `${name}.actions.${actionName}`, 'boolean');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Checks if current role allows to log in
|
|
168
|
+
*
|
|
169
|
+
* @returns {boolean}
|
|
170
|
+
*/
|
|
171
|
+
canLogIn() {
|
|
172
|
+
for (const controllerKey of ['auth', '*']) {
|
|
173
|
+
if (this.controllers[controllerKey]) {
|
|
174
|
+
const controller = this.controllers[controllerKey];
|
|
175
|
+
for (const actionKey of ['login', '*']) {
|
|
176
|
+
const action = controller.actions[actionKey];
|
|
177
|
+
if (typeof action === 'boolean' && action) {
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return false;
|
|
167
184
|
}
|
|
168
|
-
|
|
169
|
-
return false;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* @param {Request} request
|
|
175
|
-
* @param {object} restriction a restriction object on an index
|
|
176
|
-
* @returns {Boolean}
|
|
177
|
-
*/
|
|
178
|
-
function checkIndexRestriction(request, restriction) {
|
|
179
|
-
if (restriction.index !== request.input.args.index) {
|
|
180
|
-
return false;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// if no collections given on the restriction, the action is allowed for all
|
|
184
|
-
// collections:
|
|
185
|
-
if (!restriction.collections || restriction.collections.length === 0) {
|
|
186
|
-
return true;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// If the request's action does not refer to a collection, the restriction
|
|
190
|
-
// is useless for this action (=> ignored):
|
|
191
|
-
if (!request.input.args.collection) {
|
|
192
|
-
return true;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return restriction.collections.includes(request.input.args.collection);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* @param {Request} request
|
|
200
|
-
* @param {Array} restrictedTo
|
|
201
|
-
* @returns {Boolean} resolves to a Boolean value
|
|
202
|
-
*/
|
|
203
|
-
function checkRestrictions(request, restrictedTo) {
|
|
204
|
-
// If no restrictions, we allow the action:
|
|
205
|
-
if (restrictedTo.length === 0) {
|
|
206
|
-
return true;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// If the request's action does not refer to an index, restrictions are
|
|
210
|
-
// useless for this action (=> ignore them)
|
|
211
|
-
if (!request.input.args.index) {
|
|
212
|
-
return true;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
return restrictedTo
|
|
216
|
-
.some(restriction => checkIndexRestriction(request, restriction));
|
|
217
185
|
}
|
|
218
|
-
|
|
219
|
-
|
|
186
|
+
exports.Role = Role;
|
|
187
|
+
//# sourceMappingURL=role.js.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Profile } from './profile';
|
|
2
|
+
import { KuzzleRequest } from '../../../index';
|
|
3
|
+
/**
|
|
4
|
+
* @class User
|
|
5
|
+
*/
|
|
6
|
+
export declare class User {
|
|
7
|
+
_id: string;
|
|
8
|
+
profileIds: string[];
|
|
9
|
+
constructor();
|
|
10
|
+
/**
|
|
11
|
+
* @returns {Promise<Profile[]>}
|
|
12
|
+
*/
|
|
13
|
+
getProfiles(): Promise<Profile[]>;
|
|
14
|
+
/**
|
|
15
|
+
* @returns {Promise}
|
|
16
|
+
*/
|
|
17
|
+
getRights(): Promise<{}>;
|
|
18
|
+
/**
|
|
19
|
+
* @param {Request} request
|
|
20
|
+
* @returns {Promise.<boolean>}
|
|
21
|
+
*/
|
|
22
|
+
isActionAllowed(request: KuzzleRequest): Promise<boolean>;
|
|
23
|
+
/**
|
|
24
|
+
* Verifies that every targets are allowed by at least one profile,
|
|
25
|
+
* while skipping the ones that includes a wildcard since they will be expanded
|
|
26
|
+
* later on, based on index and collections authorized for the given user.
|
|
27
|
+
*/
|
|
28
|
+
private areTargetsAllowed;
|
|
29
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/*
|
|
2
3
|
* Kuzzle, a backend software, self-hostable and ready to use
|
|
3
4
|
* to power modern apps
|
|
@@ -18,62 +19,93 @@
|
|
|
18
19
|
* See the License for the specific language governing permissions and
|
|
19
20
|
* limitations under the License.
|
|
20
21
|
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
|
|
22
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
23
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.User = void 0;
|
|
27
|
+
const rights_1 = __importDefault(require("./rights"));
|
|
28
|
+
const bluebird_1 = __importDefault(require("bluebird"));
|
|
29
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
30
|
+
const kerror_1 = __importDefault(require("../../kerror"));
|
|
29
31
|
/**
|
|
30
32
|
* @class User
|
|
31
33
|
*/
|
|
32
34
|
class User {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* @returns {Promise<Profile[]>}
|
|
40
|
-
*/
|
|
41
|
-
getProfiles() {
|
|
42
|
-
if (!global.kuzzle) {
|
|
43
|
-
return kerror.reject('security', 'user', 'uninitialized', this._id);
|
|
35
|
+
constructor() {
|
|
36
|
+
this._id = null;
|
|
37
|
+
this.profileIds = [];
|
|
44
38
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
39
|
+
/**
|
|
40
|
+
* @returns {Promise<Profile[]>}
|
|
41
|
+
*/
|
|
42
|
+
getProfiles() {
|
|
43
|
+
if (!global.kuzzle) {
|
|
44
|
+
return kerror_1.default.reject('security', 'user', 'uninitialized', this._id);
|
|
45
|
+
}
|
|
46
|
+
return global.kuzzle.ask('core:security:profile:mGet', this.profileIds);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* @returns {Promise}
|
|
50
|
+
*/
|
|
51
|
+
async getRights() {
|
|
52
|
+
const profiles = await this.getProfiles();
|
|
53
|
+
const results = await bluebird_1.default.map(profiles, p => p.getRights());
|
|
54
|
+
const rights = {};
|
|
55
|
+
results.forEach(right => lodash_1.default.assignWith(rights, right, rights_1.default.merge));
|
|
56
|
+
return rights;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* @param {Request} request
|
|
60
|
+
* @returns {Promise.<boolean>}
|
|
61
|
+
*/
|
|
62
|
+
async isActionAllowed(request) {
|
|
63
|
+
if (this.profileIds === undefined || this.profileIds.length === 0) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
const targets = request.getArray('targets', []);
|
|
67
|
+
const profiles = await this.getProfiles();
|
|
68
|
+
if (targets.length === 0) {
|
|
69
|
+
for (const profile of profiles) {
|
|
70
|
+
if (await profile.isActionAllowed(request)) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
// Every target must be allowed by at least one profile
|
|
77
|
+
return this.areTargetsAllowed(profiles, targets);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Verifies that every targets are allowed by at least one profile,
|
|
81
|
+
* while skipping the ones that includes a wildcard since they will be expanded
|
|
82
|
+
* later on, based on index and collections authorized for the given user.
|
|
83
|
+
*/
|
|
84
|
+
async areTargetsAllowed(profiles, targets) {
|
|
85
|
+
const profilesPolicies = await bluebird_1.default.map(profiles, profile => profile.getAllowedPolicies());
|
|
86
|
+
// Every target must be allowed by at least one profile
|
|
87
|
+
for (const target of targets) {
|
|
88
|
+
// Skip targets with no Index or Collection
|
|
89
|
+
if (!target.index || !target.collections) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
// TODO: Support Wildcard
|
|
93
|
+
if (target.index.includes('*')) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
for (const collection of target.collections) {
|
|
97
|
+
// TODO: Support Wildcard
|
|
98
|
+
if (collection.includes('*')) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
const isTargetAllowed = profilesPolicies.some(policies => policies.some(policy => policy.role.checkRestrictions(target.index, collection, policy.restrictedTo)));
|
|
102
|
+
if (!isTargetAllowed) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return true;
|
|
70
108
|
}
|
|
71
|
-
|
|
72
|
-
const profiles = await this.getProfiles();
|
|
73
|
-
const result = await Bluebird.map(profiles, p => p.isActionAllowed(request));
|
|
74
|
-
|
|
75
|
-
return result.includes(true);
|
|
76
|
-
}
|
|
77
109
|
}
|
|
78
|
-
|
|
79
|
-
|
|
110
|
+
exports.User = User;
|
|
111
|
+
//# sourceMappingURL=user.js.map
|
|
@@ -50,7 +50,7 @@ class ApiKey extends BaseModel {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
serialize ({ includeToken=false } = {}) {
|
|
53
|
+
serialize ({ includeToken = false } = {}) {
|
|
54
54
|
const serialized = super.serialize();
|
|
55
55
|
|
|
56
56
|
if (! includeToken) {
|
|
@@ -90,7 +90,7 @@ class ApiKey extends BaseModel {
|
|
|
90
90
|
user,
|
|
91
91
|
expiresIn,
|
|
92
92
|
description,
|
|
93
|
-
{ creatorId=null, apiKeyId=null, refresh, bypassMaxTTL=false } = {}
|
|
93
|
+
{ creatorId = null, apiKeyId = null, refresh, bypassMaxTTL = false } = {}
|
|
94
94
|
) {
|
|
95
95
|
const token = await global.kuzzle.ask('core:security:token:create', user, {
|
|
96
96
|
bypassMaxTTL,
|
|
@@ -73,7 +73,7 @@ class BaseModel {
|
|
|
73
73
|
*
|
|
74
74
|
* @returns {Promise}
|
|
75
75
|
*/
|
|
76
|
-
async save ({ userId=null, refresh } = {}) {
|
|
76
|
+
async save ({ userId = null, refresh } = {}) {
|
|
77
77
|
if (! this.__persisted) {
|
|
78
78
|
const { _id, _source } = await global.kuzzle.internalIndex.create(
|
|
79
79
|
this.constructor.collection,
|
|
@@ -123,7 +123,7 @@ class BaseModel {
|
|
|
123
123
|
*/
|
|
124
124
|
serialize () {
|
|
125
125
|
return {
|
|
126
|
-
_id
|
|
126
|
+
_id: this._id,
|
|
127
127
|
_source: this._source
|
|
128
128
|
};
|
|
129
129
|
}
|
|
@@ -195,7 +195,7 @@ class BaseModel {
|
|
|
195
195
|
await Bluebird.map(
|
|
196
196
|
documents,
|
|
197
197
|
document => this._instantiateFromDb(document)._afterDelete(),
|
|
198
|
-
{concurrency: 10}); // limits the load on storage services
|
|
198
|
+
{ concurrency: 10 }); // limits the load on storage services
|
|
199
199
|
|
|
200
200
|
if (refresh) {
|
|
201
201
|
await global.kuzzle.internalIndex.refreshCollection(this.collection);
|
|
@@ -102,7 +102,7 @@ class Redis extends Service {
|
|
|
102
102
|
* Setup a ping interval to keep the connection alive
|
|
103
103
|
* Every 60 seconds a ping is sent to Redis
|
|
104
104
|
*/
|
|
105
|
-
_setupKeepAlive(delay) {
|
|
105
|
+
_setupKeepAlive (delay) {
|
|
106
106
|
this.client.on('ready', async () => {
|
|
107
107
|
await this._ping();
|
|
108
108
|
this.pingIntervalID = setInterval(this._ping.bind(this), delay);
|
|
@@ -117,7 +117,7 @@ class Redis extends Service {
|
|
|
117
117
|
/**
|
|
118
118
|
* Ping Redis
|
|
119
119
|
*/
|
|
120
|
-
async _ping() {
|
|
120
|
+
async _ping () {
|
|
121
121
|
try {
|
|
122
122
|
await this.client.ping();
|
|
123
123
|
}
|
|
@@ -134,7 +134,7 @@ class Redis extends Service {
|
|
|
134
134
|
|
|
135
135
|
for (const command of commandsList) {
|
|
136
136
|
this.commands[command] = async (...args) => {
|
|
137
|
-
if (!this.connected) {
|
|
137
|
+
if (! this.connected) {
|
|
138
138
|
throw kerror.get('notconnected');
|
|
139
139
|
}
|
|
140
140
|
|
|
@@ -156,7 +156,7 @@ class Redis extends Service {
|
|
|
156
156
|
|
|
157
157
|
arr.forEach(item => {
|
|
158
158
|
item = item.trim();
|
|
159
|
-
if (item.length > 0 && !item.startsWith('#')) {
|
|
159
|
+
if (item.length > 0 && ! item.startsWith('#')) {
|
|
160
160
|
const keyValuePair = item.split(':');
|
|
161
161
|
info[keyValuePair[0]] = keyValuePair[1];
|
|
162
162
|
}
|
|
@@ -199,7 +199,7 @@ class Redis extends Service {
|
|
|
199
199
|
* @returns {Promise}
|
|
200
200
|
*/
|
|
201
201
|
mExecute (commands) {
|
|
202
|
-
if (!Array.isArray(commands) || commands.length === 0) {
|
|
202
|
+
if (! Array.isArray(commands) || commands.length === 0) {
|
|
203
203
|
return Bluebird.resolve([]);
|
|
204
204
|
}
|
|
205
205
|
|
|
@@ -211,7 +211,7 @@ class Redis extends Service {
|
|
|
211
211
|
_searchNodeKeys (node, pattern) {
|
|
212
212
|
return new Bluebird(resolve => {
|
|
213
213
|
let keys = [];
|
|
214
|
-
const stream = node.scanStream({match: pattern});
|
|
214
|
+
const stream = node.scanStream({ match: pattern });
|
|
215
215
|
|
|
216
216
|
stream.on('data', resultKeys => {
|
|
217
217
|
keys = keys.concat(resultKeys);
|
|
@@ -243,7 +243,7 @@ class Redis extends Service {
|
|
|
243
243
|
* @param {{onlyIfNew: boolean, ttl: number}} [options]
|
|
244
244
|
* @return {boolean} true if the key was set, false otherwise
|
|
245
245
|
*/
|
|
246
|
-
async store (key, value, {onlyIfNew = false, ttl = 0} = {}) {
|
|
246
|
+
async store (key, value, { onlyIfNew = false, ttl = 0 } = {}) {
|
|
247
247
|
const command = [key, value];
|
|
248
248
|
|
|
249
249
|
if (onlyIfNew) {
|