From c96750f280eab0752c4eb858024dedd92233342d Mon Sep 17 00:00:00 2001 From: Boshi Lian Date: Sun, 6 Jan 2019 08:51:04 -0800 Subject: [PATCH] list for working dir --- sshpiperd/pipemgr.go | 27 ++++++++-- sshpiperd/sshpiperd_test.go | 8 ++- sshpiperd/upstream/database/plugin.go | 4 ++ sshpiperd/upstream/provider.go | 9 ++++ sshpiperd/upstream/workingdir/plugin.go | 32 ++++++++++- sshpiperd/upstream/workingdir/workingdir.go | 48 +++++++++-------- .../upstream/workingdir/workingdir_test.go | 54 ++++++++++++------- 7 files changed, 136 insertions(+), 46 deletions(-) diff --git a/sshpiperd/pipemgr.go b/sshpiperd/pipemgr.go index ae869fc4..862aa8c9 100644 --- a/sshpiperd/pipemgr.go +++ b/sshpiperd/pipemgr.go @@ -1,7 +1,10 @@ package main import ( + "fmt" "github.com/tg123/sshpiper/sshpiperd/upstream" + "os" + "text/template" ) func createPipeMgr(load func() (upstream.Provider, error)) interface{} { @@ -33,6 +36,24 @@ func createPipeMgr(load func() (upstream.Provider, error)) interface{} { }{} pipeMgrCmd.List.callback = func(args []string) error { + p, err := load() + if err != nil { + return err + } + + // opt := pipeMgrCmd.List + pipes, err := p.ListPipe() + if err != nil { + return err + } + + t := template.Must(template.New("").Parse(`{{.Username}} -> {{.UpstreamUsername}}@{{.Host}}:{{.Port}}`)) + + for _, pipe := range pipes { + t.Execute(os.Stdout, pipe) + fmt.Println() + } + return nil } @@ -53,14 +74,14 @@ func createPipeMgr(load func() (upstream.Provider, error)) interface{} { } pipeMgrCmd.Remove.callback = func(args []string) error { - - name := pipeMgrCmd.Remove.Name p, err := load() if err != nil { return err } - return p.RemovePipe(name) + opt := pipeMgrCmd.Remove + + return p.RemovePipe(opt.Name) } return &pipeMgrCmd diff --git a/sshpiperd/sshpiperd_test.go b/sshpiperd/sshpiperd_test.go index f7fb35c3..63ea5f8f 100644 --- a/sshpiperd/sshpiperd_test.go +++ b/sshpiperd/sshpiperd_test.go @@ -112,12 +112,16 @@ type testupstream struct { h upstream.Handler } +func (t *testupstream) ListPipe() ([]upstream.Pipe, error) { + return nil, nil +} + func (t *testupstream) CreatePipe(opt upstream.CreatePipeOption) error { - panic("implement me") + return nil } func (t *testupstream) RemovePipe(name string) error { - panic("implement me") + return nil } func (t *testupstream) GetHandler() upstream.Handler { diff --git a/sshpiperd/upstream/database/plugin.go b/sshpiperd/upstream/database/plugin.go index bda4b885..9aef8009 100644 --- a/sshpiperd/upstream/database/plugin.go +++ b/sshpiperd/upstream/database/plugin.go @@ -20,6 +20,10 @@ type plugin struct { db *gorm.DB } +func (p *plugin) ListPipe() ([]upstreamprovider.Pipe, error) { + panic("implement me") +} + func (p *plugin) CreatePipe(opt upstreamprovider.CreatePipeOption) error { panic("implement me") } diff --git a/sshpiperd/upstream/provider.go b/sshpiperd/upstream/provider.go index 0fc7ab3a..89ef2708 100644 --- a/sshpiperd/upstream/provider.go +++ b/sshpiperd/upstream/provider.go @@ -21,12 +21,21 @@ type CreatePipeOption struct { Port uint } +type Pipe struct { + Username string + UpstreamUsername string + Host string + Port uint +} + // Provider is a factory for Upstream Provider type Provider interface { registry.Plugin GetHandler() Handler + ListPipe() ([]Pipe, error) + CreatePipe(opt CreatePipeOption) error RemovePipe(name string) error diff --git a/sshpiperd/upstream/workingdir/plugin.go b/sshpiperd/upstream/workingdir/plugin.go index deb86f0c..72dc6b0b 100644 --- a/sshpiperd/upstream/workingdir/plugin.go +++ b/sshpiperd/upstream/workingdir/plugin.go @@ -14,6 +14,36 @@ var logger *log.Logger type plugin struct { } +func (p *plugin) ListPipe() ([]upstream.Pipe, error) { + files, err := ioutil.ReadDir(config.WorkingDir) + if err != nil { + return nil, err + } + + pipes := make([]upstream.Pipe, 0, len(files)) + for _, file := range files { + if !file.IsDir() { + continue + } + + data, err := userUpstreamFile.read(file.Name()) + if err != nil { + continue + } + + host, port, mappedUser, err := parseUpstreamFile(string(data)) + + pipes = append(pipes, upstream.Pipe{ + Host: host, + Port: uint(port), + Username: file.Name(), + UpstreamUsername: mappedUser, + }) + } + + return pipes, nil +} + func (p *plugin) CreatePipe(opt upstream.CreatePipeOption) error { err := os.MkdirAll(config.WorkingDir+"/"+opt.Username, 0775) if err != nil { @@ -35,7 +65,7 @@ func (p *plugin) CreatePipe(opt upstream.CreatePipeOption) error { return err } - return fmt.Errorf("upstream file alreay exists") + return fmt.Errorf("upstream file of [%v] alreay exists", opt.Username) } func (p *plugin) RemovePipe(name string) error { diff --git a/sshpiperd/upstream/workingdir/workingdir.go b/sshpiperd/upstream/workingdir/workingdir.go index 4cb34340..40aaa075 100644 --- a/sshpiperd/upstream/workingdir/workingdir.go +++ b/sshpiperd/upstream/workingdir/workingdir.go @@ -14,6 +14,7 @@ import ( "os" "path" "regexp" + "strconv" "strings" "golang.org/x/crypto/ssh" @@ -83,43 +84,48 @@ func checkUsername(user string) bool { return usernameRule.MatchString(user) } -func parseUpstreamFile(data string) (string, string) { - - var user string - var line string - +func parseUpstreamFile(data string) (host string, port int, user string, err error) { r := bufio.NewReader(strings.NewReader(data)) - for { - var err error - line, err = r.ReadString('\n') + host, err = r.ReadString('\n') if err != nil { break } - line = strings.TrimSpace(line) + host = strings.TrimSpace(host) - if line != "" && line[0] != '#' { + if host != "" && host[0] != '#' { break } } - t := strings.SplitN(line, "@", 2) + t := strings.SplitN(host, "@", 2) if len(t) > 1 { user = t[0] - line = t[1] + host = t[1] } - // test if ok - if _, _, err := net.SplitHostPort(line); err != nil && line != "" { + h, p, err := net.SplitHostPort(host) + if err == nil { + host = h + port, err = strconv.Atoi(p) + + if err != nil { + return + } + } else if host != "" { // test valid after concat :22 - if _, _, err := net.SplitHostPort(line + ":22"); err == nil { - line += ":22" + if _, _, err := net.SplitHostPort(host + ":22"); err == nil { + port = 22 } } - return line, user + if host == "" { + err = fmt.Errorf("empty addr") + } + + return } func findUpstreamFromUserfile(conn ssh.ConnMetadata) (net.Conn, *ssh.AuthPipe, error) { @@ -143,11 +149,11 @@ func findUpstreamFromUserfile(conn ssh.ConnMetadata) (net.Conn, *ssh.AuthPipe, e return nil, nil, err } - addr, mappedUser := parseUpstreamFile(string(data)) - - if addr == "" { - return nil, nil, fmt.Errorf("empty addr") + host, port, mappedUser, err := parseUpstreamFile(string(data)) + if err != nil { + return nil, nil, err } + addr := fmt.Sprintf("%v:%v", host, port) logger.Printf("mapping user [%v] to [%v@%v]", user, mappedUser, addr) diff --git a/sshpiperd/upstream/workingdir/workingdir_test.go b/sshpiperd/upstream/workingdir/workingdir_test.go index f41416c7..f4625d4d 100644 --- a/sshpiperd/upstream/workingdir/workingdir_test.go +++ b/sshpiperd/upstream/workingdir/workingdir_test.go @@ -126,58 +126,74 @@ func (s stubConnMetadata) LocalAddr() net.Addr { return nil } func TestParseUpstreamFile(t *testing.T) { - var addr, user string + { - addr, user = parseUpstreamFile(` + addr, port, user, _ := parseUpstreamFile(` a:123 `) - if addr != "a:123" || user != "" { - t.Fatalf("parse failed common with port") + if addr != "a" || port != 123 || user != "" { + t.Fatalf("parse failed common with port") + } } - addr, user = parseUpstreamFile(` + { + + addr, port, user, _ := parseUpstreamFile(` a:123 b:456 `) - if addr != "a:123" || user != "" { - t.Fatalf("parse multi line") + if addr != "a" || port != 123 || user != "" { + t.Fatalf("parse multi line") + } } - addr, user = parseUpstreamFile(` + { + + addr, port, user, _ := parseUpstreamFile(` host `) - if addr != "host:22" || user != "" { - t.Fatalf("parse no port") + if addr != "host" || port != 22 || user != "" { + t.Fatalf("parse no port") + } } - addr, user = parseUpstreamFile(` + { + + addr, port, user, _ := parseUpstreamFile(` user@github.com `) - if addr != "github.com:22" || user != "user" { - t.Fatalf("parse no port with user") + if addr != "github.com" || port != 22 || user != "user" { + t.Fatalf("parse no port with user") + } } - addr, user = parseUpstreamFile(``) + { - if addr != "" || user != "" { - t.Fatalf("empty file") + _, _, _, err := parseUpstreamFile(``) + + if err == nil { + t.Fatalf("empty file") + } } - addr, user = parseUpstreamFile(` + { + + addr, port, user, _ := parseUpstreamFile(` # comment user@github.com test@linode.com `) - if addr != "github.com:22" || user != "user" { - t.Fatalf("multi line with comment") + if addr != "github.com" || port != 22 || user != "user" { + t.Fatalf("multi line with comment") + } } }