UNPKG

@microsoft/teams-ai

Version:

SDK focused on building AI based applications for Microsoft Teams.

324 lines 13.2 kB
"use strict"; /** * @module teams-ai */ /** * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AuthError = exports.AuthenticationManager = exports.Authentication = void 0; const msal_node_1 = require("@azure/msal-node"); const BotAuthenticationBase_1 = require("./BotAuthenticationBase"); const OAuthAdaptiveCardAuthentication_1 = require("./OAuthAdaptiveCardAuthentication"); const OAuthBotAuthentication_1 = require("./OAuthBotAuthentication"); const OAuthMessageExtensionAuthentication_1 = require("./OAuthMessageExtensionAuthentication"); const TeamsSsoAdaptiveCardAuthentication_1 = require("./TeamsSsoAdaptiveCardAuthentication"); const TeamsSsoBotAuthentication_1 = require("./TeamsSsoBotAuthentication"); const TeamsSsoMessageExtensionAuthentication_1 = require("./TeamsSsoMessageExtensionAuthentication"); const UserTokenAccess = __importStar(require("./UserTokenAccess")); /** * User authentication service. */ class Authentication { _adaptiveCardAuth; _messageExtensionAuth; _botAuth; _name; _msal; /** * The authentication settings. */ settings; /** * Creates a new instance of the `Authentication` class. * @param {Application} app - The application instance. * @param {string} name - The name of the connection. * @param {OAuthSettings} settings - Authentication settings. * @param {Storage} storage - A storage instance otherwise Memory Storage is used. * @param {MessageExtensionAuthenticationBase} messageExtensionsAuth - Handles message extension flow authentication. * @param {BotAuthenticationBase} botAuth - Handles bot-flow authentication. * @param {AdaptiveCardAuthenticationBase} adaptiveCardAuth - Handles adaptive card authentication. */ constructor(app, name, settings, storage, messageExtensionsAuth, botAuth, adaptiveCardAuth) { this.settings = settings; this._name = name; if (this.isOAuthSettings(settings)) { this._messageExtensionAuth = messageExtensionsAuth || new OAuthMessageExtensionAuthentication_1.OAuthPromptMessageExtensionAuthentication(settings); this._botAuth = botAuth || new OAuthBotAuthentication_1.OAuthBotAuthentication(app, settings, this._name, storage); this._adaptiveCardAuth = adaptiveCardAuth || new OAuthAdaptiveCardAuthentication_1.OAuthAdaptiveCardAuthentication(settings); } else { this._msal = new msal_node_1.ConfidentialClientApplication(settings.msalConfig); this._botAuth = botAuth || new TeamsSsoBotAuthentication_1.TeamsSsoBotAuthentication(app, settings, this._name, this._msal, storage); this._messageExtensionAuth = messageExtensionsAuth || new TeamsSsoMessageExtensionAuthentication_1.TeamsSsoMessageExtensionAuthentication(settings, this._msal); this._adaptiveCardAuth = adaptiveCardAuth || new TeamsSsoAdaptiveCardAuthentication_1.TeamsSsoAdaptiveCardAuthentication(); } } /** * Signs in a user. * This method will be called automatically by the Application class. * @template TState * @param {TurnContext} context - Current turn context. * @param {TState} state Application state. * @returns {string | undefined} The authentication token or undefined if the user is still login in. */ async signInUser(context, state) { // Check if user is signed in. const token = await this.isUserSignedIn(context); if (token) { return token; } if (this._messageExtensionAuth.isValidActivity(context)) { return await this._messageExtensionAuth.authenticate(context); } if (this._botAuth.isValidActivity(context)) { return await this._botAuth.authenticate(context, state); } if (this._adaptiveCardAuth.isValidActivity(context)) { return await this._adaptiveCardAuth.authenticate(context); } throw new AuthError('Incoming activity is not a valid activity to initiate authentication flow.', 'invalidActivity'); } /** * Signs out a user. * @template TState * @param {TurnContext} context - Current turn context. * @param {TState} state - Application state. * @returns {Promise<void>} A Promise representing the asynchronous operation. */ async signOutUser(context, state) { this._botAuth.deleteAuthFlowState(context, state); // Signout flow is agnostic of the activity type. if (this.isOAuthSettings(this.settings)) { return await UserTokenAccess.signOutUser(context, this.settings); } else { return await this.removeTokenFromMsalCache(context); } } /** * Check if the user is signed, if they are then return the token. * @param {TurnContext} context Current turn context. * @returns {string | undefined} The token string or undefined if the user is not signed in. */ async isUserSignedIn(context) { if (this.isOAuthSettings(this.settings)) { const tokenResponse = await UserTokenAccess.getUserToken(context, this.settings, ''); if (tokenResponse && tokenResponse.token) { return tokenResponse.token; } return undefined; } else { const tokenResponse = await this.acquireTokenFromMsalCache(context); if (tokenResponse && tokenResponse.accessToken) { return tokenResponse.accessToken; } return undefined; } } /** * The handler function is called when the user has successfully signed in. * This only applies if sign in was initiated by the user sending a message to the bot. * This handler will not be triggered if a message extension triggered the authentication flow. * @template TState * @param {(context: TurnContext, state: TState) => Promise<void>} handler The handler function to call when the user has successfully signed in */ onUserSignInSuccess(handler) { this._botAuth.onUserSignInSuccess(handler); } /** * This handler function is called when the user sign in flow fails. * This only applies if sign in was initiated by the user sending a message to the bot. * This handler will not be triggered if a message extension triggered the authentication flow. * @template TState * @param {(context: TurnContext, state: TState, error: AuthError) => Promise<void>} handler The handler function to call when the user failed to signed in. */ onUserSignInFailure(handler) { this._botAuth.onUserSignInFailure(handler); } isOAuthSettings(settings) { return settings.connectionName !== undefined; } async acquireTokenFromMsalCache(context) { try { if (context.activity.from.aadObjectId) { const settings = this.settings; const account = await this._msal.getTokenCache().getAccountByLocalId(context.activity.from.aadObjectId); if (account) { const silentRequest = { account: account, scopes: settings.scopes }; return await this._msal.acquireTokenSilent(silentRequest); } } } catch (error) { return null; } return null; } async removeTokenFromMsalCache(context) { if (context.activity.from.aadObjectId) { try { const account = await this._msal.getTokenCache().getAccountByLocalId(context.activity.from.aadObjectId); if (account) { await this._msal.getTokenCache().removeAccount(account); } } catch (error) { return; } } return; } } exports.Authentication = Authentication; /** * The user authentication manager. */ class AuthenticationManager { _authentications = new Map(); default; /** * Creates a new instance of the `AuthenticationManager` class. * @param {Application} app - The application instance. * @param {AuthenticationOptions} options - Authentication options. * @param {Storage} storage - A storage instance otherwise Memory Storage is used. */ constructor(app, options, storage) { if (!options.settings || Object.keys(options.settings).length === 0) { throw new Error('Authentication settings are required.'); } this.default = options.default || Object.keys(options.settings)[0]; const settings = options.settings; for (const key in settings) { if (key in settings) { const setting = settings[key]; const authentication = new Authentication(app, key, setting, storage); this._authentications.set(key, authentication); } } } /** * @template TState * Gets the authentication instance for the specified connection name. * @param {string} name The setting name. * @returns {Authentication<TState>} The authentication instance. */ get(name) { const connection = this._authentications.get(name); if (!connection) { throw new Error(`Could not find setting name '${name}'`); } return connection; } /** * Signs in a user. * @template TState * @param {TurnContext} context The turn context. * @param {TState} state The turn state. * @param {string} settingName Optional. The name of the setting to use. If not specified, the default setting name is used. * @returns {Promise<SignInResponse>} The sign in response. */ async signUserIn(context, state, settingName) { if (!settingName) { settingName = this.default; } // Get authentication instance const auth = this.get(settingName); let status; // Sign the user in let token; try { // Get the auth token token = await auth.signInUser(context, state); } catch (e) { status = 'error'; const cause = e instanceof AuthError ? e.cause : 'other'; return { status: status, cause: cause, error: e }; } if (token) { (0, BotAuthenticationBase_1.setTokenInState)(state, settingName, token); status = 'complete'; } else { status = 'pending'; } return { status }; } /** * Signs out a user. * @template TState * @param {TurnContext} context The turn context. * @param {TState} state The turn state. * @param {string} settingName Optional. The name of the setting to use. If not specified, the default setting name is used. */ async signOutUser(context, state, settingName) { if (!settingName) { settingName = this.default; } // Get authentication instace const auth = this.get(settingName); // Sign the user out if (auth) { await auth.signOutUser(context, state); (0, BotAuthenticationBase_1.deleteTokenFromState)(state, settingName); } } } exports.AuthenticationManager = AuthenticationManager; /** * An error thrown when an authentication error occurs. */ class AuthError extends Error { /** * The cause of the error. */ cause; /** * Creates a new instance of the `AuthError` class. * @param {string} message The error message. * @param {AuthErrorReason} reason Optional. Cause of the error. Defaults to `other`. */ constructor(message, reason = 'other') { super(message); this.cause = reason; } } exports.AuthError = AuthError; //# sourceMappingURL=Authentication.js.map