(function () { "use strict"; const ORACLE_DOMAIN = "eeho.fa.us2.oraclecloud.com"; const ORACLE_COOKIE_URLS = [ "https://eeho.fa.us2.oraclecloud.com/", "https://eeho.fa.us2.oraclecloud.com/hcmUI/faces/FuseWelcome", "https://eeho.fa.us2.oraclecloud.com/fscmUI/faces/FuseWelcome", "https://eeho.fa.us2.oraclecloud.com/fscmRestApi/tokenrelay" ]; const XSRF_COOKIE_NAME = "XSRF-TOKEN-US2DZ2V_F"; const XSRF_COOKIE_PREFIX = "XSRF-TOKEN-"; const OPPORTUNITIES_LIST_URL = "https://eeho.fa.us2.oraclecloud.com/fscmUI/redwood/cx-sales/application/container/opportunities/opportunities-list"; const COOKIE_REFRESH_TIMEOUT_MS = 15000; const COOKIE_REFRESH_POLL_MS = 250; const runtimeApi = typeof browser !== "undefined" ? browser : chrome; runtimeApi.runtime.onMessage.addListener((message, sender, sendResponse) => { if (!message || !message.type) { return false; } if (message.type === "opportunitiesExtension.getXsrfToken") { getXsrfTokenCookie() .then((result) => { sendResponse({ ok: true, cookieName: result.cookie ? result.cookie.name : "", token: result.cookie ? result.cookie.value : "", matchedCookieNames: result.matchedCookieNames, lookupDetails: result.lookupDetails }); }) .catch((error) => { sendResponse({ ok: false, cookieName: "", token: "", matchedCookieNames: [], lookupDetails: [], error: error.message || "Unable to read cookies." }); }); return true; } if (message.type === "opportunitiesExtension.refreshXsrfCookie") { refreshXsrfCookie(sender) .then(sendResponse) .catch((error) => { sendResponse({ ok: false, refreshed: false, cookieName: "", durationMs: 0, error: error.message || "Unable to refresh XSRF cookie." }); }); return true; } return false; }); async function refreshXsrfCookie(sender) { const startedAt = Date.now(); const previous = (await getXsrfTokenCookie()).cookie; const createProperties = { url: OPPORTUNITIES_LIST_URL, active: false }; if (sender && sender.tab && Number.isInteger(sender.tab.windowId)) { createProperties.windowId = sender.tab.windowId; } if (supportsFirefoxCookieStoreTabs() && sender && sender.tab && sender.tab.cookieStoreId) { createProperties.cookieStoreId = sender.tab.cookieStoreId; } let refreshTab; try { refreshTab = await tabsCreate(createProperties); const current = await waitForXsrfCookieChange(previous); const refreshed = hasCookieChanged(previous, current); return { ok: Boolean(current), refreshed, cookieName: current ? current.name : "", durationMs: Date.now() - startedAt, error: refreshed ? "" : "XSRF cookie was not created or changed before timeout." }; } finally { if (refreshTab && Number.isInteger(refreshTab.id)) { try { await tabsRemove(refreshTab.id); } catch (error) { // The temporary tab may already have been closed. } } } } async function waitForXsrfCookieChange(previousCookie) { const deadline = Date.now() + COOKIE_REFRESH_TIMEOUT_MS; let currentCookie = null; while (Date.now() < deadline) { currentCookie = (await getXsrfTokenCookie()).cookie; if (hasCookieChanged(previousCookie, currentCookie)) { return currentCookie; } await wait(COOKIE_REFRESH_POLL_MS); } return currentCookie; } function hasCookieChanged(previousCookie, currentCookie) { if (!currentCookie || !currentCookie.value) { return false; } if (!previousCookie) { return true; } return previousCookie.name !== currentCookie.name || previousCookie.value !== currentCookie.value || previousCookie.expirationDate !== currentCookie.expirationDate; } function supportsFirefoxCookieStoreTabs() { return Boolean( runtimeApi.runtime && typeof runtimeApi.runtime.getBrowserInfo === "function" ); } function tabsCreate(details) { if (runtimeApi.tabs.create.length <= 1) { return runtimeApi.tabs.create(details); } return new Promise((resolve, reject) => { runtimeApi.tabs.create(details, (tab) => { const lastError = runtimeApi.runtime.lastError; if (lastError) { reject(new Error(lastError.message)); return; } resolve(tab); }); }); } function tabsRemove(tabId) { if (runtimeApi.tabs.remove.length <= 1) { return runtimeApi.tabs.remove(tabId); } return new Promise((resolve, reject) => { runtimeApi.tabs.remove(tabId, () => { const lastError = runtimeApi.runtime.lastError; if (lastError) { reject(new Error(lastError.message)); return; } resolve(); }); }); } function wait(durationMs) { return new Promise((resolve) => setTimeout(resolve, durationMs)); } async function getXsrfTokenCookie() { const lookupDetails = []; const allCookies = []; const stores = await getCookieStores(lookupDetails); for (const store of stores) { const exactCookie = await getExactCookieFromUrls(store.id, lookupDetails); if (exactCookie) { allCookies.push(exactCookie); } } for (const store of stores) { await collectCookies({ name: XSRF_COOKIE_NAME, storeId: store.id }, allCookies, lookupDetails); } for (const store of stores) { await collectCookies({ domain: ORACLE_DOMAIN, storeId: store.id }, allCookies, lookupDetails); await collectCookies({ domain: `.${ORACLE_DOMAIN}`, storeId: store.id }, allCookies, lookupDetails); } for (const store of stores) { for (const url of ORACLE_COOKIE_URLS) { await collectCookies({ url, storeId: store.id }, allCookies, lookupDetails); } } const uniqueCookies = dedupeCookies(allCookies); const xsrfCookies = uniqueCookies.filter((cookie) => cookie.name.startsWith(XSRF_COOKIE_PREFIX)); const exactCookie = xsrfCookies.find((cookie) => cookie.name === XSRF_COOKIE_NAME); const hostCookie = xsrfCookies.find((cookie) => cookie.domain === ORACLE_DOMAIN || cookie.domain === `.${ORACLE_DOMAIN}`); return { cookie: exactCookie || hostCookie || xsrfCookies[0] || null, matchedCookieNames: xsrfCookies.map((cookie) => `${cookie.name} (${cookie.domain}${cookie.path})`), lookupDetails }; } async function getExactCookieFromUrls(storeId, lookupDetails) { for (const url of ORACLE_COOKIE_URLS) { const cookie = await cookiesGet({ url, name: XSRF_COOKIE_NAME, storeId }); lookupDetails.push(`${JSON.stringify({ url, name: XSRF_COOKIE_NAME, storeId })} => ${cookie ? "found" : "not found"}`); if (cookie) { return cookie; } } return null; } async function getCookieStores(lookupDetails) { try { const stores = await cookiesGetAllCookieStores(); lookupDetails.push(`getAllCookieStores => ${stores.length} store(s)`); return stores.length ? stores : [{ id: undefined }]; } catch (error) { lookupDetails.push(`getAllCookieStores => unavailable (${error.message || "unknown error"})`); return [{ id: undefined }]; } } async function collectCookies(details, target, lookupDetails) { const cleanDetails = removeUndefinedValues(details); const cookies = await cookiesGetAll(cleanDetails); target.push(...cookies); lookupDetails.push(`${JSON.stringify(cleanDetails)} => ${cookies.length} cookie(s)`); } function dedupeCookies(cookies) { const seen = new Set(); return cookies.filter((cookie) => { const key = `${cookie.name}|${cookie.domain}|${cookie.path}|${cookie.storeId || ""}`; if (seen.has(key)) { return false; } seen.add(key); return true; }); } function cookiesGetAll(details) { if (runtimeApi.cookies.getAll.length <= 1) { return runtimeApi.cookies.getAll(details); } return new Promise((resolve, reject) => { runtimeApi.cookies.getAll(details, (cookies) => { const lastError = runtimeApi.runtime.lastError; if (lastError) { reject(new Error(lastError.message)); return; } resolve(cookies); }); }); } function cookiesGet(details) { const cleanDetails = removeUndefinedValues(details); if (runtimeApi.cookies.get.length <= 1) { return runtimeApi.cookies.get(cleanDetails); } return new Promise((resolve, reject) => { runtimeApi.cookies.get(cleanDetails, (cookie) => { const lastError = runtimeApi.runtime.lastError; if (lastError) { reject(new Error(lastError.message)); return; } resolve(cookie); }); }); } function cookiesGetAllCookieStores() { if (!runtimeApi.cookies.getAllCookieStores) { return Promise.resolve([{ id: undefined }]); } if (runtimeApi.cookies.getAllCookieStores.length === 0) { return runtimeApi.cookies.getAllCookieStores(); } return new Promise((resolve, reject) => { runtimeApi.cookies.getAllCookieStores((stores) => { const lastError = runtimeApi.runtime.lastError; if (lastError) { reject(new Error(lastError.message)); return; } resolve(stores); }); }); } function removeUndefinedValues(details) { return Object.fromEntries( Object.entries(details).filter((entry) => entry[1] !== undefined) ); } })();