@microsoft/teamsfx 0.3.3-alpha.3dc53ce2.0 → 0.3.3-alpha.7e7c7c23.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.
Files changed (68) hide show
  1. package/README.md +2 -2
  2. package/dist/index.esm2017.js +1413 -0
  3. package/dist/index.esm2017.js.map +1 -0
  4. package/dist/{index.js → index.esm2017.mjs} +1467 -1506
  5. package/dist/index.esm2017.mjs.map +1 -0
  6. package/dist/index.esm5.js +1575 -0
  7. package/dist/index.esm5.js.map +1 -0
  8. package/dist/index.node.cjs.js +1653 -0
  9. package/dist/index.node.cjs.js.map +1 -0
  10. package/package.json +58 -78
  11. package/types/teamsfx.d.ts +0 -2
  12. package/dist/index.js.map +0 -1
  13. package/dist/teamsfx.js +0 -30
  14. package/dist/teamsfx.js.map +0 -1
  15. package/dist-esm/src/bot/teamsBotSsoPrompt.browser.js +0 -118
  16. package/dist-esm/src/bot/teamsBotSsoPrompt.browser.js.map +0 -1
  17. package/dist-esm/src/bot/teamsBotSsoPrompt.js +0 -349
  18. package/dist-esm/src/bot/teamsBotSsoPrompt.js.map +0 -1
  19. package/dist-esm/src/bot/teamsBotSsoPromptTokenResponse.js +0 -2
  20. package/dist-esm/src/bot/teamsBotSsoPromptTokenResponse.js.map +0 -1
  21. package/dist-esm/src/core/cache.browser.js +0 -22
  22. package/dist-esm/src/core/cache.browser.js.map +0 -1
  23. package/dist-esm/src/core/cache.js +0 -28
  24. package/dist-esm/src/core/cache.js.map +0 -1
  25. package/dist-esm/src/core/configurationProvider.js +0 -124
  26. package/dist-esm/src/core/configurationProvider.js.map +0 -1
  27. package/dist-esm/src/core/defaultTediousConnectionConfiguration.browser.js +0 -28
  28. package/dist-esm/src/core/defaultTediousConnectionConfiguration.browser.js.map +0 -1
  29. package/dist-esm/src/core/defaultTediousConnectionConfiguration.js +0 -182
  30. package/dist-esm/src/core/defaultTediousConnectionConfiguration.js.map +0 -1
  31. package/dist-esm/src/core/errors.js +0 -97
  32. package/dist-esm/src/core/errors.js.map +0 -1
  33. package/dist-esm/src/core/msGraphAuthProvider.js +0 -68
  34. package/dist-esm/src/core/msGraphAuthProvider.js.map +0 -1
  35. package/dist-esm/src/core/msGraphClientProvider.js +0 -65
  36. package/dist-esm/src/core/msGraphClientProvider.js.map +0 -1
  37. package/dist-esm/src/credential/m365TenantCredential.browser.js +0 -38
  38. package/dist-esm/src/credential/m365TenantCredential.browser.js.map +0 -1
  39. package/dist-esm/src/credential/m365TenantCredential.js +0 -126
  40. package/dist-esm/src/credential/m365TenantCredential.js.map +0 -1
  41. package/dist-esm/src/credential/onBehalfOfUserCredential.browser.js +0 -46
  42. package/dist-esm/src/credential/onBehalfOfUserCredential.browser.js.map +0 -1
  43. package/dist-esm/src/credential/onBehalfOfUserCredential.js +0 -178
  44. package/dist-esm/src/credential/onBehalfOfUserCredential.js.map +0 -1
  45. package/dist-esm/src/credential/teamsUserCredential.browser.js +0 -462
  46. package/dist-esm/src/credential/teamsUserCredential.browser.js.map +0 -1
  47. package/dist-esm/src/credential/teamsUserCredential.js +0 -56
  48. package/dist-esm/src/credential/teamsUserCredential.js.map +0 -1
  49. package/dist-esm/src/index.js +0 -14
  50. package/dist-esm/src/index.js.map +0 -1
  51. package/dist-esm/src/models/accessTokenResult.js +0 -4
  52. package/dist-esm/src/models/accessTokenResult.js.map +0 -1
  53. package/dist-esm/src/models/authCodeResult.js +0 -4
  54. package/dist-esm/src/models/authCodeResult.js.map +0 -1
  55. package/dist-esm/src/models/configuration.js +0 -20
  56. package/dist-esm/src/models/configuration.js.map +0 -1
  57. package/dist-esm/src/models/grantType.js +0 -11
  58. package/dist-esm/src/models/grantType.js.map +0 -1
  59. package/dist-esm/src/models/ssoTokenInfo.js +0 -4
  60. package/dist-esm/src/models/ssoTokenInfo.js.map +0 -1
  61. package/dist-esm/src/models/userinfo.js +0 -4
  62. package/dist-esm/src/models/userinfo.js.map +0 -1
  63. package/dist-esm/src/util/logger.js +0 -134
  64. package/dist-esm/src/util/logger.js.map +0 -1
  65. package/dist-esm/src/util/utils.js +0 -130
  66. package/dist-esm/src/util/utils.js.map +0 -1
  67. package/dist-esm/src/util/utils.node.js +0 -23
  68. package/dist-esm/src/util/utils.node.js.map +0 -1
@@ -0,0 +1,1413 @@
1
+ import jwt_decode from 'jwt-decode';
2
+ import * as microsoftTeams from '@microsoft/teams-js';
3
+ import axios from 'axios';
4
+ import { Client } from '@microsoft/microsoft-graph-client';
5
+ import { ManagedIdentityCredential } from '@azure/identity';
6
+
7
+ // Copyright (c) Microsoft Corporation.
8
+ // Licensed under the MIT license.
9
+ /**
10
+ * Error code to trace the error types.
11
+ * @beta
12
+ */
13
+ var ErrorCode;
14
+ (function (ErrorCode) {
15
+ /**
16
+ * Invalid parameter error.
17
+ */
18
+ ErrorCode["InvalidParameter"] = "InvalidParameter";
19
+ /**
20
+ * Invalid configuration error.
21
+ */
22
+ ErrorCode["InvalidConfiguration"] = "InvalidConfiguration";
23
+ /**
24
+ * Invalid certificate error.
25
+ */
26
+ ErrorCode["InvalidCertificate"] = "InvalidCertificate";
27
+ /**
28
+ * Internal error.
29
+ */
30
+ ErrorCode["InternalError"] = "InternalError";
31
+ /**
32
+ * Channel is not supported error.
33
+ */
34
+ ErrorCode["ChannelNotSupported"] = "ChannelNotSupported";
35
+ /**
36
+ * Runtime is not supported error.
37
+ */
38
+ ErrorCode["RuntimeNotSupported"] = "RuntimeNotSupported";
39
+ /**
40
+ * User failed to finish the AAD consent flow failed.
41
+ */
42
+ ErrorCode["ConsentFailed"] = "ConsentFailed";
43
+ /**
44
+ * The user or administrator has not consented to use the application error.
45
+ */
46
+ ErrorCode["UiRequiredError"] = "UiRequiredError";
47
+ /**
48
+ * Token is not within its valid time range error.
49
+ */
50
+ ErrorCode["TokenExpiredError"] = "TokenExpiredError";
51
+ /**
52
+ * Call service (AAD or simple authentication server) failed.
53
+ */
54
+ ErrorCode["ServiceError"] = "ServiceError";
55
+ /**
56
+ * Operation failed.
57
+ */
58
+ ErrorCode["FailedOperation"] = "FailedOperation";
59
+ })(ErrorCode || (ErrorCode = {}));
60
+ /**
61
+ * @internal
62
+ */
63
+ class ErrorMessage {
64
+ }
65
+ // InvalidConfiguration Error
66
+ ErrorMessage.InvalidConfiguration = "{0} in configuration is invalid: {1}.";
67
+ ErrorMessage.ConfigurationNotExists = "Configuration does not exist. {0}";
68
+ ErrorMessage.ResourceConfigurationNotExists = "{0} resource configuration does not exist.";
69
+ ErrorMessage.MissingResourceConfiguration = "Missing resource configuration with type: {0}, name: {1}.";
70
+ ErrorMessage.AuthenticationConfigurationNotExists = "Authentication configuration does not exist.";
71
+ // RuntimeNotSupported Error
72
+ ErrorMessage.BrowserRuntimeNotSupported = "{0} is not supported in browser.";
73
+ ErrorMessage.NodejsRuntimeNotSupported = "{0} is not supported in Node.";
74
+ // Internal Error
75
+ ErrorMessage.FailToAcquireTokenOnBehalfOfUser = "Failed to acquire access token on behalf of user: {0}";
76
+ // ChannelNotSupported Error
77
+ ErrorMessage.OnlyMSTeamsChannelSupported = "{0} is only supported in MS Teams Channel";
78
+ /**
79
+ * Error class with code and message thrown by the SDK.
80
+ *
81
+ * @beta
82
+ */
83
+ class ErrorWithCode extends Error {
84
+ /**
85
+ * Constructor of ErrorWithCode.
86
+ *
87
+ * @param {string} message - error message.
88
+ * @param {ErrorCode} code - error code.
89
+ *
90
+ * @beta
91
+ */
92
+ constructor(message, code) {
93
+ if (!code) {
94
+ super(message);
95
+ return this;
96
+ }
97
+ super(message);
98
+ Object.setPrototypeOf(this, ErrorWithCode.prototype);
99
+ this.name = `${new.target.name}.${code}`;
100
+ this.code = code;
101
+ }
102
+ }
103
+
104
+ // Copyright (c) Microsoft Corporation.
105
+ // Licensed under the MIT license.
106
+ /**
107
+ * Available resource type.
108
+ * @beta
109
+ */
110
+ var ResourceType;
111
+ (function (ResourceType) {
112
+ /**
113
+ * SQL database.
114
+ *
115
+ */
116
+ ResourceType[ResourceType["SQL"] = 0] = "SQL";
117
+ /**
118
+ * Rest API.
119
+ *
120
+ */
121
+ ResourceType[ResourceType["API"] = 1] = "API";
122
+ })(ResourceType || (ResourceType = {}));
123
+
124
+ // Copyright (c) Microsoft Corporation.
125
+ // Licensed under the MIT license.
126
+ /**
127
+ * Log level.
128
+ *
129
+ * @beta
130
+ */
131
+ var LogLevel;
132
+ (function (LogLevel) {
133
+ /**
134
+ * Show verbose, information, warning and error message.
135
+ */
136
+ LogLevel[LogLevel["Verbose"] = 0] = "Verbose";
137
+ /**
138
+ * Show information, warning and error message.
139
+ */
140
+ LogLevel[LogLevel["Info"] = 1] = "Info";
141
+ /**
142
+ * Show warning and error message.
143
+ */
144
+ LogLevel[LogLevel["Warn"] = 2] = "Warn";
145
+ /**
146
+ * Show error message.
147
+ */
148
+ LogLevel[LogLevel["Error"] = 3] = "Error";
149
+ })(LogLevel || (LogLevel = {}));
150
+ /**
151
+ * Update log level helper.
152
+ *
153
+ * @param { LogLevel } level - log level in configuration
154
+ *
155
+ * @beta
156
+ */
157
+ function setLogLevel(level) {
158
+ internalLogger.level = level;
159
+ }
160
+ /**
161
+ * Get log level.
162
+ *
163
+ * @returns Log level
164
+ *
165
+ * @beta
166
+ */
167
+ function getLogLevel() {
168
+ return internalLogger.level;
169
+ }
170
+ class InternalLogger {
171
+ constructor() {
172
+ this.level = undefined;
173
+ this.defaultLogger = {
174
+ verbose: console.debug,
175
+ info: console.info,
176
+ warn: console.warn,
177
+ error: console.error,
178
+ };
179
+ }
180
+ error(message) {
181
+ this.log(LogLevel.Error, (x) => x.error, message);
182
+ }
183
+ warn(message) {
184
+ this.log(LogLevel.Warn, (x) => x.warn, message);
185
+ }
186
+ info(message) {
187
+ this.log(LogLevel.Info, (x) => x.info, message);
188
+ }
189
+ verbose(message) {
190
+ this.log(LogLevel.Verbose, (x) => x.verbose, message);
191
+ }
192
+ log(logLevel, logFunction, message) {
193
+ if (message.trim() === "") {
194
+ return;
195
+ }
196
+ const timestamp = new Date().toUTCString();
197
+ const logHeader = `[${timestamp}] : @microsoft/teamsfx : ${LogLevel[logLevel]} - `;
198
+ const logMessage = `${logHeader}${message}`;
199
+ if (this.level !== undefined && this.level <= logLevel) {
200
+ if (this.customLogger) {
201
+ logFunction(this.customLogger)(logMessage);
202
+ }
203
+ else if (this.customLogFunction) {
204
+ this.customLogFunction(logLevel, logMessage);
205
+ }
206
+ else {
207
+ logFunction(this.defaultLogger)(logMessage);
208
+ }
209
+ }
210
+ }
211
+ }
212
+ /**
213
+ * Logger instance used internally
214
+ *
215
+ * @internal
216
+ */
217
+ const internalLogger = new InternalLogger();
218
+ /**
219
+ * Set custom logger. Use the output functions if it's set. Priority is higher than setLogFunction.
220
+ *
221
+ * @param {Logger} logger - custom logger. If it's undefined, custom logger will be cleared.
222
+ *
223
+ * @example
224
+ * ```typescript
225
+ * setLogger({
226
+ * verbose: console.debug,
227
+ * info: console.info,
228
+ * warn: console.warn,
229
+ * error: console.error,
230
+ * });
231
+ * ```
232
+ *
233
+ * @beta
234
+ */
235
+ function setLogger(logger) {
236
+ internalLogger.customLogger = logger;
237
+ }
238
+ /**
239
+ * Set custom log function. Use the function if it's set. Priority is lower than setLogger.
240
+ *
241
+ * @param {LogFunction} logFunction - custom log function. If it's undefined, custom log function will be cleared.
242
+ *
243
+ * @example
244
+ * ```typescript
245
+ * setLogFunction((level: LogLevel, message: string) => {
246
+ * if (level === LogLevel.Error) {
247
+ * console.log(message);
248
+ * }
249
+ * });
250
+ * ```
251
+ *
252
+ * @beta
253
+ */
254
+ function setLogFunction(logFunction) {
255
+ internalLogger.customLogFunction = logFunction;
256
+ }
257
+
258
+ // Copyright (c) Microsoft Corporation.
259
+ /**
260
+ * Parse jwt token payload
261
+ *
262
+ * @param token
263
+ *
264
+ * @returns Payload object
265
+ *
266
+ * @internal
267
+ */
268
+ function parseJwt(token) {
269
+ try {
270
+ const tokenObj = jwt_decode(token);
271
+ if (!tokenObj || !tokenObj.exp) {
272
+ throw new ErrorWithCode("Decoded token is null or exp claim does not exists.", ErrorCode.InternalError);
273
+ }
274
+ return tokenObj;
275
+ }
276
+ catch (err) {
277
+ const errorMsg = "Parse jwt token failed in node env with error: " + err.message;
278
+ internalLogger.error(errorMsg);
279
+ throw new ErrorWithCode(errorMsg, ErrorCode.InternalError);
280
+ }
281
+ }
282
+ /**
283
+ * @internal
284
+ */
285
+ function getUserInfoFromSsoToken(ssoToken) {
286
+ if (!ssoToken) {
287
+ const errorMsg = "SSO token is undefined.";
288
+ internalLogger.error(errorMsg);
289
+ throw new ErrorWithCode(errorMsg, ErrorCode.InvalidParameter);
290
+ }
291
+ const tokenObject = parseJwt(ssoToken);
292
+ const userInfo = {
293
+ displayName: tokenObject.name,
294
+ objectId: tokenObject.oid,
295
+ preferredUserName: "",
296
+ };
297
+ if (tokenObject.ver === "2.0") {
298
+ userInfo.preferredUserName = tokenObject.preferred_username;
299
+ }
300
+ else if (tokenObject.ver === "1.0") {
301
+ userInfo.preferredUserName = tokenObject.upn;
302
+ }
303
+ return userInfo;
304
+ }
305
+ /**
306
+ * Format string template with replacements
307
+ *
308
+ * ```typescript
309
+ * const template = "{0} and {1} are fruit. {0} is my favorite one."
310
+ * const formattedStr = formatString(template, "apple", "pear"); // formattedStr: "apple and pear are fruit. apple is my favorite one."
311
+ * ```
312
+ *
313
+ * @param str string template
314
+ * @param replacements replacement string array
315
+ * @returns Formatted string
316
+ *
317
+ * @internal
318
+ */
319
+ function formatString(str, ...replacements) {
320
+ const args = replacements;
321
+ return str.replace(/{(\d+)}/g, function (match, number) {
322
+ return typeof args[number] != "undefined" ? args[number] : match;
323
+ });
324
+ }
325
+ /**
326
+ * @internal
327
+ */
328
+ function validateScopesType(value) {
329
+ // string
330
+ if (typeof value === "string" || value instanceof String) {
331
+ return;
332
+ }
333
+ // empty array
334
+ if (Array.isArray(value) && value.length === 0) {
335
+ return;
336
+ }
337
+ // string array
338
+ if (Array.isArray(value) && value.length > 0 && value.every((item) => typeof item === "string")) {
339
+ return;
340
+ }
341
+ const errorMsg = "The type of scopes is not valid, it must be string or string array";
342
+ internalLogger.error(errorMsg);
343
+ throw new ErrorWithCode(errorMsg, ErrorCode.InvalidParameter);
344
+ }
345
+ /**
346
+ * @internal
347
+ */
348
+ const isNode = typeof process !== "undefined" &&
349
+ !!process.version &&
350
+ !!process.versions &&
351
+ !!process.versions.node;
352
+
353
+ // Copyright (c) Microsoft Corporation.
354
+ /**
355
+ * Global configuration instance
356
+ *
357
+ */
358
+ let config;
359
+ /**
360
+ * Initialize configuration from environment variables or configuration object and set the global instance
361
+ *
362
+ * @param {Configuration} configuration - Optional configuration that overrides the default configuration values. The override depth is 1.
363
+ *
364
+ * @throws {@link ErrorCode|InvalidParameter} when configuration is not passed in browser environment
365
+ *
366
+ * @beta
367
+ */
368
+ function loadConfiguration(configuration) {
369
+ internalLogger.info("load configuration");
370
+ // browser environment
371
+ if (!isNode) {
372
+ if (!configuration) {
373
+ const errorMsg = "You are running the code in browser. Configuration must be passed in.";
374
+ internalLogger.error(errorMsg);
375
+ throw new ErrorWithCode(errorMsg, ErrorCode.InvalidParameter);
376
+ }
377
+ config = configuration;
378
+ return;
379
+ }
380
+ // node environment
381
+ let newAuthentication;
382
+ let newResources = [];
383
+ const defaultResourceName = "default";
384
+ if (configuration === null || configuration === void 0 ? void 0 : configuration.authentication) {
385
+ newAuthentication = configuration.authentication;
386
+ }
387
+ else {
388
+ newAuthentication = {
389
+ authorityHost: process.env.M365_AUTHORITY_HOST,
390
+ tenantId: process.env.M365_TENANT_ID,
391
+ clientId: process.env.M365_CLIENT_ID,
392
+ clientSecret: process.env.M365_CLIENT_SECRET,
393
+ simpleAuthEndpoint: process.env.SIMPLE_AUTH_ENDPOINT,
394
+ initiateLoginEndpoint: process.env.INITIATE_LOGIN_ENDPOINT,
395
+ applicationIdUri: process.env.M365_APPLICATION_ID_URI,
396
+ };
397
+ }
398
+ if (configuration === null || configuration === void 0 ? void 0 : configuration.resources) {
399
+ newResources = configuration.resources;
400
+ }
401
+ else {
402
+ newResources = [
403
+ {
404
+ // SQL resource
405
+ type: ResourceType.SQL,
406
+ name: defaultResourceName,
407
+ properties: {
408
+ sqlServerEndpoint: process.env.SQL_ENDPOINT,
409
+ sqlUsername: process.env.SQL_USER_NAME,
410
+ sqlPassword: process.env.SQL_PASSWORD,
411
+ sqlDatabaseName: process.env.SQL_DATABASE_NAME,
412
+ sqlIdentityId: process.env.IDENTITY_ID,
413
+ },
414
+ },
415
+ {
416
+ // API resource
417
+ type: ResourceType.API,
418
+ name: defaultResourceName,
419
+ properties: {
420
+ endpoint: process.env.API_ENDPOINT,
421
+ },
422
+ },
423
+ ];
424
+ }
425
+ config = {
426
+ authentication: newAuthentication,
427
+ resources: newResources,
428
+ };
429
+ }
430
+ /**
431
+ * Get configuration for a specific resource.
432
+ * @param {ResourceType} resourceType - The type of resource
433
+ * @param {string} resourceName - The name of resource, default value is "default".
434
+ *
435
+ * @returns Resource configuration for target resource from global configuration instance.
436
+ *
437
+ * @throws {@link ErrorCode|InvalidConfiguration} when resource configuration with the specific type and name is not found
438
+ *
439
+ * @beta
440
+ */
441
+ function getResourceConfiguration(resourceType, resourceName = "default") {
442
+ var _a;
443
+ internalLogger.info(`Get resource configuration of ${ResourceType[resourceType]} from ${resourceName}`);
444
+ const result = (_a = config.resources) === null || _a === void 0 ? void 0 : _a.find((item) => item.type === resourceType && item.name === resourceName);
445
+ if (result) {
446
+ return result.properties;
447
+ }
448
+ const errorMsg = formatString(ErrorMessage.MissingResourceConfiguration, ResourceType[resourceType], resourceName);
449
+ internalLogger.error(errorMsg);
450
+ throw new ErrorWithCode(errorMsg, ErrorCode.InvalidConfiguration);
451
+ }
452
+ /**
453
+ * Get configuration for authentication.
454
+ *
455
+ * @returns Authentication configuration from global configuration instance, the value may be undefined if no authentication config exists in current environment.
456
+ *
457
+ * @throws {@link ErrorCode|InvalidConfiguration} when global configuration does not exist
458
+ *
459
+ * @beta
460
+ */
461
+ function getAuthenticationConfiguration() {
462
+ internalLogger.info("Get authentication configuration");
463
+ if (config) {
464
+ return config.authentication;
465
+ }
466
+ const errorMsg = "Please call loadConfiguration() first before calling getAuthenticationConfiguration().";
467
+ internalLogger.error(errorMsg);
468
+ throw new ErrorWithCode(formatString(ErrorMessage.ConfigurationNotExists, errorMsg), ErrorCode.InvalidConfiguration);
469
+ }
470
+
471
+ // Copyright (c) Microsoft Corporation.
472
+ /**
473
+ * Represent Microsoft 365 tenant identity, and it is usually used when user is not involved.
474
+ *
475
+ * @remarks
476
+ * Only works in in server side.
477
+ *
478
+ * @beta
479
+ */
480
+ class M365TenantCredential {
481
+ /**
482
+ * Constructor of M365TenantCredential.
483
+ *
484
+ * @remarks
485
+ * Only works in in server side.
486
+ * @beta
487
+ */
488
+ constructor() {
489
+ throw new ErrorWithCode(formatString(ErrorMessage.BrowserRuntimeNotSupported, "M365TenantCredential"), ErrorCode.RuntimeNotSupported);
490
+ }
491
+ /**
492
+ * Get access token for credential.
493
+ *
494
+ * @remarks
495
+ * Only works in in server side.
496
+ * @beta
497
+ */
498
+ async getToken(scopes, options) {
499
+ throw new ErrorWithCode(formatString(ErrorMessage.BrowserRuntimeNotSupported, "M365TenantCredential"), ErrorCode.RuntimeNotSupported);
500
+ }
501
+ }
502
+
503
+ // Copyright (c) Microsoft Corporation.
504
+ /**
505
+ * Represent on-behalf-of flow to get user identity, and it is designed to be used in Azure Function or Bot scenarios.
506
+ *
507
+ * @remarks
508
+ * Can only be used in server side.
509
+ *
510
+ * @beta
511
+ */
512
+ class OnBehalfOfUserCredential {
513
+ /**
514
+ * Constructor of OnBehalfOfUserCredential
515
+ *
516
+ * @remarks
517
+ * Can Only works in in server side.
518
+ * @beta
519
+ */
520
+ constructor(ssoToken) {
521
+ throw new ErrorWithCode(formatString(ErrorMessage.BrowserRuntimeNotSupported, "OnBehalfOfUserCredential"), ErrorCode.RuntimeNotSupported);
522
+ }
523
+ /**
524
+ * Get access token from credential.
525
+ * @remarks
526
+ * Can only be used in server side.
527
+ * @beta
528
+ */
529
+ async getToken(scopes, options) {
530
+ throw new ErrorWithCode(formatString(ErrorMessage.BrowserRuntimeNotSupported, "OnBehalfOfUserCredential"), ErrorCode.RuntimeNotSupported);
531
+ }
532
+ /**
533
+ * Get basic user info from SSO token.
534
+ * @remarks
535
+ * Can only be used in server side.
536
+ * @beta
537
+ */
538
+ getUserInfo() {
539
+ throw new ErrorWithCode(formatString(ErrorMessage.BrowserRuntimeNotSupported, "OnBehalfOfUserCredential"), ErrorCode.RuntimeNotSupported);
540
+ }
541
+ }
542
+
543
+ // Copyright (c) Microsoft Corporation.
544
+ // Licensed under the MIT license.
545
+ /**
546
+ * Configuration used in initialization.
547
+ * @internal
548
+ */
549
+ class Cache {
550
+ static get(key) {
551
+ return sessionStorage.getItem(key);
552
+ }
553
+ static set(key, value) {
554
+ sessionStorage.setItem(key, value);
555
+ }
556
+ static remove(key) {
557
+ sessionStorage.removeItem(key);
558
+ }
559
+ }
560
+
561
+ // Copyright (c) Microsoft Corporation.
562
+ // Licensed under the MIT license.
563
+ /**
564
+ * @internal
565
+ */
566
+ var GrantType;
567
+ (function (GrantType) {
568
+ GrantType["authCode"] = "authorization_code";
569
+ GrantType["ssoToken"] = "sso_token";
570
+ })(GrantType || (GrantType = {}));
571
+
572
+ // Copyright (c) Microsoft Corporation.
573
+ const accessTokenCacheKeyPrefix = "accessToken";
574
+ const separator = "-";
575
+ const tokenRefreshTimeSpanInMillisecond = 5 * 60 * 1000;
576
+ const initializeTeamsSdkTimeoutInMillisecond = 5000;
577
+ const loginPageWidth = 600;
578
+ const loginPageHeight = 535;
579
+ const maxRetryCount = 3;
580
+ const retryTimeSpanInMillisecond = 3000;
581
+ /**
582
+ * Represent Teams current user's identity, and it is used within Teams tab application.
583
+ *
584
+ * @remarks
585
+ * Can only be used within Teams.
586
+ *
587
+ * @beta
588
+ */
589
+ class TeamsUserCredential {
590
+ /**
591
+ * Constructor of TeamsUserCredential.
592
+ * Developer need to call loadConfiguration(config) before using this class.
593
+ *
594
+ * @example
595
+ * ```typescript
596
+ * const config = {
597
+ * authentication: {
598
+ * runtimeConnectorEndpoint: "https://xxx.xxx.com",
599
+ * initiateLoginEndpoint: "https://localhost:3000/auth-start.html",
600
+ * clientId: "xxx"
601
+ * }
602
+ * }
603
+ loadConfiguration(config); // No default config from environment variables, developers must provide the config object.
604
+ const credential = new TeamsUserCredential(["https://graph.microsoft.com/User.Read"]);
605
+ * ```
606
+ *
607
+ * @throws {@link ErrorCode|InvalidConfiguration} when client id, initiate login endpoint or simple auth endpoint is not found in config.
608
+ * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
609
+ *
610
+ * @beta
611
+ */
612
+ constructor() {
613
+ internalLogger.info("Create teams user credential");
614
+ this.config = this.loadAndValidateConfig();
615
+ this.ssoToken = null;
616
+ }
617
+ /**
618
+ * Popup login page to get user's access token with specific scopes.
619
+ *
620
+ * @remarks
621
+ * Only works in Teams client APP. User will be redirected to the authorization page to login and consent.
622
+ *
623
+ * @example
624
+ * ```typescript
625
+ * await credential.login(["https://graph.microsoft.com/User.Read"]); // single scope using string array
626
+ * await credential.login("https://graph.microsoft.com/User.Read"); // single scopes using string
627
+ * await credential.login(["https://graph.microsoft.com/User.Read", "Calendars.Read"]); // multiple scopes using string array
628
+ * await credential.login("https://graph.microsoft.com/User.Read Calendars.Read"); // multiple scopes using string
629
+ * ```
630
+ * @param scopes - The list of scopes for which the token will have access, before that, we will request user to consent.
631
+ *
632
+ * @throws {@link ErrorCode|InternalError} when failed to login with unknown error.
633
+ * @throws {@link ErrorCode|ServiceError} when simple auth server failed to exchange access token.
634
+ * @throws {@link ErrorCode|ConsentFailed} when user canceled or failed to consent.
635
+ * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
636
+ * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
637
+ *
638
+ * @beta
639
+ */
640
+ async login(scopes) {
641
+ validateScopesType(scopes);
642
+ const scopesStr = typeof scopes === "string" ? scopes : scopes.join(" ");
643
+ internalLogger.info(`Popup login page to get user's access token with scopes: ${scopesStr}`);
644
+ return new Promise((resolve, reject) => {
645
+ microsoftTeams.initialize(() => {
646
+ microsoftTeams.authentication.authenticate({
647
+ url: `${this.config.initiateLoginEndpoint}?clientId=${this.config.clientId}&scope=${encodeURI(scopesStr)}`,
648
+ width: loginPageWidth,
649
+ height: loginPageHeight,
650
+ successCallback: async (result) => {
651
+ if (!result) {
652
+ const errorMsg = "Get empty authentication result from Teams";
653
+ internalLogger.error(errorMsg);
654
+ reject(new ErrorWithCode(errorMsg, ErrorCode.InternalError));
655
+ return;
656
+ }
657
+ const authCodeResult = JSON.parse(result);
658
+ try {
659
+ await this.exchangeAccessTokenFromSimpleAuthServer(scopesStr, authCodeResult);
660
+ resolve();
661
+ }
662
+ catch (err) {
663
+ reject(this.generateAuthServerError(err));
664
+ }
665
+ },
666
+ failureCallback: (reason) => {
667
+ const errorMsg = `Consent failed for the scope ${scopesStr} with error: ${reason}`;
668
+ internalLogger.error(errorMsg);
669
+ reject(new ErrorWithCode(errorMsg, ErrorCode.ConsentFailed));
670
+ },
671
+ });
672
+ });
673
+ });
674
+ }
675
+ /**
676
+ * Get access token from credential.
677
+ *
678
+ * @example
679
+ * ```typescript
680
+ * await credential.getToken([]) // Get SSO token using empty string array
681
+ * await credential.getToken("") // Get SSO token using empty string
682
+ * await credential.getToken([".default"]) // Get Graph access token with default scope using string array
683
+ * await credential.getToken(".default") // Get Graph access token with default scope using string
684
+ * await credential.getToken(["User.Read"]) // Get Graph access token for single scope using string array
685
+ * await credential.getToken("User.Read") // Get Graph access token for single scope using string
686
+ * await credential.getToken(["User.Read", "Application.Read.All"]) // Get Graph access token for multiple scopes using string array
687
+ * await credential.getToken("User.Read Application.Read.All") // Get Graph access token for multiple scopes using space-separated string
688
+ * await credential.getToken("https://graph.microsoft.com/User.Read") // Get Graph access token with full resource URI
689
+ * await credential.getToken(["https://outlook.office.com/Mail.Read"]) // Get Outlook access token
690
+ * ```
691
+ *
692
+ * @param {string | string[]} scopes - The list of scopes for which the token will have access.
693
+ * @param {GetTokenOptions} options - The options used to configure any requests this TokenCredential implementation might make.
694
+ *
695
+ * @throws {@link ErrorCode|InternalError} when failed to get access token with unknown error.
696
+ * @throws {@link ErrorCode|UiRequiredError} when need user consent to get access token.
697
+ * @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server.
698
+ * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
699
+ * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
700
+ *
701
+ * @returns User access token of defined scopes.
702
+ * If scopes is empty string or array, it returns SSO token.
703
+ * If scopes is non-empty, it returns access token for target scope.
704
+ * Throw error if get access token failed.
705
+ *
706
+ * @beta
707
+ */
708
+ async getToken(scopes, options) {
709
+ validateScopesType(scopes);
710
+ const ssoToken = await this.getSSOToken();
711
+ const scopeStr = typeof scopes === "string" ? scopes : scopes.join(" ");
712
+ if (scopeStr === "") {
713
+ internalLogger.info("Get SSO token");
714
+ return ssoToken;
715
+ }
716
+ else {
717
+ internalLogger.info("Get access token with scopes: " + scopeStr);
718
+ const cachedKey = await this.getAccessTokenCacheKey(scopeStr);
719
+ const cachedToken = this.getTokenCache(cachedKey);
720
+ if (cachedToken) {
721
+ if (!this.isAccessTokenNearExpired(cachedToken)) {
722
+ internalLogger.verbose("Get access token from cache");
723
+ return cachedToken;
724
+ }
725
+ else {
726
+ internalLogger.verbose("Cached access token is expired");
727
+ }
728
+ }
729
+ else {
730
+ internalLogger.verbose("No cached access token");
731
+ }
732
+ const accessToken = await this.getAndCacheAccessTokenFromSimpleAuthServer(scopeStr);
733
+ return accessToken;
734
+ }
735
+ }
736
+ /**
737
+ * Get basic user info from SSO token
738
+ *
739
+ * @example
740
+ * ```typescript
741
+ * const currentUser = await credential.getUserInfo();
742
+ * ```
743
+ *
744
+ * @throws {@link ErrorCode|InternalError} when SSO token from Teams client is not valid.
745
+ * @throws {@link ErrorCode|InvalidParameter} when SSO token from Teams client is empty.
746
+ * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
747
+ *
748
+ * @returns Basic user info with user displayName, objectId and preferredUserName.
749
+ *
750
+ * @beta
751
+ */
752
+ async getUserInfo() {
753
+ internalLogger.info("Get basic user info from SSO token");
754
+ const ssoToken = await this.getSSOToken();
755
+ return getUserInfoFromSsoToken(ssoToken.token);
756
+ }
757
+ async exchangeAccessTokenFromSimpleAuthServer(scopesStr, authCodeResult) {
758
+ var _a, _b;
759
+ const axiosInstance = await this.getAxiosInstance();
760
+ let retryCount = 0;
761
+ while (true) {
762
+ try {
763
+ const response = await axiosInstance.post("/auth/token", {
764
+ scope: scopesStr,
765
+ code: authCodeResult.code,
766
+ code_verifier: authCodeResult.codeVerifier,
767
+ redirect_uri: authCodeResult.redirectUri,
768
+ grant_type: GrantType.authCode,
769
+ });
770
+ const tokenResult = response.data;
771
+ const key = await this.getAccessTokenCacheKey(scopesStr);
772
+ this.setTokenCache(key, {
773
+ token: tokenResult.access_token,
774
+ expiresOnTimestamp: tokenResult.expires_on,
775
+ });
776
+ return;
777
+ }
778
+ catch (err) {
779
+ if (((_b = (_a = err.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.type) && err.response.data.type === "AadUiRequiredException") {
780
+ internalLogger.warn("Exchange access token failed, retry...");
781
+ if (retryCount < maxRetryCount) {
782
+ await this.sleep(retryTimeSpanInMillisecond);
783
+ retryCount++;
784
+ continue;
785
+ }
786
+ }
787
+ throw err;
788
+ }
789
+ }
790
+ }
791
+ /**
792
+ * Get access token cache from authentication server
793
+ * @returns Access token
794
+ */
795
+ async getAndCacheAccessTokenFromSimpleAuthServer(scopesStr) {
796
+ try {
797
+ internalLogger.verbose("Get access token from authentication server with scopes: " + scopesStr);
798
+ const axiosInstance = await this.getAxiosInstance();
799
+ const response = await axiosInstance.post("/auth/token", {
800
+ scope: scopesStr,
801
+ grant_type: GrantType.ssoToken,
802
+ });
803
+ const accessTokenResult = response.data;
804
+ const accessToken = {
805
+ token: accessTokenResult.access_token,
806
+ expiresOnTimestamp: accessTokenResult.expires_on,
807
+ };
808
+ const cacheKey = await this.getAccessTokenCacheKey(scopesStr);
809
+ this.setTokenCache(cacheKey, accessToken);
810
+ return accessToken;
811
+ }
812
+ catch (err) {
813
+ throw this.generateAuthServerError(err);
814
+ }
815
+ }
816
+ /**
817
+ * Get SSO token using teams SDK
818
+ * It will try to get SSO token from memory first, if SSO token doesn't exist or about to expired, then it will using teams SDK to get SSO token
819
+ * @returns SSO token
820
+ */
821
+ getSSOToken() {
822
+ return new Promise((resolve, reject) => {
823
+ if (this.ssoToken) {
824
+ if (this.ssoToken.expiresOnTimestamp - Date.now() > tokenRefreshTimeSpanInMillisecond) {
825
+ internalLogger.verbose("Get SSO token from memory cache");
826
+ resolve(this.ssoToken);
827
+ return;
828
+ }
829
+ }
830
+ let initialized = false;
831
+ microsoftTeams.initialize(() => {
832
+ initialized = true;
833
+ microsoftTeams.authentication.getAuthToken({
834
+ successCallback: (token) => {
835
+ if (!token) {
836
+ const errorMsg = "Get empty SSO token from Teams";
837
+ internalLogger.error(errorMsg);
838
+ reject(new ErrorWithCode(errorMsg, ErrorCode.InternalError));
839
+ return;
840
+ }
841
+ const tokenObject = parseJwt(token);
842
+ if (tokenObject.ver !== "1.0" && tokenObject.ver !== "2.0") {
843
+ const errorMsg = "SSO token is not valid with an unknown version: " + tokenObject.ver;
844
+ internalLogger.error(errorMsg);
845
+ reject(new ErrorWithCode(errorMsg, ErrorCode.InternalError));
846
+ return;
847
+ }
848
+ const ssoToken = {
849
+ token,
850
+ expiresOnTimestamp: tokenObject.exp * 1000,
851
+ };
852
+ this.ssoToken = ssoToken;
853
+ resolve(ssoToken);
854
+ },
855
+ failureCallback: (errMessage) => {
856
+ const errorMsg = "Get SSO token failed with error: " + errMessage;
857
+ internalLogger.error(errorMsg);
858
+ reject(new ErrorWithCode(errorMsg, ErrorCode.InternalError));
859
+ },
860
+ resources: [],
861
+ });
862
+ });
863
+ // If the code not running in Teams, the initialize callback function would never trigger
864
+ setTimeout(() => {
865
+ if (!initialized) {
866
+ const errorMsg = "Initialize teams sdk timeout, maybe the code is not running inside Teams";
867
+ internalLogger.error(errorMsg);
868
+ reject(new ErrorWithCode(errorMsg, ErrorCode.InternalError));
869
+ }
870
+ }, initializeTeamsSdkTimeoutInMillisecond);
871
+ });
872
+ }
873
+ /**
874
+ * Load and validate authentication configuration
875
+ * @returns Authentication configuration
876
+ */
877
+ loadAndValidateConfig() {
878
+ internalLogger.verbose("Validate authentication configuration");
879
+ const config = getAuthenticationConfiguration();
880
+ if (!config) {
881
+ internalLogger.error(ErrorMessage.AuthenticationConfigurationNotExists);
882
+ throw new ErrorWithCode(ErrorMessage.AuthenticationConfigurationNotExists, ErrorCode.InvalidConfiguration);
883
+ }
884
+ if (config.initiateLoginEndpoint && config.simpleAuthEndpoint && config.clientId) {
885
+ return config;
886
+ }
887
+ const missingValues = [];
888
+ if (!config.initiateLoginEndpoint) {
889
+ missingValues.push("initiateLoginEndpoint");
890
+ }
891
+ if (!config.simpleAuthEndpoint) {
892
+ missingValues.push("simpleAuthEndpoint");
893
+ }
894
+ if (!config.clientId) {
895
+ missingValues.push("clientId");
896
+ }
897
+ const errorMsg = formatString(ErrorMessage.InvalidConfiguration, missingValues.join(", "), "undefined");
898
+ internalLogger.error(errorMsg);
899
+ throw new ErrorWithCode(errorMsg, ErrorCode.InvalidConfiguration);
900
+ }
901
+ /**
902
+ * Get axios instance with sso token bearer header
903
+ * @returns AxiosInstance
904
+ */
905
+ async getAxiosInstance() {
906
+ const ssoToken = await this.getSSOToken();
907
+ const axiosInstance = axios.create({
908
+ baseURL: this.config.simpleAuthEndpoint,
909
+ });
910
+ axiosInstance.interceptors.request.use((config) => {
911
+ config.headers.Authorization = "Bearer " + ssoToken.token;
912
+ return config;
913
+ });
914
+ return axiosInstance;
915
+ }
916
+ /**
917
+ * Set access token to cache
918
+ * @param key
919
+ * @param token
920
+ */
921
+ setTokenCache(key, token) {
922
+ Cache.set(key, JSON.stringify(token));
923
+ }
924
+ /**
925
+ * Get access token from cache.
926
+ * If there is no cache or cannot be parsed, then it will return null
927
+ * @param key
928
+ * @returns Access token or null
929
+ */
930
+ getTokenCache(key) {
931
+ const value = Cache.get(key);
932
+ if (value === null) {
933
+ return null;
934
+ }
935
+ const accessToken = this.validateAndParseJson(value);
936
+ return accessToken;
937
+ }
938
+ /**
939
+ * Parses passed value as JSON access token, if value is not a valid json string JSON.parse() will throw an error.
940
+ * @param jsonValue
941
+ */
942
+ validateAndParseJson(jsonValue) {
943
+ try {
944
+ const parsedJson = JSON.parse(jsonValue);
945
+ /**
946
+ * There are edge cases in which JSON.parse will successfully parse a non-valid JSON object
947
+ * (e.g. JSON.parse will parse an escaped string into an unescaped string), so adding a type check
948
+ * of the parsed value is necessary in order to be certain that the string represents a valid JSON object.
949
+ *
950
+ */
951
+ return parsedJson && typeof parsedJson === "object" ? parsedJson : null;
952
+ }
953
+ catch (error) {
954
+ return null;
955
+ }
956
+ }
957
+ /**
958
+ * Generate cache key
959
+ * @param scopesStr
960
+ * @returns Access token cache key, a key example: accessToken-userId-clientId-tenantId-scopes
961
+ */
962
+ async getAccessTokenCacheKey(scopesStr) {
963
+ const ssoToken = await this.getSSOToken();
964
+ const ssoTokenObj = parseJwt(ssoToken.token);
965
+ const clientId = this.config.clientId;
966
+ const userObjectId = ssoTokenObj.oid;
967
+ const tenantId = ssoTokenObj.tid;
968
+ const key = [accessTokenCacheKeyPrefix, userObjectId, clientId, tenantId, scopesStr]
969
+ .join(separator)
970
+ .replace(/" "/g, "_");
971
+ return key;
972
+ }
973
+ /**
974
+ * Check whether the token is about to expire (within 5 minutes)
975
+ * @returns Boolean value indicate whether the token is about to expire
976
+ */
977
+ isAccessTokenNearExpired(token) {
978
+ const expireDate = new Date(token.expiresOnTimestamp);
979
+ if (expireDate.getTime() - Date.now() > tokenRefreshTimeSpanInMillisecond) {
980
+ return false;
981
+ }
982
+ return true;
983
+ }
984
+ generateAuthServerError(err) {
985
+ var _a, _b;
986
+ let errorMessage = err.message;
987
+ if ((_b = (_a = err.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.type) {
988
+ errorMessage = err.response.data.detail;
989
+ if (err.response.data.type === "AadUiRequiredException") {
990
+ const fullErrorMsg = "Failed to get access token from authentication server, please login first: " +
991
+ errorMessage;
992
+ internalLogger.warn(fullErrorMsg);
993
+ return new ErrorWithCode(fullErrorMsg, ErrorCode.UiRequiredError);
994
+ }
995
+ else {
996
+ const fullErrorMsg = "Failed to get access token from authentication server: " + errorMessage;
997
+ internalLogger.error(fullErrorMsg);
998
+ return new ErrorWithCode(fullErrorMsg, ErrorCode.ServiceError);
999
+ }
1000
+ }
1001
+ const fullErrorMsg = "Failed to get access token with error: " + errorMessage;
1002
+ return new ErrorWithCode(fullErrorMsg, ErrorCode.InternalError);
1003
+ }
1004
+ sleep(ms) {
1005
+ return new Promise((resolve) => setTimeout(resolve, ms));
1006
+ }
1007
+ }
1008
+
1009
+ // Copyright (c) Microsoft Corporation.
1010
+ const defaultScope = "https://graph.microsoft.com/.default";
1011
+ /**
1012
+ * Microsoft Graph auth provider for Teams Framework
1013
+ *
1014
+ * @beta
1015
+ */
1016
+ class MsGraphAuthProvider {
1017
+ /**
1018
+ * Constructor of MsGraphAuthProvider.
1019
+ *
1020
+ * @param {TokenCredential} credential - Credential used to invoke Microsoft Graph APIs.
1021
+ * @param {string | string[]} scopes - The list of scopes for which the token will have access.
1022
+ *
1023
+ * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
1024
+ *
1025
+ * @returns An instance of MsGraphAuthProvider.
1026
+ *
1027
+ * @beta
1028
+ */
1029
+ constructor(credential, scopes) {
1030
+ this.credential = credential;
1031
+ let scopesStr = defaultScope;
1032
+ if (scopes) {
1033
+ validateScopesType(scopes);
1034
+ scopesStr = typeof scopes === "string" ? scopes : scopes.join(" ");
1035
+ if (scopesStr === "") {
1036
+ scopesStr = defaultScope;
1037
+ }
1038
+ }
1039
+ internalLogger.info(`Create Microsoft Graph Authentication Provider with scopes: '${scopesStr}'`);
1040
+ this.scopes = scopesStr;
1041
+ }
1042
+ /**
1043
+ * Get access token for Microsoft Graph API requests.
1044
+ *
1045
+ * @throws {@link ErrorCode|InternalError} when get access token failed due to empty token or unknown other problems.
1046
+ * @throws {@link ErrorCode|TokenExpiredError} when SSO token has already expired.
1047
+ * @throws {@link ErrorCode|UiRequiredError} when need user consent to get access token.
1048
+ * @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth or AAD server.
1049
+ * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
1050
+ *
1051
+ * @returns Access token from the credential.
1052
+ *
1053
+ */
1054
+ async getAccessToken() {
1055
+ internalLogger.info(`Get Graph Access token with scopes: '${this.scopes}'`);
1056
+ const accessToken = await this.credential.getToken(this.scopes);
1057
+ return new Promise((resolve, reject) => {
1058
+ if (accessToken) {
1059
+ resolve(accessToken.token);
1060
+ }
1061
+ else {
1062
+ const errorMsg = "Graph access token is undefined or empty";
1063
+ internalLogger.error(errorMsg);
1064
+ reject(new ErrorWithCode(errorMsg, ErrorCode.InternalError));
1065
+ }
1066
+ });
1067
+ }
1068
+ }
1069
+
1070
+ // Copyright (c) Microsoft Corporation.
1071
+ /**
1072
+ * Get Microsoft graph client.
1073
+ *
1074
+ * @example
1075
+ * Get Microsoft graph client by TokenCredential
1076
+ * ```typescript
1077
+ * // Sso token example (Azure Function)
1078
+ * const ssoToken = "YOUR_TOKEN_STRING";
1079
+ * const options = {"AAD_APP_ID", "AAD_APP_SECRET"};
1080
+ * const credential = new OnBehalfOfAADUserCredential(ssoToken, options);
1081
+ * const graphClient = await createMicrosoftGraphClient(credential);
1082
+ * const profile = await graphClient.api("/me").get();
1083
+ *
1084
+ * // TeamsBotSsoPrompt example (Bot Application)
1085
+ * const requiredScopes = ["User.Read"];
1086
+ * const config: Configuration = {
1087
+ * loginUrl: loginUrl,
1088
+ * clientId: clientId,
1089
+ * clientSecret: clientSecret,
1090
+ * tenantId: tenantId
1091
+ * };
1092
+ * const prompt = new TeamsBotSsoPrompt(dialogId, {
1093
+ * config: config
1094
+ * scopes: '["User.Read"],
1095
+ * });
1096
+ * this.addDialog(prompt);
1097
+ *
1098
+ * const oboCredential = new OnBehalfOfAADUserCredential(
1099
+ * getUserId(dialogContext),
1100
+ * {
1101
+ * clientId: "AAD_APP_ID",
1102
+ * clientSecret: "AAD_APP_SECRET"
1103
+ * });
1104
+ * try {
1105
+ * const graphClient = await createMicrosoftGraphClient(credential);
1106
+ * const profile = await graphClient.api("/me").get();
1107
+ * } catch (e) {
1108
+ * dialogContext.beginDialog(dialogId);
1109
+ * return Dialog.endOfTurn();
1110
+ * }
1111
+ * ```
1112
+ *
1113
+ * @param {TokenCredential} credential - token credential instance.
1114
+ * @param scopes - The array of Microsoft Token scope of access. Default value is `[.default]`.
1115
+ *
1116
+ * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
1117
+ *
1118
+ * @returns Graph client with specified scopes.
1119
+ *
1120
+ * @beta
1121
+ */
1122
+ function createMicrosoftGraphClient(credential, scopes) {
1123
+ internalLogger.info("Create Microsoft Graph Client");
1124
+ const authProvider = new MsGraphAuthProvider(credential, scopes);
1125
+ const graphClient = Client.initWithMiddleware({
1126
+ authProvider,
1127
+ });
1128
+ return graphClient;
1129
+ }
1130
+
1131
+ // Copyright (c) Microsoft Corporation.
1132
+ /**
1133
+ * SQL connection configuration instance.
1134
+ * @remarks
1135
+ * Only works in in server side.
1136
+ *
1137
+ * @beta
1138
+ *
1139
+ */
1140
+ class DefaultTediousConnectionConfiguration {
1141
+ constructor() {
1142
+ /**
1143
+ * MSSQL default scope
1144
+ * https://docs.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-connect-msi
1145
+ */
1146
+ this.defaultSQLScope = "https://database.windows.net/";
1147
+ }
1148
+ /**
1149
+ * Generate connection configuration consumed by tedious.
1150
+ *
1151
+ * @returns Connection configuration of tedious for the SQL.
1152
+ *
1153
+ * @throws {@link ErrorCode|InvalidConfiguration} when SQL config resource configuration is invalid.
1154
+ * @throws {@link ErrorCode|InternalError} when get user MSI token failed or MSI token is invalid.
1155
+ * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
1156
+ *
1157
+ * @beta
1158
+ */
1159
+ async getConfig() {
1160
+ internalLogger.info("Get SQL configuration");
1161
+ const configuration = getResourceConfiguration(ResourceType.SQL);
1162
+ if (!configuration) {
1163
+ const errMsg = "SQL resource configuration not exist";
1164
+ internalLogger.error(errMsg);
1165
+ throw new ErrorWithCode(errMsg, ErrorCode.InvalidConfiguration);
1166
+ }
1167
+ try {
1168
+ this.isSQLConfigurationValid(configuration);
1169
+ }
1170
+ catch (err) {
1171
+ throw err;
1172
+ }
1173
+ if (!this.isMsiAuthentication()) {
1174
+ const configWithUPS = this.generateDefaultConfig(configuration);
1175
+ internalLogger.verbose("SQL configuration with username and password generated");
1176
+ return configWithUPS;
1177
+ }
1178
+ try {
1179
+ const configWithToken = await this.generateTokenConfig(configuration);
1180
+ internalLogger.verbose("SQL configuration with MSI token generated");
1181
+ return configWithToken;
1182
+ }
1183
+ catch (error) {
1184
+ throw error;
1185
+ }
1186
+ }
1187
+ /**
1188
+ * Check SQL use MSI identity or username and password.
1189
+ *
1190
+ * @returns false - login with SQL MSI identity, true - login with username and password.
1191
+ * @internal
1192
+ */
1193
+ isMsiAuthentication() {
1194
+ internalLogger.verbose("Check connection config using MSI access token or username and password");
1195
+ const configuration = getResourceConfiguration(ResourceType.SQL);
1196
+ if ((configuration === null || configuration === void 0 ? void 0 : configuration.sqlUsername) != null && (configuration === null || configuration === void 0 ? void 0 : configuration.sqlPassword) != null) {
1197
+ internalLogger.verbose("Login with username and password");
1198
+ return false;
1199
+ }
1200
+ internalLogger.verbose("Login with MSI identity");
1201
+ return true;
1202
+ }
1203
+ /**
1204
+ * check configuration is an available configurations.
1205
+ * @param { SqlConfiguration } sqlConfig
1206
+ *
1207
+ * @returns true - SQL configuration has a valid SQL endpoints, SQL username with password or identity ID.
1208
+ * false - configuration is not valid.
1209
+ * @internal
1210
+ */
1211
+ isSQLConfigurationValid(sqlConfig) {
1212
+ internalLogger.verbose("Check SQL configuration if valid");
1213
+ if (!sqlConfig.sqlServerEndpoint) {
1214
+ internalLogger.error("SQL configuration is not valid without SQL server endpoint exist");
1215
+ throw new ErrorWithCode("SQL configuration error without SQL server endpoint exist", ErrorCode.InvalidConfiguration);
1216
+ }
1217
+ if (!(sqlConfig.sqlUsername && sqlConfig.sqlPassword) && !sqlConfig.sqlIdentityId) {
1218
+ const errMsg = `SQL configuration is not valid without ${sqlConfig.sqlIdentityId ? "" : "identity id "} ${sqlConfig.sqlUsername ? "" : "SQL username "} ${sqlConfig.sqlPassword ? "" : "SQL password"} exist`;
1219
+ internalLogger.error(errMsg);
1220
+ throw new ErrorWithCode(errMsg, ErrorCode.InvalidConfiguration);
1221
+ }
1222
+ internalLogger.verbose("SQL configuration is valid");
1223
+ }
1224
+ /**
1225
+ * Generate tedious connection configuration with default authentication type.
1226
+ *
1227
+ * @param { SqlConfiguration } SQL configuration with username and password.
1228
+ *
1229
+ * @returns Tedious connection configuration with username and password.
1230
+ * @internal
1231
+ */
1232
+ generateDefaultConfig(sqlConfig) {
1233
+ internalLogger.verbose(`SQL server ${sqlConfig.sqlServerEndpoint}, user name ${sqlConfig.sqlUsername}, database name ${sqlConfig.sqlDatabaseName}`);
1234
+ const config = {
1235
+ server: sqlConfig.sqlServerEndpoint,
1236
+ authentication: {
1237
+ type: TediousAuthenticationType.default,
1238
+ options: {
1239
+ userName: sqlConfig.sqlUsername,
1240
+ password: sqlConfig.sqlPassword,
1241
+ },
1242
+ },
1243
+ options: {
1244
+ database: sqlConfig.sqlDatabaseName,
1245
+ encrypt: true,
1246
+ },
1247
+ };
1248
+ return config;
1249
+ }
1250
+ /**
1251
+ * Generate tedious connection configuration with azure-active-directory-access-token authentication type.
1252
+ *
1253
+ * @param { SqlConfiguration } SQL configuration with AAD access token.
1254
+ *
1255
+ * @returns Tedious connection configuration with access token.
1256
+ * @internal
1257
+ */
1258
+ async generateTokenConfig(sqlConfig) {
1259
+ internalLogger.verbose("Generate tedious config with MSI token");
1260
+ let token;
1261
+ try {
1262
+ const credential = new ManagedIdentityCredential(sqlConfig.sqlIdentityId);
1263
+ token = await credential.getToken(this.defaultSQLScope);
1264
+ }
1265
+ catch (error) {
1266
+ const errMsg = "Get user MSI token failed";
1267
+ internalLogger.error(errMsg);
1268
+ throw new ErrorWithCode(errMsg, ErrorCode.InternalError);
1269
+ }
1270
+ if (token) {
1271
+ const config = {
1272
+ server: sqlConfig.sqlServerEndpoint,
1273
+ authentication: {
1274
+ type: TediousAuthenticationType.MSI,
1275
+ options: {
1276
+ token: token.token,
1277
+ },
1278
+ },
1279
+ options: {
1280
+ database: sqlConfig.sqlDatabaseName,
1281
+ encrypt: true,
1282
+ },
1283
+ };
1284
+ internalLogger.verbose(`Generate token configuration success, server endpoint is ${sqlConfig.sqlServerEndpoint}, database name is ${sqlConfig.sqlDatabaseName}`);
1285
+ return config;
1286
+ }
1287
+ internalLogger.error(`Generate token configuration, server endpoint is ${sqlConfig.sqlServerEndpoint}, MSI token is not valid`);
1288
+ throw new ErrorWithCode("MSI token is not valid", ErrorCode.InternalError);
1289
+ }
1290
+ }
1291
+ /**
1292
+ * tedious connection config authentication type.
1293
+ * https://tediousjs.github.io/tedious/api-connection.html
1294
+ * @internal
1295
+ */
1296
+ var TediousAuthenticationType;
1297
+ (function (TediousAuthenticationType) {
1298
+ TediousAuthenticationType["default"] = "default";
1299
+ TediousAuthenticationType["MSI"] = "azure-active-directory-access-token";
1300
+ })(TediousAuthenticationType || (TediousAuthenticationType = {}));
1301
+
1302
+ // Copyright (c) Microsoft Corporation.
1303
+ /**
1304
+ * Creates a new prompt that leverage Teams Single Sign On (SSO) support for bot to automatically sign in user and
1305
+ * help receive oauth token, asks the user to consent if needed.
1306
+ *
1307
+ * @remarks
1308
+ * The prompt will attempt to retrieve the users current token of the desired scopes and store it in
1309
+ * the token store.
1310
+ *
1311
+ * User will be automatically signed in leveraging Teams support of Bot Single Sign On(SSO):
1312
+ * https://docs.microsoft.com/en-us/microsoftteams/platform/bots/how-to/authentication/auth-aad-sso-bots
1313
+ *
1314
+ * @example
1315
+ * When used with your bots `DialogSet` you can simply add a new instance of the prompt as a named
1316
+ * dialog using `DialogSet.add()`. You can then start the prompt from a waterfall step using either
1317
+ * `DialogContext.beginDialog()` or `DialogContext.prompt()`. The user will be prompted to sign in as
1318
+ * needed and their access token will be passed as an argument to the callers next waterfall step:
1319
+ *
1320
+ * ```JavaScript
1321
+ * const { ConversationState, MemoryStorage } = require('botbuilder');
1322
+ * const { DialogSet, WaterfallDialog } = require('botbuilder-dialogs');
1323
+ * const { TeamsBotSsoPrompt } = require('@microsoft/teamsfx');
1324
+ *
1325
+ * const convoState = new ConversationState(new MemoryStorage());
1326
+ * const dialogState = convoState.createProperty('dialogState');
1327
+ * const dialogs = new DialogSet(dialogState);
1328
+ *
1329
+ * loadConfiguration();
1330
+ * dialogs.add(new TeamsBotSsoPrompt('TeamsBotSsoPrompt', {
1331
+ * scopes: ["User.Read"],
1332
+ * }));
1333
+ *
1334
+ * dialogs.add(new WaterfallDialog('taskNeedingLogin', [
1335
+ * async (step) => {
1336
+ * return await step.beginDialog('TeamsBotSsoPrompt');
1337
+ * },
1338
+ * async (step) => {
1339
+ * const token = step.result;
1340
+ * if (token) {
1341
+ *
1342
+ * // ... continue with task needing access token ...
1343
+ *
1344
+ * } else {
1345
+ * await step.context.sendActivity(`Sorry... We couldn't log you in. Try again later.`);
1346
+ * return await step.endDialog();
1347
+ * }
1348
+ * }
1349
+ * ]));
1350
+ * ```
1351
+ *
1352
+ * @beta
1353
+ */
1354
+ class TeamsBotSsoPrompt {
1355
+ /**
1356
+ * Constructor of TeamsBotSsoPrompt.
1357
+ *
1358
+ * @param dialogId Unique ID of the dialog within its parent `DialogSet` or `ComponentDialog`.
1359
+ * @param settings Settings used to configure the prompt.
1360
+ *
1361
+ * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
1362
+ * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
1363
+ *
1364
+ * @beta
1365
+ */
1366
+ constructor(dialogId, settings) {
1367
+ this.settings = settings;
1368
+ throw new ErrorWithCode(formatString(ErrorMessage.BrowserRuntimeNotSupported, "TeamsBotSsoPrompt"), ErrorCode.RuntimeNotSupported);
1369
+ }
1370
+ /**
1371
+ * Called when a prompt dialog is pushed onto the dialog stack and is being activated.
1372
+ * @remarks
1373
+ * If the task is successful, the result indicates whether the prompt is still
1374
+ * active after the turn has been processed by the prompt.
1375
+ *
1376
+ * @param dc The DialogContext for the current turn of the conversation.
1377
+ *
1378
+ * @throws {@link ErrorCode|InvalidParameter} when timeout property in teams bot sso prompt settings is not number or is not positive.
1379
+ * @throws {@link ErrorCode|ChannelNotSupported} when bot channel is not MS Teams.
1380
+ * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
1381
+ *
1382
+ * @returns A `Promise` representing the asynchronous operation.
1383
+ *
1384
+ * @beta
1385
+ */
1386
+ async beginDialog(dc) {
1387
+ throw new ErrorWithCode(formatString(ErrorMessage.BrowserRuntimeNotSupported, "TeamsBotSsoPrompt"), ErrorCode.RuntimeNotSupported);
1388
+ }
1389
+ /**
1390
+ * Called when a prompt dialog is the active dialog and the user replied with a new activity.
1391
+ *
1392
+ * @remarks
1393
+ * If the task is successful, the result indicates whether the dialog is still
1394
+ * active after the turn has been processed by the dialog.
1395
+ * The prompt generally continues to receive the user's replies until it accepts the
1396
+ * user's reply as valid input for the prompt.
1397
+ *
1398
+ * @param dc The DialogContext for the current turn of the conversation.
1399
+ *
1400
+ * @returns A `Promise` representing the asynchronous operation.
1401
+ *
1402
+ * @throws {@link ErrorCode|ChannelNotSupported} when bot channel is not MS Teams.
1403
+ * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
1404
+ *
1405
+ * @beta
1406
+ */
1407
+ async continueDialog(dc) {
1408
+ throw new ErrorWithCode(formatString(ErrorMessage.BrowserRuntimeNotSupported, "TeamsBotSsoPrompt"), ErrorCode.RuntimeNotSupported);
1409
+ }
1410
+ }
1411
+
1412
+ export { DefaultTediousConnectionConfiguration, ErrorCode, ErrorWithCode, LogLevel, M365TenantCredential, MsGraphAuthProvider, OnBehalfOfUserCredential, ResourceType, TeamsBotSsoPrompt, TeamsUserCredential, createMicrosoftGraphClient, getAuthenticationConfiguration, getLogLevel, getResourceConfiguration, loadConfiguration, setLogFunction, setLogLevel, setLogger };
1413
+ //# sourceMappingURL=index.esm2017.js.map