diff options
| -rw-r--r-- | index.ts | 4 | ||||
| -rw-r--r-- | routes/users.ts | 40 |
2 files changed, 42 insertions, 2 deletions
@@ -109,6 +109,8 @@ app.post("/request", auth, users.request); app.post("/forgot", users.forgot); app.post("/login", users.login); app.post("/printer", users.printer); +app.get("/challenge", users.challenge); +app.post("/nostrLogin", users.nostrLogin); app.get("/subscriptions", auth, users.subscriptions); app.post("/subscription", auth, users.subscription); @@ -137,7 +139,7 @@ app.post("/mint", auth, ecash.mint); app.post("/melt", auth, ecash.melt); app.post("/ecash/:id", ecash.receive); -app.get("/replay/:index", (req,res) => { +app.get("/replay/:index", (req, res) => { replay(req.params.index); res.send({}); }); diff --git a/routes/users.ts b/routes/users.ts index 5c5f1a6f..87797cce 100644 --- a/routes/users.ts +++ b/routes/users.ts @@ -15,7 +15,7 @@ import whitelist from "$lib/whitelist"; import rpc from "@coinos/rpc"; import { $ } from "bun"; import jwt from "jsonwebtoken"; -import { nip19 } from "nostr-tools"; +import { nip19, verifyEvent } from "nostr-tools"; import { authenticator } from "otplib"; import { v4 } from "uuid"; @@ -355,6 +355,44 @@ export default { } }, + async challenge(_, res) { + const id = v4(); + await db.set(`challenge:${id}`, id, { EX: 300 }); + res.send({ id }); + }, + + async nostrLogin(req, res) { + try { + const { event, id, twofa } = req.body; + const challenge = await g(`challenge:${id}`); + if (!challenge) fail("Invalid or expired login challenge"); + + if (!verifyEvent(event) || event.content !== id) + fail("Invalid signature or challenge mismatch."); + + let user = await getUser(event.pubkey); + const { username } = user; + l("logging in", username, req.headers["cf-connecting-ip"]); + + if ( + user.twofa && + (typeof twofa === "undefined" || + !authenticator.check(twofa, user.otpsecret)) + ) { + return res.code(401).send("2fa required"); + } + + const payload = { id: user.id }; + const token = jwt.sign(payload, config.jwt); + res.cookie("token", token, { expires: new Date(Date.now() + 432000000) }); + user = pick(user, whitelist); + res.send({ user, token }); + } catch (e) { + err("login error", e.message, req.socket.remoteAddress); + res.code(401).send({}); + } + }, + async subscriptions(req, res) { try { const { user } = req; |
