Implemented the functionality to create Service Requests
This commit is contained in:
82
src/auth/sr-request-headers.js
Normal file
82
src/auth/sr-request-headers.js
Normal file
@@ -0,0 +1,82 @@
|
||||
function createSrRequestHeaders({ runtimeApi }) {
|
||||
const origin = "https://comcipapic-oalprod.integration.ocp.oraclecloud.com";
|
||||
const appPath = "/ic/builder/rt/SeaaS_initiation/";
|
||||
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\/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}*`], 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.");
|
||||
}
|
||||
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": "application/vnd.oracle.adf.action+json",
|
||||
Authorization: "Session", Origin: target.origin,
|
||||
...(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);
|
||||
if (serviceTarget.origin !== headers.Origin || !serviceTarget.pathname.startsWith(appPath)
|
||||
|| !serviceTarget.pathname.endsWith("/set/seaas/mgmt/serviceRequests") || 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, "\\$&");
|
||||
await runtimeApi.declarativeNetRequest.updateSessionRules({
|
||||
removeRuleIds: [7201, 7202],
|
||||
addRules: [`^${escapedCatalogUrl}[0-9]+$`, `^${escapedServiceUrl}$`].map((regexFilter, index) => ({
|
||||
id: 7201 + index, priority: 1,
|
||||
action: { type: "modifyHeaders", requestHeaders: [{ header: "Origin", operation: "set", value: headers.Origin }] },
|
||||
condition: { regexFilter, initiatorDomains: [extensionDomain],
|
||||
requestMethods: ["post"], resourceTypes: ["xmlhttprequest"] }
|
||||
}))
|
||||
});
|
||||
return headers;
|
||||
}
|
||||
return { start, tokenHeaders, previewTokenHeaders, observeResponseHeaders: observeHeaders };
|
||||
}
|
||||
Reference in New Issue
Block a user