From acd94921684759ac3d582ec87db7ceaeb2fefe45 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 5 Jan 2023 07:43:24 -0800 Subject: proxy to nostr api --- docker-compose.yml | 15 +++++++++++++++ lib/nostr.js | 32 ++++++++++++++++++++++---------- package.json | 2 ++ pnpm-lock.yaml | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ routes/events.js | 5 +++-- routes/users.js | 24 ++++++++++++++++++------ 6 files changed, 110 insertions(+), 18 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 4ab6ff37..8d61b689 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -220,6 +220,21 @@ services: networks: default: ipv4_address: 172.18.2.2 + api: + container_name: api + image: nostr-api + build: /home/adam/nostr-api + command: "pnpm dev" + volumes: + - "/home/adam/nostr-api:/app" + - "./config/nostr/data:/data" + environment: + DB: "/data/nostr.db" + ports: + - '9393:9393' + networks: + default: + ipv4_address: 172.18.2.4 networks: default: name: net diff --git a/lib/nostr.js b/lib/nostr.js index 285fdde2..8fc92be4 100644 --- a/lib/nostr.js +++ b/lib/nostr.js @@ -1,15 +1,29 @@ +import app from "$app"; +import config from "$config"; import { Relay, RelayPool } from "nostr"; import { got } from "got"; import { broadcast } from "$lib/sockets"; import store from "$lib/store"; import redis from "$lib/redis"; +import proxy from "@fastify/http-proxy"; -const relays = ["wss://relay.damus.io", "wss://nostr.coinos.io"]; +app.register(proxy, { + upstream: "http://api:9393", + prefix: "/nostr", + rewritePrefix: "", +}); + +const relays = [ + config.relay, + "wss://relay.damus.io", + "wss://nostr-pub.wellorder.net", + "wss://nostr.rocks", +]; export const pool = RelayPool(relays); pool.on("open", relay => { - if (relay.url.includes("coinos")) coinos = relay; + if (relay.url.includes(config.relay)) coinos = relay; relay.subscribe("live", { limit: 1 }); }); @@ -24,9 +38,9 @@ export let q = async (sub, query, timeout = 8000) => query.since = await redis.get(`since:${sub}`); if (now() - query.since < 3600) return r(); - coinos.on("eose", s => !rejected && s === sub && r(timeouts[sub].clear())); - - coinos.subscribe(sub, query); + coinos.on("eose", s => { + return !rejected && s === sub && r(timeouts[sub].clear()); + }); timeouts[sub] = { async clear() { @@ -47,6 +61,7 @@ export let q = async (sub, query, timeout = 8000) => }; timeouts[sub].extend(timeout); + coinos.subscribe(sub, query); }); let seen = []; @@ -79,11 +94,9 @@ pool.on("event", async (relay, sub, ev) => { seen.length > 1000 && seen.shift(); if (coinos && ev.kind < 5) { - coinos.send(["EVENT", ev]); - + // coinos.send(["EVENT", ev]); ev.user = await getUser(pubkey); - - broadcast("event", ev); + // broadcast("event", ev); } } else if (sub.includes("profile")) { let { pubkey } = ev; @@ -121,7 +134,6 @@ pool.on("event", async (relay, sub, ev) => { let pubkey = sub; ev.user = await getUser(pubkey); - // console.log(ev.user.username, "UPDATED AT", ev.user.updated) if (!ev.user.updated) { relay.subscribe(`${pubkey}:${ev.id}:profile`, { limit: 1, diff --git a/package.json b/package.json index 1bca9dba..ad806617 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "dev": "nodemon index.js" }, "dependencies": { + "@fastify/http-proxy": "^8.4.0", "@fastify/multipart": "^7.1.2", "@fastify/passport": "^2.2.0", "@fastify/secure-session": "^5.2.0", @@ -16,6 +17,7 @@ "async-mutex": "^0.2.4", "axios": "^0.21.1", "bcrypt": "^5.0.0", + "bech32": "^2.0.0", "bip32": "^2.0.5", "bip39": "^3.0.2", "bitcoinjs-lib": "6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b6722b1d..3bbe6727 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,6 +1,7 @@ lockfileVersion: 5.4 specifiers: + '@fastify/http-proxy': ^8.4.0 '@fastify/multipart': ^7.1.2 '@fastify/passport': ^2.2.0 '@fastify/secure-session': ^5.2.0 @@ -10,6 +11,7 @@ specifiers: async-mutex: ^0.2.4 axios: ^0.21.1 bcrypt: ^5.0.0 + bech32: ^2.0.0 bip32: ^2.0.5 bip39: ^3.0.2 bitcoinjs-lib: '6' @@ -65,6 +67,7 @@ specifiers: zeromq: 6.0.0-beta.6 dependencies: + '@fastify/http-proxy': 8.4.0 '@fastify/multipart': 7.2.0 '@fastify/passport': 2.2.0 '@fastify/secure-session': 5.2.0 @@ -74,6 +77,7 @@ dependencies: async-mutex: 0.2.6 axios: 0.21.4 bcrypt: 5.1.0 + bech32: 2.0.0 bip32: 2.0.6 bip39: 3.0.4 bitcoinjs-lib: 6.0.2 @@ -186,6 +190,16 @@ packages: fastify-plugin: 4.3.0 dev: false + /@fastify/http-proxy/8.4.0: + resolution: {integrity: sha512-H8nwsmawFtKKRE6uhh1BtF1gQi/l147SmLsDGxB0HdYTHzjXz6uSQO3lEVmY7unKMzbArRjdoJQkEGpScszdSw==} + dependencies: + '@fastify/reply-from': 8.3.1 + ws: 8.9.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + /@fastify/multipart/7.2.0: resolution: {integrity: sha512-LwfwbCLy30Be1pa5q7F8xCTygxJdEWkfkQhD4OWZ13+vMH4tP/6Bu3OkSTlFatxLAmbEl2UpHLf7CU7w7csRIw==} dependencies: @@ -206,6 +220,18 @@ packages: fastify-plugin: 4.3.0 dev: false + /@fastify/reply-from/8.3.1: + resolution: {integrity: sha512-fRByAvTMXuBuYIimcinukOB3YdmqtYPeoybXIBNY0aPVgetHkmCVffBo/M4pEOib9Pes8wuoYL4VawI65aHl4w==} + dependencies: + '@fastify/error': 3.0.0 + end-of-stream: 1.4.4 + fast-querystring: 1.0.0 + fastify-plugin: 4.3.0 + pump: 3.0.0 + tiny-lru: 10.0.1 + undici: 5.14.0 + dev: false + /@fastify/secure-session/5.2.0: resolution: {integrity: sha512-oRWKdHwWUzp4rsJ3GnR8w8doE+7vllWMtohBVp77bENkhm4/OvofaO6PJLJuQvKF7XJAKiGip29dX1RsllKT7g==} hasBin: true @@ -989,6 +1015,13 @@ packages: ieee754: 1.2.1 dev: false + /busboy/1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + dependencies: + streamsearch: 1.1.0 + dev: false + /bytes/3.0.0: resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} engines: {node: '>= 0.8'} @@ -4136,6 +4169,11 @@ packages: engines: {node: '>=4.0.0'} dev: false + /streamsearch/1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + dev: false + /strict-uri-encode/2.0.0: resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} engines: {node: '>=4'} @@ -4268,6 +4306,11 @@ packages: engines: {node: '>=8'} dev: false + /tiny-lru/10.0.1: + resolution: {integrity: sha512-Vst+6kEsWvb17Zpz14sRJV/f8bUWKhqm6Dc+v08iShmIJ/WxqWytHzCTd6m88pS33rE2zpX34TRmOpAJPloNCA==} + engines: {node: '>=6'} + dev: false + /tiny-lru/9.0.3: resolution: {integrity: sha512-/i9GruRjXsnDgehxvy6iZ4AFNVxngEFbwzirhdulomMNPGPVV3ECMZOWSw0w4sRMZ9Al9m4jy08GPvRxRUGYlw==} engines: {node: '>=6'} @@ -4394,6 +4437,13 @@ packages: resolution: {integrity: sha512-ekY1NhRzq0B08g4bGuX4wd2jZx5GnKz6mKSqFL4nqBlfyMGiG10gDFhDTMEfYmDL6Jy0FUIZp7wiRB+0BP7J2g==} dev: false + /undici/5.14.0: + resolution: {integrity: sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==} + engines: {node: '>=12.18'} + dependencies: + busboy: 1.6.0 + dev: false + /unique-filename/1.1.1: resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==} dependencies: diff --git a/routes/events.js b/routes/events.js index fd2d97cd..f09cea23 100644 --- a/routes/events.js +++ b/routes/events.js @@ -1,7 +1,7 @@ import app from "$app"; import db from "$db"; import redis from "$lib/redis"; -import { coinos, q } from "$lib/nostr"; +import { coinos, pool, q } from "$lib/nostr"; import store from "$lib/store"; import { wait } from "$lib/utils"; @@ -48,6 +48,7 @@ app.get("/nostr/:pubkey", async (req, res) => { app.post("/nostr/send", async (req, res) => { let { event } = req.body; - coinos.send(["EVENT", event]); + pool.send(["EVENT", event]); + console.log("SENDING", JSON.stringify(event)) res.send(event); }); diff --git a/routes/users.js b/routes/users.js index ff188fad..ae64997b 100644 --- a/routes/users.js +++ b/routes/users.js @@ -24,6 +24,9 @@ import register from "$lib/register"; import { requirePin } from "$lib/utils"; import { coinos, q } from "$lib/nostr"; import got from "got"; +import { bech32 } from "bech32"; + +const { encode, decode, fromWords, toWords } = bech32; const pick = (O, ...K) => K.reduce((o, k) => ((o[k] = O[k]), o), {}); @@ -61,7 +64,11 @@ app.get("/me", auth, async (req, res) => { app.get("/users/:username", async (req, res) => { try { - const { username } = req.params; + let { username } = req.params; + + if (username.startsWith("npub")) { + username = Buffer.from(fromWords(decode(username).words)).toString("hex") + } let user = await db.User.findOne({ attributes: [ @@ -72,10 +79,15 @@ app.get("/users/:username", async (req, res) => { "currency", "pubkey" ], - where: Sequelize.where( - Sequelize.fn("lower", Sequelize.col("username")), - username.toLowerCase() - ) + where: { + [Sequelize.Op.or]: [ + Sequelize.where( + Sequelize.fn("lower", Sequelize.col("username")), + username.toLowerCase() + ), + { pubkey: username } + ] + } }); if (user) user = user.get({ plain: true }); @@ -695,7 +707,7 @@ app.get("/:pubkey/followers", async (req, res) => { let { pubkey } = req.params; let pubkeys = await got( - `https://coinos.io/nostr/followers?pubkey=${pubkey}` + `${config.nostr}/followers?pubkey=${pubkey}` ).json(); let followers = []; -- cgit v1.2.3