UNPKG

@itwin/insights-client

Version:

Insights client for the iTwin platform

148 lines 7.12 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; import { parse, URLSearchParams } from "url"; import { inject, injectable } from "inversify"; import * as puppeteer from "puppeteer"; import { TestSetupError } from "../../CommonTestUtils"; import { TestAuthorizationClientConfig } from "./TestAuthorizationClientConfigImpl"; let TestAuthorizationClient = class TestAuthorizationClient { constructor(_authConfig) { this._authConfig = _authConfig; // cspell:disable-next-line this._pageLoadedEvent = "networkidle2"; this._consentPageTitle = "Permissions"; this._pageElementIds = { fields: { email: "#identifierInput", password: "#password", }, buttons: { next: "#sign-in-button", signIn: "#sign-in-button", consent: ".ping.button.normal.allow", }, }; } async getAccessToken(testUserCredentials) { const browserLaunchOptions = { headless: true, defaultViewport: { width: 800, height: 1200, }, }; const browser = await puppeteer.launch(browserLaunchOptions); const browserPage = await browser.newPage(); const authorizationCodePromise = this.interceptRedirectAndGetAuthorizationCode(browserPage); await browserPage.goto(this.getAuthorizationUrl(testUserCredentials), { waitUntil: this._pageLoadedEvent }); await this.fillCredentials(browserPage, testUserCredentials); await this.consentIfNeeded(browserPage); const accessToken = await this.exchangeAuthorizationCodeForAccessToken(await authorizationCodePromise); await browser.close(); return accessToken; } getAuthorizationUrl(testUserCredentials) { return `${this._authConfig.authority}/connect/authorize?` + `client_id=${encodeURIComponent(this._authConfig.clientId)}&` + `scope=${encodeURIComponent(testUserCredentials.scopes)}&` + "response_type=code&" + `redirect_uri=${encodeURIComponent(this._authConfig.redirectUrl)}`; } async fillCredentials(browserPage, testUserCredentials) { const emailField = await this.captureElement(browserPage, this._pageElementIds.fields.email); await emailField.type(testUserCredentials.email); const nextButton = await this.captureElement(browserPage, this._pageElementIds.buttons.next); await nextButton.click(); const passwordField = await this.captureElement(browserPage, this._pageElementIds.fields.password); await passwordField.type(testUserCredentials.password); const signInButton = await this.captureElement(browserPage, this._pageElementIds.buttons.signIn); await Promise.all([ signInButton.click(), browserPage.waitForNavigation({ waitUntil: this._pageLoadedEvent }), ]); } async consentIfNeeded(browserPage) { const isConsentPage = await browserPage.title() === this._consentPageTitle; if (!isConsentPage) { return; } const consentButton = await this.captureElement(browserPage, this._pageElementIds.buttons.consent); await Promise.all([ consentButton.click(), browserPage.waitForNavigation({ waitUntil: this._pageLoadedEvent }), ]); } async exchangeAuthorizationCodeForAccessToken(authorizationCode) { const requestUrl = `${this._authConfig.authority}/connect/token`; const requestBody = new URLSearchParams({ // eslint-disable-next-line @typescript-eslint/naming-convention grant_type: "authorization_code", code: authorizationCode, // eslint-disable-next-line @typescript-eslint/naming-convention redirect_uri: this._authConfig.redirectUrl, }); // eslint-disable-next-line @typescript-eslint/naming-convention const encodedClientCredentials = Buffer.from(`${encodeURIComponent(this._authConfig.clientId)}:${encodeURIComponent(this._authConfig.clientSecret)}`).toString("base64"); const requestConfig = { method: "POST", headers: { // eslint-disable-next-line @typescript-eslint/naming-convention "Content-Type": "application/x-www-form-urlencoded", // eslint-disable-next-line @typescript-eslint/naming-convention "Authorization": `Basic ${encodedClientCredentials}`, }, body: requestBody, }; const response = await fetch(requestUrl, requestConfig); const data = await response.json(); return data.access_token; } async interceptRedirectAndGetAuthorizationCode(browserPage) { await browserPage.setRequestInterception(true); return new Promise((resolve) => { browserPage.on("request", async (interceptedRequest) => { const currentRequestUrl = interceptedRequest.url(); if (!currentRequestUrl.startsWith(this._authConfig.redirectUrl)) { await interceptedRequest.continue(); } else { await this.respondSuccess(interceptedRequest); resolve(this.getCodeFromUrl(currentRequestUrl)); } }); }); } async respondSuccess(request) { await request.respond({ status: 200, contentType: "text/html", body: "OK", }); } getCodeFromUrl(redirectUrl) { // eslint-disable-next-line deprecation/deprecation const urlQuery = parse(redirectUrl, true).query; if (!urlQuery.code) throw new TestSetupError("Sign in failed: could not parse code from url."); return urlQuery.code.toString(); } async captureElement(browserPage, selector) { const element = await browserPage.waitForSelector(selector); if (!element) throw new TestSetupError(`Sign in failed: could not find element with selector '${selector}'.`); return element; } }; TestAuthorizationClient = __decorate([ injectable(), __param(0, inject(TestAuthorizationClientConfig)) ], TestAuthorizationClient); export { TestAuthorizationClient }; //# sourceMappingURL=TestAuthorizationClient.js.map