aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--index.ts4
-rw-r--r--routes/users.ts40
2 files changed, 42 insertions, 2 deletions
diff --git a/index.ts b/index.ts
index bd892f31..512d4af9 100644
--- a/index.ts
+++ b/index.ts
@@ -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;