function createSrRequestHeaders({ runtimeApi }) { const origin = "https://comcipapic-oalprod.integration.ocp.oraclecloud.com"; const appPath = "/ic/builder/rt/SeaaS_initiation/"; const internalPath = "/ic/builder/rt/SeaaS_SR_management/live;profile=PROD/services/auth/1.1/proxy/oalsetCRMRestAPICloudAccount/uri/https/eeho.fa.us2.oraclecloud.com/crmRestApi/resources/latest/serviceRequests"; const storageKey = "opportunitiesExtension.srAppBuilderClientId.v1"; const maxAge = 60 * 60 * 1000; let observed = null; let started = false; function valid(record) { return record?.origin === origin && typeof record.value === "string" && /^[\x21-\x7e]{1,2048}$/.test(record.value) && Number.isFinite(record.observedAt) && record.observedAt <= Date.now() && Date.now() - record.observedAt < maxAge; } function observeHeaders(rawUrl, headers) { let url; try { url = new URL(rawUrl); } catch { return; } if (url.origin !== origin || !/^\/ic\/builder\/rt\/(?:SeaaS_initiation|SeaaS_SR_management|oalset_timeentrymobile)\/live(?:\/|;)/.test(url.pathname)) return; // Read only the client ID, not cookies, bodies or authorization. const value = typeof headers?.get === "function" ? headers.get("x-appbuilder-client-id") : headers?.find(item => item.name.toLowerCase() === "x-appbuilder-client-id")?.value; const record = { origin, value: value?.trim(), observedAt: Date.now() }; if (!valid(record)) return; observed = record; // Session storage survives service-worker suspension without persisting across browser sessions. runtimeApi.storage?.session?.set({ [storageKey]: record }).catch(() => {}); } function start() { if (started || !runtimeApi?.webRequest) return; started = true; const filter = { urls: [`${origin}${appPath}*`, `${origin}/ic/builder/rt/SeaaS_SR_management/*`, `${origin}/ic/builder/rt/oalset_timeentrymobile/*`], types: ["xmlhttprequest"] }; runtimeApi.webRequest.onBeforeSendHeaders?.addListener(details => { if (details.tabId >= 0 && !details.incognito) observeHeaders(details.url, details.requestHeaders); }, filter, ["requestHeaders"]); runtimeApi.webRequest.onHeadersReceived?.addListener(details => { if (!details.incognito) observeHeaders(details.url, details.responseHeaders); }, filter, ["responseHeaders"]); } async function previewTokenHeaders(url) { const target = new URL(url); if (target.origin !== origin || !target.pathname.startsWith(appPath) || !/\/Catalogue_c(?:\/\d+)?$/.test(target.pathname)) { throw new Error("Unexpected Service Request token URL."); } return sessionHeaders(target.origin, "application/vnd.oracle.adf.action+json"); } async function sessionHeaders(targetOrigin, contentType) { if (!valid(observed)) { try { const stored = await runtimeApi.storage?.session?.get(storageKey); if (valid(stored?.[storageKey]) && !valid(observed)) observed = stored[storageKey]; } catch { /* A missing capture must not prevent trying the other required headers. */ } } return { Accept: "application/json", "Content-Type": contentType, Authorization: "Session", Origin: targetOrigin, ...(valid(observed) ? { "x-appbuilder-client-id": observed.value } : {}) }; } async function tokenHeaders(url, serviceRequestUrl) { const headers = await previewTokenHeaders(url); if (!/\/Catalogue_c\/\d+$/.test(new URL(url).pathname)) throw new Error("Missing Catalogue Id."); const serviceTarget = new URL(serviceRequestUrl); const isServiceRequest = serviceTarget.pathname.startsWith(appPath) && serviceTarget.pathname.endsWith("/set/seaas/mgmt/serviceRequests"); if (serviceTarget.origin !== headers.Origin || !isServiceRequest || serviceTarget.search || serviceTarget.hash) { throw new Error("Unexpected Service Request URL."); } if (!runtimeApi?.declarativeNetRequest?.updateSessionRules || !runtimeApi.runtime?.getURL) { throw new Error("Reload the extension to enable the Service Request token header permissions."); } const extensionDomain = new URL(runtimeApi.runtime.getURL("/")).hostname; const catalogUrl = url.slice(0, url.lastIndexOf("/") + 1); const escapedCatalogUrl = catalogUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); const escapedServiceUrl = serviceTarget.href.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); const ruleIds = [7201, 7202]; await runtimeApi.declarativeNetRequest.updateSessionRules({ removeRuleIds: ruleIds, addRules: [`^${escapedCatalogUrl}[0-9]+$`, `^${escapedServiceUrl}$`].map((regexFilter, index) => ({ id: ruleIds[index], priority: 1, action: { type: "modifyHeaders", requestHeaders: [{ header: "Origin", operation: "set", value: headers.Origin }] }, condition: { regexFilter, initiatorDomains: [extensionDomain], requestMethods: ["post"], resourceTypes: ["xmlhttprequest"] } })) }); return headers; } async function internalServiceRequestHeaders(url) { const target = new URL(url); if (target.origin !== origin || target.pathname !== internalPath || target.search || target.hash) { throw new Error("Unexpected Internal Service Request URL."); } if (!runtimeApi?.declarativeNetRequest?.updateSessionRules || !runtimeApi.runtime?.getURL) { throw new Error("Reload the extension to enable the Internal Service Request header permissions."); } const headers = await sessionHeaders(target.origin, "application/json"); const extensionDomain = new URL(runtimeApi.runtime.getURL("/")).hostname; const escapedUrl = target.href.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); await runtimeApi.declarativeNetRequest.updateSessionRules({ removeRuleIds: [7203], addRules: [{ id: 7203, priority: 1, action: { type: "modifyHeaders", requestHeaders: [{ header: "Origin", operation: "set", value: headers.Origin }] }, condition: { regexFilter: `^${escapedUrl}$`, initiatorDomains: [extensionDomain], requestMethods: ["post"], resourceTypes: ["xmlhttprequest"] } }] }); return headers; } async function timeEntriesHeaders(url) { const target = new URL(url); const path = "/ic/builder/rt/oalset_timeentrymobile/live;profile=PROD/services/auth/1.1/proxy/oke_seaas/uri/https/gxpap.oracle.com/oalcrm/service/set/seaas/mgmt/timeEntries"; const isDelete = target.pathname.startsWith(`${path}/`) && /^[1-9]\d*$/.test(target.pathname.slice(path.length + 1)); if (target.origin !== origin || (target.pathname !== path && !isDelete) || target.search || target.hash) { throw new Error("Unexpected time entries URL."); } if (!runtimeApi?.declarativeNetRequest?.updateSessionRules || !runtimeApi.runtime?.getURL) { throw new Error("Reload the extension to enable the time entry header permissions."); } const escapedUrl = target.href.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); await runtimeApi.declarativeNetRequest.updateSessionRules({ removeRuleIds: [isDelete ? 7205 : 7204], addRules: [{ id: isDelete ? 7205 : 7204, priority: 1, action: { type: "modifyHeaders", requestHeaders: [{ header: "Origin", operation: "set", value: target.origin }] }, condition: { regexFilter: `^${escapedUrl}$`, initiatorDomains: [new URL(runtimeApi.runtime.getURL("/")).hostname], requestMethods: isDelete ? ["delete"] : ["post", "put"], resourceTypes: ["xmlhttprequest"] } }] }); return sessionHeaders(target.origin, "application/json"); } return { start, tokenHeaders, previewTokenHeaders, internalServiceRequestHeaders, timeEntriesHeaders, observeResponseHeaders: observeHeaders }; }