Use native form login for cloud password
This commit is contained in:
parent
da5533b5cb
commit
7bf5bcae43
@ -1,8 +1,6 @@
|
|||||||
const HOTNESS_AUTH_TOKEN_KEY = "video-hotness-auth-token-v1";
|
const HOTNESS_AUTH_TOKEN_KEY = "video-hotness-auth-token-v1";
|
||||||
const authGate = document.querySelector("#auth-gate");
|
const authGate = document.querySelector("#auth-gate");
|
||||||
const authForm = document.querySelector("#auth-form");
|
|
||||||
const authPassword = document.querySelector("#auth-password");
|
const authPassword = document.querySelector("#auth-password");
|
||||||
const authSubmit = document.querySelector("#auth-submit");
|
|
||||||
const authMessage = document.querySelector("#auth-message");
|
const authMessage = document.querySelector("#auth-message");
|
||||||
const form = document.querySelector("#collect-form");
|
const form = document.querySelector("#collect-form");
|
||||||
const input = document.querySelector("#program-name");
|
const input = document.querySelector("#program-name");
|
||||||
@ -111,17 +109,6 @@ let resolveTimer = 0;
|
|||||||
let resolveRequestId = 0;
|
let resolveRequestId = 0;
|
||||||
let temporaryQueryItems = [];
|
let temporaryQueryItems = [];
|
||||||
let appStarted = false;
|
let appStarted = false;
|
||||||
let authSubmitting = false;
|
|
||||||
|
|
||||||
authForm?.addEventListener("submit", async (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
await submitAccessPassword();
|
|
||||||
});
|
|
||||||
|
|
||||||
authSubmit?.addEventListener("click", async (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
await submitAccessPassword();
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const [platform, element] of Object.entries(urlInputs)) {
|
for (const [platform, element] of Object.entries(urlInputs)) {
|
||||||
element.addEventListener("input", () => {
|
element.addEventListener("input", () => {
|
||||||
@ -2144,38 +2131,6 @@ async function ensureAccessAuth() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitAccessPassword() {
|
|
||||||
if (authSubmitting) return;
|
|
||||||
const password = authPassword?.value || "";
|
|
||||||
if (!password.trim()) {
|
|
||||||
showAuthGate("请输入访问密码");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
authSubmitting = true;
|
|
||||||
if (authSubmit) authSubmit.disabled = true;
|
|
||||||
setAuthMessage("正在验证...");
|
|
||||||
try {
|
|
||||||
const response = await fetch("/api/auth/login", {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "content-type": "application/json" },
|
|
||||||
body: JSON.stringify({ password }),
|
|
||||||
});
|
|
||||||
const payload = await response.json();
|
|
||||||
if (!response.ok) throw new Error(payload.error || "访问密码不正确");
|
|
||||||
if (payload.token) localStorage.setItem(HOTNESS_AUTH_TOKEN_KEY, payload.token);
|
|
||||||
window.dispatchEvent(new CustomEvent("hotness:auth-updated"));
|
|
||||||
if (authPassword) authPassword.value = "";
|
|
||||||
setAuthMessage("登录成功,正在进入...");
|
|
||||||
hideAuthGate();
|
|
||||||
startApp();
|
|
||||||
} catch (error) {
|
|
||||||
showAuthGate(error.message || "访问密码不正确");
|
|
||||||
} finally {
|
|
||||||
authSubmitting = false;
|
|
||||||
if (authSubmit) authSubmit.disabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function authHeaders() {
|
function authHeaders() {
|
||||||
const token = localStorage.getItem(HOTNESS_AUTH_TOKEN_KEY) || "";
|
const token = localStorage.getItem(HOTNESS_AUTH_TOKEN_KEY) || "";
|
||||||
return token ? { "x-hotness-auth-token": token } : {};
|
return token ? { "x-hotness-auth-token": token } : {};
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
const HOTNESS_AUTH_TOKEN_KEY = "video-hotness-auth-token-v1";
|
const HOTNESS_AUTH_TOKEN_KEY = "video-hotness-auth-token-v1";
|
||||||
const authGate = document.querySelector("#auth-gate");
|
const authGate = document.querySelector("#auth-gate");
|
||||||
const authForm = document.querySelector("#auth-form");
|
|
||||||
const authPassword = document.querySelector("#auth-password");
|
const authPassword = document.querySelector("#auth-password");
|
||||||
const authSubmit = document.querySelector("#auth-submit");
|
|
||||||
const authMessage = document.querySelector("#auth-message");
|
const authMessage = document.querySelector("#auth-message");
|
||||||
const form = document.querySelector("#collect-form");
|
const form = document.querySelector("#collect-form");
|
||||||
const input = document.querySelector("#program-name");
|
const input = document.querySelector("#program-name");
|
||||||
@ -63,17 +61,6 @@ let activeName = "";
|
|||||||
let dirtyUrlInputs = new Set();
|
let dirtyUrlInputs = new Set();
|
||||||
let deferredInstallPrompt = null;
|
let deferredInstallPrompt = null;
|
||||||
let appStarted = false;
|
let appStarted = false;
|
||||||
let authSubmitting = false;
|
|
||||||
|
|
||||||
authForm?.addEventListener("submit", async (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
await submitAccessPassword();
|
|
||||||
});
|
|
||||||
|
|
||||||
authSubmit?.addEventListener("click", async (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
await submitAccessPassword();
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const [platform, element] of Object.entries(urlInputs)) {
|
for (const [platform, element] of Object.entries(urlInputs)) {
|
||||||
element.addEventListener("input", () => {
|
element.addEventListener("input", () => {
|
||||||
@ -740,38 +727,6 @@ async function ensureAccessAuth() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitAccessPassword() {
|
|
||||||
if (authSubmitting) return;
|
|
||||||
const password = authPassword?.value || "";
|
|
||||||
if (!password.trim()) {
|
|
||||||
showAuthGate("请输入访问密码");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
authSubmitting = true;
|
|
||||||
if (authSubmit) authSubmit.disabled = true;
|
|
||||||
setAuthMessage("正在验证...");
|
|
||||||
try {
|
|
||||||
const response = await fetch(apiUrl("/api/auth/login"), {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "content-type": "application/json" },
|
|
||||||
body: JSON.stringify({ password }),
|
|
||||||
});
|
|
||||||
const payload = await response.json();
|
|
||||||
if (!response.ok) throw new Error(payload.error || "访问密码不正确");
|
|
||||||
if (payload.token) localStorage.setItem(HOTNESS_AUTH_TOKEN_KEY, payload.token);
|
|
||||||
window.dispatchEvent(new CustomEvent("hotness:auth-updated"));
|
|
||||||
if (authPassword) authPassword.value = "";
|
|
||||||
setAuthMessage("登录成功,正在进入...");
|
|
||||||
hideAuthGate();
|
|
||||||
await startApp();
|
|
||||||
} catch (error) {
|
|
||||||
showAuthGate(error.message || "访问密码不正确");
|
|
||||||
} finally {
|
|
||||||
authSubmitting = false;
|
|
||||||
if (authSubmit) authSubmit.disabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function authHeaders() {
|
function authHeaders() {
|
||||||
const token = localStorage.getItem(HOTNESS_AUTH_TOKEN_KEY) || "";
|
const token = localStorage.getItem(HOTNESS_AUTH_TOKEN_KEY) || "";
|
||||||
return token ? { "x-hotness-auth-token": token } : {};
|
return token ? { "x-hotness-auth-token": token } : {};
|
||||||
|
|||||||
@ -36,15 +36,10 @@ test("desktop page has a password gate and sends auth token with API calls", ()
|
|||||||
assert.match(desktopCss, /\.auth-gate/);
|
assert.match(desktopCss, /\.auth-gate/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("desktop login submit is bound before the rest of the app can fail", () => {
|
test("desktop login form is not blocked by JavaScript", () => {
|
||||||
const authBinding = desktopJs.indexOf('authForm?.addEventListener("submit"');
|
assert.doesNotMatch(desktopJs, /authForm\?\.addEventListener\("submit"/);
|
||||||
const authClickBinding = desktopJs.indexOf('authSubmit?.addEventListener("click"');
|
assert.doesNotMatch(desktopJs, /authSubmit\?\.addEventListener\("click"/);
|
||||||
const collectBinding = desktopJs.indexOf('form.addEventListener("submit"');
|
assert.doesNotMatch(desktopJs, /async function submitAccessPassword/);
|
||||||
assert.ok(authBinding > -1, "auth submit binding should exist");
|
|
||||||
assert.ok(authClickBinding > -1, "auth button click binding should exist");
|
|
||||||
assert.ok(collectBinding > -1, "collect submit binding should exist");
|
|
||||||
assert.ok(authBinding < collectBinding, "auth binding must run before normal app bindings");
|
|
||||||
assert.ok(authClickBinding < collectBinding, "auth click binding must run before normal app bindings");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("mobile page has the same password gate for cloud use", () => {
|
test("mobile page has the same password gate for cloud use", () => {
|
||||||
@ -60,15 +55,10 @@ test("mobile page has the same password gate for cloud use", () => {
|
|||||||
assert.match(mobileCss, /\.auth-gate/);
|
assert.match(mobileCss, /\.auth-gate/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("mobile login submit is bound before normal capture events", () => {
|
test("mobile login form is not blocked by JavaScript", () => {
|
||||||
const authBinding = mobileJs.indexOf('authForm?.addEventListener("submit"');
|
assert.doesNotMatch(mobileJs, /authForm\?\.addEventListener\("submit"/);
|
||||||
const authClickBinding = mobileJs.indexOf('authSubmit?.addEventListener("click"');
|
assert.doesNotMatch(mobileJs, /authSubmit\?\.addEventListener\("click"/);
|
||||||
const collectBinding = mobileJs.indexOf('form.addEventListener("submit"');
|
assert.doesNotMatch(mobileJs, /async function submitAccessPassword/);
|
||||||
assert.ok(authBinding > -1, "auth submit binding should exist");
|
|
||||||
assert.ok(authClickBinding > -1, "auth button click binding should exist");
|
|
||||||
assert.ok(collectBinding > -1, "collect submit binding should exist");
|
|
||||||
assert.ok(authBinding < collectBinding, "auth binding must run before normal app bindings");
|
|
||||||
assert.ok(authClickBinding < collectBinding, "auth click binding must run before normal app bindings");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("ranking radar requests respect the shared cloud login token", () => {
|
test("ranking radar requests respect the shared cloud login token", () => {
|
||||||
@ -78,7 +68,3 @@ test("ranking radar requests respect the shared cloud login token", () => {
|
|||||||
assert.match(rankingsJs, /requires_auth/);
|
assert.match(rankingsJs, /requires_auth/);
|
||||||
assert.match(rankingsJs, /hotness:auth-updated/);
|
assert.match(rankingsJs, /hotness:auth-updated/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("desktop login notifies secondary modules after auth succeeds", () => {
|
|
||||||
assert.match(desktopJs, /hotness:auth-updated/);
|
|
||||||
});
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user