@friggframework/core 0.2.31-v1-alpha-package-update.0 → 1.0.1-canary.278.7b20420.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/assertions/CHANGELOG.md +87 -0
- package/assertions/LICENSE.md +9 -0
- package/assertions/README.md +3 -0
- package/assertions/bump.txt +1 -0
- package/assertions/get.js +139 -0
- package/assertions/index.js +19 -0
- package/assertions/is-equal.js +17 -0
- package/associations/LICENSE.md +9 -0
- package/associations/README.md +3 -0
- package/associations/association.js +78 -0
- package/associations/bump3.txt +0 -0
- package/associations/jest.config.js +5 -0
- package/associations/model.js +54 -0
- package/bump0.txt +1 -0
- package/core/.eslintrc.json +3 -0
- package/{Delegate.js → core/Delegate.js} +1 -1
- package/core/LICENSE.md +9 -0
- package/{Worker.js → core/Worker.js} +2 -2
- package/core/bump3.txt +0 -0
- package/{create-handler.js → core/create-handler.js} +2 -2
- package/core/index.js +6 -0
- package/core/jest.config.js +5 -0
- package/database/.eslintrc.json +3 -0
- package/database/CHANGELOG.md +97 -0
- package/database/LICENSE.md +9 -0
- package/database/README.md +3 -0
- package/database/bump3.txt +0 -0
- package/database/index.js +23 -0
- package/database/jest.config.js +5 -0
- package/database/models/IndividualUser.js +76 -0
- package/database/models/OrganizationUser.js +29 -0
- package/database/models/State.js +9 -0
- package/database/models/Token.js +70 -0
- package/database/models/UserModel.js +7 -0
- package/database/mongo.js +45 -0
- package/database/mongoose.js +5 -0
- package/encrypt/.eslintrc.json +3 -0
- package/encrypt/CHANGELOG.md +78 -0
- package/encrypt/Cryptor.js +236 -0
- package/encrypt/Cryptor.test.js +32 -0
- package/encrypt/LICENSE.md +9 -0
- package/encrypt/README.md +13 -0
- package/encrypt/aes.js +27 -0
- package/encrypt/bump3.txt +0 -0
- package/encrypt/encrypt.js +132 -0
- package/encrypt/encrypt.test.js +1069 -0
- package/encrypt/index.js +4 -0
- package/encrypt/jest.config.js +5 -0
- package/encrypt/test-encrypt.js +107 -0
- package/errors/.eslintrc.json +3 -0
- package/errors/CHANGELOG.md +44 -0
- package/errors/LICENSE.md +9 -0
- package/errors/README.md +3 -0
- package/errors/base-error.js +23 -0
- package/errors/base-error.test.js +32 -0
- package/errors/bump.txt +1 -0
- package/errors/bump3.txt +0 -0
- package/errors/fetch-error.js +76 -0
- package/errors/fetch-error.test.js +79 -0
- package/errors/halt-error.js +10 -0
- package/errors/halt-error.test.js +11 -0
- package/errors/index.js +15 -0
- package/errors/jest.config.js +5 -0
- package/errors/validation-errors.js +23 -0
- package/errors/validation-errors.test.js +120 -0
- package/index.js +123 -5
- package/integrations/.eslintrc.json +3 -0
- package/integrations/CHANGELOG.md +244 -0
- package/integrations/LICENSE.md +9 -0
- package/integrations/README.md +3 -0
- package/integrations/bump3.txt +0 -0
- package/integrations/create-frigg-backend.js +31 -0
- package/integrations/index.js +19 -0
- package/integrations/integration-base.js +162 -0
- package/integrations/integration-factory.js +166 -0
- package/integrations/integration-mapping.js +43 -0
- package/integrations/integration-model.js +42 -0
- package/integrations/integration-router.js +367 -0
- package/integrations/integration-user.js +144 -0
- package/integrations/jest-setup.js +2 -0
- package/integrations/jest-teardown.js +2 -0
- package/integrations/jest.config.js +12 -0
- package/integrations/options.js +54 -0
- package/integrations/test/integration-base.test.js +143 -0
- package/lambda/README.md +3 -0
- package/lambda/TimeoutCatcher.js +43 -0
- package/lambda/TimeoutCatcher.test.js +68 -0
- package/lambda/bump3.txt +0 -0
- package/lambda/index.js +3 -0
- package/lambda/jest.config.js +3 -0
- package/logs/.eslintrc.json +3 -0
- package/logs/CHANGELOG.md +57 -0
- package/logs/LICENSE.md +9 -0
- package/logs/README.md +3 -0
- package/logs/bump3.txt +0 -0
- package/logs/index.js +7 -0
- package/logs/jest.config.js +5 -0
- package/logs/logger.js +69 -0
- package/logs/logger.test.js +76 -0
- package/module-plugin/.eslintrc.json +3 -0
- package/module-plugin/CHANGELOG.md +224 -0
- package/module-plugin/LICENSE.md +9 -0
- package/module-plugin/ModuleConstants.js +10 -0
- package/module-plugin/README.md +3 -0
- package/module-plugin/auther.js +342 -0
- package/module-plugin/bump3.txt +0 -0
- package/module-plugin/credential.js +22 -0
- package/module-plugin/entity-manager.js +70 -0
- package/module-plugin/entity.js +46 -0
- package/module-plugin/index.js +25 -0
- package/module-plugin/jest-setup.js +3 -0
- package/module-plugin/jest-teardown.js +2 -0
- package/module-plugin/jest.config.js +20 -0
- package/module-plugin/manager.js +169 -0
- package/module-plugin/module-factory.js +60 -0
- package/module-plugin/requester/api-key.js +36 -0
- package/module-plugin/requester/basic.js +43 -0
- package/module-plugin/requester/oauth-2.js +219 -0
- package/module-plugin/requester/requester.js +151 -0
- package/module-plugin/requester/requester.test.js +28 -0
- package/module-plugin/test/auther.test.js +97 -0
- package/module-plugin/test/mock-api/api.js +29 -0
- package/module-plugin/test/mock-api/definition.js +48 -0
- package/module-plugin/test/mock-api/mocks/hubspot.js +43 -0
- package/package.json +28 -12
- package/syncs/README.md +3 -0
- package/syncs/bump3.txt +0 -0
- package/syncs/jest.config.js +5 -0
- package/syncs/manager.js +464 -0
- package/syncs/model.js +62 -0
- package/syncs/sync.js +114 -0
- package/types/CHANGELOG.md +49 -0
- package/types/README.md +24 -0
- package/types/assertions/index.d.ts +83 -0
- package/types/associations/index.d.ts +74 -0
- package/types/bump3.txt +0 -0
- package/types/core/index.d.ts +54 -0
- package/types/database/index.d.ts +3 -0
- package/types/encrypt/index.d.ts +5 -0
- package/types/errors/index.d.ts +66 -0
- package/types/eslint-config/index.d.ts +41 -0
- package/types/index.d.ts +14 -0
- package/types/integrations/index.d.ts +191 -0
- package/types/lambda/index.d.ts +31 -0
- package/types/logs/index.d.ts +5 -0
- package/types/module-plugin/index.d.ts +293 -0
- package/types/prettier-config/index.d.ts +6 -0
- package/types/syncs/index.d.ts +128 -0
- package/types/test-environment/index.d.ts +17 -0
- package/types/tsconfig.json +103 -0
- /package/{.eslintrc.json → assertions/.eslintrc.json} +0 -0
- /package/{bump3.txt → assertions/bump3.txt} +0 -0
- /package/{jest.config.js → assertions/jest.config.js} +0 -0
- /package/{CHANGELOG.md → core/CHANGELOG.md} +0 -0
- /package/{README.md → core/README.md} +0 -0
- /package/{load-installed-modules.js → core/load-installed-modules.js} +0 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const { debug, initDebugLog, flushDebugLog } = require('./logger');
|
|
2
|
+
const sinon = require('sinon');
|
|
3
|
+
const {
|
|
4
|
+
overrideEnvironment,
|
|
5
|
+
restoreEnvironment,
|
|
6
|
+
} = require('@friggframework/devtools');
|
|
7
|
+
|
|
8
|
+
/* eslint-disable no-console */
|
|
9
|
+
|
|
10
|
+
describe('Logger', () => {
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
sinon.stub(console, 'debug');
|
|
13
|
+
sinon.stub(console, 'error');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
console.debug.restore();
|
|
18
|
+
console.error.restore();
|
|
19
|
+
restoreEnvironment();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('runs', () => {
|
|
23
|
+
initDebugLog('Test Event', { test: true });
|
|
24
|
+
debug('Add a message', 'or two', { or: 3 });
|
|
25
|
+
flushDebugLog(new Error());
|
|
26
|
+
|
|
27
|
+
expect(console.debug).toHaveProperty('callCount', 2);
|
|
28
|
+
expect(console.error).toHaveProperty('callCount', 1);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('logs immediately when environment variable set', () => {
|
|
32
|
+
overrideEnvironment({ DEBUG_VERBOSE: '1' });
|
|
33
|
+
|
|
34
|
+
debug('Add a message', 'or two', { or: 3 });
|
|
35
|
+
debug('And another');
|
|
36
|
+
|
|
37
|
+
expect(console.debug).toHaveProperty('callCount', 2);
|
|
38
|
+
expect(console.error).toHaveProperty('callCount', 0);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('is resilient to missing parameters', () => {
|
|
42
|
+
initDebugLog();
|
|
43
|
+
debug();
|
|
44
|
+
flushDebugLog();
|
|
45
|
+
|
|
46
|
+
expect(console.debug).toHaveProperty('callCount', 0);
|
|
47
|
+
expect(console.error).toHaveProperty('callCount', 1);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('outputs parent errors', () => {
|
|
51
|
+
initDebugLog();
|
|
52
|
+
|
|
53
|
+
const error = new Error();
|
|
54
|
+
error.cause = new Error();
|
|
55
|
+
error.cause.cause = new Error();
|
|
56
|
+
error.cause.cause.cause = new Error();
|
|
57
|
+
|
|
58
|
+
flushDebugLog(error);
|
|
59
|
+
|
|
60
|
+
expect(console.debug).toHaveProperty('callCount', 0);
|
|
61
|
+
expect(console.error).toHaveProperty('callCount', 7); // 1 + 2 for each cause
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('adds a debug message if more than 1 error encountered', () => {
|
|
65
|
+
initDebugLog();
|
|
66
|
+
flushDebugLog(new Error());
|
|
67
|
+
|
|
68
|
+
expect(console.debug).toHaveProperty('callCount', 0);
|
|
69
|
+
expect(console.error).toHaveProperty('callCount', 1);
|
|
70
|
+
|
|
71
|
+
flushDebugLog(new Error());
|
|
72
|
+
|
|
73
|
+
expect(console.debug).toHaveProperty('callCount', 1);
|
|
74
|
+
expect(console.error).toHaveProperty('callCount', 2);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# v1.1.0 (Wed Sep 06 2023)
|
|
2
|
+
|
|
3
|
+
#### 🚀 Enhancement
|
|
4
|
+
|
|
5
|
+
- Slack lookup by externalId, remove the user requirement from Mongoose DB models [#218](https://github.com/friggframework/frigg/pull/218) ([@seanspeaks](https://github.com/seanspeaks))
|
|
6
|
+
|
|
7
|
+
#### 🐛 Bug Fix
|
|
8
|
+
|
|
9
|
+
- Looking good ([@seanspeaks](https://github.com/seanspeaks))
|
|
10
|
+
- Bump independent versions \[skip ci\] ([@seanspeaks](https://github.com/seanspeaks))
|
|
11
|
+
|
|
12
|
+
#### Authors: 1
|
|
13
|
+
|
|
14
|
+
- Sean Matthews ([@seanspeaks](https://github.com/seanspeaks))
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# v1.0.27 (Thu Jun 08 2023)
|
|
19
|
+
|
|
20
|
+
#### 🐛 Bug Fix
|
|
21
|
+
|
|
22
|
+
- Fr/gdrive lef 280 [#175](https://github.com/friggframework/frigg/pull/175) (michael.webber@lefthook.com [@seanspeaks](https://github.com/seanspeaks))
|
|
23
|
+
- Google Drive update ([@seanspeaks](https://github.com/seanspeaks))
|
|
24
|
+
- Bump independent versions \[skip ci\] ([@seanspeaks](https://github.com/seanspeaks))
|
|
25
|
+
|
|
26
|
+
#### Authors: 2
|
|
27
|
+
|
|
28
|
+
- Michael Webber (michael.webber@lefthook.com)
|
|
29
|
+
- Sean Matthews ([@seanspeaks](https://github.com/seanspeaks))
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
# v1.0.26 (Thu May 25 2023)
|
|
34
|
+
|
|
35
|
+
#### 🐛 Bug Fix
|
|
36
|
+
|
|
37
|
+
- Support calling localhost for ironclad api [#160](https://github.com/friggframework/frigg/pull/160) ([@debbie-yu](https://github.com/debbie-yu))
|
|
38
|
+
- remove agent at method call level ([@debbie-yu](https://github.com/debbie-yu))
|
|
39
|
+
- address feedback to put agent in requester class ([@debbie-yu](https://github.com/debbie-yu))
|
|
40
|
+
- support calling localhost for ironclad api ([@debbie-yu](https://github.com/debbie-yu))
|
|
41
|
+
- Bump independent versions \[skip ci\] ([@seanspeaks](https://github.com/seanspeaks))
|
|
42
|
+
|
|
43
|
+
#### Authors: 2
|
|
44
|
+
|
|
45
|
+
- [@debbie-yu](https://github.com/debbie-yu)
|
|
46
|
+
- Sean Matthews ([@seanspeaks](https://github.com/seanspeaks))
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
# v1.0.25 (Tue Apr 04 2023)
|
|
51
|
+
|
|
52
|
+
:tada: This release contains work from a new contributor! :tada:
|
|
53
|
+
|
|
54
|
+
Thank you, null[@debbie-yu](https://github.com/debbie-yu), for all your work!
|
|
55
|
+
|
|
56
|
+
#### 🐛 Bug Fix
|
|
57
|
+
|
|
58
|
+
- Adding new IntegrationMapping collection [#142](https://github.com/friggframework/frigg/pull/142) ([@debbie-yu](https://github.com/debbie-yu))
|
|
59
|
+
- Merge branch 'main' of https://github.com/friggframework/frigg into debbie.yu/integration-mapping ([@debbie-yu](https://github.com/debbie-yu))
|
|
60
|
+
- addressing PR feedback and adding unit tests around IntegrationMapping ([@debbie-yu](https://github.com/debbie-yu))
|
|
61
|
+
- adding new IntegrationMapping collection to better handle keeping track of mappings for integrations ([@debbie-yu](https://github.com/debbie-yu))
|
|
62
|
+
- Bump independent versions \[skip ci\] ([@seanspeaks](https://github.com/seanspeaks))
|
|
63
|
+
|
|
64
|
+
#### Authors: 2
|
|
65
|
+
|
|
66
|
+
- [@debbie-yu](https://github.com/debbie-yu)
|
|
67
|
+
- Sean Matthews ([@seanspeaks](https://github.com/seanspeaks))
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
# v1.0.24 (Tue Feb 21 2023)
|
|
72
|
+
|
|
73
|
+
#### 🐛 Bug Fix
|
|
74
|
+
|
|
75
|
+
- Updates to HubSpot Module [#132](https://github.com/friggframework/frigg/pull/132) ([@seanspeaks](https://github.com/seanspeaks))
|
|
76
|
+
- Merge branch 'main' into hubspot-updates ([@seanspeaks](https://github.com/seanspeaks))
|
|
77
|
+
- WIP Updates... cleanup, simplify, and fix ([@seanspeaks](https://github.com/seanspeaks))
|
|
78
|
+
- Bump independent versions \[skip ci\] ([@seanspeaks](https://github.com/seanspeaks))
|
|
79
|
+
|
|
80
|
+
#### Authors: 1
|
|
81
|
+
|
|
82
|
+
- Sean Matthews ([@seanspeaks](https://github.com/seanspeaks))
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
# v1.0.23 (Wed Feb 08 2023)
|
|
87
|
+
|
|
88
|
+
#### 🐛 Bug Fix
|
|
89
|
+
|
|
90
|
+
- Fixed a Slack bug via requester improvement [#125](https://github.com/friggframework/frigg/pull/125) ([@seanspeaks](https://github.com/seanspeaks))
|
|
91
|
+
- Fixed a Slack bug via requester improvement ([@seanspeaks](https://github.com/seanspeaks))
|
|
92
|
+
|
|
93
|
+
#### Authors: 1
|
|
94
|
+
|
|
95
|
+
- Sean Matthews ([@seanspeaks](https://github.com/seanspeaks))
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
# v1.0.22 (Tue Jan 31 2023)
|
|
100
|
+
|
|
101
|
+
#### 🐛 Bug Fix
|
|
102
|
+
|
|
103
|
+
- Bump independent versions \[skip ci\] ([@seanspeaks](https://github.com/seanspeaks))
|
|
104
|
+
|
|
105
|
+
#### Authors: 1
|
|
106
|
+
|
|
107
|
+
- Sean Matthews ([@seanspeaks](https://github.com/seanspeaks))
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
# v1.0.21 (Wed Jan 18 2023)
|
|
112
|
+
|
|
113
|
+
#### 🐛 Bug Fix
|
|
114
|
+
|
|
115
|
+
- Ironclad and slack updates [#96](https://github.com/friggframework/frigg/pull/96) ([@seanspeaks](https://github.com/seanspeaks))
|
|
116
|
+
- Refresh Auth attempt only once, instead of potential for infinite loop [#95](https://github.com/friggframework/frigg/pull/95) ([@seanspeaks](https://github.com/seanspeaks))
|
|
117
|
+
- Refresh Auth attempt only once, instead of potential for infinite loop ([@seanspeaks](https://github.com/seanspeaks))
|
|
118
|
+
|
|
119
|
+
#### Authors: 1
|
|
120
|
+
|
|
121
|
+
- Sean Matthews ([@seanspeaks](https://github.com/seanspeaks))
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
# v1.0.20 (Wed Jan 11 2023)
|
|
126
|
+
|
|
127
|
+
#### 🐛 Bug Fix
|
|
128
|
+
|
|
129
|
+
- Ironclad updates and sub type [#91](https://github.com/friggframework/frigg/pull/91) ([@JonathanEdMoore](https://github.com/JonathanEdMoore) [@seanspeaks](https://github.com/seanspeaks))
|
|
130
|
+
- subType support for ironclad ([@seanspeaks](https://github.com/seanspeaks))
|
|
131
|
+
- Bump independent versions \[skip ci\] ([@seanspeaks](https://github.com/seanspeaks))
|
|
132
|
+
|
|
133
|
+
#### Authors: 2
|
|
134
|
+
|
|
135
|
+
- Jonathan Moore ([@JonathanEdMoore](https://github.com/JonathanEdMoore))
|
|
136
|
+
- Sean Matthews ([@seanspeaks](https://github.com/seanspeaks))
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
# v1.0.19 (Tue Jan 10 2023)
|
|
141
|
+
|
|
142
|
+
:tada: This release contains work from a new contributor! :tada:
|
|
143
|
+
|
|
144
|
+
Thank you, Jonathan O'Donnell ([@joncodo](https://github.com/joncodo)), for all your work!
|
|
145
|
+
|
|
146
|
+
#### 🐛 Bug Fix
|
|
147
|
+
|
|
148
|
+
- Merge branch 'main' of github.com:friggframework/frigg into doc-updates ([@joncodo](https://github.com/joncodo))
|
|
149
|
+
- Bump independent versions \[skip ci\] ([@seanspeaks](https://github.com/seanspeaks))
|
|
150
|
+
|
|
151
|
+
#### Authors: 2
|
|
152
|
+
|
|
153
|
+
- Jonathan O'Donnell ([@joncodo](https://github.com/joncodo))
|
|
154
|
+
- Sean Matthews ([@seanspeaks](https://github.com/seanspeaks))
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
# v1.0.18 (Mon Jan 09 2023)
|
|
159
|
+
|
|
160
|
+
#### 🐛 Bug Fix
|
|
161
|
+
|
|
162
|
+
- Merge remote-tracking branch 'origin/main' into gitbook-updates [#48](https://github.com/friggframework/frigg/pull/48) ([@seanspeaks](https://github.com/seanspeaks))
|
|
163
|
+
- Bump independent versions \[skip ci\] ([@seanspeaks](https://github.com/seanspeaks))
|
|
164
|
+
- Updates to managers [#24](https://github.com/friggframework/frigg/pull/24) ([@seanspeaks](https://github.com/seanspeaks))
|
|
165
|
+
- Update integrationManager createIntegration function to accept EntityManager param (WIP) (Could be improved) ([@seanspeaks](https://github.com/seanspeaks))
|
|
166
|
+
- module-plugin manager file uses MO instead of just Entity ([@seanspeaks](https://github.com/seanspeaks))
|
|
167
|
+
- A lot of changes all rolled into one [#21](https://github.com/friggframework/frigg/pull/21) ([@seanspeaks](https://github.com/seanspeaks))
|
|
168
|
+
- Bumped versions with patches ([@seanspeaks](https://github.com/seanspeaks))
|
|
169
|
+
- Mongoose models tweak for sls offline as per https://nesin.io/blog/fix-mongoose-cannot-overwrite-model-once-compiled-error ([@seanspeaks](https://github.com/seanspeaks))
|
|
170
|
+
- Continued updating of references and refactoring API modules ([@seanspeaks](https://github.com/seanspeaks))
|
|
171
|
+
- Merge remote-tracking branch 'origin/main' into simplify-mongoose-models ([@seanspeaks](https://github.com/seanspeaks))
|
|
172
|
+
- Change references to the module instead of local file reference ([@seanspeaks](https://github.com/seanspeaks))
|
|
173
|
+
- Added core as a dependency of module-plugin ([@seanspeaks](https://github.com/seanspeaks))
|
|
174
|
+
- Add READMEs for all packages and api-modules [#20](https://github.com/friggframework/frigg/pull/20) ([@seanspeaks](https://github.com/seanspeaks))
|
|
175
|
+
- Add READMEs for all packages and api-modules ([@seanspeaks](https://github.com/seanspeaks))
|
|
176
|
+
- Begin tweaks for mongo/mongoose models ([@seanspeaks](https://github.com/seanspeaks))
|
|
177
|
+
|
|
178
|
+
#### ⚠️ Pushed to `main`
|
|
179
|
+
|
|
180
|
+
- Merge branch 'main' into gitbook-updates ([@seanspeaks](https://github.com/seanspeaks))
|
|
181
|
+
- Refactored for more conventional naming (at least for packages) ([@seanspeaks](https://github.com/seanspeaks))
|
|
182
|
+
|
|
183
|
+
#### Authors: 1
|
|
184
|
+
|
|
185
|
+
- Sean Matthews ([@seanspeaks](https://github.com/seanspeaks))
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
# v1.0.17 (Fri Dec 23 2022)
|
|
190
|
+
|
|
191
|
+
#### 🐛 Bug Fix
|
|
192
|
+
|
|
193
|
+
- this may break folks' implementations, but that's what unit tests are… [#81](https://github.com/friggframework/frigg/pull/81) ([@seanspeaks](https://github.com/seanspeaks))
|
|
194
|
+
- this may break folks' implementations, but that's what unit tests are for. ([@seanspeaks](https://github.com/seanspeaks))
|
|
195
|
+
|
|
196
|
+
#### Authors: 1
|
|
197
|
+
|
|
198
|
+
- Sean Matthews ([@seanspeaks](https://github.com/seanspeaks))
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
# v1.0.15 (Tue Dec 06 2022)
|
|
203
|
+
|
|
204
|
+
#### 🐛 Bug Fix
|
|
205
|
+
|
|
206
|
+
- fix modules to @friggframework [#74](https://github.com/friggframework/frigg/pull/74) ([@sheehantoufiq](https://github.com/sheehantoufiq))
|
|
207
|
+
- Bump independent versions \[skip ci\] ([@seanspeaks](https://github.com/seanspeaks))
|
|
208
|
+
|
|
209
|
+
#### Authors: 2
|
|
210
|
+
|
|
211
|
+
- Sean Matthews ([@seanspeaks](https://github.com/seanspeaks))
|
|
212
|
+
- Sheehan Toufiq Khan ([@sheehantoufiq](https://github.com/sheehantoufiq))
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
# v1.0.12 (Mon Sep 19 2022)
|
|
217
|
+
|
|
218
|
+
#### 🐛 Bug Fix
|
|
219
|
+
|
|
220
|
+
- Merge remote-tracking branch 'origin/main' into gitbook-updates [#48](https://github.com/friggframework/frigg/pull/48) ([@seanspeaks](https://github.com/seanspeaks))
|
|
221
|
+
|
|
222
|
+
#### Authors: 1
|
|
223
|
+
|
|
224
|
+
- Sean Matthews ([@seanspeaks](https://github.com/seanspeaks))
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Left Hook Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
// Manages authorization and credential persistence
|
|
2
|
+
// Instantiation of an API Class
|
|
3
|
+
// Expects input object like this:
|
|
4
|
+
// const authDef = {
|
|
5
|
+
// API: class anAPI{},
|
|
6
|
+
// moduleName: 'anAPI', //maybe not required
|
|
7
|
+
// requiredAuthMethods: {
|
|
8
|
+
// // oauth methods, how to handle these being required/not?
|
|
9
|
+
// getToken: async function(params, callbackParams, tokenResponse) {},
|
|
10
|
+
// // required for all Auth methods
|
|
11
|
+
// getEntityDetails: async function(params) {}, //probably calls api method
|
|
12
|
+
// getCredentialDetails: async function(params) {}, // might be same as above
|
|
13
|
+
// apiParamsFromCredential: function(params) {},
|
|
14
|
+
// testAuth: async function() {}, // basic request to testAuth
|
|
15
|
+
// },
|
|
16
|
+
// env: {
|
|
17
|
+
// client_id: process.env.HUBSPOT_CLIENT_ID,
|
|
18
|
+
// client_secret: process.env.HUBSPOT_CLIENT_SECRET,
|
|
19
|
+
// scope: process.env.HUBSPOT_SCOPE,
|
|
20
|
+
// redirect_uri: `${process.env.REDIRECT_URI}/an-api`,
|
|
21
|
+
// }
|
|
22
|
+
// };
|
|
23
|
+
|
|
24
|
+
//TODO:
|
|
25
|
+
// 1. Add definition of expected params to API Class (or could just be credential?)
|
|
26
|
+
// 2.
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
const { Delegate } = require('../core');
|
|
30
|
+
const { get } = require('../assertions');
|
|
31
|
+
const _ = require('lodash');
|
|
32
|
+
const {flushDebugLog} = require('../logs');
|
|
33
|
+
const { Credential } = require('./credential');
|
|
34
|
+
const { Entity } = require('./entity');
|
|
35
|
+
const { mongoose } = require('../database/mongoose');
|
|
36
|
+
const {ModuleConstants} = require("./ModuleConstants");
|
|
37
|
+
|
|
38
|
+
class Auther extends Delegate {
|
|
39
|
+
static validateDefinition(definition) {
|
|
40
|
+
if (!definition) {
|
|
41
|
+
throw new Error('Auther definition is required');
|
|
42
|
+
}
|
|
43
|
+
if (!definition.moduleName) {
|
|
44
|
+
throw new Error('Auther definition requires moduleName');
|
|
45
|
+
}
|
|
46
|
+
if (!definition.API) {
|
|
47
|
+
throw new Error('Auther definition requires API class');
|
|
48
|
+
}
|
|
49
|
+
// if (!definition.Credential) {
|
|
50
|
+
// throw new Error('Auther definition requires Credential class');
|
|
51
|
+
// }
|
|
52
|
+
// if (!definition.Entity) {
|
|
53
|
+
// throw new Error('Auther definition requires Entity class');
|
|
54
|
+
// }
|
|
55
|
+
if (!definition.requiredAuthMethods) {
|
|
56
|
+
throw new Error('Auther definition requires requiredAuthMethods');
|
|
57
|
+
} else {
|
|
58
|
+
if (definition.API.requesterType === ModuleConstants.authType.oauth2 &&
|
|
59
|
+
!definition.requiredAuthMethods.getToken) {
|
|
60
|
+
throw new Error('Auther definition requires requiredAuthMethods.getToken');
|
|
61
|
+
}
|
|
62
|
+
if (!definition.requiredAuthMethods.getEntityDetails) {
|
|
63
|
+
throw new Error('Auther definition requires requiredAuthMethods.getEntityDetails');
|
|
64
|
+
}
|
|
65
|
+
if (!definition.requiredAuthMethods.getCredentialDetails) {
|
|
66
|
+
throw new Error('Auther definition requires requiredAuthMethods.getCredentialDetails');
|
|
67
|
+
}
|
|
68
|
+
if (!definition.requiredAuthMethods.apiPropertiesToPersist) {
|
|
69
|
+
throw new Error('Auther definition requires requiredAuthMethods.apiPropertiesToPersist');
|
|
70
|
+
} else if (definition.Credential){
|
|
71
|
+
for (const prop of definition.requiredAuthMethods.apiPropertiesToPersist?.credential) {
|
|
72
|
+
if (!definition.Credential.schema.paths.hasOwnProperty(prop)) {
|
|
73
|
+
throw new Error(
|
|
74
|
+
`Auther definition requires Credential schema to have property ${prop}`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (!definition.requiredAuthMethods.testAuthRequest) {
|
|
80
|
+
throw new Error('Auther definition requires requiredAuthMethods.testAuth');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
constructor(params) {
|
|
86
|
+
super(params);
|
|
87
|
+
this.userId = get(params, 'userId', null); // Making this non-required
|
|
88
|
+
const definition = get(params, 'definition');
|
|
89
|
+
Auther.validateDefinition(definition);
|
|
90
|
+
Object.assign(this, definition.requiredAuthMethods);
|
|
91
|
+
this.name = definition.moduleName;
|
|
92
|
+
this.modelName = definition.modelName;
|
|
93
|
+
this.apiClass = definition.API;
|
|
94
|
+
this.CredentialModel = definition.Credential || this.getCredentialModel();
|
|
95
|
+
this.EntityModel = definition.Entity || this.getEntityModel();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
static async getInstance(params) {
|
|
99
|
+
const instance = new this(params);
|
|
100
|
+
if (params.entityId) {
|
|
101
|
+
instance.entity = await instance.EntityModel.findById(params.entityId);
|
|
102
|
+
instance.credential = await instance.CredentialModel.findById(
|
|
103
|
+
instance.entity.credential
|
|
104
|
+
);
|
|
105
|
+
} else if (params.credentialId) {
|
|
106
|
+
instance.credential = await instance.CredentialModel.findById(
|
|
107
|
+
params.credentialId
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
let credential = {};
|
|
111
|
+
let entity = {};
|
|
112
|
+
if (instance.credential) {
|
|
113
|
+
credential = instance.credential.toObject();
|
|
114
|
+
}
|
|
115
|
+
if (instance.entity) {
|
|
116
|
+
entity = instance.entity.toObject();
|
|
117
|
+
}
|
|
118
|
+
const apiParams = {
|
|
119
|
+
...params.definition.env,
|
|
120
|
+
delegate: instance,
|
|
121
|
+
...instance.apiParamsFromCredential(credential),
|
|
122
|
+
...instance.apiParamsFromEntity(entity),
|
|
123
|
+
};
|
|
124
|
+
instance.api = new instance.apiClass(apiParams);
|
|
125
|
+
return instance;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
static getEntityModelFromDefinition(definition) {
|
|
129
|
+
const partialModule = new this({definition});
|
|
130
|
+
return partialModule.getEntityModel();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
getName() {
|
|
134
|
+
return this.name;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
apiParamsFromCredential(credential) {
|
|
138
|
+
return _.pick(credential, ...this.apiPropertiesToPersist?.credential);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
apiParamsFromEntity(entity) {
|
|
142
|
+
return _.pick(entity, ...this.apiPropertiesToPersist?.entity);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
getEntityModel() {
|
|
146
|
+
if (!this.EntityModel) {
|
|
147
|
+
const prefix = this.modelName ?? _.upperFirst(this.getName());
|
|
148
|
+
const arrayToDefaultObject = (array, defaultValue) => _.mapValues(_.keyBy(array), () => defaultValue);
|
|
149
|
+
const schema = new mongoose.Schema(arrayToDefaultObject(this.apiPropertiesToPersist.entity, {
|
|
150
|
+
type: mongoose.Schema.Types.Mixed,
|
|
151
|
+
trim: true,
|
|
152
|
+
}));
|
|
153
|
+
const name = `${prefix}Entity`;
|
|
154
|
+
this.EntityModel =
|
|
155
|
+
Entity.discriminators?.[name] || Entity.discriminator(name, schema);
|
|
156
|
+
}
|
|
157
|
+
return this.EntityModel;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
getCredentialModel() {
|
|
161
|
+
if (!this.CredentialModel) {
|
|
162
|
+
const arrayToDefaultObject = (array, defaultValue) => _.mapValues(_.keyBy(array), () => defaultValue);
|
|
163
|
+
const schema = new mongoose.Schema(arrayToDefaultObject(this.apiPropertiesToPersist.credential, {
|
|
164
|
+
type: mongoose.Schema.Types.Mixed,
|
|
165
|
+
trim: true,
|
|
166
|
+
lhEncrypt: true
|
|
167
|
+
}));
|
|
168
|
+
const prefix = this.modelName ?? _.upperFirst(this.getName());
|
|
169
|
+
const name = `${prefix}Credential`;
|
|
170
|
+
this.CredentialModel =
|
|
171
|
+
Credential.discriminators?.[name] || Credential.discriminator(name, schema);
|
|
172
|
+
}
|
|
173
|
+
return this.CredentialModel;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async getEntitiesForUserId(userId) {
|
|
177
|
+
// Only return non-internal fields. Leverages "select" and "options" to non-excepted fields and a pure object.
|
|
178
|
+
const list = await this.EntityModel.find(
|
|
179
|
+
{ user: userId },
|
|
180
|
+
'-dateCreated -dateUpdated -user -credentials -credential -__t -__v',
|
|
181
|
+
{ lean: true }
|
|
182
|
+
);
|
|
183
|
+
console.log('getEntitiesForUserId list', list, userId);
|
|
184
|
+
return list.map((entity) => ({
|
|
185
|
+
id: entity._id,
|
|
186
|
+
type: this.getName(),
|
|
187
|
+
...entity,
|
|
188
|
+
}));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async validateAuthorizationRequirements() {
|
|
192
|
+
const requirements = await this.getAuthorizationRequirements();
|
|
193
|
+
let valid = true;
|
|
194
|
+
if (['oauth1', 'oauth2'].includes(requirements.type) && !requirements.url) {
|
|
195
|
+
valid = false;
|
|
196
|
+
}
|
|
197
|
+
return valid;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
getAuthorizationRequirements(params) {
|
|
201
|
+
// TODO: How can this be more helpful both to implement and consume
|
|
202
|
+
// this function must return a dictionary with the following format
|
|
203
|
+
// node only url key is required. Data would be used for Base Authentication
|
|
204
|
+
// let returnData = {
|
|
205
|
+
// url: "callback url for the data or teh redirect url for login",
|
|
206
|
+
// type: one of the types defined in modules/Constants.js
|
|
207
|
+
// data: ["required", "fields", "we", "may", "need"]
|
|
208
|
+
// }
|
|
209
|
+
return this.api.getAuthorizationRequirements();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async testAuth(params) {
|
|
213
|
+
let validAuth = false;
|
|
214
|
+
try {
|
|
215
|
+
if (await this.testAuthRequest(this.api)) validAuth = true;
|
|
216
|
+
} catch (e) {
|
|
217
|
+
flushDebugLog(e);
|
|
218
|
+
}
|
|
219
|
+
return validAuth;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async processAuthorizationCallback(params) {
|
|
223
|
+
let tokenResponse;
|
|
224
|
+
if (this.apiClass.requesterType === ModuleConstants.authType.oauth2) {
|
|
225
|
+
tokenResponse = await this.getToken(this.api, params);
|
|
226
|
+
} else {
|
|
227
|
+
tokenResponse = await this.setAuthParams(this.api, params);
|
|
228
|
+
await this.onTokenUpdate();
|
|
229
|
+
}
|
|
230
|
+
const authRes = await this.testAuth();
|
|
231
|
+
if (!authRes) {
|
|
232
|
+
throw new Error('Authorization failed');
|
|
233
|
+
}
|
|
234
|
+
const entityDetails = await this.getEntityDetails(
|
|
235
|
+
this.api, params, tokenResponse, this.userId
|
|
236
|
+
);
|
|
237
|
+
Object.assign(entityDetails.details, this.apiParamsFromEntity(this.api));
|
|
238
|
+
await this.findOrCreateEntity(entityDetails);
|
|
239
|
+
return {
|
|
240
|
+
credential_id: this.credential.id,
|
|
241
|
+
entity_id: this.entity.id,
|
|
242
|
+
type: this.getName(),
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async onTokenUpdate() {
|
|
247
|
+
const credentialDetails = await this.getCredentialDetails(this.api, this.userId);
|
|
248
|
+
Object.assign(credentialDetails.details, this.apiParamsFromCredential(this.api));
|
|
249
|
+
credentialDetails.details.auth_is_valid = true;
|
|
250
|
+
await this.updateOrCreateCredential(credentialDetails);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
async receiveNotification(notifier, delegateString, object = null) {
|
|
254
|
+
if (delegateString === this.api.DLGT_TOKEN_UPDATE) {
|
|
255
|
+
await this.onTokenUpdate();
|
|
256
|
+
}
|
|
257
|
+
else if (delegateString === this.api.DLGT_TOKEN_DEAUTHORIZED) {
|
|
258
|
+
await this.deauthorize();
|
|
259
|
+
}
|
|
260
|
+
else if (delegateString === this.api.DLGT_INVALID_AUTH) {
|
|
261
|
+
await this.markCredentialsInvalid();
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
async getEntityOptions() {
|
|
266
|
+
// May not be needed if the callback already creates the entity, such as in situations
|
|
267
|
+
// like HubSpot where the account is determined in the authorization flow.
|
|
268
|
+
// This should only be used in situations such as FreshBooks where the user needs to make
|
|
269
|
+
// an account decision on the front end.
|
|
270
|
+
throw new Error(
|
|
271
|
+
'Entity requirement method getEntityOptions() is not defined in the class'
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async findOrCreateEntity(entityDetails) {
|
|
276
|
+
const identifiers = get(entityDetails, 'identifiers');
|
|
277
|
+
const details = get(entityDetails, 'details');
|
|
278
|
+
const search = await this.EntityModel.find(identifiers);
|
|
279
|
+
if (search.length > 1) {
|
|
280
|
+
throw new Error(
|
|
281
|
+
'Multiple entities found with the same identifiers: ' + JSON.stringify(identifiers)
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
else if (search.length === 0) {
|
|
285
|
+
this.entity = await this.EntityModel.create({
|
|
286
|
+
credential: this.credential.id,
|
|
287
|
+
...details,
|
|
288
|
+
...identifiers,
|
|
289
|
+
});
|
|
290
|
+
} else if (search.length === 1) {
|
|
291
|
+
this.entity = search[0];
|
|
292
|
+
}
|
|
293
|
+
if (this.entity.credential === undefined) {
|
|
294
|
+
this.entity.credential = this.credential.id;
|
|
295
|
+
await this.entity.save();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
async updateOrCreateCredential(credentialDetails) {
|
|
300
|
+
const identifiers = get(credentialDetails, 'identifiers');
|
|
301
|
+
const details = get(credentialDetails, 'details');
|
|
302
|
+
|
|
303
|
+
if (!this.credential){
|
|
304
|
+
const credentialSearch = await this.CredentialModel.find(identifiers);
|
|
305
|
+
if (credentialSearch.length > 1) {
|
|
306
|
+
throw new Error(`Multiple credentials found with same identifiers: ${identifiers}`);
|
|
307
|
+
}
|
|
308
|
+
else if (credentialSearch.length === 1) {
|
|
309
|
+
// found exactly one credential with these identifiers
|
|
310
|
+
this.credential = credentialSearch[0];
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
// found no credential with these identifiers (match none for insert)
|
|
314
|
+
this.credential = {$exists: false};
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
// update credential or create if none was found
|
|
318
|
+
this.credential = await this.CredentialModel.findOneAndUpdate(
|
|
319
|
+
{_id: this.credential},
|
|
320
|
+
{$set: {...identifiers, ...details}},
|
|
321
|
+
{useFindAndModify: true, new: true, upsert: true}
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
async markCredentialsInvalid() {
|
|
326
|
+
if (this.credential) {
|
|
327
|
+
this.credential.auth_is_valid = false;
|
|
328
|
+
await this.credential.save();
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
async deauthorize() {
|
|
333
|
+
this.api = new this.apiClass();
|
|
334
|
+
if (this.entity?.credential) {
|
|
335
|
+
await this.CredentialModel.deleteOne({ _id: this.entity.credential });
|
|
336
|
+
this.entity.credential = undefined;
|
|
337
|
+
await this.entity.save();
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
module.exports = { Auther };
|
|
File without changes
|