Fixed the SPA authentication flow
This commit is contained in:
@@ -57,30 +57,53 @@ function loadContent({ fetch = unexpectedFetch, storage = new Map(), xsrf = null
|
||||
};
|
||||
}
|
||||
|
||||
function loadBackground({ family = "chrome", fetch = unexpectedFetch, storage = {}, sessionStorage = {}, cookies = () => [], storageError = false, ruleError = false, messageTimeout = 2000 } = {}) {
|
||||
function loadBackground({ family = "chrome", fetch = unexpectedFetch, storage = {}, sessionStorage = {}, cookies = () => [], storageError = false, ruleError = false, updateTabError = false, messageTimeout = 2000 } = {}) {
|
||||
const time = clock();
|
||||
const listeners = [];
|
||||
const progress = [];
|
||||
const requestDebug = [];
|
||||
const tabs = [];
|
||||
const removedTabs = [];
|
||||
const updatedTabs = [];
|
||||
const cookieQueries = [];
|
||||
const headerListeners = [];
|
||||
const responseHeaderListeners = [];
|
||||
const headerRules = [];
|
||||
let spaDocument = 0;
|
||||
let identityRequest;
|
||||
const api = { runtime: { onMessage: { addListener: fn => listeners.push(fn) },
|
||||
getURL: path => `${family === "firefox" ? "moz" : "chrome"}-extension://synthetic-extension${path}` },
|
||||
webRequest: {
|
||||
onBeforeSendHeaders: { addListener: (listener, filter, options) => headerListeners.push({ listener, filter: plain(filter), options: plain(options) }) },
|
||||
onHeadersReceived: { addListener: (listener, filter, options) => responseHeaderListeners.push({ listener, filter: plain(filter), options: plain(options) }) }
|
||||
onHeadersReceived: {
|
||||
addListener: (listener, filter, options) => responseHeaderListeners.push({ listener, filter: plain(filter), options: plain(options) }),
|
||||
removeListener: listener => {
|
||||
const index = responseHeaderListeners.findIndex(item => item.listener === listener);
|
||||
if (index >= 0) responseHeaderListeners.splice(index, 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
declarativeNetRequest: { updateSessionRules: async rules => { if (ruleError) throw new Error("Rule permission denied"); headerRules.push(plain(rules)); } }
|
||||
};
|
||||
const readCookies = details => { cookieQueries.push(plain(details)); return cookies(details); };
|
||||
const getStored = key => ({ [key]: storage[key] === undefined ? undefined : plain(storage[key]) });
|
||||
const store = value => Object.assign(storage, plain(value));
|
||||
const openTab = details => { tabs.push(plain(details)); return { id: 91 }; };
|
||||
const newSpaDocument = () => { spaDocument++; identityRequest = null; };
|
||||
const openTab = details => { tabs.push(plain(details)); newSpaDocument(); return { id: 91 }; };
|
||||
const send = (tabId, message, options) => {
|
||||
if (message.type === "opportunitiesExtension.inspectSpaPage") return { status: "ready", documentId: String(spaDocument) };
|
||||
if (message.type === "opportunitiesExtension.readSpaIdentity") {
|
||||
assert.equal(message.documentId, String(spaDocument));
|
||||
if (!identityRequest) identityRequest = (async () => {
|
||||
try {
|
||||
const result = await fetch("https://spa.oracle.com/oalcrm/web/api/identity-management/users/current", {
|
||||
method: "GET", credentials: "include", cache: "no-store", headers: { Accept: "application/json" }
|
||||
});
|
||||
return { status: result.status, statusText: result.statusText, contentType: result.headers.get("content-type"), body: await result.text() };
|
||||
} catch (error) { return { error: error.message }; }
|
||||
})();
|
||||
return identityRequest;
|
||||
}
|
||||
const events = message.type === "opportunitiesExtension.opptyProductsRequestDebug" ? requestDebug : progress;
|
||||
events.push({ tabId, message: plain(message), options: plain(options || {}) });
|
||||
};
|
||||
@@ -91,6 +114,12 @@ function loadBackground({ family = "chrome", fetch = unexpectedFetch, storage =
|
||||
set: async value => { if (storageError) throw new Error("Storage unavailable"); store(value); }
|
||||
} };
|
||||
api.tabs = { create: async details => openTab(details), remove: async id => removedTabs.push(id),
|
||||
update: async (id, details) => {
|
||||
updatedTabs.push({ id, details: plain(details) });
|
||||
if (updateTabError) throw new Error("Synthetic navigation failure");
|
||||
newSpaDocument();
|
||||
return { id };
|
||||
},
|
||||
sendMessage: async (tabId, message, options) => send(tabId, message, options) };
|
||||
api.cookies = {
|
||||
get: async details => readCookies(details).find(cookie => cookie.name === details.name) || null,
|
||||
@@ -107,11 +136,17 @@ function loadBackground({ family = "chrome", fetch = unexpectedFetch, storage =
|
||||
set(value, callback) { withStorageError(() => { if (!storageError) store(value); callback(); }); }
|
||||
} };
|
||||
api.tabs = {
|
||||
update(id, details, callback) {
|
||||
updatedTabs.push({ id, details: plain(details) });
|
||||
api.runtime.lastError = updateTabError ? { message: "Synthetic navigation failure" } : undefined;
|
||||
if (!updateTabError) newSpaDocument();
|
||||
try { callback({ id }); } finally { delete api.runtime.lastError; }
|
||||
},
|
||||
create(details, callback) { callback(openTab(details)); },
|
||||
remove(id, callback) { removedTabs.push(id); callback(); },
|
||||
sendMessage(tabId, message, options, callback) {
|
||||
if (typeof options === "function") { callback = options; options = undefined; }
|
||||
send(tabId, message, options); callback();
|
||||
Promise.resolve(send(tabId, message, options)).then(callback);
|
||||
}
|
||||
};
|
||||
api.cookies = {
|
||||
@@ -126,7 +161,7 @@ function loadBackground({ family = "chrome", fetch = unexpectedFetch, storage =
|
||||
};
|
||||
const context = {
|
||||
[family === "firefox" ? "browser" : "chrome"]: api,
|
||||
fetch, URL, Date: time.Date,
|
||||
fetch, URL, Date: time.Date, clearTimeout,
|
||||
setTimeout: (callback, ms) => { time.advance(ms); return setTimeout(callback, 0); }
|
||||
};
|
||||
new vm.Script(composeScript("background"), { filename: "background.js" })
|
||||
@@ -146,7 +181,7 @@ function loadBackground({ family = "chrome", fetch = unexpectedFetch, storage =
|
||||
if (pending !== true) { clearTimeout(timer); reject(new Error("Expected asynchronous response contract")); }
|
||||
});
|
||||
}
|
||||
return { dispatch, listener: listeners[0], progress, requestDebug, tabs, removedTabs, cookieQueries, storage, sessionStorage, headerRules, headerListeners, responseHeaderListeners, advance: time.advance };
|
||||
return { dispatch, listener: listeners[0], progress, requestDebug, tabs, removedTabs, updatedTabs, cookieQueries, storage, sessionStorage, headerRules, headerListeners, responseHeaderListeners, advance: time.advance };
|
||||
}
|
||||
|
||||
module.exports = { root, plain, response, loadContent, loadBackground };
|
||||
|
||||
Reference in New Issue
Block a user