Adjustment to API authentication with fallback in case the cookie is invalid or missing
This commit is contained in:
199
dist/firefox/content.js
vendored
199
dist/firefox/content.js
vendored
@@ -502,8 +502,98 @@
|
||||
}
|
||||
|
||||
async function requestTokenRelay() {
|
||||
const xsrfTokenSource = await getXsrfToken();
|
||||
const requestEntry = logRequestStart({
|
||||
let refreshResult = null;
|
||||
let refreshAttempted = false;
|
||||
|
||||
while (true) {
|
||||
const xsrfTokenSource = await getXsrfToken();
|
||||
|
||||
if (!xsrfTokenSource.token) {
|
||||
if (refreshAttempted) {
|
||||
const requestEntry = createTokenRelayRequestEntry(xsrfTokenSource, refreshResult);
|
||||
logRequestFailure(requestEntry, "XSRF token cookie not found after automatic refresh.");
|
||||
throw new Error("XSRF token cookie not found after automatic refresh.");
|
||||
}
|
||||
|
||||
refreshResult = await refreshXsrfCookie("missing-cookie");
|
||||
refreshAttempted = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const requestEntry = createTokenRelayRequestEntry(xsrfTokenSource, refreshResult);
|
||||
|
||||
try {
|
||||
const response = await fetch(TOKEN_RELAY_URL, {
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"x-xsrf-token": xsrfTokenSource.token
|
||||
}
|
||||
});
|
||||
|
||||
const responseBody = await readResponseBodyForDebug(response);
|
||||
|
||||
if (!response.ok) {
|
||||
logRequestSuccess(requestEntry, response, responseBody);
|
||||
|
||||
if (!refreshAttempted && isInvalidXsrfStatus(response.status)) {
|
||||
refreshResult = await refreshXsrfCookie(`tokenrelay-${response.status}`);
|
||||
refreshAttempted = true;
|
||||
requestEntry.metadata.xsrfRefresh = formatXsrfRefreshResult(refreshResult);
|
||||
renderDebugPanel();
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new Error(`Token relay failed with status ${response.status}.`);
|
||||
}
|
||||
|
||||
let responseData;
|
||||
|
||||
try {
|
||||
responseData = await response.json();
|
||||
} catch (error) {
|
||||
logRequestSuccess(requestEntry, response, responseBody);
|
||||
|
||||
if (!refreshAttempted) {
|
||||
refreshResult = await refreshXsrfCookie("tokenrelay-invalid-response");
|
||||
refreshAttempted = true;
|
||||
requestEntry.metadata.xsrfRefresh = formatXsrfRefreshResult(refreshResult);
|
||||
renderDebugPanel();
|
||||
continue;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (!responseData || typeof responseData.access_token !== "string" || !responseData.access_token) {
|
||||
logRequestSuccess(requestEntry, response, responseBody);
|
||||
|
||||
if (!refreshAttempted) {
|
||||
refreshResult = await refreshXsrfCookie("tokenrelay-missing-access-token");
|
||||
refreshAttempted = true;
|
||||
requestEntry.metadata.xsrfRefresh = formatXsrfRefreshResult(refreshResult);
|
||||
renderDebugPanel();
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new Error("Token relay response does not contain access_token.");
|
||||
}
|
||||
|
||||
logRequestSuccess(requestEntry, response, createDebugBody(JSON.stringify({
|
||||
...responseData,
|
||||
access_token: maskToken(responseData.access_token)
|
||||
}, null, 2)));
|
||||
|
||||
return responseData.access_token;
|
||||
} catch (error) {
|
||||
logRequestFailure(requestEntry, error.message || "Request failed.");
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createTokenRelayRequestEntry(xsrfTokenSource, refreshResult) {
|
||||
return logRequestStart({
|
||||
name: "requestTokenRelay",
|
||||
method: "GET",
|
||||
url: TOKEN_RELAY_URL,
|
||||
@@ -519,56 +609,25 @@
|
||||
xsrfLookupDetails: xsrfTokenSource.lookupDetails && xsrfTokenSource.lookupDetails.length
|
||||
? xsrfTokenSource.lookupDetails.join(" | ")
|
||||
: "(none)",
|
||||
xsrfTokenError: xsrfTokenSource.error || ""
|
||||
xsrfTokenError: xsrfTokenSource.error || "",
|
||||
xsrfRefresh: formatXsrfRefreshResult(refreshResult)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!xsrfTokenSource.token) {
|
||||
logRequestFailure(requestEntry, "XSRF token cookie not found.");
|
||||
throw new Error("XSRF token cookie not found.");
|
||||
function isInvalidXsrfStatus(status) {
|
||||
return status === 400 || status === 401 || status === 403;
|
||||
}
|
||||
|
||||
function formatXsrfRefreshResult(result) {
|
||||
if (!result) {
|
||||
return "not-requested";
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(TOKEN_RELAY_URL, {
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"x-xsrf-token": xsrfTokenSource.token
|
||||
}
|
||||
});
|
||||
|
||||
const responseBody = await readResponseBodyForDebug(response);
|
||||
|
||||
if (!response.ok) {
|
||||
logRequestSuccess(requestEntry, response, responseBody);
|
||||
throw new Error(`Token relay failed with status ${response.status}.`);
|
||||
}
|
||||
|
||||
let responseData;
|
||||
|
||||
try {
|
||||
responseData = await response.json();
|
||||
} catch (error) {
|
||||
logRequestSuccess(requestEntry, response, responseBody);
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (!responseData || typeof responseData.access_token !== "string" || !responseData.access_token) {
|
||||
logRequestSuccess(requestEntry, response, responseBody);
|
||||
throw new Error("Token relay response does not contain access_token.");
|
||||
}
|
||||
|
||||
logRequestSuccess(requestEntry, response, createDebugBody(JSON.stringify({
|
||||
...responseData,
|
||||
access_token: maskToken(responseData.access_token)
|
||||
}, null, 2)));
|
||||
|
||||
return responseData.access_token;
|
||||
} catch (error) {
|
||||
logRequestFailure(requestEntry, error.message || "Request failed.");
|
||||
|
||||
throw error;
|
||||
}
|
||||
const outcome = result.refreshed ? "refreshed" : "not-refreshed";
|
||||
const cookieName = result.cookieName || "(none)";
|
||||
const duration = Number.isFinite(result.durationMs) ? `${result.durationMs}ms` : "unknown";
|
||||
return `${result.reason}; ${outcome}; cookie=${cookieName}; duration=${duration}; ${result.error || ""}`.trim();
|
||||
}
|
||||
|
||||
async function requestOpportunitiesForPeriod(period) {
|
||||
@@ -2106,6 +2165,52 @@
|
||||
});
|
||||
}
|
||||
|
||||
function refreshXsrfCookie(reason) {
|
||||
const runtimeApi = typeof browser !== "undefined" ? browser : chrome;
|
||||
|
||||
if (!runtimeApi || !runtimeApi.runtime || !runtimeApi.runtime.sendMessage) {
|
||||
return Promise.resolve({
|
||||
ok: false,
|
||||
refreshed: false,
|
||||
cookieName: "",
|
||||
durationMs: 0,
|
||||
reason,
|
||||
error: "Runtime messaging API unavailable."
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
runtimeApi.runtime.sendMessage({
|
||||
type: "opportunitiesExtension.refreshXsrfCookie"
|
||||
}, (response) => {
|
||||
const lastError = runtimeApi.runtime.lastError;
|
||||
|
||||
if (lastError) {
|
||||
resolve({
|
||||
ok: false,
|
||||
refreshed: false,
|
||||
cookieName: "",
|
||||
durationMs: 0,
|
||||
reason,
|
||||
error: lastError.message
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
resolve({
|
||||
...(response || {
|
||||
ok: false,
|
||||
refreshed: false,
|
||||
cookieName: "",
|
||||
durationMs: 0,
|
||||
error: "Empty refresh response."
|
||||
}),
|
||||
reason
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function updateAuthBadge(status) {
|
||||
const badge = document.querySelector(`#${MODAL_ID} .opportunities-extension-auth-badge`);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user