Skip to content

Commit d247ca4

Browse files
committed
creating goscp cli
1 parent f3000a3 commit d247ca4

File tree

12 files changed

+241
-98
lines changed

12 files changed

+241
-98
lines changed

.github/workflows/build.yml

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Build
2+
3+
on:
4+
push:
5+
branches: [master]
6+
7+
jobs:
8+
build:
9+
name: Build
10+
runs-on: ubuntu-latest
11+
steps:
12+
- name: Check out
13+
uses: actions/checkout@v2
14+
15+
- name: Set up Go 1.17
16+
uses: actions/setup-go@v1
17+
with:
18+
go-version: 1.17
19+
id: go
20+
21+
- name: Build
22+
run: |
23+
sudo apt-get install upx-ucl zip
24+
cd goscp
25+
go build -ldflags="-s -w"
26+
GOOS=windows go build -ldflags="-s -w"
27+
upx goscp.exe
28+
zip goscp.zip goscp.exe goscp
29+
- name: Uploading installer
30+
uses: actions/upload-artifact@v2
31+
with:
32+
name: goscp
33+
path: goscp/goscp.zip

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@ _testmain.go
2323
*.test
2424
*.prof
2525
example/example
26+
goscp/example
27+
goscp/goscp

.vscode/settings.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"yaml.schemas": {
3+
"https://json.schemastore.org/github-workflow.json": "file:///home/danny/src/scp/.github/workflows/build.yml"
4+
}
5+
}

example/README.md

-26
This file was deleted.

example/main.go

-65
This file was deleted.

go.mod

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module github.com/dtylman/scp
2+
3+
go 1.17
4+
5+
require (
6+
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838
7+
)
8+
9+
require golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect

go.sum

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
4+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5+
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
6+
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
7+
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
8+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
9+
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 h1:71vQrMauZZhcTVK6KdYM+rklehEEwb3E+ZhaE5jrPrE=
10+
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
11+
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
12+
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
13+
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
14+
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
15+
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
16+
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
17+
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
18+
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
19+
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
20+
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

goscp/README.md

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# GO-SCP
2+
3+
A simple binary to help copying files with SCP from any machine (Windows for instance) to any other place using password auth
4+
5+
This tool can only UPLOAD via SCP.
6+
7+
## Compile
8+
```
9+
go build
10+
```
11+
12+
## Running
13+
14+
Copy all images from `/home/Pictures` that starts with `a` and ends with `png` to `server-host-name:/tmp`:
15+
16+
```
17+
goscp -host [ssh-server-host-name] -username [user-name] -password [password] -from /home/Pictures -match a*png$ -to /tmp
18+
```

goscp/main.go

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"flag"
6+
"fmt"
7+
"log"
8+
"net"
9+
"path/filepath"
10+
"time"
11+
12+
"github.com/dtylman/scp"
13+
"golang.org/x/crypto/ssh"
14+
)
15+
16+
var Options struct {
17+
From string
18+
Match string
19+
To string
20+
Host string
21+
Port int
22+
Username string
23+
Password string
24+
DialTimeout time.Duration
25+
}
26+
27+
func connect() (*ssh.Client, error) {
28+
if Options.Host == "" {
29+
return nil, errors.New("host is empty")
30+
}
31+
address := fmt.Sprintf("%v:%v", Options.Host, Options.Port)
32+
log.Printf("opening tcp to %v", Options.Host)
33+
conn, err := net.DialTimeout("tcp", address, Options.DialTimeout)
34+
if err != nil {
35+
return nil, err
36+
}
37+
config := &ssh.ClientConfig{
38+
User: Options.Username,
39+
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
40+
Auth: []ssh.AuthMethod{ssh.Password(Options.Password)},
41+
}
42+
log.Printf("establishing ssh session %v...", address)
43+
sshConn, sshChan, reqChan, err := ssh.NewClientConn(conn, address, config)
44+
if err != nil {
45+
return nil, err
46+
}
47+
return ssh.NewClient(sshConn, sshChan, reqChan), nil
48+
}
49+
50+
func goSCP() error {
51+
walker, err := NewFilesWalker(Options.From, Options.Match)
52+
if err != nil {
53+
return err
54+
}
55+
err = walker.Walk()
56+
if err != nil {
57+
return err
58+
}
59+
if len(walker.Matches) == 0 {
60+
log.Printf("pattern '%v' yields no files to copy", Options.From)
61+
return nil
62+
}
63+
sc, err := connect()
64+
if err != nil {
65+
return err
66+
}
67+
defer sc.Close()
68+
start := time.Now()
69+
total := int64(0)
70+
for _, path := range walker.Matches {
71+
remotePath := fmt.Sprintf("%v/%v", Options.To, filepath.Base(path))
72+
log.Printf("copying %v to %v", path, remotePath)
73+
n, err := scp.CopyTo(sc, path, remotePath)
74+
if err != nil {
75+
log.Printf("error: %v", err)
76+
}
77+
total += n
78+
}
79+
log.Printf("copied %v bytes in %v", total, time.Since(start))
80+
return nil
81+
}
82+
83+
func main() {
84+
log.SetFlags(0)
85+
flag.StringVar(&Options.From, "from", "", "copy from (path)")
86+
flag.StringVar(&Options.Match, "match", ".*", "if [from] is a folder, scan recursively and match against this regular expression")
87+
flag.StringVar(&Options.To, "to", "", "path on target machine")
88+
flag.StringVar(&Options.Host, "host", "", "host machine")
89+
flag.IntVar(&Options.Port, "port", 22, "port")
90+
flag.StringVar(&Options.Username, "username", "", "user name")
91+
flag.StringVar(&Options.Password, "password", "", "user password")
92+
flag.DurationVar(&Options.DialTimeout, "dial-timeout", time.Minute/2, "dial timeout")
93+
94+
flag.Parse()
95+
96+
err := goSCP()
97+
if err != nil {
98+
log.Printf("error: %v", err)
99+
}
100+
}

goscp/walker.go

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package main
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"regexp"
7+
)
8+
9+
//FilesWalker searches pattern matching files by regex
10+
type FilesWalker struct {
11+
//Matches the matches found by walker
12+
Matches []string
13+
root string
14+
expression *regexp.Regexp
15+
}
16+
17+
//NewFilesWalker creates a new files walker with the provided reg-ex for matching
18+
func NewFilesWalker(root string, expr string) (*FilesWalker, error) {
19+
fw := &FilesWalker{
20+
root: root,
21+
}
22+
var err error
23+
fw.expression, err = regexp.Compile(expr)
24+
if err != nil {
25+
return nil, err
26+
}
27+
return fw, nil
28+
}
29+
30+
//Walk scans the filesystem
31+
func (fw *FilesWalker) Walk() error {
32+
fw.Matches = make([]string, 0)
33+
return filepath.WalkDir(fw.root, fw.walkDirFunc)
34+
}
35+
36+
func (fw *FilesWalker) walkDirFunc(path string, d os.DirEntry, err error) error {
37+
if d == nil {
38+
return nil
39+
}
40+
if d.IsDir() {
41+
return nil
42+
}
43+
if fw.expression.MatchString(path) {
44+
fw.Matches = append(fw.Matches, path)
45+
}
46+
return nil
47+
}

msg.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func (m *Message) ReadFrom(reader io.Reader) (int64, error) {
105105
return 0, err
106106
}
107107
default:
108-
return 0, fmt.Errorf("Unsupported opcode: %v", m.Type)
108+
return 0, fmt.Errorf("unsupported opcode: %v", m.Type)
109109
}
110110
return m.Size, nil
111111
}

0 commit comments

Comments
 (0)