@dereekb/zoom 12.6.21 → 13.0.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/LICENSE +1 -1
- package/index.cjs.js +4 -1417
- package/index.esm.js +5 -1418
- package/nestjs/index.cjs.js +692 -0
- package/nestjs/index.esm.js +662 -0
- package/nestjs/package.json +19 -3
- package/nestjs/src/lib/webhook/webhook.zoom.controller.d.ts +1 -1
- package/nestjs/src/lib/zoom/zoom.api.d.ts +1 -1
- package/package.json +14 -7
- package/src/lib/oauth/oauth.error.api.d.ts +2 -2
- package/src/lib/zoom/zoom.error.api.d.ts +2 -2
- package/src/lib/zoom.error.api.d.ts +2 -2
- package/src/lib/zoom.type.d.ts +2 -2
- package/nestjs/CHANGELOG.md +0 -459
- package/nestjs/README.md +0 -11
- package/nestjs/src/index.js +0 -5
- package/nestjs/src/index.js.map +0 -1
- package/nestjs/src/lib/index.js +0 -7
- package/nestjs/src/lib/index.js.map +0 -1
- package/nestjs/src/lib/oauth/index.js +0 -8
- package/nestjs/src/lib/oauth/index.js.map +0 -1
- package/nestjs/src/lib/oauth/oauth.api.js +0 -41
- package/nestjs/src/lib/oauth/oauth.api.js.map +0 -1
- package/nestjs/src/lib/oauth/oauth.config.js +0 -50
- package/nestjs/src/lib/oauth/oauth.config.js.map +0 -1
- package/nestjs/src/lib/oauth/oauth.module.js +0 -36
- package/nestjs/src/lib/oauth/oauth.module.js.map +0 -1
- package/nestjs/src/lib/oauth/oauth.service.js +0 -230
- package/nestjs/src/lib/oauth/oauth.service.js.map +0 -1
- package/nestjs/src/lib/webhook/index.js +0 -15
- package/nestjs/src/lib/webhook/index.js.map +0 -1
- package/nestjs/src/lib/webhook/webhook.zoom.config.js +0 -17
- package/nestjs/src/lib/webhook/webhook.zoom.config.js.map +0 -1
- package/nestjs/src/lib/webhook/webhook.zoom.controller.js +0 -38
- package/nestjs/src/lib/webhook/webhook.zoom.controller.js.map +0 -1
- package/nestjs/src/lib/webhook/webhook.zoom.js +0 -38
- package/nestjs/src/lib/webhook/webhook.zoom.js.map +0 -1
- package/nestjs/src/lib/webhook/webhook.zoom.module.js +0 -41
- package/nestjs/src/lib/webhook/webhook.zoom.module.js.map +0 -1
- package/nestjs/src/lib/webhook/webhook.zoom.service.js +0 -60
- package/nestjs/src/lib/webhook/webhook.zoom.service.js.map +0 -1
- package/nestjs/src/lib/webhook/webhook.zoom.type.common.js +0 -3
- package/nestjs/src/lib/webhook/webhook.zoom.type.common.js.map +0 -1
- package/nestjs/src/lib/webhook/webhook.zoom.type.js +0 -3
- package/nestjs/src/lib/webhook/webhook.zoom.type.js.map +0 -1
- package/nestjs/src/lib/webhook/webhook.zoom.type.meeting.js +0 -18
- package/nestjs/src/lib/webhook/webhook.zoom.type.meeting.js.map +0 -1
- package/nestjs/src/lib/webhook/webhook.zoom.type.validate.js +0 -5
- package/nestjs/src/lib/webhook/webhook.zoom.type.validate.js.map +0 -1
- package/nestjs/src/lib/webhook/webhook.zoom.validate.js +0 -25
- package/nestjs/src/lib/webhook/webhook.zoom.validate.js.map +0 -1
- package/nestjs/src/lib/webhook/webhook.zoom.verify.js +0 -27
- package/nestjs/src/lib/webhook/webhook.zoom.verify.js.map +0 -1
- package/nestjs/src/lib/zoom/index.js +0 -7
- package/nestjs/src/lib/zoom/index.js.map +0 -1
- package/nestjs/src/lib/zoom/zoom.api.js +0 -78
- package/nestjs/src/lib/zoom/zoom.api.js.map +0 -1
- package/nestjs/src/lib/zoom/zoom.config.js +0 -15
- package/nestjs/src/lib/zoom/zoom.config.js.map +0 -1
- package/nestjs/src/lib/zoom/zoom.module.js +0 -40
- package/nestjs/src/lib/zoom/zoom.module.js.map +0 -1
- /package/{index.cjs.d.ts → index.d.ts} +0 -0
- /package/{index.esm.d.ts → nestjs/index.d.ts} +0 -0
|
@@ -0,0 +1,692 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var common = require('@nestjs/common');
|
|
4
|
+
var zoom = require('@dereekb/zoom');
|
|
5
|
+
var util = require('@dereekb/util');
|
|
6
|
+
var path = require('path');
|
|
7
|
+
var fs = require('fs');
|
|
8
|
+
var config = require('@nestjs/config');
|
|
9
|
+
var nestjs = require('@dereekb/nestjs');
|
|
10
|
+
var crypto = require('crypto');
|
|
11
|
+
|
|
12
|
+
/******************************************************************************
|
|
13
|
+
Copyright (c) Microsoft Corporation.
|
|
14
|
+
|
|
15
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
16
|
+
purpose with or without fee is hereby granted.
|
|
17
|
+
|
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
19
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
20
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
21
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
22
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
23
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
24
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
25
|
+
***************************************************************************** */
|
|
26
|
+
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
function __decorate(decorators, target, key, desc) {
|
|
30
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
31
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
32
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
33
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function __param(paramIndex, decorator) {
|
|
37
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function __metadata(metadataKey, metadataValue) {
|
|
41
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
45
|
+
var e = new Error(message);
|
|
46
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Configuration for ZoomService
|
|
51
|
+
*/
|
|
52
|
+
class ZoomOAuthServiceConfig {
|
|
53
|
+
zoomOAuth;
|
|
54
|
+
factoryConfig;
|
|
55
|
+
static assertValidConfig(config) {
|
|
56
|
+
const {
|
|
57
|
+
zoomOAuth
|
|
58
|
+
} = config;
|
|
59
|
+
if (!zoomOAuth) {
|
|
60
|
+
throw new Error('ZoomOAuthServiceConfig.zoomOAuth is required');
|
|
61
|
+
} else {
|
|
62
|
+
if (!zoomOAuth.accountId) {
|
|
63
|
+
throw new Error('ZoomOAuthServiceConfig.zoomOAuth.accountId is required');
|
|
64
|
+
} else if (!zoomOAuth.clientSecret) {
|
|
65
|
+
throw new Error('ZoomOAuthServiceConfig.zoomOAuth.clientSecret is required');
|
|
66
|
+
} else if (!zoomOAuth.clientId) {
|
|
67
|
+
throw new Error('ZoomOAuthServiceConfig.zoomOAuth.clientId is required');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function readZoomOAuthServiceConfigFromConfigService(configService, prefix) {
|
|
73
|
+
const prefixString = util.characterPrefixSuffixInstance({
|
|
74
|
+
suffix: '_',
|
|
75
|
+
suffixEmptyString: false
|
|
76
|
+
}).prefixSuffixString(prefix ?? '');
|
|
77
|
+
const accountIdKey = `${prefixString}ZOOM_ACCOUNT_ID`;
|
|
78
|
+
const clientIdKey = `${prefixString}ZOOM_CLIENT_ID`;
|
|
79
|
+
const clientSecretKey = `${prefixString}ZOOM_CLIENT_SECRET`;
|
|
80
|
+
const accountId = configService.getOrThrow(accountIdKey);
|
|
81
|
+
const clientId = configService.getOrThrow(clientIdKey);
|
|
82
|
+
const clientSecret = configService.getOrThrow(clientSecretKey);
|
|
83
|
+
const config = {
|
|
84
|
+
zoomOAuth: {
|
|
85
|
+
authEntityType: 'account',
|
|
86
|
+
accountId,
|
|
87
|
+
clientId,
|
|
88
|
+
clientSecret
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
ZoomOAuthServiceConfig.assertValidConfig(config);
|
|
92
|
+
return config;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Service used for retrieving ZoomAccessTokenCache for Zoom services.
|
|
97
|
+
*/
|
|
98
|
+
exports.ZoomOAuthAccessTokenCacheService = class ZoomOAuthAccessTokenCacheService {};
|
|
99
|
+
exports.ZoomOAuthAccessTokenCacheService = __decorate([common.Injectable()], exports.ZoomOAuthAccessTokenCacheService);
|
|
100
|
+
function logMergeZoomOAuthAccessTokenCacheServiceErrorFunction(failedUpdates) {
|
|
101
|
+
console.warn(`mergeZoomOAuthAccessTokenCacheServices(): failed updating ${failedUpdates.length} caches.`);
|
|
102
|
+
failedUpdates.forEach(([x, e], i) => {
|
|
103
|
+
console.warn(`Cache update failure ${i + 1}: - ${e}`);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Merges the input services in order to use some as a backup source.
|
|
108
|
+
*
|
|
109
|
+
* If once source fails retrieval, the next will be tried.
|
|
110
|
+
*
|
|
111
|
+
* When updating a cached token, it will update the token across all services.
|
|
112
|
+
*
|
|
113
|
+
* @param servicesToMerge Must include atleast one service. Empty arrays will throw an error.
|
|
114
|
+
*/
|
|
115
|
+
function mergeZoomOAuthAccessTokenCacheServices(inputServicesToMerge, logError) {
|
|
116
|
+
const allServices = [...inputServicesToMerge];
|
|
117
|
+
const logErrorFunction = typeof logError === 'function' ? logError : logError !== false ? logMergeZoomOAuthAccessTokenCacheServiceErrorFunction : undefined;
|
|
118
|
+
if (allServices.length === 0) {
|
|
119
|
+
throw new Error('mergeZoomOAuthAccessTokenCacheServices() input cannot be empty.');
|
|
120
|
+
}
|
|
121
|
+
const loadZoomAccessTokenCache = accessCachesForServices => {
|
|
122
|
+
const loadCachedTokenFromFirstService = util.tryWithPromiseFactoriesFunction({
|
|
123
|
+
promiseFactories: accessCachesForServices.map(x => () => x.loadCachedToken().catch(() => null).then(x => {
|
|
124
|
+
let result = undefined;
|
|
125
|
+
if (x && !util.isPast(x.expiresAt)) {
|
|
126
|
+
result = x; // only return from cache if it is not expired
|
|
127
|
+
}
|
|
128
|
+
return result;
|
|
129
|
+
})),
|
|
130
|
+
successOnMaybe: false,
|
|
131
|
+
throwErrors: false
|
|
132
|
+
});
|
|
133
|
+
const cacheForService = {
|
|
134
|
+
loadCachedToken: function () {
|
|
135
|
+
return loadCachedTokenFromFirstService();
|
|
136
|
+
},
|
|
137
|
+
updateCachedToken: async function (accessToken) {
|
|
138
|
+
return Promise.allSettled(accessCachesForServices.map(x => x.updateCachedToken(accessToken).then(() => null).catch(e => {
|
|
139
|
+
return [x, e];
|
|
140
|
+
}))).then(x => {
|
|
141
|
+
// only find the failures if we're logging
|
|
142
|
+
if (logErrorFunction != null) {
|
|
143
|
+
const failedUpdates = util.filterMaybeArrayValues(x.map(y => y.value));
|
|
144
|
+
if (failedUpdates.length) {
|
|
145
|
+
logErrorFunction(failedUpdates);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
return cacheForService;
|
|
152
|
+
};
|
|
153
|
+
const allServiceAccessTokenCaches = allServices.map(x => x.loadZoomAccessTokenCache());
|
|
154
|
+
const allServicesWithCacheForRefreshToken = allServices.filter(x => x.cacheForRefreshToken != null);
|
|
155
|
+
const cacheForRefreshToken = allServiceAccessTokenCaches.length > 0 ? refreshToken => {
|
|
156
|
+
const allCaches = allServicesWithCacheForRefreshToken.map(x => x.cacheForRefreshToken(refreshToken));
|
|
157
|
+
return loadZoomAccessTokenCache(allCaches);
|
|
158
|
+
} : undefined;
|
|
159
|
+
const service = {
|
|
160
|
+
loadZoomAccessTokenCache: () => loadZoomAccessTokenCache(allServiceAccessTokenCaches),
|
|
161
|
+
cacheForRefreshToken
|
|
162
|
+
};
|
|
163
|
+
return service;
|
|
164
|
+
}
|
|
165
|
+
// MARK: Memory Access Token Cache
|
|
166
|
+
/**
|
|
167
|
+
* Creates a ZoomOAuthAccessTokenCacheService that uses in-memory storage.
|
|
168
|
+
*
|
|
169
|
+
* @returns
|
|
170
|
+
*/
|
|
171
|
+
function memoryZoomOAuthAccessTokenCacheService(existingToken, logAccessToConsole) {
|
|
172
|
+
let token = existingToken;
|
|
173
|
+
function loadZoomAccessTokenCache() {
|
|
174
|
+
const accessTokenCache = {
|
|
175
|
+
loadCachedToken: async function () {
|
|
176
|
+
if (logAccessToConsole) {
|
|
177
|
+
console.log('retrieving access token from memory: ', {
|
|
178
|
+
token
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
return token;
|
|
182
|
+
},
|
|
183
|
+
updateCachedToken: async function (accessToken) {
|
|
184
|
+
token = accessToken;
|
|
185
|
+
if (logAccessToConsole) {
|
|
186
|
+
console.log('updating access token in memory: ', {
|
|
187
|
+
accessToken
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
return accessTokenCache;
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
loadZoomAccessTokenCache,
|
|
196
|
+
cacheForRefreshToken: () => loadZoomAccessTokenCache()
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
// MARK: File System Access Token Cache
|
|
200
|
+
const DEFAULT_FILE_ZOOM_ACCOUNTS_ACCESS_TOKEN_CACHE_SERVICE_PATH = '.tmp/zoom-access-tokens.json';
|
|
201
|
+
/**
|
|
202
|
+
* Creates a ZoomOAuthAccessTokenCacheService that reads and writes the access token to the file system.
|
|
203
|
+
*
|
|
204
|
+
* Useful for testing.
|
|
205
|
+
*
|
|
206
|
+
* @returns
|
|
207
|
+
*/
|
|
208
|
+
function fileZoomOAuthAccessTokenCacheService(filename = DEFAULT_FILE_ZOOM_ACCOUNTS_ACCESS_TOKEN_CACHE_SERVICE_PATH, useMemoryCache = true) {
|
|
209
|
+
let loadedToken = null;
|
|
210
|
+
async function loadTokenFile() {
|
|
211
|
+
let token = undefined;
|
|
212
|
+
if (!loadedToken) {
|
|
213
|
+
token = (await readTokenFile()) ?? {};
|
|
214
|
+
} else {
|
|
215
|
+
token = loadedToken;
|
|
216
|
+
}
|
|
217
|
+
return token;
|
|
218
|
+
}
|
|
219
|
+
function readTokenFile() {
|
|
220
|
+
return new Promise(resolve => {
|
|
221
|
+
fs.mkdirSync(path.dirname(filename), {
|
|
222
|
+
recursive: true
|
|
223
|
+
}); // make the directory first
|
|
224
|
+
fs.readFile(filename, {}, (x, data) => {
|
|
225
|
+
let result = undefined;
|
|
226
|
+
if (!x) {
|
|
227
|
+
try {
|
|
228
|
+
result = JSON.parse(data.toString());
|
|
229
|
+
if (result?.token) {
|
|
230
|
+
result.token.expiresAt = new Date(result.token.expiresAt);
|
|
231
|
+
}
|
|
232
|
+
} catch (e) {
|
|
233
|
+
console.error('Failed reading token file: ', e);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
resolve(result);
|
|
237
|
+
});
|
|
238
|
+
}).then(x => {
|
|
239
|
+
// update loaded tokens
|
|
240
|
+
if (useMemoryCache) {
|
|
241
|
+
loadedToken = {
|
|
242
|
+
...loadedToken,
|
|
243
|
+
...x
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
return x;
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
async function writeTokenFile(tokens) {
|
|
250
|
+
return new Promise((resolve, reject) => {
|
|
251
|
+
fs.writeFile(filename, JSON.stringify(tokens), {}, x => {
|
|
252
|
+
if (!x) {
|
|
253
|
+
resolve();
|
|
254
|
+
} else {
|
|
255
|
+
reject(x);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
async function deleteTokenFile() {
|
|
261
|
+
return new Promise((resolve, reject) => {
|
|
262
|
+
fs.rm(filename, x => {
|
|
263
|
+
if (!x) {
|
|
264
|
+
resolve();
|
|
265
|
+
} else {
|
|
266
|
+
reject(x);
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
function loadZoomAccessTokenCache() {
|
|
272
|
+
const accessTokenCache = {
|
|
273
|
+
loadCachedToken: async function () {
|
|
274
|
+
const tokens = await loadTokenFile();
|
|
275
|
+
const token = tokens.token;
|
|
276
|
+
// console.log('retrieving access token from file: ', { token });
|
|
277
|
+
return token;
|
|
278
|
+
},
|
|
279
|
+
updateCachedToken: async function (accessToken) {
|
|
280
|
+
const tokenFile = await loadTokenFile();
|
|
281
|
+
if (tokenFile) {
|
|
282
|
+
tokenFile.token = accessToken;
|
|
283
|
+
}
|
|
284
|
+
// console.log('updating access token in file: ', { accessToken });
|
|
285
|
+
try {
|
|
286
|
+
await writeTokenFile(tokenFile);
|
|
287
|
+
} catch (e) {
|
|
288
|
+
console.error('Failed updating access token in file: ', e);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
return accessTokenCache;
|
|
293
|
+
}
|
|
294
|
+
return {
|
|
295
|
+
loadZoomAccessTokenCache,
|
|
296
|
+
readTokenFile,
|
|
297
|
+
writeTokenFile,
|
|
298
|
+
deleteTokenFile
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
exports.ZoomOAuthApi = class ZoomOAuthApi {
|
|
303
|
+
config;
|
|
304
|
+
cacheService;
|
|
305
|
+
zoomOAuth;
|
|
306
|
+
get oauthContext() {
|
|
307
|
+
return this.zoomOAuth.oauthContext;
|
|
308
|
+
}
|
|
309
|
+
constructor(config, cacheService) {
|
|
310
|
+
this.config = config;
|
|
311
|
+
this.cacheService = cacheService;
|
|
312
|
+
const accessTokenCache = config.zoomOAuth.accessTokenCache ? config.zoomOAuth.accessTokenCache : cacheService.loadZoomAccessTokenCache();
|
|
313
|
+
this.zoomOAuth = zoom.zoomOAuthFactory(config.factoryConfig ?? {})({
|
|
314
|
+
accessTokenCache,
|
|
315
|
+
...config.zoomOAuth
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
// MARK: Accessors
|
|
319
|
+
get serverAccessToken() {
|
|
320
|
+
return zoom.serverAccessToken(this.oauthContext);
|
|
321
|
+
}
|
|
322
|
+
get userAccessToken() {
|
|
323
|
+
return zoom.userAccessToken(this.oauthContext);
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
exports.ZoomOAuthApi = __decorate([common.Injectable(), __param(0, common.Inject(ZoomOAuthServiceConfig)), __param(1, common.Inject(exports.ZoomOAuthAccessTokenCacheService)), __metadata("design:paramtypes", [ZoomOAuthServiceConfig, exports.ZoomOAuthAccessTokenCacheService])], exports.ZoomOAuthApi);
|
|
327
|
+
|
|
328
|
+
function zoomOAuthServiceConfigFactory(configService) {
|
|
329
|
+
const config = readZoomOAuthServiceConfigFromConfigService(configService);
|
|
330
|
+
return config;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Convenience function used to generate ModuleMetadata for an app's ZoomOAuthModule.
|
|
334
|
+
*
|
|
335
|
+
* @param provide
|
|
336
|
+
* @param useFactory
|
|
337
|
+
* @returns
|
|
338
|
+
*/
|
|
339
|
+
function appZoomOAuthModuleMetadata(config$1) {
|
|
340
|
+
const {
|
|
341
|
+
dependencyModule,
|
|
342
|
+
imports,
|
|
343
|
+
exports: exports$1,
|
|
344
|
+
providers
|
|
345
|
+
} = config$1;
|
|
346
|
+
const dependencyModuleImport = dependencyModule ? [dependencyModule] : [];
|
|
347
|
+
return {
|
|
348
|
+
imports: [config.ConfigModule, ...dependencyModuleImport, ...(imports ?? [])],
|
|
349
|
+
exports: [exports.ZoomOAuthApi, ...(exports$1 ?? [])],
|
|
350
|
+
providers: [{
|
|
351
|
+
provide: ZoomOAuthServiceConfig,
|
|
352
|
+
inject: [config.ConfigService],
|
|
353
|
+
useFactory: config$1.zoomOAuthServiceConfigFactory ?? zoomOAuthServiceConfigFactory
|
|
354
|
+
}, exports.ZoomOAuthApi, ...(providers ?? [])]
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const ZOOM_SECRET_TOKEN_ENV_VAR = 'ZOOM_SECRET_TOKEN';
|
|
359
|
+
/**
|
|
360
|
+
* Configuration for ZoomService
|
|
361
|
+
*/
|
|
362
|
+
class ZoomWebhookServiceConfig {
|
|
363
|
+
webhookConfig;
|
|
364
|
+
static assertValidConfig(config) {
|
|
365
|
+
if (!config.webhookConfig.zoomSecretToken) {
|
|
366
|
+
throw new Error('No zoom secret token specified.');
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// MARK: Meeting Alert
|
|
372
|
+
const ZOOM_WEBHOOK_MEETING_ALERT_EVENT_TYPE = 'meeting.alert';
|
|
373
|
+
// MARK: Meeting Created
|
|
374
|
+
const ZOOM_WEBHOOK_MEETING_CREATED_EVENT_TYPE = 'meeting.created';
|
|
375
|
+
// MARK: Meeting Updated
|
|
376
|
+
const ZOOM_WEBHOOK_MEETING_UPDATED_EVENT_TYPE = 'meeting.updated';
|
|
377
|
+
// MARK: Meeting Deleted
|
|
378
|
+
const ZOOM_WEBHOOK_MEETING_DELETED_EVENT_TYPE = 'meeting.deleted';
|
|
379
|
+
// MARK: Meeting Started
|
|
380
|
+
const ZOOM_WEBHOOK_MEETING_STARTED_EVENT_TYPE = 'meeting.started';
|
|
381
|
+
// MARK: Meeting Ended
|
|
382
|
+
const ZOOM_WEBHOOK_MEETING_ENDED_EVENT_TYPE = 'meeting.ended';
|
|
383
|
+
// MARK: Meeting Permanently Deleted
|
|
384
|
+
const ZOOM_WEBHOOK_MEETING_PERMANENTLY_DELETED_EVENT_TYPE = 'meeting.permanently_deleted';
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Creates a ZoomWebhookEvent and treats the data as the input type.
|
|
388
|
+
*
|
|
389
|
+
* @param event
|
|
390
|
+
* @returns
|
|
391
|
+
*/
|
|
392
|
+
function zoomWebhookEvent(event) {
|
|
393
|
+
return {
|
|
394
|
+
event: event.event,
|
|
395
|
+
event_ts: event.event_ts,
|
|
396
|
+
payload: event.payload
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
const zoomEventHandlerFactory = util.handlerFactory(x => x.event);
|
|
400
|
+
const zoomEventHandlerConfigurerFactory = util.handlerConfigurerFactory({
|
|
401
|
+
configurerForAccessor: accessor => {
|
|
402
|
+
// eslint-disable-next-line
|
|
403
|
+
const fnWithKey = util.handlerMappedSetFunctionFactory(accessor, zoomWebhookEvent);
|
|
404
|
+
const configurer = {
|
|
405
|
+
...accessor,
|
|
406
|
+
// Meetings
|
|
407
|
+
handleMeetingCreated: fnWithKey(ZOOM_WEBHOOK_MEETING_CREATED_EVENT_TYPE),
|
|
408
|
+
handleMeetingUpdated: fnWithKey(ZOOM_WEBHOOK_MEETING_UPDATED_EVENT_TYPE),
|
|
409
|
+
handleMeetingDeleted: fnWithKey(ZOOM_WEBHOOK_MEETING_DELETED_EVENT_TYPE),
|
|
410
|
+
handleMeetingStarted: fnWithKey(ZOOM_WEBHOOK_MEETING_STARTED_EVENT_TYPE),
|
|
411
|
+
handleMeetingEnded: fnWithKey(ZOOM_WEBHOOK_MEETING_ENDED_EVENT_TYPE),
|
|
412
|
+
handleMeetingPermanentlyDeleted: fnWithKey(ZOOM_WEBHOOK_MEETING_PERMANENTLY_DELETED_EVENT_TYPE)
|
|
413
|
+
};
|
|
414
|
+
return configurer;
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Verifies a Zoom webhook event header.
|
|
420
|
+
*
|
|
421
|
+
* @see https://developers.zoom.us/docs/api/webhooks/#verify-with-zooms-header
|
|
422
|
+
*
|
|
423
|
+
* @param zoomSecretToken The Zoom secret token.
|
|
424
|
+
* @returns A function that verifies a Zoom webhook event.
|
|
425
|
+
*/
|
|
426
|
+
function zoomWebhookEventVerifier(zoomSecretToken) {
|
|
427
|
+
return (request, rawBody) => {
|
|
428
|
+
const requestBodyString = String(request.body);
|
|
429
|
+
const message = `v0:${request.headers['x-zm-request-timestamp']}:${requestBodyString}`;
|
|
430
|
+
const hashForVerify = crypto.createHmac('sha256', zoomSecretToken).update(message).digest('hex');
|
|
431
|
+
const signature = `v0=${hashForVerify}`;
|
|
432
|
+
const valid = request.headers['x-zm-signature'] === signature;
|
|
433
|
+
const result = {
|
|
434
|
+
valid,
|
|
435
|
+
event: JSON.parse(requestBodyString)
|
|
436
|
+
};
|
|
437
|
+
return result;
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const ZOOM_WEBHOOK_URL_VALIDATION_EVENT_TYPE = 'endpoint.url_validation';
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Creates a ZoomWebhookEventValidationFunction.
|
|
445
|
+
*
|
|
446
|
+
* @param zoomSecretToken The secret token used to validate the event.
|
|
447
|
+
* @returns A ZoomWebhookEventValidationFunction.
|
|
448
|
+
*/
|
|
449
|
+
function zoomWebhookEventValidationFunction(zoomSecretToken) {
|
|
450
|
+
return event => {
|
|
451
|
+
const {
|
|
452
|
+
plainToken
|
|
453
|
+
} = event.payload;
|
|
454
|
+
if (!plainToken) {
|
|
455
|
+
throw new Error(`The expected plaintoken value was not provided by the event's payload.`);
|
|
456
|
+
}
|
|
457
|
+
const encryptedToken = crypto.createHmac('sha256', zoomSecretToken).update(plainToken).digest('hex');
|
|
458
|
+
const result = {
|
|
459
|
+
plainToken,
|
|
460
|
+
encryptedToken
|
|
461
|
+
};
|
|
462
|
+
return result;
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Service that makes system changes based on Zoom webhook events.
|
|
468
|
+
*/
|
|
469
|
+
exports.ZoomWebhookService = class ZoomWebhookService {
|
|
470
|
+
logger = new common.Logger('ZoomWebhookService');
|
|
471
|
+
_verifier;
|
|
472
|
+
_validator;
|
|
473
|
+
handler = zoomEventHandlerFactory();
|
|
474
|
+
configure = zoomEventHandlerConfigurerFactory(this.handler);
|
|
475
|
+
constructor(config) {
|
|
476
|
+
this._verifier = zoomWebhookEventVerifier(config.webhookConfig.zoomSecretToken);
|
|
477
|
+
this._validator = zoomWebhookEventValidationFunction(config.webhookConfig.zoomSecretToken);
|
|
478
|
+
}
|
|
479
|
+
async updateForWebhook(req, rawBody) {
|
|
480
|
+
const {
|
|
481
|
+
valid,
|
|
482
|
+
event
|
|
483
|
+
} = this._verifier(req, rawBody);
|
|
484
|
+
let handled = false;
|
|
485
|
+
let validationEventResponse;
|
|
486
|
+
if (!valid) {
|
|
487
|
+
this.logger.warn('Received invalid zoom event: ', event);
|
|
488
|
+
} else if (event.event === ZOOM_WEBHOOK_URL_VALIDATION_EVENT_TYPE) {
|
|
489
|
+
validationEventResponse = this._validator(event);
|
|
490
|
+
handled = true;
|
|
491
|
+
} else {
|
|
492
|
+
handled = await this.updateForZoomEvent(event);
|
|
493
|
+
}
|
|
494
|
+
const result = {
|
|
495
|
+
valid,
|
|
496
|
+
handled,
|
|
497
|
+
event,
|
|
498
|
+
validationEventResponse
|
|
499
|
+
};
|
|
500
|
+
return result;
|
|
501
|
+
}
|
|
502
|
+
async updateForZoomEvent(event) {
|
|
503
|
+
const handled = await this.handler(event);
|
|
504
|
+
if (!handled) {
|
|
505
|
+
this.logger.warn('Received unexpected/unhandled zoom event: ', event);
|
|
506
|
+
}
|
|
507
|
+
return handled;
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
exports.ZoomWebhookService = __decorate([common.Injectable(), __param(0, common.Inject(ZoomWebhookServiceConfig)), __metadata("design:paramtypes", [ZoomWebhookServiceConfig])], exports.ZoomWebhookService);
|
|
511
|
+
|
|
512
|
+
exports.ZoomWebhookController = class ZoomWebhookController {
|
|
513
|
+
zoomWebhookService;
|
|
514
|
+
constructor(zoomWebhookService) {
|
|
515
|
+
this.zoomWebhookService = zoomWebhookService;
|
|
516
|
+
}
|
|
517
|
+
async handleZoomWebhook(res, req, rawBody) {
|
|
518
|
+
const {
|
|
519
|
+
valid,
|
|
520
|
+
validationEventResponse
|
|
521
|
+
} = await this.zoomWebhookService.updateForWebhook(req, rawBody);
|
|
522
|
+
const response = res.status(200); // always return a 200 status code
|
|
523
|
+
if (valid && validationEventResponse) {
|
|
524
|
+
response.json(validationEventResponse);
|
|
525
|
+
} else {
|
|
526
|
+
response.json({});
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
__decorate([common.Post(), __param(0, common.Res()), __param(1, common.Req()), __param(2, nestjs.RawBody()), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object, Object]), __metadata("design:returntype", Promise)], exports.ZoomWebhookController.prototype, "handleZoomWebhook", null);
|
|
531
|
+
exports.ZoomWebhookController = __decorate([common.Controller('/webhook/zoom'), __param(0, common.Inject(exports.ZoomWebhookService)), __metadata("design:paramtypes", [exports.ZoomWebhookService])], exports.ZoomWebhookController);
|
|
532
|
+
|
|
533
|
+
function zoomWebhookServiceConfigFactory(configService) {
|
|
534
|
+
const config = {
|
|
535
|
+
webhookConfig: {
|
|
536
|
+
zoomSecretToken: configService.get(ZOOM_SECRET_TOKEN_ENV_VAR)
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
ZoomWebhookServiceConfig.assertValidConfig(config);
|
|
540
|
+
return config;
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Configures webhooks for the service.
|
|
544
|
+
*/
|
|
545
|
+
exports.ZoomWebhookModule = class ZoomWebhookModule {};
|
|
546
|
+
exports.ZoomWebhookModule = __decorate([common.Module({
|
|
547
|
+
imports: [config.ConfigModule],
|
|
548
|
+
controllers: [exports.ZoomWebhookController],
|
|
549
|
+
exports: [exports.ZoomWebhookService],
|
|
550
|
+
providers: [{
|
|
551
|
+
provide: ZoomWebhookServiceConfig,
|
|
552
|
+
inject: [config.ConfigService],
|
|
553
|
+
useFactory: zoomWebhookServiceConfigFactory
|
|
554
|
+
}, exports.ZoomWebhookService]
|
|
555
|
+
})], exports.ZoomWebhookModule);
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* Configuration for ZoomService
|
|
559
|
+
*/
|
|
560
|
+
class ZoomServiceConfig {
|
|
561
|
+
zoom;
|
|
562
|
+
factoryConfig;
|
|
563
|
+
static assertValidConfig(config) {
|
|
564
|
+
// TODO?
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
exports.ZoomApi = class ZoomApi {
|
|
569
|
+
config;
|
|
570
|
+
zoomOAuthApi;
|
|
571
|
+
zoom;
|
|
572
|
+
get zoomContext() {
|
|
573
|
+
return this.zoom.zoomServerContext;
|
|
574
|
+
}
|
|
575
|
+
get zoomRateLimiter() {
|
|
576
|
+
return this.zoom.zoomServerContext.zoomRateLimiter;
|
|
577
|
+
}
|
|
578
|
+
constructor(config, zoomOAuthApi) {
|
|
579
|
+
this.config = config;
|
|
580
|
+
this.zoomOAuthApi = zoomOAuthApi;
|
|
581
|
+
this.zoom = zoom.zoomFactory({
|
|
582
|
+
...config.factoryConfig,
|
|
583
|
+
oauthContext: zoomOAuthApi.oauthContext
|
|
584
|
+
})(config.zoom);
|
|
585
|
+
}
|
|
586
|
+
// MARK: Users
|
|
587
|
+
get getUser() {
|
|
588
|
+
return zoom.getUser(this.zoomContext);
|
|
589
|
+
}
|
|
590
|
+
get listUsers() {
|
|
591
|
+
return zoom.listUsers(this.zoomContext);
|
|
592
|
+
}
|
|
593
|
+
get listUsersPageFactory() {
|
|
594
|
+
return zoom.listUsersPageFactory(this.zoomContext);
|
|
595
|
+
}
|
|
596
|
+
// MARK: Meetings
|
|
597
|
+
get listMeetingsForUser() {
|
|
598
|
+
return zoom.listMeetingsForUser(this.zoomContext);
|
|
599
|
+
}
|
|
600
|
+
get listMeetingsForUserPageFactory() {
|
|
601
|
+
return zoom.listMeetingsForUserPageFactory(this.zoomContext);
|
|
602
|
+
}
|
|
603
|
+
get createMeetingForUser() {
|
|
604
|
+
return zoom.createMeetingForUser(this.zoomContext);
|
|
605
|
+
}
|
|
606
|
+
get getMeeting() {
|
|
607
|
+
return zoom.getMeeting(this.zoomContext);
|
|
608
|
+
}
|
|
609
|
+
get updateMeeting() {
|
|
610
|
+
return zoom.updateMeeting(this.zoomContext);
|
|
611
|
+
}
|
|
612
|
+
get deleteMeeting() {
|
|
613
|
+
return zoom.deleteMeeting(this.zoomContext);
|
|
614
|
+
}
|
|
615
|
+
// MARK: Past Meetings
|
|
616
|
+
get getPastMeeting() {
|
|
617
|
+
return zoom.getPastMeeting(this.zoomContext);
|
|
618
|
+
}
|
|
619
|
+
get getPastMeetingParticipants() {
|
|
620
|
+
return zoom.getPastMeetingParticipants(this.zoomContext);
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
exports.ZoomApi = __decorate([common.Injectable(), __param(0, common.Inject(ZoomServiceConfig)), __param(1, common.Inject(exports.ZoomOAuthApi)), __metadata("design:paramtypes", [ZoomServiceConfig, exports.ZoomOAuthApi])], exports.ZoomApi);
|
|
624
|
+
class ZoomApiUserContext {
|
|
625
|
+
constructor(refreshToken) {
|
|
626
|
+
// TODO: ...
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// MARK: Provider Factories
|
|
631
|
+
function zoomServiceConfigFactory(configService) {
|
|
632
|
+
const config = {
|
|
633
|
+
zoom: {}
|
|
634
|
+
};
|
|
635
|
+
ZoomServiceConfig.assertValidConfig(config);
|
|
636
|
+
return config;
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Convenience function used to generate ModuleMetadata for an app's ZoomModule.
|
|
640
|
+
*
|
|
641
|
+
* @param provide
|
|
642
|
+
* @param useFactory
|
|
643
|
+
* @returns
|
|
644
|
+
*/
|
|
645
|
+
function appZoomModuleMetadata(config$1) {
|
|
646
|
+
const {
|
|
647
|
+
dependencyModule,
|
|
648
|
+
imports,
|
|
649
|
+
exports: exports$1,
|
|
650
|
+
providers
|
|
651
|
+
} = config$1;
|
|
652
|
+
const dependencyModuleImport = dependencyModule ? [dependencyModule] : [];
|
|
653
|
+
return {
|
|
654
|
+
imports: [config.ConfigModule, ...dependencyModuleImport, ...(imports ?? [])],
|
|
655
|
+
exports: [exports.ZoomApi, ...(exports$1 ?? [])],
|
|
656
|
+
providers: [{
|
|
657
|
+
provide: ZoomServiceConfig,
|
|
658
|
+
inject: [config.ConfigService],
|
|
659
|
+
useFactory: zoomServiceConfigFactory
|
|
660
|
+
}, exports.ZoomApi, ...(providers ?? [])]
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
exports.DEFAULT_FILE_ZOOM_ACCOUNTS_ACCESS_TOKEN_CACHE_SERVICE_PATH = DEFAULT_FILE_ZOOM_ACCOUNTS_ACCESS_TOKEN_CACHE_SERVICE_PATH;
|
|
665
|
+
exports.ZOOM_SECRET_TOKEN_ENV_VAR = ZOOM_SECRET_TOKEN_ENV_VAR;
|
|
666
|
+
exports.ZOOM_WEBHOOK_MEETING_ALERT_EVENT_TYPE = ZOOM_WEBHOOK_MEETING_ALERT_EVENT_TYPE;
|
|
667
|
+
exports.ZOOM_WEBHOOK_MEETING_CREATED_EVENT_TYPE = ZOOM_WEBHOOK_MEETING_CREATED_EVENT_TYPE;
|
|
668
|
+
exports.ZOOM_WEBHOOK_MEETING_DELETED_EVENT_TYPE = ZOOM_WEBHOOK_MEETING_DELETED_EVENT_TYPE;
|
|
669
|
+
exports.ZOOM_WEBHOOK_MEETING_ENDED_EVENT_TYPE = ZOOM_WEBHOOK_MEETING_ENDED_EVENT_TYPE;
|
|
670
|
+
exports.ZOOM_WEBHOOK_MEETING_PERMANENTLY_DELETED_EVENT_TYPE = ZOOM_WEBHOOK_MEETING_PERMANENTLY_DELETED_EVENT_TYPE;
|
|
671
|
+
exports.ZOOM_WEBHOOK_MEETING_STARTED_EVENT_TYPE = ZOOM_WEBHOOK_MEETING_STARTED_EVENT_TYPE;
|
|
672
|
+
exports.ZOOM_WEBHOOK_MEETING_UPDATED_EVENT_TYPE = ZOOM_WEBHOOK_MEETING_UPDATED_EVENT_TYPE;
|
|
673
|
+
exports.ZOOM_WEBHOOK_URL_VALIDATION_EVENT_TYPE = ZOOM_WEBHOOK_URL_VALIDATION_EVENT_TYPE;
|
|
674
|
+
exports.ZoomApiUserContext = ZoomApiUserContext;
|
|
675
|
+
exports.ZoomOAuthServiceConfig = ZoomOAuthServiceConfig;
|
|
676
|
+
exports.ZoomServiceConfig = ZoomServiceConfig;
|
|
677
|
+
exports.ZoomWebhookServiceConfig = ZoomWebhookServiceConfig;
|
|
678
|
+
exports.appZoomModuleMetadata = appZoomModuleMetadata;
|
|
679
|
+
exports.appZoomOAuthModuleMetadata = appZoomOAuthModuleMetadata;
|
|
680
|
+
exports.fileZoomOAuthAccessTokenCacheService = fileZoomOAuthAccessTokenCacheService;
|
|
681
|
+
exports.logMergeZoomOAuthAccessTokenCacheServiceErrorFunction = logMergeZoomOAuthAccessTokenCacheServiceErrorFunction;
|
|
682
|
+
exports.memoryZoomOAuthAccessTokenCacheService = memoryZoomOAuthAccessTokenCacheService;
|
|
683
|
+
exports.mergeZoomOAuthAccessTokenCacheServices = mergeZoomOAuthAccessTokenCacheServices;
|
|
684
|
+
exports.readZoomOAuthServiceConfigFromConfigService = readZoomOAuthServiceConfigFromConfigService;
|
|
685
|
+
exports.zoomEventHandlerConfigurerFactory = zoomEventHandlerConfigurerFactory;
|
|
686
|
+
exports.zoomEventHandlerFactory = zoomEventHandlerFactory;
|
|
687
|
+
exports.zoomOAuthServiceConfigFactory = zoomOAuthServiceConfigFactory;
|
|
688
|
+
exports.zoomServiceConfigFactory = zoomServiceConfigFactory;
|
|
689
|
+
exports.zoomWebhookEvent = zoomWebhookEvent;
|
|
690
|
+
exports.zoomWebhookEventValidationFunction = zoomWebhookEventValidationFunction;
|
|
691
|
+
exports.zoomWebhookEventVerifier = zoomWebhookEventVerifier;
|
|
692
|
+
exports.zoomWebhookServiceConfigFactory = zoomWebhookServiceConfigFactory;
|