Loading comcipapic to establish a session for SR requests
This commit is contained in:
@@ -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") };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user