From b27533728ee9f570df6392c321b2ecf4b93e28af Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Mon, 30 Dec 2019 20:45:54 +0400 Subject: [PATCH] Remove therealssh --- README.md | 33 +- ci_scripts/run-internal-tests.sh | 14 - cmd/apps/therealssh-client/README.md | 8 - .../therealssh-client/therealssh-client.go | 66 ---- cmd/apps/therealssh/README.md | 74 ---- cmd/apps/therealssh/therealssh.go | 93 ----- cmd/skywire-visor/config.json | 7 - cmd/therealssh-cli/README.md | 6 - cmd/therealssh-cli/commands/root.go | 230 ----------- cmd/therealssh-cli/therealssh-cli.go | 12 - docker/images/node/Dockerfile | 4 +- integration/InteractiveEnvironments.md | 57 +-- integration/generic/nodeA.json | 7 - integration/generic/nodeC.json | 7 - integration/run-ssh-env.sh | 26 -- integration/ssh/env-vars.sh | 24 -- integration/ssh/nodeA.json | 55 --- integration/ssh/nodeC.json | 61 --- integration/test-proxy.sh | 40 -- integration/test-ssh.sh | 31 -- internal/skyenv/const.go | 4 - pkg/therealssh/auth.go | 92 ----- pkg/therealssh/auth_test.go | 43 --- pkg/therealssh/chan_list.go | 54 --- pkg/therealssh/channel.go | 364 ------------------ pkg/therealssh/channel_pty_test.go | 91 ----- pkg/therealssh/channel_test.go | 130 ------- pkg/therealssh/client.go | 314 --------------- pkg/therealssh/client_test.go | 106 ----- pkg/therealssh/dialer.go | 12 - pkg/therealssh/pty_test.go | 100 ----- pkg/therealssh/server.go | 196 ---------- pkg/therealssh/server_test.go | 124 ------ pkg/therealssh/session.go | 200 ---------- pkg/therealssh/shell.go | 20 - pkg/therealssh/shell_darwin.go | 25 -- pkg/visor/visor.go | 2 +- 37 files changed, 16 insertions(+), 2716 deletions(-) delete mode 100644 cmd/apps/therealssh-client/README.md delete mode 100644 cmd/apps/therealssh-client/therealssh-client.go delete mode 100644 cmd/apps/therealssh/README.md delete mode 100644 cmd/apps/therealssh/therealssh.go delete mode 100644 cmd/therealssh-cli/README.md delete mode 100644 cmd/therealssh-cli/commands/root.go delete mode 100644 cmd/therealssh-cli/therealssh-cli.go delete mode 100644 integration/run-ssh-env.sh delete mode 100644 integration/ssh/env-vars.sh delete mode 100644 integration/ssh/nodeA.json delete mode 100644 integration/ssh/nodeC.json delete mode 100644 integration/test-proxy.sh delete mode 100644 integration/test-ssh.sh delete mode 100644 pkg/therealssh/auth.go delete mode 100644 pkg/therealssh/auth_test.go delete mode 100644 pkg/therealssh/chan_list.go delete mode 100644 pkg/therealssh/channel.go delete mode 100644 pkg/therealssh/channel_pty_test.go delete mode 100644 pkg/therealssh/channel_test.go delete mode 100644 pkg/therealssh/client.go delete mode 100644 pkg/therealssh/client_test.go delete mode 100644 pkg/therealssh/dialer.go delete mode 100644 pkg/therealssh/pty_test.go delete mode 100644 pkg/therealssh/server.go delete mode 100644 pkg/therealssh/server_test.go delete mode 100644 pkg/therealssh/session.go delete mode 100644 pkg/therealssh/shell.go delete mode 100644 pkg/therealssh/shell_darwin.go diff --git a/README.md b/README.md index 5ea3e12a8f..30e67ff05b 100644 --- a/README.md +++ b/README.md @@ -18,25 +18,25 @@ - [Testing](#testing) - [Testing with default settings](#testing-with-default-settings) - [Customization with environment variables](#customization-with-environment-variables) - - [$TEST_OPTS](#testopts) - - [$TEST_LOGGING_LEVEL](#testlogginglevel) - - [$SYSLOG_OPTS](#syslogopts) + - [$TEST_OPTS](#test_opts) + - [$TEST_LOGGING_LEVEL](#test_logging_level) + - [$SYSLOG_OPTS](#syslog_opts) - [Running skywire in docker containers](#running-skywire-in-docker-containers) - [Run dockerized `skywire-visor`](#run-dockerized-skywire-visor) - [Structure of `./node`](#structure-of-node) - [Refresh and restart `SKY01`](#refresh-and-restart-sky01) - [Customization of dockers](#customization-of-dockers) - - [1. DOCKER_IMAGE](#1-dockerimage) - - [2. DOCKER_NETWORK](#2-dockernetwork) - - [3. DOCKER_NODE](#3-dockernode) - - [4. DOCKER_OPTS](#4-dockeropts) + - [1. DOCKER_IMAGE](#1-docker_image) + - [2. DOCKER_NETWORK](#2-docker_network) + - [3. DOCKER_NODE](#3-docker_node) + - [4. DOCKER_OPTS](#4-docker_opts) - [Dockerized `skywire-visor` recipes](#dockerized-skywire-visor-recipes) - [1. Get Public Key of docker-node](#1-get-public-key-of-docker-node) - [2. Get an IP of node](#2-get-an-ip-of-node) - [3. Open in browser containerized `skychat` application](#3-open-in-browser-containerized-skychat-application) - [4. Create new dockerized `skywire-visor`s](#4-create-new-dockerized-skywire-visors) - [5. Env-vars for development-/testing- purposes](#5-env-vars-for-development-testing--purposes) - - [6. "Hello-Mike-Hello-Joe" test](#6-%22hello-mike-hello-joe%22-test) + - [6. "Hello-Mike-Hello-Joe" test](#6-hello-mike-hello-joe-test) **NOTE:** The project is still under heavy development and should only be used for testing purposes right now. Miners should not switch over to this project if they want to receive testnet rewards. @@ -186,7 +186,6 @@ After `skywire-visor` is up and running with default environment, default apps a - [Chat](/cmd/apps/skychat) - [Hello World](/cmd/apps/helloworld) - [The Real Proxy](/cmd/apps/therealproxy) ([Client](/cmd/apps/therealproxy-client)) -- [The Real SSH](/cmd/apps/therealssh) ([Client](/cmd/apps/therealssh-client)) ### Transports @@ -306,13 +305,10 @@ This will: │   ├── skychat.v1.0 # │   ├── helloworld.v1.0 # │   ├── socksproxy-client.v1.0 # -│   ├── socksproxy.v1.0 # -│   ├── SSH-client.v1.0 # -│   └── SSH.v1.0 # +│   └── socksproxy.v1.0 # ├── local # **Created inside docker** │   ├── skychat # according to "local_path" in skywire-config.json -│   ├── socksproxy # -│   └── SSH # +│   └── socksproxy # ├── PK # contains public key of node ├── skywire # db & logs. **Created inside docker** │   ├── routing.db # @@ -413,8 +409,6 @@ $ GO111MODULE=on GOOS=linux go build -o /tmp/SKYNODE/skywire-visor ./cmd/skywire $ GO111MODULE=on GOOS=linux go build -o /tmp/SKYNODE/apps/skychat.v1.0 ./cmd/apps/skychat $ GO111MODULE=on GOOS=linux go build -o /tmp/SKYNODE/apps/helloworld.v1.0 ./cmd/apps/helloworld $ GO111MODULE=on GOOS=linux go build -o /tmp/SKYNODE/apps/socksproxy.v1.0 ./cmd/apps/therealproxy -$ GO111MODULE=on GOOS=linux go build -o /tmp/SKYNODE/apps/SSH.v1.0 ./cmd/apps/SSH -$ GO111MODULE=on GOOS=linux go build -o /tmp/SKYNODE/apps/SSH-client.v1.0 ./cmd/apps/SSH-client # 4. Create skywire-config.json for node $ skywire-cli node gen-config -o /tmp/SKYNODE/skywire-config.json # 2019/03/15 16:43:49 Done! @@ -423,9 +417,7 @@ $ tree /tmp/SKYNODE # ├── apps # │   ├── skychat.v1.0 # │   ├── helloworld.v1.0 -# │   ├── socksproxy.v1.0 -# │   ├── SSH-client.v1.0 -# │   └── SSH.v1.0 +# │   └── socksproxy.v1.0 # ├── skywire-config.json # └── skywire-visor # So far so good. We prepared docker volume. Now we can: @@ -436,15 +428,12 @@ $ docker run -it -v /tmp/SKYNODE:/sky --network=SKYNET --name=SKYNODE skywire-ru # [2019-03-15T13:55:10Z] INFO [skywire]: Starting skychat.v1.0 # [2019-03-15T13:55:10Z] INFO [skywire]: Starting RPC interface on 127.0.0.1:3435 # [2019-03-15T13:55:10Z] INFO [skywire]: Starting socksproxy.v1.0 -# [2019-03-15T13:55:10Z] INFO [skywire]: Starting SSH.v1.0 # [2019-03-15T13:55:10Z] INFO [skywire]: Starting packet router # [2019-03-15T13:55:10Z] INFO [router]: Starting router # [2019-03-15T13:55:10Z] INFO [trmanager]: Starting transport manager # [2019-03-15T13:55:10Z] INFO [router]: Got new App request with type Init: {"app-name":"skychat",# "app-version":"1.0","protocol-version":"0.0.1"} # [2019-03-15T13:55:10Z] INFO [router]: Handshaked new connection with the app skychat.v1.0 # [2019-03-15T13:55:10Z] INFO [skychat.v1.0]: 2019/03/15 13:55:10 Serving HTTP on :8000 -# [2019-03-15T13:55:10Z] INFO [router]: Got new App request with type Init: {"app-name":"SSH",# "app-version":"1.0","protocol-version":"0.0.1"} -# [2019-03-15T13:55:10Z] INFO [router]: Handshaked new connection with the app SSH.v1.0 # [2019-03-15T13:55:10Z] INFO [router]: Got new App request with type Init: {"app-name":"socksproxy",# "app-version":"1.0","protocol-version":"0.0.1"} # [2019-03-15T13:55:10Z] INFO [router]: Handshaked new connection with the app socksproxy.v1.0 ``` diff --git a/ci_scripts/run-internal-tests.sh b/ci_scripts/run-internal-tests.sh index 57be9caf40..f16b933462 100755 --- a/ci_scripts/run-internal-tests.sh +++ b/ci_scripts/run-internal-tests.sh @@ -18,17 +18,3 @@ go clean -testcache &>/dev/null || go test -race -tags no_ci -cover -timeout=5m go clean -testcache &>/dev/null || go test -race -tags no_ci -cover -timeout=5m github.com/SkycoinProject/skywire-mainnet/internal/noise -run TestReadWriterConcurrentTCP >> ./logs/internal/TestReadWriterConcurrentTCP.log go clean -testcache &>/dev/null || go test -race -tags no_ci -cover -timeout=5m github.com/SkycoinProject/skywire-mainnet/internal/therealproxy -run TestProxy >> ./logs/internal/TestProxy.log - -go clean -testcache &>/dev/null || go test -race -tags no_ci -cover -timeout=5m github.com/SkycoinProject/skywire-mainnet/internal/therealssh -run TestListAuthorizer >> ./logs/internal/TestListAuthorizer.log -go clean -testcache &>/dev/null || go test -race -tags no_ci -cover -timeout=5m github.com/SkycoinProject/skywire-mainnet/internal/therealssh -run TestFileAuthorizer >> ./logs/internal/TestFileAuthorizer.log -go clean -testcache &>/dev/null || go test -race -tags no_ci -cover -timeout=5m github.com/SkycoinProject/skywire-mainnet/internal/therealssh -run TestChannelServe >> ./logs/internal/TestChannelServe.log -go clean -testcache &>/dev/null || go test -race -tags no_ci -cover -timeout=5m github.com/SkycoinProject/skywire-mainnet/internal/therealssh -run TestChannelSendWrite >> ./logs/internal/TestChannelSendWrite.log -go clean -testcache &>/dev/null || go test -race -tags no_ci -cover -timeout=5m github.com/SkycoinProject/skywire-mainnet/internal/therealssh -run TestChannelRead >> ./logs/internal/TestChannelRead.log -go clean -testcache &>/dev/null || go test -race -tags no_ci -cover -timeout=5m github.com/SkycoinProject/skywire-mainnet/internal/therealssh -run TestChannelRequest >> ./logs/internal/TestChannelRequest.log -go clean -testcache &>/dev/null || go test -race -tags no_ci -cover -timeout=5m github.com/SkycoinProject/skywire-mainnet/internal/therealssh -run TestChannelServeSocket >> ./logs/internal/TestChannelServeSocket.log -go clean -testcache &>/dev/null || go test -race -tags no_ci -cover -timeout=5m github.com/SkycoinProject/skywire-mainnet/internal/therealssh -run TestClientOpenChannel >> ./logs/internal/TestClientOpenChannel.log -go clean -testcache &>/dev/null || go test -race -tags no_ci -cover -timeout=5m github.com/SkycoinProject/skywire-mainnet/internal/therealssh -run TestClientHandleResponse >> ./logs/internal/TestClientHandleResponse.log -go clean -testcache &>/dev/null || go test -race -tags no_ci -cover -timeout=5m github.com/SkycoinProject/skywire-mainnet/internal/therealssh -run TestClientHandleData >> ./logs/internal/TestClientHandleData.log -go clean -testcache &>/dev/null || go test -race -tags no_ci -cover -timeout=5m github.com/SkycoinProject/skywire-mainnet/internal/therealssh -run TestServerOpenChannel >> ./logs/internal/TestServerOpenChannel.log -go clean -testcache &>/dev/null || go test -race -tags no_ci -cover -timeout=5m github.com/SkycoinProject/skywire-mainnet/internal/therealssh -run TestServerHandleRequest >> ./logs/internal/TestServerHandleRequest.log -go clean -testcache &>/dev/null || go test -race -tags no_ci -cover -timeout=5m github.com/SkycoinProject/skywire-mainnet/internal/therealssh -run TestServerHandleData >> ./logs/internal/TestServerHandleData.log diff --git a/cmd/apps/therealssh-client/README.md b/cmd/apps/therealssh-client/README.md deleted file mode 100644 index 3aaec45251..0000000000 --- a/cmd/apps/therealssh-client/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Skywire SSH client app - -`SSH-client` app implements client for the SSH app. - -It starts RCP interface for `SSH-cli` and handles incoming requests to -the remote node via `skywire` connection. - -Please check docs for `SSH` app for further instructions. diff --git a/cmd/apps/therealssh-client/therealssh-client.go b/cmd/apps/therealssh-client/therealssh-client.go deleted file mode 100644 index 41113089a8..0000000000 --- a/cmd/apps/therealssh-client/therealssh-client.go +++ /dev/null @@ -1,66 +0,0 @@ -/* -ssh client app for skywire visor -*/ -package main - -import ( - "flag" - "fmt" - "net/http" - - "github.com/SkycoinProject/skywire-mainnet/internal/skyenv" - - "github.com/SkycoinProject/skycoin/src/util/logging" - "github.com/sirupsen/logrus" - - "github.com/SkycoinProject/skywire-mainnet/pkg/app" - ssh "github.com/SkycoinProject/skywire-mainnet/pkg/therealssh" -) - -const ( - appName = "SSH-client" -) - -var log *logging.MasterLogger - -func main() { - log = app.NewLogger(appName) - ssh.Log = log.PackageLogger("therealssh") - - // TODO(evanlinjin): Change "rpc" to "addr". - var rpcAddr = flag.String("rpc", skyenv.SkysshClientAddr, "Client RPC address to listen on") - var debug = flag.Bool("debug", false, "enable debug messages") - flag.Parse() - - config, err := app.ClientConfigFromEnv() - if err != nil { - log.Fatalf("Error getting client config: %v\n", err) - } - - sshApp, err := app.NewClient(logging.MustGetLogger(fmt.Sprintf("app_%s", appName)), config) - if err != nil { - log.Fatal("Setup failure: ", err) - } - defer func() { - sshApp.Close() - }() - - ssh.Debug = *debug - if !ssh.Debug { - logging.SetLevel(logrus.InfoLevel) - } - - rpc, client, err := ssh.NewClient(*rpcAddr, sshApp) - if err != nil { - log.Fatal("Client setup failure: ", err) - } - defer func() { - if err := client.Close(); err != nil { - log.Println("Failed to close client:", err) - } - }() - - if err := http.Serve(rpc, nil); err != nil { - log.Fatal("Failed to start RPC interface: ", err) - } -} diff --git a/cmd/apps/therealssh/README.md b/cmd/apps/therealssh/README.md deleted file mode 100644 index c61dfb028d..0000000000 --- a/cmd/apps/therealssh/README.md +++ /dev/null @@ -1,74 +0,0 @@ -# Skywire SSH app - -`SSH` app implements SSH functionality over skywirenet. - -`SSH-cli` is used to initiate communication via client RPC -exposed by `SSH` app. - -`SSH` app implements common SSH operations: - -- starting remote shell -- and executing commands remotely - -PubKey whitelisting is performed by adding public key to the -authentication file (`$HOME/.therealssh/authorized_keys` by default). - -** Local setup - -Create 2 node config files: - -`skywire1.json` - -```json -{ - "apps": [ - { - "app": "SSH", - "version": "1.0", - "auto_start": true, - "port": 2 - } - ] -} -``` - -`skywire2.json` - -```json -{ - "apps": [ - { - "app": "SSH-client", - "version": "1.0", - "auto_start": true, - "port": 22 - } - ] -} -``` - -Compile binaries and start 2 nodes: - -```bash -$ go build -o apps/SSH.v1.0 ./cmd/apps/therealssh -$ go build -o apps/SSH-client.v1.0 ./cmd/apps/therealssh-client -$ go build ./cmd/SSH-cli -$ ./skywire-visor skywire1.json -$ ./skywire-visor skywire2.json -``` - -Add public key of the second node to the auth file: - -```bash -$ mkdir /.therealssh -$ echo "0348c941c5015a05c455ff238af2e57fb8f914c399aab604e9abb5b32b91a4c1fe" > /.SSH/authorized_keys -``` - -Connect to the first node using CLI: - -```bash -$ ./SSH-cli 024ec47420176680816e0406250e7156465e4531f5b26057c9f6297bb0303558c7 -``` - -This should get you to the $HOME folder of the user(you in this case), which -will indicate that you are seeing remote PTY session. diff --git a/cmd/apps/therealssh/therealssh.go b/cmd/apps/therealssh/therealssh.go deleted file mode 100644 index 73bec6fe71..0000000000 --- a/cmd/apps/therealssh/therealssh.go +++ /dev/null @@ -1,93 +0,0 @@ -/* -ssh server app for skywire visor -*/ -package main - -import ( - "flag" - "fmt" - - "github.com/SkycoinProject/skywire-mainnet/pkg/app/appnet" - "github.com/SkycoinProject/skywire-mainnet/pkg/routing" - - "github.com/SkycoinProject/skycoin/src/util/logging" - "github.com/mitchellh/go-homedir" - "github.com/sirupsen/logrus" - - "github.com/SkycoinProject/skywire-mainnet/pkg/app" - ssh "github.com/SkycoinProject/skywire-mainnet/pkg/therealssh" -) - -var log *logging.MasterLogger - -const ( - appName = "SSH" - netType = appnet.TypeSkynet - port = routing.Port(1000) -) - -func main() { - log = app.NewLogger(appName) - ssh.Log = log.PackageLogger("therealssh") - - // TODO: change back to the tilda-like home path - var authFile = flag.String("auth", "/Users/darkrengarius/.therealssh/authorized_keys", "Auth file location. Should contain one PubKey per line.") - var debug = flag.Bool("debug", false, "enable debug messages") - - flag.Parse() - - config, err := app.ClientConfigFromEnv() - if err != nil { - log.Fatalf("Error getting client config: %v\n", err) - } - - sshApp, err := app.NewClient(logging.MustGetLogger(fmt.Sprintf("app_%s", appName)), config) - - if err != nil { - log.Fatal("Setup failure: ", err) - } - defer func() { - sshApp.Close() - }() - - path, err := homedir.Expand(*authFile) - if err != nil { - log.Errorf("Error expanding auth file path %s: %v\n", *authFile, err) - log.Fatal("Failed to resolve auth file path: ", err) - } - - ssh.Debug = *debug - if !ssh.Debug { - logging.SetLevel(logrus.InfoLevel) - } - - auth, err := ssh.NewFileAuthorizer(path) - if err != nil { - log.Fatal("Failed to setup Authorizer: ", err) - } - - server := ssh.NewServer(auth, log) - defer func() { - if err := server.Close(); err != nil { - log.Println("Failed to close server:", err) - } - }() - - l, err := sshApp.Listen(netType, port) - if err != nil { - log.Fatalf("Error listening network %v on port %d: %v\n", netType, port, err) - } - - for { - conn, err := l.Accept() - if err != nil { - log.Fatal("failed to receive packet: ", err) - } - - go func() { - if err := server.Serve(conn); err != nil { - log.Println("Failed to serve conn:", err) - } - }() - } -} diff --git a/cmd/skywire-visor/config.json b/cmd/skywire-visor/config.json index f0200db8e9..3ee1687faa 100644 --- a/cmd/skywire-visor/config.json +++ b/cmd/skywire-visor/config.json @@ -23,13 +23,6 @@ "ports": [ 1 ] - }, - { - "app": "SSH-server", - "auto_start": true, - "ports": [ - 2 - ] } ], "messaging_path": "./messaging", diff --git a/cmd/therealssh-cli/README.md b/cmd/therealssh-cli/README.md deleted file mode 100644 index 90df7c21c3..0000000000 --- a/cmd/therealssh-cli/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# CLI for SSH app - -`SSH-cli` implements PTY related operations for SSH app. - -It connects to SSH client's RPC server, configures terminal for raw pty -data and handles pty data exchange. diff --git a/cmd/therealssh-cli/commands/root.go b/cmd/therealssh-cli/commands/root.go deleted file mode 100644 index c3bb4d65bb..0000000000 --- a/cmd/therealssh-cli/commands/root.go +++ /dev/null @@ -1,230 +0,0 @@ -package commands - -import ( - "fmt" - "io" - "log" - "net" - "net/rpc" - "os" - "os/signal" - "os/user" - "strings" - "syscall" - "time" - - "github.com/SkycoinProject/dmsg/cipher" - "github.com/creack/pty" - "github.com/spf13/cobra" - "golang.org/x/crypto/ssh/terminal" - - ssh "github.com/SkycoinProject/skywire-mainnet/pkg/therealssh" -) - -var ( - rpcAddr string - ptyMode bool - ptyRows uint16 - ptyCols uint16 - ptyX uint16 - ptyY uint16 - ptyBufferSize uint32 -) - -var rootCmd = &cobra.Command{ - Use: "SSH-cli [user@]remotePK [command] [args...]", - Short: "Client for the SSH-client app", - Args: cobra.MinimumNArgs(1), - Run: func(_ *cobra.Command, args []string) { - if ptyMode { - runInPTY(args) - return - } - client, err := rpc.DialHTTP("tcp", rpcAddr) - if err != nil { - log.Fatal("RPC connection failed:", err) - } - - size, err := pty.GetsizeFull(os.Stdin) - if err != nil { - log.Fatal("Failed to get TTY size:", err) - } - - username, pk, err := resolveUser(args[0]) - if err != nil { - log.Fatal("Invalid user/pk pair: ", err) - } - - remotePK := cipher.PubKey{} - if err := remotePK.UnmarshalText([]byte(pk)); err != nil { - log.Fatal("Invalid remote PubKey: ", err) - } - - ptyArgs := &ssh.RequestPTYArgs{Username: username, RemotePK: remotePK, Size: size} - var channelID uint32 - if err := client.Call("RPCClient.RequestPTY", ptyArgs, &channelID); err != nil { - log.Fatal("Failed to request PTY:", err) - } - defer func() { - if err := client.Call("RPCClient.Close", &channelID, nil); err != nil { - log.Printf("Failed to close RPC client: %v", err) - } - }() - - var socketPath string - execArgs := &ssh.ExecArgs{ChannelID: channelID, CommandWithArgs: args[1:]} - if err := client.Call("RPCClient.Exec", execArgs, &socketPath); err != nil { - log.Fatal("Failed to start shell:", err) - } - - conn, err := dialUnix(socketPath) - if err != nil { - log.Fatal("Failed dial ssh socket:", err) - } - - ch := make(chan os.Signal) - signal.Notify(ch, syscall.SIGWINCH) - go func() { - for range ch { - size, err := pty.GetsizeFull(os.Stdin) - if err != nil { - log.Println("Failed to change pty size:", err) - return - } - - var result int - if err := client.Call("RPCClient.WindowChange", &ssh.WindowChangeArgs{ChannelID: channelID, Size: size}, &result); err != nil { - log.Println("Failed to change pty size:", err) - } - } - }() - - oldState, err := terminal.MakeRaw(int(os.Stdin.Fd())) - if err != nil { - log.Fatal("Failed to set terminal to raw mode:", err) - } - defer func() { - if err := terminal.Restore(int(os.Stdin.Fd()), oldState); err != nil { - log.Printf("Failed to restore terminal: %v", err) - } - }() - - go func() { - if _, err := io.Copy(conn, os.Stdin); err != nil { - log.Fatal("Failed to write to ssh socket:", err) - } - }() - - if _, err := io.Copy(os.Stdout, conn); err != nil { - log.Fatal("Failed to read from ssh socket:", err) - } - }, -} - -func dialUnix(socketPath string) (net.Conn, error) { - var conn net.Conn - var err error - - for i := 0; i < 5; i++ { - conn, err = net.DialUnix("unix", nil, &net.UnixAddr{Name: socketPath, Net: "unix"}) - if err == nil { - break - } - - time.Sleep(time.Second) - } - - return conn, err -} - -func runInPTY(args []string) { - client, err := rpc.DialHTTP("tcp", rpcAddr) - if err != nil { - log.Fatal("RPC connection failed:", err) - } - - username, pk, err := resolveUser(args[0]) - if err != nil { - log.Fatal("Invalid user/pk pair: ", err) - } - - remotePK := cipher.PubKey{} - if err := remotePK.UnmarshalText([]byte(pk)); err != nil { - log.Fatal("Invalid remote PubKey: ", err) - } - - ptyArgs := &ssh.RequestPTYArgs{ - Username: username, - RemotePK: remotePK, - Size: &pty.Winsize{ - Rows: uint16(ptyRows), - Cols: ptyCols, - X: ptyX, - Y: ptyY, - }, - } - - var channelID uint32 - if err := client.Call("RPCClient.RequestPTY", ptyArgs, &channelID); err != nil { - log.Fatal("Failed to request PTY:", err) - } - - var socketPath string - execArgs := &ssh.ExecArgs{ - ChannelID: channelID, - CommandWithArgs: args[1:], - } - - err = client.Call("RPCClient.Run", execArgs, &socketPath) - if err != nil { - log.Fatal(err) - } - - conn, err := dialUnix(socketPath) - if err != nil { - log.Fatal(err) - } - - b := make([]byte, ptyBufferSize) - _, err = conn.Read(b) - if err != nil { - log.Fatal(err) - } - - fmt.Print(string(b)) -} - -func resolveUser(arg string) (username string, pk string, err error) { - components := strings.Split(arg, "@") - if len(components) == 1 { - if u, uErr := user.Current(); uErr != nil { - err = fmt.Errorf("failed to resolve current user: %s", uErr) - } else { - username = u.Username - pk = components[0] - } - - return - } - - username = components[0] - pk = components[1] - return -} - -func init() { - rootCmd.Flags().StringVarP(&rpcAddr, "rpc", "", ":2222", "RPC address to connect to") - rootCmd.Flags().BoolVarP(&ptyMode, "pty", "", false, "Whether to run the command in a simulated PTY or not") - rootCmd.Flags().Uint16VarP(&ptyRows, "ptyrows", "", 100, "PTY Rows. Applicable if run with pty flag") - rootCmd.Flags().Uint16VarP(&ptyCols, "ptycols", "", 100, "PTY Cols. Applicable if run with pty flag") - rootCmd.Flags().Uint16VarP(&ptyX, "ptyx", "", 100, "PTY X. Applicable if run with pty flag") - rootCmd.Flags().Uint16VarP(&ptyY, "ptyy", "", 100, "PTY Y. Applicable if run with pty flag") - rootCmd.Flags().Uint32VarP(&ptyBufferSize, "ptybuffer", "", 1024, "PTY Buffer size to store command output") -} - -// Execute executes root CLI command. -func Execute() { - if err := rootCmd.Execute(); err != nil { - log.Fatal(err) - } -} diff --git a/cmd/therealssh-cli/therealssh-cli.go b/cmd/therealssh-cli/therealssh-cli.go deleted file mode 100644 index 410fcf4ec6..0000000000 --- a/cmd/therealssh-cli/therealssh-cli.go +++ /dev/null @@ -1,12 +0,0 @@ -/* -CLI for SSH app -*/ -package main - -import ( - "github.com/SkycoinProject/skywire-mainnet/cmd/therealssh-cli/commands" -) - -func main() { - commands.Execute() -} diff --git a/docker/images/node/Dockerfile b/docker/images/node/Dockerfile index 4956fa5edd..4b779dfc19 100644 --- a/docker/images/node/Dockerfile +++ b/docker/images/node/Dockerfile @@ -19,9 +19,7 @@ RUN go build -mod=vendor -tags netgo -ldflags="-w -s" \ go build -mod=vendor -ldflags="-w -s" -o ./apps/skychat.v1.0 ./cmd/apps/skychat &&\ go build -mod=vendor -ldflags="-w -s" -o ./apps/helloworld.v1.0 ./cmd/apps/helloworld &&\ go build -mod=vendor -ldflags="-w -s" -o ./apps/socksproxy.v1.0 ./cmd/apps/therealproxy &&\ - go build -mod=vendor -ldflags="-w -s" -o ./apps/socksproxy-client.v1.0 ./cmd/apps/therealproxy-client &&\ - go build -mod=vendor -ldflags="-w -s" -o ./apps/SSH.v1.0 ./cmd/apps/therealssh &&\ - go build -mod=vendor -ldflags="-w -s" -o ./apps/SSH-client.v1.0 ./cmd/apps/therealssh-client + go build -mod=vendor -ldflags="-w -s" -o ./apps/socksproxy-client.v1.0 ./cmd/apps/therealproxy-client ## Resulting image diff --git a/integration/InteractiveEnvironments.md b/integration/InteractiveEnvironments.md index b7caa920e4..978d8a69ea 100644 --- a/integration/InteractiveEnvironments.md +++ b/integration/InteractiveEnvironments.md @@ -9,7 +9,6 @@ - [Environments & scenarios](#environments--scenarios) - [Base Environment](#base-environment) - [Generic Test Environment](#generic-test-environment) - - [SSH Test Environment](#ssh-test-environment) - [Proxy test environment](#proxy-test-environment) - [Preparation](#preparation) - [Scenario. Proxy test #1](#scenario-proxy-test-1) @@ -34,23 +33,17 @@ integration │   ├── env-vars.sh # │   ├── nodeA.json # │   └── nodeC.json # -├── ssh # ssh testing environment -│   ├── env-vars.sh # -│   ├── nodeA.json # -│   └── nodeC.json # ├── InteractiveEnvironments.md # You're reading it ├── intermediary-nodeB.json # NodeB configurationS ├── run-base-env.sh # base environment in detached tmux session ├── run-generic-env.sh # generic environment in tmux ├── run-proxy-env.sh # proxy environment in tmux -├── run-ssh-env.sh # ssh environment in tmux ├── start-restart-nodeB.sh # script for restart in cycle NodeB ├── startup.sh # add transports between nodes ├── tear-down.sh # tear down everything ├── test-messaging-loop.sh # Test script for messaging in infinite loop ├── test-messaging.sh # Test one message between NodeA-NodeC, NodeC-NodeA -├── test-proxy.sh # Test script for proxy -├── test-ssh.sh # Test script for ssh +└── test-proxy.sh # Test script for proxy ``` ## Dependencies @@ -162,56 +155,15 @@ The following steps will be performed: 4. $CHAT_A, $CHAT_B - addresses and ports for `skychat`-apps on node_A and node_C 4. Aliases in shell-window: `CLI_A`, `CLI_B`, `CLI_C` -### SSH Test Environment - -The SSH Test Environment will define the following: - -- skywire-services running on localhost -- 3 `skywire-visor`s: - - NodeA - running `SSH` app - - NodeB - intermediary node without apps - - NodeC - running `SSH-client` app - -**Run** - -```bash -# Tear down everything -$ make integration-teardown - -# Prerequisite -$ echo $PK_C > ~/.therealssh/authorized_keys - -# Start all services and nodes -$ make integration-run-ssh - -# Adds pre-defined transports -$ make integration-startup -``` - -**Tests** - -- **TEST 1** - 1. Run `./integration/run-ssh-env.sh` - it will run: - 1. skywire-services on localhost - 2. NodeA with configured `SSH` app - 3. NodeB - intermediary - 4. NodeC with configured `SSH-client` app - 2. Run `./integration/test-ssh.sh` which will run in cycle: - 1. `./SSH-cli $PK_A "export n=1; loop -n $n echo A"` - 2. kill all `skywire-visor`s - 3. Collect logs - 4. Increase n by power of 2 - 5. Repeat - ### Proxy test environment The proxy test environment will define the following: - skywire-services running on localhost - 3 `skywire-visor`s: - - NodeA - running `SSH` app + - NodeA - running `proxy` app - NodeB - intermediary node without apps - - NodeC - running `SSH-client` app + - NodeC - running `proxy-client` app #### Preparation @@ -248,9 +200,6 @@ It's possible that a service could start earlier or later than needed. Examine windows, in case of failed service - restart it (E.g. `KeyUp`-`Enter`) -Problem still exists in proxy test environment: - - NodeC cannot start `SSH-client` when NodeA is still starting `SSH` - ### Tmux for new users 1. Read `man tmux` diff --git a/integration/generic/nodeA.json b/integration/generic/nodeA.json index 8fe38dd06b..eaa8f4ebd5 100644 --- a/integration/generic/nodeA.json +++ b/integration/generic/nodeA.json @@ -29,13 +29,6 @@ "port": 1, "args": [] }, - { - "app": "SSH", - "version": "1.0", - "auto_start": true, - "port": 2, - "args": [] - }, { "app": "socksproxy", "version": "1.0", diff --git a/integration/generic/nodeC.json b/integration/generic/nodeC.json index 38d08b5d47..35205b3db4 100644 --- a/integration/generic/nodeC.json +++ b/integration/generic/nodeC.json @@ -32,13 +32,6 @@ ":8001" ] }, - { - "app": "SSH-client", - "version": "1.0", - "auto_start": true, - "port": 12, - "args": [] - }, { "app": "socksproxy-client", "version": "1.0", diff --git a/integration/run-ssh-env.sh b/integration/run-ssh-env.sh deleted file mode 100644 index 758d8b01fe..0000000000 --- a/integration/run-ssh-env.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -## SKYWIRE - -tmux new -s skywire -d - -source ./integration/ssh/env-vars.sh - -echo "Checking transport-discovery is up" -curl --retry 5 --retry-connrefused 1 --connect-timeout 5 https://transport.discovery.skywire.skycoin.net/security/nonces/$PK_A - -tmux rename-window -t skywire NodeA -tmux send-keys -t NodeA -l "./skywire-visor ./integration/ssh/nodeA.json --tag NodeA $SYSLOG_OPTS" -tmux send-keys C-m -tmux new-window -t skywire -n NodeB -tmux send-keys -t NodeB -l "./skywire-visor ./integration/intermediary-nodeB.json --tag NodeB $SYSLOG_OPTS" -tmux send-keys C-m -tmux new-window -t skywire -n NodeC -tmux send-keys -t NodeC -l "./skywire-visor ./integration/ssh/nodeC.json --tag NodeC $SYSLOG_OPTS" -tmux send-keys C-m - -tmux new-window -t skywire -n shell - -tmux send-keys -t shell 'source ./integration/ssh/env-vars.sh' C-m - -tmux attach -t skywire diff --git a/integration/ssh/env-vars.sh b/integration/ssh/env-vars.sh deleted file mode 100644 index bf0cab2ad9..0000000000 --- a/integration/ssh/env-vars.sh +++ /dev/null @@ -1,24 +0,0 @@ -# This script needs to be `source`d from bash-compatible shell -# E.g. `source ./integration/ssh/env-vars.sh` or `. ./integration/ssh/env-vars.sh` -export PK_A=$(jq -r ".node.static_public_key" ./integration/ssh/nodeA.json) -export RPC_A=$(jq -r ".interfaces.rpc" ./integration/ssh/nodeA.json) -export PK_B=$(jq -r ".node.static_public_key" ./integration/intermediary-nodeB.json) -export RPC_B=$(jq -r ".interfaces.rpc" ./integration/intermediary-nodeB.json) -export PK_C=$(jq -r ".node.static_public_key" ./integration/ssh/nodeC.json) -export RPC_C=$(jq -r ".interfaces.rpc" ./integration/ssh/nodeC.json) - -alias CLI_A='./skywire-cli --rpc $RPC_A' -alias CLI_B='./skywire-cli --rpc $RPC_B' -alias CLI_C='./skywire-cli --rpc $RPC_C' - -export MSGD=https://messaging.discovery.skywire.skycoin.net -export TRD=https://transport.discovery.skywire.skycoin.net -export RF=https://routefinder.skywire.skycoin.net - -alias RUN_A='go run ./cmd/skywire-visor ./integration/messaging/nodeA.json --tag NodeA' -alias RUN_B='go run ./cmd/skywire-visor ./integration/intermediary-nodeB.json --tag NodeB' -alias RUN_C='go run ./cmd/skywire-visor ./integration/messaging/nodeC.json --tag NodeC' - -echo PK_A: $PK_A -echo PK_B: $PK_B -echo PK_C: $PK_C diff --git a/integration/ssh/nodeA.json b/integration/ssh/nodeA.json deleted file mode 100644 index 8fe38dd06b..0000000000 --- a/integration/ssh/nodeA.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "version": "1.0", - "node": { - "static_public_key": "02072dd1e2ccd761e717096e1a264de1d8917e78e3176ca99dbf7ccf7292969845", - "static_secret_key": "7073e557aa2308b448525397ea2f45d56c9962c4dcdf82c5fdb5cc02fca0481c" - }, - "messaging": { - "discovery": "https://messaging.discovery.skywire.skycoin.net", - "server_count": 1 - }, - "transport": { - "discovery": "https://transport.discovery.skywire.skycoin.net", - "log_store": { - "type": "file", - "location": "./local/nodeA/transport_logs" - } - }, - "routing": { - "setup_nodes": [ - "0324579f003e6b4048bae2def4365e634d8e0e3054a20fc7af49daf2a179658557" - ], - "route_finder": "https://routefinder.skywire.skycoin.net/" - }, - "apps": [ - { - "app": "skychat", - "version": "1.0", - "auto_start": true, - "port": 1, - "args": [] - }, - { - "app": "SSH", - "version": "1.0", - "auto_start": true, - "port": 2, - "args": [] - }, - { - "app": "socksproxy", - "version": "1.0", - "auto_start": true, - "port": 3, - "args": [] - } - ], - "trusted_nodes": [], - "hypervisors": [], - "apps_path": "./apps", - "local_path": "./local/nodeA", - "log_level": "info", - "interfaces": { - "rpc": "localhost:3436" - } -} diff --git a/integration/ssh/nodeC.json b/integration/ssh/nodeC.json deleted file mode 100644 index 38d08b5d47..0000000000 --- a/integration/ssh/nodeC.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "version": "1.0", - "node": { - "static_public_key": "02c9ddf5c2ae6a5a2166028dafbc814eff3ec2352f429fb0aa37d96e1aa668f332", - "static_secret_key": "5ab3744ab56e4d0b82f9a915e07b8f05d51ec0f16ff8496bd92f4e378ca6c1fc" - }, - "messaging": { - "discovery": "https://messaging.discovery.skywire.skycoin.net", - "server_count": 1 - }, - "transport": { - "discovery": "https://transport.discovery.skywire.skycoin.net", - "log_store": { - "type": "file", - "location": "./local/nodeC/transport_logs" - } - }, - "routing": { - "setup_nodes": [ - "0324579f003e6b4048bae2def4365e634d8e0e3054a20fc7af49daf2a179658557" - ], - "route_finder": "https://routefinder.skywire.skycoin.net/" - }, - "apps": [ - { - "app": "skychat", - "version": "1.0", - "auto_start": true, - "port": 1, - "args": [ - "-addr", - ":8001" - ] - }, - { - "app": "SSH-client", - "version": "1.0", - "auto_start": true, - "port": 12, - "args": [] - }, - { - "app": "socksproxy-client", - "version": "1.0", - "auto_start": true, - "port": 13, - "args": [ - "-srv", - "024ec47420176680816e0406250e7156465e4531f5b26057c9f6297bb0303558c7" - ] - } - ], - "trusted_nodes": [], - "hypervisors": [], - "apps_path": "./apps", - "local_path": "./local/nodeC", - "log_level": "info", - "interfaces": { - "rpc": "localhost:3438" - } -} diff --git a/integration/test-proxy.sh b/integration/test-proxy.sh deleted file mode 100644 index 5ccf5f9e6d..0000000000 --- a/integration/test-proxy.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env bash - -echo Starting ssh test -echo Press Ctrl-C to exit - -source ./integration/proxy/env-vars.sh - -export N=1 -for i in {1..16} -do - echo Test with $N requests - mkdir -p ./logs/proxy/$N - - echo Killing nodes - echo Killing $(ps aux |grep "[N]odeA\|[N]odeB\|[N]odeC" |awk '{print $2}') - kill $(ps aux |grep "[N]odeA\|[N]odeB\|[N]odeC" |awk '{print $2}') - - # This sleep needed to allow clean exit of node - sleep 10 - - echo Restarting nodeA and NodeB - ./bin/skywire-visor ./integration/proxy/nodeA.json --tag NodeA &> ./logs/proxy/$N/nodeA.log & - ./bin/skywire-visor ./integration/intermediary-nodeB.json --tag NodeB &> ./logs/proxy/$N/nodeB.log & - - # TODO: improve this sleep - sleep 5 - echo Restarting nodeC - ./bin/skywire-visor ./integration/proxy/nodeC.json --tag NodeC &> ./logs/proxy/$N/nodeC.log & - - sleep 20 - echo Trying socks5 proxy - - for ((j=0; j<$N; j++)) - do - echo Request $j - curl -v --retry 5 --retry-connrefused 1 --connect-timeout 5 -x socks5://123456:@localhost:9999 https://www.google.com &>> ./logs/proxy/$N/curl.out - done - - export N=$(($N*2)) -done diff --git a/integration/test-ssh.sh b/integration/test-ssh.sh deleted file mode 100644 index 5bcb91cc4e..0000000000 --- a/integration/test-ssh.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash - -echo Starting ssh test -echo Press Ctrl-C to exit - -source ./integration/ssh/env-vars.sh - -export N=1 -for i in {1..16} -do - echo Test with $N lines - mkdir -p ./logs/ssh/$N - - echo Killing nodes and SSH-cli - echo Killing $(ps aux |grep "[N]odeA\|[N]odeB\|[N]odeC\|[s]kywire/SSH-cli" |awk '{print $2}') - kill $(ps aux |grep "[N]odeA\|[N]odeB\|[N]odeC\|[s]kywire/SSH-cli" |awk '{print $2}') - - echo Restarting nodes - ./bin/skywire-visor ./integration/ssh/nodeA.json --tag NodeA &> ./logs/ssh/$N/nodeA.log & - ./bin/skywire-visor ./integration/intermediary-nodeB.json --tag NodeB &> ./logs/ssh/$N/nodeB.log & - ./bin/skywire-visor ./integration/ssh/nodeC.json --tag NodeC &> ./logs/ssh/$N/nodeC.log & - - sleep 20 - echo Trying SSH-cli - export CMD=$(echo ./bin/SSH-cli $PK_A \"loop -n $N echo A\") - echo $CMD - eval $CMD &>./logs/ssh/$N/SSH-cli.out - - - export N=$(($N*2)) -done diff --git a/internal/skyenv/const.go b/internal/skyenv/const.go index d2d17c3171..25014054ea 100644 --- a/internal/skyenv/const.go +++ b/internal/skyenv/const.go @@ -41,14 +41,10 @@ const ( SkychatPort = uint16(1) SkychatAddr = ":8000" - SkysshPort = uint16(2) - SkyproxyName = "socksproxy" SkyproxyVersion = "1.0" SkyproxyPort = uint16(3) - SkysshClientAddr = ":2222" - SkyproxyClientName = "socksproxy-client" SkyproxyClientVersion = "1.0" SkyproxyClientPort = uint16(13) diff --git a/pkg/therealssh/auth.go b/pkg/therealssh/auth.go deleted file mode 100644 index 86115b7e23..0000000000 --- a/pkg/therealssh/auth.go +++ /dev/null @@ -1,92 +0,0 @@ -package therealssh - -import ( - "bufio" - "errors" - "fmt" - "os" - "path/filepath" - - "github.com/SkycoinProject/dmsg/cipher" -) - -// Authorizer defines interface for authorization providers. -type Authorizer interface { - Authorize(pk cipher.PubKey) error -} - -// ListAuthorizer performs authorization against static list. -type ListAuthorizer struct { - AuthorizedKeys []cipher.PubKey -} - -// Authorize implements Authorizer for ListAuthorizer -func (auth *ListAuthorizer) Authorize(remotePK cipher.PubKey) error { - for _, key := range auth.AuthorizedKeys { - if remotePK == key { - return nil - } - } - - return errors.New("unknown PubKey") -} - -// FileAuthorizer performs authorization against file that has PubKey per line. -type FileAuthorizer struct { - authFile *os.File -} - -// NewFileAuthorizer constructs new FileAuthorizer -func NewFileAuthorizer(authFile string) (*FileAuthorizer, error) { - path, err := filepath.Abs(authFile) - if err != nil { - return nil, fmt.Errorf("failed to resolve auth file path: %s", err) - } - - f, err := os.Open(filepath.Clean(path)) - if err != nil { - if os.IsNotExist(err) { - if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil { - return nil, fmt.Errorf("failed to create auth file: %s", err) - } - if f, err = os.Create(path); err != nil { - return nil, fmt.Errorf("failed to create auth file: %s", err) - } - } else { - return nil, fmt.Errorf("failed to open auth file: %s", err) - } - } - - return &FileAuthorizer{f}, nil -} - -// Close releases underlying file pointer. -func (auth *FileAuthorizer) Close() error { - if auth == nil { - return nil - } - return auth.authFile.Close() -} - -// Authorize implements Authorizer for FileAuthorizer -func (auth *FileAuthorizer) Authorize(remotePK cipher.PubKey) error { - defer func() { - if _, err := auth.authFile.Seek(0, 0); err != nil { - Log.WithError(err).Warn("Failed to seek to the beginning of auth file") - } - }() - - hexPK := remotePK.Hex() - scanner := bufio.NewScanner(auth.authFile) - for scanner.Scan() { - if hexPK == scanner.Text() { - return nil - } - } - - if err := scanner.Err(); err != nil { - return fmt.Errorf("failed to read from auth file: %s", err) - } - - return errors.New("unknown PubKey") -} diff --git a/pkg/therealssh/auth_test.go b/pkg/therealssh/auth_test.go deleted file mode 100644 index 2dd2d37911..0000000000 --- a/pkg/therealssh/auth_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package therealssh - -import ( - "io/ioutil" - "os" - "testing" - - "github.com/SkycoinProject/dmsg/cipher" - "github.com/stretchr/testify/require" -) - -func TestListAuthorizer(t *testing.T) { - pk, _ := cipher.GenerateKeyPair() - auth := &ListAuthorizer{[]cipher.PubKey{pk}} - require.Error(t, auth.Authorize(cipher.PubKey{})) - require.NoError(t, auth.Authorize(pk)) -} - -func TestFileAuthorizer(t *testing.T) { - pk, _ := cipher.GenerateKeyPair() - anotherPK, _ := cipher.GenerateKeyPair() - - tmpfile, err := ioutil.TempFile("", "authorized_keys") - require.NoError(t, err) - defer func() { - require.NoError(t, os.Remove(tmpfile.Name())) - }() - - _, err = tmpfile.Write([]byte(pk.Hex() + "\n")) - require.NoError(t, err) - - auth, err := NewFileAuthorizer(tmpfile.Name()) - require.NoError(t, err) - - require.Error(t, auth.Authorize(anotherPK)) - require.NoError(t, auth.Authorize(pk)) - - _, err = tmpfile.Write([]byte(anotherPK.Hex() + "\n")) - require.NoError(t, err) - - require.NoError(t, auth.Authorize(anotherPK)) - require.NoError(t, auth.Authorize(pk)) -} diff --git a/pkg/therealssh/chan_list.go b/pkg/therealssh/chan_list.go deleted file mode 100644 index 5f76ac10d0..0000000000 --- a/pkg/therealssh/chan_list.go +++ /dev/null @@ -1,54 +0,0 @@ -package therealssh - -import "sync" - -type chanList struct { - sync.Mutex - - chans []*SSHChannel -} - -func newChanList() *chanList { - return &chanList{chans: []*SSHChannel{}} -} - -func (c *chanList) add(sshCh *SSHChannel) uint32 { - c.Lock() - defer c.Unlock() - - for i := range c.chans { - if c.chans[i] == nil { - c.chans[i] = sshCh - return uint32(i) - } - } - - c.chans = append(c.chans, sshCh) - return uint32(len(c.chans) - 1) -} - -func (c *chanList) getChannel(id uint32) *SSHChannel { - c.Lock() - defer c.Unlock() - - if id < uint32(len(c.chans)) { - return c.chans[id] - } - - return nil -} - -func (c *chanList) dropAll() []*SSHChannel { - c.Lock() - defer c.Unlock() - var r []*SSHChannel - - for _, ch := range c.chans { - if ch == nil { - continue - } - r = append(r, ch) - } - c.chans = nil - return r -} diff --git a/pkg/therealssh/channel.go b/pkg/therealssh/channel.go deleted file mode 100644 index a2d1a4f023..0000000000 --- a/pkg/therealssh/channel.go +++ /dev/null @@ -1,364 +0,0 @@ -package therealssh - -import ( - "encoding/binary" - "errors" - "fmt" - "io" - "net" - "os" - "os/user" - "path/filepath" - "strings" - "sync" - - "github.com/SkycoinProject/skywire-mainnet/internal/skyenv" - - "github.com/SkycoinProject/dmsg/cipher" - "github.com/creack/pty" - - "github.com/SkycoinProject/skywire-mainnet/pkg/routing" -) - -// Port reserved for SSH app -const Port = routing.Port(skyenv.SkysshPort) - -// Debug enables debug messages. -var Debug = false - -// SSHChannel defines communication channel parameters. -type SSHChannel struct { - RemoteID uint32 - RemoteAddr routing.Addr - - conn net.Conn - msgCh chan []byte - - session *Session - listenerMx sync.Mutex - listener *net.UnixListener - - dataChMx sync.Mutex - dataCh chan []byte - - doneOnce sync.Once - done chan struct{} -} - -// OpenChannel constructs new SSHChannel with empty Session. -func OpenChannel(remoteID uint32, remoteAddr routing.Addr, conn net.Conn) *SSHChannel { - return &SSHChannel{RemoteID: remoteID, conn: conn, RemoteAddr: remoteAddr, msgCh: make(chan []byte), - dataCh: make(chan []byte), done: make(chan struct{})} -} - -// OpenClientChannel constructs new client SSHChannel with empty Session. -func OpenClientChannel(remoteID uint32, remotePK cipher.PubKey, conn net.Conn) *SSHChannel { - ch := OpenChannel(remoteID, routing.Addr{PubKey: remotePK, Port: Port}, conn) - return ch -} - -// Send sends command message. -func (sshCh *SSHChannel) Send(cmd CommandType, payload []byte) error { - data := appendU32([]byte{byte(cmd)}, sshCh.RemoteID) - _, err := sshCh.conn.Write(append(data, payload...)) - return err -} - -func (sshCh *SSHChannel) Read(p []byte) (int, error) { - data, more := <-sshCh.dataCh - if !more { - return 0, io.EOF - } - - return copy(p, data), nil -} - -func (sshCh *SSHChannel) Write(p []byte) (n int, err error) { - n = len(p) - err = sshCh.Send(CmdChannelData, p) - return -} - -// Request sends request message and waits for response. -func (sshCh *SSHChannel) Request(requestType RequestType, payload []byte) ([]byte, error) { - Log.Debugf("sending request %x", requestType) - req := append([]byte{byte(requestType)}, payload...) - - if err := sshCh.Send(CmdChannelRequest, req); err != nil { - return nil, fmt.Errorf("request failure: %s", err) - } - - data := <-sshCh.msgCh - if data[0] == ResponseFail { - return nil, fmt.Errorf("request failure: %s", string(data[1:])) - } - - return data[1:], nil -} - -// Serve starts request handling loop. -func (sshCh *SSHChannel) Serve() error { - for data := range sshCh.msgCh { - var err error - Log.Debugf("new request %x", data[0]) - switch RequestType(data[0]) { - case RequestPTY: - var u *user.User - u, err = user.Lookup(string(data[17:])) - if err != nil { - break - } - - cols := binary.BigEndian.Uint32(data[1:]) - rows := binary.BigEndian.Uint32(data[5:]) - width := binary.BigEndian.Uint32(data[9:]) - height := binary.BigEndian.Uint32(data[13:]) - size := &pty.Winsize{Cols: uint16(cols), Rows: uint16(rows), X: uint16(width), Y: uint16(height)} - err = sshCh.OpenPTY(u, size) - case RequestShell: - err = sshCh.Shell() - case RequestExec: - err = sshCh.Start(string(data[1:])) - case RequestExecWithoutShell: - err = sshCh.Run(string(data[1:])) - case RequestWindowChange: - cols := binary.BigEndian.Uint32(data[1:]) - rows := binary.BigEndian.Uint32(data[5:]) - width := binary.BigEndian.Uint32(data[9:]) - height := binary.BigEndian.Uint32(data[13:]) - err = sshCh.WindowChange(&pty.Winsize{Cols: uint16(cols), Rows: uint16(rows), X: uint16(width), Y: uint16(height)}) - } - - var res []byte - if err != nil { - res = append([]byte{ResponseFail}, []byte(err.Error())...) - } else { - res = []byte{ResponseConfirm} - } - - if err := sshCh.Send(CmdChannelResponse, res); err != nil { - return fmt.Errorf("failed to respond: %s", err) - } - } - - return nil -} - -// SocketPath returns unix socket location. This socket is normally -// used by the CLI to exchange PTY data with a client app. -func (sshCh *SSHChannel) SocketPath() string { - return filepath.Join(os.TempDir(), fmt.Sprintf("therealsshd-%d", sshCh.RemoteID)) -} - -// ServeSocket starts socket handling loop. -func (sshCh *SSHChannel) ServeSocket() error { - if err := os.Remove(sshCh.SocketPath()); err != nil { - Log.WithError(err).Warn("Failed to remove SSH channel socket file") - } - - Log.Debugf("waiting for new socket connections on: %s", sshCh.SocketPath()) - l, err := net.ListenUnix("unix", &net.UnixAddr{Name: sshCh.SocketPath(), Net: "unix"}) - if err != nil { - return fmt.Errorf("failed to open unix socket: %s", err) - } - - sshCh.listenerMx.Lock() - sshCh.listener = l - sshCh.listenerMx.Unlock() - conn, err := l.AcceptUnix() - if err != nil { - return fmt.Errorf("failed to accept connection: %s", err) - } - - Log.Debugln("got new socket connection") - defer func() { - if err := conn.Close(); err != nil { - Log.WithError(err).Warn("Failed to close connection") - } - if err := sshCh.closeListener(); err != nil { - Log.WithError(err).Warn("Failed to close listener") - } - if err := os.Remove(sshCh.SocketPath()); err != nil { - Log.WithError(err).Warn("Failed to close SSH channel socket file") - } - }() - - go func() { - if _, err := io.Copy(sshCh, conn); err != nil && !strings.Contains(err.Error(), "use of closed network connection") { - Log.Errorf("failed to write to server:", err) - return - } - }() - - if _, err := io.Copy(conn, sshCh); err != nil { - return fmt.Errorf("failed to write to client: %s", err) - } - - return nil -} - -// OpenPTY creates new PTY Session for the Channel. -func (sshCh *SSHChannel) OpenPTY(user *user.User, sz *pty.Winsize) (err error) { - if sshCh.session != nil { - return errors.New("session is already started") - } - - Log.Debugf("starting new session for %s with %#v", user.Username, sz) - sshCh.session, err = OpenSession(user, sz) - if err != nil { - sshCh.session = nil - return - } - - return -} - -// Shell starts shell process on Channel's PTY session. -func (sshCh *SSHChannel) Shell() error { - return sshCh.Start("shell") -} - -// Start executes provided command on Channel's PTY session. -func (sshCh *SSHChannel) Start(command string) error { - if sshCh.session == nil { - return errors.New("session is not started") - } - - go func() { - if err := sshCh.serveSession(); err != nil { - Log.Error("Session failure:", err) - } - }() - - Log.Debugf("starting new pty process %s", command) - return sshCh.session.Start(command) -} - -// Run executes provided command on Channel's PTY session and returns output as []byte. -func (sshCh *SSHChannel) Run(command string) error { - if sshCh.session == nil { - return errors.New("session is not started") - } - - out, err := sshCh.session.Run(command) - if err != nil { - return err - } - - go func() { - _, err := sshCh.Write(out) - if err != nil { - Log.Warn("error writing to channel: ", err) - } - }() - return err -} - -func (sshCh *SSHChannel) serveSession() error { - defer func() { - if err := sshCh.Send(CmdChannelServerClose, nil); err != nil { - Log.WithError(err).Warn("Failed to send to SSH channel") - } - if err := sshCh.Close(); err != nil { - Log.WithError(err).Warn("Failed to close SSH channel") - } - }() - - go func() { - if _, err := io.Copy(sshCh.session, sshCh); err != nil { - Log.Error("PTY copy: ", err) - return - } - }() - - _, err := io.Copy(sshCh, sshCh.session) - if err != nil && !strings.Contains(err.Error(), "input/output error") { - return fmt.Errorf("client copy: %s", err) - } - - return nil -} - -// WindowChange resize PTY Session size. -func (sshCh *SSHChannel) WindowChange(sz *pty.Winsize) error { - if sshCh.session == nil { - return errors.New("session is not started") - } - - return sshCh.session.WindowChange(sz) -} - -func (sshCh *SSHChannel) close() (closed bool, err error) { - sshCh.doneOnce.Do(func() { - closed = true - - close(sshCh.done) - - select { - case <-sshCh.dataCh: - default: - sshCh.dataChMx.Lock() - close(sshCh.dataCh) - sshCh.dataChMx.Unlock() - } - close(sshCh.msgCh) - - var sErr, lErr error - if sshCh.session != nil { - sErr = sshCh.session.Close() - } - - lErr = sshCh.closeListener() - - if sErr != nil { - err = sErr - return - } - - if lErr != nil { - err = lErr - } - }) - - return closed, err -} - -// Close safely closes Channel resources. -func (sshCh *SSHChannel) Close() error { - if sshCh == nil { - return nil - } - - closed, err := sshCh.close() - if err != nil { - return err - } - if !closed { - return errors.New("channel is already closed") - } - - return nil -} - -// IsClosed returns whether the Channel is closed. -func (sshCh *SSHChannel) IsClosed() bool { - select { - case <-sshCh.done: - return true - default: - return false - } -} - -func (sshCh *SSHChannel) closeListener() error { - sshCh.listenerMx.Lock() - defer sshCh.listenerMx.Unlock() - - return sshCh.listener.Close() -} - -func appendU32(buf []byte, n uint32) []byte { - uintBuf := make([]byte, 4) - binary.BigEndian.PutUint32(uintBuf[0:], n) - return append(buf, uintBuf...) -} diff --git a/pkg/therealssh/channel_pty_test.go b/pkg/therealssh/channel_pty_test.go deleted file mode 100644 index 8b2004e7e3..0000000000 --- a/pkg/therealssh/channel_pty_test.go +++ /dev/null @@ -1,91 +0,0 @@ -// +build !no_ci - -package therealssh - -import ( - "net" - "os/user" - "testing" - "time" - - "github.com/SkycoinProject/dmsg/cipher" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/SkycoinProject/skywire-mainnet/pkg/routing" -) - -func TestChannelServe(t *testing.T) { - in, out := net.Pipe() - ch := OpenChannel(1, routing.Addr{PubKey: cipher.PubKey{}, Port: Port}, in) - - errCh := make(chan error) - go func() { - errCh <- ch.Serve() - }() - - req := appendU32([]byte{byte(RequestPTY)}, 10) - req = appendU32(req, 20) - req = appendU32(req, 0) - req = appendU32(req, 0) - u, err := user.Current() - require.NoError(t, err) - req = append(req, []byte(u.Username)...) - ch.msgCh <- req - time.Sleep(100 * time.Millisecond) - - buf := make([]byte, 6) - _, err = out.Read(buf) - require.NoError(t, err) - assert.EqualValues(t, CmdChannelResponse, buf[0]) - assert.Equal(t, ResponseConfirm, buf[5]) - - require.NotNil(t, ch.session) - - ch.msgCh <- []byte{byte(RequestShell)} - time.Sleep(100 * time.Millisecond) - - buf = make([]byte, 6) - _, err = out.Read(buf) - require.NoError(t, err) - assert.EqualValues(t, CmdChannelResponse, buf[0]) - assert.Equal(t, ResponseConfirm, buf[5]) - - buf = make([]byte, 10) - _, err = out.Read(buf) - require.NoError(t, err) - assert.EqualValues(t, CmdChannelData, buf[0]) - assert.NotNil(t, buf[5:]) - - require.NotNil(t, ch.dataCh) - ch.dataCh <- []byte("echo foo\n") - time.Sleep(100 * time.Millisecond) - - buf = make([]byte, 15) - _, err = out.Read(buf) - require.NoError(t, err) - assert.EqualValues(t, CmdChannelData, buf[0]) - assert.Contains(t, string(buf[5:]), "echo foo") - - buf = make([]byte, 15) - _, err = out.Read(buf) - require.NoError(t, err) - assert.EqualValues(t, CmdChannelData, buf[0]) - assert.Contains(t, string(buf[5:]), "foo") - - req = appendU32([]byte{byte(RequestWindowChange)}, 40) - req = appendU32(req, 50) - req = appendU32(req, 0) - req = appendU32(req, 0) - ch.msgCh <- req - time.Sleep(100 * time.Millisecond) - - buf = make([]byte, 6) - _, err = out.Read(buf) - require.NoError(t, err) - assert.EqualValues(t, CmdChannelResponse, buf[0]) - assert.Equal(t, ResponseConfirm, buf[5]) - - require.NoError(t, ch.Close()) - require.NoError(t, <-errCh) -} diff --git a/pkg/therealssh/channel_test.go b/pkg/therealssh/channel_test.go deleted file mode 100644 index b92ab90ba3..0000000000 --- a/pkg/therealssh/channel_test.go +++ /dev/null @@ -1,130 +0,0 @@ -package therealssh - -import ( - "encoding/binary" - "io" - "net" - "os" - "path/filepath" - "testing" - "time" - - "github.com/SkycoinProject/dmsg/cipher" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/SkycoinProject/skywire-mainnet/internal/testhelpers" - "github.com/SkycoinProject/skywire-mainnet/pkg/routing" -) - -func TestChannelSendWrite(t *testing.T) { - pk, _ := cipher.GenerateKeyPair() - in, out := net.Pipe() - ch := OpenChannel(1, routing.Addr{PubKey: pk, Port: Port}, in) - - errCh := make(chan error) - go func() { - errCh <- ch.Send(CmdChannelOpen, []byte("foo")) - }() - - buf := make([]byte, 8) - _, err := out.Read(buf) - require.NoError(t, err) - require.NoError(t, <-errCh) - assert.Equal(t, byte(CmdChannelOpen), buf[0]) - assert.Equal(t, uint32(1), binary.BigEndian.Uint32(buf[1:])) - assert.Equal(t, []byte("foo"), buf[5:]) - - go func() { - _, err := ch.Write([]byte("foo")) - errCh <- err - }() - - buf = make([]byte, 8) - _, err = out.Read(buf) - require.NoError(t, err) - require.NoError(t, <-errCh) - assert.Equal(t, byte(CmdChannelData), buf[0]) - assert.Equal(t, []byte("foo"), buf[5:]) -} - -func TestChannelRead(t *testing.T) { - ch := OpenChannel(1, routing.Addr{PubKey: cipher.PubKey{}, Port: Port}, nil) - - buf := make([]byte, 3) - go func() { - ch.dataCh <- []byte("foo") - }() - - _, err := ch.Read(buf) - require.NoError(t, err) - assert.Equal(t, []byte("foo"), buf) - - close(ch.dataCh) - _, err = ch.Read(buf) - require.Error(t, err) - assert.Equal(t, io.EOF, err) -} - -func TestChannelRequest(t *testing.T) { - in, out := net.Pipe() - ch := OpenChannel(1, routing.Addr{PubKey: cipher.PubKey{}, Port: Port}, in) - - type data struct { - res []byte - err error - } - resCh := make(chan data) - go func() { - res, err := ch.Request(RequestPTY, []byte("foo")) - resCh <- data{res, err} - }() - - buf := make([]byte, 9) - _, err := out.Read(buf) - require.NoError(t, err) - assert.Equal(t, byte(CmdChannelOpen), buf[5]) - assert.Equal(t, []byte("foo"), buf[6:]) - - ch.msgCh <- []byte{ResponseConfirm, 0x4} - d := <-resCh - require.NoError(t, d.err) - assert.Equal(t, []byte{0x4}, d.res) -} - -func TestChannelServeSocket(t *testing.T) { - in, out := net.Pipe() - ch := OpenChannel(1, routing.Addr{PubKey: cipher.PubKey{}, Port: Port}, in) - - assert.Equal(t, filepath.Join(os.TempDir(), "therealsshd-1"), ch.SocketPath()) - - serveErr := make(chan error, 1) - go func() { - serveErr <- ch.ServeSocket() - }() - - time.Sleep(100 * time.Millisecond) - conn, err := net.DialUnix("unix", nil, &net.UnixAddr{Name: ch.SocketPath(), Net: "unix"}) - require.NoError(t, err) - - _, err = conn.Write([]byte("foo")) - require.NoError(t, err) - time.Sleep(100 * time.Millisecond) - - buf := make([]byte, 8) - _, err = out.Read(buf) - require.NoError(t, err) - assert.Equal(t, byte(CmdChannelData), buf[0]) - assert.Equal(t, []byte("foo"), buf[5:]) - - ch.dataCh <- []byte("bar") - time.Sleep(100 * time.Millisecond) - - buf = make([]byte, 3) - _, err = conn.Read(buf) - require.NoError(t, err) - assert.Equal(t, []byte("bar"), buf) - - require.NoError(t, ch.Close()) - require.NoError(t, testhelpers.WithinTimeout(serveErr)) -} diff --git a/pkg/therealssh/client.go b/pkg/therealssh/client.go deleted file mode 100644 index 162c35137a..0000000000 --- a/pkg/therealssh/client.go +++ /dev/null @@ -1,314 +0,0 @@ -package therealssh - -import ( - "encoding/binary" - "errors" - "fmt" - "io" - "net" - "net/rpc" - "strings" - "time" - - "github.com/SkycoinProject/dmsg/cipher" - "github.com/creack/pty" - - "github.com/SkycoinProject/skywire-mainnet/internal/netutil" - "github.com/SkycoinProject/skywire-mainnet/pkg/app/appnet" - "github.com/SkycoinProject/skywire-mainnet/pkg/routing" -) - -var r = netutil.NewRetrier(50*time.Millisecond, 5, 2) - -// Client proxies CLI's requests to a remote server. Control messages -// are sent via RPC interface. PTY data is exchanged via unix socket. -type Client struct { - dialer dialer - chans *chanList -} - -// NewClient construct new RPC listener and Client from a given RPC address and app dialer. -func NewClient(rpcAddr string, d dialer) (net.Listener, *Client, error) { - client := &Client{chans: newChanList(), dialer: d} - rpcClient := &RPCClient{client} - if err := rpc.Register(rpcClient); err != nil { - return nil, nil, fmt.Errorf("RPC register failure: %s", err) - } - rpc.HandleHTTP() - l, err := net.Listen("tcp", rpcAddr) - if err != nil { - return nil, nil, fmt.Errorf("RPC listen failure: %s", err) - } - - return l, client, nil -} - -// OpenChannel requests new Channel on the remote Server. -func (c *Client) OpenChannel(remotePK cipher.PubKey) (localID uint32, sshCh *SSHChannel, cErr error) { - var conn net.Conn - var err error - - err = r.Do(func() error { - conn, err = c.dialer.Dial(appnet.Addr{ - Net: appnet.TypeSkynet, - PubKey: remotePK, - Port: Port, - }) - return err - }) - if err != nil { - cErr = fmt.Errorf("dial failed: %s", err) - return - } - - sshCh = OpenClientChannel(0, remotePK, conn) - Log.Debugln("sending channel open command") - localID = c.chans.add(sshCh) - req := appendU32([]byte{byte(CmdChannelOpen)}, localID) - if _, err := conn.Write(req); err != nil { - cErr = fmt.Errorf("failed to send open channel request: %s", err) - return - } - - go func() { - if err := c.serveConn(conn); err != nil { - Log.Error(err) - } - }() - - Log.Debugln("waiting for channel open response") - data := <-sshCh.msgCh - Log.Debugln("got channel open response") - if data[0] == ResponseFail { - cErr = fmt.Errorf("failed to open channel: %s", string(data[1:])) - return - } - - sshCh.RemoteID = binary.BigEndian.Uint32(data[1:]) - return localID, sshCh, cErr -} - -func (c *Client) resolveChannel(remotePK cipher.PubKey, localID uint32) (*SSHChannel, error) { - sshCh := c.chans.getChannel(localID) - if sshCh == nil { - return nil, errors.New("channel is not opened") - } - - if sshCh.RemoteAddr.PubKey != remotePK { - return nil, errors.New("unauthorized") - } - - return sshCh, nil -} - -// Route defines routing rules for received App messages. -func (c *Client) serveConn(conn net.Conn) error { - for { - buf := make([]byte, 32*1024) - n, err := conn.Read(buf) - if err != nil { - if err == io.EOF { - return nil - } - return err - } - - raddr := conn.RemoteAddr().(routing.Addr) - payload := buf[:n] - - if len(payload) < 5 { - return errors.New("corrupted payload") - } - - sshCh, err := c.resolveChannel(raddr.PubKey, binary.BigEndian.Uint32(payload[1:])) - if err != nil { - return err - } - - data := payload[5:] - Log.Debugf("got new command: %x", payload[0]) - switch CommandType(payload[0]) { - case CmdChannelOpenResponse, CmdChannelResponse: - sshCh.msgCh <- data - case CmdChannelData: - sshCh.dataChMx.Lock() - if !sshCh.IsClosed() { - sshCh.dataCh <- data - } - sshCh.dataChMx.Unlock() - case CmdChannelServerClose: - err = sshCh.Close() - default: - err = fmt.Errorf("unknown command: %x", payload[0]) - } - - if err != nil { - return err - } - } -} - -// Close closes all opened channels. -func (c *Client) Close() error { - if c == nil { - return nil - } - - for _, sshCh := range c.chans.dropAll() { - if err := sshCh.Close(); err != nil { - Log.WithError(err).Warn("Failed to close SSH channel") - } - } - - return nil -} - -// RPCClient exposes Client's methods via RPC interface. -type RPCClient struct { - c *Client -} - -// RequestPTY defines RPC request for a new PTY session. -func (rpc *RPCClient) RequestPTY(args *RequestPTYArgs, channelID *uint32) error { - Log.Debugln("requesting SSH channel") - localID, channel, err := rpc.c.OpenChannel(args.RemotePK) - if err != nil { - return err - } - - Log.Debugln("requesting PTY session") - if _, err := channel.Request(RequestPTY, args.ToBinary()); err != nil { - return fmt.Errorf("PTY request failure: %s", err) - } - - *channelID = localID - return nil -} - -// Exec defines new remote execution RPC request. -func (rpc *RPCClient) Exec(args *ExecArgs, socketPath *string) error { - sshCh := rpc.c.chans.getChannel(args.ChannelID) - if sshCh == nil { - return errors.New("unknown channel") - } - - Log.Debugln("requesting shell process") - if args.CommandWithArgs == nil { - if _, err := sshCh.Request(RequestShell, nil); err != nil { - return fmt.Errorf("shell request failure: %s", err) - } - } else { - if _, err := sshCh.Request(RequestExec, args.ToBinary()); err != nil { - return fmt.Errorf("shell request failure: %s", err) - } - } - - waitCh := make(chan bool) - go func() { - Log.Debugln("starting socket listener") - waitCh <- true - if err := sshCh.ServeSocket(); err != nil { - Log.Error("Session failure:", err) - } - }() - - *socketPath = sshCh.SocketPath() - <-waitCh - return nil -} - -// Run defines new remote shell-less execution RPC request. -func (rpc *RPCClient) Run(args *ExecArgs, socketPath *string) error { - sshCh := rpc.c.chans.getChannel(args.ChannelID) - if sshCh == nil { - return errors.New("unknown channel") - } - - Log.Debugln("requesting shell-less process execution") - if _, err := sshCh.Request(RequestExecWithoutShell, args.ToBinary()); err != nil { - return fmt.Errorf("run command request failure: %s", err) - } - - waitCh := make(chan bool) - go func() { - Log.Debugln("starting socket listener") - waitCh <- true - if err := sshCh.ServeSocket(); err != nil { - Log.Error("Session failure:", err) - } - }() - - *socketPath = sshCh.SocketPath() - - <-waitCh - return nil -} - -// WindowChange defines window size change RPC request. -func (rpc *RPCClient) WindowChange(args *WindowChangeArgs, _ *int) error { - sshCh := rpc.c.chans.getChannel(args.ChannelID) - if sshCh == nil { - return errors.New("unknown ssh channel") - } - - if _, err := sshCh.Request(RequestWindowChange, args.ToBinary()); err != nil { - return fmt.Errorf("window change request failure: %s", err) - } - - return nil -} - -// Close defines close client RPC request. -func (rpc *RPCClient) Close(channelID *uint32, _ *struct{}) error { - if rpc == nil { - return nil - } - - sshCh := rpc.c.chans.getChannel(*channelID) - if sshCh == nil { - return errors.New("unknown ssh channel") - } - - return sshCh.conn.Close() -} - -// RequestPTYArgs defines RequestPTY request parameters. -type RequestPTYArgs struct { - Username string - RemotePK cipher.PubKey - Size *pty.Winsize -} - -// ToBinary returns binary representation of Args. -func (args *RequestPTYArgs) ToBinary() []byte { - req := appendU32([]byte{}, uint32(args.Size.Cols)) - req = appendU32(req, uint32(args.Size.Rows)) - req = appendU32(req, uint32(args.Size.X)) - req = appendU32(req, uint32(args.Size.Y)) - return append(req, []byte(args.Username)...) -} - -// ExecArgs represents Exec response parameters. -type ExecArgs struct { - ChannelID uint32 - CommandWithArgs []string -} - -// ToBinary returns binary representation of Args. -func (args *ExecArgs) ToBinary() []byte { - return append([]byte{}, []byte(strings.Join(args.CommandWithArgs, " "))...) -} - -// WindowChangeArgs defines WindowChange request parameters. -type WindowChangeArgs struct { - ChannelID uint32 - Size *pty.Winsize -} - -// ToBinary returns binary representation of Args. -func (args *WindowChangeArgs) ToBinary() []byte { - req := appendU32([]byte{}, uint32(args.Size.Cols)) - req = appendU32(req, uint32(args.Size.Rows)) - req = appendU32(req, uint32(args.Size.X)) - return appendU32(req, uint32(args.Size.Y)) -} diff --git a/pkg/therealssh/client_test.go b/pkg/therealssh/client_test.go deleted file mode 100644 index 7b49184ed5..0000000000 --- a/pkg/therealssh/client_test.go +++ /dev/null @@ -1,106 +0,0 @@ -package therealssh - -import ( - "encoding/binary" - "net" - "testing" - - "github.com/SkycoinProject/dmsg/cipher" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/SkycoinProject/skywire-mainnet/pkg/app/appnet" - "github.com/SkycoinProject/skywire-mainnet/pkg/routing" -) - -func TestClientOpenChannel(t *testing.T) { - pk, _ := cipher.GenerateKeyPair() - conn, dialer := newPipeDialer() - c := &Client{dialer, newChanList()} - - type data struct { - ch *SSHChannel - err error - } - resCh := make(chan data) - go func() { - _, ch, err := c.OpenChannel(pk) - resCh <- data{ch, err} - }() - - buf := make([]byte, 5) - _, err := conn.Read(buf) - require.NoError(t, err) - assert.Equal(t, byte(CmdChannelOpen), buf[0]) - assert.Equal(t, uint32(0), binary.BigEndian.Uint32(buf[1:])) - - ch := c.chans.getChannel(0) - require.NotNil(t, ch) - ch.msgCh <- appendU32([]byte{ResponseConfirm}, 4) - - d := <-resCh - require.NoError(t, d.err) - require.NotNil(t, d.ch) - assert.Equal(t, uint32(4), d.ch.RemoteID) - assert.Equal(t, pk, d.ch.RemoteAddr.PubKey) -} - -func TestClientHandleResponse(t *testing.T) { - pk, _ := cipher.GenerateKeyPair() - c := &Client{nil, newChanList()} - in, out := net.Pipe() - errCh := make(chan error) - go func() { - errCh <- c.serveConn(&mockConn{out, routing.Addr{PubKey: pk, Port: Port}}) - }() - - _, err := in.Write(appendU32([]byte{byte(CmdChannelResponse)}, 0)) - require.NoError(t, err) - assert.Equal(t, "channel is not opened", (<-errCh).Error()) - - go func() { - errCh <- c.serveConn(&mockConn{out, routing.Addr{PubKey: cipher.PubKey{}, Port: Port}}) - }() - - ch := OpenChannel(4, routing.Addr{PubKey: pk, Port: Port}, nil) - c.chans.add(ch) - - _, err = in.Write(appendU32([]byte{byte(CmdChannelResponse)}, 0)) - require.NoError(t, err) - assert.Equal(t, "unauthorized", (<-errCh).Error()) - - go func() { - errCh <- c.serveConn(&mockConn{out, routing.Addr{PubKey: pk, Port: Port}}) - }() - dataCh := make(chan []byte) - go func() { - dataCh <- <-ch.msgCh - }() - - data := append(appendU32([]byte{byte(CmdChannelResponse)}, 0), []byte("foo")...) - _, err = in.Write(data) - require.NoError(t, err) - assert.Equal(t, []byte("foo"), <-dataCh) -} - -type pipeDialer struct { - conn net.Conn -} - -func newPipeDialer() (net.Conn, *pipeDialer) { - in, out := net.Pipe() - return out, &pipeDialer{in} -} - -func (d *pipeDialer) Dial(raddr appnet.Addr) (net.Conn, error) { - return d.conn, nil -} - -type mockConn struct { - net.Conn - addr routing.Addr -} - -func (conn *mockConn) RemoteAddr() net.Addr { - return conn.addr -} diff --git a/pkg/therealssh/dialer.go b/pkg/therealssh/dialer.go deleted file mode 100644 index 31af779426..0000000000 --- a/pkg/therealssh/dialer.go +++ /dev/null @@ -1,12 +0,0 @@ -package therealssh - -import ( - "net" - - "github.com/SkycoinProject/skywire-mainnet/pkg/app/appnet" -) - -// dialer dials to a remote node. -type dialer interface { - Dial(raddr appnet.Addr) (net.Conn, error) -} diff --git a/pkg/therealssh/pty_test.go b/pkg/therealssh/pty_test.go deleted file mode 100644 index e65606f1b0..0000000000 --- a/pkg/therealssh/pty_test.go +++ /dev/null @@ -1,100 +0,0 @@ -// +build dragonfly freebsd linux netbsd openbsd - -package therealssh - -import ( - "net" - "net/http" - "net/rpc" - "os/user" - "testing" - - "github.com/SkycoinProject/dmsg/cipher" - "github.com/SkycoinProject/skycoin/src/util/logging" - "github.com/creack/pty" - "github.com/stretchr/testify/require" - - "github.com/SkycoinProject/skywire-mainnet/pkg/app/appnet" - "github.com/SkycoinProject/skywire-mainnet/pkg/routing" -) - -func TestRunRPC(t *testing.T) { - dialConn, acceptConn := net.Pipe() - pd := PipeDialer{PipeWithRoutingAddr{dialConn}, acceptConn} - rpcC, client, err := NewClient(":9998", pd) - require.NoError(t, err) - defer func() { - require.NoError(t, client.Close()) - }() - - server := NewServer(MockAuthorizer{}, logging.NewMasterLogger()) - go func() { - server.Serve(PipeWithRoutingAddr{acceptConn}) // nolint - }() - - go func() { - http.Serve(rpcC, nil) // nolint - }() - - rpcD, err := rpc.DialHTTP("tcp", ":9998") - require.NoError(t, err) - - cuser, err := user.Current() - require.NoError(t, err) - - ptyArgs := &RequestPTYArgs{ - Username: cuser.Username, - RemotePK: cipher.PubKey{}, - Size: &pty.Winsize{ - Rows: 100, - Cols: 100, - X: 100, - Y: 100, - }, - } - var channel uint32 - err = rpcD.Call("RPCClient.RequestPTY", ptyArgs, &channel) - require.NoError(t, err) - - var socketPath string - execArgs := &ExecArgs{ - ChannelID: channel, - CommandWithArgs: []string{"ls"}, - } - - err = rpcD.Call("RPCClient.Run", execArgs, &socketPath) - require.NoError(t, err) - - conn, err := net.DialUnix("unix", nil, &net.UnixAddr{Name: socketPath, Net: "unix"}) - require.NoError(t, err) - - b := make([]byte, 6024) - _, err = conn.Read(b) - require.NoError(t, err) - require.Contains(t, string(b), "pty_test.go") -} - -type MockAuthorizer struct{} - -func (MockAuthorizer) Authorize(pk cipher.PubKey) error { - return nil -} - -type PipeDialer struct { - dialConn, acceptConn net.Conn -} - -func (p PipeDialer) Dial(raddr appnet.Addr) (c net.Conn, err error) { - return p.dialConn, nil -} - -type PipeWithRoutingAddr struct { - net.Conn -} - -func (p PipeWithRoutingAddr) RemoteAddr() net.Addr { - return routing.Addr{ - PubKey: cipher.PubKey{}, - Port: 9999, - } -} diff --git a/pkg/therealssh/server.go b/pkg/therealssh/server.go deleted file mode 100644 index 9b1c74958b..0000000000 --- a/pkg/therealssh/server.go +++ /dev/null @@ -1,196 +0,0 @@ -package therealssh - -import ( - "encoding/binary" - "errors" - "fmt" - "io" - "net" - - "github.com/SkycoinProject/dmsg/cipher" - "github.com/SkycoinProject/skycoin/src/util/logging" - - "github.com/SkycoinProject/skywire-mainnet/pkg/routing" -) - -// CommandType represents global protocol messages. -type CommandType byte - -const ( - // CmdChannelOpen represents channel open message. - CmdChannelOpen CommandType = iota - // CmdChannelOpenResponse represents channel open response message. - CmdChannelOpenResponse - // CmdChannelRequest represents request message. - CmdChannelRequest - // CmdChannelResponse represents response message. - CmdChannelResponse - // CmdChannelData represents data message. - CmdChannelData - // CmdChannelServerClose represents server message about closing channel. - CmdChannelServerClose -) - -// RequestType represents channel requests types. -type RequestType byte - -const ( - // RequestPTY represents request for new PTY session. - RequestPTY RequestType = iota - // RequestShell represents request for new shell. - RequestShell - // RequestExec represents request for new process. - RequestExec - // RequestExecWithoutShell for use in integration testing. - RequestExecWithoutShell - // RequestWindowChange represents request for PTY size change. - RequestWindowChange -) - -const ( - // ResponseFail represents failed response. - ResponseFail byte = iota - // ResponseConfirm represents successful response. - ResponseConfirm -) - -var responseUnauthorized = append([]byte{ResponseFail}, []byte("unauthorized")...) - -// Server handles remote PTY data exchange. -type Server struct { - log *logging.Logger - auth Authorizer - chans *chanList -} - -// NewServer constructs new Server. -func NewServer(auth Authorizer, log *logging.MasterLogger) *Server { - return &Server{log.PackageLogger("therealssh_server"), auth, newChanList()} -} - -// OpenChannel opens new client channel. -func (s *Server) OpenChannel(remoteAddr routing.Addr, remoteID uint32, conn net.Conn) error { - Log.Debugln("opening new channel") - channel := OpenChannel(remoteID, remoteAddr, conn) - var res []byte - - if s.auth.Authorize(remoteAddr.PubKey) != nil { - res = responseUnauthorized - } else { - res = appendU32([]byte{ResponseConfirm}, s.chans.add(channel)) - } - - s.log.Debugln("sending response") - if err := channel.Send(CmdChannelOpenResponse, res); err != nil { - if err := channel.Close(); err != nil { - Log.WithError(err).Warn("Failed to close channel") - } - return fmt.Errorf("channel response failure: %s", err) - } - - go func() { - s.log.Debugln("listening for channel requests") - if err := channel.Serve(); err != nil { - Log.Error("channel failure:", err) - } - }() - - return nil -} - -// HandleRequest implements multiplexing logic for request messages. -func (s *Server) HandleRequest(remotePK cipher.PubKey, localID uint32, data []byte) error { - channel := s.chans.getChannel(localID) - if channel == nil { - return errors.New("channel is not opened") - } - - if s.auth.Authorize(remotePK) != nil || channel.RemoteAddr.PubKey != remotePK { - if err := channel.Send(CmdChannelResponse, responseUnauthorized); err != nil { - Log.Error("failed to send response: ", err) - } - return nil - } - - channel.msgCh <- data - return nil -} - -// HandleData implements multiplexing logic for data messages. -func (s *Server) HandleData(remotePK cipher.PubKey, localID uint32, data []byte) error { - channel := s.chans.getChannel(localID) - if channel == nil { - return errors.New("channel is not opened") - } - - if s.auth.Authorize(remotePK) != nil || channel.RemoteAddr.PubKey != remotePK { - return errors.New("unauthorized") - } - - if channel.session == nil { - return errors.New("session is not started") - } - - channel.dataChMx.Lock() - if !channel.IsClosed() { - channel.dataCh <- data - } - channel.dataChMx.Unlock() - return nil -} - -// Serve defines routing rules for received App messages. -func (s *Server) Serve(conn net.Conn) error { - for { - buf := make([]byte, 32*1024) - n, err := conn.Read(buf) - if err != nil { - if err == io.EOF { - return nil - } - - return err - } - - raddr := conn.RemoteAddr().(routing.Addr) - payload := buf[:n] - - if len(payload) < 5 { - return errors.New("corrupted payload") - } - - payloadID := binary.BigEndian.Uint32(payload[1:]) - data := payload[5:] - - s.log.Debugf("got new command: %x", payload[0]) - switch CommandType(payload[0]) { - case CmdChannelOpen: - err = s.OpenChannel(raddr, payloadID, conn) - case CmdChannelRequest: - err = s.HandleRequest(raddr.PubKey, payloadID, data) - case CmdChannelData: - err = s.HandleData(raddr.PubKey, payloadID, data) - default: - err = fmt.Errorf("unknown command: %x", payload[0]) - } - - if err != nil { - return err - } - } -} - -// Close closes all opened channels. -func (s *Server) Close() error { - if s == nil { - return nil - } - - for _, channel := range s.chans.dropAll() { - if err := channel.Close(); err != nil { - Log.WithError(err).Warn("Failed to close channel") - } - } - - return nil -} diff --git a/pkg/therealssh/server_test.go b/pkg/therealssh/server_test.go deleted file mode 100644 index 237ff4455c..0000000000 --- a/pkg/therealssh/server_test.go +++ /dev/null @@ -1,124 +0,0 @@ -package therealssh - -import ( - "encoding/binary" - "net" - "os" - "testing" - - "github.com/SkycoinProject/dmsg/cipher" - "github.com/SkycoinProject/skycoin/src/util/logging" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/SkycoinProject/skywire-mainnet/pkg/routing" -) - -func TestMain(m *testing.M) { - loggingLevel, ok := os.LookupEnv("TEST_LOGGING_LEVEL") - if ok { - lvl, err := logging.LevelFromString(loggingLevel) - if err != nil { - Log.Fatal(err) - } - logging.SetLevel(lvl) - } else { - logging.Disable() - } - - os.Exit(m.Run()) -} - -func TestServerOpenChannel(t *testing.T) { - pk, _ := cipher.GenerateKeyPair() - s := NewServer(&ListAuthorizer{[]cipher.PubKey{pk}}, logging.NewMasterLogger()) - - in, out := net.Pipe() - errCh := make(chan error) - go func() { - errCh <- s.OpenChannel(routing.Addr{PubKey: cipher.PubKey{}, Port: Port}, 4, in) - }() - - buf := make([]byte, 18) - _, err := out.Read(buf) - require.NoError(t, err) - require.NoError(t, <-errCh) - assert.Equal(t, byte(CmdChannelOpenResponse), buf[0]) - assert.Equal(t, ResponseFail, buf[5]) - assert.Equal(t, []byte("unauthorized"), buf[6:]) - - go func() { - errCh <- s.OpenChannel(routing.Addr{PubKey: pk, Port: Port}, 4, in) - }() - - buf = make([]byte, 10) - _, err = out.Read(buf) - require.NoError(t, err) - require.NoError(t, <-errCh) - assert.Equal(t, byte(CmdChannelOpenResponse), buf[0]) - assert.Equal(t, ResponseConfirm, buf[5]) - assert.Equal(t, uint32(0), binary.BigEndian.Uint32(buf[6:])) -} - -func TestServerHandleRequest(t *testing.T) { - pk, _ := cipher.GenerateKeyPair() - s := NewServer(&ListAuthorizer{[]cipher.PubKey{pk}}, logging.NewMasterLogger()) - - err := s.HandleRequest(pk, 0, []byte("foo")) - require.Error(t, err) - assert.Equal(t, "channel is not opened", err.Error()) - - in, out := net.Pipe() - ch := OpenChannel(4, routing.Addr{PubKey: pk, Port: Port}, in) - s.chans.add(ch) - - errCh := make(chan error) - go func() { - errCh <- s.HandleRequest(cipher.PubKey{}, 0, []byte("foo")) - }() - - buf := make([]byte, 18) - _, err = out.Read(buf) - require.NoError(t, err) - require.NoError(t, <-errCh) - assert.Equal(t, byte(CmdChannelResponse), buf[0]) - assert.Equal(t, ResponseFail, buf[5]) - assert.Equal(t, []byte("unauthorized"), buf[6:]) - - dataCh := make(chan []byte) - go func() { - dataCh <- <-ch.msgCh - }() - - require.NoError(t, s.HandleRequest(pk, 0, []byte("foo"))) - assert.Equal(t, []byte("foo"), <-dataCh) -} - -func TestServerHandleData(t *testing.T) { - pk, _ := cipher.GenerateKeyPair() - s := NewServer(&ListAuthorizer{[]cipher.PubKey{pk}}, logging.NewMasterLogger()) - - err := s.HandleData(pk, 0, []byte("foo")) - require.Error(t, err) - assert.Equal(t, "channel is not opened", err.Error()) - - ch := OpenChannel(4, routing.Addr{PubKey: pk, Port: Port}, nil) - s.chans.add(ch) - - err = s.HandleData(cipher.PubKey{}, 0, []byte("foo")) - require.Error(t, err) - assert.Equal(t, "unauthorized", err.Error()) - - err = s.HandleData(pk, 0, []byte("foo")) - require.Error(t, err) - assert.Equal(t, "session is not started", err.Error()) - - ch.session = &Session{} - dataCh := make(chan []byte) - go func() { - dataCh <- <-ch.dataCh - }() - - require.NoError(t, s.HandleData(pk, 0, []byte("foo"))) - assert.Equal(t, []byte("foo"), <-dataCh) -} diff --git a/pkg/therealssh/session.go b/pkg/therealssh/session.go deleted file mode 100644 index 2691ef70d2..0000000000 --- a/pkg/therealssh/session.go +++ /dev/null @@ -1,200 +0,0 @@ -package therealssh - -import ( - "fmt" - "io/ioutil" - "os" - "os/exec" - "os/user" - "strconv" - "strings" - "sync" - "syscall" - - "github.com/SkycoinProject/skycoin/src/util/logging" - "github.com/creack/pty" -) - -// Log is the package level logger, which can be replaced from outside -var Log = logging.MustGetLogger("therealssh") - -// Session represents PTY sessions. Channel normally handles Session's lifecycle. -type Session struct { - ptyMu sync.Mutex - pty *os.File - ttyMu sync.Mutex - tty *os.File - - user *user.User - cmd *exec.Cmd -} - -// OpenSession constructs new PTY sessions. -func OpenSession(user *user.User, sz *pty.Winsize) (s *Session, err error) { - s = &Session{user: user} - s.pty, s.tty, err = pty.Open() - if err != nil { - err = fmt.Errorf("failed to open PTY: %s", err) - return - } - - if sz == nil { - return - } - - s.ptyMu.Lock() - defer s.ptyMu.Unlock() - - if err = pty.Setsize(s.pty, sz); err != nil { - if closeErr := s.Close(); closeErr != nil { - Log.WithError(closeErr).Warn("Failed to close session") - } - err = fmt.Errorf("failed to set PTY size: %s", err) - } - - return -} - -// Start executes command on Session's PTY. -func (s *Session) Start(command string) (err error) { - defer func() { - s.ttyMu.Lock() - defer s.ttyMu.Unlock() - - if err := s.tty.Close(); err != nil { - Log.WithError(err).Warn("Failed to close TTY") - } - }() - - if command == "shell" { - if command, err = resolveShell(s.user); err != nil { - return err - } - } - - components := strings.Split(command, " ") - cmd := exec.Command(components[0], components[1:]...) // nolint:gosec - cmd.Dir = s.user.HomeDir - - s.ttyMu.Lock() - cmd.Stdout = s.tty - cmd.Stdin = s.tty - cmd.Stderr = s.tty - s.ttyMu.Unlock() - - if cmd.SysProcAttr == nil { - cmd.SysProcAttr = &syscall.SysProcAttr{} - } - cmd.SysProcAttr.Setctty = true - cmd.SysProcAttr.Setsid = true - cmd.SysProcAttr.Credential = s.credentials() - - s.cmd = cmd - return cmd.Start() -} - -// Run executes a command and returns it's output and error if any -func (s *Session) Run(command string) ([]byte, error) { - var err error - - if command == "shell" { - if command, err = resolveShell(s.user); err != nil { - return nil, err - } - } - - components := strings.Split(command, " ") - - c := exec.Command(components[0], components[1:]...) // nolint:gosec - ptmx, err := pty.Start(c) - if err != nil { - return nil, err - } - - // Make sure to close the pty at the end. - defer func() { - err = ptmx.Close() - if err != nil { - Log.Warn("unable to close pty") - } - }() // Best effort. - - // as stated in https://github.com/creack/pty/issues/21#issuecomment-513069505 we can ignore this error - res, err := ioutil.ReadAll(ptmx) - _ = err - return res, nil -} - -// Wait for pty process to exit. -func (s *Session) Wait() error { - if s.cmd == nil { - return nil - } - - return s.cmd.Wait() -} - -// WindowChange resize PTY Session size. -func (s *Session) WindowChange(sz *pty.Winsize) error { - s.ptyMu.Lock() - defer s.ptyMu.Unlock() - - if err := pty.Setsize(s.pty, sz); err != nil { - return fmt.Errorf("failed to set PTY size: %s", err) - } - - return nil -} - -func (s *Session) credentials() *syscall.Credential { - if s.user == nil { - return nil - } - - u, err := user.Current() - if err != nil { - return nil - } - - if u.Uid == s.user.Uid { - return nil - } - - uid, err := strconv.Atoi(s.user.Uid) - if err != nil { - return nil - } - - gid, err := strconv.Atoi(s.user.Gid) - if err != nil { - return nil - } - - return &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)} -} - -func (s *Session) Write(p []byte) (int, error) { - s.ptyMu.Lock() - defer s.ptyMu.Unlock() - - return s.pty.Write(p) -} - -func (s *Session) Read(p []byte) (int, error) { - s.ptyMu.Lock() - defer s.ptyMu.Unlock() - - return s.pty.Read(p) -} - -// Close releases PTY resources. -func (s *Session) Close() error { - if s == nil { - return nil - } - - s.ptyMu.Lock() - defer s.ptyMu.Unlock() - - return s.pty.Close() -} diff --git a/pkg/therealssh/shell.go b/pkg/therealssh/shell.go deleted file mode 100644 index f3c967adb3..0000000000 --- a/pkg/therealssh/shell.go +++ /dev/null @@ -1,20 +0,0 @@ -// +build dragonfly freebsd linux netbsd openbsd - -package therealssh - -import ( - "fmt" - "os/exec" - "os/user" - "strings" -) - -func resolveShell(u *user.User) (string, error) { - out, err := exec.Command("getent", "passwd", u.Uid).Output() // nolint:gosec - if err != nil { - return "", fmt.Errorf("getent failure: %s", err) - } - - ent := strings.Split(strings.TrimSuffix(string(out), "\n"), ":") - return ent[6], nil -} diff --git a/pkg/therealssh/shell_darwin.go b/pkg/therealssh/shell_darwin.go deleted file mode 100644 index 8115aa9b9c..0000000000 --- a/pkg/therealssh/shell_darwin.go +++ /dev/null @@ -1,25 +0,0 @@ -package therealssh - -import ( - "fmt" - "os/exec" - "os/user" - "regexp" -) - -func resolveShell(u *user.User) (string, error) { - dir := "Local/Default/Users/" + u.Username - out, err := exec.Command("dscl", "localhost", "-read", dir, "UserShell").Output() // nolint:gosec - if err != nil { - return "", err - } - - re := regexp.MustCompile("UserShell: (/[^ ]+)\n") - matched := re.FindStringSubmatch(string(out)) - shell := matched[1] - if shell == "" { - return "", fmt.Errorf("invalid output: %s", string(out)) - } - - return shell, nil -} diff --git a/pkg/visor/visor.go b/pkg/visor/visor.go index c316a51526..f342358862 100644 --- a/pkg/visor/visor.go +++ b/pkg/visor/visor.go @@ -56,7 +56,7 @@ const Version = "0.0.1" const supportedProtocolVersion = "0.0.1" -var reservedPorts = map[routing.Port]string{0: "router", 1: "skychat", 2: "SSH", 3: "skysocks"} +var reservedPorts = map[routing.Port]string{0: "router", 1: "skychat", 3: "skysocks"} // AppState defines state parameters for a registered App. type AppState struct {