kuzzle 2.14.0 → 2.14.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/securityController.js +49 -13
- package/lib/api/funnel.js +13 -24
- package/lib/api/openApiGenerator.js +6 -0
- package/lib/api/request/kuzzleRequest.js +9 -9
- package/lib/config/default.config.js +10 -1
- package/lib/core/auth/tokenManager.d.ts +65 -0
- package/lib/core/auth/tokenManager.js +222 -256
- package/lib/core/backend/backend.js +3 -4
- package/lib/core/backend/backendController.d.ts +27 -0
- package/lib/core/backend/backendController.js +27 -0
- package/lib/core/backend/backendImport.js +6 -6
- package/lib/core/backend/backendPlugin.js +1 -1
- package/lib/core/plugin/plugin.js +42 -2
- package/lib/core/plugin/pluginContext.js +2 -2
- package/lib/core/plugin/pluginsManager.js +1 -0
- package/lib/core/realtime/hotelClerk.js +30 -16
- package/lib/core/security/profileRepository.js +5 -22
- package/lib/core/security/roleRepository.js +11 -5
- package/lib/core/security/tokenRepository.js +1 -1
- package/lib/core/security/userRepository.js +2 -2
- package/lib/core/shared/KoncordeWrapper.d.ts +1 -2
- package/lib/core/shared/KoncordeWrapper.js +10 -9
- package/lib/core/shared/repository.js +3 -3
- package/lib/core/shared/sdk/embeddedSdk.d.ts +2 -2
- package/lib/core/shared/sdk/embeddedSdk.js +2 -2
- package/lib/kerror/codes/4-plugin.json +6 -0
- package/lib/kuzzle/kuzzle.js +1 -1
- package/lib/model/security/token.d.ts +29 -0
- package/lib/model/security/token.js +25 -24
- package/lib/service/storage/elasticsearch.js +23 -5
- package/lib/types/ControllerDefinition.d.ts +51 -1
- package/lib/types/Plugin.js +1 -1
- package/lib/util/koncordeCompat.js +1 -1
- package/lib/util/mutex.js +2 -2
- package/package-lock.json +559 -1889
- package/package.json +27 -34
|
@@ -73,7 +73,7 @@ class BackendPlugin extends index_1.ApplicationManager {
|
|
|
73
73
|
*/
|
|
74
74
|
get(name) {
|
|
75
75
|
if (!this._application._plugins[name]) {
|
|
76
|
-
throw assertionError.get('plugin_not_found', name, didYouMean_1.default(name, this.list()));
|
|
76
|
+
throw assertionError.get('plugin_not_found', name, (0, didYouMean_1.default)(name, this.list()));
|
|
77
77
|
}
|
|
78
78
|
return this._application._plugins[name].plugin;
|
|
79
79
|
}
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
|
|
24
24
|
const path = require('path');
|
|
25
25
|
const fs = require('fs');
|
|
26
|
-
|
|
27
26
|
const semver = require('semver');
|
|
27
|
+
const enforcer = require('openapi-enforcer');
|
|
28
28
|
|
|
29
29
|
const { PluginContext } = require('./pluginContext');
|
|
30
30
|
const PrivilegedPluginContext = require('./privilegedContext');
|
|
@@ -34,6 +34,7 @@ const Manifest = require('./pluginManifest');
|
|
|
34
34
|
const { has, isPlainObject } = require('../../util/safeObject');
|
|
35
35
|
|
|
36
36
|
const assertionError = kerror.wrap('plugin', 'assert');
|
|
37
|
+
const controllerError = kerror.wrap('plugin', 'controller');
|
|
37
38
|
const runtimeError = kerror.wrap('plugin', 'runtime');
|
|
38
39
|
|
|
39
40
|
const PLUGIN_NAME_REGEX = /^[a-z-\d]+$/;
|
|
@@ -330,16 +331,21 @@ class Plugin {
|
|
|
330
331
|
checkHttpRouteProperties(route, action, name, application);
|
|
331
332
|
|
|
332
333
|
const routeProperties = Object.keys(route);
|
|
333
|
-
if (routeProperties.length >
|
|
334
|
+
if (routeProperties.length > 3) {
|
|
334
335
|
routeProperties.splice(routeProperties.indexOf('url'), 1);
|
|
335
336
|
routeProperties.splice(routeProperties.indexOf('path'), 1);
|
|
336
337
|
routeProperties.splice(routeProperties.indexOf('verb'), 1);
|
|
338
|
+
routeProperties.splice(routeProperties.indexOf('openapi'), 1);
|
|
337
339
|
|
|
338
340
|
throw assertionError.get(
|
|
339
341
|
'invalid_controller_definition',
|
|
340
342
|
name,
|
|
341
343
|
`action "${action}" has invalid http properties: ${routeProperties.join(', ')}`);
|
|
342
344
|
}
|
|
345
|
+
|
|
346
|
+
if (route.openapi) {
|
|
347
|
+
checkOpenAPISpecification(name, action, route);
|
|
348
|
+
}
|
|
343
349
|
}
|
|
344
350
|
}
|
|
345
351
|
}
|
|
@@ -359,4 +365,38 @@ function checkHttpRouteProperties (route, action, name, application) {
|
|
|
359
365
|
}
|
|
360
366
|
}
|
|
361
367
|
|
|
368
|
+
function checkOpenAPISpecification (controller, action, route) {
|
|
369
|
+
if (! isPlainObject(route.openapi)) {
|
|
370
|
+
throw assertionError.get(
|
|
371
|
+
'invalid_controller_definition',
|
|
372
|
+
controller,
|
|
373
|
+
'The "openapi" property must be an object');
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Set :param notation to {param}
|
|
377
|
+
const formattedPath = route.path.replace(/\/:([^/]*)/g,'/{$1}');
|
|
378
|
+
|
|
379
|
+
const { error, warning } = enforcer({
|
|
380
|
+
/* eslint-disable sort-keys */
|
|
381
|
+
openapi: '3.0.1',
|
|
382
|
+
info: {
|
|
383
|
+
title: 'Kuzzle API',
|
|
384
|
+
version: require('../../../package').version
|
|
385
|
+
},
|
|
386
|
+
paths: {
|
|
387
|
+
[formattedPath]: {
|
|
388
|
+
[route.verb]: route.openapi
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
/* eslint-enable sort-keys */
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
if (warning) {
|
|
395
|
+
global.kuzzle.log.warn(`Warning for OpenAPI specification in "${controller}:${action}", ${route.openapi} : ${warning}`);
|
|
396
|
+
}
|
|
397
|
+
if (error) {
|
|
398
|
+
throw controllerError.get('invalid_openapi_schema', controller, action, route.openapi, error);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
362
402
|
module.exports = Plugin;
|
|
@@ -249,8 +249,8 @@ function curryAddStrategy(pluginName) {
|
|
|
249
249
|
// be serialized and propagated to other cluster nodes
|
|
250
250
|
// so if a strategy is not defined using an authenticator, we have
|
|
251
251
|
// to reject the call
|
|
252
|
-
if (!safeObject_1.isPlainObject(strategy)
|
|
253
|
-
|| !safeObject_1.isPlainObject(strategy.config)
|
|
252
|
+
if (!(0, safeObject_1.isPlainObject)(strategy)
|
|
253
|
+
|| !(0, safeObject_1.isPlainObject)(strategy.config)
|
|
254
254
|
|| typeof strategy.config.authenticator !== 'string') {
|
|
255
255
|
throw contextError.get('missing_authenticator', pluginName, name);
|
|
256
256
|
}
|
|
@@ -54,12 +54,13 @@ class Channel {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
class Subscription {
|
|
57
|
-
constructor (index, collection, filters, roomId, connectionId) {
|
|
57
|
+
constructor (index, collection, filters, roomId, connectionId, user) {
|
|
58
58
|
this.index = index;
|
|
59
59
|
this.collection = collection;
|
|
60
60
|
this.filters = filters;
|
|
61
61
|
this.roomId = roomId;
|
|
62
62
|
this.connectionId = connectionId;
|
|
63
|
+
this.kuid = user && user._id || null;
|
|
63
64
|
}
|
|
64
65
|
}
|
|
65
66
|
|
|
@@ -186,6 +187,7 @@ class HotelClerk {
|
|
|
186
187
|
* Unsubscribes a user from a room
|
|
187
188
|
* @param {string} connectionId
|
|
188
189
|
* @param {string} roomId
|
|
190
|
+
* @param {string} kuid
|
|
189
191
|
* @param {boolean} [notify]
|
|
190
192
|
*/
|
|
191
193
|
global.kuzzle.onAsk(
|
|
@@ -209,7 +211,6 @@ class HotelClerk {
|
|
|
209
211
|
*/
|
|
210
212
|
async subscribe (request) {
|
|
211
213
|
const { index, collection } = request.input.resource;
|
|
212
|
-
const propagate = request.input.args.propagate || false;
|
|
213
214
|
|
|
214
215
|
if (! index) {
|
|
215
216
|
return kerror.reject('api', 'assert', 'missing_argument', 'index');
|
|
@@ -230,7 +231,7 @@ class HotelClerk {
|
|
|
230
231
|
* is made on the very last moment and is essential to ensure
|
|
231
232
|
* that no zombie subscription can be performed
|
|
232
233
|
*/
|
|
233
|
-
if (!global.kuzzle.router.isConnectionAlive(request.context)) {
|
|
234
|
+
if (! global.kuzzle.router.isConnectionAlive(request.context)) {
|
|
234
235
|
return null;
|
|
235
236
|
}
|
|
236
237
|
|
|
@@ -245,13 +246,13 @@ class HotelClerk {
|
|
|
245
246
|
throw kerror.get('api', 'assert', 'koncorde_dsl_error', e.message);
|
|
246
247
|
}
|
|
247
248
|
|
|
248
|
-
|
|
249
|
+
this._createRoom(normalized);
|
|
249
250
|
|
|
250
251
|
const { channel, subscribed } = await this._subscribeToRoom(
|
|
251
252
|
normalized.id,
|
|
252
253
|
request);
|
|
253
254
|
|
|
254
|
-
if (
|
|
255
|
+
if (subscribed) {
|
|
255
256
|
global.kuzzle.emit('core:realtime:subscribe:after', normalized.id);
|
|
256
257
|
|
|
257
258
|
// @deprecated -- to be removed in next major version
|
|
@@ -271,7 +272,8 @@ class HotelClerk {
|
|
|
271
272
|
collection,
|
|
272
273
|
request.input.body,
|
|
273
274
|
normalized.id,
|
|
274
|
-
request.context.connection.id
|
|
275
|
+
request.context.connection.id,
|
|
276
|
+
request.context.user);
|
|
275
277
|
|
|
276
278
|
global.kuzzle.emit('core:realtime:user:subscribe:after', subscription);
|
|
277
279
|
|
|
@@ -419,14 +421,15 @@ class HotelClerk {
|
|
|
419
421
|
* Create new room if needed
|
|
420
422
|
*
|
|
421
423
|
* @this HotelClerk
|
|
424
|
+
*
|
|
422
425
|
* @param {NormalizedFilter} normalized - Obtained with Koncorde.normalize
|
|
423
426
|
* @param {Object} [options]
|
|
424
|
-
*
|
|
425
|
-
* be propagated to the cluster
|
|
427
|
+
*
|
|
426
428
|
* @returns {void}
|
|
427
429
|
*/
|
|
428
|
-
_createRoom (normalized
|
|
429
|
-
const {
|
|
430
|
+
_createRoom (normalized) {
|
|
431
|
+
const { index: koncordeIndex, id: roomId } = normalized;
|
|
432
|
+
const [index, collection] = koncordeIndex.split('/');
|
|
430
433
|
|
|
431
434
|
if (this.rooms.has(normalized.id)) {
|
|
432
435
|
return;
|
|
@@ -440,12 +443,10 @@ class HotelClerk {
|
|
|
440
443
|
|
|
441
444
|
global.kuzzle.koncorde.store(normalized);
|
|
442
445
|
|
|
443
|
-
|
|
444
|
-
global.kuzzle.emit('core:realtime:room:create:after', normalized);
|
|
446
|
+
global.kuzzle.emit('core:realtime:room:create:after', normalized);
|
|
445
447
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
}
|
|
448
|
+
// @deprecated -- to be removed in the next major version of kuzzle
|
|
449
|
+
global.kuzzle.emit('room:new', { collection, index, roomId });
|
|
449
450
|
|
|
450
451
|
/*
|
|
451
452
|
In some very rare cases, the room may have been created between
|
|
@@ -550,13 +551,26 @@ class HotelClerk {
|
|
|
550
551
|
});
|
|
551
552
|
}
|
|
552
553
|
|
|
554
|
+
const kuid = global.kuzzle.tokenManager.getKuidFromConnection(connectionId);
|
|
555
|
+
|
|
556
|
+
const subscription = new Subscription(
|
|
557
|
+
room.index,
|
|
558
|
+
room.collection,
|
|
559
|
+
undefined,
|
|
560
|
+
roomId,
|
|
561
|
+
connectionId,
|
|
562
|
+
{ _id: kuid });
|
|
563
|
+
|
|
553
564
|
global.kuzzle.emit('core:realtime:user:unsubscribe:after', {
|
|
565
|
+
/* @deprecated */
|
|
554
566
|
requestContext,
|
|
567
|
+
/* @deprecated */
|
|
555
568
|
room: {
|
|
556
569
|
collection: room.collection,
|
|
557
570
|
id: roomId,
|
|
558
571
|
index: room.index,
|
|
559
|
-
}
|
|
572
|
+
},
|
|
573
|
+
subscription,
|
|
560
574
|
});
|
|
561
575
|
}
|
|
562
576
|
|
|
@@ -124,14 +124,16 @@ class ProfileRepository extends Repository {
|
|
|
124
124
|
(id, ttl) => this.scroll(id, ttl));
|
|
125
125
|
|
|
126
126
|
/**
|
|
127
|
-
* Searches profiles
|
|
128
|
-
*
|
|
127
|
+
* Searches profiles
|
|
128
|
+
*
|
|
129
|
+
* @param {Object} searchBody - Search query (ES format)
|
|
129
130
|
* @param {Object} opts (from, size, scroll)
|
|
131
|
+
*
|
|
130
132
|
* @returns {Object} Search results
|
|
131
133
|
*/
|
|
132
134
|
global.kuzzle.onAsk(
|
|
133
135
|
'core:security:profile:search',
|
|
134
|
-
(
|
|
136
|
+
(searchBody, opts) => this.search(searchBody, opts));
|
|
135
137
|
|
|
136
138
|
/**
|
|
137
139
|
* Removes all existing profiles and invalidates the RAM cache
|
|
@@ -316,25 +318,6 @@ class ProfileRepository extends Repository {
|
|
|
316
318
|
});
|
|
317
319
|
}
|
|
318
320
|
|
|
319
|
-
/**
|
|
320
|
-
*
|
|
321
|
-
* @param {string[]} roles - array of role ids
|
|
322
|
-
* @param {object} [options] - optional search arguments (from, size, scroll)
|
|
323
|
-
* @returns {Promise}
|
|
324
|
-
*/
|
|
325
|
-
searchProfiles (roles = [], {from=0, scroll, size=1000} = {}) {
|
|
326
|
-
const query = {query: {}};
|
|
327
|
-
|
|
328
|
-
if (roles && roles.length > 0) {
|
|
329
|
-
query.query = {terms: {'policies.roleId': roles}};
|
|
330
|
-
}
|
|
331
|
-
else {
|
|
332
|
-
query.query = {match_all: {}};
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
return this.search(query, {from, scroll, size});
|
|
336
|
-
}
|
|
337
|
-
|
|
338
321
|
/**
|
|
339
322
|
* Deletes a profile
|
|
340
323
|
*
|
|
@@ -308,10 +308,14 @@ class RoleRepository extends Repository {
|
|
|
308
308
|
}
|
|
309
309
|
|
|
310
310
|
/**
|
|
311
|
-
* @param {
|
|
311
|
+
* @param {Object} body Search body containing either "query" or "controllers"
|
|
312
312
|
* @param {Object} options
|
|
313
313
|
*/
|
|
314
|
-
async searchRole (
|
|
314
|
+
async searchRole (body, { from = 0, size = 9999 } = {}) {
|
|
315
|
+
if (! body.controllers) {
|
|
316
|
+
return this.search(body, { from, size });
|
|
317
|
+
}
|
|
318
|
+
|
|
315
319
|
const searchResults = await this.search(
|
|
316
320
|
{ query: {}, sort: [{ _id: { order: 'asc' } }]},
|
|
317
321
|
{ from: 0, size: 9999 }); // /!\ NOT the options values
|
|
@@ -321,11 +325,11 @@ class RoleRepository extends Repository {
|
|
|
321
325
|
total: searchResults.total
|
|
322
326
|
};
|
|
323
327
|
|
|
324
|
-
if (controllers.length > 0) {
|
|
328
|
+
if (body.controllers.length > 0) {
|
|
325
329
|
result.hits = searchResults.hits
|
|
326
330
|
.filter(role => Object
|
|
327
331
|
.keys(role.controllers)
|
|
328
|
-
.some(key => key === '*' || controllers.includes(key)));
|
|
332
|
+
.some(key => key === '*' || body.controllers.includes(key)));
|
|
329
333
|
|
|
330
334
|
result.total = result.hits.length;
|
|
331
335
|
}
|
|
@@ -488,7 +492,9 @@ class RoleRepository extends Repository {
|
|
|
488
492
|
throw kerror.get('security', 'role', 'cannot_delete');
|
|
489
493
|
}
|
|
490
494
|
|
|
491
|
-
const
|
|
495
|
+
const query = { term: { 'policies.roleId': role._id } };
|
|
496
|
+
|
|
497
|
+
const response = await this.module.profile.search({ query }, {
|
|
492
498
|
from: 0,
|
|
493
499
|
size: 1
|
|
494
500
|
});
|
|
@@ -28,7 +28,7 @@ const Bluebird = require('bluebird');
|
|
|
28
28
|
|
|
29
29
|
const ApiKey = require('../../model/storage/apiKey');
|
|
30
30
|
const { UnauthorizedError } = require('../../kerror/errors');
|
|
31
|
-
const Token = require('../../model/security/token');
|
|
31
|
+
const { Token } = require('../../model/security/token');
|
|
32
32
|
const Repository = require('../shared/repository');
|
|
33
33
|
const kerror = require('../../kerror');
|
|
34
34
|
const debug = require('../../util/debug')('kuzzle:bootstrap:tokens');
|
|
@@ -122,13 +122,13 @@ class UserRepository extends Repository {
|
|
|
122
122
|
|
|
123
123
|
/**
|
|
124
124
|
* Searches users
|
|
125
|
-
* @param {Object}
|
|
125
|
+
* @param {Object} searchBody - Search body (ES format)
|
|
126
126
|
* @param {Object} opts (from, size, scroll)
|
|
127
127
|
* @returns {Object} Search results
|
|
128
128
|
*/
|
|
129
129
|
global.kuzzle.onAsk(
|
|
130
130
|
'core:security:user:search',
|
|
131
|
-
(
|
|
131
|
+
(searchBody, opts) => this.search(searchBody, opts));
|
|
132
132
|
|
|
133
133
|
/**
|
|
134
134
|
* Removes all existing users
|
|
@@ -2,7 +2,7 @@ import { JSONObject } from 'kuzzle-sdk';
|
|
|
2
2
|
/**
|
|
3
3
|
* Emulates the normalized object returned by Koncorde v3
|
|
4
4
|
*/
|
|
5
|
-
declare class NormalizedFilterV3 {
|
|
5
|
+
export declare class NormalizedFilterV3 {
|
|
6
6
|
/**
|
|
7
7
|
* Filter Unique Identifier
|
|
8
8
|
*
|
|
@@ -148,4 +148,3 @@ export declare class Koncorde {
|
|
|
148
148
|
*/
|
|
149
149
|
validate(filter: JSONObject): Promise<void>;
|
|
150
150
|
}
|
|
151
|
-
export {};
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* limitations under the License.
|
|
21
21
|
*/
|
|
22
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.Koncorde = void 0;
|
|
23
|
+
exports.Koncorde = exports.NormalizedFilterV3 = void 0;
|
|
24
24
|
const koncorde_1 = require("koncorde");
|
|
25
25
|
const koncordeCompat_1 = require("../../util/koncordeCompat");
|
|
26
26
|
/**
|
|
@@ -34,6 +34,7 @@ class NormalizedFilterV3 {
|
|
|
34
34
|
this.normalized = normalized.filter;
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
+
exports.NormalizedFilterV3 = NormalizedFilterV3;
|
|
37
38
|
/*
|
|
38
39
|
@deprecated
|
|
39
40
|
|
|
@@ -81,7 +82,7 @@ class Koncorde {
|
|
|
81
82
|
* @return {boolean}
|
|
82
83
|
*/
|
|
83
84
|
exists(index, collection) {
|
|
84
|
-
return this.koncorde.getIndexes().includes(koncordeCompat_1.toKoncordeIndex(index, collection));
|
|
85
|
+
return this.koncorde.getIndexes().includes((0, koncordeCompat_1.toKoncordeIndex)(index, collection));
|
|
85
86
|
}
|
|
86
87
|
/**
|
|
87
88
|
* Returns the list of collections associated to an index registered in this
|
|
@@ -91,7 +92,7 @@ class Koncorde {
|
|
|
91
92
|
* @return {string[]}
|
|
92
93
|
*/
|
|
93
94
|
getCollections(index) {
|
|
94
|
-
return koncordeCompat_1.getCollections(this.koncorde, index);
|
|
95
|
+
return (0, koncordeCompat_1.getCollections)(this.koncorde, index);
|
|
95
96
|
}
|
|
96
97
|
/**
|
|
97
98
|
* Returns the list of filter identifiers registered on a given
|
|
@@ -102,7 +103,7 @@ class Koncorde {
|
|
|
102
103
|
* @return {string[]}
|
|
103
104
|
*/
|
|
104
105
|
getFilterIds(index, collection) {
|
|
105
|
-
return this.koncorde.getFilterIds(koncordeCompat_1.toKoncordeIndex(index, collection));
|
|
106
|
+
return this.koncorde.getFilterIds((0, koncordeCompat_1.toKoncordeIndex)(index, collection));
|
|
106
107
|
}
|
|
107
108
|
/**
|
|
108
109
|
* Returns the list of indexes registered in this Koncorde instance
|
|
@@ -110,7 +111,7 @@ class Koncorde {
|
|
|
110
111
|
* @return {string[]}
|
|
111
112
|
*/
|
|
112
113
|
getIndexes() {
|
|
113
|
-
return koncordeCompat_1.getIndexes(this.koncorde);
|
|
114
|
+
return (0, koncordeCompat_1.getIndexes)(this.koncorde);
|
|
114
115
|
}
|
|
115
116
|
/**
|
|
116
117
|
* Checks if a filter is registered for the given filter identifier
|
|
@@ -137,7 +138,7 @@ class Koncorde {
|
|
|
137
138
|
* @return {NormalizedFilterV3}
|
|
138
139
|
*/
|
|
139
140
|
async normalize(index, collection, filter) {
|
|
140
|
-
return new NormalizedFilterV3(index, collection, this.koncorde.normalize(filter, koncordeCompat_1.toKoncordeIndex(index, collection)));
|
|
141
|
+
return new NormalizedFilterV3(index, collection, this.koncorde.normalize(filter, (0, koncordeCompat_1.toKoncordeIndex)(index, collection)));
|
|
141
142
|
}
|
|
142
143
|
/**
|
|
143
144
|
* Registers a filter to the engine instance. This method is equivalent to
|
|
@@ -149,7 +150,7 @@ class Koncorde {
|
|
|
149
150
|
* @return {JSONObject}
|
|
150
151
|
*/
|
|
151
152
|
async register(index, collection, filter) {
|
|
152
|
-
const indexV4 = koncordeCompat_1.toKoncordeIndex(index, collection);
|
|
153
|
+
const indexV4 = (0, koncordeCompat_1.toKoncordeIndex)(index, collection);
|
|
153
154
|
const normalized = this.koncorde.normalize(filter, indexV4);
|
|
154
155
|
return this.store(new NormalizedFilterV3(index, collection, normalized));
|
|
155
156
|
}
|
|
@@ -170,7 +171,7 @@ class Koncorde {
|
|
|
170
171
|
* @return {JSONObject}
|
|
171
172
|
*/
|
|
172
173
|
async store(normalized) {
|
|
173
|
-
const indexV4 = koncordeCompat_1.toKoncordeIndex(normalized.index, normalized.collection);
|
|
174
|
+
const indexV4 = (0, koncordeCompat_1.toKoncordeIndex)(normalized.index, normalized.collection);
|
|
174
175
|
if (this.koncorde.hasFilterId(normalized.id, indexV4)) {
|
|
175
176
|
return {
|
|
176
177
|
diff: false,
|
|
@@ -196,7 +197,7 @@ class Koncorde {
|
|
|
196
197
|
* @return {string[]}
|
|
197
198
|
*/
|
|
198
199
|
test(index, collection, data, id) {
|
|
199
|
-
return koncordeCompat_1.koncordeTest(this.koncorde, index, collection, data, id);
|
|
200
|
+
return (0, koncordeCompat_1.koncordeTest)(this.koncorde, index, collection, data, id);
|
|
200
201
|
}
|
|
201
202
|
/**
|
|
202
203
|
* Tests the provided filter without storing it in the engine, to check
|
|
@@ -104,12 +104,12 @@ class Repository {
|
|
|
104
104
|
/**
|
|
105
105
|
* Search in database corresponding repository according to a query
|
|
106
106
|
*
|
|
107
|
-
* @param {object}
|
|
107
|
+
* @param {object} searchBody
|
|
108
108
|
* @param {object} [options] - optional search arguments (from, size, scroll)
|
|
109
109
|
* @returns {Promise}
|
|
110
110
|
*/
|
|
111
|
-
async search (
|
|
112
|
-
const response = await this.store.search(this.collection,
|
|
111
|
+
async search (searchBody, options = {}) {
|
|
112
|
+
const response = await this.store.search(this.collection, searchBody, options);
|
|
113
113
|
|
|
114
114
|
return this._formatSearchResults(response);
|
|
115
115
|
}
|
|
@@ -16,8 +16,8 @@ interface EmbeddedRealtime extends RealtimeController {
|
|
|
16
16
|
* - `scope` Subscribe to document entering or leaving the scope. (default: 'all')
|
|
17
17
|
* - `users` Subscribe to users entering or leaving the room. (default: 'none')
|
|
18
18
|
* - `subscribeToSelf` Subscribe to notifications fired by our own queries. (default: true)
|
|
19
|
-
* - `volatile` Subscription information sent alongside notifications
|
|
20
|
-
* - `propagate` Propagate the callback execution on each cluster node
|
|
19
|
+
* - `volatile` Subscription information sent alongside notifications. (default: `{}`)
|
|
20
|
+
* - `propagate` Propagate the callback execution on each cluster node. (default: false)
|
|
21
21
|
*
|
|
22
22
|
* @returns A string containing the room ID
|
|
23
23
|
*/
|
|
@@ -44,7 +44,7 @@ class EmbeddedSDK extends kuzzle_sdk_1.Kuzzle {
|
|
|
44
44
|
* @param options - Optional sdk arguments
|
|
45
45
|
*/
|
|
46
46
|
as(user, options = { checkRights: false }) {
|
|
47
|
-
if (!safeObject_1.isPlainObject(user) || typeof user._id !== 'string') {
|
|
47
|
+
if (!(0, safeObject_1.isPlainObject)(user) || typeof user._id !== 'string') {
|
|
48
48
|
throw contextError.get('invalid_user');
|
|
49
49
|
}
|
|
50
50
|
return new impersonatedSdk_1.default(user._id, options);
|
|
@@ -60,7 +60,7 @@ class EmbeddedSDK extends kuzzle_sdk_1.Kuzzle {
|
|
|
60
60
|
*/
|
|
61
61
|
query(request, options = {}) {
|
|
62
62
|
// By default, do not propagate realtime notification accross cluster nodes
|
|
63
|
-
if (safeObject_1.isPlainObject(request)
|
|
63
|
+
if ((0, safeObject_1.isPlainObject)(request)
|
|
64
64
|
&& request.controller === 'realtime'
|
|
65
65
|
&& request.action === 'subscribe') {
|
|
66
66
|
request.propagate = options.propagate === undefined || options.propagate === null
|
|
@@ -343,6 +343,12 @@
|
|
|
343
343
|
"code": 9,
|
|
344
344
|
"message": "Unexpected return value from action \"%s:%s\": expected a Promise",
|
|
345
345
|
"class": "PluginImplementationError"
|
|
346
|
+
},
|
|
347
|
+
"invalid_openapi_schema": {
|
|
348
|
+
"description": "OpenAPI specification is invalid",
|
|
349
|
+
"code": 10,
|
|
350
|
+
"message": "Invalid OpenAPI specification in \"%s:%s\", %s : %s",
|
|
351
|
+
"class": "PluginImplementationError"
|
|
346
352
|
}
|
|
347
353
|
}
|
|
348
354
|
},
|
package/lib/kuzzle/kuzzle.js
CHANGED
|
@@ -38,7 +38,7 @@ const PassportWrapper = require('../core/auth/passportWrapper');
|
|
|
38
38
|
const PluginsManager = require('../core/plugin/pluginsManager');
|
|
39
39
|
const Router = require('../core/network/router');
|
|
40
40
|
const Statistics = require('../core/statistics');
|
|
41
|
-
const TokenManager = require('../core/auth/tokenManager');
|
|
41
|
+
const { TokenManager } = require('../core/auth/tokenManager');
|
|
42
42
|
const Validation = require('../core/validation');
|
|
43
43
|
const Logger = require('./log');
|
|
44
44
|
const vault = require('./vault');
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface TokenContent {
|
|
2
|
+
/**
|
|
3
|
+
* Token ID (also Redis key)
|
|
4
|
+
*
|
|
5
|
+
* @example `${userId}#${jwt}`
|
|
6
|
+
*/
|
|
7
|
+
_id?: string;
|
|
8
|
+
expiresAt?: number;
|
|
9
|
+
ttl?: number;
|
|
10
|
+
userId?: string;
|
|
11
|
+
connectionIds?: string[];
|
|
12
|
+
jwt?: string;
|
|
13
|
+
refreshed?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Represents a token that identify an user.
|
|
17
|
+
*/
|
|
18
|
+
export declare class Token implements TokenContent {
|
|
19
|
+
_id: string;
|
|
20
|
+
expiresAt: number;
|
|
21
|
+
ttl: number;
|
|
22
|
+
userId: string;
|
|
23
|
+
jwt: string;
|
|
24
|
+
refreshed: boolean;
|
|
25
|
+
constructor(data?: TokenContent);
|
|
26
|
+
get type(): 'apiKey' | 'authToken';
|
|
27
|
+
static get AUTH_PREFIX(): string;
|
|
28
|
+
static get APIKEY_PREFIX(): string;
|
|
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,32 +19,32 @@
|
|
|
18
19
|
* See the License for the specific language governing permissions and
|
|
19
20
|
* limitations under the License.
|
|
20
21
|
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.Token = void 0;
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
25
|
+
* Represents a token that identify an user.
|
|
26
26
|
*/
|
|
27
27
|
class Token {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
28
|
+
constructor(data = {}) {
|
|
29
|
+
this._id = data._id || null;
|
|
30
|
+
this.expiresAt = data.expiresAt || null;
|
|
31
|
+
this.ttl = data.ttl || null;
|
|
32
|
+
this.userId = data.userId || null;
|
|
33
|
+
this.jwt = data.jwt || null;
|
|
34
|
+
this.refreshed = Boolean(data.refreshed);
|
|
35
|
+
}
|
|
36
|
+
get type() {
|
|
37
|
+
if (this.jwt && this.jwt.startsWith(Token.APIKEY_PREFIX)) {
|
|
38
|
+
return 'apiKey';
|
|
39
|
+
}
|
|
40
|
+
return 'authToken';
|
|
41
|
+
}
|
|
42
|
+
static get AUTH_PREFIX() {
|
|
43
|
+
return 'kauth-';
|
|
44
|
+
}
|
|
45
|
+
static get APIKEY_PREFIX() {
|
|
46
|
+
return 'kapikey-';
|
|
41
47
|
}
|
|
42
|
-
return 'authToken';
|
|
43
|
-
}
|
|
44
48
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
Token.APIKEY_PREFIX = 'kapikey-';
|
|
48
|
-
|
|
49
|
-
module.exports = Token;
|
|
49
|
+
exports.Token = Token;
|
|
50
|
+
//# sourceMappingURL=token.js.map
|
|
@@ -116,7 +116,6 @@ class ElasticSearch extends Service {
|
|
|
116
116
|
'explain',
|
|
117
117
|
'from',
|
|
118
118
|
'highlight',
|
|
119
|
-
'inner_hits',
|
|
120
119
|
'query',
|
|
121
120
|
'search_after',
|
|
122
121
|
'search_timeout',
|
|
@@ -395,11 +394,30 @@ class ElasticSearch extends Service {
|
|
|
395
394
|
}
|
|
396
395
|
|
|
397
396
|
_formatSearchResult (body) {
|
|
397
|
+
function formatHit (hit) {
|
|
398
|
+
return {
|
|
399
|
+
_id: hit._id,
|
|
400
|
+
_score: hit._score,
|
|
401
|
+
_source: hit._source,
|
|
402
|
+
highlight: hit.highlight,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function formatInnerHits (innerHits) {
|
|
407
|
+
if (! innerHits) {
|
|
408
|
+
return undefined;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const formattedInnerHits = {};
|
|
412
|
+
for (const [name, innerHit] of Object.entries(innerHits)) {
|
|
413
|
+
formattedInnerHits[name] = innerHit.hits.hits.map(formatHit);
|
|
414
|
+
}
|
|
415
|
+
return formattedInnerHits;
|
|
416
|
+
}
|
|
417
|
+
|
|
398
418
|
const hits = body.hits.hits.map(hit => ({
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
_source: hit._source,
|
|
402
|
-
highlight: hit.highlight,
|
|
419
|
+
inner_hits: formatInnerHits(hit.inner_hits),
|
|
420
|
+
...formatHit(hit)
|
|
403
421
|
}));
|
|
404
422
|
|
|
405
423
|
return {
|