@friggframework/core 2.0.0--canary.393.f4a61c1.0 → 2.0.0--canary.395.d07514c.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/handlers/app-handler-helpers.js +0 -3
- package/handlers/backend-utils.js +34 -16
- package/handlers/routers/auth.js +18 -9
- package/handlers/routers/integration-defined-routers.js +7 -2
- package/handlers/routers/user.js +25 -5
- package/handlers/workers/integration-defined-workers.js +5 -1
- package/index.js +0 -2
- package/integrations/index.js +0 -2
- package/integrations/integration-factory.js +5 -6
- package/integrations/integration-router.js +133 -43
- package/module-plugin/auther.js +3 -2
- package/module-plugin/test/mock-api/api.js +8 -3
- package/module-plugin/test/mock-api/definition.js +12 -8
- package/package.json +5 -5
- package/user/tests/doubles/test-user-repository.js +115 -0
- package/user/tests/use-cases/create-individual-user.test.js +24 -0
- package/user/tests/use-cases/create-organization-user.test.js +28 -0
- package/user/tests/use-cases/create-token-for-user-id.test.js +19 -0
- package/user/tests/use-cases/get-user-from-bearer-token.test.js +64 -0
- package/user/tests/use-cases/login-user.test.js +148 -0
- package/user/use-cases/create-individual-user.js +52 -0
- package/user/use-cases/create-organization-user.js +39 -0
- package/user/use-cases/create-token-for-user-id.js +30 -0
- package/user/use-cases/get-user-from-bearer-token.js +50 -0
- package/user/use-cases/login-user.js +88 -0
- package/user/user-repository.js +97 -0
- package/user/user.js +77 -0
- package/handlers/routers/middleware/loadUser.js +0 -15
- package/handlers/routers/middleware/requireLoggedInUser.js +0 -12
- package/integrations/create-frigg-backend.js +0 -31
- package/integrations/integration-user.js +0 -144
|
@@ -3,22 +3,29 @@ const { get } = require('../assertions');
|
|
|
3
3
|
const Boom = require('@hapi/boom');
|
|
4
4
|
const catchAsyncError = require('express-async-handler');
|
|
5
5
|
const { debug } = require('../logs');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
// todo: dont send moduleFactory, integrationFactory, and IntegrationHelper as a factory object, instead send them as separate
|
|
9
|
+
// params and import IntegrationHelper where needed.
|
|
10
|
+
// todo: this could be a use case class
|
|
11
|
+
/**
|
|
12
|
+
* Creates an Express router with integration and entity routes configured
|
|
13
|
+
* @param {Object} params - Configuration parameters for the router
|
|
14
|
+
* @param {express.Router} [params.router] - Optional Express router instance, creates new one if not provided
|
|
15
|
+
* @param {Object} params.factory - Factory object containing moduleFactory, integrationFactory, and IntegrationHelper
|
|
16
|
+
* @param {Object} params.factory.moduleFactory - Factory for creating and managing API modules
|
|
17
|
+
* @param {Object} params.factory.integrationFactory - Factory for creating and managing integrations
|
|
18
|
+
* @param {Object} params.factory.IntegrationHelper - Helper utilities for integration operations
|
|
19
|
+
* @param {import('../user/use-cases/get-user-from-bearer-token').GetUserFromBearerToken} params.getUserFromBearerToken - Use case for retrieving a user from a bearer token
|
|
20
|
+
* @returns {express.Router} Configured Express router with integration and entity routes
|
|
21
|
+
*/
|
|
6
22
|
function createIntegrationRouter(params) {
|
|
7
23
|
const router = get(params, 'router', express());
|
|
8
24
|
const factory = get(params, 'factory');
|
|
9
|
-
const
|
|
10
|
-
const requireLoggedInUser = get(
|
|
11
|
-
params,
|
|
12
|
-
'requireLoggedInUser',
|
|
13
|
-
(req, res, next) => next()
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
router.all('/api/entities*', requireLoggedInUser);
|
|
17
|
-
router.all('/api/authorize', requireLoggedInUser);
|
|
18
|
-
router.all('/api/integrations*', requireLoggedInUser);
|
|
25
|
+
const getUserFromBearerToken = get(params, 'getUserFromBearerToken');
|
|
19
26
|
|
|
20
|
-
setIntegrationRoutes(router, factory,
|
|
21
|
-
setEntityRoutes(router, factory,
|
|
27
|
+
setIntegrationRoutes(router, factory, getUserFromBearerToken);
|
|
28
|
+
setEntityRoutes(router, factory, getUserFromBearerToken);
|
|
22
29
|
return router;
|
|
23
30
|
}
|
|
24
31
|
|
|
@@ -36,33 +43,42 @@ function checkRequiredParams(params, requiredKeys) {
|
|
|
36
43
|
|
|
37
44
|
if (missingKeys.length > 0) {
|
|
38
45
|
throw Boom.badRequest(
|
|
39
|
-
`Missing Parameter${
|
|
40
|
-
|
|
41
|
-
}: ${missingKeys.join(', ')} ${
|
|
42
|
-
missingKeys.length === 1 ? 'is' : 'are'
|
|
46
|
+
`Missing Parameter${missingKeys.length === 1 ? '' : 's'
|
|
47
|
+
}: ${missingKeys.join(', ')} ${missingKeys.length === 1 ? 'is' : 'are'
|
|
43
48
|
} required.`
|
|
44
49
|
);
|
|
45
50
|
}
|
|
46
51
|
return returnDict;
|
|
47
52
|
}
|
|
48
53
|
|
|
49
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Sets up integration-related routes on the provided Express router
|
|
56
|
+
* @param {express.Router} router - Express router instance to add routes to
|
|
57
|
+
* @param {Object} factory - Factory object containing moduleFactory, integrationFactory, and IntegrationHelper
|
|
58
|
+
* @param {Object} factory.moduleFactory - Factory for creating and managing API modules
|
|
59
|
+
* @param {Object} factory.integrationFactory - Factory for creating and managing integrations
|
|
60
|
+
* @param {Object} factory.IntegrationHelper - Helper utilities for integration operations
|
|
61
|
+
* @param {import('../user/use-cases/get-user-from-bearer-token').GetUserFromBearerToken} getUserFromBearerToken - Use case for retrieving a user from a bearer token
|
|
62
|
+
*/
|
|
63
|
+
function setIntegrationRoutes(router, factory, getUserFromBearerToken) {
|
|
50
64
|
const { moduleFactory, integrationFactory, IntegrationHelper } = factory;
|
|
51
65
|
router.route('/api/integrations').get(
|
|
52
66
|
catchAsyncError(async (req, res) => {
|
|
67
|
+
const user = await getUserFromBearerToken.execute(
|
|
68
|
+
req.headers.authorization
|
|
69
|
+
);
|
|
70
|
+
const userId = user.getId();
|
|
53
71
|
const results = await integrationFactory.getIntegrationOptions();
|
|
54
72
|
results.entities.authorized =
|
|
55
|
-
await moduleFactory.getEntitiesForUser(
|
|
73
|
+
await moduleFactory.getEntitiesForUser(userId);
|
|
56
74
|
results.integrations =
|
|
57
|
-
await IntegrationHelper.getIntegrationsForUserId(
|
|
58
|
-
getUserId(req)
|
|
59
|
-
);
|
|
75
|
+
await IntegrationHelper.getIntegrationsForUserId(userId);
|
|
60
76
|
|
|
61
77
|
for (const integrationRecord of results.integrations) {
|
|
62
78
|
const integration =
|
|
63
79
|
await integrationFactory.getInstanceFromIntegrationId({
|
|
64
80
|
integrationId: integrationRecord.id,
|
|
65
|
-
userId
|
|
81
|
+
userId,
|
|
66
82
|
});
|
|
67
83
|
integrationRecord.userActions = integration.userActions;
|
|
68
84
|
}
|
|
@@ -72,6 +88,10 @@ function setIntegrationRoutes(router, factory, getUserId) {
|
|
|
72
88
|
|
|
73
89
|
router.route('/api/integrations').post(
|
|
74
90
|
catchAsyncError(async (req, res) => {
|
|
91
|
+
const user = await getUserFromBearerToken.execute(
|
|
92
|
+
req.headers.authorization
|
|
93
|
+
);
|
|
94
|
+
const userId = user.getId();
|
|
75
95
|
const params = checkRequiredParams(req.body, [
|
|
76
96
|
'entities',
|
|
77
97
|
'config',
|
|
@@ -82,7 +102,7 @@ function setIntegrationRoutes(router, factory, getUserId) {
|
|
|
82
102
|
// create integration
|
|
83
103
|
const integration = await integrationFactory.createIntegration(
|
|
84
104
|
params.entities,
|
|
85
|
-
|
|
105
|
+
userId,
|
|
86
106
|
params.config
|
|
87
107
|
);
|
|
88
108
|
|
|
@@ -102,12 +122,16 @@ function setIntegrationRoutes(router, factory, getUserId) {
|
|
|
102
122
|
|
|
103
123
|
router.route('/api/integrations/:integrationId').patch(
|
|
104
124
|
catchAsyncError(async (req, res) => {
|
|
125
|
+
const user = await getUserFromBearerToken.execute(
|
|
126
|
+
req.headers.authorization
|
|
127
|
+
);
|
|
128
|
+
const userId = user.getId();
|
|
105
129
|
const params = checkRequiredParams(req.body, ['config']);
|
|
106
130
|
|
|
107
131
|
const integration =
|
|
108
132
|
await integrationFactory.getInstanceFromIntegrationId({
|
|
109
133
|
integrationId: req.params.integrationId,
|
|
110
|
-
userId
|
|
134
|
+
userId,
|
|
111
135
|
});
|
|
112
136
|
|
|
113
137
|
debug(
|
|
@@ -126,10 +150,14 @@ function setIntegrationRoutes(router, factory, getUserId) {
|
|
|
126
150
|
|
|
127
151
|
router.route('/api/integrations/:integrationId').delete(
|
|
128
152
|
catchAsyncError(async (req, res) => {
|
|
153
|
+
const user = await getUserFromBearerToken.execute(
|
|
154
|
+
req.headers.authorization
|
|
155
|
+
);
|
|
156
|
+
const userId = user.getId();
|
|
129
157
|
const params = checkRequiredParams(req.params, ['integrationId']);
|
|
130
158
|
const integration =
|
|
131
159
|
await integrationFactory.getInstanceFromIntegrationId({
|
|
132
|
-
userId
|
|
160
|
+
userId,
|
|
133
161
|
integrationId: params.integrationId,
|
|
134
162
|
});
|
|
135
163
|
|
|
@@ -138,7 +166,7 @@ function setIntegrationRoutes(router, factory, getUserId) {
|
|
|
138
166
|
);
|
|
139
167
|
await integration.send('ON_DELETE');
|
|
140
168
|
await IntegrationHelper.deleteIntegrationForUserById(
|
|
141
|
-
|
|
169
|
+
userId,
|
|
142
170
|
params.integrationId
|
|
143
171
|
);
|
|
144
172
|
|
|
@@ -148,6 +176,9 @@ function setIntegrationRoutes(router, factory, getUserId) {
|
|
|
148
176
|
|
|
149
177
|
router.route('/api/integrations/:integrationId/config/options').get(
|
|
150
178
|
catchAsyncError(async (req, res) => {
|
|
179
|
+
await getUserFromBearerToken.execute(
|
|
180
|
+
req.headers.authorization
|
|
181
|
+
);
|
|
151
182
|
const params = checkRequiredParams(req.params, ['integrationId']);
|
|
152
183
|
const integration =
|
|
153
184
|
await integrationFactory.getInstanceFromIntegrationId(params);
|
|
@@ -159,6 +190,9 @@ function setIntegrationRoutes(router, factory, getUserId) {
|
|
|
159
190
|
.route('/api/integrations/:integrationId/config/options/refresh')
|
|
160
191
|
.post(
|
|
161
192
|
catchAsyncError(async (req, res) => {
|
|
193
|
+
await getUserFromBearerToken.execute(
|
|
194
|
+
req.headers.authorization
|
|
195
|
+
);
|
|
162
196
|
const params = checkRequiredParams(req.params, [
|
|
163
197
|
'integrationId',
|
|
164
198
|
]);
|
|
@@ -174,6 +208,9 @@ function setIntegrationRoutes(router, factory, getUserId) {
|
|
|
174
208
|
);
|
|
175
209
|
router.route('/api/integrations/:integrationId/actions').all(
|
|
176
210
|
catchAsyncError(async (req, res) => {
|
|
211
|
+
await getUserFromBearerToken.execute(
|
|
212
|
+
req.headers.authorization
|
|
213
|
+
);
|
|
177
214
|
const params = checkRequiredParams(req.params, ['integrationId']);
|
|
178
215
|
const integration =
|
|
179
216
|
await integrationFactory.getInstanceFromIntegrationId(params);
|
|
@@ -185,6 +222,9 @@ function setIntegrationRoutes(router, factory, getUserId) {
|
|
|
185
222
|
.route('/api/integrations/:integrationId/actions/:actionId/options')
|
|
186
223
|
.all(
|
|
187
224
|
catchAsyncError(async (req, res) => {
|
|
225
|
+
await getUserFromBearerToken.execute(
|
|
226
|
+
req.headers.authorization
|
|
227
|
+
);
|
|
188
228
|
const params = checkRequiredParams(req.params, [
|
|
189
229
|
'integrationId',
|
|
190
230
|
'actionId',
|
|
@@ -209,6 +249,9 @@ function setIntegrationRoutes(router, factory, getUserId) {
|
|
|
209
249
|
)
|
|
210
250
|
.post(
|
|
211
251
|
catchAsyncError(async (req, res) => {
|
|
252
|
+
await getUserFromBearerToken.execute(
|
|
253
|
+
req.headers.authorization
|
|
254
|
+
);
|
|
212
255
|
const params = checkRequiredParams(req.params, [
|
|
213
256
|
'integrationId',
|
|
214
257
|
'actionId',
|
|
@@ -229,6 +272,9 @@ function setIntegrationRoutes(router, factory, getUserId) {
|
|
|
229
272
|
|
|
230
273
|
router.route('/api/integrations/:integrationId/actions/:actionId').post(
|
|
231
274
|
catchAsyncError(async (req, res) => {
|
|
275
|
+
await getUserFromBearerToken.execute(
|
|
276
|
+
req.headers.authorization
|
|
277
|
+
);
|
|
232
278
|
const params = checkRequiredParams(req.params, [
|
|
233
279
|
'integrationId',
|
|
234
280
|
'actionId',
|
|
@@ -242,6 +288,9 @@ function setIntegrationRoutes(router, factory, getUserId) {
|
|
|
242
288
|
|
|
243
289
|
router.route('/api/integrations/:integrationId').get(
|
|
244
290
|
catchAsyncError(async (req, res) => {
|
|
291
|
+
await getUserFromBearerToken.execute(
|
|
292
|
+
req.headers.authorization
|
|
293
|
+
);
|
|
245
294
|
const params = checkRequiredParams(req.params, ['integrationId']);
|
|
246
295
|
const integration = await IntegrationHelper.getIntegrationById(
|
|
247
296
|
params.integrationId
|
|
@@ -259,10 +308,14 @@ function setIntegrationRoutes(router, factory, getUserId) {
|
|
|
259
308
|
|
|
260
309
|
router.route('/api/integrations/:integrationId/test-auth').get(
|
|
261
310
|
catchAsyncError(async (req, res) => {
|
|
311
|
+
const user = await getUserFromBearerToken.execute(
|
|
312
|
+
req.headers.authorization
|
|
313
|
+
);
|
|
314
|
+
const userId = user.getId();
|
|
262
315
|
const params = checkRequiredParams(req.params, ['integrationId']);
|
|
263
316
|
const instance =
|
|
264
317
|
await integrationFactory.getInstanceFromIntegrationId({
|
|
265
|
-
userId
|
|
318
|
+
userId,
|
|
266
319
|
integrationId: params.integrationId,
|
|
267
320
|
});
|
|
268
321
|
|
|
@@ -286,9 +339,16 @@ function setIntegrationRoutes(router, factory, getUserId) {
|
|
|
286
339
|
);
|
|
287
340
|
}
|
|
288
341
|
|
|
289
|
-
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Sets up entity-related routes for the integration router
|
|
345
|
+
* @param {Object} router - Express router instance
|
|
346
|
+
* @param {Object} factory - Factory object containing moduleFactory and IntegrationHelper
|
|
347
|
+
* @param {import('../user/use-cases/get-user-from-bearer-token').GetUserFromBearerToken} getUserFromBearerToken - Use case for retrieving a user from a bearer token
|
|
348
|
+
*/
|
|
349
|
+
function setEntityRoutes(router, factory, getUserFromBearerToken) {
|
|
290
350
|
const { moduleFactory, IntegrationHelper } = factory;
|
|
291
|
-
const getModuleInstance = async (
|
|
351
|
+
const getModuleInstance = async (userId, entityType) => {
|
|
292
352
|
if (!moduleFactory.checkIsValidType(entityType)) {
|
|
293
353
|
throw Boom.badRequest(
|
|
294
354
|
`Error: Invalid entity type of ${entityType}, options are ${moduleFactory.moduleTypes.join(
|
|
@@ -298,14 +358,18 @@ function setEntityRoutes(router, factory, getUserId) {
|
|
|
298
358
|
}
|
|
299
359
|
return await moduleFactory.getInstanceFromTypeName(
|
|
300
360
|
entityType,
|
|
301
|
-
|
|
361
|
+
userId
|
|
302
362
|
);
|
|
303
363
|
};
|
|
304
364
|
|
|
305
365
|
router.route('/api/authorize').get(
|
|
306
366
|
catchAsyncError(async (req, res) => {
|
|
367
|
+
const user = await getUserFromBearerToken.execute(
|
|
368
|
+
req.headers.authorization
|
|
369
|
+
);
|
|
370
|
+
const userId = user.getId();
|
|
307
371
|
const params = checkRequiredParams(req.query, ['entityType']);
|
|
308
|
-
const module = await getModuleInstance(
|
|
372
|
+
const module = await getModuleInstance(userId, params.entityType);
|
|
309
373
|
const areRequirementsValid =
|
|
310
374
|
module.validateAuthorizationRequirements();
|
|
311
375
|
if (!areRequirementsValid) {
|
|
@@ -320,15 +384,19 @@ function setEntityRoutes(router, factory, getUserId) {
|
|
|
320
384
|
|
|
321
385
|
router.route('/api/authorize').post(
|
|
322
386
|
catchAsyncError(async (req, res) => {
|
|
387
|
+
const user = await getUserFromBearerToken.execute(
|
|
388
|
+
req.headers.authorization
|
|
389
|
+
);
|
|
390
|
+
const userId = user.getId();
|
|
323
391
|
const params = checkRequiredParams(req.body, [
|
|
324
392
|
'entityType',
|
|
325
393
|
'data',
|
|
326
394
|
]);
|
|
327
|
-
const module = await getModuleInstance(
|
|
395
|
+
const module = await getModuleInstance(userId, params.entityType);
|
|
328
396
|
|
|
329
397
|
res.json(
|
|
330
398
|
await module.processAuthorizationCallback({
|
|
331
|
-
userId
|
|
399
|
+
userId,
|
|
332
400
|
data: params.data,
|
|
333
401
|
})
|
|
334
402
|
);
|
|
@@ -337,6 +405,10 @@ function setEntityRoutes(router, factory, getUserId) {
|
|
|
337
405
|
|
|
338
406
|
router.route('/api/entity').post(
|
|
339
407
|
catchAsyncError(async (req, res) => {
|
|
408
|
+
const user = await getUserFromBearerToken.execute(
|
|
409
|
+
req.headers.authorization
|
|
410
|
+
);
|
|
411
|
+
const userId = user.getId();
|
|
340
412
|
const params = checkRequiredParams(req.body, [
|
|
341
413
|
'entityType',
|
|
342
414
|
'data',
|
|
@@ -352,12 +424,12 @@ function setEntityRoutes(router, factory, getUserId) {
|
|
|
352
424
|
throw Boom.badRequest('Invalid credential ID');
|
|
353
425
|
}
|
|
354
426
|
|
|
355
|
-
const module = await getModuleInstance(
|
|
427
|
+
const module = await getModuleInstance(userId, params.entityType);
|
|
356
428
|
const entityDetails = await module.getEntityDetails(
|
|
357
429
|
module.api,
|
|
358
430
|
null,
|
|
359
431
|
null,
|
|
360
|
-
|
|
432
|
+
userId
|
|
361
433
|
);
|
|
362
434
|
|
|
363
435
|
res.json(await module.findOrCreateEntity(entityDetails));
|
|
@@ -366,17 +438,21 @@ function setEntityRoutes(router, factory, getUserId) {
|
|
|
366
438
|
|
|
367
439
|
router.route('/api/entity/options/:credentialId').get(
|
|
368
440
|
catchAsyncError(async (req, res) => {
|
|
441
|
+
const user = await getUserFromBearerToken.execute(
|
|
442
|
+
req.headers.authorization
|
|
443
|
+
);
|
|
444
|
+
const userId = user.getId();
|
|
369
445
|
// TODO May want to pass along the user ID as well so credential ID's can't be fished???
|
|
370
446
|
// TODO **flagging this for review** -MW
|
|
371
447
|
const credential = await IntegrationHelper.getCredentialById(
|
|
372
448
|
req.params.credentialId
|
|
373
449
|
);
|
|
374
|
-
if (credential.user._id.toString() !==
|
|
450
|
+
if (credential.user._id.toString() !== userId) {
|
|
375
451
|
throw Boom.forbidden('Credential does not belong to user');
|
|
376
452
|
}
|
|
377
453
|
|
|
378
454
|
const params = checkRequiredParams(req.query, ['entityType']);
|
|
379
|
-
const module = await getModuleInstance(
|
|
455
|
+
const module = await getModuleInstance(userId, params.entityType);
|
|
380
456
|
|
|
381
457
|
res.json(await module.getEntityOptions());
|
|
382
458
|
})
|
|
@@ -384,10 +460,14 @@ function setEntityRoutes(router, factory, getUserId) {
|
|
|
384
460
|
|
|
385
461
|
router.route('/api/entities/:entityId/test-auth').get(
|
|
386
462
|
catchAsyncError(async (req, res) => {
|
|
463
|
+
const user = await getUserFromBearerToken.execute(
|
|
464
|
+
req.headers.authorization
|
|
465
|
+
);
|
|
466
|
+
const userId = user.getId();
|
|
387
467
|
const params = checkRequiredParams(req.params, ['entityId']);
|
|
388
468
|
const module = await moduleFactory.getModuleInstanceFromEntityId(
|
|
389
469
|
params.entityId,
|
|
390
|
-
|
|
470
|
+
userId
|
|
391
471
|
);
|
|
392
472
|
|
|
393
473
|
if (!module) {
|
|
@@ -415,10 +495,14 @@ function setEntityRoutes(router, factory, getUserId) {
|
|
|
415
495
|
|
|
416
496
|
router.route('/api/entities/:entityId').get(
|
|
417
497
|
catchAsyncError(async (req, res) => {
|
|
498
|
+
const user = await getUserFromBearerToken.execute(
|
|
499
|
+
req.headers.authorization
|
|
500
|
+
);
|
|
501
|
+
const userId = user.getId();
|
|
418
502
|
const params = checkRequiredParams(req.params, ['entityId']);
|
|
419
503
|
const module = await moduleFactory.getModuleInstanceFromEntityId(
|
|
420
504
|
params.entityId,
|
|
421
|
-
|
|
505
|
+
userId
|
|
422
506
|
);
|
|
423
507
|
|
|
424
508
|
if (!module) {
|
|
@@ -431,13 +515,16 @@ function setEntityRoutes(router, factory, getUserId) {
|
|
|
431
515
|
|
|
432
516
|
router.route('/api/entities/:entityId/options').post(
|
|
433
517
|
catchAsyncError(async (req, res) => {
|
|
518
|
+
const user = await getUserFromBearerToken.execute(
|
|
519
|
+
req.headers.authorization
|
|
520
|
+
);
|
|
521
|
+
const userId = user.getId();
|
|
434
522
|
const params = checkRequiredParams(req.params, [
|
|
435
523
|
'entityId',
|
|
436
|
-
getUserId(req),
|
|
437
524
|
]);
|
|
438
525
|
const module = await moduleFactory.getModuleInstanceFromEntityId(
|
|
439
526
|
params.entityId,
|
|
440
|
-
|
|
527
|
+
userId
|
|
441
528
|
);
|
|
442
529
|
|
|
443
530
|
if (!module) {
|
|
@@ -450,13 +537,16 @@ function setEntityRoutes(router, factory, getUserId) {
|
|
|
450
537
|
|
|
451
538
|
router.route('/api/entities/:entityId/options/refresh').post(
|
|
452
539
|
catchAsyncError(async (req, res) => {
|
|
540
|
+
const user = await getUserFromBearerToken.execute(
|
|
541
|
+
req.headers.authorization
|
|
542
|
+
);
|
|
543
|
+
const userId = user.getId();
|
|
453
544
|
const params = checkRequiredParams(req.params, [
|
|
454
545
|
'entityId',
|
|
455
|
-
getUserId(req),
|
|
456
546
|
]);
|
|
457
547
|
const module = await moduleFactory.getModuleInstanceFromEntityId(
|
|
458
548
|
params.entityId,
|
|
459
|
-
|
|
549
|
+
userId
|
|
460
550
|
);
|
|
461
551
|
|
|
462
552
|
if (!module) {
|
package/module-plugin/auther.js
CHANGED
|
@@ -56,7 +56,7 @@ class Auther extends Delegate {
|
|
|
56
56
|
} else {
|
|
57
57
|
if (
|
|
58
58
|
definition.API.requesterType ===
|
|
59
|
-
|
|
59
|
+
ModuleConstants.authType.oauth2 &&
|
|
60
60
|
!definition.requiredAuthMethods.getToken
|
|
61
61
|
) {
|
|
62
62
|
throw new Error(
|
|
@@ -241,6 +241,7 @@ class Auther extends Delegate {
|
|
|
241
241
|
// type: one of the types defined in modules/Constants.js
|
|
242
242
|
// data: ["required", "fields", "we", "may", "need"]
|
|
243
243
|
// }
|
|
244
|
+
console.log(this.api);
|
|
244
245
|
return this.api.getAuthorizationRequirements();
|
|
245
246
|
}
|
|
246
247
|
|
|
@@ -326,7 +327,7 @@ class Auther extends Delegate {
|
|
|
326
327
|
if (search.length > 1) {
|
|
327
328
|
throw new Error(
|
|
328
329
|
'Multiple entities found with the same identifiers: ' +
|
|
329
|
-
|
|
330
|
+
JSON.stringify(identifiers)
|
|
330
331
|
);
|
|
331
332
|
} else if (search.length === 0) {
|
|
332
333
|
this.entity = await this.EntityModel.create({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const { get } = require('
|
|
2
|
-
const { OAuth2Requester } = require('
|
|
1
|
+
const { get } = require('../../../assertions');
|
|
2
|
+
const { OAuth2Requester } = require('../..');
|
|
3
3
|
|
|
4
4
|
class Api extends OAuth2Requester {
|
|
5
5
|
constructor(params) {
|
|
@@ -23,7 +23,12 @@ class Api extends OAuth2Requester {
|
|
|
23
23
|
return this.authorizationUri;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
getAuthorizationRequirements() {
|
|
27
|
+
return {
|
|
28
|
+
url: this.getAuthUri(),
|
|
29
|
+
type: 'oauth2',
|
|
30
|
+
};
|
|
31
|
+
}
|
|
27
32
|
}
|
|
28
33
|
|
|
29
34
|
module.exports = { Api };
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
require('dotenv').config();
|
|
2
|
-
const {Api} = require('./api');
|
|
3
|
-
const {get} = require('
|
|
4
|
-
const config = {name: 'anapi'}
|
|
2
|
+
const { Api } = require('./api');
|
|
3
|
+
const { get } = require('../../../assertions');
|
|
4
|
+
const config = { name: 'anapi' }
|
|
5
5
|
|
|
6
6
|
const Definition = {
|
|
7
7
|
API: Api,
|
|
8
|
-
|
|
8
|
+
getAuthorizationRequirements: () => ({
|
|
9
|
+
url: 'http://localhost:3000/redirect/anapi',
|
|
10
|
+
type: 'oauth2',
|
|
11
|
+
}),
|
|
12
|
+
getName: function () { return config.name },
|
|
9
13
|
moduleName: config.name,
|
|
10
14
|
modelName: 'AnApi',
|
|
11
15
|
requiredAuthMethods: {
|
|
12
|
-
getToken: async function(api, params){
|
|
16
|
+
getToken: async function (api, params) {
|
|
13
17
|
const code = get(params.data, 'code');
|
|
14
18
|
return api.getTokenFromCode(code);
|
|
15
19
|
},
|
|
16
|
-
getEntityDetails: async function(api, callbackParams, tokenResponse, userId) {
|
|
20
|
+
getEntityDetails: async function (api, callbackParams, tokenResponse, userId) {
|
|
17
21
|
const userDetails = await api.getUserDetails();
|
|
18
22
|
return {
|
|
19
23
|
identifiers: { externalId: userDetails.portalId, user: userId },
|
|
@@ -26,14 +30,14 @@ const Definition = {
|
|
|
26
30
|
],
|
|
27
31
|
entity: [],
|
|
28
32
|
},
|
|
29
|
-
getCredentialDetails: async function(api, userId) {
|
|
33
|
+
getCredentialDetails: async function (api, userId) {
|
|
30
34
|
const userDetails = await api.getUserDetails();
|
|
31
35
|
return {
|
|
32
36
|
identifiers: { externalId: userDetails.portalId, user: userId },
|
|
33
37
|
details: {}
|
|
34
38
|
};
|
|
35
39
|
},
|
|
36
|
-
testAuthRequest: async function(api){
|
|
40
|
+
testAuthRequest: async function (api) {
|
|
37
41
|
return api.getUserDetails()
|
|
38
42
|
},
|
|
39
43
|
},
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/core",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0--canary.
|
|
4
|
+
"version": "2.0.0--canary.395.d07514c.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@hapi/boom": "^10.0.1",
|
|
7
7
|
"aws-sdk": "^2.1200.0",
|
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|
"uuid": "^9.0.1"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@friggframework/eslint-config": "2.0.0--canary.
|
|
26
|
-
"@friggframework/prettier-config": "2.0.0--canary.
|
|
27
|
-
"@friggframework/test": "2.0.0--canary.
|
|
25
|
+
"@friggframework/eslint-config": "2.0.0--canary.395.d07514c.0",
|
|
26
|
+
"@friggframework/prettier-config": "2.0.0--canary.395.d07514c.0",
|
|
27
|
+
"@friggframework/test": "2.0.0--canary.395.d07514c.0",
|
|
28
28
|
"@types/lodash": "4.17.15",
|
|
29
29
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
30
30
|
"chai": "^4.3.6",
|
|
@@ -53,5 +53,5 @@
|
|
|
53
53
|
},
|
|
54
54
|
"homepage": "https://github.com/friggframework/frigg#readme",
|
|
55
55
|
"description": "",
|
|
56
|
-
"gitHead": "
|
|
56
|
+
"gitHead": "d07514cc9f891cbe6a53bea70322bf4c613b3058"
|
|
57
57
|
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
const Boom = require('@hapi/boom');
|
|
2
|
+
const { User } = require('../../user');
|
|
3
|
+
|
|
4
|
+
class TestUserRepository {
|
|
5
|
+
constructor({ userConfig }) {
|
|
6
|
+
this.individualUsers = new Map();
|
|
7
|
+
this.organizationUsers = new Map();
|
|
8
|
+
this.tokens = new Map();
|
|
9
|
+
this.userConfig = userConfig;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async getSessionToken(token) {
|
|
13
|
+
return this.tokens.get(token);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async findOrganizationUserById(userId) {
|
|
17
|
+
const orgUserDoc = this.organizationUsers.get(userId);
|
|
18
|
+
if (!orgUserDoc) {
|
|
19
|
+
throw Boom.unauthorized('Organization User Not Found');
|
|
20
|
+
}
|
|
21
|
+
return new User(null, orgUserDoc, this.userConfig.usePassword, this.userConfig.primary, this.userConfig.individualUserRequired, this.userConfig.organizationUserRequired);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async findIndividualUserById(userId) {
|
|
25
|
+
const individualUserDoc = this.individualUsers.get(userId);
|
|
26
|
+
if (!individualUserDoc) {
|
|
27
|
+
throw Boom.unauthorized('Individual User Not Found');
|
|
28
|
+
}
|
|
29
|
+
return new User(individualUserDoc, null, this.userConfig.usePassword, this.userConfig.primary, this.userConfig.individualUserRequired, this.userConfig.organizationUserRequired);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async createToken(userId, rawToken, minutes = 120) {
|
|
33
|
+
const token = `token-for-${userId}-for-${minutes}-mins`;
|
|
34
|
+
this.tokens.set(token, { user: userId, rawToken });
|
|
35
|
+
return token;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async createIndividualUser(params) {
|
|
39
|
+
const individualUserData = { id: `individual-${Date.now()}`, ...params };
|
|
40
|
+
this.individualUsers.set(individualUserData.id, individualUserData);
|
|
41
|
+
return new User(
|
|
42
|
+
individualUserData,
|
|
43
|
+
null,
|
|
44
|
+
this.userConfig.usePassword,
|
|
45
|
+
this.userConfig.primary,
|
|
46
|
+
this.userConfig.individualUserRequired,
|
|
47
|
+
this.userConfig.organizationUserRequired
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async createOrganizationUser(params) {
|
|
52
|
+
const orgUserData = { ...params, id: `org-${Date.now()}` };
|
|
53
|
+
this.organizationUsers.set(orgUserData.id, orgUserData);
|
|
54
|
+
return new User(
|
|
55
|
+
null,
|
|
56
|
+
orgUserData,
|
|
57
|
+
this.userConfig.usePassword,
|
|
58
|
+
this.userConfig.primary,
|
|
59
|
+
this.userConfig.individualUserRequired,
|
|
60
|
+
this.userConfig.organizationUserRequired
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async findIndividualUserByUsername(username) {
|
|
65
|
+
for (const userDoc of this.individualUsers.values()) {
|
|
66
|
+
if (userDoc.username === username) {
|
|
67
|
+
return new User(
|
|
68
|
+
userDoc,
|
|
69
|
+
null,
|
|
70
|
+
this.userConfig.usePassword,
|
|
71
|
+
this.userConfig.primary,
|
|
72
|
+
this.userConfig.individualUserRequired,
|
|
73
|
+
this.userConfig.organizationUserRequired
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
throw Boom.unauthorized('user not found');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async findIndividualUserByAppUserId(appUserId) {
|
|
81
|
+
if (!appUserId) throw Boom.unauthorized('user not found');
|
|
82
|
+
for (const userDoc of this.individualUsers.values()) {
|
|
83
|
+
if (userDoc.appUserId === appUserId) {
|
|
84
|
+
return new User(
|
|
85
|
+
userDoc,
|
|
86
|
+
null,
|
|
87
|
+
this.userConfig.usePassword,
|
|
88
|
+
this.userConfig.primary,
|
|
89
|
+
this.userConfig.individualUserRequired,
|
|
90
|
+
this.userConfig.organizationUserRequired
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
throw Boom.unauthorized('user not found');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async findOrganizationUserByAppOrgId(appOrgId) {
|
|
98
|
+
if (!appOrgId) throw Boom.unauthorized('user not found');
|
|
99
|
+
for (const userDoc of this.organizationUsers.values()) {
|
|
100
|
+
if (userDoc.appOrgId === appOrgId) {
|
|
101
|
+
return new User(
|
|
102
|
+
null,
|
|
103
|
+
userDoc,
|
|
104
|
+
this.userConfig.usePassword,
|
|
105
|
+
this.userConfig.primary,
|
|
106
|
+
this.userConfig.individualUserRequired,
|
|
107
|
+
this.userConfig.organizationUserRequired
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
throw Boom.unauthorized('user not found');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
module.exports = { TestUserRepository };
|