From e6d48a64223af71e414d3bab9f5e212eb2ab070d Mon Sep 17 00:00:00 2001 From: dd dd Date: Tue, 23 Jul 2024 19:10:02 +0200 Subject: [PATCH 01/20] Add HTTPS reverse proxy support This update includes modifications to several files to support the implementation of an HTTPS reverse proxy. --- cmd/exit/exit.go | 29 +++++- docker-compose.yaml | 13 ++- exit/exit.go | 5 ++ exit/https.go | 214 ++++++++++++++++++++++++++++++++++++++++++++ netstr/conn.go | 2 +- netstr/dial.go | 2 +- protocol/signer.go | 8 +- 7 files changed, 263 insertions(+), 10 deletions(-) create mode 100644 exit/https.go diff --git a/cmd/exit/exit.go b/cmd/exit/exit.go index 1c29a78..2700b02 100644 --- a/cmd/exit/exit.go +++ b/cmd/exit/exit.go @@ -3,11 +3,24 @@ package main import ( "github.com/asmogo/nws/config" "github.com/asmogo/nws/exit" - - "golang.org/x/net/context" + "github.com/spf13/cobra" + "log/slog" ) +var httpsPort int32 +var httpTarget string + func main() { + rootCmd := &cobra.Command{Use: "exit", Run: startExitNode} + rootCmd.Flags().Int32VarP(&httpsPort, "port", "p", 0, "port for the https reverse proxy") + rootCmd.Flags().StringVarP(&httpTarget, "target", "t", "", "target for the https reverse proxy (your local service)") + err := rootCmd.Execute() + if err != nil { + panic(err) + } +} +func startExitNode(cmd *cobra.Command, args []string) { + // load the configuration // from the environment cfg, err := config.LoadConfig[config.ExitConfig]() @@ -17,7 +30,17 @@ func main() { // create a new gw server // and start it - ctx := context.Background() + ctx := cmd.Context() exitNode := exit.NewExit(ctx, cfg) + if httpsPort != 0 { + slog.Info("starting exit node with https reverse proxy", "port", httpsPort) + go func() { + err = exitNode.StartReverseProxy(httpTarget, httpsPort) + if err != nil { + panic(err) + } + }() + + } exitNode.ListenAndServe(ctx) } diff --git a/docker-compose.yaml b/docker-compose.yaml index 5e27b72..ba9b5f8 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -34,6 +34,18 @@ services: - NOSTR_RELAYS=ws://nostr-relay:8080 - NOSTR_PRIVATE_KEY=003632642b6df1bb7f150c25aae079d590e6cfcceca924304154fbc2a3a938e3 - BACKEND_HOST=mint:3338 + exit-https: + build: + context: . + dockerfile: cmd/exit/Dockerfile + container_name: exit-https + command: ["./exit", "--port", "4443", "--target", "http://mint:3338"] + networks: + nostr: + environment: + - NOSTR_RELAYS=ws://nostr-relay:8080 + - NOSTR_PRIVATE_KEY=213632642b6df1bb7f150c25aae079d590e6cfcceca924304154fbc2a3a938e3 + - BACKEND_HOST=localhost:4443 proxy: build: context: . @@ -45,7 +57,6 @@ services: nostr: environment: - NOSTR_RELAYS=ws://nostr-relay:8080 - - NOSTR_PRIVATE_KEY=b0aceff311951aaa014c3296f4346f91f7fd4fc17396e060acbb48d2f42ef1fe nostr: image: scsibug/nostr-rs-relay:latest container_name: nostr-relay diff --git a/exit/exit.go b/exit/exit.go index dbd8a02..54ab42e 100644 --- a/exit/exit.go +++ b/exit/exit.go @@ -41,6 +41,9 @@ type Exit struct { // incomingChannel represents a channel used to receive incoming events from relays. incomingChannel chan nostr.IncomingEvent + + nprofile string + publicKey string } // NewExit creates a new Exit node with the provided context and config. @@ -76,6 +79,8 @@ func NewExit(ctx context.Context, config *config.ExitConfig) *Exit { if err != nil { panic(err) } + exit.nprofile = profile + exit.publicKey = pubKey slog.Info("created exit node", "profile", profile) err = exit.setSubscriptions(ctx) if err != nil { diff --git a/exit/https.go b/exit/https.go new file mode 100644 index 0000000..1d6abed --- /dev/null +++ b/exit/https.go @@ -0,0 +1,214 @@ +package exit + +import ( + "context" + "crypto/rand" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "fmt" + "github.com/asmogo/nws/protocol" + "github.com/nbd-wtf/go-nostr" + "github.com/nbd-wtf/go-nostr/nip04" + "math/big" + "net/http" + "net/http/httputil" + "net/url" + "os" + "time" +) + +func (e *Exit) DeleteEvent(ctx context.Context, ev *nostr.Event) error { + for _, responseRelay := range e.config.NostrRelays { + var relay *nostr.Relay + relay, err := e.pool.EnsureRelay(responseRelay) + if err != nil { + return err + } + event := nostr.Event{ + CreatedAt: nostr.Now(), + PubKey: e.publicKey, + Kind: nostr.KindDeletion, + Tags: nostr.Tags{ + nostr.Tag{"e", ev.ID}, + }, + } + err = event.Sign(e.config.NostrPrivateKey) + err = relay.Publish(ctx, event) + if err != nil { + return err + } + } + return nil +} + +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}}, + }) + var cert tls.Certificate + if ev == nil { + certificate, err := e.createAndStoreCertificateData(ctx) + if err != nil { + return err + } + cert = *certificate + } else { + // 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}}, + }) + if privateKeyEvent == nil { + return fmt.Errorf("failed to find encrypted direct message") + } + sharedKey, err := nip04.ComputeSharedSecret(privateKeyEvent.PubKey, e.config.NostrPrivateKey) + if err != nil { + return err + } + decodedMessage, err := nip04.Decrypt(privateKeyEvent.Content, sharedKey) + if err != nil { + return err + } + message, err := protocol.UnmarshalJSON([]byte(decodedMessage)) + if err != nil { + return err + } + block, _ := pem.Decode(message.Data) + if block == nil { + fmt.Fprintf(os.Stderr, "error: failed to decode PEM block containing private key\n") + os.Exit(1) + } + + if got, want := block.Type, "RSA PRIVATE KEY"; got != want { + fmt.Fprintf(os.Stderr, "error: decoded PEM block of type %s, but wanted %s", got, want) + os.Exit(1) + } + + priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return err + } + certBlock, _ := pem.Decode([]byte(ev.Content)) + if certBlock == nil { + fmt.Fprintf(os.Stderr, "Failed to parse certificate PEM.") + os.Exit(1) + } + + parsedCert, err := x509.ParseCertificate(certBlock.Bytes) + if err != nil { + return err + } + cert = tls.Certificate{ + Certificate: [][]byte{certBlock.Bytes}, + PrivateKey: priv, + Leaf: parsedCert, + } + } + target, _ := url.Parse(httpTarget) + + httpsConfig := &http.Server{ + Addr: fmt.Sprintf(":%d", port), + TLSConfig: &tls.Config{Certificates: []tls.Certificate{cert}}, + Handler: http.HandlerFunc(httputil.NewSingleHostReverseProxy(target).ServeHTTP), + } + return httpsConfig.ListenAndServeTLS("", "") + +} + +func (e *Exit) createAndStoreCertificateData(ctx context.Context) (*tls.Certificate, error) { + priv, _ := rsa.GenerateKey(rand.Reader, 2048) + notBefore := time.Now() + notAfter := notBefore.Add(365 * 24 * time.Hour) + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit) + + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + Organization: []string{"NWS"}, + }, + NotBefore: notBefore, + NotAfter: notAfter, + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + certBytes, _ := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) + 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) + if err != nil { + return nil, err + } + cert, _ := tls.X509KeyPair(certPEM, keyPEM) + certificate, err := e.storeCertificate(ctx, certPEM) + if err != nil { + return certificate, err + } + err = e.storePrivateKey(ctx, keyPEM) + if err != nil { + return certificate, err + } + return &cert, nil +} + +func (e *Exit) storePrivateKey(ctx context.Context, keyPEM []byte) error { + s, err := protocol.NewEventSigner(e.config.NostrPrivateKey) + if err != nil { + return err + } + event, err := s.CreateSignedEvent(e.publicKey, nostr.KindEncryptedDirectMessage, nostr.Tags{ + nostr.Tag{"p", e.nprofile}, + }, protocol.WithData(keyPEM)) + if err != nil { + return err + } + for _, responseRelay := range e.config.NostrRelays { + var relay *nostr.Relay + relay, err = e.pool.EnsureRelay(responseRelay) + if err != nil { + return err + } + err = relay.Publish(ctx, event) + if err != nil { + return err + } + } + return nil +} +func (e *Exit) storeCertificate(ctx context.Context, certPEM []byte) (*tls.Certificate, error) { + event := nostr.Event{ + CreatedAt: nostr.Now(), + PubKey: e.publicKey, + Kind: nostr.KindTextNote, + Content: string(certPEM), + Tags: nostr.Tags{ + nostr.Tag{"p", e.nprofile}, + }, + } + err := event.Sign(e.config.NostrPrivateKey) + if err != nil { + return nil, err + } + for _, responseRelay := range e.config.NostrRelays { + var relay *nostr.Relay + relay, err = e.pool.EnsureRelay(responseRelay) + if err != nil { + return nil, err + } + err = relay.Publish(ctx, event) + if err != nil { + return nil, err + } + } + return nil, nil +} diff --git a/netstr/conn.go b/netstr/conn.go index d2baf69..461995c 100644 --- a/netstr/conn.go +++ b/netstr/conn.go @@ -171,7 +171,7 @@ func (nc *NostrConnection) handleNostrWrite(b []byte, err error) (int, error) { protocol.WithType(protocol.MessageTypeSocks5), protocol.WithData(b), } - ev, err := signer.CreateSignedEvent(publicKey, nostr.Tags{nostr.Tag{"p", publicKey}}, opts...) + ev, err := signer.CreateSignedEvent(publicKey, protocol.KindEphemeralEvent, nostr.Tags{nostr.Tag{"p", publicKey}}, opts...) if err != nil { return 0, err } diff --git a/netstr/dial.go b/netstr/dial.go index 878d3c6..b7ffd58 100644 --- a/netstr/dial.go +++ b/netstr/dial.go @@ -43,7 +43,7 @@ func DialSocks(pool *nostr.SimplePool) func(ctx context.Context, net_, addr stri protocol.WithUUID(connectionID), protocol.WithDestination(addr), } - ev, err := signer.CreateSignedEvent(publicKey, + ev, err := signer.CreateSignedEvent(publicKey, protocol.KindEphemeralEvent, nostr.Tags{nostr.Tag{"p", publicKey}}, opts...) diff --git a/protocol/signer.go b/protocol/signer.go index 4323639..f696b97 100644 --- a/protocol/signer.go +++ b/protocol/signer.go @@ -34,11 +34,11 @@ func NewEventSigner(privateKey string) (*EventSigner, error) { // CreateEvent creates a new Event with the provided tags. The Public Key and the // current timestamp are set automatically. The Kind is set to KindEphemeralEvent. -func (s *EventSigner) CreateEvent(tags nostr.Tags) nostr.Event { +func (s *EventSigner) CreateEvent(kind int, tags nostr.Tags) nostr.Event { return nostr.Event{ PubKey: s.PublicKey, CreatedAt: nostr.Now(), - Kind: KindEphemeralEvent, + Kind: kind, Tags: tags, } } @@ -51,7 +51,7 @@ func (s *EventSigner) CreateEvent(tags nostr.Tags) nostr.Event { // The encrypted message is set as the content of the event. // Finally, the event is signed with the private key of the EventSigner, setting the event ID and event Sig fields. // The signed event is returned along with any error that occurs. -func (s *EventSigner) CreateSignedEvent(targetPublicKey string, tags nostr.Tags, opts ...MessageOption) (nostr.Event, error) { +func (s *EventSigner) CreateSignedEvent(targetPublicKey string, kind int, tags nostr.Tags, opts ...MessageOption) (nostr.Event, error) { sharedKey, err := nip04.ComputeSharedSecret(targetPublicKey, s.privateKey) if err != nil { return nostr.Event{}, err @@ -64,7 +64,7 @@ func (s *EventSigner) CreateSignedEvent(targetPublicKey string, tags nostr.Tags, return nostr.Event{}, err } encryptedMessage, err := nip04.Encrypt(string(messageJson), sharedKey) - ev := s.CreateEvent(tags) + ev := s.CreateEvent(kind, tags) ev.Content = encryptedMessage // calling Sign sets the event ID field and the event Sig field err = ev.Sign(s.privateKey) From 588b0ad6451e893f99c70edfae55eb987bd3583d Mon Sep 17 00:00:00 2001 From: dd dd Date: Tue, 23 Jul 2024 19:13:56 +0200 Subject: [PATCH 02/20] Extend certificate validity to 10 years --- exit/https.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exit/https.go b/exit/https.go index 1d6abed..5c1f62e 100644 --- a/exit/https.go +++ b/exit/https.go @@ -125,7 +125,7 @@ func (e *Exit) StartReverseProxy(httpTarget string, port int32) error { func (e *Exit) createAndStoreCertificateData(ctx context.Context) (*tls.Certificate, error) { priv, _ := rsa.GenerateKey(rand.Reader, 2048) notBefore := time.Now() - notAfter := notBefore.Add(365 * 24 * time.Hour) + notAfter := notBefore.Add(10 * 365 * 24 * time.Hour) serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit) From 6b113af7fe1c5ece37d6797c825d8adcefa04706 Mon Sep 17 00:00:00 2001 From: dd dd Date: Tue, 23 Jul 2024 21:26:04 +0200 Subject: [PATCH 03/20] Update private key handling and improve readme --- README.md | 18 +++++++++++++++--- cmd/exit/exit.go | 18 ++++++++++++++++-- docker-compose.yaml | 10 +++++----- exit/https.go | 2 ++ go.mod | 3 +++ go.sum | 8 ++++++++ 6 files changed, 49 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index e57bc94..dceb18f 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,9 @@ Running NWS using Docker is recommended. For instructions on running NWS on your ### Using Docker Compose +Please navigate to the `docker-compose.yaml` file and set the value of `NOSTR_PRIVATE_KEY` to your own private key. +Leaving it empty will generate a new private key on startup. + To set up using Docker Compose, run the following command: ``` docker compose up -d --build @@ -35,18 +38,27 @@ docker compose up -d --build This will start an example setup, including the entry node, exit node, and a backend service. +You can run the following commands to receive your nprofiles: + +```bash +docker logs exit-https 2>&1 | awk -F'profile=' '{if ($2) print $2}' | awk '{print $1} +``` +```bash +docker logs exit 2>&1 | awk -F'profile=' '{if ($2) print $2}' | awk '{print $1} +``` + ### Sending Requests to the Entry node -You can use the following command to send a request to the nprofile: +With the log information from the previous step, you can use the following command to send a request to the nprofile: ``` -curl -v -x socks5h://localhost:8882 http://nprofile1qqsp98rnlp7sn4xuf7meyec48njp2qyfch0jktwvfuqx8vdqgexkg8gpz4mhxw309ahx7um5wgkhyetvv9un5wps8qcqggauk8/v1/info --insecure +curl -v -x socks5h://localhost:8882 http://"$(docker logs exit 2>&1 | awk -F'profile=' '{if ($2) print $2}' | awk '{print $1}')"/v1/info --insecure ``` If the nprofile supports TLS, you can choose to connect using https scheme ``` -curl -v -x socks5h://localhost:8882 https://nprofile1qqstw2nc544vkl4760yeq9xt2yd0gthl4trm6ruvpukdthx9fy5xqjcpz4mhxw309ahx7um5wgkhyetvv9un5wps8qcqcelsf6/v1/info --insecure +curl -v -x socks5h://localhost:8882 https://"$(docker logs exit-https 2>&1 | awk -F'profile=' '{if ($2) print $2}' | awk '{print $1}')"/v1/info --insecure ``` When using https, the entry node can be used as a service, since the operator will not be able to see the request data. diff --git a/cmd/exit/exit.go b/cmd/exit/exit.go index 2700b02..fb71efa 100644 --- a/cmd/exit/exit.go +++ b/cmd/exit/exit.go @@ -1,8 +1,10 @@ package main import ( + "fmt" "github.com/asmogo/nws/config" "github.com/asmogo/nws/exit" + "github.com/nbd-wtf/go-nostr" "github.com/spf13/cobra" "log/slog" ) @@ -10,6 +12,11 @@ import ( var httpsPort int32 var httpTarget string +const ( + generateKeyMessage = "Generated new private key. Please update your configuration file with the new key, otherwise your key will be lost, once this application restarts." + startingReverseProxyMessage = "starting exit node with https reverse proxy" +) + func main() { rootCmd := &cobra.Command{Use: "exit", Run: startExitNode} rootCmd.Flags().Int32VarP(&httpsPort, "port", "p", 0, "port for the https reverse proxy") @@ -27,13 +34,20 @@ func startExitNode(cmd *cobra.Command, args []string) { if err != nil { panic(err) } - + if httpsPort != 0 { + cfg.BackendHost = fmt.Sprintf(":%d", httpsPort) + } + if cfg.NostrPrivateKey == "" { + // generate new private key + cfg.NostrPrivateKey = nostr.GeneratePrivateKey() + slog.Warn(generateKeyMessage, "key", cfg.NostrPrivateKey) + } // create a new gw server // and start it ctx := cmd.Context() exitNode := exit.NewExit(ctx, cfg) if httpsPort != 0 { - slog.Info("starting exit node with https reverse proxy", "port", httpsPort) + slog.Info(startingReverseProxyMessage, "port", httpsPort) go func() { err = exitNode.StartReverseProxy(httpTarget, httpsPort) if err != nil { diff --git a/docker-compose.yaml b/docker-compose.yaml index ba9b5f8..1780c34 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -32,7 +32,7 @@ services: nostr: environment: - NOSTR_RELAYS=ws://nostr-relay:8080 - - NOSTR_PRIVATE_KEY=003632642b6df1bb7f150c25aae079d590e6cfcceca924304154fbc2a3a938e3 + - NOSTR_PRIVATE_KEY= - BACKEND_HOST=mint:3338 exit-https: build: @@ -44,13 +44,13 @@ services: nostr: environment: - NOSTR_RELAYS=ws://nostr-relay:8080 - - NOSTR_PRIVATE_KEY=213632642b6df1bb7f150c25aae079d590e6cfcceca924304154fbc2a3a938e3 - - BACKEND_HOST=localhost:4443 - proxy: + - NOSTR_PRIVATE_KEY= + - BACKEND_HOST=:4443 + entry: build: context: . dockerfile: cmd/proxy/Dockerfile - container_name: proxy + container_name: entry ports: - 8882:8882 networks: diff --git a/exit/https.go b/exit/https.go index 5c1f62e..549c688 100644 --- a/exit/https.go +++ b/exit/https.go @@ -12,6 +12,7 @@ import ( "github.com/asmogo/nws/protocol" "github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr/nip04" + "log/slog" "math/big" "net/http" "net/http/httputil" @@ -59,6 +60,7 @@ func (e *Exit) StartReverseProxy(httpTarget string, port int32) error { } cert = *certificate } else { + slog.Info("found certificate event", "certificate", ev.Content) // load private key from file privateKeyEvent := e.pool.QuerySingle(ctx, e.config.NostrRelays, nostr.Filter{ Authors: []string{e.publicKey}, diff --git a/go.mod b/go.mod index c045448..cc628cf 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/nbd-wtf/go-nostr v0.30.2 github.com/puzpuzpuz/xsync/v3 v3.0.2 github.com/samber/lo v1.45.0 + github.com/spf13/cobra v1.8.1 github.com/stretchr/testify v1.9.0 golang.org/x/net v0.23.0 ) @@ -23,9 +24,11 @@ require ( github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/pool v0.2.1 // indirect github.com/gobwas/ws v1.2.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect github.com/tidwall/gjson v1.14.4 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect diff --git a/go.sum b/go.sum index d2bac6d..b9fae80 100644 --- a/go.sum +++ b/go.sum @@ -25,6 +25,7 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/caarlos0/env/v11 v11.0.0 h1:ZIlkOjuL3xoZS0kmUJlF74j2Qj8GMOq3CDLX/Viak8Q= github.com/caarlos0/env/v11 v11.0.0/go.mod h1:2RC3HQu8BQqtEK3V4iHPxj0jOdWdbPpWJ6pOueeU1xM= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -58,6 +59,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= @@ -83,8 +86,13 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/puzpuzpuz/xsync/v3 v3.0.2 h1:3yESHrRFYr6xzkz61LLkvNiPFXxJEAABanTQpKbAaew= github.com/puzpuzpuz/xsync/v3 v3.0.2/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/samber/lo v1.45.0 h1:TPK85Y30Lv9Jh8s3TrJeA94u1hwcbFA9JObx/vT6lYU= github.com/samber/lo v1.45.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= From 6f4db0092d4af787d18b46ac934f9dd697dff3fa Mon Sep 17 00:00:00 2001 From: dd dd Date: Tue, 23 Jul 2024 21:36:57 +0200 Subject: [PATCH 04/20] update readme --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index dceb18f..7be5945 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Running NWS using Docker is recommended. For instructions on running NWS on your ### Using Docker Compose -Please navigate to the `docker-compose.yaml` file and set the value of `NOSTR_PRIVATE_KEY` to your own private key. +Please navigate to the `docker-compose.yaml` file and set `NOSTR_PRIVATE_KEY` to your own private key. Leaving it empty will generate a new private key on startup. To set up using Docker Compose, run the following command: @@ -36,7 +36,7 @@ To set up using Docker Compose, run the following command: docker compose up -d --build ``` -This will start an example setup, including the entry node, exit node, and a backend service. +This will start an example environment, including the entry node, exit node, and a backend service. You can run the following commands to receive your nprofiles: @@ -52,13 +52,13 @@ docker logs exit 2>&1 | awk -F'profile=' '{if ($2) print $2}' | awk '{print $1} With the log information from the previous step, you can use the following command to send a request to the nprofile: ``` -curl -v -x socks5h://localhost:8882 http://"$(docker logs exit 2>&1 | awk -F'profile=' '{if ($2) print $2}' | awk '{print $1}')"/v1/info --insecure +curl -v -x socks5h://localhost:8882 http://"$(docker logs exit 2>&1 | awk -F'profile=' '{if ($2) print $2}' | awk '{print $1}' | tail -n 1)"/v1/info --insecure ``` If the nprofile supports TLS, you can choose to connect using https scheme ``` -curl -v -x socks5h://localhost:8882 https://"$(docker logs exit-https 2>&1 | awk -F'profile=' '{if ($2) print $2}' | awk '{print $1}')"/v1/info --insecure +curl -v -x socks5h://localhost:8882 https://"$(docker logs exit-https 2>&1 | awk -F'profile=' '{if ($2) print $2}' | awk '{print $1}' | tail -n 1)"/v1/info --insecure ``` When using https, the entry node can be used as a service, since the operator will not be able to see the request data. @@ -69,7 +69,7 @@ The exit node must be set up to make the services reachable via Nostr. ### Configuration -Configuration can be completed using environment variables. +Configuration should be completed using environment variables. Alternatively, you can create a `.env` file in the current working directory with the following content: ``` NOSTR_RELAYS = 'ws://localhost:6666;wss://relay.damus.io' From e5d2a0ec57f73191a6de256aef08cf4ad6114646 Mon Sep 17 00:00:00 2001 From: dd dd Date: Tue, 23 Jul 2024 21:49:15 +0200 Subject: [PATCH 05/20] moved stuff from cmd to exit --- cmd/exit/exit.go | 26 ++++++++------------------ config/config.go | 2 ++ exit/exit.go | 27 +++++++++++++++++++++------ 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/cmd/exit/exit.go b/cmd/exit/exit.go index fb71efa..7f2fcea 100644 --- a/cmd/exit/exit.go +++ b/cmd/exit/exit.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "github.com/asmogo/nws/config" "github.com/asmogo/nws/exit" "github.com/nbd-wtf/go-nostr" @@ -13,14 +12,15 @@ var httpsPort int32 var httpTarget string const ( - generateKeyMessage = "Generated new private key. Please update your configuration file with the new key, otherwise your key will be lost, once this application restarts." - startingReverseProxyMessage = "starting exit node with https reverse proxy" + generateKeyMessage = "Generated new private key. Please set your environment using the new key, otherwise your key will be lost." + usagePort = "set the https reverse proxy port" + usageTarget = "set https reverse proxy target (your local service)" ) func main() { rootCmd := &cobra.Command{Use: "exit", Run: startExitNode} - rootCmd.Flags().Int32VarP(&httpsPort, "port", "p", 0, "port for the https reverse proxy") - rootCmd.Flags().StringVarP(&httpTarget, "target", "t", "", "target for the https reverse proxy (your local service)") + rootCmd.Flags().Int32VarP(&httpsPort, "port", "p", 0, usagePort) + rootCmd.Flags().StringVarP(&httpTarget, "target", "t", "", usageTarget) err := rootCmd.Execute() if err != nil { panic(err) @@ -34,9 +34,9 @@ func startExitNode(cmd *cobra.Command, args []string) { if err != nil { panic(err) } - if httpsPort != 0 { - cfg.BackendHost = fmt.Sprintf(":%d", httpsPort) - } + cfg.HttpsPort = httpsPort + cfg.HttpsTarget = httpTarget + if cfg.NostrPrivateKey == "" { // generate new private key cfg.NostrPrivateKey = nostr.GeneratePrivateKey() @@ -46,15 +46,5 @@ func startExitNode(cmd *cobra.Command, args []string) { // and start it ctx := cmd.Context() exitNode := exit.NewExit(ctx, cfg) - if httpsPort != 0 { - slog.Info(startingReverseProxyMessage, "port", httpsPort) - go func() { - err = exitNode.StartReverseProxy(httpTarget, httpsPort) - if err != nil { - panic(err) - } - }() - - } exitNode.ListenAndServe(ctx) } diff --git a/config/config.go b/config/config.go index fba69f5..161c76e 100644 --- a/config/config.go +++ b/config/config.go @@ -18,6 +18,8 @@ type ExitConfig struct { NostrPrivateKey string `env:"NOSTR_PRIVATE_KEY"` BackendHost string `env:"BACKEND_HOST"` BackendScheme string `env:"BACKEND_SCHEME"` + HttpsPort int32 + HttpsTarget string } // load the and marshal Configuration from .env file from the UserHomeDir diff --git a/exit/exit.go b/exit/exit.go index 54ab42e..bca8a22 100644 --- a/exit/exit.go +++ b/exit/exit.go @@ -19,6 +19,10 @@ import ( _ "net/http/pprof" ) +const ( + startingReverseProxyMessage = "starting exit node with https reverse proxy" +) + // Exit represents a structure that holds information related to an exit node. type Exit struct { @@ -47,21 +51,23 @@ type Exit struct { } // NewExit creates a new Exit node with the provided context and config. -func NewExit(ctx context.Context, config *config.ExitConfig) *Exit { +func NewExit(ctx context.Context, exitNodeConfig *config.ExitConfig) *Exit { // todo -- this is for debugging purposes only and should be removed go func() { log.Println(http.ListenAndServe("localhost:6060", nil)) }() pool := nostr.NewSimplePool(ctx) - + if exitNodeConfig.HttpsPort != 0 { + exitNodeConfig.BackendHost = fmt.Sprintf(":%d", exitNodeConfig.HttpsPort) + } exit := &Exit{ nostrConnectionMap: xsync.NewMapOf[string, *netstr.NostrConnection](), - config: config, + config: exitNodeConfig, pool: pool, mutexMap: NewMutexMap(), } - for _, relayUrl := range config.NostrRelays { + for _, relayUrl := range exitNodeConfig.NostrRelays { relay, err := exit.pool.EnsureRelay(relayUrl) if err != nil { fmt.Println(err) @@ -70,12 +76,12 @@ func NewExit(ctx context.Context, config *config.ExitConfig) *Exit { exit.relays = append(exit.relays, relay) fmt.Printf("added relay connection to %s\n", relayUrl) } - pubKey, err := nostr.GetPublicKey(config.NostrPrivateKey) + pubKey, err := nostr.GetPublicKey(exitNodeConfig.NostrPrivateKey) if err != nil { panic(err) } profile, err := nip19.EncodeProfile(pubKey, - config.NostrRelays) + exitNodeConfig.NostrRelays) if err != nil { panic(err) } @@ -83,6 +89,15 @@ func NewExit(ctx context.Context, config *config.ExitConfig) *Exit { exit.publicKey = pubKey slog.Info("created exit node", "profile", profile) err = exit.setSubscriptions(ctx) + if exit.config.HttpsPort != 0 { + slog.Info(startingReverseProxyMessage, "port", exit.config.HttpsPort) + go func() { + err = exit.StartReverseProxy(exitNodeConfig.HttpsTarget, exit.config.HttpsPort) + if err != nil { + panic(err) + } + }() + } if err != nil { panic(err) } From bd0700b8522f027f02a75a926cb8c9c05e4893eb Mon Sep 17 00:00:00 2001 From: dd dd Date: Tue, 23 Jul 2024 22:18:41 +0200 Subject: [PATCH 06/20] Refactor exit node setup and update command documentation --- README.md | 2 +- cmd/exit/exit.go | 26 +++++++----------- exit/exit.go | 69 ++++++++++++++++++++++++++---------------------- 3 files changed, 49 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 7be5945..61bbcf5 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ This will start an example environment, including the entry node, exit node, and You can run the following commands to receive your nprofiles: ```bash -docker logs exit-https 2>&1 | awk -F'profile=' '{if ($2) print $2}' | awk '{print $1} +docker logs exit-https 2>&1 | awk -F'profile=' '{if ($2) print $2}' | awk '{print $1}' ``` ```bash docker logs exit 2>&1 | awk -F'profile=' '{if ($2) print $2}' | awk '{print $1} diff --git a/cmd/exit/exit.go b/cmd/exit/exit.go index 7f2fcea..b8f6c37 100644 --- a/cmd/exit/exit.go +++ b/cmd/exit/exit.go @@ -3,18 +3,15 @@ package main import ( "github.com/asmogo/nws/config" "github.com/asmogo/nws/exit" - "github.com/nbd-wtf/go-nostr" "github.com/spf13/cobra" - "log/slog" ) var httpsPort int32 var httpTarget string const ( - generateKeyMessage = "Generated new private key. Please set your environment using the new key, otherwise your key will be lost." - usagePort = "set the https reverse proxy port" - usageTarget = "set https reverse proxy target (your local service)" + usagePort = "set the https reverse proxy port" + usageTarget = "set https reverse proxy target (your local service)" ) func main() { @@ -26,24 +23,21 @@ func main() { panic(err) } } -func startExitNode(cmd *cobra.Command, args []string) { +// updateConfigFlag updates the configuration with the provided flags. +func updateConfigFlag(cfg *config.ExitConfig) { + cfg.HttpsPort = httpsPort + cfg.HttpsTarget = httpTarget +} + +func startExitNode(cmd *cobra.Command, args []string) { // load the configuration // from the environment cfg, err := config.LoadConfig[config.ExitConfig]() if err != nil { panic(err) } - cfg.HttpsPort = httpsPort - cfg.HttpsTarget = httpTarget - - if cfg.NostrPrivateKey == "" { - // generate new private key - cfg.NostrPrivateKey = nostr.GeneratePrivateKey() - slog.Warn(generateKeyMessage, "key", cfg.NostrPrivateKey) - } - // create a new gw server - // and start it + updateConfigFlag(cfg) ctx := cmd.Context() exitNode := exit.NewExit(ctx, cfg) exitNode.ListenAndServe(ctx) diff --git a/exit/exit.go b/exit/exit.go index bca8a22..b0c607e 100644 --- a/exit/exit.go +++ b/exit/exit.go @@ -12,15 +12,14 @@ import ( "github.com/nbd-wtf/go-nostr/nip19" "github.com/puzpuzpuz/xsync/v3" "golang.org/x/net/context" - "log" "log/slog" "net" - "net/http" _ "net/http/pprof" ) const ( startingReverseProxyMessage = "starting exit node with https reverse proxy" + generateKeyMessage = "Generated new private key. Please set your environment using the new key, otherwise your key will be lost." ) // Exit represents a structure that holds information related to an exit node. @@ -52,21 +51,47 @@ type Exit struct { // NewExit creates a new Exit node with the provided context and config. func NewExit(ctx context.Context, exitNodeConfig *config.ExitConfig) *Exit { - // todo -- this is for debugging purposes only and should be removed - go func() { - log.Println(http.ListenAndServe("localhost:6060", nil)) - }() - pool := nostr.NewSimplePool(ctx) - if exitNodeConfig.HttpsPort != 0 { - exitNodeConfig.BackendHost = fmt.Sprintf(":%d", exitNodeConfig.HttpsPort) + // generate new private key if it is not set + if exitNodeConfig.NostrPrivateKey == "" { + // generate new private key + exitNodeConfig.NostrPrivateKey = nostr.GeneratePrivateKey() + slog.Warn(generateKeyMessage, "key", exitNodeConfig.NostrPrivateKey) } + // get public key from private key + pubKey, err := nostr.GetPublicKey(exitNodeConfig.NostrPrivateKey) + if err != nil { + panic(err) + } + // encode profile + profile, err := nip19.EncodeProfile(pubKey, + exitNodeConfig.NostrRelays) + if err != nil { + panic(err) + } + // create a new pool + pool := nostr.NewSimplePool(ctx) + exit := &Exit{ nostrConnectionMap: xsync.NewMapOf[string, *netstr.NostrConnection](), - config: exitNodeConfig, pool: pool, mutexMap: NewMutexMap(), + publicKey: pubKey, + nprofile: profile, } - + // start reverse proxy if https port is set + if exitNodeConfig.HttpsPort != 0 { + exitNodeConfig.BackendHost = fmt.Sprintf(":%d", exitNodeConfig.HttpsPort) + go func(cfg *config.ExitConfig) { + slog.Info(startingReverseProxyMessage, "port", cfg.HttpsPort) + err := exit.StartReverseProxy(cfg.HttpsTarget, cfg.HttpsPort) + if err != nil { + panic(err) + } + }(exitNodeConfig) + } + // set config + exit.config = exitNodeConfig + // add relays to the pool for _, relayUrl := range exitNodeConfig.NostrRelays { relay, err := exit.pool.EnsureRelay(relayUrl) if err != nil { @@ -76,28 +101,10 @@ func NewExit(ctx context.Context, exitNodeConfig *config.ExitConfig) *Exit { exit.relays = append(exit.relays, relay) fmt.Printf("added relay connection to %s\n", relayUrl) } - pubKey, err := nostr.GetPublicKey(exitNodeConfig.NostrPrivateKey) - if err != nil { - panic(err) - } - profile, err := nip19.EncodeProfile(pubKey, - exitNodeConfig.NostrRelays) - if err != nil { - panic(err) - } - exit.nprofile = profile - exit.publicKey = pubKey + slog.Info("created exit node", "profile", profile) + // setup subscriptions err = exit.setSubscriptions(ctx) - if exit.config.HttpsPort != 0 { - slog.Info(startingReverseProxyMessage, "port", exit.config.HttpsPort) - go func() { - err = exit.StartReverseProxy(exitNodeConfig.HttpsTarget, exit.config.HttpsPort) - if err != nil { - panic(err) - } - }() - } if err != nil { panic(err) } From b8472a65492a8d602dc6a75e89c3cbc1b83d7578 Mon Sep 17 00:00:00 2001 From: dd dd Date: Tue, 23 Jul 2024 22:19:33 +0200 Subject: [PATCH 07/20] Fix missing backtick in README.md docker instruction --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 61bbcf5..239c345 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ You can run the following commands to receive your nprofiles: docker logs exit-https 2>&1 | awk -F'profile=' '{if ($2) print $2}' | awk '{print $1}' ``` ```bash -docker logs exit 2>&1 | awk -F'profile=' '{if ($2) print $2}' | awk '{print $1} +docker logs exit 2>&1 | awk -F'profile=' '{if ($2) print $2}' | awk '{print $1}` ``` ### Sending Requests to the Entry node From 3de5d16951e1f357b4b7113b8179aa5b3d5b2a79 Mon Sep 17 00:00:00 2001 From: dd dd Date: Wed, 24 Jul 2024 22:45:41 +0200 Subject: [PATCH 08/20] updated readme --- .github/codecov.yml | 9 +++ .github/workflows/master.yml | 29 ++++++++ .github/workflows/tag.yml | 35 ++++++++++ .github/workflows/test.yml | 18 +++++ README.md | 4 +- cmd/listener/listener.go | 71 ++++++++++++++++++++ cmd/testr/testr.go | 49 ++++++++++++++ coverage.txt | 1 + netstr/conn_test.go | 125 +++++++++++++++++++++++++++++++++++ 9 files changed, 339 insertions(+), 2 deletions(-) create mode 100644 .github/codecov.yml create mode 100644 .github/workflows/master.yml create mode 100644 .github/workflows/tag.yml create mode 100644 .github/workflows/test.yml create mode 100644 cmd/listener/listener.go create mode 100644 cmd/testr/testr.go create mode 100644 coverage.txt create mode 100644 netstr/conn_test.go diff --git a/.github/codecov.yml b/.github/codecov.yml new file mode 100644 index 0000000..e190e6a --- /dev/null +++ b/.github/codecov.yml @@ -0,0 +1,9 @@ +coverage: + status: + patch: off + project: + default: + target: auto + # adjust accordingly based on how flaky your tests are + # this allows a 10% drop from the previous base commit coverage + threshold: 10% \ No newline at end of file diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml new file mode 100644 index 0000000..840b40a --- /dev/null +++ b/.github/workflows/master.yml @@ -0,0 +1,29 @@ +name: gobuild + +on: + push: + branches: [ "master" ] + +jobs: + docker: + runs-on: ubuntu-latest + steps: + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - name: Docker Setup Buildx + uses: docker/setup-buildx-action@v2.0.0 + - name: Build and push + uses: docker/build-push-action@v3 + with: + platforms: linux/amd64,linux/arm64 + push: true + tags: asmogo/nws-exit-node:latest \ No newline at end of file diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml new file mode 100644 index 0000000..94d5e19 --- /dev/null +++ b/.github/workflows/tag.yml @@ -0,0 +1,35 @@ +name: goreleaser + +on: + push: + # run only against tags + tags: + - '*' + +permissions: + contents: write + # packages: write + # issues: write + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - run: git fetch --force --tags + - uses: actions/setup-go@v3 + with: + go-version: '>=1.21.2' + cache: true + # More assembly might be required: Docker logins, GPG, etc. It all depends + # on your needs. + - uses: goreleaser/goreleaser-action@v2 + with: + # either 'goreleaser' (default) or 'goreleaser-pro' + distribution: goreleaser + version: latest + args: release --rm-dist + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..e405da0 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,18 @@ +name: tests + +on: [ push, pull_request ] + +jobs: + golang: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.19 + - name: Golang run tests + run: go test -coverprofile=coverage.txt -covermode=atomic -v ./... + - uses: codecov/codecov-action@v3 + with: + verbose: true # optional (default = false) \ No newline at end of file diff --git a/README.md b/README.md index 239c345..bade659 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ If you used environment variables, no further configuration is needed. For `.env` file configurations, do so in the current working directory with the following content: ``` -NOSTR_RELAYS = 'ws://localhost:6666;wss://relay.damus.io' +NOSTR_RELAYS = 'ws://localhost:6666;wss://relay.com' ``` -Here, NOSTR_RELAYS is a list of nostr relays to publish events to and will only be used if there was no nprofile in the request. \ No newline at end of file +Here, NOSTR_RELAYS is a list of nostr relays to publish events to and will only be used if there was no nprofile in the request. diff --git a/cmd/listener/listener.go b/cmd/listener/listener.go new file mode 100644 index 0000000..0fa00b2 --- /dev/null +++ b/cmd/listener/listener.go @@ -0,0 +1,71 @@ +package main + +import ( + "bufio" + "encoding/binary" + "fmt" + "io" + "log" + "net" +) + +func main() { + startServer() +} +func startServer() { + l, err := net.Listen("tcp", "localhost:3338") + if err != nil { + log.Fatal(err) + } + defer l.Close() + for { + conn, err := l.Accept() + if err != nil { + log.Fatal(err) + } + go handleConnection(conn) + } +} + +func handleRequest(conn net.Conn) { + defer conn.Close() + + reader := bufio.NewReader(conn) + + for { + message, err := reader.ReadString('\n') // change the delimiter according to your messaging protocol + if err != nil { + if err != io.EOF { + log.Fatal(err) + } + break + } + fmt.Printf("Received message: %s", message) + _, err = conn.Write([]byte(message)) + if err != nil { + log.Fatal(err) + } + } +} +func handleConnection(conn net.Conn) { + defer conn.Close() + for { + var num int32 + // Read the integer from the connection + err := binary.Read(conn, binary.BigEndian, &num) + if err != nil { + fmt.Println("Error reading from connection:", err) + return + } + + // Write the integer back to the connection + err = binary.Write(conn, binary.BigEndian, num) + if err != nil { + fmt.Println("Error writing to connection:", err) + return + } + + fmt.Println("Received and sent back:", num) + } + +} diff --git a/cmd/testr/testr.go b/cmd/testr/testr.go new file mode 100644 index 0000000..cca5932 --- /dev/null +++ b/cmd/testr/testr.go @@ -0,0 +1,49 @@ +package main + +import ( + "encoding/binary" + "fmt" + "golang.org/x/net/proxy" + "os" +) + +func main() { + // set up a socks5 dialer + dialer, err := proxy.SOCKS5("tcp", "localhost:8882", nil, proxy.Direct) + if err != nil { + fmt.Fprintln(os.Stderr, "can't connect to the proxy:", err) + os.Exit(1) + } + // use the dialer to connect to the server + conn, err := dialer.Dial("tcp", "nprofile1qqs9ntc52tn0app0w7azwpj4s39lnz8h0frnzlhf6mun2ptq9ay36kspzemhxue69uhhyetvv9ujuwpnxvejuumsv93k20v2pva:3338") + if err != nil { + fmt.Fprintln(os.Stderr, "can't connect to the server:", err) + os.Exit(1) + } + counter := int32(0) + + for { + + // Increment the counter + counter++ + + // Write the counter to the connection + err = binary.Write(conn, binary.BigEndian, counter) + if err != nil { + fmt.Println("Error writing to connection:", err) + break + } + + // Read the response from the server + var response int32 + err = binary.Read(conn, binary.BigEndian, &response) + if err != nil { + fmt.Println("Error reading from connection:", err) + break + } + + fmt.Println("Sent:", counter, "Received:", response) + + } + _ = conn.Close() +} diff --git a/coverage.txt b/coverage.txt new file mode 100644 index 0000000..79b28a0 --- /dev/null +++ b/coverage.txt @@ -0,0 +1 @@ +mode: atomic diff --git a/netstr/conn_test.go b/netstr/conn_test.go new file mode 100644 index 0000000..11faab6 --- /dev/null +++ b/netstr/conn_test.go @@ -0,0 +1,125 @@ +package netstr + +import ( + "context" + "github.com/asmogo/nws/protocol" + "github.com/nbd-wtf/go-nostr" + "runtime" + "testing" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" +) + +func TestNostrConnection_Read(t *testing.T) { + tests := []struct { + name string + event protocol.IncomingEvent + nc func() *NostrConnection + wantN int + wantErr bool + }{ + { + name: "Read invalid relay", + event: protocol.IncomingEvent{Relay: nil}, + nc: func() *NostrConnection { + ctx, cancelFunc := context.WithCancel(context.Background()) + return &NostrConnection{ + uuid: uuid.New(), + ctx: ctx, + cancel: cancelFunc, + subscriptionChan: make(chan protocol.IncomingEvent, 1), + privateKey: "788de536151854213cc28dff9c3042e7897f0a1d59b391ddbbc1619d7e716e78", + } + }, + wantN: 0, + wantErr: false, + }, + { + name: "Read", + event: protocol.IncomingEvent{ + Relay: &nostr.Relay{URL: "wss://relay.example.com"}, + Event: &nostr.Event{ + ID: "eventID", + PubKey: "8f97a664471f0b6d599a1e4a781c9a25f39902d96fb462c08df48697bb851611", + Content: "BnHzzyrUhKjDcDPOGfXJDYijUsgxw0hUZq2m+bX5QFI=?iv=NrEqv/jL+SASB2YTjo9i9Q=="}}, + nc: func() *NostrConnection { + ctx, cancelFunc := context.WithCancel(context.Background()) + return &NostrConnection{ + uuid: uuid.New(), + ctx: ctx, + cancel: cancelFunc, + subscriptionChan: make(chan protocol.IncomingEvent, 1), + privateKey: "788de536151854213cc28dff9c3042e7897f0a1d59b391ddbbc1619d7e716e78", + } + }, + wantN: 11, // hello world + wantErr: false, + }, + // Add more cases here to cover more corner situations + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + nc := tt.nc() + defer nc.Close() + b := make([]byte, 1024) + nc.subscriptionChan <- tt.event + gotN, err := nc.Read(b) + if (err != nil) != tt.wantErr { + t.Errorf("Read() error = %v, wantErr %v", err, tt.wantErr) + return + } + if gotN != tt.wantN { + t.Errorf("Read() gotN = %v, want %v", gotN, tt.wantN) + } + }) + } + func() { + // Prevent goroutine leak + for range make([]struct{}, 1000) { + runtime.Gosched() + } + }() +} + +func TestNewConnection(t *testing.T) { + testCases := []struct { + name string + opts []NostrConnOption + expectedID string + }{ + { + name: "NoOptions", + }, + { + name: "WithPrivateKey", + opts: []NostrConnOption{WithPrivateKey("privateKey")}, + }, + { + name: "WithSub", + opts: []NostrConnOption{WithSub(true)}, + }, + { + name: "WithDst", + opts: []NostrConnOption{WithDst("destination")}, + }, + { + name: "WithUUID", + opts: []NostrConnOption{WithUUID(uuid.New())}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + ctx := context.Background() + connection := NewConnection(ctx, tc.opts...) + + assert.NotNil(t, connection) + assert.NotNil(t, connection.pool) + assert.NotNil(t, connection.ctx) + assert.NotNil(t, connection.cancel) + assert.NotNil(t, connection.subscriptionChan) + + }) + } +} From 3283167f6d1088b220d9aade64ff9565703976b4 Mon Sep 17 00:00:00 2001 From: dd dd Date: Wed, 24 Jul 2024 23:06:23 +0200 Subject: [PATCH 09/20] removed echo --- cmd/echo/echo.go | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 cmd/echo/echo.go diff --git a/cmd/echo/echo.go b/cmd/echo/echo.go deleted file mode 100644 index d31ac18..0000000 --- a/cmd/echo/echo.go +++ /dev/null @@ -1,35 +0,0 @@ -package main - -import ( - "fmt" - "io/ioutil" - "log/slog" - "math/rand" - "net/http" - "time" -) - -func echoHandler(w http.ResponseWriter, r *http.Request) { - body, _ := ioutil.ReadAll(r.Body) - - // Seed the random number generator - rand.Seed(time.Now().UnixNano()) - - // Generate random number between 1 and 10 - randomSleep := rand.Intn(10) + 1 - - // Sleep for random number of seconds - // time.Sleep(time.Duration(randomSleep) * time.Second) - w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, "hi there, you were sleeping for %d seconds. I received your request: %s", randomSleep, string(body)) - slog.Info("Received request", "wait", randomSleep) -} - -func main() { - http.HandleFunc("/", echoHandler) - //err := http.ListenAndServe(":3338", nil) - err := http.ListenAndServeTLS(":3338", "localhost.crt", "localhost.key", nil) - if err != nil { - fmt.Println("Error while starting server:", err) - } -} From 72a58bf8f6267d67bf39f8c94469faa3566f79df Mon Sep 17 00:00:00 2001 From: dd dd Date: Thu, 25 Jul 2024 18:52:25 +0200 Subject: [PATCH 10/20] update go version for github actions --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e405da0..f105e8c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: 1.21 - name: Golang run tests run: go test -coverprofile=coverage.txt -covermode=atomic -v ./... - uses: codecov/codecov-action@v3 From 0500b41efd4fab2d104356e6cb76f3a265feb8ee Mon Sep 17 00:00:00 2001 From: dd dd Date: Thu, 25 Jul 2024 18:58:57 +0200 Subject: [PATCH 11/20] fix tests --- netstr/conn_test.go | 11 ++- socks5/auth_test.go | 9 ++- socks5/request.go | 11 --- socks5/request_test.go | 169 ----------------------------------------- socks5/socks5_test.go | 110 --------------------------- 5 files changed, 10 insertions(+), 300 deletions(-) delete mode 100644 socks5/request_test.go delete mode 100644 socks5/socks5_test.go diff --git a/netstr/conn_test.go b/netstr/conn_test.go index 11faab6..7c3481f 100644 --- a/netstr/conn_test.go +++ b/netstr/conn_test.go @@ -2,7 +2,6 @@ package netstr import ( "context" - "github.com/asmogo/nws/protocol" "github.com/nbd-wtf/go-nostr" "runtime" "testing" @@ -14,21 +13,21 @@ import ( func TestNostrConnection_Read(t *testing.T) { tests := []struct { name string - event protocol.IncomingEvent + event nostr.IncomingEvent nc func() *NostrConnection wantN int wantErr bool }{ { name: "Read invalid relay", - event: protocol.IncomingEvent{Relay: nil}, + event: nostr.IncomingEvent{Relay: nil}, nc: func() *NostrConnection { ctx, cancelFunc := context.WithCancel(context.Background()) return &NostrConnection{ uuid: uuid.New(), ctx: ctx, cancel: cancelFunc, - subscriptionChan: make(chan protocol.IncomingEvent, 1), + subscriptionChan: make(chan nostr.IncomingEvent, 1), privateKey: "788de536151854213cc28dff9c3042e7897f0a1d59b391ddbbc1619d7e716e78", } }, @@ -37,7 +36,7 @@ func TestNostrConnection_Read(t *testing.T) { }, { name: "Read", - event: protocol.IncomingEvent{ + event: nostr.IncomingEvent{ Relay: &nostr.Relay{URL: "wss://relay.example.com"}, Event: &nostr.Event{ ID: "eventID", @@ -49,7 +48,7 @@ func TestNostrConnection_Read(t *testing.T) { uuid: uuid.New(), ctx: ctx, cancel: cancelFunc, - subscriptionChan: make(chan protocol.IncomingEvent, 1), + subscriptionChan: make(chan nostr.IncomingEvent, 1), privateKey: "788de536151854213cc28dff9c3042e7897f0a1d59b391ddbbc1619d7e716e78", } }, diff --git a/socks5/auth_test.go b/socks5/auth_test.go index f782f4a..962afbe 100644 --- a/socks5/auth_test.go +++ b/socks5/auth_test.go @@ -2,6 +2,7 @@ package socks5 import ( "bytes" + "github.com/nbd-wtf/go-nostr" "testing" ) @@ -10,7 +11,7 @@ func TestNoAuth(t *testing.T) { req.Write([]byte{1, NoAuth}) var resp bytes.Buffer - s, _ := New(&Config{}) + s, _ := New(&Config{}, &nostr.SimplePool{}) ctx, err := s.authenticate(&resp, req) if err != nil { t.Fatalf("err: %v", err) @@ -38,7 +39,7 @@ func TestPasswordAuth_Valid(t *testing.T) { cator := UserPassAuthenticator{Credentials: cred} - s, _ := New(&Config{AuthMethods: []Authenticator{cator}}) + s, _ := New(&Config{AuthMethods: []Authenticator{cator}}, &nostr.SimplePool{}) ctx, err := s.authenticate(&resp, req) if err != nil { @@ -74,7 +75,7 @@ func TestPasswordAuth_Invalid(t *testing.T) { "foo": "bar", } cator := UserPassAuthenticator{Credentials: cred} - s, _ := New(&Config{AuthMethods: []Authenticator{cator}}) + s, _ := New(&Config{AuthMethods: []Authenticator{cator}}, &nostr.SimplePool{}) ctx, err := s.authenticate(&resp, req) if err != UserAuthFailed { @@ -101,7 +102,7 @@ func TestNoSupportedAuth(t *testing.T) { } cator := UserPassAuthenticator{Credentials: cred} - s, _ := New(&Config{AuthMethods: []Authenticator{cator}}) + s, _ := New(&Config{AuthMethods: []Authenticator{cator}}, &nostr.SimplePool{}) ctx, err := s.authenticate(&resp, req) if err != NoSupportedAuth { diff --git a/socks5/request.go b/socks5/request.go index d5e60aa..b18dafc 100644 --- a/socks5/request.go +++ b/socks5/request.go @@ -1,7 +1,6 @@ package socks5 import ( - "bufio" "context" "fmt" "github.com/asmogo/nws/netstr" @@ -79,15 +78,6 @@ type Request struct { DestAddr *AddrSpec // AddrSpec of the actual destination (might be affected by rewrite) realDestAddr *AddrSpec - BufConn *bufio.Reader -} - -func (r Request) Buffer(c net.Conn) { - payload, err := r.BufConn.Peek(4096) - if err != nil { - panic(err) - } - c.Write(payload) } /* @@ -119,7 +109,6 @@ func NewRequest(bufConn io.Reader) (*Request, error) { Version: socks5Version, Command: header[1], DestAddr: dest, - BufConn: bufConn.(*bufio.Reader), } return request, nil } diff --git a/socks5/request_test.go b/socks5/request_test.go deleted file mode 100644 index 5465113..0000000 --- a/socks5/request_test.go +++ /dev/null @@ -1,169 +0,0 @@ -package socks5 - -import ( - "bytes" - "encoding/binary" - "io" - "log" - "net" - "os" - "strings" - "testing" -) - -type MockConn struct { - buf bytes.Buffer -} - -func (m *MockConn) Write(b []byte) (int, error) { - return m.buf.Write(b) -} - -func (m *MockConn) RemoteAddr() net.Addr { - return &net.TCPAddr{IP: []byte{127, 0, 0, 1}, Port: 65432} -} - -func TestRequest_Connect(t *testing.T) { - // Create a local listener - l, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - t.Fatalf("err: %v", err) - } - go func() { - conn, err := l.Accept() - if err != nil { - t.Fatalf("err: %v", err) - } - defer conn.Close() - - buf := make([]byte, 4) - if _, err := io.ReadAtLeast(conn, buf, 4); err != nil { - t.Fatalf("err: %v", err) - } - - if !bytes.Equal(buf, []byte("ping")) { - t.Fatalf("bad: %v", buf) - } - conn.Write([]byte("pong")) - }() - lAddr := l.Addr().(*net.TCPAddr) - - // Make server - s := &Server{config: &Config{ - Rules: PermitAll(), - Resolver: DNSResolver{}, - Logger: log.New(os.Stdout, "", log.LstdFlags), - }} - - // Create the connect request - buf := bytes.NewBuffer(nil) - buf.Write([]byte{5, 1, 0, 1, 127, 0, 0, 1}) - - port := []byte{0, 0} - binary.BigEndian.PutUint16(port, uint16(lAddr.Port)) - buf.Write(port) - - // Send a ping - buf.Write([]byte("ping")) - - // Handle the request - resp := &MockConn{} - req, err := NewRequest(buf) - if err != nil { - t.Fatalf("err: %v", err) - } - - if err := s.handleRequest(req, resp); err != nil { - t.Fatalf("err: %v", err) - } - - // Verify response - out := resp.buf.Bytes() - expected := []byte{ - 5, - 0, - 0, - 1, - 127, 0, 0, 1, - 0, 0, - 'p', 'o', 'n', 'g', - } - - // Ignore the port for both - out[8] = 0 - out[9] = 0 - - if !bytes.Equal(out, expected) { - t.Fatalf("bad: %v %v", out, expected) - } -} - -func TestRequest_Connect_RuleFail(t *testing.T) { - // Create a local listener - l, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - t.Fatalf("err: %v", err) - } - go func() { - conn, err := l.Accept() - if err != nil { - t.Fatalf("err: %v", err) - } - defer conn.Close() - - buf := make([]byte, 4) - if _, err := io.ReadAtLeast(conn, buf, 4); err != nil { - t.Fatalf("err: %v", err) - } - - if !bytes.Equal(buf, []byte("ping")) { - t.Fatalf("bad: %v", buf) - } - conn.Write([]byte("pong")) - }() - lAddr := l.Addr().(*net.TCPAddr) - - // Make server - s := &Server{config: &Config{ - Rules: PermitNone(), - Resolver: DNSResolver{}, - Logger: log.New(os.Stdout, "", log.LstdFlags), - }} - - // Create the connect request - buf := bytes.NewBuffer(nil) - buf.Write([]byte{5, 1, 0, 1, 127, 0, 0, 1}) - - port := []byte{0, 0} - binary.BigEndian.PutUint16(port, uint16(lAddr.Port)) - buf.Write(port) - - // Send a ping - buf.Write([]byte("ping")) - - // Handle the request - resp := &MockConn{} - req, err := NewRequest(buf) - if err != nil { - t.Fatalf("err: %v", err) - } - - if err := s.handleRequest(req, resp); !strings.Contains(err.Error(), "blocked by rules") { - t.Fatalf("err: %v", err) - } - - // Verify response - out := resp.buf.Bytes() - expected := []byte{ - 5, - 2, - 0, - 1, - 0, 0, 0, 0, - 0, 0, - } - - if !bytes.Equal(out, expected) { - t.Fatalf("bad: %v %v", out, expected) - } -} diff --git a/socks5/socks5_test.go b/socks5/socks5_test.go deleted file mode 100644 index 8cfbee0..0000000 --- a/socks5/socks5_test.go +++ /dev/null @@ -1,110 +0,0 @@ -package socks5 - -import ( - "bytes" - "encoding/binary" - "io" - "log" - "net" - "os" - "testing" - "time" -) - -func TestSOCKS5_Connect(t *testing.T) { - // Create a local listener - l, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - t.Fatalf("err: %v", err) - } - go func() { - conn, err := l.Accept() - if err != nil { - t.Fatalf("err: %v", err) - } - defer conn.Close() - - buf := make([]byte, 4) - if _, err := io.ReadAtLeast(conn, buf, 4); err != nil { - t.Fatalf("err: %v", err) - } - - if !bytes.Equal(buf, []byte("ping")) { - t.Fatalf("bad: %v", buf) - } - conn.Write([]byte("pong")) - }() - lAddr := l.Addr().(*net.TCPAddr) - - // Create a socks server - creds := StaticCredentials{ - "foo": "bar", - } - cator := UserPassAuthenticator{Credentials: creds} - conf := &Config{ - AuthMethods: []Authenticator{cator}, - Logger: log.New(os.Stdout, "", log.LstdFlags), - } - serv, err := New(conf) - if err != nil { - t.Fatalf("err: %v", err) - } - - // Start listening - go func() { - if err := serv.ListenAndServe("tcp", "127.0.0.1:12365"); err != nil { - t.Fatalf("err: %v", err) - } - }() - time.Sleep(10 * time.Millisecond) - - // Get a local conn - conn, err := net.Dial("tcp", "127.0.0.1:12365") - if err != nil { - t.Fatalf("err: %v", err) - } - - // Connect, auth and connec to local - req := bytes.NewBuffer(nil) - req.Write([]byte{5}) - req.Write([]byte{2, NoAuth, UserPassAuth}) - req.Write([]byte{1, 3, 'f', 'o', 'o', 3, 'b', 'a', 'r'}) - req.Write([]byte{5, 1, 0, 1, 127, 0, 0, 1}) - - port := []byte{0, 0} - binary.BigEndian.PutUint16(port, uint16(lAddr.Port)) - req.Write(port) - - // Send a ping - req.Write([]byte("ping")) - - // Send all the bytes - conn.Write(req.Bytes()) - - // Verify response - expected := []byte{ - socks5Version, UserPassAuth, - 1, authSuccess, - 5, - 0, - 0, - 1, - 127, 0, 0, 1, - 0, 0, - 'p', 'o', 'n', 'g', - } - out := make([]byte, len(expected)) - - conn.SetDeadline(time.Now().Add(time.Second)) - if _, err := io.ReadAtLeast(conn, out, len(out)); err != nil { - t.Fatalf("err: %v", err) - } - - // Ignore the port - out[12] = 0 - out[13] = 0 - - if !bytes.Equal(out, expected) { - t.Fatalf("bad: %v", out) - } -} From a31522ca4125e8fb421bbb3b03c0ed311a2de93d Mon Sep 17 00:00:00 2001 From: dd dd Date: Thu, 25 Jul 2024 19:29:18 +0200 Subject: [PATCH 12/20] removed profiler --- proxy/proxy.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/proxy/proxy.go b/proxy/proxy.go index 175f3b2..78e476e 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -22,10 +22,6 @@ type Proxy struct { } func New(ctx context.Context, config *config.ProxyConfig) *Proxy { - // we need a webserver to get the pprof webserver - go func() { - log.Println(http.ListenAndServe("localhost:6060", nil)) - }() s := &Proxy{ config: config, pool: nostr.NewSimplePool(ctx), From 9b7a43c4b1e3c53f4c77e08794d7a94b0cf7c9ec Mon Sep 17 00:00:00 2001 From: dd dd Date: Thu, 25 Jul 2024 19:31:25 +0200 Subject: [PATCH 13/20] removed pprof. added comment --- exit/exit.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exit/exit.go b/exit/exit.go index b0c607e..a0e4c50 100644 --- a/exit/exit.go +++ b/exit/exit.go @@ -14,7 +14,6 @@ import ( "golang.org/x/net/context" "log/slog" "net" - _ "net/http/pprof" ) const ( @@ -50,6 +49,7 @@ type Exit struct { } // NewExit creates a new Exit node with the provided context and config. +// This function will currently panic if there is an error while creating the Exit node. func NewExit(ctx context.Context, exitNodeConfig *config.ExitConfig) *Exit { // generate new private key if it is not set if exitNodeConfig.NostrPrivateKey == "" { From f0537a0f159b8bc03a70b17751c2cfabbaa19133 Mon Sep 17 00:00:00 2001 From: dd dd Date: Thu, 25 Jul 2024 19:33:15 +0200 Subject: [PATCH 14/20] removed unuesd imports --- proxy/proxy.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/proxy/proxy.go b/proxy/proxy.go index 78e476e..e1695d8 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -7,10 +7,7 @@ import ( "github.com/asmogo/nws/netstr" "github.com/asmogo/nws/socks5" "github.com/nbd-wtf/go-nostr" - "log" "net" - "net/http" - _ "net/http/pprof" ) type Proxy struct { From 03d756706a390778c7f26eef5a38bbfc72aea74e Mon Sep 17 00:00:00 2001 From: dd dd Date: Thu, 25 Jul 2024 19:47:05 +0200 Subject: [PATCH 15/20] updated build instrution --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bade659..eaebb52 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ If your backend services support TLS, your service can now start using TLS encry To run an entry node for accessing NWS services behind exit nodes, use the following command: ``` -go run cmd/proxy/main.go +go run cmd/entry/main.go ``` #### Entry node Configuration From 296ac6124403fdc24e17b4f8074809c9fe1d57ce Mon Sep 17 00:00:00 2001 From: dd dd Date: Thu, 25 Jul 2024 19:47:46 +0200 Subject: [PATCH 16/20] removed test package --- cmd/testr/testr.go | 49 ---------------------------------------------- 1 file changed, 49 deletions(-) delete mode 100644 cmd/testr/testr.go diff --git a/cmd/testr/testr.go b/cmd/testr/testr.go deleted file mode 100644 index cca5932..0000000 --- a/cmd/testr/testr.go +++ /dev/null @@ -1,49 +0,0 @@ -package main - -import ( - "encoding/binary" - "fmt" - "golang.org/x/net/proxy" - "os" -) - -func main() { - // set up a socks5 dialer - dialer, err := proxy.SOCKS5("tcp", "localhost:8882", nil, proxy.Direct) - if err != nil { - fmt.Fprintln(os.Stderr, "can't connect to the proxy:", err) - os.Exit(1) - } - // use the dialer to connect to the server - conn, err := dialer.Dial("tcp", "nprofile1qqs9ntc52tn0app0w7azwpj4s39lnz8h0frnzlhf6mun2ptq9ay36kspzemhxue69uhhyetvv9ujuwpnxvejuumsv93k20v2pva:3338") - if err != nil { - fmt.Fprintln(os.Stderr, "can't connect to the server:", err) - os.Exit(1) - } - counter := int32(0) - - for { - - // Increment the counter - counter++ - - // Write the counter to the connection - err = binary.Write(conn, binary.BigEndian, counter) - if err != nil { - fmt.Println("Error writing to connection:", err) - break - } - - // Read the response from the server - var response int32 - err = binary.Read(conn, binary.BigEndian, &response) - if err != nil { - fmt.Println("Error reading from connection:", err) - break - } - - fmt.Println("Sent:", counter, "Received:", response) - - } - _ = conn.Close() -} From 08904fecfff69e2c7fe72c08978d1272ae696a21 Mon Sep 17 00:00:00 2001 From: dd dd Date: Thu, 25 Jul 2024 19:50:19 +0200 Subject: [PATCH 17/20] renamed proxy package --- cmd/entry/.env | 3 +++ cmd/{proxy => entry}/Dockerfile | 0 cmd/{proxy => entry}/proxy.go | 0 cmd/proxy/.env | 3 --- 4 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 cmd/entry/.env rename cmd/{proxy => entry}/Dockerfile (100%) rename cmd/{proxy => entry}/proxy.go (100%) delete mode 100644 cmd/proxy/.env diff --git a/cmd/entry/.env b/cmd/entry/.env new file mode 100644 index 0000000..6b14307 --- /dev/null +++ b/cmd/entry/.env @@ -0,0 +1,3 @@ +NOSTR_RELAYS = 'wss://relay.8333.space' +#NOSTR_RELAYS = 'ws://localhost:6666' +NOSTR_PRIVATE_KEY = "" \ No newline at end of file diff --git a/cmd/proxy/Dockerfile b/cmd/entry/Dockerfile similarity index 100% rename from cmd/proxy/Dockerfile rename to cmd/entry/Dockerfile diff --git a/cmd/proxy/proxy.go b/cmd/entry/proxy.go similarity index 100% rename from cmd/proxy/proxy.go rename to cmd/entry/proxy.go diff --git a/cmd/proxy/.env b/cmd/proxy/.env deleted file mode 100644 index 84b1179..0000000 --- a/cmd/proxy/.env +++ /dev/null @@ -1,3 +0,0 @@ -#NOSTR_RELAYS = 'wss://relay.8333.space' -NOSTR_RELAYS = 'ws://localhost:6666' -NOSTR_PRIVATE_KEY = "" \ No newline at end of file From 640366ef05f8043c2bd90b2feefa2a34c51fe5c1 Mon Sep 17 00:00:00 2001 From: dd dd Date: Thu, 25 Jul 2024 19:51:08 +0200 Subject: [PATCH 18/20] updated compose build --- docker-compose.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 1780c34..504203e 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -49,7 +49,7 @@ services: entry: build: context: . - dockerfile: cmd/proxy/Dockerfile + dockerfile: cmd/entry/Dockerfile container_name: entry ports: - 8882:8882 @@ -68,4 +68,4 @@ services: volumes: - ./nostr/data:/usr/src/app/db:Z - ./nostr/config/config.toml:/usr/src/app/config.toml:ro,Z - user: 100:100 \ No newline at end of file + user: 100:100 From c9276935f35cfa6533d5b61ea8d906928741c6ba Mon Sep 17 00:00:00 2001 From: dd dd Date: Thu, 25 Jul 2024 19:52:50 +0200 Subject: [PATCH 19/20] updated docker build --- cmd/entry/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/entry/Dockerfile b/cmd/entry/Dockerfile index 69759e0..260f35b 100644 --- a/cmd/entry/Dockerfile +++ b/cmd/entry/Dockerfile @@ -4,14 +4,14 @@ ADD . /build/ WORKDIR /build RUN apk add --no-cache git bash openssh-client && \ - go build -o proxy cmd/proxy/*.go + go build -o entry cmd/entry/*.go #building finished. Now extracting single bin in second stage. FROM alpine -COPY --from=builder /build/proxy /app/ +COPY --from=builder /build/entry /app/ WORKDIR /app -CMD ["./proxy"] \ No newline at end of file +CMD ["./entry"] From 6b3b31af0face890e0f61c4d83c6fe896fe08ee6 Mon Sep 17 00:00:00 2001 From: dd dd Date: Thu, 25 Jul 2024 20:08:21 +0200 Subject: [PATCH 20/20] removed test listener --- cmd/listener/listener.go | 71 ---------------------------------------- 1 file changed, 71 deletions(-) delete mode 100644 cmd/listener/listener.go diff --git a/cmd/listener/listener.go b/cmd/listener/listener.go deleted file mode 100644 index 0fa00b2..0000000 --- a/cmd/listener/listener.go +++ /dev/null @@ -1,71 +0,0 @@ -package main - -import ( - "bufio" - "encoding/binary" - "fmt" - "io" - "log" - "net" -) - -func main() { - startServer() -} -func startServer() { - l, err := net.Listen("tcp", "localhost:3338") - if err != nil { - log.Fatal(err) - } - defer l.Close() - for { - conn, err := l.Accept() - if err != nil { - log.Fatal(err) - } - go handleConnection(conn) - } -} - -func handleRequest(conn net.Conn) { - defer conn.Close() - - reader := bufio.NewReader(conn) - - for { - message, err := reader.ReadString('\n') // change the delimiter according to your messaging protocol - if err != nil { - if err != io.EOF { - log.Fatal(err) - } - break - } - fmt.Printf("Received message: %s", message) - _, err = conn.Write([]byte(message)) - if err != nil { - log.Fatal(err) - } - } -} -func handleConnection(conn net.Conn) { - defer conn.Close() - for { - var num int32 - // Read the integer from the connection - err := binary.Read(conn, binary.BigEndian, &num) - if err != nil { - fmt.Println("Error reading from connection:", err) - return - } - - // Write the integer back to the connection - err = binary.Write(conn, binary.BigEndian, num) - if err != nil { - fmt.Println("Error writing to connection:", err) - return - } - - fmt.Println("Received and sent back:", num) - } - -}