From 87d01366d1de2a28c81ca56d9835ef00fbf8d7d5 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 5 Mar 2026 16:45:10 -0800 Subject: auth fix --- lib/ark.ts | 2 +- routes/users.ts | 26 +++++++++++++++++--------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/lib/ark.ts b/lib/ark.ts index dd35ca21..792ef142 100644 --- a/lib/ark.ts +++ b/lib/ark.ts @@ -120,7 +120,7 @@ export const refreshArkWallet = async (force = false) => { failedBoardingOutpoints.clear(); break; } catch (e: any) { - const retriable = /not enough intent confirmations/i.test(e.message); + const retriable = /not enough intent confirmations|timed out|signing_session/i.test(e.message); if (!retriable) failedBoardingOutpoints.add(outpointKey(utxo)); warn("ark onboard failed:", utxo.value, "sats:", e.message); } diff --git a/routes/users.ts b/routes/users.ts index f1f6a302..8dc384af 100644 --- a/routes/users.ts +++ b/routes/users.ts @@ -24,7 +24,7 @@ import { getPublicKey, nip19, verifyEvent } from "nostr-tools"; import { hexToBytes } from "@noble/hashes/utils.js"; import { authenticator } from "otplib"; import { v4 } from "uuid"; -import { setCookie } from "hono/cookie"; +import { getCookie, setCookie } from "hono/cookie"; import { setupBip353, teardownBip353 } from "$lib/bip353"; import { PaymentType } from "$lib/types"; @@ -230,7 +230,10 @@ export default { const user = c.get("user"); const body = await c.req.json(); try { - const { id: tokid } = jwt.verify(c.req.header("authorization").split(" ")[1], config.jwt); + const authHeader = c.req.header("authorization"); + const token = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : getCookie(c, "token"); + if (!token) fail("unauthorized"); + const { id: tokid } = jwt.verify(token, config.jwt); l("updating user", user.username, tokid); if (user.id !== tokid) fail("unauthorized"); @@ -257,13 +260,18 @@ export default { else fail("Key in use by another account"); } - const event = JSON.parse(body.event); - const challenge = event.tags.find((t) => t[0] === "challenge")[1]; - const ch = await g(`challenge:${challenge}`); - if (!ch) fail("Invalid or expired challenge"); - - if (!verifyEvent(event) || event.pubkey !== pubkey) - fail("Invalid signature or challenge mismatch."); + // Allow initial pubkey setting without signed event (e.g. during registration) + if (user.pubkey && body.event) { + const event = JSON.parse(body.event); + const challenge = event.tags.find((t) => t[0] === "challenge")[1]; + const ch = await g(`challenge:${challenge}`); + if (!ch) fail("Invalid or expired challenge"); + + if (!verifyEvent(event) || event.pubkey !== pubkey) + fail("Invalid signature or challenge mismatch."); + } else if (user.pubkey) { + fail("Signed event required to change pubkey"); + } pubkey = pubkey.replace(/\s*/g, ""); if (pubkey.length !== 64) fail(`Invalid pubkey ${pubkey}`); -- cgit v1.2.3