diff --git a/.gitignore b/.gitignore index a1481e7..8cffff1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ localhost.crt localhost.key .idea +.vscode nostr \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index 504203e..7547a8b 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -31,9 +31,12 @@ services: networks: nostr: environment: - - NOSTR_RELAYS=ws://nostr-relay:8080 + - NOSTR_RELAYS=ws://nostr-relay:7777 - NOSTR_PRIVATE_KEY= - BACKEND_HOST=mint:3338 + depends_on: + - mint + - nostr exit-https: build: context: . @@ -43,9 +46,12 @@ services: networks: nostr: environment: - - NOSTR_RELAYS=ws://nostr-relay:8080 + - NOSTR_RELAYS=ws://nostr-relay:7777 - NOSTR_PRIVATE_KEY= - BACKEND_HOST=:4443 + depends_on: + - mint + - nostr entry: build: context: . @@ -56,16 +62,17 @@ services: networks: nostr: environment: - - NOSTR_RELAYS=ws://nostr-relay:8080 + - NOSTR_RELAYS=ws://nostr-relay:7777 + depends_on: + - nostr nostr: - image: scsibug/nostr-rs-relay:latest + image: carroarmato0/strfry:latest container_name: nostr-relay ports: - - 8080:8080 + - 7777:7777 networks: nostr: restart: always volumes: - - ./nostr/data:/usr/src/app/db:Z - - ./nostr/config/config.toml:/usr/src/app/config.toml:ro,Z - user: 100:100 + - ./strfry/data:/app/strfry-db/:Z + - ./strfry/strfry.conf:/app/strfry.conf:ro,Z diff --git a/exit/exit.go b/exit/exit.go index 0de3f9e..ad0322b 100644 --- a/exit/exit.go +++ b/exit/exit.go @@ -61,15 +61,10 @@ func NewExit(ctx context.Context, exitNodeConfig *config.ExitConfig) *Exit { // generate new private key exitNodeConfig.NostrPrivateKey = nostr.GeneratePrivateKey() slog.Warn(generateKeyMessage, "key", exitNodeConfig.NostrPrivateKey) - } else { - pubKey, err := nostr.GetPublicKey(exitNodeConfig.NostrPrivateKey) - if err != nil { - panic(err) - } - slog.Info("using public key", "key", pubKey) } // get public key from private key pubKey, err := nostr.GetPublicKey(exitNodeConfig.NostrPrivateKey) + slog.Info("using public key", "key", pubKey) if err != nil { panic(err) } diff --git a/exit/https.go b/exit/https.go index d87befe..343dfc9 100644 --- a/exit/https.go +++ b/exit/https.go @@ -9,9 +9,6 @@ import ( "crypto/x509/pkix" "encoding/pem" "fmt" - "github.com/asmogo/nws/protocol" - "github.com/nbd-wtf/go-nostr" - "github.com/nbd-wtf/go-nostr/nip04" "log/slog" "math/big" "net/http" @@ -19,14 +16,18 @@ import ( "net/url" "os" "time" + + "github.com/asmogo/nws/protocol" + "github.com/nbd-wtf/go-nostr" + "github.com/nbd-wtf/go-nostr/nip04" ) func (e *Exit) StartReverseProxy(httpTarget string, port int32) error { ctx := context.Background() ev := e.pool.QuerySingle(ctx, e.config.NostrRelays, nostr.Filter{ Authors: []string{e.publicKey}, - Kinds: []int{nostr.KindTextNote}, - Tags: nostr.TagMap{"p": []string{e.nprofile}}, + Kinds: []int{protocol.KindCertificateEvent}, + Tags: nostr.TagMap{"p": []string{e.publicKey}}, }) var cert tls.Certificate if ev == nil { @@ -40,8 +41,8 @@ func (e *Exit) StartReverseProxy(httpTarget string, port int32) error { // load private key from file privateKeyEvent := e.pool.QuerySingle(ctx, e.config.NostrRelays, nostr.Filter{ Authors: []string{e.publicKey}, - Kinds: []int{nostr.KindEncryptedDirectMessage}, - Tags: nostr.TagMap{"p": []string{e.nprofile}}, + Kinds: []int{protocol.KindPrivateKeyEvent}, + Tags: nostr.TagMap{"p": []string{e.publicKey}}, }) if privateKeyEvent == nil { return fmt.Errorf("failed to find encrypted direct message") @@ -125,7 +126,7 @@ func (e *Exit) createAndStoreCertificateData(ctx context.Context) (*tls.Certific certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certBytes}) keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}) // save key pem to file - err := os.WriteFile(fmt.Sprintf("%s.key", e.nprofile), keyPEM, 0644) + err := os.WriteFile(fmt.Sprintf("%s.key", e.publicKey), keyPEM, 0644) if err != nil { return nil, err } @@ -146,8 +147,8 @@ func (e *Exit) storePrivateKey(ctx context.Context, keyPEM []byte) error { if err != nil { return err } - event, err := s.CreateSignedEvent(e.publicKey, nostr.KindEncryptedDirectMessage, nostr.Tags{ - nostr.Tag{"p", e.nprofile}, + event, err := s.CreateSignedEvent(e.publicKey, protocol.KindPrivateKeyEvent, nostr.Tags{ + nostr.Tag{"p", e.publicKey}, }, protocol.WithData(keyPEM)) if err != nil { return err @@ -169,10 +170,10 @@ func (e *Exit) storeCertificate(ctx context.Context, certPEM []byte) (*tls.Certi event := nostr.Event{ CreatedAt: nostr.Now(), PubKey: e.publicKey, - Kind: nostr.KindTextNote, + Kind: protocol.KindCertificateEvent, Content: string(certPEM), Tags: nostr.Tags{ - nostr.Tag{"p", e.nprofile}, + nostr.Tag{"p", e.publicKey}, }, } err := event.Sign(e.config.NostrPrivateKey) diff --git a/exit/nostr.go b/exit/nostr.go index c48268c..e0132ed 100644 --- a/exit/nostr.go +++ b/exit/nostr.go @@ -6,6 +6,7 @@ import ( "strconv" "time" + "github.com/asmogo/nws/protocol" "github.com/nbd-wtf/go-nostr" ) @@ -18,9 +19,8 @@ func (e *Exit) announceExitNode(ctx context.Context) error { event := nostr.Event{ PubKey: e.publicKey, CreatedAt: nostr.Now(), - Kind: nostr.KindTextNote, + Kind: protocol.KindAnnouncementEvent, Tags: nostr.Tags{ - nostr.Tag{"n", "nws"}, nostr.Tag{"expiration", strconv.FormatInt(time.Now().Add(time.Second*10).Unix(), 20)}, }, } diff --git a/netstr/dns.go b/netstr/dns.go index 55b6318..fa31998 100644 --- a/netstr/dns.go +++ b/netstr/dns.go @@ -3,10 +3,12 @@ package netstr import ( "context" "fmt" - "github.com/nbd-wtf/go-nostr" "net" "strings" "time" + + "github.com/asmogo/nws/protocol" + "github.com/nbd-wtf/go-nostr" ) // NostrDNS does not resolve anything @@ -36,9 +38,8 @@ func (d NostrDNS) Resolve(ctx context.Context, name string) (context.Context, ne } since := nostr.Timestamp(time.Now().Add(-time.Second * 10).Unix()) ev := d.pool.QuerySingle(ctx, d.nostrRelays, nostr.Filter{ - Kinds: []int{nostr.KindTextNote}, + Kinds: []int{protocol.KindAnnouncementEvent}, Since: &since, - Tags: nostr.TagMap{"n": []string{"nws"}}, }) if ev == nil { return ctx, nil, fmt.Errorf("failed to find exit node event") diff --git a/protocol/signer.go b/protocol/signer.go index 40152a3..994c5aa 100644 --- a/protocol/signer.go +++ b/protocol/signer.go @@ -9,7 +9,16 @@ import ( ) // KindEphemeralEvent represents the unique identifier for ephemeral events. -const KindEphemeralEvent int = 38333 +const KindEphemeralEvent int = 28333 + +// KindAnnouncementEvent represents the unique identifier for announcement events. +const KindAnnouncementEvent int = 38333 + +// KindCertificateEvent represents the unique identifier for certificate events. +const KindCertificateEvent int = 38334 + +// KindPrivateKeyEvent represents the unique identifier for private key events. +const KindPrivateKeyEvent int = 38335 // EventSigner represents a signer that can create and sign events. // diff --git a/strfry/strfry.conf b/strfry/strfry.conf new file mode 100644 index 0000000..0907843 --- /dev/null +++ b/strfry/strfry.conf @@ -0,0 +1,141 @@ +## +## 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 = "0.0.0.0" + + # 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 = "" + + # NIP-11: URL pointing to an image to be used as an icon for the relay + icon = "" + } + + # 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 + } +} \ No newline at end of file