{"version":3,"sources":["../../../packages/core/host/host-core-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAM,MAAM,MAAM,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAIzC,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAQrE,oBAAY,iBAAiB;IACzB,OAAO,IAAA;IACP,GAAG,IAAA;CACN;AAED,qBAAa,eAAe;IACxB,OAAO,CAAC,MAAM,CAAC,WAAW,CAAW;IACrC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAS;IAC/B,OAAO,CAAC,kBAAkB,CAAY;IAEtC;;OAEG;IACI,SAAS,EAAE,iBAAiB,CAAC;IAEpC;;OAEG;IACI,KAAK,EAAE,sBAAsB,CAAQ;IAE5C;;OAEG;;IAQH;;;;OAIG;IACI,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IAK1D;;;;OAIG;IACI,UAAU,CACb,GAAG,EAAE,MAAM,EAAE,OAAO,UAAO,EAAE,YAAY,GAAE,0BAA+B,EAAE,eAAe,UAAO,GAAG,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IA2DtI;;;;;OAKG;IACH,OAAO,CAAC,0BAA0B;CAuCrC","file":"host-core-manager.d.ts","sourcesContent":["import { Observable, of } from 'rxjs';\r\nimport { AjaxResponse } from 'rxjs/ajax';\r\nimport { mergeMap } from 'rxjs/operators';\r\nimport { ErrorExtended } from '../data/error-extended';\r\nimport { headerConstants } from '../data/http-constants';\r\nimport { SignedHttpRequestToken } from '../security/sign-on-manager';\r\nimport { HostCoreMessageType } from './host-core-message-type';\r\nimport { HostCoreRequest, HostCoreResponse } from './host-core-messages';\r\n\r\ninterface HostCoreTokenRequest extends HostCoreRequest {\r\n    type: HostCoreMessageType.HostCoreToken;\r\n}\r\n\r\nexport enum HostCoreTokenMode {\r\n    Unknown,\r\n    Aad\r\n}\r\n\r\nexport class HostCoreManager {\r\n    private static tokenOption = 'token';\r\n    private static aadMode = 'aad';\r\n    private maxResponseTimeout = 2 * 1000;\r\n\r\n    /**\r\n     * The token mode.\r\n     */\r\n    public tokenMode: HostCoreTokenMode;\r\n\r\n    /**\r\n     * Token will be collected when using HostCoreManager for manifest loading.\r\n     */\r\n    public token: SignedHttpRequestToken = null;\r\n\r\n    /**\r\n     * Initializes a new instance of new HostCoreManager class.\r\n     */\r\n    constructor() {\r\n        // Check if token mode was sepecified at URL parameter.\r\n        const optionParam = MsftSme.getLocationSearchParameter(HostCoreManager.tokenOption);\r\n        this.tokenMode = optionParam && MsftSme.localeCompareIgnoreCase(optionParam.value, HostCoreManager.aadMode) === 0 ?\r\n                            HostCoreTokenMode.Aad : HostCoreTokenMode.Unknown;\r\n    }\r\n\r\n    /**\r\n     * Query JSON data with a token.\r\n     * @param url Url to query data using current token.\r\n     * @returns ajax response object.\r\n     */\r\n    public httpGet(url: string): Observable<AjaxResponse<any>> {\r\n        const tokenQuery = this.tokenMode === HostCoreTokenMode.Aad ? this.requestTokenToParentWindow(url) : of(null);\r\n        return tokenQuery.pipe(mergeMap(() => this.getNoCache(url)));\r\n    }\r\n\r\n    /**\r\n     * Performs a request with 'get' http method with cache control.\r\n     * @param url the uri for GET call.\r\n     * @return the observable for GET result data.\r\n     */\r\n    public getNoCache(\r\n        url: string, noCache = true, responseType: XMLHttpRequestResponseType = '', withCredentials = true): Observable<AjaxResponse<any>> {\r\n        const publish = new Observable<AjaxResponse<any>>(observer => {\r\n            const request = new XMLHttpRequest();\r\n            const handler = () => {\r\n                if (request.readyState === XMLHttpRequest.DONE) {\r\n                    if (request.status === 200) {\r\n                        try {\r\n                            let response: string;\r\n                            if (responseType === '') {\r\n                                response = JSON.parse(request.response);\r\n                            } else {\r\n                                response = request.response;\r\n                            }\r\n\r\n                            observer.next(<AjaxResponse<any>>{\r\n                                status: request.status,\r\n                                response\r\n                            });\r\n                            observer.complete();\r\n                        } catch (e) {\r\n                            observer.error(e);\r\n                        }\r\n                    } else {\r\n                        // if response has a html content, redirects to the form login page which is \"/\".\r\n                        // if response has an error JSON payload, it displays the error at the splashscreen. (RBAC error)\r\n                        let errorMessage = request.statusText;\r\n                        if (request.response && request.response.indexOf('<!DOCTYPE html>') < 0) {\r\n                            const errorResponse = JSON.parse(request.response);\r\n                            errorMessage = errorResponse?.error.message || errorMessage;\r\n                        }\r\n\r\n                        const error = new ErrorExtended<{ status: number, url: string }>(errorMessage);\r\n                        error.extendedSource = ErrorExtended.sources.getNoCache;\r\n                        error.extended = { status: request.status, url };\r\n                        observer.error(error);\r\n                    }\r\n                }\r\n            };\r\n\r\n            request.open('Get', url);\r\n            request.withCredentials = withCredentials;\r\n            request.responseType = responseType;\r\n            request.setRequestHeader(headerConstants.ACCEPT, 'application/json, text/plain, */*');\r\n            if (this.token) {\r\n                // sending a token, it creates an active cookie on the browser.\r\n                request.setRequestHeader(headerConstants.SME_AAD_AUTHORIZATION, `WAC;PAS ${this.token.jwt}`);\r\n            }\r\n\r\n            if (noCache) {\r\n                request.setRequestHeader('Cache-control', 'no-cache');\r\n            }\r\n\r\n            request.onreadystatechange = handler;\r\n            request.send();\r\n        });\r\n\r\n        return publish;\r\n    }\r\n\r\n    /**\r\n     * Query the token to host window.\r\n     * @param url the target url (manifest.json)\r\n     * @param responseTimeout the response timeout.\r\n     * @returns observeral of token query.\r\n     */\r\n    private requestTokenToParentWindow(url: string, responseTimeout: number = this.maxResponseTimeout): Observable<SignedHttpRequestToken> {\r\n        const hostWindow = MsftSme.getHostWindow();\r\n        if (!hostWindow) {\r\n            return of(null);\r\n        }\r\n\r\n        if (this.token) {\r\n            return of(this.token);\r\n        }\r\n\r\n        return new Observable(subscriber => {\r\n            const request: HostCoreTokenRequest = { requestId: MsftSme.newGuid(), type: HostCoreMessageType.HostCoreToken };\r\n            const listener = (event: MessageEvent) => {\r\n                if (event.data && event.data.requestId === request.requestId && event.data.data) {\r\n                    this.token = (<HostCoreResponse<SignedHttpRequestToken>>event.data).data;\r\n                    subscriber.next(this.token);\r\n                    subscriber.complete();\r\n                }\r\n            };\r\n            const channel = new MessageChannel();\r\n            channel.port1.addEventListener('message', listener);\r\n            channel.port1.start();\r\n            channel.port2.start();\r\n            setTimeout(() => {\r\n                hostWindow.postMessage(request, '*', [channel.port2]);\r\n                setTimeout(() => {\r\n                    const error = new ErrorExtended<{ status: number, url: string }>('timed out for token query');\r\n                    error.extendedSource = ErrorExtended.sources.getNoCache;\r\n                    error.extended = { status: 403, url  };\r\n                    subscriber.error(error);\r\n                },\r\n                responseTimeout);\r\n            });\r\n            return () => {\r\n                channel.port1.removeEventListener('message', listener);\r\n                channel.port1.close();\r\n            };\r\n        });\r\n    }\r\n}\r\n"]}