kuzzle 2.17.8 → 2.19.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/index.d.ts +1 -0
- package/index.js +3 -0
- package/lib/api/controllers/adminController.js +9 -0
- package/lib/api/controllers/authController.js +8 -2
- package/lib/api/controllers/debugController.d.ts +59 -0
- package/lib/api/controllers/debugController.js +285 -0
- package/lib/api/controllers/documentController.js +49 -31
- package/lib/api/controllers/index.js +1 -0
- package/lib/api/controllers/indexController.js +10 -6
- package/lib/api/controllers/securityController.js +81 -43
- package/lib/api/controllers/serverController.js +2 -1
- package/lib/api/documentExtractor.js +51 -9
- package/lib/api/funnel.js +30 -8
- package/lib/api/httpRoutes.js +8 -1
- package/lib/api/openapi/OpenApiManager.js +3 -0
- package/lib/api/openapi/components/document/get.yaml +1 -1
- package/lib/api/openapi/components/document/update.yaml +1 -1
- package/lib/api/openapi/components/index.d.ts +1 -0
- package/lib/api/openapi/components/index.js +1 -0
- package/lib/api/openapi/components/security/index.d.ts +2 -0
- package/lib/api/openapi/components/security/index.js +10 -0
- package/lib/api/openapi/components/security/upsertUser.yaml +59 -0
- package/lib/api/request/kuzzleRequest.d.ts +58 -4
- package/lib/api/request/kuzzleRequest.js +163 -31
- package/lib/api/request/requestResponse.js +25 -0
- package/lib/cluster/idCardHandler.js +1 -1
- package/lib/config/default.config.js +3 -0
- package/lib/config/documentEventAliases.d.ts +7 -0
- package/lib/config/documentEventAliases.js +26 -12
- package/lib/core/backend/backend.d.ts +4 -0
- package/lib/core/backend/backend.js +9 -0
- package/lib/core/backend/backendController.d.ts +7 -1
- package/lib/core/backend/backendController.js +15 -3
- package/lib/core/network/protocols/httpwsProtocol.js +14 -6
- package/lib/core/plugin/plugin.js +7 -0
- package/lib/core/shared/sdk/embeddedSdk.d.ts +3 -3
- package/lib/core/shared/sdk/embeddedSdk.js +33 -0
- package/lib/core/shared/sdk/funnelProtocol.d.ts +1 -2
- package/lib/kerror/codes/0-core.json +35 -0
- package/lib/kerror/codes/1-services.json +1 -1
- package/lib/kerror/codes/2-api.json +6 -0
- package/lib/kerror/errors/kuzzleError.d.ts +1 -1
- package/lib/kuzzle/kuzzle.d.ts +1 -1
- package/lib/kuzzle/kuzzle.js +27 -8
- package/lib/model/security/user.js +5 -6
- package/lib/model/storage/apiKey.js +1 -6
- package/lib/service/storage/elasticsearch.js +143 -47
- package/lib/types/DebugModule.d.ts +23 -0
- package/lib/types/DebugModule.js +39 -0
- package/lib/types/config/SecurityConfiguration.d.ts +10 -0
- package/lib/types/index.d.ts +0 -1
- package/lib/types/index.js +0 -1
- package/lib/util/crypto.d.ts +1 -0
- package/lib/util/crypto.js +12 -0
- package/lib/util/dump-collection.d.ts +35 -0
- package/lib/util/dump-collection.js +11 -8
- package/lib/util/name-generator.d.ts +79 -0
- package/lib/util/name-generator.js +1409 -1345
- package/lib/util/time.d.ts +1 -0
- package/lib/util/time.js +9 -0
- package/package.json +19 -21
- package/lib/core/security/README.md +0 -224
- package/lib/core/shared/README.md +0 -3
- package/package-lock.json +0 -8403
|
@@ -31,13 +31,18 @@ const { NativeController } = require('./baseController');
|
|
|
31
31
|
const formatProcessing = require('../../core/auth/formatProcessing');
|
|
32
32
|
const ApiKey = require('../../model/storage/apiKey');
|
|
33
33
|
const kerror = require('../../kerror');
|
|
34
|
-
const { has
|
|
35
|
-
const {
|
|
34
|
+
const { has } = require('../../util/safeObject');
|
|
35
|
+
const { NameGenerator } = require('../../util/name-generator');
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* @class SecurityController
|
|
39
39
|
*/
|
|
40
40
|
class SecurityController extends NativeController {
|
|
41
|
+
|
|
42
|
+
static userOrSdk (userId) {
|
|
43
|
+
return userId === null ? 'EmbeddedSDK' : `User "${userId}"`;
|
|
44
|
+
}
|
|
45
|
+
|
|
41
46
|
constructor () {
|
|
42
47
|
super([
|
|
43
48
|
'checkRights',
|
|
@@ -92,6 +97,7 @@ class SecurityController extends NativeController {
|
|
|
92
97
|
'updateRoleMapping',
|
|
93
98
|
'updateUser',
|
|
94
99
|
'updateUserMapping',
|
|
100
|
+
'upsertUser',
|
|
95
101
|
'validateCredentials'
|
|
96
102
|
]);
|
|
97
103
|
|
|
@@ -149,7 +155,7 @@ class SecurityController extends NativeController {
|
|
|
149
155
|
refresh,
|
|
150
156
|
});
|
|
151
157
|
|
|
152
|
-
global.kuzzle.log.info(`[SECURITY]
|
|
158
|
+
global.kuzzle.log.info(`[SECURITY] ${SecurityController.userOrSdk(creatorId)} applied action "${request.input.action}" on user "${userId}."`);
|
|
153
159
|
return apiKey.serialize({ includeToken: true });
|
|
154
160
|
}
|
|
155
161
|
|
|
@@ -371,7 +377,7 @@ class SecurityController extends NativeController {
|
|
|
371
377
|
userId,
|
|
372
378
|
});
|
|
373
379
|
|
|
374
|
-
global.kuzzle.log.info(`[SECURITY]
|
|
380
|
+
global.kuzzle.log.info(`[SECURITY] ${SecurityController.userOrSdk(userId)} applied action "${request.input.action}" on role "${role._id}."`);
|
|
375
381
|
return formatProcessing.serializeRole(role);
|
|
376
382
|
}
|
|
377
383
|
|
|
@@ -392,7 +398,7 @@ class SecurityController extends NativeController {
|
|
|
392
398
|
userId,
|
|
393
399
|
});
|
|
394
400
|
|
|
395
|
-
global.kuzzle.log.info(`[SECURITY]
|
|
401
|
+
global.kuzzle.log.info(`[SECURITY] ${SecurityController.userOrSdk(userId)} applied action "${request.input.action}" on role "${role._id}."`);
|
|
396
402
|
return formatProcessing.serializeRole(role);
|
|
397
403
|
}
|
|
398
404
|
|
|
@@ -409,7 +415,7 @@ class SecurityController extends NativeController {
|
|
|
409
415
|
refresh: request.getRefresh('wait_for')
|
|
410
416
|
});
|
|
411
417
|
|
|
412
|
-
global.kuzzle.log.info(`[SECURITY]
|
|
418
|
+
global.kuzzle.log.info(`[SECURITY] ${SecurityController.userOrSdk(request.getKuid())} applied action "${request.input.action} on role "${id}."`);
|
|
413
419
|
|
|
414
420
|
// @todo This avoids a breaking change... but we should really return
|
|
415
421
|
// an acknowledgment.
|
|
@@ -472,7 +478,7 @@ class SecurityController extends NativeController {
|
|
|
472
478
|
userId,
|
|
473
479
|
});
|
|
474
480
|
|
|
475
|
-
global.kuzzle.log.info(`[SECURITY]
|
|
481
|
+
global.kuzzle.log.info(`[SECURITY] ${SecurityController.userOrSdk(userId)} applied action "${request.input.action}" on profile "${profile._id}."`);
|
|
476
482
|
|
|
477
483
|
return formatProcessing.serializeProfile(profile);
|
|
478
484
|
}
|
|
@@ -501,7 +507,7 @@ class SecurityController extends NativeController {
|
|
|
501
507
|
userId,
|
|
502
508
|
});
|
|
503
509
|
|
|
504
|
-
global.kuzzle.log.info(`[SECURITY]
|
|
510
|
+
global.kuzzle.log.info(`[SECURITY] ${SecurityController.userOrSdk(userId)} applied action "${request.input.action}" on profile "${profile._id}."`);
|
|
505
511
|
|
|
506
512
|
return formatProcessing.serializeProfile(profile);
|
|
507
513
|
}
|
|
@@ -522,7 +528,7 @@ class SecurityController extends NativeController {
|
|
|
522
528
|
|
|
523
529
|
await this.ask('core:security:profile:delete', id, options);
|
|
524
530
|
|
|
525
|
-
global.kuzzle.log.info(`[SECURITY]
|
|
531
|
+
global.kuzzle.log.info(`[SECURITY] ${SecurityController.userOrSdk(userId)} applied action "${request.input.action}" on profile "${id}."`);
|
|
526
532
|
|
|
527
533
|
// @todo - replace by an acknowledgement
|
|
528
534
|
return { _id: id };
|
|
@@ -602,7 +608,8 @@ class SecurityController extends NativeController {
|
|
|
602
608
|
ids = request.getBodyArray('ids');
|
|
603
609
|
}
|
|
604
610
|
else {
|
|
605
|
-
|
|
611
|
+
// @deprecated Should be replaced with request.getArray('ids')
|
|
612
|
+
ids = request.getArrayLegacy('ids');
|
|
606
613
|
}
|
|
607
614
|
|
|
608
615
|
const users = await this.ask('core:security:user:mGet', ids);
|
|
@@ -757,7 +764,7 @@ class SecurityController extends NativeController {
|
|
|
757
764
|
|
|
758
765
|
await this.ask('core:security:user:delete', id, options);
|
|
759
766
|
|
|
760
|
-
global.kuzzle.log.info(`[SECURITY]
|
|
767
|
+
global.kuzzle.log.info(`[SECURITY] ${SecurityController.userOrSdk(request.getKuid())} applied action "${request.input.action}" on user "${id}."`);
|
|
761
768
|
|
|
762
769
|
return { _id: id };
|
|
763
770
|
}
|
|
@@ -770,17 +777,9 @@ class SecurityController extends NativeController {
|
|
|
770
777
|
*/
|
|
771
778
|
async createUser (request) {
|
|
772
779
|
const content = request.getBodyObject('content');
|
|
773
|
-
const profileIds =
|
|
780
|
+
const profileIds = request.getBodyArray('content.profileIds');
|
|
774
781
|
const humanReadableId = request.getString('kuid', 'human') !== 'uuid';
|
|
775
782
|
|
|
776
|
-
if (profileIds === undefined) {
|
|
777
|
-
throw kerror.get('api', 'assert', 'missing_argument', 'body.content.profileIds');
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
if (! Array.isArray(profileIds)) {
|
|
781
|
-
throw kerror.get('api', 'assert', 'invalid_type', 'body.content.profileIds', 'array');
|
|
782
|
-
}
|
|
783
|
-
|
|
784
783
|
return this._persistUser(request, profileIds, content, { humanReadableId });
|
|
785
784
|
}
|
|
786
785
|
|
|
@@ -819,20 +818,38 @@ class SecurityController extends NativeController {
|
|
|
819
818
|
? null
|
|
820
819
|
: request.getBodyArray('profileIds');
|
|
821
820
|
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
id,
|
|
825
|
-
profileIds,
|
|
826
|
-
content,
|
|
827
|
-
{
|
|
828
|
-
refresh: request.getRefresh('wait_for'),
|
|
829
|
-
retryOnConflict: request.getInteger('retryOnConflict', 10),
|
|
830
|
-
userId,
|
|
831
|
-
});
|
|
821
|
+
return this._changeUser(request, id, content, userId, profileIds);
|
|
822
|
+
}
|
|
832
823
|
|
|
833
|
-
|
|
824
|
+
/**
|
|
825
|
+
* Applies a partial update to an existing user.
|
|
826
|
+
* If the user doesn't already exist, a new user is created.
|
|
827
|
+
*
|
|
828
|
+
* @param {Request} request
|
|
829
|
+
* @returns {Promise}
|
|
830
|
+
*/
|
|
831
|
+
async upsertUser (request) {
|
|
832
|
+
const id = request.getId();
|
|
833
|
+
const content = request.getBodyObject('content');
|
|
834
|
+
const userId = request.getKuid();
|
|
835
|
+
const profileIds = request.getBodyArray('content.profileIds');
|
|
836
|
+
const defaultValues = request.getBodyObject('default', {});
|
|
834
837
|
|
|
835
|
-
|
|
838
|
+
try {
|
|
839
|
+
return await this._changeUser(request, id, content, userId, profileIds);
|
|
840
|
+
}
|
|
841
|
+
catch (error) {
|
|
842
|
+
if (error.id && error.id === 'security.user.not_found') {
|
|
843
|
+
const creatingContent = {
|
|
844
|
+
...defaultValues,
|
|
845
|
+
...content, // Order important, content erase default duplicates
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
return this._persistUser(request, profileIds, creatingContent);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
throw error;
|
|
852
|
+
}
|
|
836
853
|
}
|
|
837
854
|
|
|
838
855
|
/**
|
|
@@ -854,7 +871,7 @@ class SecurityController extends NativeController {
|
|
|
854
871
|
content,
|
|
855
872
|
{ refresh: request.getRefresh('wait_for'), userId });
|
|
856
873
|
|
|
857
|
-
global.kuzzle.log.info(`[SECURITY]
|
|
874
|
+
global.kuzzle.log.info(`[SECURITY] ${SecurityController.userOrSdk(userId)} applied action "${request.input.action}" on user "${id}."`);
|
|
858
875
|
|
|
859
876
|
return formatProcessing.serializeUser(user);
|
|
860
877
|
}
|
|
@@ -877,7 +894,7 @@ class SecurityController extends NativeController {
|
|
|
877
894
|
userId,
|
|
878
895
|
});
|
|
879
896
|
|
|
880
|
-
global.kuzzle.log.info(`[SECURITY]
|
|
897
|
+
global.kuzzle.log.info(`[SECURITY] ${SecurityController.userOrSdk(userId)} applied action "${request.input.action}" on profile "${id}."`);
|
|
881
898
|
return formatProcessing.serializeProfile(updated);
|
|
882
899
|
}
|
|
883
900
|
|
|
@@ -899,7 +916,7 @@ class SecurityController extends NativeController {
|
|
|
899
916
|
userId,
|
|
900
917
|
});
|
|
901
918
|
|
|
902
|
-
global.kuzzle.log.info(`[SECURITY]
|
|
919
|
+
global.kuzzle.log.info(`[SECURITY] ${SecurityController.userOrSdk(userId)} applied action "${request.input.action}" on role "${id}."`);
|
|
903
920
|
|
|
904
921
|
return formatProcessing.serializeRole(updated);
|
|
905
922
|
}
|
|
@@ -940,7 +957,7 @@ class SecurityController extends NativeController {
|
|
|
940
957
|
}
|
|
941
958
|
}
|
|
942
959
|
|
|
943
|
-
global.kuzzle.log.info(`[SECURITY]
|
|
960
|
+
global.kuzzle.log.info(`[SECURITY] ${SecurityController.userOrSdk(userId)} applied action "${request.input.action}".`);
|
|
944
961
|
|
|
945
962
|
return user;
|
|
946
963
|
}
|
|
@@ -1029,7 +1046,7 @@ class SecurityController extends NativeController {
|
|
|
1029
1046
|
|
|
1030
1047
|
const createMethod = this.getStrategyMethod(strategy, 'create');
|
|
1031
1048
|
|
|
1032
|
-
global.kuzzle.log.info(`[SECURITY]
|
|
1049
|
+
global.kuzzle.log.info(`[SECURITY] ${SecurityController.userOrSdk(request.getKuid())} applied action "${request.input.action}" on user "${id}."`);
|
|
1033
1050
|
return createMethod(request, body, id, strategy);
|
|
1034
1051
|
}
|
|
1035
1052
|
|
|
@@ -1053,7 +1070,7 @@ class SecurityController extends NativeController {
|
|
|
1053
1070
|
|
|
1054
1071
|
const updateMethod = this.getStrategyMethod(strategy, 'update');
|
|
1055
1072
|
|
|
1056
|
-
global.kuzzle.log.info(`[SECURITY]
|
|
1073
|
+
global.kuzzle.log.info(`[SECURITY] ${SecurityController.userOrSdk(request.getKuid())} applied action "${request.input.action}" on user "${id}."`);
|
|
1057
1074
|
|
|
1058
1075
|
return updateMethod(request, body, id, strategy);
|
|
1059
1076
|
}
|
|
@@ -1106,7 +1123,7 @@ class SecurityController extends NativeController {
|
|
|
1106
1123
|
|
|
1107
1124
|
await deleteMethod(request, id, strategy);
|
|
1108
1125
|
|
|
1109
|
-
global.kuzzle.log.info(`[SECURITY]
|
|
1126
|
+
global.kuzzle.log.info(`[SECURITY] ${SecurityController.userOrSdk(request.getKuid())} applied action "${request.input.action}" on user "${id}."`);
|
|
1110
1127
|
|
|
1111
1128
|
return { acknowledged: true };
|
|
1112
1129
|
}
|
|
@@ -1217,15 +1234,36 @@ class SecurityController extends NativeController {
|
|
|
1217
1234
|
}
|
|
1218
1235
|
|
|
1219
1236
|
if (successes.length > 1000) {
|
|
1220
|
-
global.kuzzle.log.info(`[SECURITY]
|
|
1237
|
+
global.kuzzle.log.info(`[SECURITY] ${SecurityController.userOrSdk(request.getKuid())} deleted the following ${type}s: ${successes.slice(0, 1000).join(', ')}... (${successes.length - 1000} more users deleted)."`);
|
|
1221
1238
|
}
|
|
1222
1239
|
else {
|
|
1223
|
-
global.kuzzle.log.info(`[SECURITY]
|
|
1240
|
+
global.kuzzle.log.info(`[SECURITY] ${SecurityController.userOrSdk(request.getKuid())} deleted the following ${type}s: ${successes.join(', ')}."`);
|
|
1224
1241
|
}
|
|
1225
1242
|
|
|
1226
1243
|
return successes;
|
|
1227
1244
|
}
|
|
1228
1245
|
|
|
1246
|
+
/**
|
|
1247
|
+
* @returns {Promise}
|
|
1248
|
+
* @private
|
|
1249
|
+
*/
|
|
1250
|
+
async _changeUser (request, id, content, userId, profileIds) {
|
|
1251
|
+
const updated = await this.ask(
|
|
1252
|
+
'core:security:user:update',
|
|
1253
|
+
id,
|
|
1254
|
+
profileIds,
|
|
1255
|
+
content,
|
|
1256
|
+
{
|
|
1257
|
+
refresh: request.getRefresh('wait_for'),
|
|
1258
|
+
retryOnConflict: request.getInteger('retryOnConflict', 10),
|
|
1259
|
+
userId,
|
|
1260
|
+
});
|
|
1261
|
+
|
|
1262
|
+
global.kuzzle.log.info(`[SECURITY] ${SecurityController.userOrSdk(userId)} applied action "${request.input.action}" on user "${id}."`);
|
|
1263
|
+
|
|
1264
|
+
return formatProcessing.serializeUser(updated);
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1229
1267
|
/**
|
|
1230
1268
|
* @param {Request} request
|
|
1231
1269
|
* @returns {Promise}
|
|
@@ -1235,7 +1273,7 @@ class SecurityController extends NativeController {
|
|
|
1235
1273
|
const credentials = request.getBodyObject('credentials', {});
|
|
1236
1274
|
const strategies = Object.keys(credentials);
|
|
1237
1275
|
const generator = humanReadableId
|
|
1238
|
-
? () => generateRandomName('kuid')
|
|
1276
|
+
? () => NameGenerator.generateRandomName({ prefix: 'kuid' })
|
|
1239
1277
|
: () => 'kuid-' + uuidv4();
|
|
1240
1278
|
|
|
1241
1279
|
let id = '';
|
|
@@ -1315,7 +1353,7 @@ class SecurityController extends NativeController {
|
|
|
1315
1353
|
}
|
|
1316
1354
|
|
|
1317
1355
|
if (creationFailure === null) {
|
|
1318
|
-
global.kuzzle.log.info(`[SECURITY]
|
|
1356
|
+
global.kuzzle.log.info(`[SECURITY] ${SecurityController.userOrSdk(request.getKuid())} applied action "${request.input.action}" on user "${id}."`);
|
|
1319
1357
|
return createdUser;
|
|
1320
1358
|
}
|
|
1321
1359
|
|
|
@@ -188,7 +188,8 @@ class ServerController extends NativeController {
|
|
|
188
188
|
|
|
189
189
|
let services;
|
|
190
190
|
if (typeof request.input.args.services === 'string') {
|
|
191
|
-
|
|
191
|
+
// @deprecated Should be replaced with request.getArray('services')
|
|
192
|
+
services = request.getArrayLegacy('services');
|
|
192
193
|
}
|
|
193
194
|
if (! services || services.includes('internalCache')) {
|
|
194
195
|
try {
|
|
@@ -26,6 +26,27 @@ const kerror = require('../kerror');
|
|
|
26
26
|
const assertionError = kerror.wrap('api', 'assert');
|
|
27
27
|
|
|
28
28
|
const extractors = ([
|
|
29
|
+
{
|
|
30
|
+
methods: {
|
|
31
|
+
extractFromRequest: request => [
|
|
32
|
+
{
|
|
33
|
+
_id: request.input.args._id,
|
|
34
|
+
_source: request.input.body.fields,
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
extractFromResult: request => [request.result],
|
|
38
|
+
insertInRequest: ([documents], request) => {
|
|
39
|
+
request.input.args._id = documents._id;
|
|
40
|
+
request.input.body.fields = documents._source;
|
|
41
|
+
return request;
|
|
42
|
+
},
|
|
43
|
+
insertInResult: ([document], request) => {
|
|
44
|
+
request.setResult(document, { status: request.status });
|
|
45
|
+
return request;
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
targets: [ 'deleteFields' ]
|
|
49
|
+
},
|
|
29
50
|
{
|
|
30
51
|
methods: {
|
|
31
52
|
extractFromRequest: request => [{ _id: request.input.args._id }],
|
|
@@ -39,7 +60,7 @@ const extractors = ([
|
|
|
39
60
|
return request;
|
|
40
61
|
}
|
|
41
62
|
},
|
|
42
|
-
targets: ['delete', 'get']
|
|
63
|
+
targets: [ 'delete', 'get', 'exists' ]
|
|
43
64
|
},
|
|
44
65
|
{
|
|
45
66
|
methods: {
|
|
@@ -56,7 +77,8 @@ const extractors = ([
|
|
|
56
77
|
ids = request.input.args.ids;
|
|
57
78
|
}
|
|
58
79
|
else if (typeof request.input.args.ids === 'string') {
|
|
59
|
-
|
|
80
|
+
// @deprecated Should be replaced with request.getArray('ids')
|
|
81
|
+
ids = request.getArrayLegacy('ids');
|
|
60
82
|
}
|
|
61
83
|
else {
|
|
62
84
|
throw assertionError.get(
|
|
@@ -117,7 +139,7 @@ const extractors = ([
|
|
|
117
139
|
return request;
|
|
118
140
|
}
|
|
119
141
|
},
|
|
120
|
-
targets: ['mDelete', 'mGet']
|
|
142
|
+
targets: [ 'mDelete', 'mGet', 'mExists' ]
|
|
121
143
|
},
|
|
122
144
|
{
|
|
123
145
|
methods: {
|
|
@@ -127,21 +149,41 @@ const extractors = ([
|
|
|
127
149
|
for (let it = 0; it < request.input.body.documents.length; it++) {
|
|
128
150
|
const document = request.input.body.documents[it];
|
|
129
151
|
|
|
130
|
-
|
|
152
|
+
if (request.input.action === 'mUpsert') {
|
|
153
|
+
documents.push({
|
|
154
|
+
_id: document._id,
|
|
155
|
+
_source: document.changes,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
documents.push({ _id: document._id, _source: document.body });
|
|
160
|
+
}
|
|
131
161
|
}
|
|
132
162
|
|
|
133
163
|
return documents;
|
|
134
164
|
},
|
|
135
165
|
extractFromResult: request => request.result.successes,
|
|
136
166
|
insertInRequest: (documents, request) => {
|
|
167
|
+
const tmpDocuments = request.input.body.documents;
|
|
168
|
+
|
|
137
169
|
request.input.body.documents = [];
|
|
138
170
|
|
|
139
171
|
for (let it = 0; it < documents.length; it++) {
|
|
140
172
|
const document = documents[it];
|
|
141
173
|
|
|
142
|
-
request.input.
|
|
143
|
-
|
|
144
|
-
|
|
174
|
+
if (request.input.action === 'mUpsert') {
|
|
175
|
+
request.input.body.documents.push({
|
|
176
|
+
_id: document._id,
|
|
177
|
+
changes: document._source,
|
|
178
|
+
default: tmpDocuments[it].default,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
request.input.body.documents.push({
|
|
183
|
+
_id: document._id,
|
|
184
|
+
body: document._source,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
145
187
|
}
|
|
146
188
|
|
|
147
189
|
return request;
|
|
@@ -157,7 +199,7 @@ const extractors = ([
|
|
|
157
199
|
return request;
|
|
158
200
|
}
|
|
159
201
|
},
|
|
160
|
-
targets: ['mCreate', 'mCreateOrReplace', 'mReplace', 'mUpdate', 'updateByQuery']
|
|
202
|
+
targets: [ 'mCreate', 'mCreateOrReplace', 'mReplace', 'mUpdate', 'updateByQuery', 'mUpsert' ]
|
|
161
203
|
},
|
|
162
204
|
{
|
|
163
205
|
methods: {
|
|
@@ -177,7 +219,7 @@ const extractors = ([
|
|
|
177
219
|
return request;
|
|
178
220
|
},
|
|
179
221
|
},
|
|
180
|
-
targets: ['search', 'deleteByQuery'],
|
|
222
|
+
targets: [ 'search', 'deleteByQuery', 'export' ],
|
|
181
223
|
},
|
|
182
224
|
{
|
|
183
225
|
methods: {
|
package/lib/api/funnel.js
CHANGED
|
@@ -33,6 +33,7 @@ const {
|
|
|
33
33
|
BulkController,
|
|
34
34
|
ClusterController,
|
|
35
35
|
CollectionController,
|
|
36
|
+
DebugController,
|
|
36
37
|
DocumentController,
|
|
37
38
|
IndexController,
|
|
38
39
|
MemoryStorageController,
|
|
@@ -40,7 +41,7 @@ const {
|
|
|
40
41
|
SecurityController,
|
|
41
42
|
ServerController,
|
|
42
43
|
} = require('./controllers');
|
|
43
|
-
const documentEventAliases = require('../config/documentEventAliases');
|
|
44
|
+
const { documentEventAliases } = require('../config/documentEventAliases');
|
|
44
45
|
const DocumentExtractor = require('./documentExtractor');
|
|
45
46
|
const sdkCompatibility = require('../config/sdkCompatibility');
|
|
46
47
|
const RateLimiter = require('./rateLimiter');
|
|
@@ -115,6 +116,7 @@ class Funnel {
|
|
|
115
116
|
this.controllers.set('bulk', new BulkController());
|
|
116
117
|
this.controllers.set('cluster', new ClusterController());
|
|
117
118
|
this.controllers.set('collection', new CollectionController());
|
|
119
|
+
this.controllers.set('debug', new DebugController());
|
|
118
120
|
this.controllers.set('document', new DocumentController());
|
|
119
121
|
this.controllers.set('index', new IndexController());
|
|
120
122
|
this.controllers.set('realtime', new RealtimeController());
|
|
@@ -344,19 +346,39 @@ class Funnel {
|
|
|
344
346
|
modifiedRequest.id,
|
|
345
347
|
processResult);
|
|
346
348
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
349
|
+
return global.kuzzle.pipe(
|
|
350
|
+
'request:afterExecution',
|
|
351
|
+
{
|
|
352
|
+
request: _request,
|
|
353
|
+
result: processResult,
|
|
354
|
+
success: true,
|
|
355
|
+
})
|
|
356
|
+
.then(pipeEvent => {
|
|
357
|
+
callback(null, pipeEvent.result);
|
|
358
|
+
|
|
359
|
+
// disables a bluebird warning in dev. mode triggered when
|
|
360
|
+
// a promise is created and not returned
|
|
361
|
+
return null;
|
|
362
|
+
});
|
|
352
363
|
}).catch(err => {
|
|
353
364
|
debug('Error processing request %s: %a', modifiedRequest.id, err);
|
|
354
|
-
return
|
|
365
|
+
return global.kuzzle.pipe(
|
|
366
|
+
'request:afterExecution',
|
|
367
|
+
{
|
|
368
|
+
error: err,
|
|
369
|
+
request: modifiedRequest,
|
|
370
|
+
success: false,
|
|
371
|
+
}).then(pipeEvent => this._executeError(pipeEvent.error, pipeEvent.request, true, callback));
|
|
355
372
|
});
|
|
356
373
|
})
|
|
357
374
|
.catch(err => {
|
|
358
375
|
debug('Error processing request %s: %a', req.id, err);
|
|
359
|
-
return
|
|
376
|
+
return global.kuzzle.pipe('request:afterExecution',
|
|
377
|
+
{
|
|
378
|
+
error: err,
|
|
379
|
+
request: req,
|
|
380
|
+
success: false,
|
|
381
|
+
}).then(pipeEvent => this._executeError(pipeEvent.error, pipeEvent.request, true, callback));
|
|
360
382
|
});
|
|
361
383
|
});
|
|
362
384
|
}, this, request);
|
package/lib/api/httpRoutes.js
CHANGED
|
@@ -35,10 +35,10 @@ const {
|
|
|
35
35
|
OpenApiDocumentCreate,
|
|
36
36
|
OpenApiDocumentCreateOrReplace,
|
|
37
37
|
OpenApiDocumentValidate,
|
|
38
|
+
OpenApiSecurityUpsertUser,
|
|
38
39
|
OpenApiDocumentmCreateOrReplace,
|
|
39
40
|
} = require('./openapi/components');
|
|
40
41
|
|
|
41
|
-
|
|
42
42
|
const routes = [
|
|
43
43
|
// GET (idempotent)
|
|
44
44
|
{ verb: 'get', path: '/_me', controller: 'auth', action: 'getCurrentUser' },
|
|
@@ -52,6 +52,12 @@ const routes = [
|
|
|
52
52
|
{ verb: 'get', path: '/credentials/:strategy/_me', controller: 'auth', action: 'getMyCredentials', deprecated: { since: '2.4.0', message: 'Use this route instead: http://kuzzle:7512/_me/credentials/:strategy' } }, // @deprecated
|
|
53
53
|
{ verb: 'get', path: '/credentials/:strategy/_me/_exists', controller: 'auth', action: 'credentialsExist', deprecated: { since: '2.4.0', message: 'Use this route instead: http://kuzzle:7512/_me/credentials/:strategy/_exists' } }, // @deprecated
|
|
54
54
|
|
|
55
|
+
{ verb: 'get', path: '/debug/_nodeVersion', controller: 'debug', action: 'nodeVersion' },
|
|
56
|
+
{ verb: 'post', path: '/debug/_post', controller: 'debug', action: 'post' },
|
|
57
|
+
{ verb: 'post', path: '/debug/_enable', controller: 'debug', action: 'enable' },
|
|
58
|
+
{ verb: 'post', path: '/debug/_disable', controller: 'debug', action: 'disable' },
|
|
59
|
+
|
|
60
|
+
|
|
55
61
|
// We need to expose a GET method for "login" action in order to make authentication protocol like Oauth2 or CAS work:
|
|
56
62
|
{ verb: 'get', path: '/_login/:strategy', controller: 'auth', action: 'login' },
|
|
57
63
|
|
|
@@ -235,6 +241,7 @@ const routes = [
|
|
|
235
241
|
{ verb: 'post', path: '/roles/_search', controller: 'security', action: 'searchRoles' },
|
|
236
242
|
{ verb: 'post', path: '/users/_search', controller: 'security', action: 'searchUsers' },
|
|
237
243
|
{ verb: 'post', path: '/credentials/:strategy/users/_search', controller: 'security', action: 'searchUsersByCredentials' },
|
|
244
|
+
{ verb: 'post', path: '/users/:_id/_upsert', controller: 'security', action: 'upsertUser', openapi: OpenApiSecurityUpsertUser },
|
|
238
245
|
{ verb: 'post', path: '/credentials/:strategy/:_id/_validate', controller: 'security', action: 'validateCredentials' },
|
|
239
246
|
{ verb: 'post', path: '/_checkRights', controller: 'auth', action: 'checkRights' },
|
|
240
247
|
{ verb: 'post', path: '/_checkRights/:userId', controller: 'security', action: 'checkRights' },
|
|
@@ -79,6 +79,9 @@ class OpenApiManager {
|
|
|
79
79
|
...components_1.OpenApiDocumentCreateOrReplaceComponent,
|
|
80
80
|
...components_1.OpenApiDocumentCreateComponent,
|
|
81
81
|
...components_1.OpenApiDocumentValidateComponent,
|
|
82
|
+
},
|
|
83
|
+
security: {
|
|
84
|
+
...components_1.OpenApiSecurityUpsertUserComponent,
|
|
82
85
|
...components_1.OpenApiDocumentmCreateOrReplaceComponent,
|
|
83
86
|
}
|
|
84
87
|
}
|
|
@@ -17,6 +17,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
exports.OpenApiPayloadsDefinitions = void 0;
|
|
18
18
|
const readYamlFile_1 = require("../../../util/readYamlFile");
|
|
19
19
|
__exportStar(require("./document"), exports);
|
|
20
|
+
__exportStar(require("./security"), exports);
|
|
20
21
|
// Document definitions (reusable object for KuzzleRequest and KuzzleResponse)
|
|
21
22
|
exports.OpenApiPayloadsDefinitions = (0, readYamlFile_1.readYamlFile)(__dirname + '/payloads.yaml').definitions;
|
|
22
23
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OpenApiSecurityUpsertUserComponent = exports.OpenApiSecurityUpsertUser = void 0;
|
|
4
|
+
const readYamlFile_1 = require("../../../../util/readYamlFile");
|
|
5
|
+
// reading the description of the UpsertUser action in the controller security.
|
|
6
|
+
// The yaml objects are then stored in the variables below
|
|
7
|
+
const upsertUserObject = (0, readYamlFile_1.readYamlFile)(__dirname + '/upsertUser.yaml');
|
|
8
|
+
exports.OpenApiSecurityUpsertUser = upsertUserObject.SecurityUpsertUser;
|
|
9
|
+
exports.OpenApiSecurityUpsertUserComponent = upsertUserObject.components.schemas;
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
SecurityUpsertUser:
|
|
2
|
+
summary: "Update or create a user."
|
|
3
|
+
tags:
|
|
4
|
+
- user
|
|
5
|
+
parameters:
|
|
6
|
+
- in: path
|
|
7
|
+
name: _id
|
|
8
|
+
schema:
|
|
9
|
+
type: string
|
|
10
|
+
required: true
|
|
11
|
+
- in: path
|
|
12
|
+
name: refresh
|
|
13
|
+
schema:
|
|
14
|
+
type: string
|
|
15
|
+
description: " if set to wait_for, Kuzzle will not respond until the deletion has been indexed"
|
|
16
|
+
required: false
|
|
17
|
+
- in: path
|
|
18
|
+
name: retryOnConflict
|
|
19
|
+
schema:
|
|
20
|
+
type: integer
|
|
21
|
+
description: "conflicts may occur if the same user gets updated multiple times within a short timespan, in a database cluster. You can set the retryOnConflict optional argument (with a retry count), to tell Kuzzle to retry the failing updates the specified amount of times before rejecting the request with an error."
|
|
22
|
+
required: false
|
|
23
|
+
- name: content
|
|
24
|
+
in: "body"
|
|
25
|
+
description: "Updates a user content."
|
|
26
|
+
required: true
|
|
27
|
+
schema:
|
|
28
|
+
$ref: "#/components/security/SecurityUpsertUserRequest"
|
|
29
|
+
responses:
|
|
30
|
+
200:
|
|
31
|
+
description: "Updates or creates a user."
|
|
32
|
+
schema:
|
|
33
|
+
$ref: "#/components/security/SecurityUpsertUserResponse"
|
|
34
|
+
|
|
35
|
+
components:
|
|
36
|
+
schemas:
|
|
37
|
+
SecurityUpsertUserRequest:
|
|
38
|
+
allOf:
|
|
39
|
+
- type: "object"
|
|
40
|
+
description: "user changes"
|
|
41
|
+
SecurityUpsertUserResponse:
|
|
42
|
+
allOf:
|
|
43
|
+
- $ref: "#/components/ResponsePayload"
|
|
44
|
+
- type: "object"
|
|
45
|
+
properties:
|
|
46
|
+
result:
|
|
47
|
+
type: "object"
|
|
48
|
+
properties:
|
|
49
|
+
_id:
|
|
50
|
+
type: "string"
|
|
51
|
+
description: "userId"
|
|
52
|
+
_version:
|
|
53
|
+
type: "integer"
|
|
54
|
+
_source:
|
|
55
|
+
type: "object"
|
|
56
|
+
description: " (optional) actualized user content. This property appears only if the \"source\" option is set to true"
|
|
57
|
+
created:
|
|
58
|
+
type: "boolean"
|
|
59
|
+
|