Loading comcipapic to establish a session for SR requests

This commit is contained in:
2026-10-02 02:37:35 -03:00
parent 3fd89a307c
commit f512ef9928
27 changed files with 2377 additions and 373 deletions

View File

@@ -1,4 +1,146 @@
function createFusionSrDetails({ fetchJson }) {
function createFusionSrDetails({ fetchJson, tabsCreate, tabsRemove, supportsFirefoxCookieStoreTabs, cookiesGetAll, cookieChanges, wait }) {
const sessions = new Map();
function cookiePart(cookie) {
if (!cookie) return null;
const match = /^ORA_OCIS_CG_SESSION_idcs-([a-zA-Z0-9-]+)_comcipapic-oalprod\.integration\.ocp\.oraclecloud\.com_([12])$/.exec(cookie.name);
const domain = "comcipapic-oalprod.integration.ocp.oraclecloud.com";
const cookieDomain = cookie.domain?.replace(/^\./, "");
if (!match || (cookieDomain && cookieDomain !== domain && !domain.endsWith(`.${cookieDomain}`))) return null;
return { key: `${match[1]}|${cookie.path || "/"}|${cookie.storeId || ""}`, part: match[2],
valid: Boolean(cookie.value) && (cookie.expirationDate == null || cookie.expirationDate > Date.now() / 1000) };
}
function watchSession(session, sender) {
const pairs = new Map();
let available;
session.cookieReady = new Promise(resolve => { available = resolve; });
const listener = change => {
const cookie = change.cookie;
const part = cookiePart(cookie);
if (!part) return;
if (sender?.tab?.cookieStoreId && cookie.storeId !== sender.tab.cookieStoreId) return;
if (!pairs.has(part.key)) pairs.set(part.key, new Map());
const pair = pairs.get(part.key);
if (change.removed || !part.valid) pair.delete(part.part);
else pair.set(part.part, cookie);
if (pair.size === 2 && [...pair.values()].every(item => cookiePart(item)?.valid)) available(new Set([part.key]));
session.wake?.();
};
cookieChanges?.addListener(listener);
session.unwatch = () => cookieChanges?.removeListener(listener);
}
function waitForSessionCookies(session, sender) {
if (session.cookieWait) return session.cookieWait;
session.cookieWait = (async () => {
const deadline = Date.now() + 1000;
for (let attempt = 0; attempt < 5; attempt += 1) {
// Install the wake-up before reading so a renewal during getAll is not missed.
const changed = new Promise(resolve => { session.wake = resolve; });
const current = await sessionCookies(sender);
const renewed = [...current].some(pair => !session.baseline.has(pair));
if (renewed || Date.now() >= deadline) {
session.baseline = current;
return current;
}
await Promise.race([changed, wait(250)]);
}
return sessionCookies(sender);
})().finally(() => { session.cookieWait = null; session.wake = null; });
return session.cookieWait;
}
async function sessionCookies(sender) {
const domain = "comcipapic-oalprod.integration.ocp.oraclecloud.com";
const details = { domain };
if (sender?.tab?.cookieStoreId) details.storeId = sender.tab.cookieStoreId;
try {
const groups = new Map();
for (const cookie of await cookiesGetAll(details)) {
const part = cookiePart(cookie);
if (!part?.valid) continue;
if (!groups.has(part.key)) groups.set(part.key, {});
groups.get(part.key)[part.part] = [cookie.name, cookie.value, cookie.expirationDate ?? null];
}
// Fingerprints remain in memory only; the browser sends the actual Cookie header.
return new Set([...groups.values()].filter(pair => pair[1] && pair[2]).map(pair => JSON.stringify([pair[1], pair[2]])));
} catch { return new Set(); }
}
async function requestLookupWithSession(operation, message, sender, initialize = false) {
const existingCookies = initialize ? await sessionCookies(sender) : null;
if (existingCookies?.size) return { ok: true, debugRequests: [] };
const logs = [];
const query = async () => {
try {
const result = await operation(message);
logs.push(...(result.debugRequests || []));
return { ...result, debugRequests: logs };
} catch (error) {
logs.push(...(error.debugRequests || []));
error.debugRequests = logs;
throw error;
}
};
if (!initialize) {
try { return await query(); } catch (error) { if (error.httpStatus !== 401) throw error; }
}
const key = sender?.tab?.cookieStoreId || "default";
let session = sessions.get(key);
if (!session) {
const details = {
url: "https://comcipapic-oalprod.integration.ocp.oraclecloud.com/ic/builder/rt/SeaaS_initiation/live/webApps/external/",
active: false
};
if (Number.isInteger(sender?.tab?.windowId)) details.windowId = sender.tab.windowId;
if (supportsFirefoxCookieStoreTabs() && sender?.tab?.cookieStoreId) details.cookieStoreId = sender.tab.cookieStoreId;
session = { users: 0, closed: null, baseline: null };
watchSession(session, sender);
session.tab = (async () => {
session.baseline = existingCookies || await sessionCookies(sender);
return tabsCreate(details);
})();
sessions.set(key, session);
}
session.users += 1;
let tab;
try {
tab = await session.tab;
const deadline = Date.now() + 60000;
for (let attempt = 0; attempt < 240 && Date.now() < deadline; attempt += 1) {
const pendingCookies = initialize && attempt === 0
? sessionCookies(sender) : waitForSessionCookies(session, sender);
const cookies = await (initialize ? Promise.race([session.cookieReady, pendingCookies]) : pendingCookies);
if (initialize) {
// Proactive preparation observes cookies only; API requests belong to the form.
if (!cookies.size) continue;
await closeSessionTab();
return { ok: true, debugRequests: [] };
}
try {
const result = await query();
// Any successful lookup confirms the shared session; stop the page immediately.
await closeSessionTab();
return result;
} catch (error) {
if (error.httpStatus !== 401) throw error;
}
}
throw new Error("Service Request session could not be established after 60 seconds. Sign in to Oracle and retry.");
} catch (error) {
error.debugRequests = logs;
throw error;
} finally {
session.users -= 1;
if (session.users === 0) {
sessions.delete(key);
session.unwatch();
await closeSessionTab();
}
}
function closeSessionTab() {
if (!session.closed && Number.isInteger(tab?.id)) {
session.closed = tabsRemove(tab.id).catch(() => {});
}
return session.closed;
}
}
async function requestInternalServiceRequest(message) {
const debugRequests = [];
try {
@@ -27,5 +169,34 @@ function createFusionSrDetails({ fetchJson }) {
throw error;
}
}
return { requestInternalServiceRequest };
async function requestLookup(lookupType, requestName) {
const debugRequests = [];
try {
const url = `https://comcipapic-oalprod.integration.ocp.oraclecloud.com/ic/builder/rt/SeaaS_initiation/live;profile=PROD/services/auth/1.1/proxy/oke_seaas/uri/https/gxpap.oracle.com/oalcrm/service/set/seaas/crm/lookups?lookupType=${lookupType}&type=STANDARD`;
const result = await fetchJson(url, { method: "GET", credentials: "include",
headers: { Accept: "application/json", Authorization: "Session" }
}, requestName, debugRequests);
if (!Array.isArray(result?.items) || result.items.some(item => typeof item?.code !== "string" || typeof item?.name !== "string")) throw new Error(`Invalid ${requestName} response.`);
const items = result.items.filter(item => item.enabledFlag !== "N")
.sort((a, b) => (Number(a.displaySequence) || 0) - (Number(b.displaySequence) || 0))
.map(({ code, name }) => ({ code, name }));
return { ok: true, items, debugRequests };
} catch (error) { error.debugRequests = debugRequests; throw error; }
}
async function requestSrLookupOpportunityBusiness(message) {
const debugRequests = [];
try {
if (typeof message.emailAddress !== "string" || !message.emailAddress.trim()) throw new Error("Current user email is unavailable.");
const url = "https://comcipapic-oalprod.integration.ocp.oraclecloud.com/ic/builder/rt/SeaaS_initiation/live;profile=PROD/services/auth/1.1/proxy/oke_seaas/uri/https/gxpap.oracle.com/oalcrm/service/set/seaas/crm/services"
+ `?emailAddress=${encodeURIComponent(message.emailAddress.trim())}&salesObject=OPPORTUNITY&serviceType=BUSINESS`;
const result = await fetchJson(url, { method: "GET", credentials: "include", headers: { Accept: "application/json", Authorization: "Session" } }, "requestSrLookupOpportunityBusiness", debugRequests);
if (!Array.isArray(result?.items) || result.items.some(item => !/^\d+$/.test(String(item?.Id ?? "")) || typeof item?.RecordName !== "string")) throw new Error("Invalid Services response.");
return { ok: true, items: result.items.map(({ Id, RecordName, Abstract_c }) => ({ Id: String(Id), RecordName, Abstract_c: Abstract_c == null ? "" : String(Abstract_c) })), debugRequests };
} catch (error) { error.debugRequests = debugRequests; throw error; }
}
return { requestLookupWithSession, requestInternalServiceRequest, requestSrLookupOpportunityBusiness,
prepareSession: sender => requestLookupWithSession(null, {}, sender, true),
requestSrLookupPrimaryPillar: () => requestLookup("SENGG_PRIMARY_PILLAR", "requestSrLookupPrimaryPillar"),
requestSrLookupLanguage: () => requestLookup("SENGG_LANGUAGE", "requestSrLookupLanguage"),
requestSrLookupTechPlatform: () => requestLookup("SENGG_TECH_PLATFORM", "requestSrLookupTechPlatform") };
}