From 26a2e48a8cf2d1a3d61765548c7bc8b3c2a06583 Mon Sep 17 00:00:00 2001 From: David McFadzean Date: Tue, 24 Oct 2023 09:10:29 -0400 Subject: [PATCH 1/3] Added strfry nostr-relay --- .gitignore | 1 + docker-compose.yml | 9 ++ nostr.js | 62 +++++++++++ nostr/strfry.conf | 138 ++++++++++++++++++++++++ package-lock.json | 259 +++++++++++++++++++++++++++++++++++++++++++-- package.json | 5 +- test-nostr.js | 10 ++ xidb.js | 2 +- 8 files changed, 474 insertions(+), 12 deletions(-) create mode 100644 nostr.js create mode 100644 nostr/strfry.conf create mode 100644 test-nostr.js diff --git a/.gitignore b/.gitignore index 9ad985b..fda10bd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Custom ignores data/ frontend/build/ +nostr/strfry-db # Logs logs diff --git a/docker-compose.yml b/docker-compose.yml index a2b3db0..88f32d1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -47,3 +47,12 @@ services: - ./data:/data depends_on: - ipfs + + strfry: + container_name: strfry + image: dockurr/strfry:latest + ports: + - 7777:7777 + volumes: + - ./nostr/strfry-db:/app/strfry-db + - ./nostr/strfry.conf:/etc/strfry.conf diff --git a/nostr.js b/nostr.js new file mode 100644 index 0000000..e42b296 --- /dev/null +++ b/nostr.js @@ -0,0 +1,62 @@ + +const { WebSocket } = require('websocket-polyfill'); + +const { + finishEvent, + relayInit, + validateEvent, + verifySignature, + getSignature, + getEventHash, + getPublicKey +} = require('nostr-tools'); + + +const config = { + nostr_relay: 'strfry:7777', + nostr_sk: '80ac742bbc82d1b53fb9518d20beb32545e0265b184a007e57c00da8f81f3973', +}; + +config.nostr_pk = getPublicKey(config.nostr_sk); + +const sendMessage = async (message) => { + let event = { + kind: 1, + created_at: Math.floor(Date.now() / 1000), + tags: [], + content: message, + pubkey: getPublicKey(config.nostr_sk), + }; + + finishEvent(event, config.nostr_sk); + + let ok = validateEvent(event); + let veryOk = verifySignature(event); + + console.log('Event:', event); + console.log('Validation result:', ok); + console.log('Signature verification result:', veryOk); +}; + +const tryConnect = async () => { + + //const relay = relayInit('wss://taranis.local:4848'); + const relay = relayInit('wss://localhost:7777'); + + relay.on('connect', () => { + console.log(`connected to ${relay.url}`); + }); + + relay.on('error', () => { + console.log(`failed to connect to ${relay.url}`); S + }); + + await relay.connect(); + + return relay; +}; + +module.exports = { + sendMessage, + tryConnect, +}; diff --git a/nostr/strfry.conf b/nostr/strfry.conf new file mode 100644 index 0000000..e643878 --- /dev/null +++ b/nostr/strfry.conf @@ -0,0 +1,138 @@ +## +## Default strfry config +## + +# Directory that contains the strfry LMDB database (restart required) +db = "./strfry-db/" + +dbParams { + # Maximum number of threads/processes that can simultaneously have LMDB transactions open (restart required) + maxreaders = 256 + + # Size of mmap() to use when loading LMDB (default is 10TB, does *not* correspond to disk-space used) (restart required) + mapsize = 10995116277760 + + # Disables read-ahead when accessing the LMDB mapping. Reduces IO activity when DB size is larger than RAM. (restart required) + noReadAhead = false +} + +events { + # Maximum size of normalised JSON, in bytes + maxEventSize = 65536 + + # Events newer than this will be rejected + rejectEventsNewerThanSeconds = 900 + + # Events older than this will be rejected + rejectEventsOlderThanSeconds = 94608000 + + # Ephemeral events older than this will be rejected + rejectEphemeralEventsOlderThanSeconds = 60 + + # Ephemeral events will be deleted from the DB when older than this + ephemeralEventsLifetimeSeconds = 300 + + # Maximum number of tags allowed + maxNumTags = 2000 + + # Maximum size for tag values, in bytes + maxTagValSize = 1024 +} + +relay { + # Interface to listen on. Use 0.0.0.0 to listen on all interfaces (restart required) + bind = "127.0.0.1" + + # Port to open for the nostr websocket protocol (restart required) + port = 7777 + + # Set OS-limit on maximum number of open files/sockets (if 0, don't attempt to set) (restart required) + nofiles = 1000000 + + # HTTP header that contains the client's real IP, before reverse proxying (ie x-real-ip) (MUST be all lower-case) + realIpHeader = "" + + info { + # NIP-11: Name of this server. Short/descriptive (< 30 characters) + name = "strfry default" + + # NIP-11: Detailed information about relay, free-form + description = "This is a strfry instance." + + # NIP-11: Administrative nostr pubkey, for contact purposes + pubkey = "" + + # NIP-11: Alternative administrative contact (email, website, etc) + contact = "" + } + + # Maximum accepted incoming websocket frame size (should be larger than max event) (restart required) + maxWebsocketPayloadSize = 131072 + + # Websocket-level PING message frequency (should be less than any reverse proxy idle timeouts) (restart required) + autoPingSeconds = 55 + + # If TCP keep-alive should be enabled (detect dropped connections to upstream reverse proxy) + enableTcpKeepalive = false + + # How much uninterrupted CPU time a REQ query should get during its DB scan + queryTimesliceBudgetMicroseconds = 10000 + + # Maximum records that can be returned per filter + maxFilterLimit = 500 + + # Maximum number of subscriptions (concurrent REQs) a connection can have open at any time + maxSubsPerConnection = 20 + + writePolicy { + # If non-empty, path to an executable script that implements the writePolicy plugin logic + plugin = "" + } + + compression { + # Use permessage-deflate compression if supported by client. Reduces bandwidth, but slight increase in CPU (restart required) + enabled = true + + # Maintain a sliding window buffer for each connection. Improves compression, but uses more memory (restart required) + slidingWindow = true + } + + logging { + # Dump all incoming messages + dumpInAll = false + + # Dump all incoming EVENT messages + dumpInEvents = false + + # Dump all incoming REQ/CLOSE messages + dumpInReqs = false + + # Log performance metrics for initial REQ database scans + dbScanPerf = false + + # Log reason for invalid event rejection? Can be disabled to silence excessive logging + invalidEvents = true + } + + numThreads { + # Ingester threads: route incoming requests, validate events/sigs (restart required) + ingester = 3 + + # reqWorker threads: Handle initial DB scan for events (restart required) + reqWorker = 3 + + # reqMonitor threads: Handle filtering of new events (restart required) + reqMonitor = 3 + + # negentropy threads: Handle negentropy protocol messages (restart required) + negentropy = 2 + } + + negentropy { + # Support negentropy protocol messages + enabled = true + + # Maximum records that sync will process before returning an error + maxSyncEvents = 1000000 + } +} diff --git a/package-lock.json b/package-lock.json index 2b2f454..741c350 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,13 +19,16 @@ "morgan": "^1.10.0", "multer": "^1.4.5-lts.1", "node-cron": "^3.0.2", + "nostr-tools": "^1.17.0", "passport": "^0.6.0", "passport-lnurl-auth": "^1.5.1", "path": "^0.12.7", "rimraf": "^5.0.1", "serve-static": "^1.15.0", "sharp": "^0.32.1", - "uuid": "^9.0.0" + "uuid": "^9.0.0", + "websocket-polyfill": "^0.0.3", + "ws": "^8.14.2" } }, "node_modules/@aws-crypto/sha256-js": { @@ -176,16 +179,35 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/@noble/ciphers": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.2.0.tgz", + "integrity": "sha512-6YBxJDAapHSdd3bLDv6x2wRPwq4QFMUaB3HvljNBUTThDd12eSm7/3F+2lnfzx2jvM+S6Nsy0jEt9QbPqSwqRw==", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", + "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", + "dependencies": { + "@noble/hashes": "1.3.1" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@noble/hashes": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz", - "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", + "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", @@ -196,6 +218,42 @@ "node": ">=14" } }, + "node_modules/@scure/base": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@scure/bip32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.1.tgz", + "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==", + "dependencies": { + "@noble/curves": "~1.1.0", + "@noble/hashes": "~1.3.1", + "@scure/base": "~1.1.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", + "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", + "dependencies": { + "@noble/hashes": "~1.3.0", + "@scure/base": "~1.1.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@smithy/types": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@smithy/types/-/types-1.1.0.tgz", @@ -575,6 +633,18 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, + "node_modules/bufferutil": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", + "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, "node_modules/builtin-status-codes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", @@ -795,6 +865,15 @@ "node": ">= 8" } }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -961,11 +1040,44 @@ "once": "^1.4.0" } }, + "node_modules/es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, "node_modules/es6-object-assign": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", "integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==" }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1067,6 +1179,19 @@ "node": ">= 0.6" } }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==" + }, "node_modules/filelist": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", @@ -1570,6 +1695,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, "node_modules/is-url": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", @@ -2071,6 +2201,11 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + }, "node_modules/node-abi": { "version": "3.43.0", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.43.0.tgz", @@ -2116,6 +2251,27 @@ "node-gyp-build-test": "build-test.js" } }, + "node_modules/nostr-tools": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/nostr-tools/-/nostr-tools-1.17.0.tgz", + "integrity": "sha512-LZmR8GEWKZeElbFV5Xte75dOeE9EFUW/QLI1Ncn3JKn0kFddDKEfBbFN8Mu4TMs+L4HR/WTPha2l+PPuRnJcMw==", + "dependencies": { + "@noble/ciphers": "0.2.0", + "@noble/curves": "1.1.0", + "@noble/hashes": "1.3.1", + "@scure/base": "1.1.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -3101,6 +3257,11 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==" }, + "node_modules/tstl": { + "version": "2.5.13", + "resolved": "https://registry.npmjs.org/tstl/-/tstl-2.5.13.tgz", + "integrity": "sha512-h9wayHHFI5+yqt8iau0vqH96cTNhezhZ/Fk/hrIdpfkiMu3lg9nzyvMfs5bIdX51IVzZO6DudLqhkL/rVXpT6g==" + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -3112,6 +3273,11 @@ "node": "*" } }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -3129,6 +3295,14 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, "node_modules/typeforce": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz", @@ -3170,6 +3344,18 @@ "node": ">= 0.8" } }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, "node_modules/util": { "version": "0.10.4", "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", @@ -3220,6 +3406,31 @@ "node": ">= 0.8" } }, + "node_modules/websocket": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", + "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", + "dependencies": { + "bufferutil": "^4.0.1", + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "typedarray-to-buffer": "^3.1.5", + "utf-8-validate": "^5.0.2", + "yaeti": "^0.0.6" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/websocket-polyfill": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/websocket-polyfill/-/websocket-polyfill-0.0.3.tgz", + "integrity": "sha512-pF3kR8Uaoau78MpUmFfzbIRxXj9PeQrCuPepGE6JIsfsJ/o/iXr07Q2iQNzKSSblQJ0FiGWlS64N4pVSm+O3Dg==", + "dependencies": { + "tstl": "^2.0.7", + "websocket": "^1.0.28" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -3298,6 +3509,26 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "node_modules/ws": { + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -3311,6 +3542,14 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" }, + "node_modules/yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", + "engines": { + "node": ">=0.10.32" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/package.json b/package.json index 68c43a5..d893a4a 100644 --- a/package.json +++ b/package.json @@ -22,12 +22,15 @@ "morgan": "^1.10.0", "multer": "^1.4.5-lts.1", "node-cron": "^3.0.2", + "nostr-tools": "^1.17.0", "passport": "^0.6.0", "passport-lnurl-auth": "^1.5.1", "path": "^0.12.7", "rimraf": "^5.0.1", "serve-static": "^1.15.0", "sharp": "^0.32.1", - "uuid": "^9.0.0" + "uuid": "^9.0.0", + "websocket-polyfill": "^0.0.3", + "ws": "^8.14.2" } } diff --git a/test-nostr.js b/test-nostr.js new file mode 100644 index 0000000..d5fd34b --- /dev/null +++ b/test-nostr.js @@ -0,0 +1,10 @@ +const nostr = require('./nostr'); + +console.log('nostr-test'); + +async function main() { + await nostr.sendMessage('hello!'); + await nostr.tryConnect(); +} + +main(); diff --git a/xidb.js b/xidb.js index 444e0d1..4044993 100644 --- a/xidb.js +++ b/xidb.js @@ -6,7 +6,7 @@ const crypto = require('crypto'); const uuid = require('uuid'); const bs58 = require('bs58'); const ejs = require('ejs'); -const { rimrafSync } = require('rimraf') +const { rimrafSync } = require('rimraf'); const config = require('./config'); const lnbits = require('./lnbits'); From aceabaf832fd61dab1412d2fada721372471bac3 Mon Sep 17 00:00:00 2001 From: David McFadzean Date: Tue, 24 Oct 2023 13:59:56 -0400 Subject: [PATCH 2/3] Working nostr-test --- nostr.js | 79 ++++++++++++++++++++++++------ nostr/strfry.conf | 9 ++-- package-lock.json | 121 ++-------------------------------------------- package.json | 1 - test-nostr.js | 14 +++++- 5 files changed, 84 insertions(+), 140 deletions(-) diff --git a/nostr.js b/nostr.js index e42b296..7de9f58 100644 --- a/nostr.js +++ b/nostr.js @@ -1,5 +1,5 @@ -const { WebSocket } = require('websocket-polyfill'); +const WebSocket = require('ws'); const { finishEvent, @@ -11,15 +11,14 @@ const { getPublicKey } = require('nostr-tools'); - const config = { nostr_relay: 'strfry:7777', - nostr_sk: '80ac742bbc82d1b53fb9518d20beb32545e0265b184a007e57c00da8f81f3973', + nostr_sk: '531622b8f6eb29937abfea6029d70a00ec925a081e565d5875661002b49551fb', }; config.nostr_pk = getPublicKey(config.nostr_sk); -const sendMessage = async (message) => { +const createEvent = async (message) => { let event = { kind: 1, created_at: Math.floor(Date.now() / 1000), @@ -36,27 +35,75 @@ const sendMessage = async (message) => { console.log('Event:', event); console.log('Validation result:', ok); console.log('Signature verification result:', veryOk); + + return event; }; -const tryConnect = async () => { +const RELAYS = {}; - //const relay = relayInit('wss://taranis.local:4848'); - const relay = relayInit('wss://localhost:7777'); +function openRelay(wsurl) { + const ws = new WebSocket(wsurl); - relay.on('connect', () => { - console.log(`connected to ${relay.url}`); + ws.on('open', () => { + console.log(`ws open ${wsurl}`); + RELAYS[wsurl] = ws; }); - relay.on('error', () => { - console.log(`failed to connect to ${relay.url}`); S + ws.on('error', (error) => { + console.log(`ws error from ${wsurl}: ${error}`); }); - await relay.connect(); + ws.on('message', (event) => { + console.log(`ws message from ${wsurl}: ${event} `); + }); - return relay; -}; + ws.on('close', () => { + console.log(`ws close ${wsurl}`); + delete RELAYS[wsurl]; + }); +} + +function closeRelays() { + for (let key in RELAYS) { + const ws = RELAYS[key]; + ws.close(); + } +} + +function countOpenRelays() { + let count = 0; + + for (let key in RELAYS) { + const ws = RELAYS[key]; + + if (ws.readyState === WebSocket.OPEN) { + count++; + } + } + + return count; +} + +function sendEvent(event) { + const message = JSON.stringify(["EVENT", event]); + + for (let key in RELAYS) { + const ws = RELAYS[key]; + + if (ws.readyState === WebSocket.OPEN) { + ws.send(message); + console.log(`ws event sent to ${key}`); + } + else { + console.log(`ws ${key} not open`); + } + } +} module.exports = { - sendMessage, - tryConnect, + createEvent, + openRelay, + closeRelays, + countOpenRelays, + sendEvent, }; diff --git a/nostr/strfry.conf b/nostr/strfry.conf index e643878..4935041 100644 --- a/nostr/strfry.conf +++ b/nostr/strfry.conf @@ -41,7 +41,8 @@ events { relay { # Interface to listen on. Use 0.0.0.0 to listen on all interfaces (restart required) - bind = "127.0.0.1" + #bind = "127.0.0.1" + bind = "0.0.0.0" # Port to open for the nostr websocket protocol (restart required) port = 7777 @@ -54,16 +55,16 @@ relay { info { # NIP-11: Name of this server. Short/descriptive (< 30 characters) - name = "strfry default" + name = "artx.market nostr-relay" # NIP-11: Detailed information about relay, free-form description = "This is a strfry instance." # NIP-11: Administrative nostr pubkey, for contact purposes - pubkey = "" + pubkey = "e8d667dd0c571ba799390a392b690dd7b5491f484690ba922ab3f17965fb2139" # NIP-11: Alternative administrative contact (email, website, etc) - contact = "" + contact = "davidmc@gmail.com" } # Maximum accepted incoming websocket frame size (should be larger than max event) (restart required) diff --git a/package-lock.json b/package-lock.json index 741c350..7b6a9cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,6 @@ "serve-static": "^1.15.0", "sharp": "^0.32.1", "uuid": "^9.0.0", - "websocket-polyfill": "^0.0.3", "ws": "^8.14.2" } }, @@ -638,6 +637,8 @@ "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", "hasInstallScript": true, + "optional": true, + "peer": true, "dependencies": { "node-gyp-build": "^4.3.0" }, @@ -865,15 +866,6 @@ "node": ">= 8" } }, - "node_modules/d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dependencies": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -1040,44 +1032,11 @@ "once": "^1.4.0" } }, - "node_modules/es5-ext": { - "version": "0.10.62", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", - "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", - "hasInstallScript": true, - "dependencies": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, "node_modules/es6-object-assign": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", "integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==" }, - "node_modules/es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1179,19 +1138,6 @@ "node": ">= 0.6" } }, - "node_modules/ext": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", - "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", - "dependencies": { - "type": "^2.7.2" - } - }, - "node_modules/ext/node_modules/type": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", - "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==" - }, "node_modules/filelist": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", @@ -1695,11 +1641,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" - }, "node_modules/is-url": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", @@ -2201,11 +2142,6 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, - "node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" - }, "node_modules/node-abi": { "version": "3.43.0", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.43.0.tgz", @@ -3257,11 +3193,6 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==" }, - "node_modules/tstl": { - "version": "2.5.13", - "resolved": "https://registry.npmjs.org/tstl/-/tstl-2.5.13.tgz", - "integrity": "sha512-h9wayHHFI5+yqt8iau0vqH96cTNhezhZ/Fk/hrIdpfkiMu3lg9nzyvMfs5bIdX51IVzZO6DudLqhkL/rVXpT6g==" - }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -3273,11 +3204,6 @@ "node": "*" } }, - "node_modules/type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -3295,14 +3221,6 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, "node_modules/typeforce": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz", @@ -3349,6 +3267,8 @@ "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", "hasInstallScript": true, + "optional": true, + "peer": true, "dependencies": { "node-gyp-build": "^4.3.0" }, @@ -3406,31 +3326,6 @@ "node": ">= 0.8" } }, - "node_modules/websocket": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", - "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", - "dependencies": { - "bufferutil": "^4.0.1", - "debug": "^2.2.0", - "es5-ext": "^0.10.50", - "typedarray-to-buffer": "^3.1.5", - "utf-8-validate": "^5.0.2", - "yaeti": "^0.0.6" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/websocket-polyfill": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/websocket-polyfill/-/websocket-polyfill-0.0.3.tgz", - "integrity": "sha512-pF3kR8Uaoau78MpUmFfzbIRxXj9PeQrCuPepGE6JIsfsJ/o/iXr07Q2iQNzKSSblQJ0FiGWlS64N4pVSm+O3Dg==", - "dependencies": { - "tstl": "^2.0.7", - "websocket": "^1.0.28" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -3542,14 +3437,6 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" }, - "node_modules/yaeti": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", - "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", - "engines": { - "node": ">=0.10.32" - } - }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/package.json b/package.json index d893a4a..f48b390 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "serve-static": "^1.15.0", "sharp": "^0.32.1", "uuid": "^9.0.0", - "websocket-polyfill": "^0.0.3", "ws": "^8.14.2" } } diff --git a/test-nostr.js b/test-nostr.js index d5fd34b..bce2aaa 100644 --- a/test-nostr.js +++ b/test-nostr.js @@ -3,8 +3,18 @@ const nostr = require('./nostr'); console.log('nostr-test'); async function main() { - await nostr.sendMessage('hello!'); - await nostr.tryConnect(); + const event = await nostr.createEvent('hello again!'); + + nostr.openRelay('ws://taranis.local:4848'); + nostr.openRelay('ws://localhost:7777'); + + while (nostr.countOpenRelays() < 2) { + console.log('waiting to open relays...'); + await new Promise(resolve => setTimeout(resolve, 1000)); + } + + nostr.sendEvent(event); + nostr.closeRelays(); } main(); From 77d83cfc0571142edb34e95870ae323a5ed4eaea Mon Sep 17 00:00:00 2001 From: David McFadzean Date: Tue, 24 Oct 2023 16:09:46 -0400 Subject: [PATCH 3/3] Refactored nostr module --- config.js | 1 + nostr.js | 71 ++++++++++++++++++++++++++++++++++----------------- test-nostr.js | 13 +++++----- 3 files changed, 56 insertions(+), 29 deletions(-) diff --git a/config.js b/config.js index 5ea3715..3ac0a88 100644 --- a/config.js +++ b/config.js @@ -21,6 +21,7 @@ const config = { ln_wallet: process.env.LN_WALLET, ln_api_key: process.env.LN_API_KEY, ln_admin_key: process.env.LN_ADMIN_KEY, + nostr_key: process.env.NOSTR_KEY, data: 'data', uploads: 'data/uploads', assets: 'data/assets', diff --git a/nostr.js b/nostr.js index 7de9f58..167f3a5 100644 --- a/nostr.js +++ b/nostr.js @@ -1,46 +1,35 @@ const WebSocket = require('ws'); +const config = require('./config'); const { finishEvent, - relayInit, validateEvent, verifySignature, - getSignature, - getEventHash, getPublicKey } = require('nostr-tools'); -const config = { - nostr_relay: 'strfry:7777', - nostr_sk: '531622b8f6eb29937abfea6029d70a00ec925a081e565d5875661002b49551fb', -}; - -config.nostr_pk = getPublicKey(config.nostr_sk); +const RELAYS = {}; -const createEvent = async (message) => { +function createMessage(message) { let event = { kind: 1, created_at: Math.floor(Date.now() / 1000), tags: [], content: message, - pubkey: getPublicKey(config.nostr_sk), + pubkey: getPublicKey(config.nostr_key), }; - finishEvent(event, config.nostr_sk); - - let ok = validateEvent(event); - let veryOk = verifySignature(event); + finishEvent(event, config.nostr_key); - console.log('Event:', event); - console.log('Validation result:', ok); - console.log('Signature verification result:', veryOk); + const valid = validateEvent(event); + const verified = verifySignature(event); - return event; + if (valid && verified) { + return event; + } }; -const RELAYS = {}; - function openRelay(wsurl) { const ws = new WebSocket(wsurl); @@ -84,6 +73,15 @@ function countOpenRelays() { return count; } +function subscribeToRelays() { + const filters = { + kinds: [1], + limit: 1000, + }; + + sendRequest(filters); +} + function sendEvent(event) { const message = JSON.stringify(["EVENT", event]); @@ -100,10 +98,37 @@ function sendEvent(event) { } } +function sendMessage(message) { + const event = createMessage(message); + + if (event) { + sendEvent(event); + } +} + +function sendRequest(filters) { + const sub = "foo"; + const message = JSON.stringify(["REQ", sub, filters]); + + for (let key in RELAYS) { + const ws = RELAYS[key]; + + if (ws.readyState === WebSocket.OPEN) { + ws.send(message); + console.log(`ws req sent to ${key}`); + } + else { + console.log(`ws ${key} not open`); + } + } +} + module.exports = { - createEvent, - openRelay, closeRelays, countOpenRelays, + createMessage, + openRelay, sendEvent, + sendMessage, + subscribeToRelays, }; diff --git a/test-nostr.js b/test-nostr.js index bce2aaa..859a31a 100644 --- a/test-nostr.js +++ b/test-nostr.js @@ -1,20 +1,21 @@ const nostr = require('./nostr'); -console.log('nostr-test'); - async function main() { - const event = await nostr.createEvent('hello again!'); nostr.openRelay('ws://taranis.local:4848'); nostr.openRelay('ws://localhost:7777'); - while (nostr.countOpenRelays() < 2) { + while (nostr.countOpenRelays() < 1) { console.log('waiting to open relays...'); await new Promise(resolve => setTimeout(resolve, 1000)); } - nostr.sendEvent(event); - nostr.closeRelays(); + nostr.subscribeToRelays(); + + while (true) { + nostr.sendMessage(`hello again! ${new Date().toISOString()}`); + await new Promise(resolve => setTimeout(resolve, 10000)); + } } main();