UNPKG

8.68 kBJavaScriptView Raw
1"use strict";
2/**
3 * @module botbuilder
4 */
5/**
6 * Copyright (c) Microsoft Corporation. All rights reserved.
7 * Licensed under the MIT License.
8 */
9var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
10 function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
11 return new (P || (P = Promise))(function (resolve, reject) {
12 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
13 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
14 function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
15 step((generator = generator.apply(thisArg, _arguments || [])).next());
16 });
17};
18Object.defineProperty(exports, "__esModule", { value: true });
19exports.BotFrameworkHttpClient = void 0;
20const axios_1 = require("axios");
21const botbuilder_core_1 = require("botbuilder-core");
22const botframework_connector_1 = require("botframework-connector");
23const botFrameworkAdapter_1 = require("./botFrameworkAdapter");
24/**
25 * HttpClient for calling skills from a Node.js BotBuilder V4 SDK bot.
26 */
27class BotFrameworkHttpClient {
28 /**
29 * Creates a new instance of the [BotFrameworkHttpClient](xref:botbuilder.BotFrameworkHttpClient) class
30 * @param credentialProvider An instance of [ICredentialProvider](xref:botframework-connector.ICredentialProvider).
31 * @param channelService Optional. The channel service.
32 */
33 constructor(credentialProvider, channelService) {
34 if (!credentialProvider) {
35 throw new Error('BotFrameworkHttpClient(): missing credentialProvider');
36 }
37 this.credentialProvider = credentialProvider;
38 this.channelService = channelService || process.env[botframework_connector_1.AuthenticationConstants.ChannelService];
39 }
40 /**
41 * Forwards an activity to another bot.
42 * @remarks
43 *
44 * @template T The type of body in the InvokeResponse.
45 * @param fromBotId The MicrosoftAppId of the bot sending the activity.
46 * @param toBotId The MicrosoftAppId of the bot receiving the activity.
47 * @param toUrl The URL of the bot receiving the activity.
48 * @param serviceUrl The callback Url for the skill host.
49 * @param conversationId A conversation ID to use for the conversation with the skill.
50 * @param activity Activity to forward.
51 */
52 postActivity(fromBotId, toBotId, toUrl, serviceUrl, conversationId, activity) {
53 return __awaiter(this, void 0, void 0, function* () {
54 const appCredentials = yield this.getAppCredentials(fromBotId, toBotId);
55 if (!appCredentials) {
56 throw new Error('BotFrameworkHttpClient.postActivity(): Unable to get appCredentials to connect to the skill');
57 }
58 if (!activity) {
59 throw new Error('BotFrameworkHttpClient.postActivity(): missing activity');
60 }
61 if (activity.conversation === undefined) {
62 throw new Error('BotFrameworkHttpClient.postActivity(): Activity must have a ConversationReference');
63 }
64 // Get token for the skill call
65 const token = appCredentials.appId ? yield appCredentials.getToken() : null;
66 // Capture current activity settings before changing them.
67 // TODO: DO we need to set the activity ID? (events that are created manually don't have it).
68 const originalConversationId = activity.conversation.id;
69 const originalServiceUrl = activity.serviceUrl;
70 const originalRelatesTo = activity.relatesTo;
71 const originalRecipient = activity.recipient;
72 try {
73 activity.relatesTo = {
74 serviceUrl: activity.serviceUrl,
75 activityId: activity.id,
76 channelId: activity.channelId,
77 conversation: {
78 id: activity.conversation.id,
79 name: activity.conversation.name,
80 conversationType: activity.conversation.conversationType,
81 aadObjectId: activity.conversation.aadObjectId,
82 isGroup: activity.conversation.isGroup,
83 properties: activity.conversation.properties,
84 role: activity.conversation.role,
85 tenantId: activity.conversation.tenantId,
86 },
87 bot: null,
88 };
89 activity.conversation.id = conversationId;
90 activity.serviceUrl = serviceUrl;
91 // Fixes: https://github.com/microsoft/botframework-sdk/issues/5785
92 if (!activity.recipient) {
93 activity.recipient = {};
94 }
95 activity.recipient.role = botbuilder_core_1.RoleTypes.Skill;
96 const config = {
97 headers: {
98 Accept: 'application/json',
99 [botframework_connector_1.ConversationConstants.ConversationIdHttpHeaderName]: conversationId,
100 'Content-Type': 'application/json',
101 'User-Agent': botFrameworkAdapter_1.USER_AGENT,
102 },
103 validateStatus: () => true,
104 };
105 if (token) {
106 config.headers.Authorization = `Bearer ${token}`;
107 }
108 const response = yield axios_1.default.post(toUrl, activity, config);
109 return { status: response.status, body: response.data };
110 }
111 finally {
112 // Restore activity properties.
113 activity.conversation.id = originalConversationId;
114 activity.serviceUrl = originalServiceUrl;
115 activity.relatesTo = originalRelatesTo;
116 activity.recipient = originalRecipient;
117 }
118 });
119 }
120 /**
121 * Logic to build an [AppCredentials](xref:botframework-connector.AppCredentials) to be used to acquire tokens for this `HttpClient`.
122 * @param appId The application id.
123 * @param oAuthScope Optional. The OAuth scope.
124 *
125 * @returns The app credentials to be used to acquire tokens.
126 */
127 buildCredentials(appId, oAuthScope) {
128 return __awaiter(this, void 0, void 0, function* () {
129 const appPassword = yield this.credentialProvider.getAppPassword(appId);
130 if (botframework_connector_1.JwtTokenValidation.isGovernment(this.channelService)) {
131 const appCredentials = new botframework_connector_1.MicrosoftAppCredentials(appId, appPassword, undefined, oAuthScope);
132 appCredentials.oAuthEndpoint = botframework_connector_1.GovernmentConstants.ToChannelFromBotLoginUrl;
133 return appCredentials;
134 }
135 else {
136 return new botframework_connector_1.MicrosoftAppCredentials(appId, appPassword, undefined, oAuthScope);
137 }
138 });
139 }
140 /**
141 * Gets the application credentials. App Credentials are cached so as to ensure we are not refreshing
142 * token every time.
143 * @private
144 * @param appId The application identifier (AAD Id for the bot).
145 * @param oAuthScope The scope for the token, skills will use the Skill App Id.
146 */
147 getAppCredentials(appId, oAuthScope) {
148 return __awaiter(this, void 0, void 0, function* () {
149 if (!appId) {
150 return new botframework_connector_1.MicrosoftAppCredentials('', '');
151 }
152 const cacheKey = `${appId}${oAuthScope}`;
153 let appCredentials = BotFrameworkHttpClient.appCredentialMapCache.get(cacheKey);
154 if (appCredentials) {
155 return appCredentials;
156 }
157 // Credentials not found in cache, build them
158 appCredentials = yield this.buildCredentials(appId, oAuthScope);
159 // Cache the credentials for later use
160 BotFrameworkHttpClient.appCredentialMapCache.set(cacheKey, appCredentials);
161 return appCredentials;
162 });
163 }
164}
165exports.BotFrameworkHttpClient = BotFrameworkHttpClient;
166/**
167 * Cache for appCredentials to speed up token acquisition (a token is not requested unless is expired)
168 * AppCredentials are cached using appId + scope (this last parameter is only used if the app credentials are used to call a skill)
169 */
170BotFrameworkHttpClient.appCredentialMapCache = new Map();
171//# sourceMappingURL=botFrameworkHttpClient.js.map
\No newline at end of file