aboutsummaryrefslogtreecommitdiffstats
path: root/routes
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-02-16 11:51:41 -0800
committerAdam Soltys <[email protected]>2026-02-16 11:51:41 -0800
commitee0513838b1d336fa60eb9a8f7ca1ce43e6d9e40 (patch)
tree04d097d676c4c0a48287f631a539b4055522dcfe /routes
parent20cee249905ee6975e88089b76b2eccb4019e19a (diff)
downloadcoinos-server-ee0513838b1d336fa60eb9a8f7ca1ce43e6d9e40.tar.gz
coinos-server-ee0513838b1d336fa60eb9a8f7ca1ce43e6d9e40.zip
passkey auth
Diffstat (limited to 'routes')
-rw-r--r--routes/payments.ts31
-rw-r--r--routes/users.ts58
2 files changed, 88 insertions, 1 deletions
diff --git a/routes/payments.ts b/routes/payments.ts
index 4bdd0d30..c77da697 100644
--- a/routes/payments.ts
+++ b/routes/payments.ts
@@ -933,8 +933,9 @@ export default {
async arkSync(req, res) {
try {
const { user } = req;
- const { transactions, aid } = req.body;
+ const { transactions = [], aid } = req.body;
const { id: uid } = user;
+ l("arkSync", user.username, aid, "txs:", transactions.length, "bal:", req.body.balance);
// Per-account lock prevents concurrent syncs from racing
const lockKey = `arksynclock:${aid}`;
@@ -1003,6 +1004,34 @@ export default {
}
}
+ // Reconcile expired VTXOs
+ const { balance } = req.body;
+ if (typeof balance === "number" && balance >= 0) {
+ const paymentIds = await db.lRange(`${aid}:payments`, 0, -1);
+ let expectedBalance = 0;
+ for (const pid of paymentIds) {
+ const pay = await g(`payment:${pid}`);
+ if (pay) expectedBalance += pay.amount;
+ }
+
+ if (expectedBalance > balance) {
+ const p = await createArkPayment({
+ aid,
+ uid,
+ amount: balance - expectedBalance,
+ hash: `expired-${Date.now()}`,
+ rate,
+ currency,
+ created: Date.now(),
+ extraHashMappings: [],
+ });
+ p.memo = "expired";
+ await s(`payment:${p.id}`, p);
+ payments.push(p);
+ synced++;
+ }
+ }
+
// Check for pending custodial ark invoice to forward
let forward;
if (received > 0) {
diff --git a/routes/users.ts b/routes/users.ts
index 904a5bb0..8d67444d 100644
--- a/routes/users.ts
+++ b/routes/users.ts
@@ -6,6 +6,12 @@ import { db, g, ga, gf, s, scan } from "$lib/db";
import { err, l, warn } from "$lib/logging";
import { mail, templates } from "$lib/mail";
import { getNostrUser, getProfile, serverPubkey2 } from "$lib/nostr";
+import {
+ generatePasskeyRegistration,
+ verifyPasskeyRegistration,
+ generatePasskeyLogin,
+ verifyPasskeyLogin,
+} from "$lib/passkey";
import register from "$lib/register";
import { emit } from "$lib/sockets";
import upload from "$lib/upload";
@@ -1164,6 +1170,58 @@ export default {
res.send({});
},
+ async passkeyRegisterOptions(req, res) {
+ try {
+ const { user } = req;
+ const origin = req.body.origin || `https://${config.hostname}`;
+ const options = await generatePasskeyRegistration(user, origin);
+ res.send(options);
+ } catch (e) {
+ console.log(e);
+ bail(res, e.message);
+ }
+ },
+
+ async passkeyRegisterVerify(req, res) {
+ try {
+ const { user } = req;
+ const origin = req.body.origin || `https://${config.hostname}`;
+ const credential = await verifyPasskeyRegistration(user, req.body, origin);
+ if (!user.passkeys) user.passkeys = [];
+ user.passkeys.push(credential);
+ await s(`user:${user.id}`, user);
+ res.send({ ok: true });
+ } catch (e) {
+ console.log(e);
+ bail(res, e.message);
+ }
+ },
+
+ async passkeyLoginOptions(req, res) {
+ try {
+ const origin = req.body.origin || `https://${config.hostname}`;
+ const options = await generatePasskeyLogin(origin);
+ res.send(options);
+ } catch (e) {
+ console.log(e);
+ bail(res, e.message);
+ }
+ },
+
+ async passkeyLoginVerify(req, res) {
+ try {
+ const { credential, challengeId, origin: reqOrigin } = req.body;
+ const origin = reqOrigin || `https://${config.hostname}`;
+ const user = await verifyPasskeyLogin(credential, challengeId, origin);
+ const payload = { id: user.id };
+ const token = jwt.sign(payload, config.jwt);
+ res.send({ user: pick(user, whitelist), token });
+ } catch (e) {
+ console.log(e);
+ bail(res, e.message);
+ }
+ },
+
async credits(req, res) {
const { id } = req.user;
const bitcoin = await getCredit(id, "bitcoin");