UNPKG

msal

Version:
220 lines (188 loc) 7.13 kB
// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. import { IUri } from "../IUri"; import { Constants, SSOTypes } from "./Constants"; import { ServerRequestParameters } from "../ServerRequestParameters"; import { ScopeSet } from "../ScopeSet"; import { StringUtils } from './StringUtils'; /** * @hidden */ export class UrlUtils { /** * generates the URL with QueryString Parameters * @param scopes */ static createNavigateUrl(serverRequestParams: ServerRequestParameters): string { const str = this.createNavigationUrlString(serverRequestParams); let authEndpoint: string = serverRequestParams.authorityInstance.AuthorizationEndpoint; // if the endpoint already has queryparams, lets add to it, otherwise add the first one if (authEndpoint.indexOf("?") < 0) { authEndpoint += "?"; } else { authEndpoint += "&"; } const requestUrl: string = `${authEndpoint}${str.join("&")}`; return requestUrl; } /** * Generate the array of all QueryStringParams to be sent to the server * @param scopes */ static createNavigationUrlString(serverRequestParams: ServerRequestParameters): Array<string> { let scopes = serverRequestParams.scopes; if (scopes.indexOf(serverRequestParams.clientId) === -1) { scopes.push(serverRequestParams.clientId); } const str: Array<string> = []; str.push("response_type=" + serverRequestParams.responseType); this.translateclientIdUsedInScope(scopes, serverRequestParams.clientId); str.push("scope=" + encodeURIComponent(ScopeSet.parseScope(scopes))); str.push("client_id=" + encodeURIComponent(serverRequestParams.clientId)); str.push("redirect_uri=" + encodeURIComponent(serverRequestParams.redirectUri)); str.push("state=" + encodeURIComponent(serverRequestParams.state)); str.push("nonce=" + encodeURIComponent(serverRequestParams.nonce)); str.push("client_info=1"); str.push(`x-client-SKU=${serverRequestParams.xClientSku}`); str.push(`x-client-Ver=${serverRequestParams.xClientVer}`); if (serverRequestParams.promptValue) { str.push("prompt=" + encodeURIComponent(serverRequestParams.promptValue)); } if (serverRequestParams.claimsValue) { str.push("claims=" + encodeURIComponent(serverRequestParams.claimsValue)); } if (serverRequestParams.queryParameters) { str.push(serverRequestParams.queryParameters); } if (serverRequestParams.extraQueryParameters) { str.push(serverRequestParams.extraQueryParameters); } str.push("client-request-id=" + encodeURIComponent(serverRequestParams.correlationId)); return str; } /** * append the required scopes: https://openid.net/specs/openid-connect-basic-1_0.html#Scopes * @param scopes */ private static translateclientIdUsedInScope(scopes: Array<string>, clientId: string): void { const clientIdIndex: number = scopes.indexOf(clientId); if (clientIdIndex >= 0) { scopes.splice(clientIdIndex, 1); if (scopes.indexOf("openid") === -1) { scopes.push("openid"); } if (scopes.indexOf("profile") === -1) { scopes.push("profile"); } } } /** * Returns current window URL as redirect uri */ static getDefaultRedirectUri(): string { return window.location.href.split("?")[0].split("#")[0]; } /** * Given a url like https://a:b/common/d?e=f#g, and a tenantId, returns https://a:b/tenantId/d * @param href The url * @param tenantId The tenant id to replace */ static replaceTenantPath(url: string, tenantId: string): string { url = url.toLowerCase(); var urlObject = this.GetUrlComponents(url); var pathArray = urlObject.PathSegments; if (tenantId && (pathArray.length !== 0 && (pathArray[0] === Constants.common || pathArray[0] === SSOTypes.ORGANIZATIONS))) { pathArray[0] = tenantId; } return this.constructAuthorityUriFromObject(urlObject, pathArray); } static constructAuthorityUriFromObject(urlObject: IUri, pathArray: string[]) { return this.CanonicalizeUri(urlObject.Protocol + "//" + urlObject.HostNameAndPort + "/" + pathArray.join("/")); } /** * Parses out the components from a url string. * @returns An object with the various components. Please cache this value insted of calling this multiple times on the same url. */ static GetUrlComponents(url: string): IUri { if (!url) { throw "Url required"; } // https://gist.github.com/curtisz/11139b2cfcaef4a261e0 var regEx = RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"); var match = url.match(regEx); if (!match || match.length < 6) { throw "Valid url required"; } let urlComponents = <IUri>{ Protocol: match[1], HostNameAndPort: match[4], AbsolutePath: match[5] }; let pathSegments = urlComponents.AbsolutePath.split("/"); pathSegments = pathSegments.filter((val) => val && val.length > 0); // remove empty elements urlComponents.PathSegments = pathSegments; return urlComponents; } /** * Given a url or path, append a trailing slash if one doesnt exist * * @param url */ static CanonicalizeUri(url: string): string { if (url) { url = url.toLowerCase(); } if (url && !UrlUtils.endsWith(url, "/")) { url += "/"; } return url; } /** * Checks to see if the url ends with the suffix * Required because we are compiling for es5 instead of es6 * @param url * @param str */ // TODO: Rename this, not clear what it is supposed to do static endsWith(url: string, suffix: string): boolean { if (!url || !suffix) { return false; } return url.indexOf(suffix, url.length - suffix.length) !== -1; } /** * Utils function to remove the login_hint and domain_hint from the i/p extraQueryParameters * @param url * @param name */ static urlRemoveQueryStringParameter(url: string, name: string): string { if (StringUtils.isEmpty(url)) { return url; } var regex = new RegExp("(\\&" + name + "=)[^\&]+"); url = url.replace(regex, ""); // name=value& regex = new RegExp("(" + name + "=)[^\&]+&"); url = url.replace(regex, ""); // name=value regex = new RegExp("(" + name + "=)[^\&]+"); url = url.replace(regex, ""); return url; } /** * @hidden * @ignore * * Returns the anchor part(#) of the URL */ static getHashFromUrl(urlStringOrFragment: string): string { const hashIndex1 = urlStringOrFragment.indexOf("#"); const hashIndex2 = urlStringOrFragment.indexOf("#/"); if (hashIndex2 > -1) { return urlStringOrFragment.substring(hashIndex2 + 2); } else if (hashIndex1 > -1) { return urlStringOrFragment.substring(hashIndex1 + 1); } return urlStringOrFragment; } }