Skip to content

Commit

Permalink
created zscp with fluid Path order
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon Kochanik committed Jul 9, 2021
1 parent 60bde94 commit f3c2cd0
Show file tree
Hide file tree
Showing 8 changed files with 259 additions and 9 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
.idea
build/
zssh
build

7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ go 1.16

require (
github.com/mattn/go-isatty v0.0.13 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d
github.com/natefinch/npipe v0.0.0-20160621034901-c1b8fa8bdcce
github.com/openziti/foundation v0.15.53 // indirect
github.com/openziti/foundation v0.15.53
github.com/openziti/sdk-golang v0.15.47
github.com/orcaman/concurrent-map v0.0.0-20210106121528-16402b402231 // indirect
github.com/pkg/errors v0.9.1
github.com/pkg/sftp v1.13.1
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.1.3
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
)
12 changes: 11 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
Expand Down Expand Up @@ -267,6 +269,8 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.5.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
github.com/pkg/sftp v1.13.1 h1:I2qBYMChEhIjOgazfJmV3/mZM256btk6wkCDRmW7JYs=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
Expand Down Expand Up @@ -382,8 +386,9 @@ golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
Expand Down Expand Up @@ -425,6 +430,7 @@ golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
Expand Down Expand Up @@ -468,8 +474,12 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
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=
Expand Down
147 changes: 147 additions & 0 deletions zscp/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package zscp

import (
"fmt"
"github.com/openziti/sdk-golang/ziti"
"github.com/openziti/sdk-golang/ziti/config"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"log"
"os"
"os/user"
"path/filepath"
"runtime"
"strings"
"zssh/zsshlib"
)

const ExpectedServiceAndExeName = "zssh"

var (
ZConfig string
SshKeyPath string
debug bool

rootCmd = &cobra.Command{
Use: "Remote to Local: zscp <remoteUsername>@<targetIdentity>:[Remote Path] [Local Path]\n" +
"Local to Remote: zscp [Local Path] <remoteUsername>@<targetIdentity>:[Remote Path]",
Short: "Z(iti)scp, Carb-loaded ssh performs faster and stronger than ssh",
Long: "Z(iti)scp is a version of ssh that utilizes a ziti network to provide a faster and more secure remote connection. A ziti connection must be established before use",
Args: cobra.ExactValidArgs(2),
Run: func(cmd *cobra.Command, args []string) {
if SshKeyPath == "" {
userHome, err := os.UserHomeDir()
if err != nil {
logrus.Fatal(err)
}
SshKeyPath = filepath.Join(userHome,".ssh","id_rsa")
}
if debug {
logrus.Infof(" sshKeyPath set to: %s", SshKeyPath)
}

if ZConfig == "" {
userHome, err := os.UserHomeDir()
if err != nil {
logrus.Fatal(err)
}
ZConfig = filepath.Join(userHome,".ziti", fmt.Sprintf("%s.json", ExpectedServiceAndExeName))
}
if debug {
logrus.Infof(" ZConfig set to: %s", ZConfig)
}

var username string
var targetIdentity string
var remoteFilePath string
var localFilePath string
var isCopyToRemote bool

if strings.ContainsAny(args[0],":") {
remoteFilePath = args[0]
localFilePath = args[1]
isCopyToRemote = false

} else if strings.ContainsAny(args[1],":") {
remoteFilePath = args[1]
localFilePath = args[0]
isCopyToRemote = true
} else {
logrus.Fatal("cannot determine remote file PATH")
}

fullRemoteFilePath := strings.Split(remoteFilePath, ":")
remoteFilePath = fullRemoteFilePath[1]

if strings.ContainsAny(fullRemoteFilePath[0], "@") {
userServiceName := strings.Split(fullRemoteFilePath[0], "@")
username = userServiceName[0]
targetIdentity = userServiceName[1]
} else {
curUser, err := user.Current()
if err != nil {
logrus.Fatal(err)
}
username = curUser.Username
if strings.Contains(username, "\\") && runtime.GOOS == "windows" {
username = strings.Split(username, "\\")[1]
}
targetIdentity = args[0]
}
if debug {
logrus.Infof(" username set to: %s", username)
logrus.Infof("targetIdentity set to: %s", targetIdentity)
}

ctx := ziti.NewContextWithConfig(getConfig(ZConfig))

_, ok := ctx.GetService(ExpectedServiceAndExeName)
if !ok {
logrus.Fatal("error when retrieving all the services for the provided config")
}

dialOptions := &ziti.DialOptions{
ConnectTimeout: 0,
Identity: targetIdentity,
AppData: nil,
}
svc, err := ctx.DialWithOptions(ExpectedServiceAndExeName, dialOptions)
if err != nil {
logrus.Fatal(fmt.Sprintf("error when dialing service name %s. %v", ExpectedServiceAndExeName, err))
}
factory := zsshlib.NewSshConfigFactoryImpl(username, SshKeyPath)

if isCopyToRemote {
zsshlib.SendFile(factory,localFilePath,remoteFilePath,svc)
} else {
zsshlib.RetrieveRemoteFiles(factory, svc, localFilePath, remoteFilePath)
}
},
}
)

func init() {
rootCmd.Flags().StringVarP(&ZConfig, "ZConfig", "c", "", fmt.Sprintf("Path to ziti config file. default: $HOME/.ziti/%s.json", ExpectedServiceAndExeName))
rootCmd.Flags().StringVarP(&SshKeyPath, "SshKeyPath", "i", "", "Path to ssh key. default: $HOME/.ssh/id_rsa")
rootCmd.Flags().BoolVarP(&debug, "debug", "d", false, "pass to enable additional debug information")
}

type ServiceConfig struct {
Protocol string
Hostname string
Port int
}

func Execute() error{
return rootCmd.Execute()
}

func getConfig(cfgFile string) (zitiCfg *config.Config) {
zitiCfg, err := config.NewFromFile(cfgFile)
if err != nil {
log.Fatalf("failed to load ziti configuration file: %v", err)
}
return zitiCfg
}


9 changes: 9 additions & 0 deletions zscp/zscp/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package main

import (
"zssh/zscp"
)

func main() {
zscp.Execute()
}
2 changes: 1 addition & 1 deletion cmd/root.go → zssh/root.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package cmd
package zssh

import (
"fmt"
Expand Down
4 changes: 2 additions & 2 deletions cmd/zssh/main.go → zssh/zssh/main.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package main

import (
"zssh/cmd"
"zssh/zssh"
)

func main() {
cmd.Execute()
zssh.Execute()
}

83 changes: 83 additions & 0 deletions zsshlib/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@ package zsshlib

import (
"fmt"
"github.com/openziti/foundation/util/info"
"github.com/pkg/errors"
"github.com/pkg/sftp"
"io"
"io/ioutil"
"net"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
Expand Down Expand Up @@ -175,3 +180,81 @@ func sshAuthMethodFromFile(keyPath string) (ssh.AuthMethod, error) {
}
}
}

func SendFile(factory SshConfigFactory, localPath string, remotePath string, conn net.Conn) error {
config := factory.Config()
localFile, err := ioutil.ReadFile(localPath)

if err != nil {
return errors.Wrapf(err, "unable to read local file %v", localFile)
}

defer func() { _ = conn.Close() }()
sshConn, err := Dial(config, conn)
client, err := sftp.NewClient(sshConn)
if err != nil {
return errors.Wrap(err, "error creating sftp client")
}
defer func() { _ = client.Close() }()

rmtFile, err := client.OpenFile(remotePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC)

if err != nil {
return errors.Wrapf(err, "unable to open remote file %v", remotePath)
}
defer rmtFile.Close()

_, err = rmtFile.Write(localFile)

if err != nil {
return err
}

return nil
}

func RetrieveRemoteFiles(factory SshConfigFactory, conn net.Conn, localPath string, paths ...string) error {
if len(paths) < 1 {
return nil
}

if err := os.MkdirAll(localPath, os.ModePerm); err != nil {
return fmt.Errorf("error creating local path: %s", localPath)
}

config := factory.Config()

sshConn, err := Dial(config,conn)
if err != nil {
return fmt.Errorf("error dialing zssh server (%w)", err)
}
defer func() { _ = conn.Close() }()

client, err := sftp.NewClient(sshConn)
if err != nil {
return fmt.Errorf("error creating sftp client (%w)", err)
}
defer func() { _ = client.Close() }()

for _, path := range paths {
rf, err := client.Open(path)
if err != nil {
return fmt.Errorf("error opening remote file [%s] (%w)", path, err)
}
defer func() { _ = rf.Close() }()

lf, err := os.OpenFile(filepath.Join(localPath, filepath.Base(path)), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm)
if err != nil {
return fmt.Errorf("error opening local file [%s] (%w)", path, err)
}
defer func() { _ = lf.Close() }()

n, err := io.Copy(lf, rf)
if err != nil {
return fmt.Errorf("error copying remote file to local [%s] (%w)", path, err)
}
logrus.Infof("%s => %s", path, info.ByteCount(n))
}

return nil
}

0 comments on commit f3c2cd0

Please sign in to comment.