aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-09-14 12:54:23 -0700
committerAdam Soltys <[email protected]>2026-09-14 12:54:23 -0700
commit1d87d0d36feea526f8f6bf4a62b012132bd36128 (patch)
tree60d93cc41bbdfbcf9b3a9adb3e8482a3bdd0ed91 /src
parent57191e941016f15a9c52de7e95e7bb2a04c9de13 (diff)
downloadcoinos-ui-1d87d0d36feea526f8f6bf4a62b012132bd36128.tar.gz
coinos-ui-1d87d0d36feea526f8f6bf4a62b012132bd36128.zip
register: start the session from the register response
/register now verifies the recaptcha token itself, and Google tokens are single-use — so the follow-up /login that reused the same token came back "failed captcha" for an account that had just been created. The register response already carries the JWT; set the session cookies from it and only fall back to /login when registration itself failed. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_0166Ci2XdCair1B9ych7w8dq
Diffstat (limited to 'src')
-rw-r--r--src/lib/utils.ts39
1 files changed, 30 insertions, 9 deletions
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index 14a1370e..b6bbdb53 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -172,8 +172,6 @@ export const login = async (
host?: string,
extraHeaders?: Record<string, string>,
) => {
- const maxAge = 380 * 24 * 60 * 60;
-
const headers: Record<string, string> = {
"content-type": "application/json",
accept: "application/json",
@@ -198,6 +196,18 @@ export const login = async (
const { user: u, token } = JSON.parse(text);
if (!token) throw new Error("Login failed");
+ setSession(cookies, user, u, token);
+};
+
+// Session cookies for a freshly issued JWT — shared by login and register,
+// which both get a token back from the server.
+const setSession = (
+ cookies,
+ user: { username: string; password: string },
+ u: { language?: string; nsec?: string },
+ token: string,
+) => {
+ const maxAge = 380 * 24 * 60 * 60;
const expires = new Date();
expires.setSeconds(expires.getSeconds() + maxAge);
@@ -507,19 +517,30 @@ export const register = async (user, ip, cookies, loginRedirect, host?, extraHea
};
if (ip) headers["cf-connecting-ip"] = ip;
- let sk;
+ let sk, token, u;
try {
- ({ sk } = await post("/register", { user }, headers));
+ ({ sk, token, ...u } = await post("/register", { user }, headers));
} catch (e) {
({ message: error } = e as Error);
}
- try {
- await login(user, cookies, ip, host, extraHeaders);
+ // /register verifies the recaptcha token itself now, and Google tokens
+ // are single-use: a follow-up /login carrying the same token comes back
+ // "failed captcha" for an account that was just created. The register
+ // response already includes the JWT, so start the session from it and
+ // only fall back to /login when registration failed (e.g. the username
+ // already exists and this is really a login).
+ if (token) {
+ setSession(cookies, user, u, token);
error = null;
- } catch (e) {
- const { message } = e as Error;
- error ||= message;
+ } else {
+ try {
+ await login(user, cookies, ip, host, extraHeaders);
+ error = null;
+ } catch (e) {
+ const { message } = e as Error;
+ error ||= message;
+ }
}
const expires = new Date();