From dd38809942b807f753d163d27f9d4eada0a98fee Mon Sep 17 00:00:00 2001 From: Trajan0x Date: Thu, 21 Dec 2023 02:43:33 -0400 Subject: [PATCH] remove tunnel functionality --- core/go.mod | 6 +- core/go.sum | 8 - core/tunnel/internal/check.go | 41 ----- core/tunnel/internal/internal.go | 2 - core/tunnel/internal/proxy.go | 44 ----- core/tunnel/internal/proxy_test.go | 7 - core/tunnel/moe/doc.go | 8 - core/tunnel/moe/export_test.go | 14 -- core/tunnel/moe/moe.go | 110 ------------- core/tunnel/moe/ssh.go | 255 ----------------------------- core/tunnel/moe/ssh_test.go | 57 ------- core/tunnel/ngrok/doc.go | 2 - core/tunnel/ngrok/ngrok.go | 85 ---------- core/tunnel/options.go | 51 ------ core/tunnel/provider.go | 13 -- core/tunnel/provider_string.go | 25 --- core/tunnel/suite_test.go | 86 ---------- core/tunnel/tunnel.go | 32 ---- core/tunnel/tunnel_test.go | 84 ---------- core/tunnel/types/provider.go | 12 -- 20 files changed, 1 insertion(+), 941 deletions(-) delete mode 100644 core/tunnel/internal/check.go delete mode 100644 core/tunnel/internal/internal.go delete mode 100644 core/tunnel/internal/proxy.go delete mode 100644 core/tunnel/internal/proxy_test.go delete mode 100644 core/tunnel/moe/doc.go delete mode 100644 core/tunnel/moe/export_test.go delete mode 100644 core/tunnel/moe/moe.go delete mode 100644 core/tunnel/moe/ssh.go delete mode 100644 core/tunnel/moe/ssh_test.go delete mode 100644 core/tunnel/ngrok/doc.go delete mode 100644 core/tunnel/ngrok/ngrok.go delete mode 100644 core/tunnel/options.go delete mode 100644 core/tunnel/provider.go delete mode 100644 core/tunnel/provider_string.go delete mode 100644 core/tunnel/suite_test.go delete mode 100644 core/tunnel/tunnel.go delete mode 100644 core/tunnel/tunnel_test.go delete mode 100644 core/tunnel/types/provider.go diff --git a/core/go.mod b/core/go.mod index c60d1ea638..f9e7e2f65b 100644 --- a/core/go.mod +++ b/core/go.mod @@ -53,8 +53,6 @@ require ( go.opentelemetry.io/otel/sdk/metric v0.39.0 go.opentelemetry.io/otel/trace v1.16.0 go.uber.org/zap v1.25.0 - golang.ngrok.com/ngrok v1.0.0 - golang.org/x/crypto v0.11.0 golang.org/x/sync v0.3.0 gorm.io/driver/sqlite v1.5.3 gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55 @@ -107,8 +105,6 @@ require ( github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 // indirect github.com/imdario/mergo v0.3.13 // indirect - github.com/inconshreveable/log15 v3.0.0-testing.3+incompatible // indirect - github.com/inconshreveable/log15/v3 v3.0.0-testing.5 // indirect github.com/ipfs/go-log/v2 v2.1.3 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jinzhu/inflection v1.0.0 // indirect @@ -163,10 +159,10 @@ require ( go.opentelemetry.io/proto/otlp v0.19.0 // indirect go.uber.org/multierr v1.10.0 // indirect golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.11.0 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/net v0.12.0 // indirect golang.org/x/sys v0.10.0 // indirect - golang.org/x/term v0.10.0 // indirect golang.org/x/text v0.11.0 // indirect golang.org/x/tools v0.9.3 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect diff --git a/core/go.sum b/core/go.sum index 0ef03cca63..fbf47ceae8 100644 --- a/core/go.sum +++ b/core/go.sum @@ -294,15 +294,10 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 h1:lLT7ZLSzGLI08vc9cpd+tYmNWjd github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= -github.com/inconshreveable/log15 v3.0.0-testing.3+incompatible h1:zaX5fYT98jX5j4UhO/WbfY8T1HkgVrydiDMC9PWqGCo= -github.com/inconshreveable/log15 v3.0.0-testing.3+incompatible/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= -github.com/inconshreveable/log15/v3 v3.0.0-testing.5 h1:h4e0f3kjgg+RJBlKOabrohjHe47D3bbAB9BgMrc3DYA= -github.com/inconshreveable/log15/v3 v3.0.0-testing.5/go.mod h1:3GQg1SVrLoWGfRv/kAZMsdyU5cp8eFc1P3cw+Wwku94= github.com/integralist/go-findroot v0.0.0-20160518114804-ac90681525dc h1:4IZpk3M4m6ypx0IlRoEyEyY1gAdicWLMQ0NcG/gBnnA= github.com/integralist/go-findroot v0.0.0-20160518114804-ac90681525dc/go.mod h1:UlaC6ndby46IJz9m/03cZPKKkR9ykeIVBBDE3UDBdJk= github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= @@ -565,8 +560,6 @@ go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= -golang.ngrok.com/ngrok v1.0.0 h1:36xgYK8C05D4V/KslXc+Nm6E+qorNLv8zZiQCHO+FB4= -golang.ngrok.com/ngrok v1.0.0/go.mod h1:h0SmDbrHimeTrjlMgUWh21Ni3e4s5SQZm2nMJZe3XHI= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= @@ -758,7 +751,6 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/core/tunnel/internal/check.go b/core/tunnel/internal/check.go deleted file mode 100644 index b306c24ce8..0000000000 --- a/core/tunnel/internal/check.go +++ /dev/null @@ -1,41 +0,0 @@ -package internal - -import ( - "context" - "fmt" - "net" - "net/http" -) - -// CheckPathFunc is called when the checkPath is hit. -type CheckPathFunc func() - -// VerifiableProxy is a proxy that has an overidable path. The path calls checkFunc when hit. -// this is used to make sure a proxy has started. -func VerifiableProxy(ctx context.Context, backendURL, checkPath string, listener net.Listener, pathFunc CheckPathFunc) (_ <-chan error) { - errChan := make(chan error, 1) - - proxy, err := newCheckableProxy(backendURL, checkPath, pathFunc) - if err != nil { - select { - case <-ctx.Done(): - return errChan - case errChan <- err: - return errChan - } - } - - go func() { - err = http.Serve(listener, proxy) - if err != nil { - select { - case errChan <- fmt.Errorf("could not serve ngrok: %w", err): - return - case <-ctx.Done(): - return - } - } - }() - - return errChan -} diff --git a/core/tunnel/internal/internal.go b/core/tunnel/internal/internal.go deleted file mode 100644 index 073cf677ed..0000000000 --- a/core/tunnel/internal/internal.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package internal provides the internal tunnel implementation. -package internal diff --git a/core/tunnel/internal/proxy.go b/core/tunnel/internal/proxy.go deleted file mode 100644 index 089f832772..0000000000 --- a/core/tunnel/internal/proxy.go +++ /dev/null @@ -1,44 +0,0 @@ -package internal - -import ( - "fmt" - "net/http" - "net/http/httputil" - "net/url" -) - -func newCheckableProxy(backendURL string, checkPath string, checkFunc CheckPathFunc) (*checkableProxy, error) { - parsedURL, err := url.Parse(backendURL) - if err != nil { - return nil, fmt.Errorf("could not parse backend URL: %w", err) - } - - proxy := httputil.NewSingleHostReverseProxy(parsedURL) - - return &checkableProxy{ - proxy: proxy, - checkPath: checkPath, - checkFunc: checkFunc, - }, nil -} - -type checkableProxy struct { - // proxy is the underlying proxy. - proxy *httputil.ReverseProxy - // checkPath is the checkPath - checkPath string - // checkFunc is called when checkPath is hit - checkFunc CheckPathFunc -} - -func (c checkableProxy) ServeHTTP(writer http.ResponseWriter, request *http.Request) { - if c.checkPath == request.URL.Path { - c.checkFunc() - writer.WriteHeader(http.StatusOK) - return - } - - c.proxy.ServeHTTP(writer, request) -} - -var _ http.Handler = &checkableProxy{} diff --git a/core/tunnel/internal/proxy_test.go b/core/tunnel/internal/proxy_test.go deleted file mode 100644 index 2d2bbc41f7..0000000000 --- a/core/tunnel/internal/proxy_test.go +++ /dev/null @@ -1,7 +0,0 @@ -package internal_test - -import "testing" - -func TestVerifiableProxy(t *testing.T) { - t.Skip("this test is in the tunnel/suite_test.go file") -} diff --git a/core/tunnel/moe/doc.go b/core/tunnel/moe/doc.go deleted file mode 100644 index 3eece70710..0000000000 --- a/core/tunnel/moe/doc.go +++ /dev/null @@ -1,8 +0,0 @@ -// Package moe provides a tunnel that uses the Moe protocol. -// this module is currently broken due to an issue with moe. -// this is caused by two issues: -// 1. Moe returns localhost as the hostname: https://github.com/fasmide/remotemoe/blob/13a9ba0f5ddadffdf4fb395ebff7c366b88a0745/ssh/session.go#L363 -// 2. Go assumes the response returned by forwarded-tcpip is a tcp address: https://github.com/golang/crypto/blob/master/ssh/tcpip.go#L211 -// A PR has been made to fix this: https://github.com/fasmide/remotemoe/pull/18 and this module will be ready when that's merged -// should the PR be unmergable for an extended period of time, we can intercept the requests in the net.Conn through a reverse ssh proxy -package moe diff --git a/core/tunnel/moe/export_test.go b/core/tunnel/moe/export_test.go deleted file mode 100644 index 22fad055b6..0000000000 --- a/core/tunnel/moe/export_test.go +++ /dev/null @@ -1,14 +0,0 @@ -package moe - -import ( - "context" - "io" -) - -// Export for testing. -const MoeServer = moeServer - -// ConsumeBufferUntilURL exports consumeBufferUntilURL for testing. -func ConsumeBufferUntilURL(ctx context.Context, reader io.Reader) (host string, err error) { - return consumeBufferUntilURL(ctx, reader) -} diff --git a/core/tunnel/moe/moe.go b/core/tunnel/moe/moe.go deleted file mode 100644 index 7800da25a4..0000000000 --- a/core/tunnel/moe/moe.go +++ /dev/null @@ -1,110 +0,0 @@ -package moe - -import ( - "context" - "fmt" - "github.com/brianvoe/gofakeit/v6" - "github.com/ipfs/go-log" - "github.com/jpillora/backoff" - "github.com/phayes/freeport" - "github.com/synapsecns/sanguine/core/tunnel/internal" - "github.com/synapsecns/sanguine/core/tunnel/types" - "net" - "net/http" - "time" -) - -var logger = log.Logger("moe") - -type moeProvider struct { - // checkPath is a path we override the backend with to check if the tunnel is up. - checkPath string - // checkChan is a channel that is closed when the checkPath is hit. - checkChan chan bool -} - -// New returns a new moe provider. -func New() types.Provider { - return &moeProvider{ - checkPath: fmt.Sprintf("/%s", gofakeit.UUID()), - checkChan: make(chan bool, 1), - } -} - -type hostInfo struct { - hostname string - port int -} - -// makeListener returns the hostname and port of a listener. -func (m *moeProvider) makeListener() hostInfo { - port := freeport.GetPort() - return hostInfo{ - port: port, - hostname: fmt.Sprintf("localhost:%d", port), - } -} - -// moeServer is the remote moe server. -const moeServer = "remote.moe" -const remotePort = 80 - -// nolint: cyclop -func (m *moeProvider) Start(ctx context.Context, backendURL string) (_ string, err error) { - var lc net.ListenConfig - - // make the verifiable proxy and listener - verifiableProxy := m.makeListener() - vpListener, err := lc.Listen(ctx, "tcp", verifiableProxy.hostname) - if err != nil { - return "", fmt.Errorf("could not start moe: %w", err) - } - - errChan := internal.VerifiableProxy(ctx, backendURL, m.checkPath, vpListener, func() { - m.checkChan <- true - }) - - // make the backend proxy and listener - host, err := createTunnel(context.Background(), moeServer, verifiableProxy.port, remotePort) - if err != nil { - return "", fmt.Errorf("could not get tunnel") - } - - // TODO: this needs to be deduped w/ moe - timeout := &backoff.Backoff{ - Factor: 2, - Jitter: true, - Min: 200 * time.Millisecond, - Max: time.Second, - } - - // give the server a max of 30 seconds to start - ctx, cancel := context.WithTimeout(ctx, time.Second*30) - defer cancel() - duration := time.Duration(0) - for { - select { - case <-ctx.Done(): - return "", nil - case err := <-errChan: - return "", fmt.Errorf("could not serve ngrok: %w", err) - case <-time.After(duration): - req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s%s", host, m.checkPath), nil) - if err != nil { - return "", fmt.Errorf("could not create request: %w", err) - } - - resp, err := http.DefaultClient.Do(req) - if err != nil { - duration = timeout.Duration() - continue - } - - if resp != nil { - _ = resp.Body.Close() - } - case <-m.checkChan: - return backendURL, nil - } - } -} diff --git a/core/tunnel/moe/ssh.go b/core/tunnel/moe/ssh.go deleted file mode 100644 index 8fba34389c..0000000000 --- a/core/tunnel/moe/ssh.go +++ /dev/null @@ -1,255 +0,0 @@ -package moe - -import ( - "bufio" - "context" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "encoding/pem" - "fmt" - "golang.org/x/crypto/ssh" - "io" - "net" - "os" - "regexp" - "strings" - "time" -) - -// Get private key for ssh authentication. -func generatePrivateKey() (ssh.Signer, error) { - privateKey, err := rsa.GenerateKey(rand.Reader, 2048) - if err != nil { - return nil, fmt.Errorf("failed to generate private key: %w", err) - } - - privateKeyBytes := pem.EncodeToMemory(&pem.Block{ - Type: "RSA PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(privateKey), - }) - - sshPrivateKey, err := ssh.ParseRawPrivateKey(privateKeyBytes) - if err != nil { - return nil, fmt.Errorf("failed to parse private key: %w", err) - } - signer, err := ssh.NewSignerFromKey(sshPrivateKey) - if err != nil { - return nil, fmt.Errorf("failed to create signer: %w", err) - } - return signer, nil -} - -// Get ssh client config for our connection -// SSH config will use 2 authentication strategies: by key and by password. -func makeSSHConfig() (*ssh.ClientConfig, error) { - key, err := generatePrivateKey() - if err != nil { - return nil, err - } - - config := ssh.ClientConfig{ - Auth: []ssh.AuthMethod{ - ssh.PublicKeys(key), - }, - //nolint: gosec - HostKeyCallback: ssh.InsecureIgnoreHostKey(), - } - - return &config, nil -} - -// From https://sosedoff.com/2015/05/25/ssh-port-forwarding-with-go.html -// Handle local client connections and tunnel data to the remote server -// Will use io.Copy - http://golang.org/pkg/io/#Copy -func handleClient(client net.Conn, remote net.Conn) { - defer func() { - _ = client.Close() - }() - chDone := make(chan bool) - - // Start remote -> local data transfer - go func() { - _, err := io.Copy(client, remote) - if err != nil { - logger.Debugf("error while copy remote->local: %w", err) - } - chDone <- true - }() - - // Start local -> remote data transfer - go func() { - _, err := io.Copy(remote, client) - if err != nil { - logger.Debugf("error while copy local->remote: %w", err) - } - chDone <- true - }() - - <-chDone -} - -func createTunnel(ctx context.Context, sshAddr string, localPort, remotePort int) (host string, err error) { - errChan := make(chan error, 1) - hostChan := make(chan string, 1) - - go func() { - startReverseSSHTunnel(ctx, sshAddr, localPort, remotePort, errChan, hostChan) - }() - - select { - case <-ctx.Done(): - return "", fmt.Errorf("context canceled: %w", ctx.Err()) - case host := <-hostChan: - // after this point, we'll need to consume and log the errors since we can't tell the client anything - go func() { - select { - case <-ctx.Done(): - return - case err := <-errChan: - logger.Warn(err) - } - }() - return host, nil - case err := <-errChan: - return "", fmt.Errorf("could not start proxy: %w", err) - } -} - -// appendToErrChan appends the error to the error channel if the context is not done. -func appendToErrChan(ctx context.Context, err error, errChan chan<- error) { - select { - case <-ctx.Done(): - case errChan <- err: - } -} - -// appendToHostChan adds the host to the host chan. -func appendToHostChan(ctx context.Context, host string, hostChan chan<- string) { - select { - case <-ctx.Done(): - case hostChan <- host: - } -} - -// nolint: cyclop -func startReverseSSHTunnel(ctx context.Context, sshAddr string, localPort, remotePort int, errChan chan<- error, hostChan chan<- string) { - // Build SSH client configuration - cfg, err := makeSSHConfig() - if err != nil { - appendToErrChan(ctx, fmt.Errorf("failed to make ssh config: %w", err), errChan) - return - } - - // Connect to SSH remote server using serverEndpoint - serverConn, err := ssh.Dial("tcp", net.JoinHostPort(sshAddr, "22"), cfg) - if err != nil { - appendToErrChan(ctx, fmt.Errorf("failed to make ssh config: %w", err), errChan) - return - } - - // Listen on remote server port - listener, err := serverConn.Listen("tcp", fmt.Sprintf("127.0.01:%d", remotePort)) - if err != nil { - appendToErrChan(ctx, fmt.Errorf("listen open port ON remote server error: %w", err), errChan) - return - } - - defer func() { - _ = listener.Close() - }() - - // Create a new session - session, err := serverConn.NewSession() - if err != nil { - appendToErrChan(ctx, fmt.Errorf("listen open port ON remote server error: %w", err), errChan) - return - } - - defer func() { - _ = session.Close() - }() - - session.Stderr = os.Stderr - stdOut, err := session.StdoutPipe() - if err != nil { - appendToErrChan(ctx, fmt.Errorf("failed to make ssh config: %w", err), errChan) - return - } - - err = session.RequestPty("xterm", 80, 40, ssh.TerminalModes{ - ssh.ECHO: 1, // enable echoing - ssh.TTY_OP_ISPEED: 14400, - ssh.TTY_OP_OSPEED: 14400, - }) - if err != nil { - appendToErrChan(ctx, fmt.Errorf("could not request pty: %w", err), errChan) - return - } - - err = session.Shell() - if err != nil { - appendToErrChan(ctx, fmt.Errorf("failed to start: %w", err), errChan) - return - } - - // wait for the banner - consumeCtx, cancel := context.WithTimeout(ctx, time.Second*30) - defer cancel() - - var host string - host, err = consumeBufferUntilURL(ctx, stdOut) - if err != nil { - appendToErrChan(consumeCtx, fmt.Errorf("could not request pty: %w", err), errChan) - return - } - appendToHostChan(ctx, host, hostChan) - - // handle incoming connections on reverse forwarded tunnel - for { - // Open a (local) connection to localEndpoint whose content will be forwarded to serverEndpoint - local, err := net.Dial("tcp", fmt.Sprintf(":%d", localPort)) - if err != nil { - appendToErrChan(ctx, fmt.Errorf("dial INTO local service error: %w", err), errChan) - return - } - - client, err := listener.Accept() - if err != nil { - appendToErrChan(ctx, fmt.Errorf("could not accept connection: %w", err), errChan) - return - } - - handleClient(client, local) - } -} - -var re = regexp.MustCompile(`https?://[^\s]+`) - -// nolint: nestif -func consumeBufferUntilURL(ctx context.Context, reader io.Reader) (host string, err error) { - scanner := bufio.NewScanner(reader) - var buffer string - for { - select { - case <-ctx.Done(): - return "", fmt.Errorf("context canceled before string was found") - default: - if scanner.Scan() { - buffer += scanner.Text() - if strings.Contains(buffer, moeServer) { - matches := re.FindStringSubmatch(buffer) - if len(matches) == 0 { - return "", fmt.Errorf("could not parse %s from %s", re.String(), buffer) - } - return matches[0], nil - } - } else { - if err := scanner.Err(); err != nil { - return "", fmt.Errorf("could not scan: %w", err) - } - return "", fmt.Errorf("EOF before string was found") - } - } - } -} diff --git a/core/tunnel/moe/ssh_test.go b/core/tunnel/moe/ssh_test.go deleted file mode 100644 index 79c20ad5ac..0000000000 --- a/core/tunnel/moe/ssh_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package moe_test - -import ( - "context" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/synapsecns/sanguine/core/tunnel/moe" - "strings" - "testing" -) - -func TestConsumeBufferUntilURL(t *testing.T) { - testCases := []struct { - name string - input string - want string - wantErr bool - }{ - { - name: "url found", - input: "some text http://example.com/ some more text " + moe.MoeServer, - want: "http://example.com/", - wantErr: false, - }, - { - name: "url not found", - input: "some text" + moe.MoeServer + "some more text", - want: "", - wantErr: true, - }, - { - name: "context canceled", - input: "some text", - want: "", - wantErr: true, - }, - } - - for i := range testCases { - tc := testCases[i] // capture range variable - t.Run(tc.name, func(t *testing.T) { - reader := strings.NewReader(tc.input) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - got, err := moe.ConsumeBufferUntilURL(ctx, reader) - - if tc.wantErr { - require.Error(t, err) - } else { - require.NoError(t, err) - } - - assert.Equal(t, tc.want, got) - }) - } -} diff --git a/core/tunnel/ngrok/doc.go b/core/tunnel/ngrok/doc.go deleted file mode 100644 index 763510da7a..0000000000 --- a/core/tunnel/ngrok/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package ngrok provides a tunnel that uses ngrok to expose a local port to the internet. -package ngrok diff --git a/core/tunnel/ngrok/ngrok.go b/core/tunnel/ngrok/ngrok.go deleted file mode 100644 index fd2311bb04..0000000000 --- a/core/tunnel/ngrok/ngrok.go +++ /dev/null @@ -1,85 +0,0 @@ -package ngrok - -import ( - "context" - "fmt" - "github.com/brianvoe/gofakeit/v6" - "github.com/jpillora/backoff" - "github.com/synapsecns/sanguine/core/tunnel/internal" - "github.com/synapsecns/sanguine/core/tunnel/types" - "golang.ngrok.com/ngrok" - grokconfig "golang.ngrok.com/ngrok/config" - "net/http" - "time" -) - -type ngrokProvider struct { - options []ngrok.ConnectOption - // checkPath is a path we override the backend with to check if the tunnel is up. - checkPath string - // checkChan is a channel that is closed when the checkPath is hit. - checkChan chan bool -} - -// New returns a new ngrok provider. -func New(opts ...ngrok.ConnectOption) types.Provider { - return &ngrokProvider{ - options: opts, - checkPath: fmt.Sprintf("/%s", gofakeit.UUID()), - checkChan: make(chan bool, 1), - } -} - -func (n *ngrokProvider) Start(ctx context.Context, backendURL string) (_ string, err error) { - // add the default options - ngrokOptions := append([]ngrok.ConnectOption{ - ngrok.WithAuthtokenFromEnv(), - }, n.options...) - - listener, err := ngrok.Listen(ctx, grokconfig.HTTPEndpoint(), ngrokOptions...) - if err != nil { - return "", fmt.Errorf("could not start ngrok: %w", err) - } - - errChan := internal.VerifiableProxy(ctx, backendURL, n.checkPath, listener, func() { - n.checkChan <- true - }) - - // TODO: this needs to be deduped w/ moe - timeout := &backoff.Backoff{ - Factor: 2, - Jitter: true, - Min: 200 * time.Millisecond, - Max: time.Second, - } - - // give the server a max of 30 seconds to start - ctx, cancel := context.WithTimeout(ctx, time.Second*30) - defer cancel() - duration := time.Duration(0) - for { - select { - case <-ctx.Done(): - return "", nil - case err := <-errChan: - return "", fmt.Errorf("could not serve ngrok: %w", err) - case <-time.After(duration): - req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s%s", listener.URL(), n.checkPath), nil) - if err != nil { - return "", fmt.Errorf("could not create request: %w", err) - } - - resp, err := http.DefaultClient.Do(req) - if err != nil { - duration = timeout.Duration() - continue - } - - if resp != nil { - _ = resp.Body.Close() - } - case <-n.checkChan: - return backendURL, nil - } - } -} diff --git a/core/tunnel/options.go b/core/tunnel/options.go deleted file mode 100644 index 2f46c0719f..0000000000 --- a/core/tunnel/options.go +++ /dev/null @@ -1,51 +0,0 @@ -package tunnel - -import ( - "fmt" - "golang.ngrok.com/ngrok" -) - -type config struct { - provider Provider - ngrokOptions []ngrok.ConnectOption -} - -func (c *config) Validate() error { - if len(c.ngrokOptions) != 0 && c.provider != Ngrok { - return fmt.Errorf("ngrok options are only valid for ngrok provider") - } - return nil -} - -// Option is a tunnel option. -type Option func(*config) - -// WithNgrokOptions sets the ngrok options to use when using the ngrok provider. -func WithNgrokOptions(opts ...ngrok.ConnectOption) Option { - return func(c *config) { - c.ngrokOptions = opts - } -} - -// WithProvider sets the provider to use. -func WithProvider(provider Provider) Option { - return func(c *config) { - c.provider = provider - } -} - -func makeConfig(opts []Option) (*config, error) { - c := &config{ - // TODO: switch to moe once it's ready - provider: Ngrok, - } - for _, opt := range opts { - opt(c) - } - - err := c.Validate() - if err != nil { - return nil, fmt.Errorf("invalid options: %w", err) - } - return c, nil -} diff --git a/core/tunnel/provider.go b/core/tunnel/provider.go deleted file mode 100644 index 5014a3015b..0000000000 --- a/core/tunnel/provider.go +++ /dev/null @@ -1,13 +0,0 @@ -package tunnel - -// Provider is a tunnel provider. -// -//go:generate go run golang.org/x/tools/cmd/stringer -type=Provider -linecomment -type Provider uint8 - -const ( - // Moe is the moe provider: https://github.com/fasmide/remotemoe - Moe Provider = iota + 1 - // Ngrok is the ngrok provider: https://ngrok.com/ - Ngrok -) diff --git a/core/tunnel/provider_string.go b/core/tunnel/provider_string.go deleted file mode 100644 index 4bcbab0da9..0000000000 --- a/core/tunnel/provider_string.go +++ /dev/null @@ -1,25 +0,0 @@ -// Code generated by "stringer -type=Provider -linecomment"; DO NOT EDIT. - -package tunnel - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[Moe-1] - _ = x[Ngrok-2] -} - -const _Provider_name = "MoeNgrok" - -var _Provider_index = [...]uint8{0, 3, 8} - -func (i Provider) String() string { - i -= 1 - if i >= Provider(len(_Provider_index)-1) { - return "Provider(" + strconv.FormatInt(int64(i+1), 10) + ")" - } - return _Provider_name[_Provider_index[i]:_Provider_index[i+1]] -} diff --git a/core/tunnel/suite_test.go b/core/tunnel/suite_test.go deleted file mode 100644 index a9c5dced45..0000000000 --- a/core/tunnel/suite_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package tunnel_test - -import ( - "context" - "errors" - "fmt" - "github.com/ipfs/go-log" - "github.com/phayes/freeport" - "github.com/stretchr/testify/suite" - "github.com/synapsecns/sanguine/core/ginhelper" - "github.com/synapsecns/sanguine/core/retry" - baseServer "github.com/synapsecns/sanguine/core/server" - "github.com/synapsecns/sanguine/core/testsuite" - "net/http" - "testing" - "time" -) - -// TunnelSuite defines the basic test suite. -type TunnelSuite struct { - *testsuite.TestSuite - // testServer is the url of the local server to test on. - testServer string - logger *log.ZapEventLogger -} - -// NewTestSuite creates a new test suite and performs some basic checks afterward. -// Every test suite in the synapse library should inherit from this suite and override where necessary. -func NewTunnelSuite(tb testing.TB) *TunnelSuite { - tb.Helper() - return &TunnelSuite{ - TestSuite: testsuite.NewTestSuite(tb), - } -} - -func (n *TunnelSuite) SetupTest() { - n.TestSuite.SetupTest() - n.logger = log.Logger(fmt.Sprintf("test-%d-logger", n.GetTestID())) - n.startServer(n.GetTestContext()) -} - -// startServer starts the test server and sets the testServer field. -func (n *TunnelSuite) startServer(ctx context.Context) { - testServer := ginhelper.New(n.logger) - freePort, err := freeport.GetFreePort() - n.Require().NoError(err) - - n.testServer = fmt.Sprintf("http://localhost:%d", freePort) - - go func() { - connection := baseServer.Server{} - err = connection.ListenAndServe(ctx, fmt.Sprintf(":%d", freePort), testServer) - // we expect context cancellation errors at the end of the test - if !errors.Is(err, context.Canceled) { - n.Require().NoError(err) - } - }() - - // make sure the server is running - - err = retry.WithBackoff(ctx, func(ctx context.Context) error { - req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s%s", n.testServer, ginhelper.HealthCheck), nil) - if err != nil { - return fmt.Errorf("could not create request: %w", err) - } - resp, err := http.DefaultClient.Do(req) - if err != nil { - return fmt.Errorf("could not send request: %w", err) - } - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("unexpected status code: %d", resp.StatusCode) - } - - if resp.Body != nil { - _ = resp.Body.Close() - } - - return nil - }, retry.WithMin(time.Millisecond), retry.WithMax(time.Second), retry.WithMaxAttemptTime(time.Second*30)) - - n.Require().NoError(err) -} - -func TestTunnelSuite(t *testing.T) { - suite.Run(t, NewTunnelSuite(t)) -} diff --git a/core/tunnel/tunnel.go b/core/tunnel/tunnel.go deleted file mode 100644 index 4251aaa895..0000000000 --- a/core/tunnel/tunnel.go +++ /dev/null @@ -1,32 +0,0 @@ -// Package tunnel provides a simple interface to start a tunnel to a backend URL. -package tunnel - -import ( - "context" - "fmt" - "github.com/synapsecns/sanguine/core/tunnel/moe" - ngrok "github.com/synapsecns/sanguine/core/tunnel/ngrok" - "github.com/synapsecns/sanguine/core/tunnel/types" -) - -// StartTunnel starts a tunnel to the backend URL. -func StartTunnel(ctx context.Context, backendURL string, opts ...Option) (string, error) { - cfg, err := makeConfig(opts) - if err != nil { - return "", err - } - - var provider types.Provider - - switch cfg.provider { - case Moe: - provider = moe.New() - case Ngrok: - provider = ngrok.New(cfg.ngrokOptions...) - } - tunnelURL, err := provider.Start(ctx, backendURL) - if err != nil { - return "", fmt.Errorf("could not start tunnel: %w", err) - } - return tunnelURL, nil -} diff --git a/core/tunnel/tunnel_test.go b/core/tunnel/tunnel_test.go deleted file mode 100644 index fbebb17921..0000000000 --- a/core/tunnel/tunnel_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package tunnel_test - -import ( - "context" - "fmt" - "github.com/brianvoe/gofakeit/v6" - "github.com/phayes/freeport" - "github.com/synapsecns/sanguine/core/ginhelper" - "github.com/synapsecns/sanguine/core/tunnel" - "github.com/synapsecns/sanguine/core/tunnel/internal" - "net" - "net/http" - "time" -) - -// this module is currently broken due to an issue with moe. -// this is caused by two issues: -// 1. Moe returns localhost as the hostname: https://github.com/fasmide/remotemoe/blob/13a9ba0f5ddadffdf4fb395ebff7c366b88a0745/ssh/session.go#L363 -// 2. Go assumes the response returned by forwarded-tcpip is a tcp address: https://github.com/golang/crypto/blob/master/ssh/tcpip.go#L211 -// A PR has been made to fix this: https://github.com/fasmide/remotemoe/pull/18 and this module will be ready when that's merged -// should the PR be unmergable for an extended period of time, we can intercept the requests in the net.Conn through a reverse ssh proxy. -func (n *TunnelSuite) TestMoe() { - n.T().Skip("moe is currently broken, waiting on https://github.com/fasmide/remotemoe/pull/18") - remoteURL, err := tunnel.StartTunnel(n.GetTestContext(), n.testServer, tunnel.WithProvider(tunnel.Moe)) - time.Sleep(time.Hour) - n.Require().NoError(err) - - n.checkTunnel(n.GetTestContext(), remoteURL) -} - -func (n *TunnelSuite) TestNgrok() { - remoteURL, err := tunnel.StartTunnel(n.GetTestContext(), n.testServer, tunnel.WithNgrokOptions(), tunnel.WithProvider(tunnel.Ngrok)) - n.Require().NoError(err) - - n.checkTunnel(n.GetTestContext(), remoteURL) -} - -func (n *TunnelSuite) checkTunnel(ctx context.Context, remoteURL string) { - req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s%s", remoteURL, ginhelper.HealthCheck), nil) - n.Require().NoError(err) - - resp, err := http.DefaultClient.Do(req) - n.Require().NoError(err) - n.Require().Equal(http.StatusOK, resp.StatusCode) - - if resp.Body != nil { - _ = resp.Body.Close() - } -} - -func (n *TunnelSuite) TestVerifiableProxy() { - var lc net.ListenConfig - port := freeport.GetPort() - - hostname := fmt.Sprintf("localhost:%d", port) - listener, err := lc.Listen(n.GetTestContext(), "tcp", hostname) - n.Require().NoError(err) - - checkPath := fmt.Sprintf("/%s", gofakeit.Word()) - - pathChan := make(chan bool, 1) - errChan := internal.VerifiableProxy(n.GetTestContext(), n.testServer, checkPath, listener, func() { - pathChan <- true - }) - - req, err := http.NewRequestWithContext(n.GetTestContext(), http.MethodGet, fmt.Sprintf("http://%s%s", hostname, checkPath), nil) - n.Require().NoError(err) - - resp, err := http.DefaultClient.Do(req) - n.Require().NoError(err) - - if resp.Body != nil { - _ = resp.Body.Close() - } - - select { - case <-n.GetTestContext().Done(): - n.Require().NoError(n.GetTestContext().Err()) - case err := <-errChan: - n.Require().NoError(err) - case <-pathChan: - return - } -} diff --git a/core/tunnel/types/provider.go b/core/tunnel/types/provider.go deleted file mode 100644 index 8e1f8ca284..0000000000 --- a/core/tunnel/types/provider.go +++ /dev/null @@ -1,12 +0,0 @@ -// Package types provides common types to avoid circular dependencies. -package types - -import ( - "context" -) - -// Provider is a tunnel provider. -type Provider interface { - // Start starts the tunnel provider and returns the URL of the tunnel. - Start(ctx context.Context, backendURL string) (_ string, err error) -}