@microsoft/teamsfx 3.0.0-beta.2024112506.0 → 3.0.0-rc.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/dist/index.esm2017.js +1 -1734
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +16 -3577
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +15 -1778
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +15 -3735
- package/dist/index.node.cjs.js.map +1 -1
- package/package.json +8 -8
- package/types/teamsfx.d.ts +0 -2181
package/dist/index.node.cjs.js
CHANGED
@@ -1,3736 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
var fs = require('fs');
|
16
|
-
|
17
|
-
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
18
|
-
|
19
|
-
function _interopNamespace(e) {
|
20
|
-
if (e && e.__esModule) return e;
|
21
|
-
var n = Object.create(null);
|
22
|
-
if (e) {
|
23
|
-
Object.keys(e).forEach(function (k) {
|
24
|
-
if (k !== 'default') {
|
25
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
26
|
-
Object.defineProperty(n, k, d.get ? d : {
|
27
|
-
enumerable: true,
|
28
|
-
get: function () { return e[k]; }
|
29
|
-
});
|
30
|
-
}
|
31
|
-
});
|
32
|
-
}
|
33
|
-
n["default"] = e;
|
34
|
-
return Object.freeze(n);
|
35
|
-
}
|
36
|
-
|
37
|
-
var axios__default = /*#__PURE__*/_interopDefaultLegacy(axios);
|
38
|
-
var ACData__namespace = /*#__PURE__*/_interopNamespace(ACData);
|
39
|
-
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
40
|
-
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
41
|
-
|
42
|
-
// Copyright (c) Microsoft Corporation.
|
43
|
-
// Licensed under the MIT license.
|
44
|
-
/**
|
45
|
-
* Error code to trace the error types.
|
46
|
-
*/
|
47
|
-
exports.ErrorCode = void 0;
|
48
|
-
(function (ErrorCode) {
|
49
|
-
/**
|
50
|
-
* Invalid parameter error.
|
51
|
-
*/
|
52
|
-
ErrorCode["InvalidParameter"] = "InvalidParameter";
|
53
|
-
/**
|
54
|
-
* Invalid configuration error.
|
55
|
-
*/
|
56
|
-
ErrorCode["InvalidConfiguration"] = "InvalidConfiguration";
|
57
|
-
/**
|
58
|
-
* Invalid certificate error.
|
59
|
-
*/
|
60
|
-
ErrorCode["InvalidCertificate"] = "InvalidCertificate";
|
61
|
-
/**
|
62
|
-
* Internal error.
|
63
|
-
*/
|
64
|
-
ErrorCode["InternalError"] = "InternalError";
|
65
|
-
/**
|
66
|
-
* Channel is not supported error.
|
67
|
-
*/
|
68
|
-
ErrorCode["ChannelNotSupported"] = "ChannelNotSupported";
|
69
|
-
/**
|
70
|
-
* Failed to retrieve sso token
|
71
|
-
*/
|
72
|
-
ErrorCode["FailedToRetrieveSsoToken"] = "FailedToRetrieveSsoToken";
|
73
|
-
/**
|
74
|
-
* Failed to process sso handler
|
75
|
-
*/
|
76
|
-
ErrorCode["FailedToProcessSsoHandler"] = "FailedToProcessSsoHandler";
|
77
|
-
/**
|
78
|
-
* Cannot find command
|
79
|
-
*/
|
80
|
-
ErrorCode["CannotFindCommand"] = "CannotFindCommand";
|
81
|
-
/**
|
82
|
-
* Failed to run sso step
|
83
|
-
*/
|
84
|
-
ErrorCode["FailedToRunSsoStep"] = "FailedToRunSsoStep";
|
85
|
-
/**
|
86
|
-
* Failed to run dedup step
|
87
|
-
*/
|
88
|
-
ErrorCode["FailedToRunDedupStep"] = "FailedToRunDedupStep";
|
89
|
-
/**
|
90
|
-
* Sso activity handler is undefined
|
91
|
-
*/
|
92
|
-
ErrorCode["SsoActivityHandlerIsUndefined"] = "SsoActivityHandlerIsUndefined";
|
93
|
-
/**
|
94
|
-
* Runtime is not supported error.
|
95
|
-
*/
|
96
|
-
ErrorCode["RuntimeNotSupported"] = "RuntimeNotSupported";
|
97
|
-
/**
|
98
|
-
* User failed to finish the AAD consent flow failed.
|
99
|
-
*/
|
100
|
-
ErrorCode["ConsentFailed"] = "ConsentFailed";
|
101
|
-
/**
|
102
|
-
* The user or administrator has not consented to use the application error.
|
103
|
-
*/
|
104
|
-
ErrorCode["UiRequiredError"] = "UiRequiredError";
|
105
|
-
/**
|
106
|
-
* Token is not within its valid time range error.
|
107
|
-
*/
|
108
|
-
ErrorCode["TokenExpiredError"] = "TokenExpiredError";
|
109
|
-
/**
|
110
|
-
* Call service (AAD or simple authentication server) failed.
|
111
|
-
*/
|
112
|
-
ErrorCode["ServiceError"] = "ServiceError";
|
113
|
-
/**
|
114
|
-
* Operation failed.
|
115
|
-
*/
|
116
|
-
ErrorCode["FailedOperation"] = "FailedOperation";
|
117
|
-
/**
|
118
|
-
* Invalid response error.
|
119
|
-
*/
|
120
|
-
ErrorCode["InvalidResponse"] = "InvalidResponse";
|
121
|
-
/**
|
122
|
-
* Authentication info already exists error.
|
123
|
-
*/
|
124
|
-
ErrorCode["AuthorizationInfoAlreadyExists"] = "AuthorizationInfoAlreadyExists";
|
125
|
-
})(exports.ErrorCode || (exports.ErrorCode = {}));
|
126
|
-
/**
|
127
|
-
* @internal
|
128
|
-
*/
|
129
|
-
class ErrorMessage {
|
130
|
-
}
|
131
|
-
// InvalidConfiguration Error
|
132
|
-
ErrorMessage.InvalidConfiguration = "{0} in configuration is invalid: {1}.";
|
133
|
-
ErrorMessage.ConfigurationNotExists = "Configuration does not exist. {0}";
|
134
|
-
ErrorMessage.ResourceConfigurationNotExists = "{0} resource configuration does not exist.";
|
135
|
-
ErrorMessage.MissingResourceConfiguration = "Missing resource configuration with type: {0}, name: {1}.";
|
136
|
-
ErrorMessage.AuthenticationConfigurationNotExists = "Authentication configuration does not exist.";
|
137
|
-
// RuntimeNotSupported Error
|
138
|
-
ErrorMessage.BrowserRuntimeNotSupported = "{0} is not supported in browser.";
|
139
|
-
ErrorMessage.NodejsRuntimeNotSupported = "{0} is not supported in Node.";
|
140
|
-
// Internal Error
|
141
|
-
ErrorMessage.FailToAcquireTokenOnBehalfOfUser = "Failed to acquire access token on behalf of user: {0}";
|
142
|
-
// ChannelNotSupported Error
|
143
|
-
ErrorMessage.OnlyMSTeamsChannelSupported = "{0} is only supported in MS Teams Channel";
|
144
|
-
ErrorMessage.FailedToProcessSsoHandler = "Failed to process sso handler: {0}";
|
145
|
-
// FailedToRetrieveSsoToken Error
|
146
|
-
ErrorMessage.FailedToRetrieveSsoToken = "Failed to retrieve sso token, user failed to finish the AAD consent flow.";
|
147
|
-
// CannotFindCommand Error
|
148
|
-
ErrorMessage.CannotFindCommand = "Cannot find command: {0}";
|
149
|
-
ErrorMessage.FailedToRunSsoStep = "Failed to run dialog to retrieve sso token: {0}";
|
150
|
-
ErrorMessage.FailedToRunDedupStep = "Failed to run dialog to remove duplicated messages: {0}";
|
151
|
-
// SsoActivityHandlerIsUndefined Error
|
152
|
-
ErrorMessage.SsoActivityHandlerIsNull = "Sso command can only be used or added when sso activity handler is not undefined";
|
153
|
-
// AuthorizationInfoError
|
154
|
-
ErrorMessage.AuthorizationHeaderAlreadyExists = "Authorization header already exists!";
|
155
|
-
ErrorMessage.BasicCredentialAlreadyExists = "Basic credential already exists!";
|
156
|
-
// InvalidParameter Error
|
157
|
-
ErrorMessage.EmptyParameter = "Parameter {0} is empty";
|
158
|
-
ErrorMessage.DuplicateHttpsOptionProperty = "Axios HTTPS agent already defined value for property {0}";
|
159
|
-
ErrorMessage.DuplicateApiKeyInHeader = "The request already defined api key in request header with name {0}.";
|
160
|
-
ErrorMessage.DuplicateApiKeyInQueryParam = "The request already defined api key in query parameter with name {0}.";
|
161
|
-
ErrorMessage.OnlySupportInQueryActivity = "The handleMessageExtensionQueryWithToken only support in handleTeamsMessagingExtensionQuery with composeExtension/query type.";
|
162
|
-
ErrorMessage.OnlySupportInLinkQueryActivity = "The handleMessageExtensionLinkQueryWithSSO only support in handleTeamsAppBasedLinkQuery with composeExtension/queryLink type.";
|
163
|
-
/**
|
164
|
-
* Error class with code and message thrown by the SDK.
|
165
|
-
*/
|
166
|
-
class ErrorWithCode extends Error {
|
167
|
-
/**
|
168
|
-
* Constructor of ErrorWithCode.
|
169
|
-
*
|
170
|
-
* @param {string} message - error message.
|
171
|
-
* @param {ErrorCode} code - error code.
|
172
|
-
*/
|
173
|
-
constructor(message, code) {
|
174
|
-
if (!code) {
|
175
|
-
super(message);
|
176
|
-
return this;
|
177
|
-
}
|
178
|
-
super(message);
|
179
|
-
Object.setPrototypeOf(this, ErrorWithCode.prototype);
|
180
|
-
this.name = `${new.target.name}.${code}`;
|
181
|
-
this.code = code;
|
182
|
-
}
|
183
|
-
}
|
184
|
-
|
185
|
-
/******************************************************************************
|
186
|
-
Copyright (c) Microsoft Corporation.
|
187
|
-
|
188
|
-
Permission to use, copy, modify, and/or distribute this software for any
|
189
|
-
purpose with or without fee is hereby granted.
|
190
|
-
|
191
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
192
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
193
|
-
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
194
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
195
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
196
|
-
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
197
|
-
PERFORMANCE OF THIS SOFTWARE.
|
198
|
-
***************************************************************************** */
|
199
|
-
|
200
|
-
function __rest(s, e) {
|
201
|
-
var t = {};
|
202
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
203
|
-
t[p] = s[p];
|
204
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
205
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
206
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
207
|
-
t[p[i]] = s[p[i]];
|
208
|
-
}
|
209
|
-
return t;
|
210
|
-
}
|
211
|
-
|
212
|
-
function __awaiter(thisArg, _arguments, P, generator) {
|
213
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
214
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
215
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
216
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
217
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
218
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
219
|
-
});
|
220
|
-
}
|
221
|
-
|
222
|
-
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
223
|
-
var e = new Error(message);
|
224
|
-
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
225
|
-
};
|
226
|
-
|
227
|
-
// Copyright (c) Microsoft Corporation.
|
228
|
-
// Licensed under the MIT license.
|
229
|
-
/**
|
230
|
-
* Log level.
|
231
|
-
*/
|
232
|
-
exports.LogLevel = void 0;
|
233
|
-
(function (LogLevel) {
|
234
|
-
/**
|
235
|
-
* Show verbose, information, warning and error message.
|
236
|
-
*/
|
237
|
-
LogLevel[LogLevel["Verbose"] = 0] = "Verbose";
|
238
|
-
/**
|
239
|
-
* Show information, warning and error message.
|
240
|
-
*/
|
241
|
-
LogLevel[LogLevel["Info"] = 1] = "Info";
|
242
|
-
/**
|
243
|
-
* Show warning and error message.
|
244
|
-
*/
|
245
|
-
LogLevel[LogLevel["Warn"] = 2] = "Warn";
|
246
|
-
/**
|
247
|
-
* Show error message.
|
248
|
-
*/
|
249
|
-
LogLevel[LogLevel["Error"] = 3] = "Error";
|
250
|
-
})(exports.LogLevel || (exports.LogLevel = {}));
|
251
|
-
/**
|
252
|
-
* Update log level helper.
|
253
|
-
*
|
254
|
-
* @param { LogLevel } level - log level in configuration
|
255
|
-
*/
|
256
|
-
function setLogLevel(level) {
|
257
|
-
internalLogger.level = level;
|
258
|
-
}
|
259
|
-
/**
|
260
|
-
* Get log level.
|
261
|
-
*
|
262
|
-
* @returns Log level
|
263
|
-
*/
|
264
|
-
function getLogLevel() {
|
265
|
-
return internalLogger.level;
|
266
|
-
}
|
267
|
-
class InternalLogger {
|
268
|
-
constructor(name, logLevel) {
|
269
|
-
this.level = undefined;
|
270
|
-
this.defaultLogger = {
|
271
|
-
verbose: console.debug,
|
272
|
-
info: console.info,
|
273
|
-
warn: console.warn,
|
274
|
-
error: console.error,
|
275
|
-
};
|
276
|
-
this.name = name;
|
277
|
-
this.level = logLevel;
|
278
|
-
}
|
279
|
-
error(message) {
|
280
|
-
this.log(exports.LogLevel.Error, (x) => x.error, message);
|
281
|
-
}
|
282
|
-
warn(message) {
|
283
|
-
this.log(exports.LogLevel.Warn, (x) => x.warn, message);
|
284
|
-
}
|
285
|
-
info(message) {
|
286
|
-
this.log(exports.LogLevel.Info, (x) => x.info, message);
|
287
|
-
}
|
288
|
-
verbose(message) {
|
289
|
-
this.log(exports.LogLevel.Verbose, (x) => x.verbose, message);
|
290
|
-
}
|
291
|
-
log(logLevel, logFunction, message) {
|
292
|
-
if (message.trim() === "") {
|
293
|
-
return;
|
294
|
-
}
|
295
|
-
const timestamp = new Date().toUTCString();
|
296
|
-
let logHeader;
|
297
|
-
if (this.name) {
|
298
|
-
logHeader = `[${timestamp}] : @microsoft/teamsfx - ${this.name} : ${exports.LogLevel[logLevel]} - `;
|
299
|
-
}
|
300
|
-
else {
|
301
|
-
logHeader = `[${timestamp}] : @microsoft/teamsfx : ${exports.LogLevel[logLevel]} - `;
|
302
|
-
}
|
303
|
-
const logMessage = `${logHeader}${message}`;
|
304
|
-
if (this.level !== undefined && this.level <= logLevel) {
|
305
|
-
if (this.customLogger) {
|
306
|
-
logFunction(this.customLogger)(logMessage);
|
307
|
-
}
|
308
|
-
else if (this.customLogFunction) {
|
309
|
-
this.customLogFunction(logLevel, logMessage);
|
310
|
-
}
|
311
|
-
else {
|
312
|
-
logFunction(this.defaultLogger)(logMessage);
|
313
|
-
}
|
314
|
-
}
|
315
|
-
}
|
316
|
-
}
|
317
|
-
/**
|
318
|
-
* Logger instance used internally
|
319
|
-
*
|
320
|
-
* @internal
|
321
|
-
*/
|
322
|
-
const internalLogger = new InternalLogger();
|
323
|
-
/**
|
324
|
-
* Set custom logger. Use the output functions if it's set. Priority is higher than setLogFunction.
|
325
|
-
*
|
326
|
-
* @param {Logger} logger - custom logger. If it's undefined, custom logger will be cleared.
|
327
|
-
*
|
328
|
-
* @example
|
329
|
-
* ```typescript
|
330
|
-
* setLogger({
|
331
|
-
* verbose: console.debug,
|
332
|
-
* info: console.info,
|
333
|
-
* warn: console.warn,
|
334
|
-
* error: console.error,
|
335
|
-
* });
|
336
|
-
* ```
|
337
|
-
*/
|
338
|
-
function setLogger(logger) {
|
339
|
-
internalLogger.customLogger = logger;
|
340
|
-
}
|
341
|
-
/**
|
342
|
-
* Set custom log function. Use the function if it's set. Priority is lower than setLogger.
|
343
|
-
*
|
344
|
-
* @param {LogFunction} logFunction - custom log function. If it's undefined, custom log function will be cleared.
|
345
|
-
*
|
346
|
-
* @example
|
347
|
-
* ```typescript
|
348
|
-
* setLogFunction((level: LogLevel, message: string) => {
|
349
|
-
* if (level === LogLevel.Error) {
|
350
|
-
* console.log(message);
|
351
|
-
* }
|
352
|
-
* });
|
353
|
-
* ```
|
354
|
-
*/
|
355
|
-
function setLogFunction(logFunction) {
|
356
|
-
internalLogger.customLogFunction = logFunction;
|
357
|
-
}
|
358
|
-
|
359
|
-
// Copyright (c) Microsoft Corporation.
|
360
|
-
/**
|
361
|
-
* Parse jwt token payload
|
362
|
-
*
|
363
|
-
* @param token
|
364
|
-
*
|
365
|
-
* @returns Payload object
|
366
|
-
*
|
367
|
-
* @internal
|
368
|
-
*/
|
369
|
-
function parseJwt(token) {
|
370
|
-
try {
|
371
|
-
const tokenObj = jwtDecode.jwtDecode(token);
|
372
|
-
if (!tokenObj || !tokenObj.exp) {
|
373
|
-
throw new ErrorWithCode("Decoded token is null or exp claim does not exists.", exports.ErrorCode.InternalError);
|
374
|
-
}
|
375
|
-
return tokenObj;
|
376
|
-
}
|
377
|
-
catch (err) {
|
378
|
-
const errorMsg = "Parse jwt token failed in node env with error: " + err.message;
|
379
|
-
internalLogger.error(errorMsg);
|
380
|
-
throw new ErrorWithCode(errorMsg, exports.ErrorCode.InternalError);
|
381
|
-
}
|
382
|
-
}
|
383
|
-
/**
|
384
|
-
* @internal
|
385
|
-
*/
|
386
|
-
function getUserInfoFromSsoToken(ssoToken) {
|
387
|
-
if (!ssoToken) {
|
388
|
-
const errorMsg = "SSO token is undefined.";
|
389
|
-
internalLogger.error(errorMsg);
|
390
|
-
throw new ErrorWithCode(errorMsg, exports.ErrorCode.InvalidParameter);
|
391
|
-
}
|
392
|
-
const tokenObject = parseJwt(ssoToken);
|
393
|
-
const userInfo = {
|
394
|
-
displayName: tokenObject.name,
|
395
|
-
objectId: tokenObject.oid,
|
396
|
-
tenantId: tokenObject.tid,
|
397
|
-
preferredUserName: "",
|
398
|
-
};
|
399
|
-
if (tokenObject.ver === "2.0") {
|
400
|
-
userInfo.preferredUserName = tokenObject.preferred_username;
|
401
|
-
}
|
402
|
-
else if (tokenObject.ver === "1.0") {
|
403
|
-
userInfo.preferredUserName = tokenObject.upn;
|
404
|
-
}
|
405
|
-
return userInfo;
|
406
|
-
}
|
407
|
-
/**
|
408
|
-
* Format string template with replacements
|
409
|
-
*
|
410
|
-
* ```typescript
|
411
|
-
* const template = "{0} and {1} are fruit. {0} is my favorite one."
|
412
|
-
* const formattedStr = formatString(template, "apple", "pear"); // formattedStr: "apple and pear are fruit. apple is my favorite one."
|
413
|
-
* ```
|
414
|
-
*
|
415
|
-
* @param str string template
|
416
|
-
* @param replacements replacement string array
|
417
|
-
* @returns Formatted string
|
418
|
-
*
|
419
|
-
* @internal
|
420
|
-
*/
|
421
|
-
function formatString(str, ...replacements) {
|
422
|
-
const args = replacements;
|
423
|
-
return str.replace(/{(\d+)}/g, function (match, number) {
|
424
|
-
return typeof args[number] != "undefined" ? args[number] : match;
|
425
|
-
});
|
426
|
-
}
|
427
|
-
/**
|
428
|
-
* @internal
|
429
|
-
*/
|
430
|
-
function validateScopesType(value) {
|
431
|
-
// string
|
432
|
-
if (typeof value === "string" || value instanceof String) {
|
433
|
-
return;
|
434
|
-
}
|
435
|
-
// empty array
|
436
|
-
if (Array.isArray(value) && value.length === 0) {
|
437
|
-
return;
|
438
|
-
}
|
439
|
-
// string array
|
440
|
-
if (Array.isArray(value) && value.length > 0 && value.every((item) => typeof item === "string")) {
|
441
|
-
return;
|
442
|
-
}
|
443
|
-
const errorMsg = "The type of scopes is not valid, it must be string or string array";
|
444
|
-
internalLogger.error(errorMsg);
|
445
|
-
throw new ErrorWithCode(errorMsg, exports.ErrorCode.InvalidParameter);
|
446
|
-
}
|
447
|
-
/**
|
448
|
-
* @internal
|
449
|
-
*/
|
450
|
-
function getScopesArray(scopes) {
|
451
|
-
const scopesArray = typeof scopes === "string" ? scopes.split(" ") : scopes;
|
452
|
-
return scopesArray.filter((x) => x !== null && x !== "");
|
453
|
-
}
|
454
|
-
/**
|
455
|
-
* @internal
|
456
|
-
*/
|
457
|
-
function getAuthority(authorityHost, tenantId) {
|
458
|
-
const normalizedAuthorityHost = authorityHost.replace(/\/+$/g, "");
|
459
|
-
return normalizedAuthorityHost + "/" + tenantId;
|
460
|
-
}
|
461
|
-
/**
|
462
|
-
* @internal
|
463
|
-
*/
|
464
|
-
function validateConfig(config) {
|
465
|
-
if (config.clientId &&
|
466
|
-
(config.clientSecret || config.certificateContent) &&
|
467
|
-
config.tenantId &&
|
468
|
-
config.authorityHost) {
|
469
|
-
return;
|
470
|
-
}
|
471
|
-
const missingValues = [];
|
472
|
-
if (!config.clientId) {
|
473
|
-
missingValues.push("clientId");
|
474
|
-
}
|
475
|
-
if (!config.clientSecret && !config.certificateContent) {
|
476
|
-
missingValues.push("clientSecret or certificateContent");
|
477
|
-
}
|
478
|
-
if (!config.tenantId) {
|
479
|
-
missingValues.push("tenantId");
|
480
|
-
}
|
481
|
-
if (!config.authorityHost) {
|
482
|
-
missingValues.push("authorityHost");
|
483
|
-
}
|
484
|
-
const errorMsg = formatString(ErrorMessage.InvalidConfiguration, missingValues.join(", "), "undefined");
|
485
|
-
internalLogger.error(errorMsg);
|
486
|
-
throw new ErrorWithCode(errorMsg, exports.ErrorCode.InvalidConfiguration);
|
487
|
-
}
|
488
|
-
|
489
|
-
// Copyright (c) Microsoft Corporation.
|
490
|
-
/**
|
491
|
-
* @internal
|
492
|
-
*/
|
493
|
-
function createConfidentialClientApplication(authentication) {
|
494
|
-
const authority = getAuthority(authentication.authorityHost, authentication.tenantId);
|
495
|
-
const clientCertificate = parseCertificate(authentication.certificateContent);
|
496
|
-
const auth = {
|
497
|
-
clientId: authentication.clientId,
|
498
|
-
authority: authority,
|
499
|
-
};
|
500
|
-
if (clientCertificate) {
|
501
|
-
auth.clientCertificate = clientCertificate;
|
502
|
-
}
|
503
|
-
else {
|
504
|
-
auth.clientSecret = authentication.clientSecret;
|
505
|
-
}
|
506
|
-
return new msalNode.ConfidentialClientApplication({
|
507
|
-
auth,
|
508
|
-
});
|
509
|
-
}
|
510
|
-
/**
|
511
|
-
* @internal
|
512
|
-
*/
|
513
|
-
function parseCertificate(certificateContent) {
|
514
|
-
if (!certificateContent) {
|
515
|
-
return undefined;
|
516
|
-
}
|
517
|
-
const certificatePattern = /(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/;
|
518
|
-
const match = certificatePattern.exec(certificateContent);
|
519
|
-
if (!match) {
|
520
|
-
const errorMsg = "The certificate content does not contain a PEM-encoded certificate.";
|
521
|
-
internalLogger.error(errorMsg);
|
522
|
-
throw new ErrorWithCode(errorMsg, exports.ErrorCode.InvalidCertificate);
|
523
|
-
}
|
524
|
-
const thumbprint = crypto.createHash("sha256")
|
525
|
-
.update(Buffer.from(match[3], "base64"))
|
526
|
-
.digest("hex")
|
527
|
-
.toUpperCase();
|
528
|
-
return {
|
529
|
-
thumbprintSha256: thumbprint,
|
530
|
-
privateKey: certificateContent,
|
531
|
-
};
|
532
|
-
}
|
533
|
-
|
534
|
-
// Copyright (c) Microsoft Corporation.
|
535
|
-
/**
|
536
|
-
* Represent Microsoft 365 tenant identity, and it is usually used when user is not involved like time-triggered automation job.
|
537
|
-
*
|
538
|
-
* @example
|
539
|
-
* ```typescript
|
540
|
-
* loadConfiguration(); // load configuration from environment variables
|
541
|
-
* const credential = new AppCredential();
|
542
|
-
* ```
|
543
|
-
*
|
544
|
-
* @remarks
|
545
|
-
* Only works in in server side.
|
546
|
-
*/
|
547
|
-
class AppCredential {
|
548
|
-
/**
|
549
|
-
* Constructor of AppCredential.
|
550
|
-
*
|
551
|
-
* @remarks
|
552
|
-
* Only works in in server side.
|
553
|
-
*
|
554
|
-
* @param {AppCredentialAuthConfig} authConfig - The authentication configuration.
|
555
|
-
*
|
556
|
-
* @throws {@link ErrorCode|InvalidConfiguration} when client id, client secret or tenant id is not found in config.
|
557
|
-
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
|
558
|
-
*/
|
559
|
-
constructor(authConfig) {
|
560
|
-
internalLogger.info("Create M365 tenant credential");
|
561
|
-
const config = this.loadAndValidateConfig(authConfig);
|
562
|
-
this.msalClient = createConfidentialClientApplication(config);
|
563
|
-
}
|
564
|
-
/**
|
565
|
-
* Get access token for credential.
|
566
|
-
*
|
567
|
-
* @example
|
568
|
-
* ```typescript
|
569
|
-
* await credential.getToken(["User.Read.All"]) // Get Graph access token for single scope using string array
|
570
|
-
* await credential.getToken("User.Read.All") // Get Graph access token for single scope using string
|
571
|
-
* await credential.getToken(["User.Read.All", "Calendars.Read"]) // Get Graph access token for multiple scopes using string array
|
572
|
-
* await credential.getToken("User.Read.All Calendars.Read") // Get Graph access token for multiple scopes using space-separated string
|
573
|
-
* await credential.getToken("https://graph.microsoft.com/User.Read.All") // Get Graph access token with full resource URI
|
574
|
-
* await credential.getToken(["https://outlook.office.com/Mail.Read"]) // Get Outlook access token
|
575
|
-
* ```
|
576
|
-
*
|
577
|
-
* @param {string | string[]} scopes - The list of scopes for which the token will have access.
|
578
|
-
* @param {GetTokenOptions} options - The options used to configure any requests this TokenCredential implementation might make.
|
579
|
-
*
|
580
|
-
* @throws {@link ErrorCode|ServiceError} when get access token with authentication error.
|
581
|
-
* @throws {@link ErrorCode|InternalError} when get access token with unknown error.
|
582
|
-
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
583
|
-
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
|
584
|
-
*
|
585
|
-
* @returns Access token with expected scopes.
|
586
|
-
* Throw error if get access token failed.
|
587
|
-
*/
|
588
|
-
getToken(scopes, options) {
|
589
|
-
return __awaiter(this, void 0, void 0, function* () {
|
590
|
-
let accessToken;
|
591
|
-
validateScopesType(scopes);
|
592
|
-
const scopesStr = typeof scopes === "string" ? scopes : scopes.join(" ");
|
593
|
-
internalLogger.info("Get access token with scopes: " + scopesStr);
|
594
|
-
try {
|
595
|
-
const scopesArray = getScopesArray(scopes);
|
596
|
-
const authenticationResult = yield this.msalClient.acquireTokenByClientCredential({
|
597
|
-
scopes: scopesArray,
|
598
|
-
});
|
599
|
-
if (authenticationResult) {
|
600
|
-
accessToken = {
|
601
|
-
token: authenticationResult.accessToken,
|
602
|
-
expiresOnTimestamp: authenticationResult.expiresOn.getTime(),
|
603
|
-
};
|
604
|
-
}
|
605
|
-
}
|
606
|
-
catch (err) {
|
607
|
-
const errorMsg = "Get M365 tenant credential failed with error: " + err.message;
|
608
|
-
internalLogger.error(errorMsg);
|
609
|
-
throw new ErrorWithCode(errorMsg, exports.ErrorCode.ServiceError);
|
610
|
-
}
|
611
|
-
if (!accessToken) {
|
612
|
-
const errorMsg = "Get M365 tenant credential access token failed with empty access token";
|
613
|
-
internalLogger.error(errorMsg);
|
614
|
-
throw new ErrorWithCode(errorMsg, exports.ErrorCode.InternalError);
|
615
|
-
}
|
616
|
-
return accessToken;
|
617
|
-
});
|
618
|
-
}
|
619
|
-
/**
|
620
|
-
* Load and validate authentication configuration
|
621
|
-
*
|
622
|
-
* @param {AuthenticationConfiguration} authConfig - The authentication configuration. Use environment variables if not provided.
|
623
|
-
*
|
624
|
-
* @returns Authentication configuration
|
625
|
-
*/
|
626
|
-
loadAndValidateConfig(config) {
|
627
|
-
internalLogger.verbose("Validate authentication configuration");
|
628
|
-
if (config.clientId &&
|
629
|
-
(config.clientSecret || config.certificateContent) &&
|
630
|
-
config.tenantId &&
|
631
|
-
config.authorityHost) {
|
632
|
-
return config;
|
633
|
-
}
|
634
|
-
const missingValues = [];
|
635
|
-
if (!config.clientId) {
|
636
|
-
missingValues.push("clientId");
|
637
|
-
}
|
638
|
-
if (!config.clientSecret && !config.certificateContent) {
|
639
|
-
missingValues.push("clientSecret or certificateContent");
|
640
|
-
}
|
641
|
-
if (!config.tenantId) {
|
642
|
-
missingValues.push("tenantId");
|
643
|
-
}
|
644
|
-
if (!config.authorityHost) {
|
645
|
-
missingValues.push("authorityHost");
|
646
|
-
}
|
647
|
-
const errorMsg = formatString(ErrorMessage.InvalidConfiguration, missingValues.join(", "), "undefined");
|
648
|
-
internalLogger.error(errorMsg);
|
649
|
-
throw new ErrorWithCode(errorMsg, exports.ErrorCode.InvalidConfiguration);
|
650
|
-
}
|
651
|
-
}
|
652
|
-
|
653
|
-
// Copyright (c) Microsoft Corporation.
|
654
|
-
/**
|
655
|
-
* Represent on-behalf-of flow to get user identity, and it is designed to be used in server side.
|
656
|
-
*
|
657
|
-
* @example
|
658
|
-
* ```typescript
|
659
|
-
* const credential = new OnBehalfOfUserCredential(ssoToken);
|
660
|
-
* ```
|
661
|
-
*
|
662
|
-
* @remarks
|
663
|
-
* Can only be used in server side.
|
664
|
-
*/
|
665
|
-
class OnBehalfOfUserCredential {
|
666
|
-
/**
|
667
|
-
* Constructor of OnBehalfOfUserCredential
|
668
|
-
*
|
669
|
-
* @remarks
|
670
|
-
* Only works in in server side.
|
671
|
-
*
|
672
|
-
* @param {string} ssoToken - User token provided by Teams SSO feature.
|
673
|
-
* @param {OnBehalfOfCredentialAuthConfig} config - The authentication configuration.
|
674
|
-
*
|
675
|
-
* @throws {@link ErrorCode|InvalidConfiguration} when client id, client secret, certificate content, authority host or tenant id is not found in config.
|
676
|
-
* @throws {@link ErrorCode|InternalError} when SSO token is not valid.
|
677
|
-
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
678
|
-
*/
|
679
|
-
constructor(ssoToken, config) {
|
680
|
-
internalLogger.info("Get on behalf of user credential");
|
681
|
-
const missingConfigurations = [];
|
682
|
-
if (!config.clientId) {
|
683
|
-
missingConfigurations.push("clientId");
|
684
|
-
}
|
685
|
-
if (!config.authorityHost) {
|
686
|
-
missingConfigurations.push("authorityHost");
|
687
|
-
}
|
688
|
-
if (!config.clientSecret && !config.certificateContent) {
|
689
|
-
missingConfigurations.push("clientSecret or certificateContent");
|
690
|
-
}
|
691
|
-
if (!config.tenantId) {
|
692
|
-
missingConfigurations.push("tenantId");
|
693
|
-
}
|
694
|
-
if (missingConfigurations.length != 0) {
|
695
|
-
const errorMsg = formatString(ErrorMessage.InvalidConfiguration, missingConfigurations.join(", "), "undefined");
|
696
|
-
internalLogger.error(errorMsg);
|
697
|
-
throw new ErrorWithCode(errorMsg, exports.ErrorCode.InvalidConfiguration);
|
698
|
-
}
|
699
|
-
this.msalClient = createConfidentialClientApplication(config);
|
700
|
-
const decodedSsoToken = parseJwt(ssoToken);
|
701
|
-
this.ssoToken = {
|
702
|
-
token: ssoToken,
|
703
|
-
expiresOnTimestamp: decodedSsoToken.exp,
|
704
|
-
};
|
705
|
-
}
|
706
|
-
/**
|
707
|
-
* Get access token from credential.
|
708
|
-
*
|
709
|
-
* @example
|
710
|
-
* ```typescript
|
711
|
-
* await credential.getToken([]) // Get SSO token using empty string array
|
712
|
-
* await credential.getToken("") // Get SSO token using empty string
|
713
|
-
* await credential.getToken([".default"]) // Get Graph access token with default scope using string array
|
714
|
-
* await credential.getToken(".default") // Get Graph access token with default scope using string
|
715
|
-
* await credential.getToken(["User.Read"]) // Get Graph access token for single scope using string array
|
716
|
-
* await credential.getToken("User.Read") // Get Graph access token for single scope using string
|
717
|
-
* await credential.getToken(["User.Read", "Application.Read.All"]) // Get Graph access token for multiple scopes using string array
|
718
|
-
* await credential.getToken("User.Read Application.Read.All") // Get Graph access token for multiple scopes using space-separated string
|
719
|
-
* await credential.getToken("https://graph.microsoft.com/User.Read") // Get Graph access token with full resource URI
|
720
|
-
* await credential.getToken(["https://outlook.office.com/Mail.Read"]) // Get Outlook access token
|
721
|
-
* ```
|
722
|
-
*
|
723
|
-
* @param {string | string[]} scopes - The list of scopes for which the token will have access.
|
724
|
-
* @param {GetTokenOptions} options - The options used to configure any requests this TokenCredential implementation might make.
|
725
|
-
*
|
726
|
-
* @throws {@link ErrorCode|InternalError} when failed to acquire access token on behalf of user with unknown error.
|
727
|
-
* @throws {@link ErrorCode|TokenExpiredError} when SSO token has already expired.
|
728
|
-
* @throws {@link ErrorCode|UiRequiredError} when need user consent to get access token.
|
729
|
-
* @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server.
|
730
|
-
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
731
|
-
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
732
|
-
*
|
733
|
-
* @returns Access token with expected scopes.
|
734
|
-
*
|
735
|
-
* @remarks
|
736
|
-
* If scopes is empty string or array, it returns SSO token.
|
737
|
-
* If scopes is non-empty, it returns access token for target scope.
|
738
|
-
*/
|
739
|
-
getToken(scopes, options) {
|
740
|
-
return __awaiter(this, void 0, void 0, function* () {
|
741
|
-
validateScopesType(scopes);
|
742
|
-
const scopesArray = getScopesArray(scopes);
|
743
|
-
let result;
|
744
|
-
if (!scopesArray.length) {
|
745
|
-
internalLogger.info("Get SSO token.");
|
746
|
-
if (Math.floor(Date.now() / 1000) > this.ssoToken.expiresOnTimestamp) {
|
747
|
-
const errorMsg = "Sso token has already expired.";
|
748
|
-
internalLogger.error(errorMsg);
|
749
|
-
throw new ErrorWithCode(errorMsg, exports.ErrorCode.TokenExpiredError);
|
750
|
-
}
|
751
|
-
result = this.ssoToken;
|
752
|
-
}
|
753
|
-
else {
|
754
|
-
internalLogger.info("Get access token with scopes: " + scopesArray.join(" "));
|
755
|
-
let authenticationResult;
|
756
|
-
try {
|
757
|
-
authenticationResult = yield this.msalClient.acquireTokenOnBehalfOf({
|
758
|
-
oboAssertion: this.ssoToken.token,
|
759
|
-
scopes: scopesArray,
|
760
|
-
});
|
761
|
-
}
|
762
|
-
catch (error) {
|
763
|
-
throw this.generateAuthServerError(error);
|
764
|
-
}
|
765
|
-
if (!authenticationResult) {
|
766
|
-
const errorMsg = "Access token is null";
|
767
|
-
internalLogger.error(errorMsg);
|
768
|
-
throw new ErrorWithCode(formatString(ErrorMessage.FailToAcquireTokenOnBehalfOfUser, errorMsg), exports.ErrorCode.InternalError);
|
769
|
-
}
|
770
|
-
result = {
|
771
|
-
token: authenticationResult.accessToken,
|
772
|
-
expiresOnTimestamp: authenticationResult.expiresOn.getTime(),
|
773
|
-
};
|
774
|
-
}
|
775
|
-
return result;
|
776
|
-
});
|
777
|
-
}
|
778
|
-
/**
|
779
|
-
* Get basic user info from SSO token.
|
780
|
-
*
|
781
|
-
* @example
|
782
|
-
* ```typescript
|
783
|
-
* const currentUser = getUserInfo();
|
784
|
-
* ```
|
785
|
-
*
|
786
|
-
* @throws {@link ErrorCode|InternalError} when SSO token is not valid.
|
787
|
-
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
788
|
-
*
|
789
|
-
* @returns Basic user info with user displayName, objectId and preferredUserName.
|
790
|
-
*/
|
791
|
-
getUserInfo() {
|
792
|
-
internalLogger.info("Get basic user info from SSO token");
|
793
|
-
return getUserInfoFromSsoToken(this.ssoToken.token);
|
794
|
-
}
|
795
|
-
generateAuthServerError(err) {
|
796
|
-
const errorMessage = err.errorMessage;
|
797
|
-
if (err.name === "InteractionRequiredAuthError") {
|
798
|
-
const fullErrorMsg = "Failed to get access token from AAD server, interaction required: " + errorMessage;
|
799
|
-
internalLogger.warn(fullErrorMsg);
|
800
|
-
return new ErrorWithCode(fullErrorMsg, exports.ErrorCode.UiRequiredError);
|
801
|
-
}
|
802
|
-
else if (errorMessage && errorMessage.indexOf("AADSTS50013") >= 0) {
|
803
|
-
const fullErrorMsg = "Failed to get access token from AAD server, assertion is invalid because of various reasons: " +
|
804
|
-
errorMessage;
|
805
|
-
internalLogger.error(fullErrorMsg);
|
806
|
-
return new ErrorWithCode(fullErrorMsg, exports.ErrorCode.TokenExpiredError);
|
807
|
-
}
|
808
|
-
else {
|
809
|
-
const fullErrorMsg = formatString(ErrorMessage.FailToAcquireTokenOnBehalfOfUser, errorMessage);
|
810
|
-
internalLogger.error(fullErrorMsg);
|
811
|
-
return new ErrorWithCode(fullErrorMsg, exports.ErrorCode.ServiceError);
|
812
|
-
}
|
813
|
-
}
|
814
|
-
}
|
815
|
-
|
816
|
-
// Copyright (c) Microsoft Corporation.
|
817
|
-
/**
|
818
|
-
* Represent Teams current user's identity, and it is used within Teams client applications.
|
819
|
-
*
|
820
|
-
* @remarks
|
821
|
-
* Can only be used within Teams.
|
822
|
-
*/
|
823
|
-
class TeamsUserCredential {
|
824
|
-
/**
|
825
|
-
* Constructor of TeamsUserCredential.
|
826
|
-
* @remarks
|
827
|
-
* Can only be used within Teams.
|
828
|
-
*/
|
829
|
-
constructor(authConfig) {
|
830
|
-
throw new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "TeamsUserCredential"), exports.ErrorCode.RuntimeNotSupported);
|
831
|
-
}
|
832
|
-
/**
|
833
|
-
* Popup login page to get user's access token with specific scopes.
|
834
|
-
*
|
835
|
-
* @param {string[]} resources - The optional list of resources for full trust Teams apps.
|
836
|
-
*
|
837
|
-
* @remarks
|
838
|
-
* Can only be used within Teams.
|
839
|
-
*/
|
840
|
-
login(scopes, resources) {
|
841
|
-
return Promise.reject(new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "TeamsUserCredential"), exports.ErrorCode.RuntimeNotSupported));
|
842
|
-
}
|
843
|
-
/**
|
844
|
-
* Get access token from credential.
|
845
|
-
* @remarks
|
846
|
-
* Can only be used within Teams.
|
847
|
-
*/
|
848
|
-
getToken(scopes, options) {
|
849
|
-
return Promise.reject(new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "TeamsUserCredential"), exports.ErrorCode.RuntimeNotSupported));
|
850
|
-
}
|
851
|
-
/**
|
852
|
-
* Get basic user info from SSO token
|
853
|
-
*
|
854
|
-
* @param {string[]} resources - The optional list of resources for full trust Teams apps.
|
855
|
-
*
|
856
|
-
* @remarks
|
857
|
-
* Can only be used within Teams.
|
858
|
-
*/
|
859
|
-
getUserInfo(resources) {
|
860
|
-
return Promise.reject(new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "TeamsUserCredential"), exports.ErrorCode.RuntimeNotSupported));
|
861
|
-
}
|
862
|
-
}
|
863
|
-
|
864
|
-
// Copyright (c) Microsoft Corporation.
|
865
|
-
const invokeResponseType = "invokeResponse";
|
866
|
-
/**
|
867
|
-
* Response body returned for a token exchange invoke activity.
|
868
|
-
*/
|
869
|
-
class TokenExchangeInvokeResponse {
|
870
|
-
constructor(id, failureDetail) {
|
871
|
-
this.id = id;
|
872
|
-
this.failureDetail = failureDetail;
|
873
|
-
}
|
874
|
-
}
|
875
|
-
/**
|
876
|
-
* Creates a new prompt that leverage Teams Single Sign On (SSO) support for bot to automatically sign in user and
|
877
|
-
* help receive oauth token, asks the user to consent if needed.
|
878
|
-
*
|
879
|
-
* @remarks
|
880
|
-
* The prompt will attempt to retrieve the users current token of the desired scopes and store it in
|
881
|
-
* the token store.
|
882
|
-
*
|
883
|
-
* User will be automatically signed in leveraging Teams support of Bot Single Sign On(SSO):
|
884
|
-
* https://docs.microsoft.com/en-us/microsoftteams/platform/bots/how-to/authentication/auth-aad-sso-bots
|
885
|
-
*
|
886
|
-
* @example
|
887
|
-
* When used with your bots `DialogSet` you can simply add a new instance of the prompt as a named
|
888
|
-
* dialog using `DialogSet.add()`. You can then start the prompt from a waterfall step using either
|
889
|
-
* `DialogContext.beginDialog()` or `DialogContext.prompt()`. The user will be prompted to sign in as
|
890
|
-
* needed and their access token will be passed as an argument to the callers next waterfall step:
|
891
|
-
*
|
892
|
-
* ```JavaScript
|
893
|
-
* const { ConversationState, MemoryStorage } = require('botbuilder');
|
894
|
-
* const { DialogSet, WaterfallDialog } = require('botbuilder-dialogs');
|
895
|
-
* const { TeamsBotSsoPrompt } = require('@microsoft/teamsfx');
|
896
|
-
*
|
897
|
-
* const convoState = new ConversationState(new MemoryStorage());
|
898
|
-
* const dialogState = convoState.createProperty('dialogState');
|
899
|
-
* const dialogs = new DialogSet(dialogState);
|
900
|
-
*
|
901
|
-
* dialogs.add(new TeamsBotSsoPrompt('TeamsBotSsoPrompt', {
|
902
|
-
* scopes: ["User.Read"],
|
903
|
-
* }));
|
904
|
-
*
|
905
|
-
* dialogs.add(new WaterfallDialog('taskNeedingLogin', [
|
906
|
-
* async (step) => {
|
907
|
-
* return await step.beginDialog('TeamsBotSsoPrompt');
|
908
|
-
* },
|
909
|
-
* async (step) => {
|
910
|
-
* const token = step.result;
|
911
|
-
* if (token) {
|
912
|
-
*
|
913
|
-
* // ... continue with task needing access token ...
|
914
|
-
*
|
915
|
-
* } else {
|
916
|
-
* await step.context.sendActivity(`Sorry... We couldn't log you in. Try again later.`);
|
917
|
-
* return await step.endDialog();
|
918
|
-
* }
|
919
|
-
* }
|
920
|
-
* ]));
|
921
|
-
* ```
|
922
|
-
*/
|
923
|
-
class TeamsBotSsoPrompt extends botbuilderDialogs.Dialog {
|
924
|
-
/**
|
925
|
-
* Constructor of TeamsBotSsoPrompt.
|
926
|
-
*
|
927
|
-
* @param {OnBehalfOfCredentialAuthConfig} authConfig - Used to provide configuration and auth
|
928
|
-
* @param {string} initiateLoginEndpoint - Login URL for Teams to redirect to
|
929
|
-
* @param {string} dialogId Unique ID of the dialog within its parent `DialogSet` or `ComponentDialog`.
|
930
|
-
* @param {TeamsBotSsoPromptSettings} settings Settings used to configure the prompt.
|
931
|
-
*
|
932
|
-
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
933
|
-
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
934
|
-
*/
|
935
|
-
constructor(authConfig, initiateLoginEndpoint, dialogId, settings) {
|
936
|
-
super(dialogId);
|
937
|
-
this.initiateLoginEndpoint = initiateLoginEndpoint;
|
938
|
-
this.authConfig = authConfig;
|
939
|
-
this.settings = settings;
|
940
|
-
validateScopesType(this.settings.scopes);
|
941
|
-
validateConfig(this.authConfig);
|
942
|
-
internalLogger.info("Create a new Teams Bot SSO Prompt");
|
943
|
-
}
|
944
|
-
/**
|
945
|
-
* Called when a prompt dialog is pushed onto the dialog stack and is being activated.
|
946
|
-
* @remarks
|
947
|
-
* If the task is successful, the result indicates whether the prompt is still
|
948
|
-
* active after the turn has been processed by the prompt.
|
949
|
-
*
|
950
|
-
* @param dc The DialogContext for the current turn of the conversation.
|
951
|
-
*
|
952
|
-
* @throws {@link ErrorCode|InvalidParameter} when timeout property in teams bot sso prompt settings is not number or is not positive.
|
953
|
-
* @throws {@link ErrorCode|ChannelNotSupported} when bot channel is not MS Teams.
|
954
|
-
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
955
|
-
*
|
956
|
-
* @returns A `Promise` representing the asynchronous operation.
|
957
|
-
*/
|
958
|
-
beginDialog(dc) {
|
959
|
-
return __awaiter(this, void 0, void 0, function* () {
|
960
|
-
var _a;
|
961
|
-
internalLogger.info("Begin Teams Bot SSO Prompt");
|
962
|
-
this.ensureMsTeamsChannel(dc);
|
963
|
-
// Initialize prompt state
|
964
|
-
const default_timeout = 900000;
|
965
|
-
let timeout = default_timeout;
|
966
|
-
if (this.settings.timeout) {
|
967
|
-
if (typeof this.settings.timeout != "number") {
|
968
|
-
const errorMsg = "type of timeout property in teamsBotSsoPromptSettings should be number.";
|
969
|
-
internalLogger.error(errorMsg);
|
970
|
-
throw new ErrorWithCode(errorMsg, exports.ErrorCode.InvalidParameter);
|
971
|
-
}
|
972
|
-
if (this.settings.timeout <= 0) {
|
973
|
-
const errorMsg = "value of timeout property in teamsBotSsoPromptSettings should be positive.";
|
974
|
-
internalLogger.error(errorMsg);
|
975
|
-
throw new ErrorWithCode(errorMsg, exports.ErrorCode.InvalidParameter);
|
976
|
-
}
|
977
|
-
timeout = this.settings.timeout;
|
978
|
-
}
|
979
|
-
if (this.settings.endOnInvalidMessage === undefined) {
|
980
|
-
this.settings.endOnInvalidMessage = true;
|
981
|
-
}
|
982
|
-
const state = (_a = dc.activeDialog) === null || _a === void 0 ? void 0 : _a.state;
|
983
|
-
state.state = {};
|
984
|
-
state.options = {};
|
985
|
-
state.expires = new Date().getTime() + timeout;
|
986
|
-
// Send OAuth card to get SSO token
|
987
|
-
yield this.sendOAuthCardAsync(dc.context);
|
988
|
-
return botbuilderDialogs.Dialog.EndOfTurn;
|
989
|
-
});
|
990
|
-
}
|
991
|
-
/**
|
992
|
-
* Called when a prompt dialog is the active dialog and the user replied with a new activity.
|
993
|
-
*
|
994
|
-
* @remarks
|
995
|
-
* If the task is successful, the result indicates whether the dialog is still
|
996
|
-
* active after the turn has been processed by the dialog.
|
997
|
-
* The prompt generally continues to receive the user's replies until it accepts the
|
998
|
-
* user's reply as valid input for the prompt.
|
999
|
-
*
|
1000
|
-
* @param dc The DialogContext for the current turn of the conversation.
|
1001
|
-
*
|
1002
|
-
* @returns A `Promise` representing the asynchronous operation.
|
1003
|
-
*
|
1004
|
-
* @throws {@link ErrorCode|ChannelNotSupported} when bot channel is not MS Teams.
|
1005
|
-
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
1006
|
-
*/
|
1007
|
-
continueDialog(dc) {
|
1008
|
-
return __awaiter(this, void 0, void 0, function* () {
|
1009
|
-
var _a;
|
1010
|
-
internalLogger.info("Continue Teams Bot SSO Prompt");
|
1011
|
-
this.ensureMsTeamsChannel(dc);
|
1012
|
-
// Check for timeout
|
1013
|
-
const state = (_a = dc.activeDialog) === null || _a === void 0 ? void 0 : _a.state;
|
1014
|
-
const isMessage = dc.context.activity.type === botbuilder.ActivityTypes.Message;
|
1015
|
-
const isTimeoutActivityType = isMessage ||
|
1016
|
-
this.isTeamsVerificationInvoke(dc.context) ||
|
1017
|
-
this.isTokenExchangeRequestInvoke(dc.context);
|
1018
|
-
// If the incoming Activity is a message, or an Activity Type normally handled by TeamsBotSsoPrompt,
|
1019
|
-
// check to see if this TeamsBotSsoPrompt Expiration has elapsed, and end the dialog if so.
|
1020
|
-
const hasTimedOut = isTimeoutActivityType && new Date().getTime() > state.expires;
|
1021
|
-
if (hasTimedOut) {
|
1022
|
-
internalLogger.warn("End Teams Bot SSO Prompt due to timeout");
|
1023
|
-
return yield dc.endDialog(undefined);
|
1024
|
-
}
|
1025
|
-
else {
|
1026
|
-
if (this.isTeamsVerificationInvoke(dc.context) ||
|
1027
|
-
this.isTokenExchangeRequestInvoke(dc.context)) {
|
1028
|
-
// Recognize token
|
1029
|
-
const recognized = yield this.recognizeToken(dc);
|
1030
|
-
if (recognized.succeeded) {
|
1031
|
-
return yield dc.endDialog(recognized.value);
|
1032
|
-
}
|
1033
|
-
}
|
1034
|
-
else if (isMessage && this.settings.endOnInvalidMessage) {
|
1035
|
-
internalLogger.warn("End Teams Bot SSO Prompt due to invalid message");
|
1036
|
-
return yield dc.endDialog(undefined);
|
1037
|
-
}
|
1038
|
-
return botbuilderDialogs.Dialog.EndOfTurn;
|
1039
|
-
}
|
1040
|
-
});
|
1041
|
-
}
|
1042
|
-
/**
|
1043
|
-
* Ensure bot is running in MS Teams since TeamsBotSsoPrompt is only supported in MS Teams channel.
|
1044
|
-
* @param dc dialog context
|
1045
|
-
* @throws {@link ErrorCode|ChannelNotSupported} if bot channel is not MS Teams
|
1046
|
-
* @internal
|
1047
|
-
*/
|
1048
|
-
ensureMsTeamsChannel(dc) {
|
1049
|
-
if (dc.context.activity.channelId != botbuilder.Channels.Msteams) {
|
1050
|
-
const errorMsg = formatString(ErrorMessage.OnlyMSTeamsChannelSupported, "Teams Bot SSO Prompt");
|
1051
|
-
internalLogger.error(errorMsg);
|
1052
|
-
throw new ErrorWithCode(errorMsg, exports.ErrorCode.ChannelNotSupported);
|
1053
|
-
}
|
1054
|
-
}
|
1055
|
-
/**
|
1056
|
-
* Send OAuthCard that tells Teams to obtain an authentication token for the bot application.
|
1057
|
-
* For details see https://docs.microsoft.com/en-us/microsoftteams/platform/bots/how-to/authentication/auth-aad-sso-bots.
|
1058
|
-
*
|
1059
|
-
* @internal
|
1060
|
-
*/
|
1061
|
-
sendOAuthCardAsync(context) {
|
1062
|
-
return __awaiter(this, void 0, void 0, function* () {
|
1063
|
-
internalLogger.verbose("Send OAuth card to get SSO token");
|
1064
|
-
const account = yield botbuilder.TeamsInfo.getMember(context, context.activity.from.id);
|
1065
|
-
internalLogger.verbose("Get Teams member account user principal name: " +
|
1066
|
-
(account.userPrincipalName ? account.userPrincipalName : ""));
|
1067
|
-
const loginHint = account.userPrincipalName ? account.userPrincipalName : "";
|
1068
|
-
const signInResource = this.getSignInResource(loginHint);
|
1069
|
-
const card = botbuilder.CardFactory.oauthCard("", "Teams SSO Sign In", "Sign In", signInResource.signInLink, signInResource.tokenExchangeResource);
|
1070
|
-
card.content.buttons[0].type = botbuilder.ActionTypes.Signin;
|
1071
|
-
const msg = botbuilder.MessageFactory.attachment(card);
|
1072
|
-
// Send prompt
|
1073
|
-
yield context.sendActivity(msg);
|
1074
|
-
});
|
1075
|
-
}
|
1076
|
-
/**
|
1077
|
-
* Get sign in resource.
|
1078
|
-
*
|
1079
|
-
* @throws {@link ErrorCode|InvalidConfiguration} if client id, tenant id or initiate login endpoint is not found in config.
|
1080
|
-
*
|
1081
|
-
* @internal
|
1082
|
-
*/
|
1083
|
-
getSignInResource(loginHint) {
|
1084
|
-
internalLogger.verbose("Get sign in authentication configuration");
|
1085
|
-
const signInLink = `${this.initiateLoginEndpoint}?scope=${encodeURI(this.settings.scopes.join(" "))}&clientId=${this.authConfig.clientId}&tenantId=${this.authConfig.tenantId}&loginHint=${loginHint}`;
|
1086
|
-
internalLogger.verbose("Sign in link: " + signInLink);
|
1087
|
-
const tokenExchangeResource = {
|
1088
|
-
id: uuid.v4(),
|
1089
|
-
};
|
1090
|
-
return {
|
1091
|
-
signInLink: signInLink,
|
1092
|
-
tokenExchangeResource: tokenExchangeResource,
|
1093
|
-
};
|
1094
|
-
}
|
1095
|
-
/**
|
1096
|
-
* @internal
|
1097
|
-
*/
|
1098
|
-
recognizeToken(dc) {
|
1099
|
-
return __awaiter(this, void 0, void 0, function* () {
|
1100
|
-
const context = dc.context;
|
1101
|
-
let tokenResponse;
|
1102
|
-
if (this.isTokenExchangeRequestInvoke(context)) {
|
1103
|
-
internalLogger.verbose("Receive token exchange request");
|
1104
|
-
// Received activity is not a token exchange request
|
1105
|
-
if (!(context.activity.value && this.isTokenExchangeRequest(context.activity.value))) {
|
1106
|
-
const warningMsg = "The bot received an InvokeActivity that is missing a TokenExchangeInvokeRequest value. This is required to be sent with the InvokeActivity.";
|
1107
|
-
internalLogger.warn(warningMsg);
|
1108
|
-
yield context.sendActivity(this.getTokenExchangeInvokeResponse(botbuilder.StatusCodes.BAD_REQUEST, warningMsg));
|
1109
|
-
}
|
1110
|
-
else {
|
1111
|
-
const ssoToken = context.activity.value.token;
|
1112
|
-
const credential = new OnBehalfOfUserCredential(ssoToken, this.authConfig);
|
1113
|
-
let exchangedToken;
|
1114
|
-
try {
|
1115
|
-
exchangedToken = yield credential.getToken(this.settings.scopes);
|
1116
|
-
if (exchangedToken) {
|
1117
|
-
yield context.sendActivity(this.getTokenExchangeInvokeResponse(botbuilder.StatusCodes.OK, "", context.activity.value.id));
|
1118
|
-
const ssoTokenExpiration = parseJwt(ssoToken).exp;
|
1119
|
-
tokenResponse = {
|
1120
|
-
ssoToken: ssoToken,
|
1121
|
-
ssoTokenExpiration: new Date(ssoTokenExpiration * 1000).toISOString(),
|
1122
|
-
connectionName: "",
|
1123
|
-
token: exchangedToken.token,
|
1124
|
-
expiration: exchangedToken.expiresOnTimestamp.toString(),
|
1125
|
-
};
|
1126
|
-
}
|
1127
|
-
}
|
1128
|
-
catch (error) {
|
1129
|
-
const warningMsg = "The bot is unable to exchange token. Ask for user consent.";
|
1130
|
-
internalLogger.info(warningMsg);
|
1131
|
-
yield context.sendActivity(this.getTokenExchangeInvokeResponse(botbuilder.StatusCodes.PRECONDITION_FAILED, warningMsg, context.activity.value.id));
|
1132
|
-
}
|
1133
|
-
}
|
1134
|
-
}
|
1135
|
-
else if (this.isTeamsVerificationInvoke(context)) {
|
1136
|
-
internalLogger.verbose("Receive Teams state verification request");
|
1137
|
-
yield this.sendOAuthCardAsync(dc.context);
|
1138
|
-
yield context.sendActivity({ type: invokeResponseType, value: { status: botbuilder.StatusCodes.OK } });
|
1139
|
-
}
|
1140
|
-
return tokenResponse !== undefined
|
1141
|
-
? { succeeded: true, value: tokenResponse }
|
1142
|
-
: { succeeded: false };
|
1143
|
-
});
|
1144
|
-
}
|
1145
|
-
/**
|
1146
|
-
* @internal
|
1147
|
-
*/
|
1148
|
-
getTokenExchangeInvokeResponse(status, failureDetail, id) {
|
1149
|
-
const invokeResponse = {
|
1150
|
-
type: invokeResponseType,
|
1151
|
-
value: { status, body: new TokenExchangeInvokeResponse(id, failureDetail) },
|
1152
|
-
};
|
1153
|
-
return invokeResponse;
|
1154
|
-
}
|
1155
|
-
/**
|
1156
|
-
* @internal
|
1157
|
-
*/
|
1158
|
-
isTeamsVerificationInvoke(context) {
|
1159
|
-
const activity = context.activity;
|
1160
|
-
return activity.type === botbuilder.ActivityTypes.Invoke && activity.name === botbuilder.verifyStateOperationName;
|
1161
|
-
}
|
1162
|
-
/**
|
1163
|
-
* @internal
|
1164
|
-
*/
|
1165
|
-
isTokenExchangeRequestInvoke(context) {
|
1166
|
-
const activity = context.activity;
|
1167
|
-
return activity.type === botbuilder.ActivityTypes.Invoke && activity.name === botbuilder.tokenExchangeOperationName;
|
1168
|
-
}
|
1169
|
-
/**
|
1170
|
-
* @internal
|
1171
|
-
*/
|
1172
|
-
isTokenExchangeRequest(obj) {
|
1173
|
-
return obj.hasOwnProperty("token");
|
1174
|
-
}
|
1175
|
-
}
|
1176
|
-
|
1177
|
-
// Copyright (c) Microsoft Corporation.
|
1178
|
-
/**
|
1179
|
-
* Initializes new Axios instance with specific auth provider
|
1180
|
-
*
|
1181
|
-
* @param apiEndpoint - Base url of the API
|
1182
|
-
* @param authProvider - Auth provider that injects authentication info to each request
|
1183
|
-
* @returns axios instance configured with specfic auth provider
|
1184
|
-
*
|
1185
|
-
* @example
|
1186
|
-
* ```typescript
|
1187
|
-
* const client = createApiClient("https://my-api-endpoint-base-url", new BasicAuthProvider("xxx","xxx"));
|
1188
|
-
* ```
|
1189
|
-
*/
|
1190
|
-
function createApiClient(apiEndpoint, authProvider) {
|
1191
|
-
// Add a request interceptor
|
1192
|
-
const instance = axios__default["default"].create({
|
1193
|
-
baseURL: apiEndpoint,
|
1194
|
-
});
|
1195
|
-
instance.interceptors.request.use(function (config) {
|
1196
|
-
return __awaiter(this, void 0, void 0, function* () {
|
1197
|
-
return (yield authProvider.AddAuthenticationInfo(config));
|
1198
|
-
});
|
1199
|
-
});
|
1200
|
-
return instance;
|
1201
|
-
}
|
1202
|
-
|
1203
|
-
// Copyright (c) Microsoft Corporation.
|
1204
|
-
/**
|
1205
|
-
* Provider that handles Bearer Token authentication
|
1206
|
-
*/
|
1207
|
-
class BearerTokenAuthProvider {
|
1208
|
-
/**
|
1209
|
-
* @param { () => Promise<string> } getToken - Function that returns the content of bearer token used in http request
|
1210
|
-
*/
|
1211
|
-
constructor(getToken) {
|
1212
|
-
this.getToken = getToken;
|
1213
|
-
}
|
1214
|
-
/**
|
1215
|
-
* Adds authentication info to http requests
|
1216
|
-
*
|
1217
|
-
* @param { AxiosRequestConfig } config - Contains all the request information and can be updated to include extra authentication info.
|
1218
|
-
* Refer https://axios-http.com/docs/req_config for detailed document.
|
1219
|
-
*
|
1220
|
-
* @returns Updated axios request config.
|
1221
|
-
*
|
1222
|
-
* @throws {@link ErrorCode|AuthorizationInfoAlreadyExists} - when Authorization header already exists in request configuration.
|
1223
|
-
*/
|
1224
|
-
AddAuthenticationInfo(config) {
|
1225
|
-
return __awaiter(this, void 0, void 0, function* () {
|
1226
|
-
const token = yield this.getToken();
|
1227
|
-
if (!config.headers) {
|
1228
|
-
config.headers = {};
|
1229
|
-
}
|
1230
|
-
if (config.headers["Authorization"]) {
|
1231
|
-
throw new ErrorWithCode(ErrorMessage.AuthorizationHeaderAlreadyExists, exports.ErrorCode.AuthorizationInfoAlreadyExists);
|
1232
|
-
}
|
1233
|
-
config.headers["Authorization"] = `Bearer ${token}`;
|
1234
|
-
return config;
|
1235
|
-
});
|
1236
|
-
}
|
1237
|
-
}
|
1238
|
-
|
1239
|
-
// Copyright (c) Microsoft Corporation.
|
1240
|
-
/**
|
1241
|
-
* Provider that handles Basic authentication
|
1242
|
-
*/
|
1243
|
-
class BasicAuthProvider {
|
1244
|
-
/**
|
1245
|
-
*
|
1246
|
-
* @param { string } userName - Username used in basic auth
|
1247
|
-
* @param { string } password - Password used in basic auth
|
1248
|
-
*
|
1249
|
-
* @throws {@link ErrorCode|InvalidParameter} - when username or password is empty.
|
1250
|
-
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
1251
|
-
*/
|
1252
|
-
constructor(userName, password) {
|
1253
|
-
if (!userName) {
|
1254
|
-
throw new ErrorWithCode(formatString(ErrorMessage.EmptyParameter, "username"), exports.ErrorCode.InvalidParameter);
|
1255
|
-
}
|
1256
|
-
if (!password) {
|
1257
|
-
throw new ErrorWithCode(formatString(ErrorMessage.EmptyParameter, "password"), exports.ErrorCode.InvalidParameter);
|
1258
|
-
}
|
1259
|
-
this.userName = userName;
|
1260
|
-
this.password = password;
|
1261
|
-
}
|
1262
|
-
/**
|
1263
|
-
* Adds authentication info to http requests
|
1264
|
-
*
|
1265
|
-
* @param { AxiosRequestConfig } config - Contains all the request information and can be updated to include extra authentication info.
|
1266
|
-
* Refer https://axios-http.com/docs/req_config for detailed document.
|
1267
|
-
*
|
1268
|
-
* @returns Updated axios request config.
|
1269
|
-
*
|
1270
|
-
* @throws {@link ErrorCode|AuthorizationInfoAlreadyExists} - when Authorization header or auth property already exists in request configuration.
|
1271
|
-
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
1272
|
-
*/
|
1273
|
-
AddAuthenticationInfo(config) {
|
1274
|
-
if (config.headers && config.headers["Authorization"]) {
|
1275
|
-
return Promise.reject(new ErrorWithCode(ErrorMessage.AuthorizationHeaderAlreadyExists, exports.ErrorCode.AuthorizationInfoAlreadyExists));
|
1276
|
-
}
|
1277
|
-
if (config.auth) {
|
1278
|
-
return Promise.reject(new ErrorWithCode(ErrorMessage.BasicCredentialAlreadyExists, exports.ErrorCode.AuthorizationInfoAlreadyExists));
|
1279
|
-
}
|
1280
|
-
config.auth = {
|
1281
|
-
username: this.userName,
|
1282
|
-
password: this.password,
|
1283
|
-
};
|
1284
|
-
return Promise.resolve(config);
|
1285
|
-
}
|
1286
|
-
}
|
1287
|
-
|
1288
|
-
// Copyright (c) Microsoft Corporation.
|
1289
|
-
/**
|
1290
|
-
* Provider that handles API Key authentication
|
1291
|
-
*/
|
1292
|
-
class ApiKeyProvider {
|
1293
|
-
/**
|
1294
|
-
*
|
1295
|
-
* @param { string } keyName - The name of request header or query parameter that specifies API Key
|
1296
|
-
* @param { string } keyValue - The value of API Key
|
1297
|
-
* @param { ApiKeyLocation } keyLocation - The location of API Key: request header or query parameter.
|
1298
|
-
*
|
1299
|
-
* @throws {@link ErrorCode|InvalidParameter} - when key name or key value is empty.
|
1300
|
-
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
1301
|
-
*/
|
1302
|
-
constructor(keyName, keyValue, keyLocation) {
|
1303
|
-
if (!keyName) {
|
1304
|
-
throw new ErrorWithCode(formatString(ErrorMessage.EmptyParameter, "keyName"), exports.ErrorCode.InvalidParameter);
|
1305
|
-
}
|
1306
|
-
if (!keyValue) {
|
1307
|
-
throw new ErrorWithCode(formatString(ErrorMessage.EmptyParameter, "keyVaule"), exports.ErrorCode.InvalidParameter);
|
1308
|
-
}
|
1309
|
-
this.keyName = keyName;
|
1310
|
-
this.keyValue = keyValue;
|
1311
|
-
this.keyLocation = keyLocation;
|
1312
|
-
}
|
1313
|
-
/**
|
1314
|
-
* Adds authentication info to http requests
|
1315
|
-
*
|
1316
|
-
* @param { AxiosRequestConfig } config - Contains all the request information and can be updated to include extra authentication info.
|
1317
|
-
* Refer https://axios-http.com/docs/req_config for detailed document.
|
1318
|
-
*
|
1319
|
-
* @returns Updated axios request config.
|
1320
|
-
*
|
1321
|
-
* @throws {@link ErrorCode|AuthorizationInfoAlreadyExists} - when API key already exists in request header or url query parameter.
|
1322
|
-
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
1323
|
-
*/
|
1324
|
-
AddAuthenticationInfo(config) {
|
1325
|
-
switch (this.keyLocation) {
|
1326
|
-
case exports.ApiKeyLocation.Header:
|
1327
|
-
if (!config.headers) {
|
1328
|
-
config.headers = {};
|
1329
|
-
}
|
1330
|
-
if (config.headers[this.keyName]) {
|
1331
|
-
return Promise.reject(new ErrorWithCode(formatString(ErrorMessage.DuplicateApiKeyInHeader, this.keyName), exports.ErrorCode.AuthorizationInfoAlreadyExists));
|
1332
|
-
}
|
1333
|
-
config.headers[this.keyName] = this.keyValue;
|
1334
|
-
break;
|
1335
|
-
case exports.ApiKeyLocation.QueryParams:
|
1336
|
-
if (!config.params) {
|
1337
|
-
config.params = {};
|
1338
|
-
}
|
1339
|
-
let urlHasDefinedApiKey = false;
|
1340
|
-
if (config.url) {
|
1341
|
-
const url = new URL(config.url, config.baseURL);
|
1342
|
-
urlHasDefinedApiKey = url.searchParams.has(this.keyName);
|
1343
|
-
}
|
1344
|
-
if (config.params[this.keyName] || urlHasDefinedApiKey) {
|
1345
|
-
return Promise.reject(new ErrorWithCode(formatString(ErrorMessage.DuplicateApiKeyInQueryParam, this.keyName), exports.ErrorCode.AuthorizationInfoAlreadyExists));
|
1346
|
-
}
|
1347
|
-
config.params[this.keyName] = this.keyValue;
|
1348
|
-
break;
|
1349
|
-
}
|
1350
|
-
return Promise.resolve(config);
|
1351
|
-
}
|
1352
|
-
}
|
1353
|
-
/**
|
1354
|
-
* Define available location for API Key location
|
1355
|
-
*/
|
1356
|
-
exports.ApiKeyLocation = void 0;
|
1357
|
-
(function (ApiKeyLocation) {
|
1358
|
-
/**
|
1359
|
-
* The API Key is placed in request header
|
1360
|
-
*/
|
1361
|
-
ApiKeyLocation[ApiKeyLocation["Header"] = 0] = "Header";
|
1362
|
-
/**
|
1363
|
-
* The API Key is placed in query parameter
|
1364
|
-
*/
|
1365
|
-
ApiKeyLocation[ApiKeyLocation["QueryParams"] = 1] = "QueryParams";
|
1366
|
-
})(exports.ApiKeyLocation || (exports.ApiKeyLocation = {}));
|
1367
|
-
|
1368
|
-
// Copyright (c) Microsoft Corporation.
|
1369
|
-
/**
|
1370
|
-
* Provider that handles Certificate authentication
|
1371
|
-
*/
|
1372
|
-
class CertificateAuthProvider {
|
1373
|
-
/**
|
1374
|
-
*
|
1375
|
-
* @param { SecureContextOptions } certOption - information about the cert used in http requests
|
1376
|
-
*
|
1377
|
-
* @throws {@link ErrorCode|InvalidParameter} - when cert option is empty.
|
1378
|
-
*/
|
1379
|
-
constructor(certOption) {
|
1380
|
-
if (certOption && Object.keys(certOption).length !== 0) {
|
1381
|
-
this.certOption = certOption;
|
1382
|
-
}
|
1383
|
-
else {
|
1384
|
-
throw new ErrorWithCode(formatString(ErrorMessage.EmptyParameter, "certOption"), exports.ErrorCode.InvalidParameter);
|
1385
|
-
}
|
1386
|
-
}
|
1387
|
-
/**
|
1388
|
-
* Adds authentication info to http requests.
|
1389
|
-
*
|
1390
|
-
* @param { AxiosRequestConfig } config - Contains all the request information and can be updated to include extra authentication info.
|
1391
|
-
* Refer https://axios-http.com/docs/req_config for detailed document.
|
1392
|
-
*
|
1393
|
-
* @returns Updated axios request config.
|
1394
|
-
*
|
1395
|
-
* @throws {@link ErrorCode|InvalidParameter} - when custom httpsAgent in the request has duplicate properties with certOption provided in constructor.
|
1396
|
-
*/
|
1397
|
-
AddAuthenticationInfo(config) {
|
1398
|
-
if (!config.httpsAgent) {
|
1399
|
-
config.httpsAgent = new https.Agent(this.certOption);
|
1400
|
-
}
|
1401
|
-
else {
|
1402
|
-
const existingProperties = new Set(Object.keys(config.httpsAgent.options));
|
1403
|
-
for (const property of Object.keys(this.certOption)) {
|
1404
|
-
if (existingProperties.has(property)) {
|
1405
|
-
return Promise.reject(new ErrorWithCode(formatString(ErrorMessage.DuplicateHttpsOptionProperty, property), exports.ErrorCode.InvalidParameter));
|
1406
|
-
}
|
1407
|
-
}
|
1408
|
-
Object.assign(config.httpsAgent.options, this.certOption);
|
1409
|
-
}
|
1410
|
-
return Promise.resolve(config);
|
1411
|
-
}
|
1412
|
-
}
|
1413
|
-
/**
|
1414
|
-
* Helper to create SecureContextOptions from PEM format cert
|
1415
|
-
*
|
1416
|
-
* @param { string | Buffer } cert - The cert chain in PEM format
|
1417
|
-
* @param { string | Buffer } key - The private key for the cert chain
|
1418
|
-
* @param { {passphrase?: string; ca?: string | Buffer} } options - Optional settings when create the cert options.
|
1419
|
-
*
|
1420
|
-
* @returns Instance of SecureContextOptions
|
1421
|
-
*
|
1422
|
-
* @throws {@link ErrorCode|InvalidParameter} - when any parameter is empty
|
1423
|
-
*
|
1424
|
-
*/
|
1425
|
-
function createPemCertOption(cert, key, options) {
|
1426
|
-
if (cert.length === 0) {
|
1427
|
-
throw new ErrorWithCode(formatString(ErrorMessage.EmptyParameter, "cert"), exports.ErrorCode.InvalidParameter);
|
1428
|
-
}
|
1429
|
-
if (key.length === 0) {
|
1430
|
-
throw new ErrorWithCode(formatString(ErrorMessage.EmptyParameter, "key"), exports.ErrorCode.InvalidParameter);
|
1431
|
-
}
|
1432
|
-
return {
|
1433
|
-
cert,
|
1434
|
-
key,
|
1435
|
-
passphrase: options === null || options === void 0 ? void 0 : options.passphrase,
|
1436
|
-
ca: options === null || options === void 0 ? void 0 : options.ca,
|
1437
|
-
};
|
1438
|
-
}
|
1439
|
-
/**
|
1440
|
-
* Helper to create SecureContextOptions from PFX format cert
|
1441
|
-
*
|
1442
|
-
* @param { string | Buffer } pfx - The content of .pfx file
|
1443
|
-
* @param { {passphrase?: string} } options - Optional settings when create the cert options.
|
1444
|
-
*
|
1445
|
-
* @returns Instance of SecureContextOptions
|
1446
|
-
*
|
1447
|
-
* @throws {@link ErrorCode|InvalidParameter} - when any parameter is empty
|
1448
|
-
*
|
1449
|
-
*/
|
1450
|
-
function createPfxCertOption(pfx, options) {
|
1451
|
-
if (pfx.length === 0) {
|
1452
|
-
throw new ErrorWithCode(formatString(ErrorMessage.EmptyParameter, "pfx"), exports.ErrorCode.InvalidParameter);
|
1453
|
-
}
|
1454
|
-
return {
|
1455
|
-
pfx,
|
1456
|
-
passphrase: options === null || options === void 0 ? void 0 : options.passphrase,
|
1457
|
-
};
|
1458
|
-
}
|
1459
|
-
|
1460
|
-
// Copyright (c) Microsoft Corporation.
|
1461
|
-
// Licensed under the MIT license.
|
1462
|
-
/**
|
1463
|
-
* The target type where the notification will be sent to.
|
1464
|
-
*
|
1465
|
-
* @remarks
|
1466
|
-
* - "Channel" means to a team channel. (By default, notification to a team will be sent to its "General" channel.)
|
1467
|
-
* - "Group" means to a group chat.
|
1468
|
-
* - "Person" means to a personal chat.
|
1469
|
-
*/
|
1470
|
-
exports.NotificationTargetType = void 0;
|
1471
|
-
(function (NotificationTargetType) {
|
1472
|
-
/**
|
1473
|
-
* The notification will be sent to a team channel.
|
1474
|
-
* (By default, notification to a team will be sent to its "General" channel.)
|
1475
|
-
*/
|
1476
|
-
NotificationTargetType["Channel"] = "Channel";
|
1477
|
-
/**
|
1478
|
-
* The notification will be sent to a group chat.
|
1479
|
-
*/
|
1480
|
-
NotificationTargetType["Group"] = "Group";
|
1481
|
-
/**
|
1482
|
-
* The notification will be sent to a personal chat.
|
1483
|
-
*/
|
1484
|
-
NotificationTargetType["Person"] = "Person";
|
1485
|
-
})(exports.NotificationTargetType || (exports.NotificationTargetType = {}));
|
1486
|
-
/**
|
1487
|
-
* Options used to control how the response card will be sent to users.
|
1488
|
-
*/
|
1489
|
-
exports.AdaptiveCardResponse = void 0;
|
1490
|
-
(function (AdaptiveCardResponse) {
|
1491
|
-
/**
|
1492
|
-
* The response card will be replaced the current one for the interactor who trigger the action.
|
1493
|
-
*/
|
1494
|
-
AdaptiveCardResponse[AdaptiveCardResponse["ReplaceForInteractor"] = 0] = "ReplaceForInteractor";
|
1495
|
-
/**
|
1496
|
-
* The response card will be replaced the current one for all users in the chat.
|
1497
|
-
*/
|
1498
|
-
AdaptiveCardResponse[AdaptiveCardResponse["ReplaceForAll"] = 1] = "ReplaceForAll";
|
1499
|
-
/**
|
1500
|
-
* The response card will be sent as a new message for all users in the chat.
|
1501
|
-
*/
|
1502
|
-
AdaptiveCardResponse[AdaptiveCardResponse["NewForAll"] = 2] = "NewForAll";
|
1503
|
-
})(exports.AdaptiveCardResponse || (exports.AdaptiveCardResponse = {}));
|
1504
|
-
/**
|
1505
|
-
* Status code for an `application/vnd.microsoft.error` invoke response.
|
1506
|
-
*/
|
1507
|
-
exports.InvokeResponseErrorCode = void 0;
|
1508
|
-
(function (InvokeResponseErrorCode) {
|
1509
|
-
/**
|
1510
|
-
* Invalid request.
|
1511
|
-
*/
|
1512
|
-
InvokeResponseErrorCode[InvokeResponseErrorCode["BadRequest"] = 400] = "BadRequest";
|
1513
|
-
/**
|
1514
|
-
* Internal server error.
|
1515
|
-
*/
|
1516
|
-
InvokeResponseErrorCode[InvokeResponseErrorCode["InternalServerError"] = 500] = "InternalServerError";
|
1517
|
-
})(exports.InvokeResponseErrorCode || (exports.InvokeResponseErrorCode = {}));
|
1518
|
-
|
1519
|
-
// Copyright (c) Microsoft Corporation.
|
1520
|
-
let DIALOG_NAME = "BotSsoExecutionDialog";
|
1521
|
-
let TEAMS_SSO_PROMPT_ID = "TeamsFxSsoPrompt";
|
1522
|
-
let COMMAND_ROUTE_DIALOG = "CommandRouteDialog";
|
1523
|
-
/**
|
1524
|
-
* Sso execution dialog, use to handle sso command
|
1525
|
-
*/
|
1526
|
-
class BotSsoExecutionDialog extends botbuilderDialogs.ComponentDialog {
|
1527
|
-
/**
|
1528
|
-
* Creates a new instance of the BotSsoExecutionDialog.
|
1529
|
-
* @param {@link Storage} dedupStorage Helper storage to remove duplicated messages
|
1530
|
-
* @param {@link TeamsBotSsoPromptSettings} settings The list of scopes for which the token will have access
|
1531
|
-
* @param {@link OnBehalfOfCredentialAuthConfig} authConfig The authentication configuration.
|
1532
|
-
* @param {string} initiateLoginEndpoint Login URL for Teams to redirect to.
|
1533
|
-
* @param {string} dialogName custom dialog name
|
1534
|
-
*/
|
1535
|
-
constructor(dedupStorage, ssoPromptSettings, authConfig, initiateLoginEndpoint, dialogName) {
|
1536
|
-
super(dialogName !== null && dialogName !== void 0 ? dialogName : DIALOG_NAME);
|
1537
|
-
this.dedupStorageKeys = [];
|
1538
|
-
// Map to store the commandId and triggerPatterns, key: commandId, value: triggerPatterns
|
1539
|
-
this.commandMapping = new Map();
|
1540
|
-
if (dialogName) {
|
1541
|
-
DIALOG_NAME = dialogName;
|
1542
|
-
TEAMS_SSO_PROMPT_ID = dialogName + TEAMS_SSO_PROMPT_ID;
|
1543
|
-
COMMAND_ROUTE_DIALOG = dialogName + COMMAND_ROUTE_DIALOG;
|
1544
|
-
}
|
1545
|
-
const ssoDialog = new TeamsBotSsoPrompt(authConfig, initiateLoginEndpoint, TEAMS_SSO_PROMPT_ID, ssoPromptSettings);
|
1546
|
-
this.addDialog(ssoDialog);
|
1547
|
-
this.initialDialogId = COMMAND_ROUTE_DIALOG;
|
1548
|
-
this.dedupStorage = dedupStorage;
|
1549
|
-
this.dedupStorageKeys = [];
|
1550
|
-
const commandRouteDialog = new botbuilderDialogs.WaterfallDialog(COMMAND_ROUTE_DIALOG, [
|
1551
|
-
this.commandRouteStep.bind(this),
|
1552
|
-
]);
|
1553
|
-
this.addDialog(commandRouteDialog);
|
1554
|
-
}
|
1555
|
-
/**
|
1556
|
-
* Add TeamsFxBotSsoCommandHandler instance
|
1557
|
-
* @param handler {@link BotSsoExecutionDialogHandler} callback function
|
1558
|
-
* @param triggerPatterns The trigger pattern
|
1559
|
-
*/
|
1560
|
-
addCommand(handler, triggerPatterns) {
|
1561
|
-
const commandId = this.getCommandHash(triggerPatterns);
|
1562
|
-
const dialog = new botbuilderDialogs.WaterfallDialog(commandId, [
|
1563
|
-
this.ssoStep.bind(this),
|
1564
|
-
this.dedupStep.bind(this),
|
1565
|
-
(stepContext) => __awaiter(this, void 0, void 0, function* () {
|
1566
|
-
const tokenResponse = stepContext.result.tokenResponse;
|
1567
|
-
const context = stepContext.context;
|
1568
|
-
const message = stepContext.result.message;
|
1569
|
-
try {
|
1570
|
-
if (tokenResponse) {
|
1571
|
-
yield handler(context, tokenResponse, message);
|
1572
|
-
}
|
1573
|
-
else {
|
1574
|
-
throw new Error(ErrorMessage.FailedToRetrieveSsoToken);
|
1575
|
-
}
|
1576
|
-
return yield stepContext.endDialog();
|
1577
|
-
}
|
1578
|
-
catch (error) {
|
1579
|
-
const errorMsg = formatString(ErrorMessage.FailedToProcessSsoHandler, error.message);
|
1580
|
-
internalLogger.error(errorMsg);
|
1581
|
-
return yield stepContext.endDialog(new ErrorWithCode(errorMsg, exports.ErrorCode.FailedToProcessSsoHandler));
|
1582
|
-
}
|
1583
|
-
}),
|
1584
|
-
]);
|
1585
|
-
this.commandMapping.set(commandId, triggerPatterns);
|
1586
|
-
this.addDialog(dialog);
|
1587
|
-
}
|
1588
|
-
getCommandHash(patterns) {
|
1589
|
-
const expressions = Array.isArray(patterns) ? patterns : [patterns];
|
1590
|
-
const patternStr = expressions.join();
|
1591
|
-
const patternStrWithoutSpecialChar = patternStr.replace(/[^a-zA-Z0-9]/g, "");
|
1592
|
-
const hash = crypto.createHash("sha256").update(patternStr).digest("hex").toLowerCase();
|
1593
|
-
return patternStrWithoutSpecialChar + hash;
|
1594
|
-
}
|
1595
|
-
/**
|
1596
|
-
* The run method handles the incoming activity (in the form of a DialogContext) and passes it through the dialog system.
|
1597
|
-
*
|
1598
|
-
* @param context The context object for the current turn.
|
1599
|
-
* @param accessor The instance of StatePropertyAccessor for dialog system.
|
1600
|
-
*/
|
1601
|
-
run(context, accessor) {
|
1602
|
-
return __awaiter(this, void 0, void 0, function* () {
|
1603
|
-
const dialogSet = new botbuilderDialogs.DialogSet(accessor);
|
1604
|
-
dialogSet.add(this);
|
1605
|
-
const dialogContext = yield dialogSet.createContext(context);
|
1606
|
-
this.ensureMsTeamsChannel(dialogContext);
|
1607
|
-
const results = yield dialogContext.continueDialog();
|
1608
|
-
if (results && results.status === botbuilderDialogs.DialogTurnStatus.empty) {
|
1609
|
-
yield dialogContext.beginDialog(this.id);
|
1610
|
-
}
|
1611
|
-
else if (results &&
|
1612
|
-
results.status === botbuilderDialogs.DialogTurnStatus.complete &&
|
1613
|
-
results.result instanceof Error) {
|
1614
|
-
throw results.result;
|
1615
|
-
}
|
1616
|
-
});
|
1617
|
-
}
|
1618
|
-
getActivityText(activity) {
|
1619
|
-
let text = activity.text;
|
1620
|
-
const removedMentionText = botbuilder.TurnContext.removeRecipientMention(activity);
|
1621
|
-
if (removedMentionText) {
|
1622
|
-
text = removedMentionText
|
1623
|
-
.toLowerCase()
|
1624
|
-
.replace(/\n|\r\n/g, "")
|
1625
|
-
.trim();
|
1626
|
-
}
|
1627
|
-
return text;
|
1628
|
-
}
|
1629
|
-
commandRouteStep(stepContext) {
|
1630
|
-
return __awaiter(this, void 0, void 0, function* () {
|
1631
|
-
const turnContext = stepContext.context;
|
1632
|
-
const text = this.getActivityText(turnContext.activity);
|
1633
|
-
const commandId = this.getMatchesCommandId(text);
|
1634
|
-
if (commandId) {
|
1635
|
-
return yield stepContext.beginDialog(commandId);
|
1636
|
-
}
|
1637
|
-
const errorMsg = formatString(ErrorMessage.CannotFindCommand, turnContext.activity.text);
|
1638
|
-
internalLogger.error(errorMsg);
|
1639
|
-
throw new ErrorWithCode(errorMsg, exports.ErrorCode.CannotFindCommand);
|
1640
|
-
});
|
1641
|
-
}
|
1642
|
-
ssoStep(stepContext) {
|
1643
|
-
return __awaiter(this, void 0, void 0, function* () {
|
1644
|
-
try {
|
1645
|
-
const turnContext = stepContext.context;
|
1646
|
-
const text = this.getActivityText(turnContext.activity);
|
1647
|
-
const message = {
|
1648
|
-
text,
|
1649
|
-
};
|
1650
|
-
stepContext.options.commandMessage = message;
|
1651
|
-
return yield stepContext.beginDialog(TEAMS_SSO_PROMPT_ID);
|
1652
|
-
}
|
1653
|
-
catch (error) {
|
1654
|
-
const errorMsg = formatString(ErrorMessage.FailedToRunSsoStep, error.message);
|
1655
|
-
internalLogger.error(errorMsg);
|
1656
|
-
return yield stepContext.endDialog(new ErrorWithCode(errorMsg, exports.ErrorCode.FailedToRunSsoStep));
|
1657
|
-
}
|
1658
|
-
});
|
1659
|
-
}
|
1660
|
-
dedupStep(stepContext) {
|
1661
|
-
return __awaiter(this, void 0, void 0, function* () {
|
1662
|
-
const tokenResponse = stepContext.result;
|
1663
|
-
if (!tokenResponse) {
|
1664
|
-
internalLogger.error(ErrorMessage.FailedToRetrieveSsoToken);
|
1665
|
-
return yield stepContext.endDialog(new ErrorWithCode(ErrorMessage.FailedToRetrieveSsoToken, exports.ErrorCode.FailedToRunSsoStep));
|
1666
|
-
}
|
1667
|
-
try {
|
1668
|
-
// Only dedup after ssoStep to make sure that all Teams client would receive the login request
|
1669
|
-
if (tokenResponse && (yield this.shouldDedup(stepContext.context))) {
|
1670
|
-
return botbuilderDialogs.Dialog.EndOfTurn;
|
1671
|
-
}
|
1672
|
-
return yield stepContext.next({
|
1673
|
-
tokenResponse,
|
1674
|
-
message: stepContext.options.commandMessage,
|
1675
|
-
});
|
1676
|
-
}
|
1677
|
-
catch (error) {
|
1678
|
-
const errorMsg = formatString(ErrorMessage.FailedToRunDedupStep, error.message);
|
1679
|
-
internalLogger.error(errorMsg);
|
1680
|
-
return yield stepContext.endDialog(new ErrorWithCode(errorMsg, exports.ErrorCode.FailedToRunDedupStep));
|
1681
|
-
}
|
1682
|
-
});
|
1683
|
-
}
|
1684
|
-
/**
|
1685
|
-
* Called when the component is ending.
|
1686
|
-
*
|
1687
|
-
* @param context Context for the current turn of conversation.
|
1688
|
-
*/
|
1689
|
-
onEndDialog(context) {
|
1690
|
-
return __awaiter(this, void 0, void 0, function* () {
|
1691
|
-
const conversationId = context.activity.conversation.id;
|
1692
|
-
const currentDedupKeys = this.dedupStorageKeys.filter((key) => key.indexOf(conversationId) > 0);
|
1693
|
-
yield this.dedupStorage.delete(currentDedupKeys);
|
1694
|
-
this.dedupStorageKeys = this.dedupStorageKeys.filter((key) => key.indexOf(conversationId) < 0);
|
1695
|
-
});
|
1696
|
-
}
|
1697
|
-
/**
|
1698
|
-
* If a user is signed into multiple Teams clients, the Bot might receive a "signin/tokenExchange" from each client.
|
1699
|
-
* Each token exchange request for a specific user login will have an identical activity.value.Id.
|
1700
|
-
* Only one of these token exchange requests should be processed by the bot. For a distributed bot in production,
|
1701
|
-
* this requires a distributed storage to ensure only one token exchange is processed.
|
1702
|
-
* @param context Context for the current turn of conversation.
|
1703
|
-
* @returns boolean value indicate whether the message should be removed
|
1704
|
-
*/
|
1705
|
-
shouldDedup(context) {
|
1706
|
-
return __awaiter(this, void 0, void 0, function* () {
|
1707
|
-
const storeItem = {
|
1708
|
-
eTag: context.activity.value.id,
|
1709
|
-
};
|
1710
|
-
const key = this.getStorageKey(context);
|
1711
|
-
const storeItems = { [key]: storeItem };
|
1712
|
-
try {
|
1713
|
-
yield this.dedupStorage.write(storeItems);
|
1714
|
-
this.dedupStorageKeys.push(key);
|
1715
|
-
}
|
1716
|
-
catch (err) {
|
1717
|
-
if (err instanceof Error && err.message.indexOf("eTag conflict")) {
|
1718
|
-
return true;
|
1719
|
-
}
|
1720
|
-
throw err;
|
1721
|
-
}
|
1722
|
-
return false;
|
1723
|
-
});
|
1724
|
-
}
|
1725
|
-
getStorageKey(context) {
|
1726
|
-
if (!context || !context.activity || !context.activity.conversation) {
|
1727
|
-
throw new Error("Invalid context, can not get storage key!");
|
1728
|
-
}
|
1729
|
-
const activity = context.activity;
|
1730
|
-
const channelId = activity.channelId;
|
1731
|
-
const conversationId = activity.conversation.id;
|
1732
|
-
if (activity.type !== botbuilder.ActivityTypes.Invoke || activity.name !== botbuilder.tokenExchangeOperationName) {
|
1733
|
-
throw new Error("TokenExchangeState can only be used with Invokes of signin/tokenExchange.");
|
1734
|
-
}
|
1735
|
-
const value = activity.value;
|
1736
|
-
if (!value || !value.id) {
|
1737
|
-
throw new Error("Invalid signin/tokenExchange. Missing activity.value.id.");
|
1738
|
-
}
|
1739
|
-
return `${channelId}/${conversationId}/${value.id}`;
|
1740
|
-
}
|
1741
|
-
matchPattern(pattern, text) {
|
1742
|
-
if (text) {
|
1743
|
-
if (typeof pattern === "string") {
|
1744
|
-
const regExp = new RegExp(pattern, "i");
|
1745
|
-
return regExp.test(text);
|
1746
|
-
}
|
1747
|
-
if (pattern instanceof RegExp) {
|
1748
|
-
const matches = text.match(pattern);
|
1749
|
-
return matches !== null && matches !== void 0 ? matches : false;
|
1750
|
-
}
|
1751
|
-
}
|
1752
|
-
return false;
|
1753
|
-
}
|
1754
|
-
isPatternMatched(patterns, text) {
|
1755
|
-
const expressions = Array.isArray(patterns) ? patterns : [patterns];
|
1756
|
-
for (const ex of expressions) {
|
1757
|
-
const matches = this.matchPattern(ex, text);
|
1758
|
-
return !!matches;
|
1759
|
-
}
|
1760
|
-
return false;
|
1761
|
-
}
|
1762
|
-
getMatchesCommandId(text) {
|
1763
|
-
for (const command of this.commandMapping) {
|
1764
|
-
const pattern = command[1];
|
1765
|
-
if (this.isPatternMatched(pattern, text)) {
|
1766
|
-
return command[0];
|
1767
|
-
}
|
1768
|
-
}
|
1769
|
-
return undefined;
|
1770
|
-
}
|
1771
|
-
/**
|
1772
|
-
* Ensure bot is running in MS Teams since TeamsBotSsoPrompt is only supported in MS Teams channel.
|
1773
|
-
* @param dc dialog context
|
1774
|
-
* @throws {@link ErrorCode|ChannelNotSupported} if bot channel is not MS Teams
|
1775
|
-
* @internal
|
1776
|
-
*/
|
1777
|
-
ensureMsTeamsChannel(dc) {
|
1778
|
-
if (dc.context.activity.channelId != botbuilder.Channels.Msteams) {
|
1779
|
-
const errorMsg = formatString(ErrorMessage.OnlyMSTeamsChannelSupported, "SSO execution dialog");
|
1780
|
-
internalLogger.error(errorMsg);
|
1781
|
-
throw new ErrorWithCode(errorMsg, exports.ErrorCode.ChannelNotSupported);
|
1782
|
-
}
|
1783
|
-
}
|
1784
|
-
}
|
1785
|
-
|
1786
|
-
// Copyright (c) Microsoft Corporation.
|
1787
|
-
/**
|
1788
|
-
* Provides utility method to build bot message with cards that supported in Teams.
|
1789
|
-
*/
|
1790
|
-
class MessageBuilder {
|
1791
|
-
/**
|
1792
|
-
* Build a bot message activity attached with adaptive card.
|
1793
|
-
*
|
1794
|
-
* @param cardTemplate The adaptive card template.
|
1795
|
-
* @param data card data used to render the template.
|
1796
|
-
* @returns A bot message activity attached with an adaptive card.
|
1797
|
-
*
|
1798
|
-
* @example
|
1799
|
-
* ```javascript
|
1800
|
-
* const cardTemplate = {
|
1801
|
-
* type: "AdaptiveCard",
|
1802
|
-
* body: [
|
1803
|
-
* {
|
1804
|
-
* "type": "TextBlock",
|
1805
|
-
* "text": "${title}",
|
1806
|
-
* "size": "Large"
|
1807
|
-
* },
|
1808
|
-
* {
|
1809
|
-
* "type": "TextBlock",
|
1810
|
-
* "text": "${description}"
|
1811
|
-
* }],
|
1812
|
-
* $schema: "http://adaptivecards.io/schemas/adaptive-card.json",
|
1813
|
-
* version: "1.4"
|
1814
|
-
* };
|
1815
|
-
*
|
1816
|
-
* type CardData = {
|
1817
|
-
* title: string,
|
1818
|
-
* description: string
|
1819
|
-
* };
|
1820
|
-
* const card = MessageBuilder.attachAdaptiveCard<CardData>(
|
1821
|
-
* cardTemplate, {
|
1822
|
-
* title: "sample card title",
|
1823
|
-
* description: "sample card description"
|
1824
|
-
* });
|
1825
|
-
* ```
|
1826
|
-
*/
|
1827
|
-
static attachAdaptiveCard(cardTemplate, data) {
|
1828
|
-
const context = {
|
1829
|
-
$root: data,
|
1830
|
-
};
|
1831
|
-
return {
|
1832
|
-
attachments: [botbuilder.CardFactory.adaptiveCard(new ACData__namespace.Template(cardTemplate).expand(context))],
|
1833
|
-
};
|
1834
|
-
}
|
1835
|
-
/**
|
1836
|
-
* Build a bot message activity attached with an adaptive card.
|
1837
|
-
*
|
1838
|
-
* @param card The adaptive card content.
|
1839
|
-
* @returns A bot message activity attached with an adaptive card.
|
1840
|
-
*/
|
1841
|
-
static attachAdaptiveCardWithoutData(card) {
|
1842
|
-
return {
|
1843
|
-
attachments: [botbuilder.CardFactory.adaptiveCard(card)],
|
1844
|
-
};
|
1845
|
-
}
|
1846
|
-
/**
|
1847
|
-
* Build a bot message activity attached with an hero card.
|
1848
|
-
*
|
1849
|
-
* @param title The card title.
|
1850
|
-
* @param images Optional. The array of images to include on the card.
|
1851
|
-
* @param buttons Optional. The array of buttons to include on the card. Each `string` in the array
|
1852
|
-
* is converted to an `imBack` button with a title and value set to the value of the string.
|
1853
|
-
* @param other Optional. Any additional properties to include on the card.
|
1854
|
-
*
|
1855
|
-
* @returns A bot message activity attached with a hero card.
|
1856
|
-
*
|
1857
|
-
* @example
|
1858
|
-
* ```javascript
|
1859
|
-
* const message = MessageBuilder.attachHeroCard(
|
1860
|
-
* 'sample title',
|
1861
|
-
* ['https://example.com/sample.jpg'],
|
1862
|
-
* ['action']
|
1863
|
-
* );
|
1864
|
-
* ```
|
1865
|
-
*/
|
1866
|
-
static attachHeroCard(title, images, buttons, other) {
|
1867
|
-
return MessageBuilder.attachContent(botbuilder.CardFactory.heroCard(title, images, buttons, other));
|
1868
|
-
}
|
1869
|
-
/**
|
1870
|
-
* Returns an attachment for a sign-in card.
|
1871
|
-
*
|
1872
|
-
* @param title The title for the card's sign-in button.
|
1873
|
-
* @param url The URL of the sign-in page to use.
|
1874
|
-
* @param text Optional. Additional text to include on the card.
|
1875
|
-
*
|
1876
|
-
* @returns A bot message activity attached with a sign-in card.
|
1877
|
-
*
|
1878
|
-
* @remarks
|
1879
|
-
* For channels that don't natively support sign-in cards, an alternative message is rendered.
|
1880
|
-
*/
|
1881
|
-
static attachSigninCard(title, url, text) {
|
1882
|
-
return MessageBuilder.attachContent(botbuilder.CardFactory.signinCard(title, url, text));
|
1883
|
-
}
|
1884
|
-
/**
|
1885
|
-
* Build a bot message activity attached with an Office 365 connector card.
|
1886
|
-
*
|
1887
|
-
* @param card A description of the Office 365 connector card.
|
1888
|
-
* @returns A bot message activity attached with an Office 365 connector card.
|
1889
|
-
*/
|
1890
|
-
static attachO365ConnectorCard(card) {
|
1891
|
-
return MessageBuilder.attachContent(botbuilder.CardFactory.o365ConnectorCard(card));
|
1892
|
-
}
|
1893
|
-
/**
|
1894
|
-
* Build a message activity attached with a receipt card.
|
1895
|
-
* @param card A description of the receipt card.
|
1896
|
-
* @returns A message activity attached with a receipt card.
|
1897
|
-
*/
|
1898
|
-
static AttachReceiptCard(card) {
|
1899
|
-
return MessageBuilder.attachContent(botbuilder.CardFactory.receiptCard(card));
|
1900
|
-
}
|
1901
|
-
/**
|
1902
|
-
*
|
1903
|
-
* @param title The card title.
|
1904
|
-
* @param images Optional. The array of images to include on the card.
|
1905
|
-
* @param buttons Optional. The array of buttons to include on the card. Each `string` in the array
|
1906
|
-
* is converted to an `imBack` button with a title and value set to the value of the string.
|
1907
|
-
* @param other Optional. Any additional properties to include on the card.
|
1908
|
-
* @returns A message activity attached with a thumbnail card
|
1909
|
-
*/
|
1910
|
-
static attachThumbnailCard(title, images, buttons, other) {
|
1911
|
-
return MessageBuilder.attachContent(botbuilder.CardFactory.thumbnailCard(title, images, buttons, other));
|
1912
|
-
}
|
1913
|
-
/**
|
1914
|
-
* Add an attachement to a bot activity.
|
1915
|
-
* @param attachement The attachment object to attach.
|
1916
|
-
* @returns A message activity with an attachment.
|
1917
|
-
*/
|
1918
|
-
static attachContent(attachement) {
|
1919
|
-
return {
|
1920
|
-
attachments: [attachement],
|
1921
|
-
};
|
1922
|
-
}
|
1923
|
-
}
|
1924
|
-
|
1925
|
-
// Copyright (c) Microsoft Corporation.
|
1926
|
-
/**
|
1927
|
-
* Available response type for an adaptive card invoke response.
|
1928
|
-
* @internal
|
1929
|
-
*/
|
1930
|
-
var InvokeResponseType;
|
1931
|
-
(function (InvokeResponseType) {
|
1932
|
-
InvokeResponseType["AdaptiveCard"] = "application/vnd.microsoft.card.adaptive";
|
1933
|
-
InvokeResponseType["Message"] = "application/vnd.microsoft.activity.message";
|
1934
|
-
InvokeResponseType["Error"] = "application/vnd.microsoft.error";
|
1935
|
-
})(InvokeResponseType || (InvokeResponseType = {}));
|
1936
|
-
/**
|
1937
|
-
* Provides methods for formatting various invoke responses a bot can send to respond to an invoke request.
|
1938
|
-
*
|
1939
|
-
* @remarks
|
1940
|
-
* All of these functions return an `InvokeResponse` object, which can be
|
1941
|
-
* passed as input to generate a new `invokeResponse` activity.
|
1942
|
-
*
|
1943
|
-
* This example sends an invoke response that contains an adaptive card.
|
1944
|
-
*
|
1945
|
-
* ```typescript
|
1946
|
-
*
|
1947
|
-
* const myCard = {
|
1948
|
-
* type: "AdaptiveCard",
|
1949
|
-
* body: [
|
1950
|
-
* {
|
1951
|
-
* "type": "TextBlock",
|
1952
|
-
* "text": "This is a sample card"
|
1953
|
-
* }],
|
1954
|
-
* $schema: "http://adaptivecards.io/schemas/adaptive-card.json",
|
1955
|
-
* version: "1.4"
|
1956
|
-
* };
|
1957
|
-
*
|
1958
|
-
* const invokeResponse = InvokeResponseFactory.adaptiveCard(myCard);
|
1959
|
-
* await context.sendActivity({
|
1960
|
-
* type: ActivityTypes.InvokeResponse,
|
1961
|
-
* value: invokeResponse,
|
1962
|
-
* });
|
1963
|
-
* ```
|
1964
|
-
*/
|
1965
|
-
class InvokeResponseFactory {
|
1966
|
-
/**
|
1967
|
-
* Create an invoke response from a text message.
|
1968
|
-
* The type of the invoke response is `application/vnd.microsoft.activity.message`
|
1969
|
-
* indicates the request was successfully processed.
|
1970
|
-
*
|
1971
|
-
* @param message - A text message included in a invoke response.
|
1972
|
-
*
|
1973
|
-
* @returns An `InvokeResponse` object.
|
1974
|
-
*/
|
1975
|
-
static textMessage(message) {
|
1976
|
-
if (!message) {
|
1977
|
-
throw new Error("The text message cannot be null or empty");
|
1978
|
-
}
|
1979
|
-
return {
|
1980
|
-
status: botbuilder.StatusCodes.OK,
|
1981
|
-
body: {
|
1982
|
-
statusCode: botbuilder.StatusCodes.OK,
|
1983
|
-
type: InvokeResponseType.Message,
|
1984
|
-
value: message,
|
1985
|
-
},
|
1986
|
-
};
|
1987
|
-
}
|
1988
|
-
/**
|
1989
|
-
* Create an invoke response from an adaptive card.
|
1990
|
-
*
|
1991
|
-
* The type of the invoke response is `application/vnd.microsoft.card.adaptive` indicates
|
1992
|
-
* the request was successfully processed, and the response includes an adaptive card
|
1993
|
-
* that the client should display in place of the current one.
|
1994
|
-
*
|
1995
|
-
* @param card - The adaptive card JSON payload.
|
1996
|
-
*
|
1997
|
-
* @returns An `InvokeResponse` object.
|
1998
|
-
*/
|
1999
|
-
static adaptiveCard(card) {
|
2000
|
-
if (!card) {
|
2001
|
-
throw new Error("The adaptive card content cannot be null or undefined");
|
2002
|
-
}
|
2003
|
-
return {
|
2004
|
-
status: botbuilder.StatusCodes.OK,
|
2005
|
-
body: {
|
2006
|
-
statusCode: botbuilder.StatusCodes.OK,
|
2007
|
-
type: InvokeResponseType.AdaptiveCard,
|
2008
|
-
value: card,
|
2009
|
-
},
|
2010
|
-
};
|
2011
|
-
}
|
2012
|
-
/**
|
2013
|
-
* Create an invoke response with error code and message.
|
2014
|
-
*
|
2015
|
-
* The type of the invoke response is `application/vnd.microsoft.error` indicates
|
2016
|
-
* the request was failed to processed.
|
2017
|
-
*
|
2018
|
-
* @param errorCode - The status code indicates error, available values:
|
2019
|
-
* - 400 (BadRequest): indicate the incoming request was invalid.
|
2020
|
-
* - 500 (InternalServerError): indicate an unexpected error occurred.
|
2021
|
-
* @param errorMessage - The error message.
|
2022
|
-
*
|
2023
|
-
* @returns An `InvokeResponse` object.
|
2024
|
-
*/
|
2025
|
-
static errorResponse(errorCode, errorMessage) {
|
2026
|
-
return {
|
2027
|
-
status: botbuilder.StatusCodes.OK,
|
2028
|
-
body: {
|
2029
|
-
statusCode: errorCode,
|
2030
|
-
type: InvokeResponseType.Error,
|
2031
|
-
value: {
|
2032
|
-
code: errorCode.toString(),
|
2033
|
-
message: errorMessage,
|
2034
|
-
},
|
2035
|
-
},
|
2036
|
-
};
|
2037
|
-
}
|
2038
|
-
/**
|
2039
|
-
* Create an invoke response with status code and response value.
|
2040
|
-
* @param statusCode - The status code.
|
2041
|
-
* @param body - The value of the response body.
|
2042
|
-
*
|
2043
|
-
* @returns An `InvokeResponse` object.
|
2044
|
-
*/
|
2045
|
-
static createInvokeResponse(statusCode, body) {
|
2046
|
-
return {
|
2047
|
-
status: statusCode,
|
2048
|
-
body: body,
|
2049
|
-
};
|
2050
|
-
}
|
2051
|
-
}
|
2052
|
-
|
2053
|
-
// Copyright (c) Microsoft Corporation.
|
2054
|
-
/**
|
2055
|
-
* Retrieve the OAuth Sign in Link to use in the MessagingExtensionResult Suggested Actions.
|
2056
|
-
* This method only work on MessageExtension with Query now.
|
2057
|
-
*
|
2058
|
-
* @param {OnBehalfOfCredentialAuthConfig} authConfig - User custom the message extension authentication configuration.
|
2059
|
-
* @param {initiateLoginEndpoint} initiateLoginEndpoint - Login page for Teams to redirect to.
|
2060
|
-
* @param {string | string[]} scopes - The list of scopes for which the token will have access.
|
2061
|
-
*
|
2062
|
-
* @returns SignIn link SilentAuth CardAction with 200 status code.
|
2063
|
-
*/
|
2064
|
-
function getSignInResponseForMessageExtensionWithSilentAuthConfig(authConfig, initiateLoginEndpoint, scopes) {
|
2065
|
-
const scopesArray = getScopesArray(scopes);
|
2066
|
-
const signInLink = `${initiateLoginEndpoint}?scope=${encodeURI(scopesArray.join(" "))}&clientId=${authConfig.clientId}&tenantId=${authConfig.tenantId}`;
|
2067
|
-
return {
|
2068
|
-
composeExtension: {
|
2069
|
-
type: "silentAuth",
|
2070
|
-
suggestedActions: {
|
2071
|
-
actions: [
|
2072
|
-
{
|
2073
|
-
type: "openUrl",
|
2074
|
-
value: signInLink,
|
2075
|
-
title: "Message Extension OAuth",
|
2076
|
-
},
|
2077
|
-
],
|
2078
|
-
},
|
2079
|
-
},
|
2080
|
-
};
|
2081
|
-
}
|
2082
|
-
/**
|
2083
|
-
* Retrieve the OAuth Sign in Link to use in the MessagingExtensionResult Suggested Actions.
|
2084
|
-
* This method just a workaround for link unfurling now.
|
2085
|
-
*
|
2086
|
-
* @param {OnBehalfOfCredentialAuthConfig} authConfig - User custom the message extension authentication configuration.
|
2087
|
-
* @param {initiateLoginEndpoint} initiateLoginEndpoint - Login page for Teams to redirect to.
|
2088
|
-
* @param {string | string[]} scopes - The list of scopes for which the token will have access.
|
2089
|
-
*
|
2090
|
-
* @returns SignIn link Auth CardAction with 200 status code.
|
2091
|
-
*/
|
2092
|
-
function getSignInResponseForMessageExtensionWithAuthConfig(authConfig, initiateLoginEndpoint, scopes) {
|
2093
|
-
const scopesArray = getScopesArray(scopes);
|
2094
|
-
const signInLink = `${initiateLoginEndpoint}?scope=${encodeURI(scopesArray.join(" "))}&clientId=${authConfig.clientId}&tenantId=${authConfig.tenantId}`;
|
2095
|
-
return {
|
2096
|
-
composeExtension: {
|
2097
|
-
type: "auth",
|
2098
|
-
suggestedActions: {
|
2099
|
-
actions: [
|
2100
|
-
{
|
2101
|
-
type: "openUrl",
|
2102
|
-
value: signInLink,
|
2103
|
-
title: "Message Extension OAuth",
|
2104
|
-
},
|
2105
|
-
],
|
2106
|
-
},
|
2107
|
-
},
|
2108
|
-
};
|
2109
|
-
}
|
2110
|
-
/**
|
2111
|
-
* execution in message extension with SSO token.
|
2112
|
-
*
|
2113
|
-
* @param {TurnContext} context - The context object for the current turn.
|
2114
|
-
* @param {OnBehalfOfCredentialAuthConfig} authConfig - User custom the message extension authentication configuration.
|
2115
|
-
* @param {initiateLoginEndpoint} initiateLoginEndpoint - Login page for Teams to redirect to.
|
2116
|
-
* @param {string[]} scopes - The list of scopes for which the token will have access.
|
2117
|
-
* @param {function} logic - Business logic when executing the query in message extension with SSO or access token.
|
2118
|
-
*
|
2119
|
-
* @throws {@link ErrorCode|InternalError} when failed to get access token with unknown error.
|
2120
|
-
* @throws {@link ErrorCode|TokenExpiredError} when SSO token has already expired.
|
2121
|
-
* @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server.
|
2122
|
-
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
2123
|
-
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
|
2124
|
-
*
|
2125
|
-
* @returns A MessageExtension Response for the activity. If the logic not return any, return void instead.
|
2126
|
-
*/
|
2127
|
-
function executionWithTokenAndConfig(context, authConfig, initiateLoginEndpoint, scopes, logic) {
|
2128
|
-
return __awaiter(this, void 0, void 0, function* () {
|
2129
|
-
const valueObj = context.activity.value;
|
2130
|
-
if (!valueObj.authentication || !valueObj.authentication.token) {
|
2131
|
-
internalLogger.verbose("No AccessToken in request, return silentAuth for AccessToken");
|
2132
|
-
return getSignInResponseForMessageExtensionWithSilentAuthConfig(authConfig, initiateLoginEndpoint, scopes);
|
2133
|
-
}
|
2134
|
-
try {
|
2135
|
-
const credential = new OnBehalfOfUserCredential(valueObj.authentication.token, authConfig);
|
2136
|
-
const token = yield credential.getToken(scopes);
|
2137
|
-
const ssoTokenExpiration = parseJwt(valueObj.authentication.token).exp;
|
2138
|
-
const tokenRes = {
|
2139
|
-
ssoToken: valueObj.authentication.token,
|
2140
|
-
ssoTokenExpiration: new Date(ssoTokenExpiration * 1000).toISOString(),
|
2141
|
-
token: token.token,
|
2142
|
-
expiration: token.expiresOnTimestamp.toString(),
|
2143
|
-
connectionName: "",
|
2144
|
-
};
|
2145
|
-
if (logic) {
|
2146
|
-
return yield logic(tokenRes);
|
2147
|
-
}
|
2148
|
-
}
|
2149
|
-
catch (err) {
|
2150
|
-
if (err instanceof ErrorWithCode &&
|
2151
|
-
err.code === exports.ErrorCode.UiRequiredError &&
|
2152
|
-
context.activity.name === "composeExtension/query") {
|
2153
|
-
internalLogger.verbose("User not consent yet, return 412 to user consent first.");
|
2154
|
-
const response = { status: 412 };
|
2155
|
-
yield context.sendActivity({ value: response, type: botbuilder.ActivityTypes.InvokeResponse });
|
2156
|
-
return;
|
2157
|
-
}
|
2158
|
-
else if (err instanceof ErrorWithCode &&
|
2159
|
-
err.code === exports.ErrorCode.UiRequiredError &&
|
2160
|
-
context.activity.name === "composeExtension/queryLink") {
|
2161
|
-
internalLogger.verbose("User not consent yet, return auth card for user login");
|
2162
|
-
const response = getSignInResponseForMessageExtensionWithAuthConfig(authConfig, initiateLoginEndpoint, scopes);
|
2163
|
-
yield context.sendActivity({
|
2164
|
-
value: { status: 200, body: response },
|
2165
|
-
type: botbuilder.ActivityTypes.InvokeResponse,
|
2166
|
-
});
|
2167
|
-
return;
|
2168
|
-
}
|
2169
|
-
throw err;
|
2170
|
-
}
|
2171
|
-
});
|
2172
|
-
}
|
2173
|
-
/**
|
2174
|
-
* Users execute query in message extension with SSO or access token.
|
2175
|
-
*
|
2176
|
-
* @param {TurnContext} context - The context object for the current turn.
|
2177
|
-
* @param {OnBehalfOfCredentialAuthConfig} config - User custom the message extension authentication configuration.
|
2178
|
-
* @param {initiateLoginEndpoint} initiateLoginEndpoint - Login page for Teams to redirect to.
|
2179
|
-
* @param {string| string[]} scopes - The list of scopes for which the token will have access.
|
2180
|
-
* @param {function} logic - Business logic when executing the query in message extension with SSO or access token.
|
2181
|
-
*
|
2182
|
-
* @throws {@link ErrorCode|InternalError} when User invoke not response to message extension query.
|
2183
|
-
* @throws {@link ErrorCode|InternalError} when failed to get access token with unknown error.
|
2184
|
-
* @throws {@link ErrorCode|TokenExpiredError} when SSO token has already expired.
|
2185
|
-
* @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server.
|
2186
|
-
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
2187
|
-
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
|
2188
|
-
*
|
2189
|
-
* @returns A MessageExtension Response for the activity. If the logic not return any, return void instead.
|
2190
|
-
*/
|
2191
|
-
function handleMessageExtensionQueryWithSSO(context, config, initiateLoginEndpoint, scopes, logic) {
|
2192
|
-
return __awaiter(this, void 0, void 0, function* () {
|
2193
|
-
if (context.activity.name != "composeExtension/query") {
|
2194
|
-
internalLogger.error(ErrorMessage.OnlySupportInQueryActivity);
|
2195
|
-
throw new ErrorWithCode(formatString(ErrorMessage.OnlySupportInQueryActivity), exports.ErrorCode.FailedOperation);
|
2196
|
-
}
|
2197
|
-
return yield executionWithTokenAndConfig(context, config !== null && config !== void 0 ? config : {}, initiateLoginEndpoint, scopes, logic);
|
2198
|
-
});
|
2199
|
-
}
|
2200
|
-
/**
|
2201
|
-
* Users execute link query in message extension with SSO or access token.
|
2202
|
-
*
|
2203
|
-
* @param {TurnContext} context - The context object for the current turn.
|
2204
|
-
* @param {OnBehalfOfCredentialAuthConfig} config - User custom the message extension authentication configuration.
|
2205
|
-
* @param {initiateLoginEndpoint} initiateLoginEndpoint - Login page for Teams to redirect to.
|
2206
|
-
* @param {string| string[]} scopes - The list of scopes for which the token will have access.
|
2207
|
-
* @param {function} logic - Business logic when executing the link query in message extension with SSO or access token.
|
2208
|
-
*
|
2209
|
-
* @throws {@link ErrorCode|InternalError} when User invoke not response to message extension link query.
|
2210
|
-
* @throws {@link ErrorCode|InternalError} when failed to get access token with unknown error.
|
2211
|
-
* @throws {@link ErrorCode|TokenExpiredError} when SSO token has already expired.
|
2212
|
-
* @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server.
|
2213
|
-
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
2214
|
-
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
|
2215
|
-
*
|
2216
|
-
* @returns A MessageExtension Response for the activity. If the logic not return any, return void instead.
|
2217
|
-
*/
|
2218
|
-
function handleMessageExtensionLinkQueryWithSSO(context, config, initiateLoginEndpoint, scopes, logic) {
|
2219
|
-
return __awaiter(this, void 0, void 0, function* () {
|
2220
|
-
if (context.activity.name != "composeExtension/queryLink") {
|
2221
|
-
internalLogger.error(ErrorMessage.OnlySupportInLinkQueryActivity);
|
2222
|
-
throw new ErrorWithCode(formatString(ErrorMessage.OnlySupportInLinkQueryActivity), exports.ErrorCode.FailedOperation);
|
2223
|
-
}
|
2224
|
-
return yield executionWithTokenAndConfig(context, config !== null && config !== void 0 ? config : {}, initiateLoginEndpoint, scopes, logic);
|
2225
|
-
});
|
2226
|
-
}
|
2227
|
-
|
2228
|
-
/**
|
2229
|
-
* @internal
|
2230
|
-
*/
|
2231
|
-
class CardActionMiddleware {
|
2232
|
-
constructor(handlers) {
|
2233
|
-
this.actionHandlers = [];
|
2234
|
-
this.defaultMessage = "Your response was sent to the app";
|
2235
|
-
if (handlers && handlers.length > 0) {
|
2236
|
-
this.actionHandlers.push(...handlers);
|
2237
|
-
}
|
2238
|
-
}
|
2239
|
-
onTurn(context, next) {
|
2240
|
-
return __awaiter(this, void 0, void 0, function* () {
|
2241
|
-
var _a, _b, _c;
|
2242
|
-
if (context.activity.name === "adaptiveCard/action") {
|
2243
|
-
const action = context.activity.value.action;
|
2244
|
-
const actionVerb = action.verb;
|
2245
|
-
for (const handler of this.actionHandlers) {
|
2246
|
-
if (((_a = handler.triggerVerb) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === (actionVerb === null || actionVerb === void 0 ? void 0 : actionVerb.toLowerCase())) {
|
2247
|
-
let response;
|
2248
|
-
try {
|
2249
|
-
response = yield handler.handleActionInvoked(context, action.data);
|
2250
|
-
}
|
2251
|
-
catch (error) {
|
2252
|
-
const errorResponse = InvokeResponseFactory.errorResponse(exports.InvokeResponseErrorCode.InternalServerError, error.message);
|
2253
|
-
yield this.sendInvokeResponse(context, errorResponse);
|
2254
|
-
throw error;
|
2255
|
-
}
|
2256
|
-
const responseType = (_b = response.body) === null || _b === void 0 ? void 0 : _b.type;
|
2257
|
-
switch (responseType) {
|
2258
|
-
case InvokeResponseType.AdaptiveCard:
|
2259
|
-
const card = (_c = response.body) === null || _c === void 0 ? void 0 : _c.value;
|
2260
|
-
if (!card) {
|
2261
|
-
const errorMessage = "Adaptive card content cannot be found in the response body";
|
2262
|
-
yield this.sendInvokeResponse(context, InvokeResponseFactory.errorResponse(exports.InvokeResponseErrorCode.InternalServerError, errorMessage));
|
2263
|
-
throw new Error(errorMessage);
|
2264
|
-
}
|
2265
|
-
if (card.refresh && handler.adaptiveCardResponse !== exports.AdaptiveCardResponse.NewForAll) {
|
2266
|
-
// Card won't be refreshed with AdaptiveCardResponse.ReplaceForInteractor.
|
2267
|
-
// So set to AdaptiveCardResponse.ReplaceForAll here.
|
2268
|
-
handler.adaptiveCardResponse = exports.AdaptiveCardResponse.ReplaceForAll;
|
2269
|
-
}
|
2270
|
-
const activity = botbuilder.MessageFactory.attachment(botbuilder.CardFactory.adaptiveCard(card));
|
2271
|
-
if (handler.adaptiveCardResponse === exports.AdaptiveCardResponse.NewForAll) {
|
2272
|
-
yield this.sendInvokeResponse(context, InvokeResponseFactory.textMessage(this.defaultMessage));
|
2273
|
-
yield context.sendActivity(activity);
|
2274
|
-
}
|
2275
|
-
else if (handler.adaptiveCardResponse === exports.AdaptiveCardResponse.ReplaceForAll) {
|
2276
|
-
activity.id = context.activity.replyToId;
|
2277
|
-
yield context.updateActivity(activity);
|
2278
|
-
yield this.sendInvokeResponse(context, response);
|
2279
|
-
}
|
2280
|
-
else {
|
2281
|
-
yield this.sendInvokeResponse(context, response);
|
2282
|
-
}
|
2283
|
-
break;
|
2284
|
-
case InvokeResponseType.Message:
|
2285
|
-
case InvokeResponseType.Error:
|
2286
|
-
default:
|
2287
|
-
yield this.sendInvokeResponse(context, response);
|
2288
|
-
break;
|
2289
|
-
}
|
2290
|
-
break;
|
2291
|
-
}
|
2292
|
-
}
|
2293
|
-
}
|
2294
|
-
yield next();
|
2295
|
-
});
|
2296
|
-
}
|
2297
|
-
sendInvokeResponse(context, response) {
|
2298
|
-
return __awaiter(this, void 0, void 0, function* () {
|
2299
|
-
yield context.sendActivity({
|
2300
|
-
type: botbuilder.ActivityTypes.InvokeResponse,
|
2301
|
-
value: response,
|
2302
|
-
});
|
2303
|
-
});
|
2304
|
-
}
|
2305
|
-
}
|
2306
|
-
|
2307
|
-
/**
|
2308
|
-
* A card action bot to respond to adaptive card universal actions.
|
2309
|
-
*/
|
2310
|
-
class CardActionBot {
|
2311
|
-
/**
|
2312
|
-
* Create a new instance of the `CardActionBot`.
|
2313
|
-
*
|
2314
|
-
* @param adapter - The bound `CloudAdapter`.
|
2315
|
-
* @param options - The initialize options.
|
2316
|
-
*/
|
2317
|
-
constructor(adapter, options) {
|
2318
|
-
this.middleware = new CardActionMiddleware(options === null || options === void 0 ? void 0 : options.actions);
|
2319
|
-
this.adapter = adapter.use(this.middleware);
|
2320
|
-
}
|
2321
|
-
/**
|
2322
|
-
* Register a card action handler to the bot.
|
2323
|
-
*
|
2324
|
-
* @param actionHandler - A card action handler to be registered.
|
2325
|
-
*/
|
2326
|
-
registerHandler(actionHandler) {
|
2327
|
-
if (actionHandler) {
|
2328
|
-
this.middleware.actionHandlers.push(actionHandler);
|
2329
|
-
}
|
2330
|
-
}
|
2331
|
-
/**
|
2332
|
-
* Register card action handlers to the bot.
|
2333
|
-
*
|
2334
|
-
* @param actionHandlers - A set of card action handlers to be registered.
|
2335
|
-
*/
|
2336
|
-
registerHandlers(actionHandlers) {
|
2337
|
-
if (actionHandlers) {
|
2338
|
-
this.middleware.actionHandlers.push(...actionHandlers);
|
2339
|
-
}
|
2340
|
-
}
|
2341
|
-
}
|
2342
|
-
|
2343
|
-
// Copyright (c) Microsoft Corporation.
|
2344
|
-
/**
|
2345
|
-
* @internal
|
2346
|
-
*/
|
2347
|
-
class CommandResponseMiddleware {
|
2348
|
-
constructor(handlers, ssoHandlers, activityHandler) {
|
2349
|
-
this.commandHandlers = [];
|
2350
|
-
this.ssoCommandHandlers = [];
|
2351
|
-
handlers = handlers !== null && handlers !== void 0 ? handlers : [];
|
2352
|
-
ssoHandlers = ssoHandlers !== null && ssoHandlers !== void 0 ? ssoHandlers : [];
|
2353
|
-
this.hasSsoCommand = ssoHandlers.length > 0;
|
2354
|
-
this.ssoActivityHandler = activityHandler;
|
2355
|
-
if (this.hasSsoCommand && !this.ssoActivityHandler) {
|
2356
|
-
internalLogger.error(ErrorMessage.SsoActivityHandlerIsNull);
|
2357
|
-
throw new ErrorWithCode(ErrorMessage.SsoActivityHandlerIsNull, exports.ErrorCode.SsoActivityHandlerIsUndefined);
|
2358
|
-
}
|
2359
|
-
this.commandHandlers.push(...handlers);
|
2360
|
-
for (const ssoHandler of ssoHandlers) {
|
2361
|
-
this.addSsoCommand(ssoHandler);
|
2362
|
-
}
|
2363
|
-
}
|
2364
|
-
addSsoCommand(ssoHandler) {
|
2365
|
-
var _a;
|
2366
|
-
(_a = this.ssoActivityHandler) === null || _a === void 0 ? void 0 : _a.addCommand((context, tokenResponse, message) => __awaiter(this, void 0, void 0, function* () {
|
2367
|
-
const matchResult = this.shouldTrigger(ssoHandler.triggerPatterns, message.text);
|
2368
|
-
message.matches = Array.isArray(matchResult) ? matchResult : void 0;
|
2369
|
-
const response = yield ssoHandler.handleCommandReceived(context, message, tokenResponse);
|
2370
|
-
yield this.processResponse(context, response);
|
2371
|
-
}), ssoHandler.triggerPatterns);
|
2372
|
-
this.ssoCommandHandlers.push(ssoHandler);
|
2373
|
-
this.hasSsoCommand = true;
|
2374
|
-
}
|
2375
|
-
onTurn(context, next) {
|
2376
|
-
return __awaiter(this, void 0, void 0, function* () {
|
2377
|
-
var _a, _b;
|
2378
|
-
if (context.activity.type === botbuilder.ActivityTypes.Message) {
|
2379
|
-
// Invoke corresponding command handler for the command response
|
2380
|
-
const commandText = this.getActivityText(context.activity);
|
2381
|
-
let alreadyProcessed = false;
|
2382
|
-
for (const handler of this.commandHandlers) {
|
2383
|
-
const matchResult = this.shouldTrigger(handler.triggerPatterns, commandText);
|
2384
|
-
// It is important to note that the command bot will stop processing handlers
|
2385
|
-
// when the first command handler is matched.
|
2386
|
-
if (!!matchResult) {
|
2387
|
-
const message = {
|
2388
|
-
text: commandText,
|
2389
|
-
};
|
2390
|
-
message.matches = Array.isArray(matchResult) ? matchResult : void 0;
|
2391
|
-
const response = yield handler.handleCommandReceived(context, message);
|
2392
|
-
yield this.processResponse(context, response);
|
2393
|
-
alreadyProcessed = true;
|
2394
|
-
break;
|
2395
|
-
}
|
2396
|
-
}
|
2397
|
-
if (!alreadyProcessed) {
|
2398
|
-
for (const handler of this.ssoCommandHandlers) {
|
2399
|
-
const matchResult = this.shouldTrigger(handler.triggerPatterns, commandText);
|
2400
|
-
if (!!matchResult) {
|
2401
|
-
yield ((_a = this.ssoActivityHandler) === null || _a === void 0 ? void 0 : _a.run(context));
|
2402
|
-
break;
|
2403
|
-
}
|
2404
|
-
}
|
2405
|
-
}
|
2406
|
-
}
|
2407
|
-
else {
|
2408
|
-
if (this.hasSsoCommand) {
|
2409
|
-
yield ((_b = this.ssoActivityHandler) === null || _b === void 0 ? void 0 : _b.run(context));
|
2410
|
-
}
|
2411
|
-
}
|
2412
|
-
yield next();
|
2413
|
-
});
|
2414
|
-
}
|
2415
|
-
processResponse(context, response) {
|
2416
|
-
return __awaiter(this, void 0, void 0, function* () {
|
2417
|
-
if (typeof response === "string") {
|
2418
|
-
yield context.sendActivity(response);
|
2419
|
-
}
|
2420
|
-
else {
|
2421
|
-
const replyActivity = response;
|
2422
|
-
if (replyActivity) {
|
2423
|
-
yield context.sendActivity(replyActivity);
|
2424
|
-
}
|
2425
|
-
}
|
2426
|
-
});
|
2427
|
-
}
|
2428
|
-
matchPattern(pattern, text) {
|
2429
|
-
if (text) {
|
2430
|
-
if (typeof pattern === "string") {
|
2431
|
-
const regExp = new RegExp(pattern, "i");
|
2432
|
-
return regExp.test(text);
|
2433
|
-
}
|
2434
|
-
if (pattern instanceof RegExp) {
|
2435
|
-
const matches = text.match(pattern);
|
2436
|
-
return matches !== null && matches !== void 0 ? matches : false;
|
2437
|
-
}
|
2438
|
-
}
|
2439
|
-
return false;
|
2440
|
-
}
|
2441
|
-
shouldTrigger(patterns, text) {
|
2442
|
-
const expressions = Array.isArray(patterns) ? patterns : [patterns];
|
2443
|
-
for (const ex of expressions) {
|
2444
|
-
const arg = this.matchPattern(ex, text);
|
2445
|
-
if (arg)
|
2446
|
-
return arg;
|
2447
|
-
}
|
2448
|
-
return false;
|
2449
|
-
}
|
2450
|
-
getActivityText(activity) {
|
2451
|
-
let text = activity.text;
|
2452
|
-
const removedMentionText = botbuilder.TurnContext.removeRecipientMention(activity);
|
2453
|
-
if (removedMentionText) {
|
2454
|
-
text = removedMentionText
|
2455
|
-
.toLowerCase()
|
2456
|
-
.replace(/\n|\r\n/g, "")
|
2457
|
-
.trim();
|
2458
|
-
}
|
2459
|
-
return text;
|
2460
|
-
}
|
2461
|
-
}
|
2462
|
-
|
2463
|
-
// Copyright (c) Microsoft Corporation.
|
2464
|
-
/**
|
2465
|
-
* A command bot for receiving commands and sending responses in Teams.
|
2466
|
-
*
|
2467
|
-
* @remarks
|
2468
|
-
* Ensure each command should ONLY be registered with the command once, otherwise it'll cause unexpected behavior if you register the same command more than once.
|
2469
|
-
*/
|
2470
|
-
class CommandBot {
|
2471
|
-
// eslint-disable-next-line no-secrets/no-secrets
|
2472
|
-
/**
|
2473
|
-
* Create a new instance of the `CommandBot`.
|
2474
|
-
*
|
2475
|
-
* @param adapter - The bound `CloudAdapter`.
|
2476
|
-
* @param options - The initialize options
|
2477
|
-
* @param ssoCommandActivityHandler - SSO execution activity handler.
|
2478
|
-
* @param ssoConfig - SSO configuration for Bot SSO.
|
2479
|
-
*/
|
2480
|
-
constructor(adapter, options, ssoCommandActivityHandler, ssoConfig) {
|
2481
|
-
this.ssoConfig = ssoConfig;
|
2482
|
-
this.middleware = new CommandResponseMiddleware(options === null || options === void 0 ? void 0 : options.commands, options === null || options === void 0 ? void 0 : options.ssoCommands, ssoCommandActivityHandler);
|
2483
|
-
this.adapter = adapter.use(this.middleware);
|
2484
|
-
}
|
2485
|
-
/**
|
2486
|
-
* Register a command into the command bot.
|
2487
|
-
*
|
2488
|
-
* @param command - The command to be registered.
|
2489
|
-
*/
|
2490
|
-
registerCommand(command) {
|
2491
|
-
if (command) {
|
2492
|
-
this.middleware.commandHandlers.push(command);
|
2493
|
-
}
|
2494
|
-
}
|
2495
|
-
/**
|
2496
|
-
* Register commands into the command bot.
|
2497
|
-
*
|
2498
|
-
* @param commands - The commands to be registered.
|
2499
|
-
*/
|
2500
|
-
registerCommands(commands) {
|
2501
|
-
if (commands) {
|
2502
|
-
this.middleware.commandHandlers.push(...commands);
|
2503
|
-
}
|
2504
|
-
}
|
2505
|
-
/**
|
2506
|
-
* Register a sso command into the command bot.
|
2507
|
-
*
|
2508
|
-
* @param ssoCommand - The sso command to be registered.
|
2509
|
-
*/
|
2510
|
-
registerSsoCommand(ssoCommand) {
|
2511
|
-
this.validateSsoActivityHandler();
|
2512
|
-
this.middleware.addSsoCommand(ssoCommand);
|
2513
|
-
}
|
2514
|
-
/**
|
2515
|
-
* Register sso commands into the command bot.
|
2516
|
-
*
|
2517
|
-
* @param ssoCommands - The sso commands to be registered.
|
2518
|
-
*/
|
2519
|
-
registerSsoCommands(ssoCommands) {
|
2520
|
-
if (ssoCommands.length > 0) {
|
2521
|
-
this.validateSsoActivityHandler();
|
2522
|
-
for (const ssoCommand of ssoCommands) {
|
2523
|
-
this.middleware.addSsoCommand(ssoCommand);
|
2524
|
-
}
|
2525
|
-
}
|
2526
|
-
}
|
2527
|
-
validateSsoActivityHandler() {
|
2528
|
-
if (!this.middleware.ssoActivityHandler) {
|
2529
|
-
internalLogger.error(ErrorMessage.SsoActivityHandlerIsNull);
|
2530
|
-
throw new ErrorWithCode(ErrorMessage.SsoActivityHandlerIsNull, exports.ErrorCode.SsoActivityHandlerIsUndefined);
|
2531
|
-
}
|
2532
|
-
}
|
2533
|
-
}
|
2534
|
-
|
2535
|
-
// Copyright (c) Microsoft Corporation.
|
2536
|
-
/**
|
2537
|
-
* @internal
|
2538
|
-
*/
|
2539
|
-
function cloneConversation(conversation) {
|
2540
|
-
return JSON.parse(JSON.stringify(conversation));
|
2541
|
-
}
|
2542
|
-
/**
|
2543
|
-
* @internal
|
2544
|
-
*/
|
2545
|
-
function getKey(reference) {
|
2546
|
-
var _a, _b;
|
2547
|
-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
2548
|
-
return `_${(_a = reference.conversation) === null || _a === void 0 ? void 0 : _a.tenantId}_${(_b = reference.conversation) === null || _b === void 0 ? void 0 : _b.id}`;
|
2549
|
-
}
|
2550
|
-
/**
|
2551
|
-
* @internal
|
2552
|
-
*/
|
2553
|
-
function getTargetType(conversationReference) {
|
2554
|
-
var _a;
|
2555
|
-
const conversationType = (_a = conversationReference.conversation) === null || _a === void 0 ? void 0 : _a.conversationType;
|
2556
|
-
if (conversationType === "personal") {
|
2557
|
-
return exports.NotificationTargetType.Person;
|
2558
|
-
}
|
2559
|
-
else if (conversationType === "groupChat") {
|
2560
|
-
return exports.NotificationTargetType.Group;
|
2561
|
-
}
|
2562
|
-
else if (conversationType === "channel") {
|
2563
|
-
return exports.NotificationTargetType.Channel;
|
2564
|
-
}
|
2565
|
-
else {
|
2566
|
-
return undefined;
|
2567
|
-
}
|
2568
|
-
}
|
2569
|
-
/**
|
2570
|
-
* @internal
|
2571
|
-
*/
|
2572
|
-
function getTeamsBotInstallationId(context) {
|
2573
|
-
var _a, _b, _c;
|
2574
|
-
const teamId = (_c = (_b = (_a = context.activity) === null || _a === void 0 ? void 0 : _a.channelData) === null || _b === void 0 ? void 0 : _b.team) === null || _c === void 0 ? void 0 : _c.id;
|
2575
|
-
if (teamId) {
|
2576
|
-
return teamId;
|
2577
|
-
}
|
2578
|
-
// Fallback to use conversation id.
|
2579
|
-
// The conversation id is equal to team id only when the bot app is installed into the General channel.
|
2580
|
-
if (context.activity.conversation.name === undefined) {
|
2581
|
-
return context.activity.conversation.id;
|
2582
|
-
}
|
2583
|
-
return undefined;
|
2584
|
-
}
|
2585
|
-
|
2586
|
-
// Copyright (c) Microsoft Corporation.
|
2587
|
-
/**
|
2588
|
-
* @internal
|
2589
|
-
*/
|
2590
|
-
var ActivityType;
|
2591
|
-
(function (ActivityType) {
|
2592
|
-
ActivityType[ActivityType["CurrentBotInstalled"] = 0] = "CurrentBotInstalled";
|
2593
|
-
ActivityType[ActivityType["CurrentBotMessaged"] = 1] = "CurrentBotMessaged";
|
2594
|
-
ActivityType[ActivityType["CurrentBotUninstalled"] = 2] = "CurrentBotUninstalled";
|
2595
|
-
ActivityType[ActivityType["TeamDeleted"] = 3] = "TeamDeleted";
|
2596
|
-
ActivityType[ActivityType["TeamRestored"] = 4] = "TeamRestored";
|
2597
|
-
ActivityType[ActivityType["Unknown"] = 5] = "Unknown";
|
2598
|
-
})(ActivityType || (ActivityType = {}));
|
2599
|
-
/**
|
2600
|
-
* @internal
|
2601
|
-
*/
|
2602
|
-
class NotificationMiddleware {
|
2603
|
-
constructor(options) {
|
2604
|
-
this.conversationReferenceStore = options.conversationReferenceStore;
|
2605
|
-
}
|
2606
|
-
onTurn(context, next) {
|
2607
|
-
return __awaiter(this, void 0, void 0, function* () {
|
2608
|
-
const type = this.classifyActivity(context.activity);
|
2609
|
-
switch (type) {
|
2610
|
-
case ActivityType.CurrentBotInstalled:
|
2611
|
-
case ActivityType.TeamRestored: {
|
2612
|
-
const reference = botbuilder.TurnContext.getConversationReference(context.activity);
|
2613
|
-
yield this.conversationReferenceStore.add(getKey(reference), reference, {
|
2614
|
-
overwrite: true,
|
2615
|
-
});
|
2616
|
-
break;
|
2617
|
-
}
|
2618
|
-
case ActivityType.CurrentBotMessaged: {
|
2619
|
-
yield this.tryAddMessagedReference(context);
|
2620
|
-
break;
|
2621
|
-
}
|
2622
|
-
case ActivityType.CurrentBotUninstalled:
|
2623
|
-
case ActivityType.TeamDeleted: {
|
2624
|
-
const reference = botbuilder.TurnContext.getConversationReference(context.activity);
|
2625
|
-
yield this.conversationReferenceStore.remove(getKey(reference), reference);
|
2626
|
-
break;
|
2627
|
-
}
|
2628
|
-
}
|
2629
|
-
yield next();
|
2630
|
-
});
|
2631
|
-
}
|
2632
|
-
classifyActivity(activity) {
|
2633
|
-
var _a, _b;
|
2634
|
-
const activityType = activity.type;
|
2635
|
-
if (activityType === "installationUpdate") {
|
2636
|
-
const action = (_a = activity.action) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
2637
|
-
if (action === "add" || action === "add-upgrade") {
|
2638
|
-
return ActivityType.CurrentBotInstalled;
|
2639
|
-
}
|
2640
|
-
else {
|
2641
|
-
return ActivityType.CurrentBotUninstalled;
|
2642
|
-
}
|
2643
|
-
}
|
2644
|
-
else if (activityType === "conversationUpdate") {
|
2645
|
-
const eventType = (_b = activity.channelData) === null || _b === void 0 ? void 0 : _b.eventType;
|
2646
|
-
if (eventType === "teamDeleted") {
|
2647
|
-
return ActivityType.TeamDeleted;
|
2648
|
-
}
|
2649
|
-
else if (eventType === "teamRestored") {
|
2650
|
-
return ActivityType.TeamRestored;
|
2651
|
-
}
|
2652
|
-
}
|
2653
|
-
else if (activityType === "message") {
|
2654
|
-
return ActivityType.CurrentBotMessaged;
|
2655
|
-
}
|
2656
|
-
return ActivityType.Unknown;
|
2657
|
-
}
|
2658
|
-
tryAddMessagedReference(context) {
|
2659
|
-
return __awaiter(this, void 0, void 0, function* () {
|
2660
|
-
var _a, _b, _c, _d, _e, _f;
|
2661
|
-
const reference = botbuilder.TurnContext.getConversationReference(context.activity);
|
2662
|
-
const conversationType = (_a = reference === null || reference === void 0 ? void 0 : reference.conversation) === null || _a === void 0 ? void 0 : _a.conversationType;
|
2663
|
-
if (conversationType === "personal" || conversationType === "groupChat") {
|
2664
|
-
yield this.conversationReferenceStore.add(getKey(reference), reference, { overwrite: false });
|
2665
|
-
}
|
2666
|
-
else if (conversationType === "channel") {
|
2667
|
-
const teamId = (_d = (_c = (_b = context.activity) === null || _b === void 0 ? void 0 : _b.channelData) === null || _c === void 0 ? void 0 : _c.team) === null || _d === void 0 ? void 0 : _d.id;
|
2668
|
-
const channelId = (_f = (_e = context.activity.channelData) === null || _e === void 0 ? void 0 : _e.channel) === null || _f === void 0 ? void 0 : _f.id;
|
2669
|
-
// `teamId === channelId` means General channel. Ignore messaging in non-General channel.
|
2670
|
-
if (teamId !== undefined && (channelId === undefined || teamId === channelId)) {
|
2671
|
-
const teamReference = cloneConversation(reference);
|
2672
|
-
teamReference.conversation.id = teamId;
|
2673
|
-
yield this.conversationReferenceStore.add(getKey(teamReference), teamReference, {
|
2674
|
-
overwrite: false,
|
2675
|
-
});
|
2676
|
-
}
|
2677
|
-
}
|
2678
|
-
});
|
2679
|
-
}
|
2680
|
-
}
|
2681
|
-
|
2682
|
-
// Copyright (c) Microsoft Corporation.
|
2683
|
-
/**
|
2684
|
-
* @internal
|
2685
|
-
*/
|
2686
|
-
class DefaultConversationReferenceStore {
|
2687
|
-
constructor(fileDir) {
|
2688
|
-
var _a;
|
2689
|
-
this.localFileName = (_a = process.env.TEAMSFX_NOTIFICATION_STORE_FILENAME) !== null && _a !== void 0 ? _a : ".notification.localstore.json";
|
2690
|
-
this.filePath = path__namespace.resolve(fileDir, this.localFileName);
|
2691
|
-
}
|
2692
|
-
add(key, reference, options) {
|
2693
|
-
return __awaiter(this, void 0, void 0, function* () {
|
2694
|
-
if (options.overwrite || !(yield this.storeFileExists())) {
|
2695
|
-
if (!(yield this.storeFileExists())) {
|
2696
|
-
yield this.writeToFile({ [key]: reference });
|
2697
|
-
}
|
2698
|
-
else {
|
2699
|
-
const data = yield this.readFromFile();
|
2700
|
-
yield this.writeToFile(Object.assign(data, { [key]: reference }));
|
2701
|
-
}
|
2702
|
-
return true;
|
2703
|
-
}
|
2704
|
-
return false;
|
2705
|
-
});
|
2706
|
-
}
|
2707
|
-
remove(key, reference) {
|
2708
|
-
return __awaiter(this, void 0, void 0, function* () {
|
2709
|
-
if (!(yield this.storeFileExists())) {
|
2710
|
-
return false;
|
2711
|
-
}
|
2712
|
-
if (yield this.storeFileExists()) {
|
2713
|
-
const data = yield this.readFromFile();
|
2714
|
-
if (data[key] !== undefined) {
|
2715
|
-
delete data[key];
|
2716
|
-
yield this.writeToFile(data);
|
2717
|
-
}
|
2718
|
-
}
|
2719
|
-
return true;
|
2720
|
-
});
|
2721
|
-
}
|
2722
|
-
list(pageSize, continuationToken) {
|
2723
|
-
return __awaiter(this, void 0, void 0, function* () {
|
2724
|
-
if (!(yield this.storeFileExists())) {
|
2725
|
-
return {
|
2726
|
-
data: [],
|
2727
|
-
continuationToken: "",
|
2728
|
-
};
|
2729
|
-
}
|
2730
|
-
const fileData = yield this.readFromFile();
|
2731
|
-
const data = Object.entries(fileData).map((entry) => entry[1]);
|
2732
|
-
return {
|
2733
|
-
data,
|
2734
|
-
continuationToken: "",
|
2735
|
-
};
|
2736
|
-
});
|
2737
|
-
}
|
2738
|
-
storeFileExists() {
|
2739
|
-
return new Promise((resolve) => {
|
2740
|
-
try {
|
2741
|
-
fs__namespace.access(this.filePath, (err) => {
|
2742
|
-
if (err) {
|
2743
|
-
resolve(false);
|
2744
|
-
}
|
2745
|
-
else {
|
2746
|
-
resolve(true);
|
2747
|
-
}
|
2748
|
-
});
|
2749
|
-
}
|
2750
|
-
catch (error) {
|
2751
|
-
resolve(false);
|
2752
|
-
}
|
2753
|
-
});
|
2754
|
-
}
|
2755
|
-
readFromFile() {
|
2756
|
-
return new Promise((resolve, reject) => {
|
2757
|
-
try {
|
2758
|
-
fs__namespace.readFile(this.filePath, { encoding: "utf-8" }, (err, rawData) => {
|
2759
|
-
if (err) {
|
2760
|
-
reject(err);
|
2761
|
-
}
|
2762
|
-
else {
|
2763
|
-
resolve(JSON.parse(rawData));
|
2764
|
-
}
|
2765
|
-
});
|
2766
|
-
}
|
2767
|
-
catch (error) {
|
2768
|
-
reject(error);
|
2769
|
-
}
|
2770
|
-
});
|
2771
|
-
}
|
2772
|
-
writeToFile(data) {
|
2773
|
-
return __awaiter(this, void 0, void 0, function* () {
|
2774
|
-
return new Promise((resolve, reject) => {
|
2775
|
-
try {
|
2776
|
-
const rawData = JSON.stringify(data, undefined, 2);
|
2777
|
-
fs__namespace.writeFile(this.filePath, rawData, { encoding: "utf-8" }, (err) => {
|
2778
|
-
if (err) {
|
2779
|
-
reject(err);
|
2780
|
-
}
|
2781
|
-
else {
|
2782
|
-
resolve();
|
2783
|
-
}
|
2784
|
-
});
|
2785
|
-
}
|
2786
|
-
catch (error) {
|
2787
|
-
reject(error);
|
2788
|
-
}
|
2789
|
-
});
|
2790
|
-
});
|
2791
|
-
}
|
2792
|
-
}
|
2793
|
-
|
2794
|
-
// Copyright (c) Microsoft Corporation.
|
2795
|
-
/**
|
2796
|
-
* Send a plain text message to a notification target.
|
2797
|
-
*
|
2798
|
-
* @param target - The notification target.
|
2799
|
-
* @param text - The plain text message.
|
2800
|
-
* @param onError - An optional error handler that can catch exceptions during message sending.
|
2801
|
-
* If not defined, error will be handled by `BotAdapter.onTurnError`.
|
2802
|
-
*
|
2803
|
-
* @returns The response of sending message.
|
2804
|
-
*/
|
2805
|
-
function sendMessage(target, text, onError) {
|
2806
|
-
return target.sendMessage(text, onError);
|
2807
|
-
}
|
2808
|
-
/**
|
2809
|
-
* Send an adaptive card message to a notification target.
|
2810
|
-
*
|
2811
|
-
* @param target - The notification target.
|
2812
|
-
* @param card - The adaptive card raw JSON.
|
2813
|
-
* @param onError - An optional error handler that can catch exceptions during adaptive card sending.
|
2814
|
-
* If not defined, error will be handled by `BotAdapter.onTurnError`.
|
2815
|
-
*
|
2816
|
-
* @returns The response of sending adaptive card message.
|
2817
|
-
*/
|
2818
|
-
function sendAdaptiveCard(target, card, onError) {
|
2819
|
-
return target.sendAdaptiveCard(card, onError);
|
2820
|
-
}
|
2821
|
-
/**
|
2822
|
-
* A {@link NotificationTarget} that represents a team channel.
|
2823
|
-
*
|
2824
|
-
* @remarks
|
2825
|
-
* It's recommended to get channels from {@link TeamsBotInstallation.channels()}.
|
2826
|
-
*/
|
2827
|
-
class Channel {
|
2828
|
-
/**
|
2829
|
-
* Constructor.
|
2830
|
-
*
|
2831
|
-
* @remarks
|
2832
|
-
* It's recommended to get channels from {@link TeamsBotInstallation.channels()}, instead of using this constructor.
|
2833
|
-
*
|
2834
|
-
* @param parent - The parent {@link TeamsBotInstallation} where this channel is created from.
|
2835
|
-
* @param info - Detailed channel information.
|
2836
|
-
*/
|
2837
|
-
constructor(parent, info) {
|
2838
|
-
/**
|
2839
|
-
* Notification target type. For channel it's always "Channel".
|
2840
|
-
*/
|
2841
|
-
this.type = exports.NotificationTargetType.Channel;
|
2842
|
-
this.parent = parent;
|
2843
|
-
this.info = info;
|
2844
|
-
}
|
2845
|
-
/**
|
2846
|
-
* Send a plain text message.
|
2847
|
-
*
|
2848
|
-
* @param text - The plain text message.
|
2849
|
-
* @param onError - An optional error handler that can catch exceptions during message sending.
|
2850
|
-
* If not defined, error will be handled by `BotAdapter.onTurnError`.
|
2851
|
-
*
|
2852
|
-
* @returns The response of sending message.
|
2853
|
-
*/
|
2854
|
-
sendMessage(text, onError) {
|
2855
|
-
return __awaiter(this, void 0, void 0, function* () {
|
2856
|
-
const response = {};
|
2857
|
-
yield this.parent.adapter.continueConversationAsync(this.parent.botAppId, this.parent.conversationReference, (context) => __awaiter(this, void 0, void 0, function* () {
|
2858
|
-
const conversation = yield this.newConversation(context);
|
2859
|
-
yield this.parent.adapter.continueConversationAsync(this.parent.botAppId, conversation, (ctx) => __awaiter(this, void 0, void 0, function* () {
|
2860
|
-
try {
|
2861
|
-
const res = yield ctx.sendActivity(text);
|
2862
|
-
response.id = res === null || res === void 0 ? void 0 : res.id;
|
2863
|
-
}
|
2864
|
-
catch (error) {
|
2865
|
-
if (onError) {
|
2866
|
-
yield onError(ctx, error);
|
2867
|
-
}
|
2868
|
-
else {
|
2869
|
-
throw error;
|
2870
|
-
}
|
2871
|
-
}
|
2872
|
-
}));
|
2873
|
-
}));
|
2874
|
-
return response;
|
2875
|
-
});
|
2876
|
-
}
|
2877
|
-
/**
|
2878
|
-
* Send an adaptive card message.
|
2879
|
-
*
|
2880
|
-
* @param card - The adaptive card raw JSON.
|
2881
|
-
* @param onError - An optional error handler that can catch exceptions during adaptive card sending.
|
2882
|
-
* If not defined, error will be handled by `BotAdapter.onTurnError`.
|
2883
|
-
*
|
2884
|
-
* @returns The response of sending adaptive card message.
|
2885
|
-
*/
|
2886
|
-
sendAdaptiveCard(card, onError) {
|
2887
|
-
return __awaiter(this, void 0, void 0, function* () {
|
2888
|
-
const response = {};
|
2889
|
-
yield this.parent.adapter.continueConversationAsync(this.parent.botAppId, this.parent.conversationReference, (context) => __awaiter(this, void 0, void 0, function* () {
|
2890
|
-
const conversation = yield this.newConversation(context);
|
2891
|
-
yield this.parent.adapter.continueConversationAsync(this.parent.botAppId, conversation, (ctx) => __awaiter(this, void 0, void 0, function* () {
|
2892
|
-
try {
|
2893
|
-
const res = yield ctx.sendActivity({
|
2894
|
-
attachments: [botbuilder.CardFactory.adaptiveCard(card)],
|
2895
|
-
});
|
2896
|
-
response.id = res === null || res === void 0 ? void 0 : res.id;
|
2897
|
-
}
|
2898
|
-
catch (error) {
|
2899
|
-
if (onError) {
|
2900
|
-
yield onError(ctx, error);
|
2901
|
-
}
|
2902
|
-
else {
|
2903
|
-
throw error;
|
2904
|
-
}
|
2905
|
-
}
|
2906
|
-
}));
|
2907
|
-
}));
|
2908
|
-
return response;
|
2909
|
-
});
|
2910
|
-
}
|
2911
|
-
/**
|
2912
|
-
* @internal
|
2913
|
-
*/
|
2914
|
-
newConversation(context) {
|
2915
|
-
const reference = botbuilder.TurnContext.getConversationReference(context.activity);
|
2916
|
-
const channelConversation = cloneConversation(reference);
|
2917
|
-
channelConversation.conversation.id = this.info.id || "";
|
2918
|
-
return Promise.resolve(channelConversation);
|
2919
|
-
}
|
2920
|
-
}
|
2921
|
-
/**
|
2922
|
-
* A {@link NotificationTarget} that represents a team member.
|
2923
|
-
*
|
2924
|
-
* @remarks
|
2925
|
-
* It's recommended to get members from {@link TeamsBotInstallation.members()}.
|
2926
|
-
*/
|
2927
|
-
class Member {
|
2928
|
-
/**
|
2929
|
-
* Constructor.
|
2930
|
-
*
|
2931
|
-
* @remarks
|
2932
|
-
* It's recommended to get members from {@link TeamsBotInstallation.members()}, instead of using this constructor.
|
2933
|
-
*
|
2934
|
-
* @param parent - The parent {@link TeamsBotInstallation} where this member is created from.
|
2935
|
-
* @param account - Detailed member account information.
|
2936
|
-
*/
|
2937
|
-
constructor(parent, account) {
|
2938
|
-
/**
|
2939
|
-
* Notification target type. For member it's always "Person".
|
2940
|
-
*/
|
2941
|
-
this.type = exports.NotificationTargetType.Person;
|
2942
|
-
this.parent = parent;
|
2943
|
-
this.account = account;
|
2944
|
-
}
|
2945
|
-
/**
|
2946
|
-
* Send a plain text message.
|
2947
|
-
*
|
2948
|
-
* @param text - The plain text message.
|
2949
|
-
* @param onError - An optional error handler that can catch exceptions during message sending.
|
2950
|
-
* If not defined, error will be handled by `BotAdapter.onTurnError`.
|
2951
|
-
*
|
2952
|
-
* @returns The response of sending message.
|
2953
|
-
*/
|
2954
|
-
sendMessage(text, onError) {
|
2955
|
-
return __awaiter(this, void 0, void 0, function* () {
|
2956
|
-
const response = {};
|
2957
|
-
yield this.parent.adapter.continueConversationAsync(this.parent.botAppId, this.parent.conversationReference, (context) => __awaiter(this, void 0, void 0, function* () {
|
2958
|
-
const conversation = yield this.newConversation(context);
|
2959
|
-
yield this.parent.adapter.continueConversationAsync(this.parent.botAppId, conversation, (ctx) => __awaiter(this, void 0, void 0, function* () {
|
2960
|
-
try {
|
2961
|
-
const res = yield ctx.sendActivity(text);
|
2962
|
-
response.id = res === null || res === void 0 ? void 0 : res.id;
|
2963
|
-
}
|
2964
|
-
catch (error) {
|
2965
|
-
if (onError) {
|
2966
|
-
yield onError(ctx, error);
|
2967
|
-
}
|
2968
|
-
else {
|
2969
|
-
throw error;
|
2970
|
-
}
|
2971
|
-
}
|
2972
|
-
}));
|
2973
|
-
}));
|
2974
|
-
return response;
|
2975
|
-
});
|
2976
|
-
}
|
2977
|
-
/**
|
2978
|
-
* Send an adaptive card message.
|
2979
|
-
*
|
2980
|
-
* @param card - The adaptive card raw JSON.
|
2981
|
-
* @param onError - An optional error handler that can catch exceptions during adaptive card sending.
|
2982
|
-
* If not defined, error will be handled by `BotAdapter.onTurnError`.
|
2983
|
-
*
|
2984
|
-
* @returns The response of sending adaptive card message.
|
2985
|
-
*/
|
2986
|
-
sendAdaptiveCard(card, onError) {
|
2987
|
-
return __awaiter(this, void 0, void 0, function* () {
|
2988
|
-
const response = {};
|
2989
|
-
yield this.parent.adapter.continueConversationAsync(this.parent.botAppId, this.parent.conversationReference, (context) => __awaiter(this, void 0, void 0, function* () {
|
2990
|
-
const conversation = yield this.newConversation(context);
|
2991
|
-
yield this.parent.adapter.continueConversationAsync(this.parent.botAppId, conversation, (ctx) => __awaiter(this, void 0, void 0, function* () {
|
2992
|
-
try {
|
2993
|
-
const res = yield ctx.sendActivity({
|
2994
|
-
attachments: [botbuilder.CardFactory.adaptiveCard(card)],
|
2995
|
-
});
|
2996
|
-
response.id = res === null || res === void 0 ? void 0 : res.id;
|
2997
|
-
}
|
2998
|
-
catch (error) {
|
2999
|
-
if (onError) {
|
3000
|
-
yield onError(ctx, error);
|
3001
|
-
}
|
3002
|
-
else {
|
3003
|
-
throw error;
|
3004
|
-
}
|
3005
|
-
}
|
3006
|
-
}));
|
3007
|
-
}));
|
3008
|
-
return response;
|
3009
|
-
});
|
3010
|
-
}
|
3011
|
-
/**
|
3012
|
-
* @internal
|
3013
|
-
*/
|
3014
|
-
newConversation(context) {
|
3015
|
-
return __awaiter(this, void 0, void 0, function* () {
|
3016
|
-
const reference = botbuilder.TurnContext.getConversationReference(context.activity);
|
3017
|
-
const personalConversation = cloneConversation(reference);
|
3018
|
-
const connectorClient = context.turnState.get(this.parent.adapter.ConnectorClientKey);
|
3019
|
-
const conversation = yield connectorClient.conversations.createConversation({
|
3020
|
-
isGroup: false,
|
3021
|
-
tenantId: context.activity.conversation.tenantId,
|
3022
|
-
bot: context.activity.recipient,
|
3023
|
-
members: [this.account],
|
3024
|
-
channelData: {},
|
3025
|
-
});
|
3026
|
-
personalConversation.conversation.id = conversation.id;
|
3027
|
-
return personalConversation;
|
3028
|
-
});
|
3029
|
-
}
|
3030
|
-
}
|
3031
|
-
/**
|
3032
|
-
* A {@link NotificationTarget} that represents a bot installation. Teams Bot could be installed into
|
3033
|
-
* - Personal chat
|
3034
|
-
* - Group chat
|
3035
|
-
* - Team (by default the `General` channel)
|
3036
|
-
*
|
3037
|
-
* @remarks
|
3038
|
-
* It's recommended to get bot installations from {@link ConversationBot.installations()}.
|
3039
|
-
*/
|
3040
|
-
class TeamsBotInstallation {
|
3041
|
-
/**
|
3042
|
-
* Constructor
|
3043
|
-
*
|
3044
|
-
* @remarks
|
3045
|
-
* It's recommended to get bot installations from {@link ConversationBot.installations()}, instead of using this constructor.
|
3046
|
-
*
|
3047
|
-
* @param adapter - The bound `CloudAdapter`.
|
3048
|
-
* @param conversationReference - The bound `ConversationReference`.
|
3049
|
-
* @param botAppId - The bot app id.
|
3050
|
-
*/
|
3051
|
-
constructor(adapter, conversationReference, botAppId) {
|
3052
|
-
this.adapter = adapter;
|
3053
|
-
this.conversationReference = conversationReference;
|
3054
|
-
this.type = getTargetType(conversationReference);
|
3055
|
-
this.botAppId = botAppId;
|
3056
|
-
}
|
3057
|
-
/**
|
3058
|
-
* Send a plain text message.
|
3059
|
-
*
|
3060
|
-
* @param text - The plain text message.
|
3061
|
-
* @param onError - An optional error handler that can catch exceptions during message sending.
|
3062
|
-
* If not defined, error will be handled by `BotAdapter.onTurnError`.
|
3063
|
-
*
|
3064
|
-
* @returns The response of sending message.
|
3065
|
-
*/
|
3066
|
-
sendMessage(text, onError) {
|
3067
|
-
return __awaiter(this, void 0, void 0, function* () {
|
3068
|
-
const response = {};
|
3069
|
-
yield this.adapter.continueConversationAsync(this.botAppId, this.conversationReference, (context) => __awaiter(this, void 0, void 0, function* () {
|
3070
|
-
try {
|
3071
|
-
const res = yield context.sendActivity(text);
|
3072
|
-
response.id = res === null || res === void 0 ? void 0 : res.id;
|
3073
|
-
}
|
3074
|
-
catch (error) {
|
3075
|
-
if (onError) {
|
3076
|
-
yield onError(context, error);
|
3077
|
-
}
|
3078
|
-
else {
|
3079
|
-
throw error;
|
3080
|
-
}
|
3081
|
-
}
|
3082
|
-
}));
|
3083
|
-
return response;
|
3084
|
-
});
|
3085
|
-
}
|
3086
|
-
/**
|
3087
|
-
* Send an adaptive card message.
|
3088
|
-
*
|
3089
|
-
* @param card - The adaptive card raw JSON.
|
3090
|
-
* @param onError - An optional error handler that can catch exceptions during adaptive card sending.
|
3091
|
-
* If not defined, error will be handled by `BotAdapter.onTurnError`.
|
3092
|
-
*
|
3093
|
-
* @returns The response of sending adaptive card message.
|
3094
|
-
*/
|
3095
|
-
sendAdaptiveCard(card, onError) {
|
3096
|
-
return __awaiter(this, void 0, void 0, function* () {
|
3097
|
-
const response = {};
|
3098
|
-
yield this.adapter.continueConversationAsync(this.botAppId, this.conversationReference, (context) => __awaiter(this, void 0, void 0, function* () {
|
3099
|
-
try {
|
3100
|
-
const res = yield context.sendActivity({
|
3101
|
-
attachments: [botbuilder.CardFactory.adaptiveCard(card)],
|
3102
|
-
});
|
3103
|
-
response.id = res === null || res === void 0 ? void 0 : res.id;
|
3104
|
-
}
|
3105
|
-
catch (error) {
|
3106
|
-
if (onError) {
|
3107
|
-
yield onError(context, error);
|
3108
|
-
}
|
3109
|
-
else {
|
3110
|
-
throw error;
|
3111
|
-
}
|
3112
|
-
}
|
3113
|
-
}));
|
3114
|
-
return response;
|
3115
|
-
});
|
3116
|
-
}
|
3117
|
-
/**
|
3118
|
-
* Get channels from this bot installation.
|
3119
|
-
*
|
3120
|
-
* @returns An array of channels if bot is installed into a team, otherwise returns an empty array.
|
3121
|
-
*/
|
3122
|
-
channels() {
|
3123
|
-
return __awaiter(this, void 0, void 0, function* () {
|
3124
|
-
const channels = [];
|
3125
|
-
if (this.type !== exports.NotificationTargetType.Channel) {
|
3126
|
-
return channels;
|
3127
|
-
}
|
3128
|
-
let teamsChannels = [];
|
3129
|
-
yield this.adapter.continueConversationAsync(this.botAppId, this.conversationReference, (context) => __awaiter(this, void 0, void 0, function* () {
|
3130
|
-
const teamId = getTeamsBotInstallationId(context);
|
3131
|
-
if (teamId !== undefined) {
|
3132
|
-
teamsChannels = yield botbuilder.TeamsInfo.getTeamChannels(context, teamId);
|
3133
|
-
}
|
3134
|
-
}));
|
3135
|
-
for (const channel of teamsChannels) {
|
3136
|
-
channels.push(new Channel(this, channel));
|
3137
|
-
}
|
3138
|
-
return channels;
|
3139
|
-
});
|
3140
|
-
}
|
3141
|
-
/**
|
3142
|
-
* Gets a pagined list of members from this bot installation.
|
3143
|
-
*
|
3144
|
-
* @param pageSize - Suggested number of entries on a page.
|
3145
|
-
* @param continuationToken - A continuation token.
|
3146
|
-
* @returns An array of members from where the bot is installed.
|
3147
|
-
*/
|
3148
|
-
getPagedMembers(pageSize, continuationToken) {
|
3149
|
-
return __awaiter(this, void 0, void 0, function* () {
|
3150
|
-
let result = {
|
3151
|
-
data: [],
|
3152
|
-
continuationToken: "",
|
3153
|
-
};
|
3154
|
-
yield this.adapter.continueConversationAsync(this.botAppId, this.conversationReference, (context) => __awaiter(this, void 0, void 0, function* () {
|
3155
|
-
const pagedMembers = yield botbuilder.TeamsInfo.getPagedMembers(context, pageSize, continuationToken);
|
3156
|
-
result = {
|
3157
|
-
data: pagedMembers.members.map((m) => new Member(this, m)),
|
3158
|
-
continuationToken: pagedMembers.continuationToken,
|
3159
|
-
};
|
3160
|
-
}));
|
3161
|
-
return result;
|
3162
|
-
});
|
3163
|
-
}
|
3164
|
-
/**
|
3165
|
-
* Get team details from this bot installation
|
3166
|
-
*
|
3167
|
-
* @returns The team details if bot is installed into a team, otherwise returns `undefined`.
|
3168
|
-
*/
|
3169
|
-
getTeamDetails() {
|
3170
|
-
return __awaiter(this, void 0, void 0, function* () {
|
3171
|
-
if (this.type !== exports.NotificationTargetType.Channel) {
|
3172
|
-
return undefined;
|
3173
|
-
}
|
3174
|
-
let teamDetails;
|
3175
|
-
yield this.adapter.continueConversationAsync(this.botAppId, this.conversationReference, (context) => __awaiter(this, void 0, void 0, function* () {
|
3176
|
-
const teamId = getTeamsBotInstallationId(context);
|
3177
|
-
if (teamId !== undefined) {
|
3178
|
-
teamDetails = yield botbuilder.TeamsInfo.getTeamDetails(context, teamId);
|
3179
|
-
}
|
3180
|
-
}));
|
3181
|
-
return teamDetails;
|
3182
|
-
});
|
3183
|
-
}
|
3184
|
-
}
|
3185
|
-
/**
|
3186
|
-
* Provide utilities to send notification to varies targets (e.g., member, group, channel).
|
3187
|
-
*/
|
3188
|
-
class NotificationBot {
|
3189
|
-
/**
|
3190
|
-
* Constructor of the notification bot.
|
3191
|
-
*
|
3192
|
-
* @remarks
|
3193
|
-
* To ensure accuracy, it's recommended to initialize before handling any message.
|
3194
|
-
*
|
3195
|
-
* @param adapter - The bound `CloudAdapter`
|
3196
|
-
* @param options - The initialize options
|
3197
|
-
*/
|
3198
|
-
constructor(adapter, options) {
|
3199
|
-
var _a, _b;
|
3200
|
-
if (options === null || options === void 0 ? void 0 : options.store) {
|
3201
|
-
this.conversationReferenceStore = options.store;
|
3202
|
-
}
|
3203
|
-
else {
|
3204
|
-
this.conversationReferenceStore = new DefaultConversationReferenceStore(path__namespace.resolve(process.env.RUNNING_ON_AZURE === "1" ? (_a = process.env.TEMP) !== null && _a !== void 0 ? _a : "./" : "./"));
|
3205
|
-
}
|
3206
|
-
this.adapter = adapter.use(new NotificationMiddleware({
|
3207
|
-
conversationReferenceStore: this.conversationReferenceStore,
|
3208
|
-
}));
|
3209
|
-
this.botAppId = ((_b = options === null || options === void 0 ? void 0 : options.botAppId) !== null && _b !== void 0 ? _b : process.env.BOT_ID);
|
3210
|
-
}
|
3211
|
-
/**
|
3212
|
-
* Create a {@link TeamsBotInstallation} instance with conversation reference.
|
3213
|
-
*
|
3214
|
-
* @param conversationReference - The bound `ConversationReference`.
|
3215
|
-
* @returns - The {@link TeamsBotInstallation} instance or null.
|
3216
|
-
*/
|
3217
|
-
buildTeamsBotInstallation(conversationReference) {
|
3218
|
-
if (!conversationReference) {
|
3219
|
-
throw new Error("conversationReference is required.");
|
3220
|
-
}
|
3221
|
-
return new TeamsBotInstallation(this.adapter, conversationReference, this.botAppId);
|
3222
|
-
}
|
3223
|
-
/**
|
3224
|
-
* Validate the installation by getting paged memebers.
|
3225
|
-
*
|
3226
|
-
* @param conversationReference The bound `ConversationReference`.
|
3227
|
-
* @returns Returns false if recieves `BotNotInConversationRoster` error, otherwise returns true.
|
3228
|
-
*/
|
3229
|
-
validateInstallation(conversationReference) {
|
3230
|
-
return __awaiter(this, void 0, void 0, function* () {
|
3231
|
-
let isValid = true;
|
3232
|
-
yield this.adapter.continueConversationAsync(this.botAppId, conversationReference, (context) => __awaiter(this, void 0, void 0, function* () {
|
3233
|
-
try {
|
3234
|
-
// try get member to see if the installation is still valid
|
3235
|
-
yield botbuilder.TeamsInfo.getPagedMembers(context, 1);
|
3236
|
-
}
|
3237
|
-
catch (error) {
|
3238
|
-
if (error.code === "BotNotInConversationRoster") {
|
3239
|
-
isValid = false;
|
3240
|
-
}
|
3241
|
-
}
|
3242
|
-
}));
|
3243
|
-
return isValid;
|
3244
|
-
});
|
3245
|
-
}
|
3246
|
-
/**
|
3247
|
-
* Gets a pagined list of targets where the bot is installed.
|
3248
|
-
*
|
3249
|
-
* @remarks
|
3250
|
-
* The result is retrieving from the persisted storage.
|
3251
|
-
*
|
3252
|
-
* @param pageSize - Suggested number of entries on a page.
|
3253
|
-
* @param continuationToken - A continuation token.
|
3254
|
-
*
|
3255
|
-
* @returns An array of {@link TeamsBotInstallation} with paged data and continuation token.
|
3256
|
-
*/
|
3257
|
-
getPagedInstallations(pageSize_1, continuationToken_1) {
|
3258
|
-
return __awaiter(this, arguments, void 0, function* (pageSize, continuationToken, validationEnabled = true) {
|
3259
|
-
if (this.conversationReferenceStore === undefined || this.adapter === undefined) {
|
3260
|
-
throw new Error("NotificationBot has not been initialized.");
|
3261
|
-
}
|
3262
|
-
const references = yield this.conversationReferenceStore.list(pageSize, continuationToken);
|
3263
|
-
const targets = [];
|
3264
|
-
for (const reference of references.data) {
|
3265
|
-
// validate connection
|
3266
|
-
let valid;
|
3267
|
-
if (validationEnabled) {
|
3268
|
-
// try get member to see if the installation is still valid
|
3269
|
-
valid = yield this.validateInstallation(reference);
|
3270
|
-
}
|
3271
|
-
if (!validationEnabled || (validationEnabled && valid)) {
|
3272
|
-
targets.push(new TeamsBotInstallation(this.adapter, reference, this.botAppId));
|
3273
|
-
}
|
3274
|
-
else {
|
3275
|
-
yield this.conversationReferenceStore.remove(getKey(reference), reference);
|
3276
|
-
}
|
3277
|
-
}
|
3278
|
-
return {
|
3279
|
-
data: targets,
|
3280
|
-
continuationToken: references.continuationToken,
|
3281
|
-
};
|
3282
|
-
});
|
3283
|
-
}
|
3284
|
-
/**
|
3285
|
-
* Return the first {@link Member} where predicate is true, and undefined otherwise.
|
3286
|
-
*
|
3287
|
-
* @param predicate - Find calls predicate once for each member of the installation,
|
3288
|
-
* until it finds one where predicate returns true. If such a member is found, find
|
3289
|
-
* immediately returns that member. Otherwise, find returns undefined.
|
3290
|
-
* @param scope - The scope to find members from the installations
|
3291
|
-
* (personal chat, group chat, Teams channel).
|
3292
|
-
*
|
3293
|
-
* @returns The first {@link Member} where predicate is true, and `undefined` otherwise.
|
3294
|
-
*/
|
3295
|
-
findMember(predicate, scope) {
|
3296
|
-
return __awaiter(this, void 0, void 0, function* () {
|
3297
|
-
for (const target of yield this.installations()) {
|
3298
|
-
if (this.matchSearchScope(target, scope)) {
|
3299
|
-
const members = [];
|
3300
|
-
let continuationToken;
|
3301
|
-
do {
|
3302
|
-
const pagedData = yield target.getPagedMembers(undefined, continuationToken);
|
3303
|
-
continuationToken = pagedData.continuationToken;
|
3304
|
-
members.push(...pagedData.data);
|
3305
|
-
} while (continuationToken);
|
3306
|
-
for (const member of members) {
|
3307
|
-
if (yield predicate(member)) {
|
3308
|
-
return member;
|
3309
|
-
}
|
3310
|
-
}
|
3311
|
-
}
|
3312
|
-
}
|
3313
|
-
return;
|
3314
|
-
});
|
3315
|
-
}
|
3316
|
-
/**
|
3317
|
-
* Return the first {@link Channel} where predicate is true, and undefined otherwise.
|
3318
|
-
* (Ensure the bot app is installed into the `General` channel, otherwise undefined will be returned.)
|
3319
|
-
*
|
3320
|
-
* @param predicate - Find calls predicate once for each channel of the installation,
|
3321
|
-
* until it finds one where predicate returns true. If such a channel is found, find
|
3322
|
-
* immediately returns that channel. Otherwise, find returns `undefined`.
|
3323
|
-
*
|
3324
|
-
* @returns The first {@link Channel} where predicate is true, and `undefined` otherwise.
|
3325
|
-
*/
|
3326
|
-
findChannel(predicate) {
|
3327
|
-
return __awaiter(this, void 0, void 0, function* () {
|
3328
|
-
for (const target of yield this.installations()) {
|
3329
|
-
if (target.type === exports.NotificationTargetType.Channel) {
|
3330
|
-
const teamDetails = yield target.getTeamDetails();
|
3331
|
-
for (const channel of yield target.channels()) {
|
3332
|
-
if (yield predicate(channel, teamDetails)) {
|
3333
|
-
return channel;
|
3334
|
-
}
|
3335
|
-
}
|
3336
|
-
}
|
3337
|
-
}
|
3338
|
-
return;
|
3339
|
-
});
|
3340
|
-
}
|
3341
|
-
/**
|
3342
|
-
* Return all {@link Member} where predicate is true, and empty array otherwise.
|
3343
|
-
*
|
3344
|
-
* @param predicate - Find calls predicate for each member of the installation.
|
3345
|
-
* @param scope - The scope to find members from the installations
|
3346
|
-
* (personal chat, group chat, Teams channel).
|
3347
|
-
*
|
3348
|
-
* @returns An array of {@link Member} where predicate is true, and empty array otherwise.
|
3349
|
-
*/
|
3350
|
-
findAllMembers(predicate, scope) {
|
3351
|
-
return __awaiter(this, void 0, void 0, function* () {
|
3352
|
-
const members = [];
|
3353
|
-
for (const target of yield this.installations()) {
|
3354
|
-
if (this.matchSearchScope(target, scope)) {
|
3355
|
-
const targetMembers = [];
|
3356
|
-
let continuationToken;
|
3357
|
-
do {
|
3358
|
-
const pagedData = yield target.getPagedMembers(undefined, continuationToken);
|
3359
|
-
continuationToken = pagedData.continuationToken;
|
3360
|
-
targetMembers.push(...pagedData.data);
|
3361
|
-
} while (continuationToken);
|
3362
|
-
for (const member of targetMembers) {
|
3363
|
-
if (yield predicate(member)) {
|
3364
|
-
members.push(member);
|
3365
|
-
}
|
3366
|
-
}
|
3367
|
-
}
|
3368
|
-
}
|
3369
|
-
return members;
|
3370
|
-
});
|
3371
|
-
}
|
3372
|
-
/**
|
3373
|
-
* Return all {@link Channel} where predicate is true, and empty array otherwise.
|
3374
|
-
* (Ensure the bot app is installed into the `General` channel, otherwise empty array will be returned.)
|
3375
|
-
*
|
3376
|
-
* @param predicate - Find calls predicate for each channel of the installation.
|
3377
|
-
*
|
3378
|
-
* @returns An array of {@link Channel} where predicate is true, and empty array otherwise.
|
3379
|
-
*/
|
3380
|
-
findAllChannels(predicate) {
|
3381
|
-
return __awaiter(this, void 0, void 0, function* () {
|
3382
|
-
const channels = [];
|
3383
|
-
for (const target of yield this.installations()) {
|
3384
|
-
if (target.type === exports.NotificationTargetType.Channel) {
|
3385
|
-
const teamDetails = yield target.getTeamDetails();
|
3386
|
-
for (const channel of yield target.channels()) {
|
3387
|
-
if (yield predicate(channel, teamDetails)) {
|
3388
|
-
channels.push(channel);
|
3389
|
-
}
|
3390
|
-
}
|
3391
|
-
}
|
3392
|
-
}
|
3393
|
-
return channels;
|
3394
|
-
});
|
3395
|
-
}
|
3396
|
-
matchSearchScope(target, scope) {
|
3397
|
-
scope = scope !== null && scope !== void 0 ? scope : SearchScope.All;
|
3398
|
-
return ((target.type === exports.NotificationTargetType.Channel && (scope & SearchScope.Channel) !== 0) ||
|
3399
|
-
(target.type === exports.NotificationTargetType.Group && (scope & SearchScope.Group) !== 0) ||
|
3400
|
-
(target.type === exports.NotificationTargetType.Person && (scope & SearchScope.Person) !== 0));
|
3401
|
-
}
|
3402
|
-
/**
|
3403
|
-
* @internal
|
3404
|
-
* Get all targets where the bot is installed.
|
3405
|
-
*
|
3406
|
-
* @remarks
|
3407
|
-
* The result is retrieving from the persisted storage.
|
3408
|
-
*
|
3409
|
-
* @returns An array of {@link TeamsBotInstallation}
|
3410
|
-
*/
|
3411
|
-
installations() {
|
3412
|
-
return __awaiter(this, void 0, void 0, function* () {
|
3413
|
-
let continuationToken;
|
3414
|
-
const targets = [];
|
3415
|
-
do {
|
3416
|
-
const result = yield this.getPagedInstallations(undefined, continuationToken);
|
3417
|
-
continuationToken = result.continuationToken;
|
3418
|
-
targets.push(...result.data);
|
3419
|
-
} while (continuationToken);
|
3420
|
-
return targets;
|
3421
|
-
});
|
3422
|
-
}
|
3423
|
-
}
|
3424
|
-
/**
|
3425
|
-
* The search scope when calling {@link NotificationBot.findMember} and {@link NotificationBot.findAllMembers}.
|
3426
|
-
* The search scope is a flagged enum and it can be combined with `|`.
|
3427
|
-
* For example, to search from personal chat and group chat, use `SearchScope.Person | SearchScope.Group`.
|
3428
|
-
*/
|
3429
|
-
var SearchScope;
|
3430
|
-
(function (SearchScope) {
|
3431
|
-
/**
|
3432
|
-
* Search members from the installations in personal chat only.
|
3433
|
-
*/
|
3434
|
-
SearchScope[SearchScope["Person"] = 1] = "Person";
|
3435
|
-
/**
|
3436
|
-
* Search members from the installations in group chat only.
|
3437
|
-
*/
|
3438
|
-
SearchScope[SearchScope["Group"] = 2] = "Group";
|
3439
|
-
/**
|
3440
|
-
* Search members from the installations in Teams channel only.
|
3441
|
-
*/
|
3442
|
-
SearchScope[SearchScope["Channel"] = 4] = "Channel";
|
3443
|
-
/**
|
3444
|
-
* Search members from all installations including personal chat, group chat and Teams channel.
|
3445
|
-
*/
|
3446
|
-
SearchScope[SearchScope["All"] = 7] = "All";
|
3447
|
-
})(SearchScope || (SearchScope = {}));
|
3448
|
-
|
3449
|
-
// Copyright (c) Microsoft Corporation.
|
3450
|
-
/**
|
3451
|
-
* Default SSO execution activity handler
|
3452
|
-
*/
|
3453
|
-
class DefaultBotSsoExecutionActivityHandler extends botbuilder.TeamsActivityHandler {
|
3454
|
-
/**
|
3455
|
-
* Creates a new instance of the DefaultBotSsoExecutionActivityHandler.
|
3456
|
-
* @param ssoConfig configuration for SSO command bot
|
3457
|
-
*
|
3458
|
-
* @remarks
|
3459
|
-
* In the constructor, it uses BotSsoConfig parameter which from {@link ConversationBot} options to initialize {@link BotSsoExecutionDialog}.
|
3460
|
-
* It also need to register an event handler for the message event which trigger {@link BotSsoExecutionDialog} instance.
|
3461
|
-
*/
|
3462
|
-
constructor(ssoConfig) {
|
3463
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
3464
|
-
super();
|
3465
|
-
const memoryStorage = new botbuilder.MemoryStorage();
|
3466
|
-
const userState = (_b = (_a = ssoConfig.dialog) === null || _a === void 0 ? void 0 : _a.userState) !== null && _b !== void 0 ? _b : new botbuilder.UserState(memoryStorage);
|
3467
|
-
const conversationState = (_d = (_c = ssoConfig.dialog) === null || _c === void 0 ? void 0 : _c.conversationState) !== null && _d !== void 0 ? _d : new botbuilder.ConversationState(memoryStorage);
|
3468
|
-
const dedupStorage = (_f = (_e = ssoConfig.dialog) === null || _e === void 0 ? void 0 : _e.dedupStorage) !== null && _f !== void 0 ? _f : memoryStorage;
|
3469
|
-
const _l = ssoConfig.aad, { scopes } = _l, customConfig = __rest(_l, ["scopes"]);
|
3470
|
-
const settings = {
|
3471
|
-
scopes: scopes,
|
3472
|
-
timeout: (_h = (_g = ssoConfig.dialog) === null || _g === void 0 ? void 0 : _g.ssoPromptConfig) === null || _h === void 0 ? void 0 : _h.timeout,
|
3473
|
-
endOnInvalidMessage: (_k = (_j = ssoConfig.dialog) === null || _j === void 0 ? void 0 : _j.ssoPromptConfig) === null || _k === void 0 ? void 0 : _k.endOnInvalidMessage,
|
3474
|
-
};
|
3475
|
-
this.ssoExecutionDialog = new BotSsoExecutionDialog(dedupStorage, settings, customConfig, customConfig.initiateLoginEndpoint);
|
3476
|
-
this.conversationState = conversationState;
|
3477
|
-
this.dialogState = conversationState.createProperty("DialogState");
|
3478
|
-
this.userState = userState;
|
3479
|
-
this.onMessage((context, next) => __awaiter(this, void 0, void 0, function* () {
|
3480
|
-
yield this.ssoExecutionDialog.run(context, this.dialogState);
|
3481
|
-
yield next();
|
3482
|
-
}));
|
3483
|
-
}
|
3484
|
-
/**
|
3485
|
-
* Add TeamsFxBotSsoCommandHandler instance to SSO execution dialog
|
3486
|
-
* @param handler {@link BotSsoExecutionDialogHandler} callback function
|
3487
|
-
* @param triggerPatterns The trigger pattern
|
3488
|
-
*
|
3489
|
-
* @remarks
|
3490
|
-
* This function is used to add SSO command to {@link BotSsoExecutionDialog} instance.
|
3491
|
-
*/
|
3492
|
-
addCommand(handler, triggerPatterns) {
|
3493
|
-
this.ssoExecutionDialog.addCommand(handler, triggerPatterns);
|
3494
|
-
}
|
3495
|
-
/**
|
3496
|
-
* Called to initiate the event emission process.
|
3497
|
-
* @param context The context object for the current turn.
|
3498
|
-
*/
|
3499
|
-
run(context) {
|
3500
|
-
const _super = Object.create(null, {
|
3501
|
-
run: { get: () => super.run }
|
3502
|
-
});
|
3503
|
-
return __awaiter(this, void 0, void 0, function* () {
|
3504
|
-
try {
|
3505
|
-
yield _super.run.call(this, context);
|
3506
|
-
}
|
3507
|
-
finally {
|
3508
|
-
yield this.conversationState.saveChanges(context, false);
|
3509
|
-
yield this.userState.saveChanges(context, false);
|
3510
|
-
}
|
3511
|
-
});
|
3512
|
-
}
|
3513
|
-
/**
|
3514
|
-
* Receives invoke activities with Activity name of 'signin/verifyState'.
|
3515
|
-
* @param context A context object for this turn.
|
3516
|
-
* @param query Signin state (part of signin action auth flow) verification invoke query.
|
3517
|
-
* @returns A promise that represents the work queued.
|
3518
|
-
*
|
3519
|
-
* @remarks
|
3520
|
-
* It should trigger {@link BotSsoExecutionDialog} instance to handle signin process
|
3521
|
-
*/
|
3522
|
-
handleTeamsSigninVerifyState(context, query) {
|
3523
|
-
return __awaiter(this, void 0, void 0, function* () {
|
3524
|
-
yield this.ssoExecutionDialog.run(context, this.dialogState);
|
3525
|
-
});
|
3526
|
-
}
|
3527
|
-
/**
|
3528
|
-
* Receives invoke activities with Activity name of 'signin/tokenExchange'
|
3529
|
-
* @param context A context object for this turn.
|
3530
|
-
* @param query Signin state (part of signin action auth flow) verification invoke query
|
3531
|
-
* @returns A promise that represents the work queued.
|
3532
|
-
*
|
3533
|
-
* @remarks
|
3534
|
-
* It should trigger {@link BotSsoExecutionDialog} instance to handle signin process
|
3535
|
-
*/
|
3536
|
-
handleTeamsSigninTokenExchange(context, query) {
|
3537
|
-
return __awaiter(this, void 0, void 0, function* () {
|
3538
|
-
yield this.ssoExecutionDialog.run(context, this.dialogState);
|
3539
|
-
});
|
3540
|
-
}
|
3541
|
-
}
|
3542
|
-
|
3543
|
-
// Copyright (c) Microsoft Corporation.
|
3544
|
-
/**
|
3545
|
-
* Provide utilities for bot conversation, including:
|
3546
|
-
* - handle command and response.
|
3547
|
-
* - send notification to varies targets (e.g., member, group, channel).
|
3548
|
-
*
|
3549
|
-
* @example
|
3550
|
-
* For command and response, you can register your commands through the constructor, or use the `registerCommand` and `registerCommands` API to add commands later.
|
3551
|
-
*
|
3552
|
-
* ```typescript
|
3553
|
-
* import { BotBuilderCloudAdapter } from "@microsoft/teamsfx";
|
3554
|
-
* import ConversationBot = BotBuilderCloudAdapter.ConversationBot;
|
3555
|
-
*
|
3556
|
-
* // register through constructor
|
3557
|
-
* const conversationBot = new ConversationBot({
|
3558
|
-
* command: {
|
3559
|
-
* enabled: true,
|
3560
|
-
* commands: [ new HelloWorldCommandHandler() ],
|
3561
|
-
* },
|
3562
|
-
* });
|
3563
|
-
*
|
3564
|
-
* // register through `register*` API
|
3565
|
-
* conversationBot.command.registerCommand(new HelpCommandHandler());
|
3566
|
-
* ```
|
3567
|
-
*
|
3568
|
-
* For notification, you can enable notification at initialization, then send notifications at any time.
|
3569
|
-
*
|
3570
|
-
* ```typescript
|
3571
|
-
* import { BotBuilderCloudAdapter } from "@microsoft/teamsfx";
|
3572
|
-
* import ConversationBot = BotBuilderCloudAdapter.ConversationBot;
|
3573
|
-
*
|
3574
|
-
* // enable through constructor
|
3575
|
-
* const conversationBot = new ConversationBot({
|
3576
|
-
* notification: {
|
3577
|
-
* enabled: true,
|
3578
|
-
* },
|
3579
|
-
* });
|
3580
|
-
*
|
3581
|
-
* // get all bot installations and send message
|
3582
|
-
* for (const target of await conversationBot.notification.installations()) {
|
3583
|
-
* await target.sendMessage("Hello Notification");
|
3584
|
-
* }
|
3585
|
-
*
|
3586
|
-
* // alternative - send message to all members
|
3587
|
-
* for (const target of await conversationBot.notification.installations()) {
|
3588
|
-
* for (const member of await target.members()) {
|
3589
|
-
* await member.sendMessage("Hello Notification");
|
3590
|
-
* }
|
3591
|
-
* }
|
3592
|
-
* ```
|
3593
|
-
*
|
3594
|
-
* @remarks
|
3595
|
-
* Set `adapter` in {@link ConversationOptions} to use your own bot adapter.
|
3596
|
-
*
|
3597
|
-
* For command and response, ensure each command should ONLY be registered with the command once, otherwise it'll cause unexpected behavior if you register the same command more than once.
|
3598
|
-
*
|
3599
|
-
* For notification, set `notification.storage` in {@link ConversationOptions} to use your own storage implementation.
|
3600
|
-
*/
|
3601
|
-
class ConversationBot {
|
3602
|
-
/**
|
3603
|
-
* Create new instance of the `ConversationBot`.
|
3604
|
-
*
|
3605
|
-
* @remarks
|
3606
|
-
* It's recommended to create your own adapter and storage for production environment instead of the default one.
|
3607
|
-
*
|
3608
|
-
* @param options - The initialize options.
|
3609
|
-
*/
|
3610
|
-
constructor(options) {
|
3611
|
-
var _a, _b, _c, _d;
|
3612
|
-
if (options.adapter) {
|
3613
|
-
this.adapter = options.adapter;
|
3614
|
-
}
|
3615
|
-
else {
|
3616
|
-
this.adapter = this.createDefaultAdapter(options.adapterConfig);
|
3617
|
-
}
|
3618
|
-
let ssoCommandActivityHandler;
|
3619
|
-
if (options === null || options === void 0 ? void 0 : options.ssoConfig) {
|
3620
|
-
if ((_a = options.ssoConfig.dialog) === null || _a === void 0 ? void 0 : _a.CustomBotSsoExecutionActivityHandler) {
|
3621
|
-
ssoCommandActivityHandler =
|
3622
|
-
new options.ssoConfig.dialog.CustomBotSsoExecutionActivityHandler(options.ssoConfig);
|
3623
|
-
}
|
3624
|
-
else {
|
3625
|
-
ssoCommandActivityHandler = new DefaultBotSsoExecutionActivityHandler(options.ssoConfig);
|
3626
|
-
}
|
3627
|
-
}
|
3628
|
-
if ((_b = options.command) === null || _b === void 0 ? void 0 : _b.enabled) {
|
3629
|
-
this.command = new CommandBot(this.adapter, options.command, ssoCommandActivityHandler, options.ssoConfig);
|
3630
|
-
}
|
3631
|
-
if ((_c = options.notification) === null || _c === void 0 ? void 0 : _c.enabled) {
|
3632
|
-
this.notification = new NotificationBot(this.adapter, options.notification);
|
3633
|
-
}
|
3634
|
-
if ((_d = options.cardAction) === null || _d === void 0 ? void 0 : _d.enabled) {
|
3635
|
-
this.cardAction = new CardActionBot(this.adapter, options.cardAction);
|
3636
|
-
}
|
3637
|
-
}
|
3638
|
-
createDefaultAdapter(adapterConfig) {
|
3639
|
-
const credentialsFactory = adapterConfig === undefined
|
3640
|
-
? new botbuilder.ConfigurationServiceClientCredentialFactory({
|
3641
|
-
MicrosoftAppId: process.env.BOT_ID,
|
3642
|
-
MicrosoftAppPassword: process.env.BOT_PASSWORD,
|
3643
|
-
MicrosoftAppType: "MultiTenant",
|
3644
|
-
})
|
3645
|
-
: new botbuilder.ConfigurationServiceClientCredentialFactory(adapterConfig);
|
3646
|
-
const botFrameworkAuthentication = new botbuilder.ConfigurationBotFrameworkAuthentication({}, credentialsFactory);
|
3647
|
-
const adapter = new botbuilder.CloudAdapter(botFrameworkAuthentication);
|
3648
|
-
// the default error handler
|
3649
|
-
adapter.onTurnError = (context, error) => __awaiter(this, void 0, void 0, function* () {
|
3650
|
-
// This check writes out errors to console.
|
3651
|
-
console.error(`[onTurnError] unhandled error`, error);
|
3652
|
-
// Only send error message for user messages, not for other message types so the bot doesn't spam a channel or chat.
|
3653
|
-
if (context.activity.type === "message") {
|
3654
|
-
// Send a trace activity, which will be displayed in Bot Framework Emulator
|
3655
|
-
yield context.sendTraceActivity("OnTurnError Trace", error instanceof Error ? error.message : error, "https://www.botframework.com/schemas/error", "TurnError");
|
3656
|
-
// Send a message to the user
|
3657
|
-
yield context.sendActivity(`The bot encountered unhandled error: ${error.message}`);
|
3658
|
-
yield context.sendActivity("To continue to run this bot, please fix the bot source code.");
|
3659
|
-
}
|
3660
|
-
});
|
3661
|
-
return adapter;
|
3662
|
-
}
|
3663
|
-
/**
|
3664
|
-
* The request handler to integrate with web request.
|
3665
|
-
*
|
3666
|
-
* @param req - An incoming HTTP [Request](xref:botbuilder.Request).
|
3667
|
-
* @param res - The corresponding HTTP [Response](xref:botbuilder.Response).
|
3668
|
-
* @param logic - The additional function to handle bot context.
|
3669
|
-
*
|
3670
|
-
* @example
|
3671
|
-
* For example, to use with Express:
|
3672
|
-
* ``` typescript
|
3673
|
-
* // The default/empty behavior
|
3674
|
-
* const expressApp = express();
|
3675
|
-
* expressApp.use(express.json());
|
3676
|
-
* expressApp.post("/api/notification", conversationBot.requestHandler);
|
3677
|
-
*
|
3678
|
-
* // Or, add your own logic
|
3679
|
-
* const expressApp = express();
|
3680
|
-
* expressApp.use(express.json());
|
3681
|
-
* expressApp.post("/api/notification", async (req, res) => {
|
3682
|
-
* await conversationBot.requestHandler(req, res, async (context) => {
|
3683
|
-
* // your-own-context-logic
|
3684
|
-
* });
|
3685
|
-
* });
|
3686
|
-
* ```
|
3687
|
-
*/
|
3688
|
-
requestHandler(req, res, logic) {
|
3689
|
-
return __awaiter(this, void 0, void 0, function* () {
|
3690
|
-
if (logic === undefined) {
|
3691
|
-
// create empty logic
|
3692
|
-
logic = () => __awaiter(this, void 0, void 0, function* () { });
|
3693
|
-
}
|
3694
|
-
yield this.adapter.process(req, res, logic);
|
3695
|
-
});
|
3696
|
-
}
|
3697
|
-
}
|
3698
|
-
|
3699
|
-
var conversationWithCloudAdapter = /*#__PURE__*/Object.freeze({
|
3700
|
-
__proto__: null,
|
3701
|
-
ConversationBot: ConversationBot,
|
3702
|
-
BotSsoExecutionDialog: BotSsoExecutionDialog,
|
3703
|
-
Channel: Channel,
|
3704
|
-
Member: Member,
|
3705
|
-
NotificationBot: NotificationBot,
|
3706
|
-
sendAdaptiveCard: sendAdaptiveCard,
|
3707
|
-
sendMessage: sendMessage,
|
3708
|
-
TeamsBotInstallation: TeamsBotInstallation,
|
3709
|
-
get SearchScope () { return SearchScope; },
|
3710
|
-
CommandBot: CommandBot,
|
3711
|
-
CardActionBot: CardActionBot
|
3712
|
-
});
|
3713
|
-
|
3714
|
-
exports.ApiKeyProvider = ApiKeyProvider;
|
3715
|
-
exports.AppCredential = AppCredential;
|
3716
|
-
exports.BasicAuthProvider = BasicAuthProvider;
|
3717
|
-
exports.BearerTokenAuthProvider = BearerTokenAuthProvider;
|
3718
|
-
exports.BotBuilderCloudAdapter = conversationWithCloudAdapter;
|
3719
|
-
exports.BotSsoExecutionDialog = BotSsoExecutionDialog;
|
3720
|
-
exports.CertificateAuthProvider = CertificateAuthProvider;
|
3721
|
-
exports.ErrorWithCode = ErrorWithCode;
|
3722
|
-
exports.InvokeResponseFactory = InvokeResponseFactory;
|
3723
|
-
exports.MessageBuilder = MessageBuilder;
|
3724
|
-
exports.OnBehalfOfUserCredential = OnBehalfOfUserCredential;
|
3725
|
-
exports.TeamsBotSsoPrompt = TeamsBotSsoPrompt;
|
3726
|
-
exports.TeamsUserCredential = TeamsUserCredential;
|
3727
|
-
exports.createApiClient = createApiClient;
|
3728
|
-
exports.createPemCertOption = createPemCertOption;
|
3729
|
-
exports.createPfxCertOption = createPfxCertOption;
|
3730
|
-
exports.getLogLevel = getLogLevel;
|
3731
|
-
exports.handleMessageExtensionLinkQueryWithSSO = handleMessageExtensionLinkQueryWithSSO;
|
3732
|
-
exports.handleMessageExtensionQueryWithSSO = handleMessageExtensionQueryWithSSO;
|
3733
|
-
exports.setLogFunction = setLogFunction;
|
3734
|
-
exports.setLogLevel = setLogLevel;
|
3735
|
-
exports.setLogger = setLogger;
|
1
|
+
"use strict";var e=require("jwt-decode"),t=require("@azure/msal-node"),o=require("crypto"),n=require("botbuilder"),i=require("botbuilder-dialogs"),r=require("uuid"),s=require("axios"),a=require("https"),d=require("adaptivecards-templating"),c=require("path"),l=require("fs");function u(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(o){if("default"!==o){var n=Object.getOwnPropertyDescriptor(e,o);Object.defineProperty(t,o,n.get?n:{enumerable:!0,get:function(){return e[o]}})}})),t.default=e,Object.freeze(t)}var h,p,v=u(d),y=u(c),f=u(l);exports.ErrorCode=void 0,(h=exports.ErrorCode||(exports.ErrorCode={})).InvalidParameter="InvalidParameter",h.InvalidConfiguration="InvalidConfiguration",h.InvalidCertificate="InvalidCertificate",h.InternalError="InternalError",h.ChannelNotSupported="ChannelNotSupported",h.FailedToRetrieveSsoToken="FailedToRetrieveSsoToken",h.FailedToProcessSsoHandler="FailedToProcessSsoHandler",h.CannotFindCommand="CannotFindCommand",h.FailedToRunSsoStep="FailedToRunSsoStep",h.FailedToRunDedupStep="FailedToRunDedupStep",h.SsoActivityHandlerIsUndefined="SsoActivityHandlerIsUndefined",h.RuntimeNotSupported="RuntimeNotSupported",h.ConsentFailed="ConsentFailed",h.UiRequiredError="UiRequiredError",h.TokenExpiredError="TokenExpiredError",h.ServiceError="ServiceError",h.FailedOperation="FailedOperation",h.InvalidResponse="InvalidResponse",h.AuthorizationInfoAlreadyExists="AuthorizationInfoAlreadyExists";class m{}m.InvalidConfiguration="{0} in configuration is invalid: {1}.",m.ConfigurationNotExists="Configuration does not exist. {0}",m.ResourceConfigurationNotExists="{0} resource configuration does not exist.",m.MissingResourceConfiguration="Missing resource configuration with type: {0}, name: {1}.",m.AuthenticationConfigurationNotExists="Authentication configuration does not exist.",m.BrowserRuntimeNotSupported="{0} is not supported in browser.",m.NodejsRuntimeNotSupported="{0} is not supported in Node.",m.FailToAcquireTokenOnBehalfOfUser="Failed to acquire access token on behalf of user: {0}",m.OnlyMSTeamsChannelSupported="{0} is only supported in MS Teams Channel",m.FailedToProcessSsoHandler="Failed to process sso handler: {0}",m.FailedToRetrieveSsoToken="Failed to retrieve sso token, user failed to finish the AAD consent flow.",m.CannotFindCommand="Cannot find command: {0}",m.FailedToRunSsoStep="Failed to run dialog to retrieve sso token: {0}",m.FailedToRunDedupStep="Failed to run dialog to remove duplicated messages: {0}",m.SsoActivityHandlerIsNull="Sso command can only be used or added when sso activity handler is not undefined",m.AuthorizationHeaderAlreadyExists="Authorization header already exists!",m.BasicCredentialAlreadyExists="Basic credential already exists!",m.EmptyParameter="Parameter {0} is empty",m.DuplicateHttpsOptionProperty="Axios HTTPS agent already defined value for property {0}",m.DuplicateApiKeyInHeader="The request already defined api key in request header with name {0}.",m.DuplicateApiKeyInQueryParam="The request already defined api key in query parameter with name {0}.",m.OnlySupportInQueryActivity="The handleMessageExtensionQueryWithToken only support in handleTeamsMessagingExtensionQuery with composeExtension/query type.",m.OnlySupportInLinkQueryActivity="The handleMessageExtensionLinkQueryWithSSO only support in handleTeamsAppBasedLinkQuery with composeExtension/queryLink type.";class g extends Error{constructor(e,t){if(!t)return super(e),this;super(e),Object.setPrototypeOf(this,g.prototype),this.name=`${new.target.name}.${t}`,this.code=t}}
|
2
|
+
/*! *****************************************************************************
|
3
|
+
Copyright (c) Microsoft Corporation.
|
4
|
+
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
6
|
+
purpose with or without fee is hereby granted.
|
7
|
+
|
8
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
9
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
10
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
11
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
12
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
13
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
14
|
+
PERFORMANCE OF THIS SOFTWARE.
|
15
|
+
***************************************************************************** */function C(e,t,o,n){return new(o||(o=Promise))((function(i,r){function s(e){try{d(n.next(e))}catch(e){r(e)}}function a(e){try{d(n.throw(e))}catch(e){r(e)}}function d(e){var t;e.done?i(e.value):(t=e.value,t instanceof o?t:new o((function(e){e(t)}))).then(s,a)}d((n=n.apply(e,t||[])).next())}))}exports.LogLevel=void 0,(p=exports.LogLevel||(exports.LogLevel={}))[p.Verbose=0]="Verbose",p[p.Info=1]="Info",p[p.Warn=2]="Warn",p[p.Error=3]="Error";const x=new class{constructor(e,t){this.level=void 0,this.defaultLogger={verbose:console.debug,info:console.info,warn:console.warn,error:console.error},this.name=e,this.level=t}error(e){this.log(exports.LogLevel.Error,(e=>e.error),e)}warn(e){this.log(exports.LogLevel.Warn,(e=>e.warn),e)}info(e){this.log(exports.LogLevel.Info,(e=>e.info),e)}verbose(e){this.log(exports.LogLevel.Verbose,(e=>e.verbose),e)}log(e,t,o){if(""===o.trim())return;const n=(new Date).toUTCString();let i;i=this.name?`[${n}] : @microsoft/teamsfx - ${this.name} : ${exports.LogLevel[e]} - `:`[${n}] : @microsoft/teamsfx : ${exports.LogLevel[e]} - `;const r=`${i}${o}`;void 0!==this.level&&this.level<=e&&(this.customLogger?t(this.customLogger)(r):this.customLogFunction?this.customLogFunction(e,r):t(this.defaultLogger)(r))}};function A(t){try{const o=e.jwtDecode(t);if(!o||!o.exp)throw new g("Decoded token is null or exp claim does not exists.",exports.ErrorCode.InternalError);return o}catch(e){const t="Parse jwt token failed in node env with error: "+e.message;throw x.error(t),new g(t,exports.ErrorCode.InternalError)}}function T(e,...t){const o=t;return e.replace(/{(\d+)}/g,(function(e,t){return void 0!==o[t]?o[t]:e}))}function S(e){if("string"==typeof e||e instanceof String)return;if(Array.isArray(e)&&0===e.length)return;if(Array.isArray(e)&&e.length>0&&e.every((e=>"string"==typeof e)))return;const t="The type of scopes is not valid, it must be string or string array";throw x.error(t),new g(t,exports.ErrorCode.InvalidParameter)}function w(e){return("string"==typeof e?e.split(" "):e).filter((e=>null!==e&&""!==e))}function I(e){const n=(i=e.authorityHost,r=e.tenantId,i.replace(/\/+$/g,"")+"/"+r);var i,r;const s=function(e){if(!e)return;const t=/(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/.exec(e);if(!t){const e="The certificate content does not contain a PEM-encoded certificate.";throw x.error(e),new g(e,exports.ErrorCode.InvalidCertificate)}return{thumbprintSha256:o.createHash("sha256").update(Buffer.from(t[3],"base64")).digest("hex").toUpperCase(),privateKey:e}}(e.certificateContent),a={clientId:e.clientId,authority:n};return s?a.clientCertificate=s:a.clientSecret=e.clientSecret,new t.ConfidentialClientApplication({auth:a})}class E{constructor(e,t){x.info("Get on behalf of user credential");const o=[];if(t.clientId||o.push("clientId"),t.authorityHost||o.push("authorityHost"),t.clientSecret||t.certificateContent||o.push("clientSecret or certificateContent"),t.tenantId||o.push("tenantId"),0!=o.length){const e=T(m.InvalidConfiguration,o.join(", "),"undefined");throw x.error(e),new g(e,exports.ErrorCode.InvalidConfiguration)}this.msalClient=I(t);const n=A(e);this.ssoToken={token:e,expiresOnTimestamp:n.exp}}getToken(e,t){return C(this,void 0,void 0,(function*(){S(e);const t=w(e);let o;if(t.length){let e;x.info("Get access token with scopes: "+t.join(" "));try{e=yield this.msalClient.acquireTokenOnBehalfOf({oboAssertion:this.ssoToken.token,scopes:t})}catch(e){throw this.generateAuthServerError(e)}if(!e){const e="Access token is null";throw x.error(e),new g(T(m.FailToAcquireTokenOnBehalfOfUser,e),exports.ErrorCode.InternalError)}o={token:e.accessToken,expiresOnTimestamp:e.expiresOn.getTime()}}else{if(x.info("Get SSO token."),Math.floor(Date.now()/1e3)>this.ssoToken.expiresOnTimestamp){const e="Sso token has already expired.";throw x.error(e),new g(e,exports.ErrorCode.TokenExpiredError)}o=this.ssoToken}return o}))}getUserInfo(){return x.info("Get basic user info from SSO token"),function(e){if(!e){const e="SSO token is undefined.";throw x.error(e),new g(e,exports.ErrorCode.InvalidParameter)}const t=A(e),o={displayName:t.name,objectId:t.oid,tenantId:t.tid,preferredUserName:""};return"2.0"===t.ver?o.preferredUserName=t.preferred_username:"1.0"===t.ver&&(o.preferredUserName=t.upn),o}(this.ssoToken.token)}generateAuthServerError(e){const t=e.errorMessage;if("InteractionRequiredAuthError"===e.name){const e="Failed to get access token from AAD server, interaction required: "+t;return x.warn(e),new g(e,exports.ErrorCode.UiRequiredError)}if(t&&t.indexOf("AADSTS50013")>=0){const e="Failed to get access token from AAD server, assertion is invalid because of various reasons: "+t;return x.error(e),new g(e,exports.ErrorCode.TokenExpiredError)}{const e=T(m.FailToAcquireTokenOnBehalfOfUser,t);return x.error(e),new g(e,exports.ErrorCode.ServiceError)}}}const k="invokeResponse";class R{constructor(e,t){this.id=e,this.failureDetail=t}}class b extends i.Dialog{constructor(e,t,o,n){super(o),this.initiateLoginEndpoint=t,this.authConfig=e,this.settings=n,S(this.settings.scopes),function(e){if(e.clientId&&(e.clientSecret||e.certificateContent)&&e.tenantId&&e.authorityHost)return;const t=[];e.clientId||t.push("clientId"),e.clientSecret||e.certificateContent||t.push("clientSecret or certificateContent"),e.tenantId||t.push("tenantId"),e.authorityHost||t.push("authorityHost");const o=T(m.InvalidConfiguration,t.join(", "),"undefined");throw x.error(o),new g(o,exports.ErrorCode.InvalidConfiguration)}(this.authConfig),x.info("Create a new Teams Bot SSO Prompt")}beginDialog(e){return C(this,void 0,void 0,(function*(){var t;x.info("Begin Teams Bot SSO Prompt"),this.ensureMsTeamsChannel(e);let o=9e5;if(this.settings.timeout){if("number"!=typeof this.settings.timeout){const e="type of timeout property in teamsBotSsoPromptSettings should be number.";throw x.error(e),new g(e,exports.ErrorCode.InvalidParameter)}if(this.settings.timeout<=0){const e="value of timeout property in teamsBotSsoPromptSettings should be positive.";throw x.error(e),new g(e,exports.ErrorCode.InvalidParameter)}o=this.settings.timeout}void 0===this.settings.endOnInvalidMessage&&(this.settings.endOnInvalidMessage=!0);const n=null===(t=e.activeDialog)||void 0===t?void 0:t.state;return n.state={},n.options={},n.expires=(new Date).getTime()+o,yield this.sendOAuthCardAsync(e.context),i.Dialog.EndOfTurn}))}continueDialog(e){return C(this,void 0,void 0,(function*(){var t;x.info("Continue Teams Bot SSO Prompt"),this.ensureMsTeamsChannel(e);const o=null===(t=e.activeDialog)||void 0===t?void 0:t.state,r=e.context.activity.type===n.ActivityTypes.Message;if((r||this.isTeamsVerificationInvoke(e.context)||this.isTokenExchangeRequestInvoke(e.context))&&(new Date).getTime()>o.expires)return x.warn("End Teams Bot SSO Prompt due to timeout"),yield e.endDialog(void 0);if(this.isTeamsVerificationInvoke(e.context)||this.isTokenExchangeRequestInvoke(e.context)){const t=yield this.recognizeToken(e);if(t.succeeded)return yield e.endDialog(t.value)}else if(r&&this.settings.endOnInvalidMessage)return x.warn("End Teams Bot SSO Prompt due to invalid message"),yield e.endDialog(void 0);return i.Dialog.EndOfTurn}))}ensureMsTeamsChannel(e){if(e.context.activity.channelId!=n.Channels.Msteams){const e=T(m.OnlyMSTeamsChannelSupported,"Teams Bot SSO Prompt");throw x.error(e),new g(e,exports.ErrorCode.ChannelNotSupported)}}sendOAuthCardAsync(e){return C(this,void 0,void 0,(function*(){x.verbose("Send OAuth card to get SSO token");const t=yield n.TeamsInfo.getMember(e,e.activity.from.id);x.verbose("Get Teams member account user principal name: "+(t.userPrincipalName?t.userPrincipalName:""));const o=t.userPrincipalName?t.userPrincipalName:"",i=this.getSignInResource(o),r=n.CardFactory.oauthCard("","Teams SSO Sign In","Sign In",i.signInLink,i.tokenExchangeResource);r.content.buttons[0].type=n.ActionTypes.Signin;const s=n.MessageFactory.attachment(r);yield e.sendActivity(s)}))}getSignInResource(e){x.verbose("Get sign in authentication configuration");const t=`${this.initiateLoginEndpoint}?scope=${encodeURI(this.settings.scopes.join(" "))}&clientId=${this.authConfig.clientId}&tenantId=${this.authConfig.tenantId}&loginHint=${e}`;x.verbose("Sign in link: "+t);return{signInLink:t,tokenExchangeResource:{id:r.v4()}}}recognizeToken(e){return C(this,void 0,void 0,(function*(){const t=e.context;let o;if(this.isTokenExchangeRequestInvoke(t))if(x.verbose("Receive token exchange request"),t.activity.value&&this.isTokenExchangeRequest(t.activity.value)){const e=t.activity.value.token,i=new E(e,this.authConfig);let r;try{if(r=yield i.getToken(this.settings.scopes),r){yield t.sendActivity(this.getTokenExchangeInvokeResponse(n.StatusCodes.OK,"",t.activity.value.id));const i=A(e).exp;o={ssoToken:e,ssoTokenExpiration:new Date(1e3*i).toISOString(),connectionName:"",token:r.token,expiration:r.expiresOnTimestamp.toString()}}}catch(e){const o="The bot is unable to exchange token. Ask for user consent.";x.info(o),yield t.sendActivity(this.getTokenExchangeInvokeResponse(n.StatusCodes.PRECONDITION_FAILED,o,t.activity.value.id))}}else{const e="The bot received an InvokeActivity that is missing a TokenExchangeInvokeRequest value. This is required to be sent with the InvokeActivity.";x.warn(e),yield t.sendActivity(this.getTokenExchangeInvokeResponse(n.StatusCodes.BAD_REQUEST,e))}else this.isTeamsVerificationInvoke(t)&&(x.verbose("Receive Teams state verification request"),yield this.sendOAuthCardAsync(e.context),yield t.sendActivity({type:k,value:{status:n.StatusCodes.OK}}));return void 0!==o?{succeeded:!0,value:o}:{succeeded:!1}}))}getTokenExchangeInvokeResponse(e,t,o){return{type:k,value:{status:e,body:new R(o,t)}}}isTeamsVerificationInvoke(e){const t=e.activity;return t.type===n.ActivityTypes.Invoke&&t.name===n.verifyStateOperationName}isTokenExchangeRequestInvoke(e){const t=e.activity;return t.type===n.ActivityTypes.Invoke&&t.name===n.tokenExchangeOperationName}isTokenExchangeRequest(e){return e.hasOwnProperty("token")}}var O,P,F,N;exports.ApiKeyLocation=void 0,(O=exports.ApiKeyLocation||(exports.ApiKeyLocation={}))[O.Header=0]="Header",O[O.QueryParams=1]="QueryParams";exports.NotificationTargetType=void 0,(P=exports.NotificationTargetType||(exports.NotificationTargetType={})).Channel="Channel",P.Group="Group",P.Person="Person",exports.AdaptiveCardResponse=void 0,(F=exports.AdaptiveCardResponse||(exports.AdaptiveCardResponse={}))[F.ReplaceForInteractor=0]="ReplaceForInteractor",F[F.ReplaceForAll=1]="ReplaceForAll",F[F.NewForAll=2]="NewForAll",exports.InvokeResponseErrorCode=void 0,(N=exports.InvokeResponseErrorCode||(exports.InvokeResponseErrorCode={}))[N.BadRequest=400]="BadRequest",N[N.InternalServerError=500]="InternalServerError";let D="BotSsoExecutionDialog",M="TeamsFxSsoPrompt",H="CommandRouteDialog";class L extends i.ComponentDialog{constructor(e,t,o,n,r){super(null!=r?r:D),this.dedupStorageKeys=[],this.commandMapping=new Map,r&&(D=r,M=r+M,H=r+H);const s=new b(o,n,M,t);this.addDialog(s),this.initialDialogId=H,this.dedupStorage=e,this.dedupStorageKeys=[];const a=new i.WaterfallDialog(H,[this.commandRouteStep.bind(this)]);this.addDialog(a)}addCommand(e,t){const o=this.getCommandHash(t),n=new i.WaterfallDialog(o,[this.ssoStep.bind(this),this.dedupStep.bind(this),t=>C(this,void 0,void 0,(function*(){const o=t.result.tokenResponse,n=t.context,i=t.result.message;try{if(!o)throw new Error(m.FailedToRetrieveSsoToken);return yield e(n,o,i),yield t.endDialog()}catch(e){const o=T(m.FailedToProcessSsoHandler,e.message);return x.error(o),yield t.endDialog(new g(o,exports.ErrorCode.FailedToProcessSsoHandler))}}))]);this.commandMapping.set(o,t),this.addDialog(n)}getCommandHash(e){const t=(Array.isArray(e)?e:[e]).join();return t.replace(/[^a-zA-Z0-9]/g,"")+o.createHash("sha256").update(t).digest("hex").toLowerCase()}run(e,t){return C(this,void 0,void 0,(function*(){const o=new i.DialogSet(t);o.add(this);const n=yield o.createContext(e);this.ensureMsTeamsChannel(n);const r=yield n.continueDialog();if(r&&r.status===i.DialogTurnStatus.empty)yield n.beginDialog(this.id);else if(r&&r.status===i.DialogTurnStatus.complete&&r.result instanceof Error)throw r.result}))}getActivityText(e){let t=e.text;const o=n.TurnContext.removeRecipientMention(e);return o&&(t=o.toLowerCase().replace(/\n|\r\n/g,"").trim()),t}commandRouteStep(e){return C(this,void 0,void 0,(function*(){const t=e.context,o=this.getActivityText(t.activity),n=this.getMatchesCommandId(o);if(n)return yield e.beginDialog(n);const i=T(m.CannotFindCommand,t.activity.text);throw x.error(i),new g(i,exports.ErrorCode.CannotFindCommand)}))}ssoStep(e){return C(this,void 0,void 0,(function*(){try{const t=e.context,o={text:this.getActivityText(t.activity)};return e.options.commandMessage=o,yield e.beginDialog(M)}catch(t){const o=T(m.FailedToRunSsoStep,t.message);return x.error(o),yield e.endDialog(new g(o,exports.ErrorCode.FailedToRunSsoStep))}}))}dedupStep(e){return C(this,void 0,void 0,(function*(){const t=e.result;if(!t)return x.error(m.FailedToRetrieveSsoToken),yield e.endDialog(new g(m.FailedToRetrieveSsoToken,exports.ErrorCode.FailedToRunSsoStep));try{return t&&(yield this.shouldDedup(e.context))?i.Dialog.EndOfTurn:yield e.next({tokenResponse:t,message:e.options.commandMessage})}catch(t){const o=T(m.FailedToRunDedupStep,t.message);return x.error(o),yield e.endDialog(new g(o,exports.ErrorCode.FailedToRunDedupStep))}}))}onEndDialog(e){return C(this,void 0,void 0,(function*(){const t=e.activity.conversation.id,o=this.dedupStorageKeys.filter((e=>e.indexOf(t)>0));yield this.dedupStorage.delete(o),this.dedupStorageKeys=this.dedupStorageKeys.filter((e=>e.indexOf(t)<0))}))}shouldDedup(e){return C(this,void 0,void 0,(function*(){const t={eTag:e.activity.value.id},o=this.getStorageKey(e),n={[o]:t};try{yield this.dedupStorage.write(n),this.dedupStorageKeys.push(o)}catch(e){if(e instanceof Error&&e.message.indexOf("eTag conflict"))return!0;throw e}return!1}))}getStorageKey(e){if(!e||!e.activity||!e.activity.conversation)throw new Error("Invalid context, can not get storage key!");const t=e.activity,o=t.channelId,i=t.conversation.id;if(t.type!==n.ActivityTypes.Invoke||t.name!==n.tokenExchangeOperationName)throw new Error("TokenExchangeState can only be used with Invokes of signin/tokenExchange.");const r=t.value;if(!r||!r.id)throw new Error("Invalid signin/tokenExchange. Missing activity.value.id.");return`${o}/${i}/${r.id}`}matchPattern(e,t){if(t){if("string"==typeof e){return new RegExp(e,"i").test(t)}if(e instanceof RegExp){const o=t.match(e);return null!=o&&o}}return!1}isPatternMatched(e,t){const o=Array.isArray(e)?e:[e];for(const e of o){return!!this.matchPattern(e,t)}return!1}getMatchesCommandId(e){for(const t of this.commandMapping){const o=t[1];if(this.isPatternMatched(o,e))return t[0]}}ensureMsTeamsChannel(e){if(e.context.activity.channelId!=n.Channels.Msteams){const e=T(m.OnlyMSTeamsChannelSupported,"SSO execution dialog");throw x.error(e),new g(e,exports.ErrorCode.ChannelNotSupported)}}}class B{static attachAdaptiveCard(e,t){const o={$root:t};return{attachments:[n.CardFactory.adaptiveCard(new v.Template(e).expand(o))]}}static attachAdaptiveCardWithoutData(e){return{attachments:[n.CardFactory.adaptiveCard(e)]}}static attachHeroCard(e,t,o,i){return B.attachContent(n.CardFactory.heroCard(e,t,o,i))}static attachSigninCard(e,t,o){return B.attachContent(n.CardFactory.signinCard(e,t,o))}static attachO365ConnectorCard(e){return B.attachContent(n.CardFactory.o365ConnectorCard(e))}static AttachReceiptCard(e){return B.attachContent(n.CardFactory.receiptCard(e))}static attachThumbnailCard(e,t,o,i){return B.attachContent(n.CardFactory.thumbnailCard(e,t,o,i))}static attachContent(e){return{attachments:[e]}}}var q,U,j;!function(e){e.AdaptiveCard="application/vnd.microsoft.card.adaptive",e.Message="application/vnd.microsoft.activity.message",e.Error="application/vnd.microsoft.error"}(q||(q={}));class ${static textMessage(e){if(!e)throw new Error("The text message cannot be null or empty");return{status:n.StatusCodes.OK,body:{statusCode:n.StatusCodes.OK,type:q.Message,value:e}}}static adaptiveCard(e){if(!e)throw new Error("The adaptive card content cannot be null or undefined");return{status:n.StatusCodes.OK,body:{statusCode:n.StatusCodes.OK,type:q.AdaptiveCard,value:e}}}static errorResponse(e,t){return{status:n.StatusCodes.OK,body:{statusCode:e,type:q.Error,value:{code:e.toString(),message:t}}}}static createInvokeResponse(e,t){return{status:e,body:t}}}function K(e,t,o,i,r){return C(this,void 0,void 0,(function*(){const s=e.activity.value;if(!s.authentication||!s.authentication.token)return x.verbose("No AccessToken in request, return silentAuth for AccessToken"),function(e,t,o){const n=w(o);return{composeExtension:{type:"silentAuth",suggestedActions:{actions:[{type:"openUrl",value:`${t}?scope=${encodeURI(n.join(" "))}&clientId=${e.clientId}&tenantId=${e.tenantId}`,title:"Message Extension OAuth"}]}}}}(t,o,i);try{const e=new E(s.authentication.token,t),o=yield e.getToken(i),n=A(s.authentication.token).exp,a={ssoToken:s.authentication.token,ssoTokenExpiration:new Date(1e3*n).toISOString(),token:o.token,expiration:o.expiresOnTimestamp.toString(),connectionName:""};if(r)return yield r(a)}catch(r){if(r instanceof g&&r.code===exports.ErrorCode.UiRequiredError&&"composeExtension/query"===e.activity.name){x.verbose("User not consent yet, return 412 to user consent first.");const t={status:412};return void(yield e.sendActivity({value:t,type:n.ActivityTypes.InvokeResponse}))}if(r instanceof g&&r.code===exports.ErrorCode.UiRequiredError&&"composeExtension/queryLink"===e.activity.name){x.verbose("User not consent yet, return auth card for user login");const r=function(e,t,o){const n=w(o);return{composeExtension:{type:"auth",suggestedActions:{actions:[{type:"openUrl",value:`${t}?scope=${encodeURI(n.join(" "))}&clientId=${e.clientId}&tenantId=${e.tenantId}`,title:"Message Extension OAuth"}]}}}}(t,o,i);return void(yield e.sendActivity({value:{status:200,body:r},type:n.ActivityTypes.InvokeResponse}))}throw r}}))}class z{constructor(e){this.actionHandlers=[],this.defaultMessage="Your response was sent to the app",e&&e.length>0&&this.actionHandlers.push(...e)}onTurn(e,t){return C(this,void 0,void 0,(function*(){var o,i,r;if("adaptiveCard/action"===e.activity.name){const t=e.activity.value.action,s=t.verb;for(const a of this.actionHandlers)if((null===(o=a.triggerVerb)||void 0===o?void 0:o.toLowerCase())===(null==s?void 0:s.toLowerCase())){let o;try{o=yield a.handleActionInvoked(e,t.data)}catch(t){const o=$.errorResponse(exports.InvokeResponseErrorCode.InternalServerError,t.message);throw yield this.sendInvokeResponse(e,o),t}switch(null===(i=o.body)||void 0===i?void 0:i.type){case q.AdaptiveCard:const t=null===(r=o.body)||void 0===r?void 0:r.value;if(!t){const t="Adaptive card content cannot be found in the response body";throw yield this.sendInvokeResponse(e,$.errorResponse(exports.InvokeResponseErrorCode.InternalServerError,t)),new Error(t)}t.refresh&&a.adaptiveCardResponse!==exports.AdaptiveCardResponse.NewForAll&&(a.adaptiveCardResponse=exports.AdaptiveCardResponse.ReplaceForAll);const i=n.MessageFactory.attachment(n.CardFactory.adaptiveCard(t));a.adaptiveCardResponse===exports.AdaptiveCardResponse.NewForAll?(yield this.sendInvokeResponse(e,$.textMessage(this.defaultMessage)),yield e.sendActivity(i)):a.adaptiveCardResponse===exports.AdaptiveCardResponse.ReplaceForAll?(i.id=e.activity.replyToId,yield e.updateActivity(i),yield this.sendInvokeResponse(e,o)):yield this.sendInvokeResponse(e,o);break;case q.Message:case q.Error:default:yield this.sendInvokeResponse(e,o)}break}}yield t()}))}sendInvokeResponse(e,t){return C(this,void 0,void 0,(function*(){yield e.sendActivity({type:n.ActivityTypes.InvokeResponse,value:t})}))}}class G{constructor(e,t){this.middleware=new z(null==t?void 0:t.actions),this.adapter=e.use(this.middleware)}registerHandler(e){e&&this.middleware.actionHandlers.push(e)}registerHandlers(e){e&&this.middleware.actionHandlers.push(...e)}}class Q{constructor(e,t,o){if(this.commandHandlers=[],this.ssoCommandHandlers=[],e=null!=e?e:[],t=null!=t?t:[],this.hasSsoCommand=t.length>0,this.ssoActivityHandler=o,this.hasSsoCommand&&!this.ssoActivityHandler)throw x.error(m.SsoActivityHandlerIsNull),new g(m.SsoActivityHandlerIsNull,exports.ErrorCode.SsoActivityHandlerIsUndefined);this.commandHandlers.push(...e);for(const e of t)this.addSsoCommand(e)}addSsoCommand(e){var t;null===(t=this.ssoActivityHandler)||void 0===t||t.addCommand(((t,o,n)=>C(this,void 0,void 0,(function*(){const i=this.shouldTrigger(e.triggerPatterns,n.text);n.matches=Array.isArray(i)?i:void 0;const r=yield e.handleCommandReceived(t,n,o);yield this.processResponse(t,r)}))),e.triggerPatterns),this.ssoCommandHandlers.push(e),this.hasSsoCommand=!0}onTurn(e,t){return C(this,void 0,void 0,(function*(){var o,i;if(e.activity.type===n.ActivityTypes.Message){const t=this.getActivityText(e.activity);let n=!1;for(const o of this.commandHandlers){const i=this.shouldTrigger(o.triggerPatterns,t);if(i){const r={text:t};r.matches=Array.isArray(i)?i:void 0;const s=yield o.handleCommandReceived(e,r);yield this.processResponse(e,s),n=!0;break}}if(!n)for(const n of this.ssoCommandHandlers){if(this.shouldTrigger(n.triggerPatterns,t)){yield null===(o=this.ssoActivityHandler)||void 0===o?void 0:o.run(e);break}}}else this.hasSsoCommand&&(yield null===(i=this.ssoActivityHandler)||void 0===i?void 0:i.run(e));yield t()}))}processResponse(e,t){return C(this,void 0,void 0,(function*(){if("string"==typeof t)yield e.sendActivity(t);else{const o=t;o&&(yield e.sendActivity(o))}}))}matchPattern(e,t){if(t){if("string"==typeof e){return new RegExp(e,"i").test(t)}if(e instanceof RegExp){const o=t.match(e);return null!=o&&o}}return!1}shouldTrigger(e,t){const o=Array.isArray(e)?e:[e];for(const e of o){const o=this.matchPattern(e,t);if(o)return o}return!1}getActivityText(e){let t=e.text;const o=n.TurnContext.removeRecipientMention(e);return o&&(t=o.toLowerCase().replace(/\n|\r\n/g,"").trim()),t}}class _{constructor(e,t,o,n){this.ssoConfig=n,this.middleware=new Q(null==t?void 0:t.commands,null==t?void 0:t.ssoCommands,o),this.adapter=e.use(this.middleware)}registerCommand(e){e&&this.middleware.commandHandlers.push(e)}registerCommands(e){e&&this.middleware.commandHandlers.push(...e)}registerSsoCommand(e){this.validateSsoActivityHandler(),this.middleware.addSsoCommand(e)}registerSsoCommands(e){if(e.length>0){this.validateSsoActivityHandler();for(const t of e)this.middleware.addSsoCommand(t)}}validateSsoActivityHandler(){if(!this.middleware.ssoActivityHandler)throw x.error(m.SsoActivityHandlerIsNull),new g(m.SsoActivityHandlerIsNull,exports.ErrorCode.SsoActivityHandlerIsUndefined)}}function V(e){return JSON.parse(JSON.stringify(e))}function W(e){var t,o;return`_${null===(t=e.conversation)||void 0===t?void 0:t.tenantId}_${null===(o=e.conversation)||void 0===o?void 0:o.id}`}function J(e){var t,o,n;const i=null===(n=null===(o=null===(t=e.activity)||void 0===t?void 0:t.channelData)||void 0===o?void 0:o.team)||void 0===n?void 0:n.id;return i||(void 0===e.activity.conversation.name?e.activity.conversation.id:void 0)}!function(e){e[e.CurrentBotInstalled=0]="CurrentBotInstalled",e[e.CurrentBotMessaged=1]="CurrentBotMessaged",e[e.CurrentBotUninstalled=2]="CurrentBotUninstalled",e[e.TeamDeleted=3]="TeamDeleted",e[e.TeamRestored=4]="TeamRestored",e[e.Unknown=5]="Unknown"}(U||(U={}));class Z{constructor(e){this.conversationReferenceStore=e.conversationReferenceStore}onTurn(e,t){return C(this,void 0,void 0,(function*(){switch(this.classifyActivity(e.activity)){case U.CurrentBotInstalled:case U.TeamRestored:{const t=n.TurnContext.getConversationReference(e.activity);yield this.conversationReferenceStore.add(W(t),t,{overwrite:!0});break}case U.CurrentBotMessaged:yield this.tryAddMessagedReference(e);break;case U.CurrentBotUninstalled:case U.TeamDeleted:{const t=n.TurnContext.getConversationReference(e.activity);yield this.conversationReferenceStore.remove(W(t),t);break}}yield t()}))}classifyActivity(e){var t,o;const n=e.type;if("installationUpdate"===n){const o=null===(t=e.action)||void 0===t?void 0:t.toLowerCase();return"add"===o||"add-upgrade"===o?U.CurrentBotInstalled:U.CurrentBotUninstalled}if("conversationUpdate"===n){const t=null===(o=e.channelData)||void 0===o?void 0:o.eventType;if("teamDeleted"===t)return U.TeamDeleted;if("teamRestored"===t)return U.TeamRestored}else if("message"===n)return U.CurrentBotMessaged;return U.Unknown}tryAddMessagedReference(e){return C(this,void 0,void 0,(function*(){var t,o,i,r,s,a;const d=n.TurnContext.getConversationReference(e.activity),c=null===(t=null==d?void 0:d.conversation)||void 0===t?void 0:t.conversationType;if("personal"===c||"groupChat"===c)yield this.conversationReferenceStore.add(W(d),d,{overwrite:!1});else if("channel"===c){const t=null===(r=null===(i=null===(o=e.activity)||void 0===o?void 0:o.channelData)||void 0===i?void 0:i.team)||void 0===r?void 0:r.id,n=null===(a=null===(s=e.activity.channelData)||void 0===s?void 0:s.channel)||void 0===a?void 0:a.id;if(void 0!==t&&(void 0===n||t===n)){const e=V(d);e.conversation.id=t,yield this.conversationReferenceStore.add(W(e),e,{overwrite:!1})}}}))}}class X{constructor(e){var t;this.localFileName=null!==(t=process.env.TEAMSFX_NOTIFICATION_STORE_FILENAME)&&void 0!==t?t:".notification.localstore.json",this.filePath=y.resolve(e,this.localFileName)}add(e,t,o){return C(this,void 0,void 0,(function*(){if(o.overwrite||!(yield this.storeFileExists())){if(yield this.storeFileExists()){const o=yield this.readFromFile();yield this.writeToFile(Object.assign(o,{[e]:t}))}else yield this.writeToFile({[e]:t});return!0}return!1}))}remove(e,t){return C(this,void 0,void 0,(function*(){if(!(yield this.storeFileExists()))return!1;if(yield this.storeFileExists()){const t=yield this.readFromFile();void 0!==t[e]&&(delete t[e],yield this.writeToFile(t))}return!0}))}list(e,t){return C(this,void 0,void 0,(function*(){if(!(yield this.storeFileExists()))return{data:[],continuationToken:""};const e=yield this.readFromFile();return{data:Object.entries(e).map((e=>e[1])),continuationToken:""}}))}storeFileExists(){return new Promise((e=>{try{f.access(this.filePath,(t=>{e(!t)}))}catch(t){e(!1)}}))}readFromFile(){return new Promise(((e,t)=>{try{f.readFile(this.filePath,{encoding:"utf-8"},((o,n)=>{o?t(o):e(JSON.parse(n))}))}catch(e){t(e)}}))}writeToFile(e){return C(this,void 0,void 0,(function*(){return new Promise(((t,o)=>{try{const n=JSON.stringify(e,void 0,2);f.writeFile(this.filePath,n,{encoding:"utf-8"},(e=>{e?o(e):t()}))}catch(e){o(e)}}))}))}}class Y{constructor(e,t){this.type=exports.NotificationTargetType.Channel,this.parent=e,this.info=t}sendMessage(e,t){return C(this,void 0,void 0,(function*(){const o={};return yield this.parent.adapter.continueConversationAsync(this.parent.botAppId,this.parent.conversationReference,(n=>C(this,void 0,void 0,(function*(){const i=yield this.newConversation(n);yield this.parent.adapter.continueConversationAsync(this.parent.botAppId,i,(n=>C(this,void 0,void 0,(function*(){try{const t=yield n.sendActivity(e);o.id=null==t?void 0:t.id}catch(e){if(!t)throw e;yield t(n,e)}}))))})))),o}))}sendAdaptiveCard(e,t){return C(this,void 0,void 0,(function*(){const o={};return yield this.parent.adapter.continueConversationAsync(this.parent.botAppId,this.parent.conversationReference,(i=>C(this,void 0,void 0,(function*(){const r=yield this.newConversation(i);yield this.parent.adapter.continueConversationAsync(this.parent.botAppId,r,(i=>C(this,void 0,void 0,(function*(){try{const t=yield i.sendActivity({attachments:[n.CardFactory.adaptiveCard(e)]});o.id=null==t?void 0:t.id}catch(e){if(!t)throw e;yield t(i,e)}}))))})))),o}))}newConversation(e){const t=V(n.TurnContext.getConversationReference(e.activity));return t.conversation.id=this.info.id||"",Promise.resolve(t)}}class ee{constructor(e,t){this.type=exports.NotificationTargetType.Person,this.parent=e,this.account=t}sendMessage(e,t){return C(this,void 0,void 0,(function*(){const o={};return yield this.parent.adapter.continueConversationAsync(this.parent.botAppId,this.parent.conversationReference,(n=>C(this,void 0,void 0,(function*(){const i=yield this.newConversation(n);yield this.parent.adapter.continueConversationAsync(this.parent.botAppId,i,(n=>C(this,void 0,void 0,(function*(){try{const t=yield n.sendActivity(e);o.id=null==t?void 0:t.id}catch(e){if(!t)throw e;yield t(n,e)}}))))})))),o}))}sendAdaptiveCard(e,t){return C(this,void 0,void 0,(function*(){const o={};return yield this.parent.adapter.continueConversationAsync(this.parent.botAppId,this.parent.conversationReference,(i=>C(this,void 0,void 0,(function*(){const r=yield this.newConversation(i);yield this.parent.adapter.continueConversationAsync(this.parent.botAppId,r,(i=>C(this,void 0,void 0,(function*(){try{const t=yield i.sendActivity({attachments:[n.CardFactory.adaptiveCard(e)]});o.id=null==t?void 0:t.id}catch(e){if(!t)throw e;yield t(i,e)}}))))})))),o}))}newConversation(e){return C(this,void 0,void 0,(function*(){const t=V(n.TurnContext.getConversationReference(e.activity)),o=e.turnState.get(this.parent.adapter.ConnectorClientKey),i=yield o.conversations.createConversation({isGroup:!1,tenantId:e.activity.conversation.tenantId,bot:e.activity.recipient,members:[this.account],channelData:{}});return t.conversation.id=i.id,t}))}}class te{constructor(e,t,o){this.adapter=e,this.conversationReference=t,this.type=function(e){var t;const o=null===(t=e.conversation)||void 0===t?void 0:t.conversationType;return"personal"===o?exports.NotificationTargetType.Person:"groupChat"===o?exports.NotificationTargetType.Group:"channel"===o?exports.NotificationTargetType.Channel:void 0}(t),this.botAppId=o}sendMessage(e,t){return C(this,void 0,void 0,(function*(){const o={};return yield this.adapter.continueConversationAsync(this.botAppId,this.conversationReference,(n=>C(this,void 0,void 0,(function*(){try{const t=yield n.sendActivity(e);o.id=null==t?void 0:t.id}catch(e){if(!t)throw e;yield t(n,e)}})))),o}))}sendAdaptiveCard(e,t){return C(this,void 0,void 0,(function*(){const o={};return yield this.adapter.continueConversationAsync(this.botAppId,this.conversationReference,(i=>C(this,void 0,void 0,(function*(){try{const t=yield i.sendActivity({attachments:[n.CardFactory.adaptiveCard(e)]});o.id=null==t?void 0:t.id}catch(e){if(!t)throw e;yield t(i,e)}})))),o}))}channels(){return C(this,void 0,void 0,(function*(){const e=[];if(this.type!==exports.NotificationTargetType.Channel)return e;let t=[];yield this.adapter.continueConversationAsync(this.botAppId,this.conversationReference,(e=>C(this,void 0,void 0,(function*(){const o=J(e);void 0!==o&&(t=yield n.TeamsInfo.getTeamChannels(e,o))}))));for(const o of t)e.push(new Y(this,o));return e}))}getPagedMembers(e,t){return C(this,void 0,void 0,(function*(){let o={data:[],continuationToken:""};return yield this.adapter.continueConversationAsync(this.botAppId,this.conversationReference,(i=>C(this,void 0,void 0,(function*(){const r=yield n.TeamsInfo.getPagedMembers(i,e,t);o={data:r.members.map((e=>new ee(this,e))),continuationToken:r.continuationToken}})))),o}))}getTeamDetails(){return C(this,void 0,void 0,(function*(){if(this.type!==exports.NotificationTargetType.Channel)return;let e;return yield this.adapter.continueConversationAsync(this.botAppId,this.conversationReference,(t=>C(this,void 0,void 0,(function*(){const o=J(t);void 0!==o&&(e=yield n.TeamsInfo.getTeamDetails(t,o))})))),e}))}}class oe{constructor(e,t){var o,n;(null==t?void 0:t.store)?this.conversationReferenceStore=t.store:this.conversationReferenceStore=new X(y.resolve("1"===process.env.RUNNING_ON_AZURE&&null!==(o=process.env.TEMP)&&void 0!==o?o:"./")),this.adapter=e.use(new Z({conversationReferenceStore:this.conversationReferenceStore})),this.botAppId=null!==(n=null==t?void 0:t.botAppId)&&void 0!==n?n:process.env.BOT_ID}buildTeamsBotInstallation(e){if(!e)throw new Error("conversationReference is required.");return new te(this.adapter,e,this.botAppId)}validateInstallation(e){return C(this,void 0,void 0,(function*(){let t=!0;return yield this.adapter.continueConversationAsync(this.botAppId,e,(e=>C(this,void 0,void 0,(function*(){try{yield n.TeamsInfo.getPagedMembers(e,1)}catch(e){"BotNotInConversationRoster"===e.code&&(t=!1)}})))),t}))}getPagedInstallations(e,t){return C(this,arguments,void 0,(function*(e,t,o=!0){if(void 0===this.conversationReferenceStore||void 0===this.adapter)throw new Error("NotificationBot has not been initialized.");const n=yield this.conversationReferenceStore.list(e,t),i=[];for(const e of n.data){let t;o&&(t=yield this.validateInstallation(e)),!o||o&&t?i.push(new te(this.adapter,e,this.botAppId)):yield this.conversationReferenceStore.remove(W(e),e)}return{data:i,continuationToken:n.continuationToken}}))}findMember(e,t){return C(this,void 0,void 0,(function*(){for(const o of yield this.installations())if(this.matchSearchScope(o,t)){const t=[];let n;do{const e=yield o.getPagedMembers(void 0,n);n=e.continuationToken,t.push(...e.data)}while(n);for(const o of t)if(yield e(o))return o}}))}findChannel(e){return C(this,void 0,void 0,(function*(){for(const t of yield this.installations())if(t.type===exports.NotificationTargetType.Channel){const o=yield t.getTeamDetails();for(const n of yield t.channels())if(yield e(n,o))return n}}))}findAllMembers(e,t){return C(this,void 0,void 0,(function*(){const o=[];for(const n of yield this.installations())if(this.matchSearchScope(n,t)){const t=[];let i;do{const e=yield n.getPagedMembers(void 0,i);i=e.continuationToken,t.push(...e.data)}while(i);for(const n of t)(yield e(n))&&o.push(n)}return o}))}findAllChannels(e){return C(this,void 0,void 0,(function*(){const t=[];for(const o of yield this.installations())if(o.type===exports.NotificationTargetType.Channel){const n=yield o.getTeamDetails();for(const i of yield o.channels())(yield e(i,n))&&t.push(i)}return t}))}matchSearchScope(e,t){return t=null!=t?t:j.All,e.type===exports.NotificationTargetType.Channel&&0!=(t&j.Channel)||e.type===exports.NotificationTargetType.Group&&0!=(t&j.Group)||e.type===exports.NotificationTargetType.Person&&0!=(t&j.Person)}installations(){return C(this,void 0,void 0,(function*(){let e;const t=[];do{const o=yield this.getPagedInstallations(void 0,e);e=o.continuationToken,t.push(...o.data)}while(e);return t}))}}!function(e){e[e.Person=1]="Person",e[e.Group=2]="Group",e[e.Channel=4]="Channel",e[e.All=7]="All"}(j||(j={}));class ne extends n.TeamsActivityHandler{constructor(e){var t,o,i,r,s,a,d,c,l,u;super();const h=new n.MemoryStorage,p=null!==(o=null===(t=e.dialog)||void 0===t?void 0:t.userState)&&void 0!==o?o:new n.UserState(h),v=null!==(r=null===(i=e.dialog)||void 0===i?void 0:i.conversationState)&&void 0!==r?r:new n.ConversationState(h),y=null!==(a=null===(s=e.dialog)||void 0===s?void 0:s.dedupStorage)&&void 0!==a?a:h,f=e.aad,{scopes:m}=f,g=function(e,t){var o={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&t.indexOf(n)<0&&(o[n]=e[n]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var i=0;for(n=Object.getOwnPropertySymbols(e);i<n.length;i++)t.indexOf(n[i])<0&&Object.prototype.propertyIsEnumerable.call(e,n[i])&&(o[n[i]]=e[n[i]])}return o}(f,["scopes"]),x={scopes:m,timeout:null===(c=null===(d=e.dialog)||void 0===d?void 0:d.ssoPromptConfig)||void 0===c?void 0:c.timeout,endOnInvalidMessage:null===(u=null===(l=e.dialog)||void 0===l?void 0:l.ssoPromptConfig)||void 0===u?void 0:u.endOnInvalidMessage};this.ssoExecutionDialog=new L(y,x,g,g.initiateLoginEndpoint),this.conversationState=v,this.dialogState=v.createProperty("DialogState"),this.userState=p,this.onMessage(((e,t)=>C(this,void 0,void 0,(function*(){yield this.ssoExecutionDialog.run(e,this.dialogState),yield t()}))))}addCommand(e,t){this.ssoExecutionDialog.addCommand(e,t)}run(e){const t=Object.create(null,{run:{get:()=>super.run}});return C(this,void 0,void 0,(function*(){try{yield t.run.call(this,e)}finally{yield this.conversationState.saveChanges(e,!1),yield this.userState.saveChanges(e,!1)}}))}handleTeamsSigninVerifyState(e,t){return C(this,void 0,void 0,(function*(){yield this.ssoExecutionDialog.run(e,this.dialogState)}))}handleTeamsSigninTokenExchange(e,t){return C(this,void 0,void 0,(function*(){yield this.ssoExecutionDialog.run(e,this.dialogState)}))}}var ie=Object.freeze({__proto__:null,BotSsoExecutionDialog:L,CardActionBot:G,Channel:Y,CommandBot:_,ConversationBot:class{constructor(e){var t,o,n,i;let r;e.adapter?this.adapter=e.adapter:this.adapter=this.createDefaultAdapter(e.adapterConfig),(null==e?void 0:e.ssoConfig)&&(r=(null===(t=e.ssoConfig.dialog)||void 0===t?void 0:t.CustomBotSsoExecutionActivityHandler)?new e.ssoConfig.dialog.CustomBotSsoExecutionActivityHandler(e.ssoConfig):new ne(e.ssoConfig)),(null===(o=e.command)||void 0===o?void 0:o.enabled)&&(this.command=new _(this.adapter,e.command,r,e.ssoConfig)),(null===(n=e.notification)||void 0===n?void 0:n.enabled)&&(this.notification=new oe(this.adapter,e.notification)),(null===(i=e.cardAction)||void 0===i?void 0:i.enabled)&&(this.cardAction=new G(this.adapter,e.cardAction))}createDefaultAdapter(e){const t=void 0===e?new n.ConfigurationServiceClientCredentialFactory({MicrosoftAppId:process.env.BOT_ID,MicrosoftAppPassword:process.env.BOT_PASSWORD,MicrosoftAppType:"MultiTenant"}):new n.ConfigurationServiceClientCredentialFactory(e),o=new n.ConfigurationBotFrameworkAuthentication({},t),i=new n.CloudAdapter(o);return i.onTurnError=(e,t)=>C(this,void 0,void 0,(function*(){console.error("[onTurnError] unhandled error",t),"message"===e.activity.type&&(yield e.sendTraceActivity("OnTurnError Trace",t instanceof Error?t.message:t,"https://www.botframework.com/schemas/error","TurnError"),yield e.sendActivity(`The bot encountered unhandled error: ${t.message}`),yield e.sendActivity("To continue to run this bot, please fix the bot source code."))})),i}requestHandler(e,t,o){return C(this,void 0,void 0,(function*(){void 0===o&&(o=()=>C(this,void 0,void 0,(function*(){}))),yield this.adapter.process(e,t,o)}))}},Member:ee,NotificationBot:oe,get SearchScope(){return j},TeamsBotInstallation:te,sendAdaptiveCard:function(e,t,o){return e.sendAdaptiveCard(t,o)},sendMessage:function(e,t,o){return e.sendMessage(t,o)}});exports.ApiKeyProvider=class{constructor(e,t,o){if(!e)throw new g(T(m.EmptyParameter,"keyName"),exports.ErrorCode.InvalidParameter);if(!t)throw new g(T(m.EmptyParameter,"keyVaule"),exports.ErrorCode.InvalidParameter);this.keyName=e,this.keyValue=t,this.keyLocation=o}AddAuthenticationInfo(e){switch(this.keyLocation){case exports.ApiKeyLocation.Header:if(e.headers||(e.headers={}),e.headers[this.keyName])return Promise.reject(new g(T(m.DuplicateApiKeyInHeader,this.keyName),exports.ErrorCode.AuthorizationInfoAlreadyExists));e.headers[this.keyName]=this.keyValue;break;case exports.ApiKeyLocation.QueryParams:e.params||(e.params={});let t=!1;if(e.url){t=new URL(e.url,e.baseURL).searchParams.has(this.keyName)}if(e.params[this.keyName]||t)return Promise.reject(new g(T(m.DuplicateApiKeyInQueryParam,this.keyName),exports.ErrorCode.AuthorizationInfoAlreadyExists));e.params[this.keyName]=this.keyValue}return Promise.resolve(e)}},exports.AppCredential=class{constructor(e){x.info("Create M365 tenant credential");const t=this.loadAndValidateConfig(e);this.msalClient=I(t)}getToken(e,t){return C(this,void 0,void 0,(function*(){let t;S(e);const o="string"==typeof e?e:e.join(" ");x.info("Get access token with scopes: "+o);try{const o=w(e),n=yield this.msalClient.acquireTokenByClientCredential({scopes:o});n&&(t={token:n.accessToken,expiresOnTimestamp:n.expiresOn.getTime()})}catch(e){const t="Get M365 tenant credential failed with error: "+e.message;throw x.error(t),new g(t,exports.ErrorCode.ServiceError)}if(!t){const e="Get M365 tenant credential access token failed with empty access token";throw x.error(e),new g(e,exports.ErrorCode.InternalError)}return t}))}loadAndValidateConfig(e){if(x.verbose("Validate authentication configuration"),e.clientId&&(e.clientSecret||e.certificateContent)&&e.tenantId&&e.authorityHost)return e;const t=[];e.clientId||t.push("clientId"),e.clientSecret||e.certificateContent||t.push("clientSecret or certificateContent"),e.tenantId||t.push("tenantId"),e.authorityHost||t.push("authorityHost");const o=T(m.InvalidConfiguration,t.join(", "),"undefined");throw x.error(o),new g(o,exports.ErrorCode.InvalidConfiguration)}},exports.BasicAuthProvider=class{constructor(e,t){if(!e)throw new g(T(m.EmptyParameter,"username"),exports.ErrorCode.InvalidParameter);if(!t)throw new g(T(m.EmptyParameter,"password"),exports.ErrorCode.InvalidParameter);this.userName=e,this.password=t}AddAuthenticationInfo(e){return e.headers&&e.headers.Authorization?Promise.reject(new g(m.AuthorizationHeaderAlreadyExists,exports.ErrorCode.AuthorizationInfoAlreadyExists)):e.auth?Promise.reject(new g(m.BasicCredentialAlreadyExists,exports.ErrorCode.AuthorizationInfoAlreadyExists)):(e.auth={username:this.userName,password:this.password},Promise.resolve(e))}},exports.BearerTokenAuthProvider=class{constructor(e){this.getToken=e}AddAuthenticationInfo(e){return C(this,void 0,void 0,(function*(){const t=yield this.getToken();if(e.headers||(e.headers={}),e.headers.Authorization)throw new g(m.AuthorizationHeaderAlreadyExists,exports.ErrorCode.AuthorizationInfoAlreadyExists);return e.headers.Authorization=`Bearer ${t}`,e}))}},exports.BotBuilderCloudAdapter=ie,exports.BotSsoExecutionDialog=L,exports.CertificateAuthProvider=class{constructor(e){if(!e||0===Object.keys(e).length)throw new g(T(m.EmptyParameter,"certOption"),exports.ErrorCode.InvalidParameter);this.certOption=e}AddAuthenticationInfo(e){if(e.httpsAgent){const t=new Set(Object.keys(e.httpsAgent.options));for(const e of Object.keys(this.certOption))if(t.has(e))return Promise.reject(new g(T(m.DuplicateHttpsOptionProperty,e),exports.ErrorCode.InvalidParameter));Object.assign(e.httpsAgent.options,this.certOption)}else e.httpsAgent=new a.Agent(this.certOption);return Promise.resolve(e)}},exports.ErrorWithCode=g,exports.InvokeResponseFactory=$,exports.MessageBuilder=B,exports.OnBehalfOfUserCredential=E,exports.TeamsBotSsoPrompt=b,exports.TeamsUserCredential=class{constructor(e){throw new g(T(m.NodejsRuntimeNotSupported,"TeamsUserCredential"),exports.ErrorCode.RuntimeNotSupported)}login(e,t){return Promise.reject(new g(T(m.NodejsRuntimeNotSupported,"TeamsUserCredential"),exports.ErrorCode.RuntimeNotSupported))}getToken(e,t){return Promise.reject(new g(T(m.NodejsRuntimeNotSupported,"TeamsUserCredential"),exports.ErrorCode.RuntimeNotSupported))}getUserInfo(e){return Promise.reject(new g(T(m.NodejsRuntimeNotSupported,"TeamsUserCredential"),exports.ErrorCode.RuntimeNotSupported))}},exports.createApiClient=function(e,t){const o=s.create({baseURL:e});return o.interceptors.request.use((function(e){return C(this,void 0,void 0,(function*(){return yield t.AddAuthenticationInfo(e)}))})),o},exports.createPemCertOption=function(e,t,o){if(0===e.length)throw new g(T(m.EmptyParameter,"cert"),exports.ErrorCode.InvalidParameter);if(0===t.length)throw new g(T(m.EmptyParameter,"key"),exports.ErrorCode.InvalidParameter);return{cert:e,key:t,passphrase:null==o?void 0:o.passphrase,ca:null==o?void 0:o.ca}},exports.createPfxCertOption=function(e,t){if(0===e.length)throw new g(T(m.EmptyParameter,"pfx"),exports.ErrorCode.InvalidParameter);return{pfx:e,passphrase:null==t?void 0:t.passphrase}},exports.getLogLevel=function(){return x.level},exports.handleMessageExtensionLinkQueryWithSSO=function(e,t,o,n,i){return C(this,void 0,void 0,(function*(){if("composeExtension/queryLink"!=e.activity.name)throw x.error(m.OnlySupportInLinkQueryActivity),new g(T(m.OnlySupportInLinkQueryActivity),exports.ErrorCode.FailedOperation);return yield K(e,null!=t?t:{},o,n,i)}))},exports.handleMessageExtensionQueryWithSSO=function(e,t,o,n,i){return C(this,void 0,void 0,(function*(){if("composeExtension/query"!=e.activity.name)throw x.error(m.OnlySupportInQueryActivity),new g(T(m.OnlySupportInQueryActivity),exports.ErrorCode.FailedOperation);return yield K(e,null!=t?t:{},o,n,i)}))},exports.setLogFunction=function(e){x.customLogFunction=e},exports.setLogLevel=function(e){x.level=e},exports.setLogger=function(e){x.customLogger=e};
|
3736
16
|
//# sourceMappingURL=index.node.cjs.js.map
|