@microsoft/teamsfx 1.1.2-alpha.988c78cba.0 → 1.1.2-alpha.9bd0cb559.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 +180 -17
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +492 -32
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +192 -17
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +513 -29
- package/dist/index.node.cjs.js.map +1 -1
- package/package.json +3 -3
- package/types/teamsfx.d.ts +336 -29
package/dist/index.node.cjs.js
CHANGED
|
@@ -69,6 +69,30 @@ exports.ErrorCode = void 0;
|
|
|
69
69
|
* Channel is not supported error.
|
|
70
70
|
*/
|
|
71
71
|
ErrorCode["ChannelNotSupported"] = "ChannelNotSupported";
|
|
72
|
+
/**
|
|
73
|
+
* Failed to retrieve sso token
|
|
74
|
+
*/
|
|
75
|
+
ErrorCode["FailedToRetrieveSsoToken"] = "FailedToRetrieveSsoToken";
|
|
76
|
+
/**
|
|
77
|
+
* Failed to process sso handler
|
|
78
|
+
*/
|
|
79
|
+
ErrorCode["FailedToProcessSsoHandler"] = "FailedToProcessSsoHandler";
|
|
80
|
+
/**
|
|
81
|
+
* Cannot find command
|
|
82
|
+
*/
|
|
83
|
+
ErrorCode["CannotFindCommand"] = "CannotFindCommand";
|
|
84
|
+
/**
|
|
85
|
+
* Failed to run sso step
|
|
86
|
+
*/
|
|
87
|
+
ErrorCode["FailedToRunSsoStep"] = "FailedToRunSsoStep";
|
|
88
|
+
/**
|
|
89
|
+
* Failed to run dedup step
|
|
90
|
+
*/
|
|
91
|
+
ErrorCode["FailedToRunDedupStep"] = "FailedToRunDedupStep";
|
|
92
|
+
/**
|
|
93
|
+
* Sso activity handler is undefined
|
|
94
|
+
*/
|
|
95
|
+
ErrorCode["SsoActivityHandlerIsUndefined"] = "SsoActivityHandlerIsUndefined";
|
|
72
96
|
/**
|
|
73
97
|
* Runtime is not supported error.
|
|
74
98
|
*/
|
|
@@ -124,6 +148,15 @@ ErrorMessage.NodejsRuntimeNotSupported = "{0} is not supported in Node.";
|
|
|
124
148
|
ErrorMessage.FailToAcquireTokenOnBehalfOfUser = "Failed to acquire access token on behalf of user: {0}";
|
|
125
149
|
// ChannelNotSupported Error
|
|
126
150
|
ErrorMessage.OnlyMSTeamsChannelSupported = "{0} is only supported in MS Teams Channel";
|
|
151
|
+
ErrorMessage.FailedToProcessSsoHandler = "Failed to process sso handler: {0}";
|
|
152
|
+
// FailedToRetrieveSsoToken Error
|
|
153
|
+
ErrorMessage.FailedToRetrieveSsoToken = "Failed to retrieve sso token, user failed to finish the AAD consent flow.";
|
|
154
|
+
// CannotFindCommand Error
|
|
155
|
+
ErrorMessage.CannotFindCommand = "Cannot find command: {0}";
|
|
156
|
+
ErrorMessage.FailedToRunSsoStep = "Failed to run dialog to retrieve sso token: {0}";
|
|
157
|
+
ErrorMessage.FailedToRunDedupStep = "Failed to run dialog to remove duplicated messages: {0}";
|
|
158
|
+
// SsoActivityHandlerIsUndefined Error
|
|
159
|
+
ErrorMessage.SsoActivityHandlerIsNull = "Sso command can only be used or added when sso activity handler is not undefined";
|
|
127
160
|
// IdentityTypeNotSupported Error
|
|
128
161
|
ErrorMessage.IdentityTypeNotSupported = "{0} identity is not supported in {1}";
|
|
129
162
|
// AuthorizationInfoError
|
|
@@ -728,10 +761,13 @@ class TeamsUserCredential {
|
|
|
728
761
|
}
|
|
729
762
|
/**
|
|
730
763
|
* Popup login page to get user's access token with specific scopes.
|
|
764
|
+
*
|
|
765
|
+
* @param {string[]} resources - The optional list of resources for full trust Teams apps.
|
|
766
|
+
*
|
|
731
767
|
* @remarks
|
|
732
768
|
* Can only be used within Teams.
|
|
733
769
|
*/
|
|
734
|
-
login(scopes) {
|
|
770
|
+
login(scopes, resources) {
|
|
735
771
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
736
772
|
throw new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "TeamsUserCredential"), exports.ErrorCode.RuntimeNotSupported);
|
|
737
773
|
});
|
|
@@ -748,10 +784,13 @@ class TeamsUserCredential {
|
|
|
748
784
|
}
|
|
749
785
|
/**
|
|
750
786
|
* Get basic user info from SSO token
|
|
787
|
+
*
|
|
788
|
+
* @param {string[]} resources - The optional list of resources for full trust Teams apps.
|
|
789
|
+
*
|
|
751
790
|
* @remarks
|
|
752
791
|
* Can only be used within Teams.
|
|
753
792
|
*/
|
|
754
|
-
getUserInfo() {
|
|
793
|
+
getUserInfo(resources) {
|
|
755
794
|
throw new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "TeamsUserCredential"), exports.ErrorCode.RuntimeNotSupported);
|
|
756
795
|
}
|
|
757
796
|
}
|
|
@@ -1723,8 +1762,9 @@ class TeamsFx {
|
|
|
1723
1762
|
this.configuration = new Map();
|
|
1724
1763
|
this.loadFromEnv();
|
|
1725
1764
|
if (customConfig) {
|
|
1726
|
-
|
|
1727
|
-
|
|
1765
|
+
const myConfig = Object.assign({}, customConfig);
|
|
1766
|
+
for (const key of Object.keys(myConfig)) {
|
|
1767
|
+
const value = myConfig[key];
|
|
1728
1768
|
if (value) {
|
|
1729
1769
|
this.configuration.set(key, value);
|
|
1730
1770
|
}
|
|
@@ -1766,9 +1806,10 @@ class TeamsFx {
|
|
|
1766
1806
|
}
|
|
1767
1807
|
/**
|
|
1768
1808
|
* Get user information.
|
|
1809
|
+
* @param {string[]} resources - The optional list of resources for full trust Teams apps.
|
|
1769
1810
|
* @returns UserInfo object.
|
|
1770
1811
|
*/
|
|
1771
|
-
getUserInfo() {
|
|
1812
|
+
getUserInfo(resources) {
|
|
1772
1813
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
1773
1814
|
if (this.identityType !== exports.IdentityType.User) {
|
|
1774
1815
|
const errorMsg = formatString(ErrorMessage.IdentityTypeNotSupported, this.identityType.toString(), "TeamsFx");
|
|
@@ -1792,13 +1833,14 @@ class TeamsFx {
|
|
|
1792
1833
|
* await teamsfx.login("https://graph.microsoft.com/User.Read Calendars.Read"); // multiple scopes using string
|
|
1793
1834
|
* ```
|
|
1794
1835
|
* @param scopes - The list of scopes for which the token will have access, before that, we will request user to consent.
|
|
1836
|
+
* @param {string[]} resources - The optional list of resources for full trust Teams apps.
|
|
1795
1837
|
*
|
|
1796
1838
|
* @throws {@link ErrorCode|InternalError} when failed to login with unknown error.
|
|
1797
1839
|
* @throws {@link ErrorCode|ConsentFailed} when user canceled or failed to consent.
|
|
1798
1840
|
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
|
1799
1841
|
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
|
|
1800
1842
|
*/
|
|
1801
|
-
login(scopes) {
|
|
1843
|
+
login(scopes, resources) {
|
|
1802
1844
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
1803
1845
|
throw new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "login"), exports.ErrorCode.RuntimeNotSupported);
|
|
1804
1846
|
});
|
|
@@ -2183,43 +2225,84 @@ class CardActionBot {
|
|
|
2183
2225
|
* @internal
|
|
2184
2226
|
*/
|
|
2185
2227
|
class CommandResponseMiddleware {
|
|
2186
|
-
constructor(handlers) {
|
|
2228
|
+
constructor(handlers, ssoHandlers, activityHandler) {
|
|
2187
2229
|
this.commandHandlers = [];
|
|
2188
|
-
|
|
2189
|
-
|
|
2230
|
+
this.ssoCommandHandlers = [];
|
|
2231
|
+
handlers = handlers !== null && handlers !== void 0 ? handlers : [];
|
|
2232
|
+
ssoHandlers = ssoHandlers !== null && ssoHandlers !== void 0 ? ssoHandlers : [];
|
|
2233
|
+
this.hasSsoCommand = ssoHandlers.length > 0;
|
|
2234
|
+
this.ssoActivityHandler = activityHandler;
|
|
2235
|
+
if (this.hasSsoCommand && !this.ssoActivityHandler) {
|
|
2236
|
+
internalLogger.error(ErrorMessage.SsoActivityHandlerIsNull);
|
|
2237
|
+
throw new ErrorWithCode(ErrorMessage.SsoActivityHandlerIsNull, exports.ErrorCode.SsoActivityHandlerIsUndefined);
|
|
2238
|
+
}
|
|
2239
|
+
this.commandHandlers.push(...handlers);
|
|
2240
|
+
for (const ssoHandler of ssoHandlers) {
|
|
2241
|
+
this.addSsoCommand(ssoHandler);
|
|
2190
2242
|
}
|
|
2191
2243
|
}
|
|
2244
|
+
addSsoCommand(ssoHandler) {
|
|
2245
|
+
var _a;
|
|
2246
|
+
(_a = this.ssoActivityHandler) === null || _a === void 0 ? void 0 : _a.addCommand((context, tokenResponse, message) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2247
|
+
const matchResult = this.shouldTrigger(ssoHandler.triggerPatterns, message.text);
|
|
2248
|
+
message.matches = Array.isArray(matchResult) ? matchResult : void 0;
|
|
2249
|
+
const response = yield ssoHandler.handleCommandReceived(context, message, tokenResponse);
|
|
2250
|
+
yield this.processResponse(context, response);
|
|
2251
|
+
}), ssoHandler.triggerPatterns);
|
|
2252
|
+
this.ssoCommandHandlers.push(ssoHandler);
|
|
2253
|
+
this.commandHandlers.push(ssoHandler);
|
|
2254
|
+
this.hasSsoCommand = true;
|
|
2255
|
+
}
|
|
2192
2256
|
onTurn(context, next) {
|
|
2257
|
+
var _a, _b;
|
|
2193
2258
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2194
2259
|
if (context.activity.type === botbuilder.ActivityTypes.Message) {
|
|
2195
2260
|
// Invoke corresponding command handler for the command response
|
|
2196
2261
|
const commandText = this.getActivityText(context.activity);
|
|
2197
|
-
const message = {
|
|
2198
|
-
text: commandText,
|
|
2199
|
-
};
|
|
2200
2262
|
for (const handler of this.commandHandlers) {
|
|
2201
2263
|
const matchResult = this.shouldTrigger(handler.triggerPatterns, commandText);
|
|
2202
2264
|
// It is important to note that the command bot will stop processing handlers
|
|
2203
2265
|
// when the first command handler is matched.
|
|
2204
2266
|
if (!!matchResult) {
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
if (typeof response === "string") {
|
|
2208
|
-
yield context.sendActivity(response);
|
|
2267
|
+
if (this.isSsoExecutionHandler(handler)) {
|
|
2268
|
+
yield ((_a = this.ssoActivityHandler) === null || _a === void 0 ? void 0 : _a.run(context));
|
|
2209
2269
|
}
|
|
2210
2270
|
else {
|
|
2211
|
-
const
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2271
|
+
const message = {
|
|
2272
|
+
text: commandText,
|
|
2273
|
+
};
|
|
2274
|
+
message.matches = Array.isArray(matchResult) ? matchResult : void 0;
|
|
2275
|
+
const response = yield handler.handleCommandReceived(context, message);
|
|
2276
|
+
yield this.processResponse(context, response);
|
|
2215
2277
|
}
|
|
2216
2278
|
break;
|
|
2217
2279
|
}
|
|
2218
2280
|
}
|
|
2219
2281
|
}
|
|
2282
|
+
else {
|
|
2283
|
+
if (this.hasSsoCommand) {
|
|
2284
|
+
yield ((_b = this.ssoActivityHandler) === null || _b === void 0 ? void 0 : _b.run(context));
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2220
2287
|
yield next();
|
|
2221
2288
|
});
|
|
2222
2289
|
}
|
|
2290
|
+
processResponse(context, response) {
|
|
2291
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2292
|
+
if (typeof response === "string") {
|
|
2293
|
+
yield context.sendActivity(response);
|
|
2294
|
+
}
|
|
2295
|
+
else {
|
|
2296
|
+
const replyActivity = response;
|
|
2297
|
+
if (replyActivity) {
|
|
2298
|
+
yield context.sendActivity(replyActivity);
|
|
2299
|
+
}
|
|
2300
|
+
}
|
|
2301
|
+
});
|
|
2302
|
+
}
|
|
2303
|
+
isSsoExecutionHandler(handler) {
|
|
2304
|
+
return this.ssoCommandHandlers.indexOf(handler) >= 0;
|
|
2305
|
+
}
|
|
2223
2306
|
matchPattern(pattern, text) {
|
|
2224
2307
|
if (text) {
|
|
2225
2308
|
if (typeof pattern === "string") {
|
|
@@ -2269,14 +2352,15 @@ class CommandBot {
|
|
|
2269
2352
|
* @param adapter The bound `BotFrameworkAdapter`.
|
|
2270
2353
|
* @param options - initialize options
|
|
2271
2354
|
*/
|
|
2272
|
-
constructor(adapter, options) {
|
|
2273
|
-
this.
|
|
2355
|
+
constructor(adapter, options, ssoCommandActivityHandler, ssoConfig) {
|
|
2356
|
+
this.ssoConfig = ssoConfig;
|
|
2357
|
+
this.middleware = new CommandResponseMiddleware(options === null || options === void 0 ? void 0 : options.commands, options === null || options === void 0 ? void 0 : options.ssoCommands, ssoCommandActivityHandler);
|
|
2274
2358
|
this.adapter = adapter.use(this.middleware);
|
|
2275
2359
|
}
|
|
2276
2360
|
/**
|
|
2277
2361
|
* Registers a command into the command bot.
|
|
2278
2362
|
*
|
|
2279
|
-
* @param command The command to
|
|
2363
|
+
* @param command The command to register.
|
|
2280
2364
|
*/
|
|
2281
2365
|
registerCommand(command) {
|
|
2282
2366
|
if (command) {
|
|
@@ -2286,13 +2370,41 @@ class CommandBot {
|
|
|
2286
2370
|
/**
|
|
2287
2371
|
* Registers commands into the command bot.
|
|
2288
2372
|
*
|
|
2289
|
-
* @param commands The
|
|
2373
|
+
* @param commands The commands to register.
|
|
2290
2374
|
*/
|
|
2291
2375
|
registerCommands(commands) {
|
|
2292
2376
|
if (commands) {
|
|
2293
2377
|
this.middleware.commandHandlers.push(...commands);
|
|
2294
2378
|
}
|
|
2295
2379
|
}
|
|
2380
|
+
/**
|
|
2381
|
+
* Registers a sso command into the command bot.
|
|
2382
|
+
*
|
|
2383
|
+
* @param command The command to register.
|
|
2384
|
+
*/
|
|
2385
|
+
registerSsoCommand(ssoCommand) {
|
|
2386
|
+
this.validateSsoActivityHandler();
|
|
2387
|
+
this.middleware.addSsoCommand(ssoCommand);
|
|
2388
|
+
}
|
|
2389
|
+
/**
|
|
2390
|
+
* Registers commands into the command bot.
|
|
2391
|
+
*
|
|
2392
|
+
* @param commands The commands to register.
|
|
2393
|
+
*/
|
|
2394
|
+
registerSsoCommands(ssoCommands) {
|
|
2395
|
+
if (ssoCommands.length > 0) {
|
|
2396
|
+
this.validateSsoActivityHandler();
|
|
2397
|
+
for (const ssoCommand of ssoCommands) {
|
|
2398
|
+
this.middleware.addSsoCommand(ssoCommand);
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
validateSsoActivityHandler() {
|
|
2403
|
+
if (!this.middleware.ssoActivityHandler) {
|
|
2404
|
+
internalLogger.error(ErrorMessage.SsoActivityHandlerIsNull);
|
|
2405
|
+
throw new ErrorWithCode(ErrorMessage.SsoActivityHandlerIsNull, exports.ErrorCode.SsoActivityHandlerIsUndefined);
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2296
2408
|
}
|
|
2297
2409
|
|
|
2298
2410
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -2898,6 +3010,366 @@ class NotificationBot {
|
|
|
2898
3010
|
}
|
|
2899
3011
|
}
|
|
2900
3012
|
|
|
3013
|
+
// Copyright (c) Microsoft Corporation.
|
|
3014
|
+
let DIALOG_NAME = "BotSsoExecutionDialog";
|
|
3015
|
+
let TEAMS_SSO_PROMPT_ID = "TeamsFxSsoPrompt";
|
|
3016
|
+
let COMMAND_ROUTE_DIALOG = "CommandRouteDialog";
|
|
3017
|
+
/**
|
|
3018
|
+
* Sso execution dialog, use to handle sso command
|
|
3019
|
+
*/
|
|
3020
|
+
class BotSsoExecutionDialog extends botbuilderDialogs.ComponentDialog {
|
|
3021
|
+
/**
|
|
3022
|
+
* Creates a new instance of the BotSsoExecutionDialog.
|
|
3023
|
+
* @param dedupStorage Helper storage to remove duplicated messages
|
|
3024
|
+
* @param settings The list of scopes for which the token will have access
|
|
3025
|
+
* @param teamsfx {@link TeamsFx} instance for authentication
|
|
3026
|
+
*/
|
|
3027
|
+
constructor(dedupStorage, ssoPromptSettings, teamsfx, dialogName) {
|
|
3028
|
+
super(dialogName !== null && dialogName !== void 0 ? dialogName : DIALOG_NAME);
|
|
3029
|
+
this.dedupStorageKeys = [];
|
|
3030
|
+
// Map to store the commandId and triggerPatterns, key: commandId, value: triggerPatterns
|
|
3031
|
+
this.commandMapping = new Map();
|
|
3032
|
+
if (dialogName) {
|
|
3033
|
+
DIALOG_NAME = dialogName;
|
|
3034
|
+
TEAMS_SSO_PROMPT_ID = dialogName + TEAMS_SSO_PROMPT_ID;
|
|
3035
|
+
COMMAND_ROUTE_DIALOG = dialogName + COMMAND_ROUTE_DIALOG;
|
|
3036
|
+
}
|
|
3037
|
+
this.initialDialogId = COMMAND_ROUTE_DIALOG;
|
|
3038
|
+
this.dedupStorage = dedupStorage;
|
|
3039
|
+
this.dedupStorageKeys = [];
|
|
3040
|
+
const ssoDialog = new TeamsBotSsoPrompt(teamsfx, TEAMS_SSO_PROMPT_ID, ssoPromptSettings);
|
|
3041
|
+
this.addDialog(ssoDialog);
|
|
3042
|
+
const commandRouteDialog = new botbuilderDialogs.WaterfallDialog(COMMAND_ROUTE_DIALOG, [
|
|
3043
|
+
this.commandRouteStep.bind(this),
|
|
3044
|
+
]);
|
|
3045
|
+
this.addDialog(commandRouteDialog);
|
|
3046
|
+
}
|
|
3047
|
+
/**
|
|
3048
|
+
* Add TeamsFxBotSsoCommandHandler instance
|
|
3049
|
+
* @param handler {@link BotSsoExecutionDialogHandler} callback function
|
|
3050
|
+
* @param triggerPatterns The trigger pattern
|
|
3051
|
+
*/
|
|
3052
|
+
addCommand(handler, triggerPatterns) {
|
|
3053
|
+
const commandId = this.getCommandHash(triggerPatterns);
|
|
3054
|
+
const dialog = new botbuilderDialogs.WaterfallDialog(commandId, [
|
|
3055
|
+
this.ssoStep.bind(this),
|
|
3056
|
+
this.dedupStep.bind(this),
|
|
3057
|
+
(stepContext) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3058
|
+
const tokenResponse = stepContext.result.tokenResponse;
|
|
3059
|
+
const context = stepContext.context;
|
|
3060
|
+
const message = stepContext.result.message;
|
|
3061
|
+
try {
|
|
3062
|
+
if (tokenResponse) {
|
|
3063
|
+
yield handler(context, tokenResponse, message);
|
|
3064
|
+
}
|
|
3065
|
+
else {
|
|
3066
|
+
throw new Error(ErrorMessage.FailedToRetrieveSsoToken);
|
|
3067
|
+
}
|
|
3068
|
+
return yield stepContext.endDialog();
|
|
3069
|
+
}
|
|
3070
|
+
catch (error) {
|
|
3071
|
+
const errorMsg = formatString(ErrorMessage.FailedToProcessSsoHandler, error.message);
|
|
3072
|
+
internalLogger.error(errorMsg);
|
|
3073
|
+
return yield stepContext.endDialog(new ErrorWithCode(errorMsg, exports.ErrorCode.FailedToProcessSsoHandler));
|
|
3074
|
+
}
|
|
3075
|
+
}),
|
|
3076
|
+
]);
|
|
3077
|
+
this.commandMapping.set(commandId, triggerPatterns);
|
|
3078
|
+
this.addDialog(dialog);
|
|
3079
|
+
}
|
|
3080
|
+
getCommandHash(patterns) {
|
|
3081
|
+
const expressions = Array.isArray(patterns) ? patterns : [patterns];
|
|
3082
|
+
const patternStr = expressions.join();
|
|
3083
|
+
const patternStrWithoutSpecialChar = patternStr.replace(/[^a-zA-Z0-9]/g, "");
|
|
3084
|
+
const hash = crypto.createHash("sha256").update(patternStr).digest("hex").toLowerCase();
|
|
3085
|
+
return patternStrWithoutSpecialChar + hash;
|
|
3086
|
+
}
|
|
3087
|
+
/**
|
|
3088
|
+
* The run method handles the incoming activity (in the form of a DialogContext) and passes it through the dialog system.
|
|
3089
|
+
*
|
|
3090
|
+
* @param context The context object for the current turn.
|
|
3091
|
+
* @param accessor The instance of StatePropertyAccessor for dialog system.
|
|
3092
|
+
*/
|
|
3093
|
+
run(context, accessor) {
|
|
3094
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3095
|
+
const dialogSet = new botbuilderDialogs.DialogSet(accessor);
|
|
3096
|
+
dialogSet.add(this);
|
|
3097
|
+
const dialogContext = yield dialogSet.createContext(context);
|
|
3098
|
+
this.ensureMsTeamsChannel(dialogContext);
|
|
3099
|
+
const results = yield dialogContext.continueDialog();
|
|
3100
|
+
if (results && results.status === botbuilderDialogs.DialogTurnStatus.empty) {
|
|
3101
|
+
yield dialogContext.beginDialog(this.id);
|
|
3102
|
+
}
|
|
3103
|
+
else if (results &&
|
|
3104
|
+
results.status === botbuilderDialogs.DialogTurnStatus.complete &&
|
|
3105
|
+
results.result instanceof Error) {
|
|
3106
|
+
throw results.result;
|
|
3107
|
+
}
|
|
3108
|
+
});
|
|
3109
|
+
}
|
|
3110
|
+
getActivityText(activity) {
|
|
3111
|
+
let text = activity.text;
|
|
3112
|
+
const removedMentionText = botbuilder.TurnContext.removeRecipientMention(activity);
|
|
3113
|
+
if (removedMentionText) {
|
|
3114
|
+
text = removedMentionText
|
|
3115
|
+
.toLowerCase()
|
|
3116
|
+
.replace(/\n|\r\n/g, "")
|
|
3117
|
+
.trim();
|
|
3118
|
+
}
|
|
3119
|
+
return text;
|
|
3120
|
+
}
|
|
3121
|
+
commandRouteStep(stepContext) {
|
|
3122
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3123
|
+
const turnContext = stepContext.context;
|
|
3124
|
+
const text = this.getActivityText(turnContext.activity);
|
|
3125
|
+
const commandId = this.getMatchesCommandId(text);
|
|
3126
|
+
if (commandId) {
|
|
3127
|
+
return yield stepContext.beginDialog(commandId);
|
|
3128
|
+
}
|
|
3129
|
+
const errorMsg = formatString(ErrorMessage.CannotFindCommand, turnContext.activity.text);
|
|
3130
|
+
internalLogger.error(errorMsg);
|
|
3131
|
+
throw new ErrorWithCode(errorMsg, exports.ErrorCode.CannotFindCommand);
|
|
3132
|
+
});
|
|
3133
|
+
}
|
|
3134
|
+
ssoStep(stepContext) {
|
|
3135
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3136
|
+
try {
|
|
3137
|
+
const turnContext = stepContext.context;
|
|
3138
|
+
const text = this.getActivityText(turnContext.activity);
|
|
3139
|
+
const message = {
|
|
3140
|
+
text,
|
|
3141
|
+
};
|
|
3142
|
+
stepContext.options.commandMessage = message;
|
|
3143
|
+
return yield stepContext.beginDialog(TEAMS_SSO_PROMPT_ID);
|
|
3144
|
+
}
|
|
3145
|
+
catch (error) {
|
|
3146
|
+
const errorMsg = formatString(ErrorMessage.FailedToRunSsoStep, error.message);
|
|
3147
|
+
internalLogger.error(errorMsg);
|
|
3148
|
+
return yield stepContext.endDialog(new ErrorWithCode(errorMsg, exports.ErrorCode.FailedToRunSsoStep));
|
|
3149
|
+
}
|
|
3150
|
+
});
|
|
3151
|
+
}
|
|
3152
|
+
dedupStep(stepContext) {
|
|
3153
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3154
|
+
const tokenResponse = stepContext.result;
|
|
3155
|
+
if (!tokenResponse) {
|
|
3156
|
+
internalLogger.error(ErrorMessage.FailedToRetrieveSsoToken);
|
|
3157
|
+
return yield stepContext.endDialog(new ErrorWithCode(ErrorMessage.FailedToRetrieveSsoToken, exports.ErrorCode.FailedToRunSsoStep));
|
|
3158
|
+
}
|
|
3159
|
+
try {
|
|
3160
|
+
// Only dedup after ssoStep to make sure that all Teams client would receive the login request
|
|
3161
|
+
if (tokenResponse && (yield this.shouldDedup(stepContext.context))) {
|
|
3162
|
+
return botbuilderDialogs.Dialog.EndOfTurn;
|
|
3163
|
+
}
|
|
3164
|
+
return yield stepContext.next({
|
|
3165
|
+
tokenResponse,
|
|
3166
|
+
message: stepContext.options.commandMessage,
|
|
3167
|
+
});
|
|
3168
|
+
}
|
|
3169
|
+
catch (error) {
|
|
3170
|
+
const errorMsg = formatString(ErrorMessage.FailedToRunDedupStep, error.message);
|
|
3171
|
+
internalLogger.error(errorMsg);
|
|
3172
|
+
return yield stepContext.endDialog(new ErrorWithCode(errorMsg, exports.ErrorCode.FailedToRunDedupStep));
|
|
3173
|
+
}
|
|
3174
|
+
});
|
|
3175
|
+
}
|
|
3176
|
+
/**
|
|
3177
|
+
* Called when the component is ending.
|
|
3178
|
+
*
|
|
3179
|
+
* @param context Context for the current turn of conversation.
|
|
3180
|
+
*/
|
|
3181
|
+
onEndDialog(context) {
|
|
3182
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3183
|
+
const conversationId = context.activity.conversation.id;
|
|
3184
|
+
const currentDedupKeys = this.dedupStorageKeys.filter((key) => key.indexOf(conversationId) > 0);
|
|
3185
|
+
yield this.dedupStorage.delete(currentDedupKeys);
|
|
3186
|
+
this.dedupStorageKeys = this.dedupStorageKeys.filter((key) => key.indexOf(conversationId) < 0);
|
|
3187
|
+
});
|
|
3188
|
+
}
|
|
3189
|
+
/**
|
|
3190
|
+
* If a user is signed into multiple Teams clients, the Bot might receive a "signin/tokenExchange" from each client.
|
|
3191
|
+
* Each token exchange request for a specific user login will have an identical activity.value.Id.
|
|
3192
|
+
* Only one of these token exchange requests should be processed by the bot. For a distributed bot in production,
|
|
3193
|
+
* this requires a distributed storage to ensure only one token exchange is processed.
|
|
3194
|
+
* @param context Context for the current turn of conversation.
|
|
3195
|
+
* @returns boolean value indicate whether the message should be removed
|
|
3196
|
+
*/
|
|
3197
|
+
shouldDedup(context) {
|
|
3198
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3199
|
+
const storeItem = {
|
|
3200
|
+
eTag: context.activity.value.id,
|
|
3201
|
+
};
|
|
3202
|
+
const key = this.getStorageKey(context);
|
|
3203
|
+
const storeItems = { [key]: storeItem };
|
|
3204
|
+
try {
|
|
3205
|
+
yield this.dedupStorage.write(storeItems);
|
|
3206
|
+
this.dedupStorageKeys.push(key);
|
|
3207
|
+
}
|
|
3208
|
+
catch (err) {
|
|
3209
|
+
if (err instanceof Error && err.message.indexOf("eTag conflict")) {
|
|
3210
|
+
return true;
|
|
3211
|
+
}
|
|
3212
|
+
throw err;
|
|
3213
|
+
}
|
|
3214
|
+
return false;
|
|
3215
|
+
});
|
|
3216
|
+
}
|
|
3217
|
+
getStorageKey(context) {
|
|
3218
|
+
if (!context || !context.activity || !context.activity.conversation) {
|
|
3219
|
+
throw new Error("Invalid context, can not get storage key!");
|
|
3220
|
+
}
|
|
3221
|
+
const activity = context.activity;
|
|
3222
|
+
const channelId = activity.channelId;
|
|
3223
|
+
const conversationId = activity.conversation.id;
|
|
3224
|
+
if (activity.type !== botbuilder.ActivityTypes.Invoke || activity.name !== botbuilder.tokenExchangeOperationName) {
|
|
3225
|
+
throw new Error("TokenExchangeState can only be used with Invokes of signin/tokenExchange.");
|
|
3226
|
+
}
|
|
3227
|
+
const value = activity.value;
|
|
3228
|
+
if (!value || !value.id) {
|
|
3229
|
+
throw new Error("Invalid signin/tokenExchange. Missing activity.value.id.");
|
|
3230
|
+
}
|
|
3231
|
+
return `${channelId}/${conversationId}/${value.id}`;
|
|
3232
|
+
}
|
|
3233
|
+
matchPattern(pattern, text) {
|
|
3234
|
+
if (text) {
|
|
3235
|
+
if (typeof pattern === "string") {
|
|
3236
|
+
const regExp = new RegExp(pattern, "i");
|
|
3237
|
+
return regExp.test(text);
|
|
3238
|
+
}
|
|
3239
|
+
if (pattern instanceof RegExp) {
|
|
3240
|
+
const matches = text.match(pattern);
|
|
3241
|
+
return matches !== null && matches !== void 0 ? matches : false;
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3244
|
+
return false;
|
|
3245
|
+
}
|
|
3246
|
+
isPatternMatched(patterns, text) {
|
|
3247
|
+
const expressions = Array.isArray(patterns) ? patterns : [patterns];
|
|
3248
|
+
for (const ex of expressions) {
|
|
3249
|
+
const matches = this.matchPattern(ex, text);
|
|
3250
|
+
return !!matches;
|
|
3251
|
+
}
|
|
3252
|
+
return false;
|
|
3253
|
+
}
|
|
3254
|
+
getMatchesCommandId(text) {
|
|
3255
|
+
for (const command of this.commandMapping) {
|
|
3256
|
+
const pattern = command[1];
|
|
3257
|
+
if (this.isPatternMatched(pattern, text)) {
|
|
3258
|
+
return command[0];
|
|
3259
|
+
}
|
|
3260
|
+
}
|
|
3261
|
+
return undefined;
|
|
3262
|
+
}
|
|
3263
|
+
/**
|
|
3264
|
+
* Ensure bot is running in MS Teams since TeamsBotSsoPrompt is only supported in MS Teams channel.
|
|
3265
|
+
* @param dc dialog context
|
|
3266
|
+
* @throws {@link ErrorCode|ChannelNotSupported} if bot channel is not MS Teams
|
|
3267
|
+
* @internal
|
|
3268
|
+
*/
|
|
3269
|
+
ensureMsTeamsChannel(dc) {
|
|
3270
|
+
if (dc.context.activity.channelId != botbuilder.Channels.Msteams) {
|
|
3271
|
+
const errorMsg = formatString(ErrorMessage.OnlyMSTeamsChannelSupported, "SSO execution dialog");
|
|
3272
|
+
internalLogger.error(errorMsg);
|
|
3273
|
+
throw new ErrorWithCode(errorMsg, exports.ErrorCode.ChannelNotSupported);
|
|
3274
|
+
}
|
|
3275
|
+
}
|
|
3276
|
+
}
|
|
3277
|
+
|
|
3278
|
+
// Copyright (c) Microsoft Corporation.
|
|
3279
|
+
/**
|
|
3280
|
+
* Default SSO execution activity handler
|
|
3281
|
+
*/
|
|
3282
|
+
class DefaultBotSsoExecutionActivityHandler extends botbuilder.TeamsActivityHandler {
|
|
3283
|
+
/**
|
|
3284
|
+
* Creates a new instance of the DefaultBotSsoExecutionActivityHandler.
|
|
3285
|
+
* @param ssoConfig configuration for SSO command bot
|
|
3286
|
+
*
|
|
3287
|
+
* @remarks
|
|
3288
|
+
* In the constructor, it uses BotSsoConfig parameter which from {@link ConversationBot} options to initialize {@link BotSsoExecutionDialog}.
|
|
3289
|
+
* It also need to register an event handler for the message event which trigger {@link BotSsoExecutionDialog} instance.
|
|
3290
|
+
*/
|
|
3291
|
+
constructor(ssoConfig) {
|
|
3292
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
3293
|
+
super();
|
|
3294
|
+
const memoryStorage = new botbuilder.MemoryStorage();
|
|
3295
|
+
const userState = (_b = (_a = ssoConfig.dialog) === null || _a === void 0 ? void 0 : _a.userState) !== null && _b !== void 0 ? _b : new botbuilder.UserState(memoryStorage);
|
|
3296
|
+
const conversationState = (_d = (_c = ssoConfig.dialog) === null || _c === void 0 ? void 0 : _c.conversationState) !== null && _d !== void 0 ? _d : new botbuilder.ConversationState(memoryStorage);
|
|
3297
|
+
const dedupStorage = (_f = (_e = ssoConfig.dialog) === null || _e === void 0 ? void 0 : _e.dedupStorage) !== null && _f !== void 0 ? _f : memoryStorage;
|
|
3298
|
+
const _l = ssoConfig.aad, { scopes } = _l, customConfig = tslib.__rest(_l, ["scopes"]);
|
|
3299
|
+
const settings = {
|
|
3300
|
+
scopes: scopes,
|
|
3301
|
+
timeout: (_h = (_g = ssoConfig.dialog) === null || _g === void 0 ? void 0 : _g.ssoPromptConfig) === null || _h === void 0 ? void 0 : _h.timeout,
|
|
3302
|
+
endOnInvalidMessage: (_k = (_j = ssoConfig.dialog) === null || _j === void 0 ? void 0 : _j.ssoPromptConfig) === null || _k === void 0 ? void 0 : _k.endOnInvalidMessage,
|
|
3303
|
+
};
|
|
3304
|
+
const teamsfx = new TeamsFx(exports.IdentityType.User, Object.assign({}, customConfig));
|
|
3305
|
+
this.ssoExecutionDialog = new BotSsoExecutionDialog(dedupStorage, settings, teamsfx);
|
|
3306
|
+
this.conversationState = conversationState;
|
|
3307
|
+
this.dialogState = conversationState.createProperty("DialogState");
|
|
3308
|
+
this.userState = userState;
|
|
3309
|
+
this.onMessage((context, next) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3310
|
+
yield this.ssoExecutionDialog.run(context, this.dialogState);
|
|
3311
|
+
yield next();
|
|
3312
|
+
}));
|
|
3313
|
+
}
|
|
3314
|
+
/**
|
|
3315
|
+
* Add TeamsFxBotSsoCommandHandler instance to SSO execution dialog
|
|
3316
|
+
* @param handler {@link BotSsoExecutionDialogHandler} callback function
|
|
3317
|
+
* @param triggerPatterns The trigger pattern
|
|
3318
|
+
*
|
|
3319
|
+
* @remarks
|
|
3320
|
+
* This function is used to add SSO command to {@link BotSsoExecutionDialog} instance.
|
|
3321
|
+
*/
|
|
3322
|
+
addCommand(handler, triggerPatterns) {
|
|
3323
|
+
this.ssoExecutionDialog.addCommand(handler, triggerPatterns);
|
|
3324
|
+
}
|
|
3325
|
+
/**
|
|
3326
|
+
* Called to initiate the event emission process.
|
|
3327
|
+
* @param context The context object for the current turn.
|
|
3328
|
+
*/
|
|
3329
|
+
run(context) {
|
|
3330
|
+
const _super = Object.create(null, {
|
|
3331
|
+
run: { get: () => super.run }
|
|
3332
|
+
});
|
|
3333
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3334
|
+
try {
|
|
3335
|
+
yield _super.run.call(this, context);
|
|
3336
|
+
}
|
|
3337
|
+
finally {
|
|
3338
|
+
yield this.conversationState.saveChanges(context, false);
|
|
3339
|
+
yield this.userState.saveChanges(context, false);
|
|
3340
|
+
}
|
|
3341
|
+
});
|
|
3342
|
+
}
|
|
3343
|
+
/**
|
|
3344
|
+
* Receives invoke activities with Activity name of 'signin/verifyState'.
|
|
3345
|
+
* @param context A context object for this turn.
|
|
3346
|
+
* @param query Signin state (part of signin action auth flow) verification invoke query.
|
|
3347
|
+
* @returns A promise that represents the work queued.
|
|
3348
|
+
*
|
|
3349
|
+
* @remarks
|
|
3350
|
+
* It should trigger {@link BotSsoExecutionDialog} instance to handle signin process
|
|
3351
|
+
*/
|
|
3352
|
+
handleTeamsSigninVerifyState(context, query) {
|
|
3353
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3354
|
+
yield this.ssoExecutionDialog.run(context, this.dialogState);
|
|
3355
|
+
});
|
|
3356
|
+
}
|
|
3357
|
+
/**
|
|
3358
|
+
* Receives invoke activities with Activity name of 'signin/tokenExchange'
|
|
3359
|
+
* @param context A context object for this turn.
|
|
3360
|
+
* @param query Signin state (part of signin action auth flow) verification invoke query
|
|
3361
|
+
* @returns A promise that represents the work queued.
|
|
3362
|
+
*
|
|
3363
|
+
* @remark
|
|
3364
|
+
* It should trigger {@link BotSsoExecutionDialog} instance to handle signin process
|
|
3365
|
+
*/
|
|
3366
|
+
handleTeamsSigninTokenExchange(context, query) {
|
|
3367
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3368
|
+
yield this.ssoExecutionDialog.run(context, this.dialogState);
|
|
3369
|
+
});
|
|
3370
|
+
}
|
|
3371
|
+
}
|
|
3372
|
+
|
|
2901
3373
|
// Copyright (c) Microsoft Corporation.
|
|
2902
3374
|
/**
|
|
2903
3375
|
* Provide utilities for bot conversation, including:
|
|
@@ -2960,20 +3432,30 @@ class ConversationBot {
|
|
|
2960
3432
|
* @param options - initialize options
|
|
2961
3433
|
*/
|
|
2962
3434
|
constructor(options) {
|
|
2963
|
-
var _a, _b, _c;
|
|
3435
|
+
var _a, _b, _c, _d;
|
|
2964
3436
|
if (options.adapter) {
|
|
2965
3437
|
this.adapter = options.adapter;
|
|
2966
3438
|
}
|
|
2967
3439
|
else {
|
|
2968
3440
|
this.adapter = this.createDefaultAdapter(options.adapterConfig);
|
|
2969
3441
|
}
|
|
2970
|
-
|
|
2971
|
-
|
|
3442
|
+
let ssoCommandActivityHandler;
|
|
3443
|
+
if (options === null || options === void 0 ? void 0 : options.ssoConfig) {
|
|
3444
|
+
if ((_a = options.ssoConfig.dialog) === null || _a === void 0 ? void 0 : _a.CustomBotSsoExecutionActivityHandler) {
|
|
3445
|
+
ssoCommandActivityHandler =
|
|
3446
|
+
new options.ssoConfig.dialog.CustomBotSsoExecutionActivityHandler(options.ssoConfig);
|
|
3447
|
+
}
|
|
3448
|
+
else {
|
|
3449
|
+
ssoCommandActivityHandler = new DefaultBotSsoExecutionActivityHandler(options.ssoConfig);
|
|
3450
|
+
}
|
|
3451
|
+
}
|
|
3452
|
+
if ((_b = options.command) === null || _b === void 0 ? void 0 : _b.enabled) {
|
|
3453
|
+
this.command = new CommandBot(this.adapter, options.command, ssoCommandActivityHandler, options.ssoConfig);
|
|
2972
3454
|
}
|
|
2973
|
-
if ((
|
|
3455
|
+
if ((_c = options.notification) === null || _c === void 0 ? void 0 : _c.enabled) {
|
|
2974
3456
|
this.notification = new NotificationBot(this.adapter, options.notification);
|
|
2975
3457
|
}
|
|
2976
|
-
if ((
|
|
3458
|
+
if ((_d = options.cardAction) === null || _d === void 0 ? void 0 : _d.enabled) {
|
|
2977
3459
|
this.cardAction = new CardActionBot(this.adapter, options.cardAction);
|
|
2978
3460
|
}
|
|
2979
3461
|
}
|
|
@@ -3168,11 +3650,13 @@ exports.ApiKeyProvider = ApiKeyProvider;
|
|
|
3168
3650
|
exports.AppCredential = AppCredential;
|
|
3169
3651
|
exports.BasicAuthProvider = BasicAuthProvider;
|
|
3170
3652
|
exports.BearerTokenAuthProvider = BearerTokenAuthProvider;
|
|
3653
|
+
exports.BotSsoExecutionDialog = BotSsoExecutionDialog;
|
|
3171
3654
|
exports.CardActionBot = CardActionBot;
|
|
3172
3655
|
exports.CertificateAuthProvider = CertificateAuthProvider;
|
|
3173
3656
|
exports.Channel = Channel;
|
|
3174
3657
|
exports.CommandBot = CommandBot;
|
|
3175
3658
|
exports.ConversationBot = ConversationBot;
|
|
3659
|
+
exports.DefaultBotSsoExecutionActivityHandler = DefaultBotSsoExecutionActivityHandler;
|
|
3176
3660
|
exports.ErrorWithCode = ErrorWithCode;
|
|
3177
3661
|
exports.InvokeResponseFactory = InvokeResponseFactory;
|
|
3178
3662
|
exports.Member = Member;
|