Add access token fallback for cloud login
This commit is contained in:
parent
7bf5bcae43
commit
e1a80f5527
@ -609,6 +609,7 @@ dutyRunNow?.addEventListener("click", () => {
|
||||
runDutyNow();
|
||||
});
|
||||
|
||||
consumeRedirectedAccessToken();
|
||||
initializeApp();
|
||||
document.addEventListener("hotness:programs-changed", refreshPrograms);
|
||||
|
||||
@ -617,6 +618,17 @@ async function initializeApp() {
|
||||
startApp();
|
||||
}
|
||||
|
||||
function consumeRedirectedAccessToken() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const token = params.get("access_token");
|
||||
if (!token) return;
|
||||
localStorage.setItem(HOTNESS_AUTH_TOKEN_KEY, token);
|
||||
params.delete("access_token");
|
||||
const search = params.toString();
|
||||
const cleanUrl = `${window.location.pathname}${search ? `?${search}` : ""}${window.location.hash}`;
|
||||
history.replaceState(null, "", cleanUrl || "/");
|
||||
}
|
||||
|
||||
function startApp() {
|
||||
if (appStarted) return;
|
||||
appStarted = true;
|
||||
|
||||
@ -175,6 +175,7 @@ window.addEventListener("appinstalled", () => {
|
||||
updateInstallPrompt("installed");
|
||||
});
|
||||
|
||||
consumeRedirectedAccessToken();
|
||||
initializeApp();
|
||||
|
||||
async function initializeApp() {
|
||||
@ -182,6 +183,17 @@ async function initializeApp() {
|
||||
startApp();
|
||||
}
|
||||
|
||||
function consumeRedirectedAccessToken() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const token = params.get("access_token");
|
||||
if (!token) return;
|
||||
localStorage.setItem(HOTNESS_AUTH_TOKEN_KEY, token);
|
||||
params.delete("access_token");
|
||||
const search = params.toString();
|
||||
const cleanUrl = `${window.location.pathname}${search ? `?${search}` : ""}${window.location.hash}`;
|
||||
history.replaceState(null, "", cleanUrl || "/");
|
||||
}
|
||||
|
||||
async function startApp() {
|
||||
if (appStarted) return;
|
||||
appStarted = true;
|
||||
|
||||
@ -80,7 +80,7 @@ const server = http.createServer(async (request, response) => {
|
||||
const body = await readFormBody(request);
|
||||
if (!ACCESS_PASSWORD || timingSafeEqualText(String(body.password || ""), ACCESS_PASSWORD)) {
|
||||
if (ACCESS_PASSWORD) response.setHeader("set-cookie", cookieHeader(ACCESS_TOKEN));
|
||||
return sendRedirect(response, body.next || "/");
|
||||
return sendRedirect(response, buildAuthRedirectLocation(body.next || "/", ACCESS_TOKEN));
|
||||
}
|
||||
return sendRedirect(response, "/?auth_error=1");
|
||||
}
|
||||
@ -909,6 +909,14 @@ function cookieHeader(token) {
|
||||
return `hotness_auth=${encodeURIComponent(token)}; Path=/; SameSite=Lax; Max-Age=${60 * 60 * 24 * 30}`;
|
||||
}
|
||||
|
||||
function buildAuthRedirectLocation(location, token) {
|
||||
const safeLocation = String(location || "/").startsWith("/") ? String(location || "/") : "/";
|
||||
if (!token) return safeLocation;
|
||||
const redirectUrl = new URL(safeLocation, "http://video-hotness.local");
|
||||
redirectUrl.searchParams.set("access_token", token);
|
||||
return `${redirectUrl.pathname}${redirectUrl.search}${redirectUrl.hash}`;
|
||||
}
|
||||
|
||||
function timingSafeEqualText(left, right) {
|
||||
const leftBuffer = Buffer.from(String(left || ""));
|
||||
const rightBuffer = Buffer.from(String(right || ""));
|
||||
|
||||
@ -42,6 +42,14 @@ test("desktop login form is not blocked by JavaScript", () => {
|
||||
assert.doesNotMatch(desktopJs, /async function submitAccessPassword/);
|
||||
});
|
||||
|
||||
test("desktop can finish login from a redirected access token", () => {
|
||||
assert.match(server, /buildAuthRedirectLocation/);
|
||||
assert.match(server, /access_token/);
|
||||
assert.match(desktopJs, /consumeRedirectedAccessToken/);
|
||||
assert.match(desktopJs, /URLSearchParams/);
|
||||
assert.match(desktopJs, /history\.replaceState/);
|
||||
});
|
||||
|
||||
test("mobile page has the same password gate for cloud use", () => {
|
||||
assert.match(mobileHtml, /id="auth-gate"/);
|
||||
assert.match(mobileHtml, /action="\/auth\/login"/);
|
||||
@ -61,6 +69,12 @@ test("mobile login form is not blocked by JavaScript", () => {
|
||||
assert.doesNotMatch(mobileJs, /async function submitAccessPassword/);
|
||||
});
|
||||
|
||||
test("mobile can finish login from a redirected access token", () => {
|
||||
assert.match(mobileJs, /consumeRedirectedAccessToken/);
|
||||
assert.match(mobileJs, /URLSearchParams/);
|
||||
assert.match(mobileJs, /history\.replaceState/);
|
||||
});
|
||||
|
||||
test("ranking radar requests respect the shared cloud login token", () => {
|
||||
assert.match(rankingsJs, /HOTNESS_AUTH_TOKEN_KEY/);
|
||||
assert.match(rankingsJs, /authHeaders/);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user