UNPKG

@kwiz/common

Version:

KWIZ common utilities and helpers for M365 platform

277 lines 12.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.GetSPFxClientAuthTokenSync = exports.GetSPFxClientAuthToken = exports.GetMSALSiteScope = exports.GetDefaultScope = exports.GetTokenAudiencePrefix = void 0; const collections_base_1 = require("../../helpers/collections.base"); const random_1 = require("../../helpers/random"); const typecheckers_1 = require("../../helpers/typecheckers"); const auth_1 = require("../../types/auth"); const localstoragecache_1 = require("../localstoragecache"); const rest_1 = require("../rest"); const common_1 = require("../sharepoint.rest/common"); function GetTokenAudiencePrefix(appId) { return `api://${appId}`; } exports.GetTokenAudiencePrefix = GetTokenAudiencePrefix; function GetDefaultScope(appId) { return `${GetTokenAudiencePrefix(appId)}/access_as_user`; } exports.GetDefaultScope = GetDefaultScope; function GetMSALSiteScope(hostName) { return `https://${hostName}`; } exports.GetMSALSiteScope = GetMSALSiteScope; function _getGetSPFxClientAuthTokenParams(siteUrl, spfxTokenType = auth_1.SPFxAuthTokenType.Graph) { let acquireURL = `${(0, common_1.GetRestBaseUrl)(siteUrl)}/SP.OAuth.Token/Acquire`; //todo: add all the resource end points (ie. OneNote, Yammer, Stream) let resource = ""; let isSPOToken = false; switch (spfxTokenType) { case auth_1.SPFxAuthTokenType.Outlook: resource = "https://outlook.office365.com/search"; break; case auth_1.SPFxAuthTokenType.SharePoint: case auth_1.SPFxAuthTokenType.MySite: isSPOToken = true; resource = new URL(acquireURL).origin; if (spfxTokenType === auth_1.SPFxAuthTokenType.MySite) { let split = resource.split("."); split[0] += "-my"; resource = split.join("."); } break; default: resource = "https://graph.microsoft.com"; } let data = { resource: resource, tokenType: isSPOToken ? "SPO" : undefined }; let params = { url: acquireURL, body: JSON.stringify(data), options: { allowCache: false, // ...shortLocalCache, // postCacheKey: `${spfxTokenType}_${_spPageContextInfo.webId}`, includeDigestInPost: true, headers: { "Accept": "application/json;odata.metadata=minimal", "content-type": "application/json; charset=UTF-8", "odata-version": "4.0", } } }; return params; } function _parseAndCacheGetSPFxClientAuthTokenResult(result, spfxTokenType = auth_1.SPFxAuthTokenType.Graph) { if (!(0, typecheckers_1.isNullOrUndefined)(result) && !(0, typecheckers_1.isNullOrEmptyString)(result.access_token)) { let expiration = (0, typecheckers_1.isNumber)(result.expires_on) ? new Date(result.expires_on * 1000) : { minutes: 15 }; (0, localstoragecache_1.setCacheItem)(`access_token_${spfxTokenType}_${_spPageContextInfo.webId}`, result.access_token, expiration); return result.access_token; } return null; } function _getSPFxClientAuthTokenFromCache(spfxTokenType = auth_1.SPFxAuthTokenType.Graph) { let cachedToken = (0, localstoragecache_1.getCacheItem)(`access_token_${spfxTokenType}_${_spPageContextInfo.webId}`); if (!(0, typecheckers_1.isNullOrEmptyString)(cachedToken)) { return cachedToken; } return null; } /** Acquire an authorization token for a Outlook, Graph, or SharePoint the same way SPFx clients do */ async function GetSPFxClientAuthToken(siteUrl, spfxTokenType = auth_1.SPFxAuthTokenType.Graph) { let cachedToken = _getSPFxClientAuthTokenFromCache(spfxTokenType); if (!(0, typecheckers_1.isNullOrEmptyString)(cachedToken)) { return cachedToken; } if (spfxTokenType === auth_1.SPFxAuthTokenType.Graph) { let resource = "https://graph.microsoft.com"; try { let cachedToken; for (let key in localStorage) { if (key.startsWith(`Identity.OAuth.${_spPageContextInfo.systemUserKey}`) && key.indexOf(resource) !== -1) { cachedToken = JSON.parse(localStorage.getItem(key)); break; } } if (!(0, typecheckers_1.isNullOrUndefined)(cachedToken)) { return _parseAndCacheGetSPFxClientAuthTokenResult({ access_token: cachedToken.value, expires_on: cachedToken.expiration.toString(), resource: resource, scope: null, token_type: "Bearer" }, spfxTokenType); } } catch { } try { let _spComponentLoader = window["_spComponentLoader"]; let manifests = _spComponentLoader.getManifests(); let manifest = (0, collections_base_1.firstOrNull)(manifests, (manifest) => { return manifest.alias === "@microsoft/sp-http-base"; }); let module = await _spComponentLoader.loadComponentById(manifest.id); let factory = new module.AadTokenProviderFactory(); let provider = await factory.getTokenProvider(); let token = await provider.getToken(resource, true); if (!(0, typecheckers_1.isNullOrEmptyString)(token)) { return _parseAndCacheGetSPFxClientAuthTokenResult({ access_token: token, expires_on: null, resource: resource, scope: null, token_type: "Bearer" }, spfxTokenType); } } catch { } try { let bufferToString = (buffer) => { let result = Array.from(buffer, (c) => { return String.fromCodePoint(c); }).join(""); return window.btoa(result); }; let ni = new Uint32Array(1); let ci = () => { let b = window.crypto.getRandomValues(ni); return b[0]; }; let generateNonce = () => { let ti = "0123456789abcdef"; const e = Date.now(), t = 1024 * ci() + (1023 & ci()), n = new Uint8Array(16), a = Math.trunc(t / 2 ** 30), i = t & 2 ** 30 - 1, r = ci(); n[0] = e / 2 ** 40, n[1] = e / 2 ** 32, n[2] = e / 2 ** 24, n[3] = e / 65536, n[4] = e / 256, n[5] = e, n[6] = 112 | a >>> 8, n[7] = a, n[8] = 128 | i >>> 24, n[9] = i >>> 16, n[10] = i >>> 8, n[11] = i, n[12] = r >>> 24, n[13] = r >>> 16, n[14] = r >>> 8, n[15] = r; let o = ""; for (let e = 0; e < n.length; e++) o += ti.charAt(n[e] >>> 4), o += ti.charAt(15 & n[e]), 3 !== e && 5 !== e && 7 !== e && 9 !== e || (o += "-"); return o; }; let requestId = (0, random_1.getUniqueId)(); let stateBuffer = new TextEncoder().encode(JSON.stringify({ id: (0, random_1.getUniqueId)(), meta: { interactionType: "silent" } })); let state = bufferToString(stateBuffer); let redirectUri = `https://${window.location.host}/_forms/spfxsinglesignon.aspx`; let sid = _spPageContextInfo["aadSessionId"]; let codeVerifierBuffer = window.crypto.getRandomValues(new Uint8Array(32)); let codeVerifier = bufferToString(codeVerifierBuffer).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_"); let codeChallengeBuffer = await window.crypto.subtle.digest("SHA-256", new TextEncoder().encode(codeVerifier)); let codeChallenge = bufferToString(new Uint8Array(codeChallengeBuffer)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_"); let nonce = generateNonce(); let url = `${_spPageContextInfo["aadInstanceUrl"]}/${_spPageContextInfo.aadTenantId}/oauth2/v2.0/authorize?`; url += `client_id=08e18876-6177-487e-b8b5-cf950c1e598c`; url += `&scope=${encodeURIComponent("https://graph.microsoft.com/.default openid profile offline_access")}`; url += `&redirect_uri=${encodeURIComponent(redirectUri)}`; url += `&client-request-id=${encodeURIComponent(requestId)}`; url += `&response_mode=fragment`; url += `&response_type=code`; url += `&code_challenge=${codeChallenge}&code_challenge_method=S256&prompt=none`; url += `&sid=${encodeURIComponent(sid)}&nonce=${nonce}`; url += `&state=${encodeURIComponent(state)}`; let getCodeFromIframe = async () => { return new Promise((resolve, reject) => { try { let iframe = document.createElement("iframe"); iframe.style.display = "none"; iframe.src = url; iframe.onload = () => { window.setTimeout(() => { let params = new URLSearchParams(iframe.contentWindow.location.hash.replace("#", "?")); let pCode = params.get("code"); let pState = params.get("state"); let pSid = params.get("session_state"); if (!(0, typecheckers_1.isNullOrEmptyString)(pCode) && pState === state && pSid === sid) { resolve(pCode); } else { reject(); } document.removeChild(iframe); }, 100); }; document.body.appendChild(iframe); } catch { reject(); } }); }; let authCode = await getCodeFromIframe(); if (!(0, typecheckers_1.isNullOrEmptyString)(authCode)) { let url = `${_spPageContextInfo["aadInstanceUrl"]}/${_spPageContextInfo.aadTenantId}/oauth2/v2.0/token?`; url += `client-request-id=${encodeURIComponent(requestId)}`; let fd = new FormData(); fd.append("client_id", "08e18876-6177-487e-b8b5-cf950c1e598c"); fd.append("scope", "https://graph.microsoft.com/.default openid profile offline_access"); fd.append("redirect_uri", redirectUri); fd.append("code", authCode); fd.append("grant_type", "authorization_code"); fd.append("code_verifier", codeVerifier); let response = await fetch(url, { method: "POST", body: fd }); if (response.ok) { let authToken = await response.json(); return _parseAndCacheGetSPFxClientAuthTokenResult(authToken, spfxTokenType); } } } catch { } } else { try { let { url, body, options } = _getGetSPFxClientAuthTokenParams(siteUrl, spfxTokenType); let result = await (0, rest_1.GetJson)(url, body, options); return _parseAndCacheGetSPFxClientAuthTokenResult(result, spfxTokenType); } catch { } } return null; } exports.GetSPFxClientAuthToken = GetSPFxClientAuthToken; /** Acquire an authorization token for a Outlook, Graph, or SharePoint the same way SPFx clients do */ function GetSPFxClientAuthTokenSync(siteUrl, spfxTokenType = auth_1.SPFxAuthTokenType.Graph) { try { let cachedToken = _getSPFxClientAuthTokenFromCache(spfxTokenType); if (!(0, typecheckers_1.isNullOrEmptyString)(cachedToken)) { return cachedToken; } let { url, body, options } = _getGetSPFxClientAuthTokenParams(siteUrl, spfxTokenType); let response = (0, rest_1.GetJsonSync)(url, body, options); return _parseAndCacheGetSPFxClientAuthTokenResult(response.result, spfxTokenType); } catch { } return null; } exports.GetSPFxClientAuthTokenSync = GetSPFxClientAuthTokenSync; //# sourceMappingURL=common.js.map