From 18c841050b4c843ef723e788d4c0a4c29c67ffe3 Mon Sep 17 00:00:00 2001 From: Unknwon Date: Sun, 8 Nov 2015 16:59:56 -0500 Subject: fix 1540 and experimental SSH server support --- modules/ssh/ssh.go | 114 ++++++++++++++++++++++++++++++++----------------- modules/ssh/ssh_1.3.go | 7 +++ 2 files changed, 82 insertions(+), 39 deletions(-) create mode 100644 modules/ssh/ssh_1.3.go (limited to 'modules/ssh') diff --git a/modules/ssh/ssh.go b/modules/ssh/ssh.go index 557f08ff..5e3761ca 100644 --- a/modules/ssh/ssh.go +++ b/modules/ssh/ssh.go @@ -1,80 +1,110 @@ +// +build go1.4 + // Copyright 2014 The Gogs Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -// Prototype, git client looks like do not recognize req.Reply. package ssh import ( - "fmt" + "io" "io/ioutil" "net" "os" "os/exec" + "path/filepath" "strings" "github.com/Unknwon/com" + "golang.org/x/crypto/ssh" - "github.com/gogits/gogs/modules/crypto/ssh" + "github.com/gogits/gogs/models" "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/setting" ) -func handleServerConn(keyId string, chans <-chan ssh.NewChannel) { +func cleanCommand(cmd string) string { + i := strings.Index(cmd, "git") + if i == -1 { + return cmd + } + return cmd[i:] +} + +func handleServerConn(keyID string, chans <-chan ssh.NewChannel) { for newChan := range chans { if newChan.ChannelType() != "session" { newChan.Reject(ssh.UnknownChannelType, "unknown channel type") continue } - channel, requests, err := newChan.Accept() + + ch, reqs, err := newChan.Accept() if err != nil { - log.Error(3, "Could not accept channel: %v", err) + log.Error(3, "Error accepting channel: %v", err) continue } go func(in <-chan *ssh.Request) { - defer channel.Close() + defer ch.Close() for req := range in { - ok, payload := false, strings.TrimLeft(string(req.Payload), "\x00&") - fmt.Println("Request:", req.Type, req.WantReply, payload) - if req.WantReply { - fmt.Println(req.Reply(true, nil)) - } + payload := cleanCommand(string(req.Payload)) switch req.Type { case "env": args := strings.Split(strings.Replace(payload, "\x00", "", -1), "\v") if len(args) != 2 { - break + return } args[0] = strings.TrimLeft(args[0], "\x04") _, _, err := com.ExecCmdBytes("env", args[0]+"="+args[1]) if err != nil { log.Error(3, "env: %v", err) - channel.Stderr().Write([]byte(err.Error())) - break + return } - ok = true case "exec": - os.Setenv("SSH_ORIGINAL_COMMAND", strings.TrimLeft(payload, "'(")) - log.Info("Payload: %v", strings.TrimLeft(payload, "'(")) - cmd := exec.Command("/Users/jiahuachen/Applications/Go/src/github.com/gogits/gogs/gogs", "serv", "key-"+keyId) - cmd.Stdout = channel - cmd.Stdin = channel - cmd.Stderr = channel.Stderr() - if err := cmd.Run(); err != nil { - log.Error(3, "exec: %v", err) - } else { - ok = true + cmdName := strings.TrimLeft(payload, "'()") + os.Setenv("SSH_ORIGINAL_COMMAND", cmdName) + log.Trace("Payload: %v", cmdName) + cmd := exec.Command(setting.AppPath, "serv", "key-"+keyID) + + stdout, err := cmd.StdoutPipe() + if err != nil { + log.Error(3, "StdoutPipe: %v", err) + return + } + stderr, err := cmd.StderrPipe() + if err != nil { + log.Error(3, "StderrPipe: %v", err) + return + } + input, err := cmd.StdinPipe() + if err != nil { + log.Error(3, "StdinPipe: %v", err) + return } + + go io.Copy(ch, stdout) + go io.Copy(ch.Stderr(), stderr) + go io.Copy(input, ch) + + if err = cmd.Start(); err != nil { + log.Error(3, "Start: %v", err) + return + } else if err = cmd.Wait(); err != nil { + log.Error(3, "Wait: %v", err) + return + } + + ch.SendRequest("exit-status", false, []byte{0, 0, 0, 0}) + return + default: } - fmt.Println("Done:", ok) } - fmt.Println("Done!!!") - }(requests) + }(reqs) } } -func listen(config *ssh.ServerConfig, port string) { - listener, err := net.Listen("tcp", "0.0.0.0:"+port) +func listen(config *ssh.ServerConfig, port int) { + listener, err := net.Listen("tcp", "0.0.0.0:"+com.ToStr(port)) if err != nil { panic(err) } @@ -82,15 +112,17 @@ func listen(config *ssh.ServerConfig, port string) { // Once a ServerConfig has been configured, connections can be accepted. conn, err := listener.Accept() if err != nil { - log.Error(3, "Fail to accept incoming connection: %v", err) + log.Error(3, "Error accepting incoming connection: %v", err) continue } // Before use, a handshake must be performed on the incoming net.Conn. sConn, chans, reqs, err := ssh.NewServerConn(conn, config) if err != nil { - log.Error(3, "Fail to handshake: %v", err) + log.Error(3, "Error on handshaking: %v", err) continue } + + log.Trace("Connection from %s (%s)", sConn.RemoteAddr(), sConn.ClientVersion()) // The incoming Request channel must be serviced. go ssh.DiscardRequests(reqs) go handleServerConn(sConn.Permissions.Extensions["key-id"], chans) @@ -98,21 +130,25 @@ func listen(config *ssh.ServerConfig, port string) { } // Listen starts a SSH server listens on given port. -func Listen(port string) { +func Listen(port int) { config := &ssh.ServerConfig{ PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { - // keyCache[string(ssh.MarshalAuthorizedKey(key))] = 2 - return &ssh.Permissions{Extensions: map[string]string{"key-id": "1"}}, nil + pkey, err := models.SearchPublicKeyByContent(strings.TrimSpace(string(ssh.MarshalAuthorizedKey(key)))) + if err != nil { + log.Error(3, "SearchPublicKeyByContent: %v", err) + return nil, err + } + return &ssh.Permissions{Extensions: map[string]string{"key-id": com.ToStr(pkey.ID)}}, nil }, } - privateBytes, err := ioutil.ReadFile("/Users/jiahuachen/.ssh/id_rsa") + privateBytes, err := ioutil.ReadFile(filepath.Join(models.SSHPath, "id_rsa")) if err != nil { - panic("failed to load private key") + panic("Fail to load private key") } private, err := ssh.ParsePrivateKey(privateBytes) if err != nil { - panic("failed to parse private key") + panic("Fail to parse private key") } config.AddHostKey(private) diff --git a/modules/ssh/ssh_1.3.go b/modules/ssh/ssh_1.3.go new file mode 100644 index 00000000..62275ee6 --- /dev/null +++ b/modules/ssh/ssh_1.3.go @@ -0,0 +1,7 @@ +// +build !go1.4 + +package ssh + +func Listen(port int) { + panic("Gogs requires Go 1.4 for starting a SSH server") +} -- cgit v1.2.3 From 7c80eba77f727c2b80b4091c850dc38d47532b8d Mon Sep 17 00:00:00 2001 From: Unknwon Date: Sat, 14 Nov 2015 13:21:31 -0500 Subject: minor UI fix and fix ssh race --- README.md | 2 +- cmd/web.go | 3 ++- gogs.go | 2 +- modules/ssh/ssh.go | 24 ++++++++++++++++++------ routers/repo/commit.go | 3 +++ templates/.VERSION | 2 +- templates/repo/commits.tmpl | 1 + templates/repo/settings/deploy_keys.tmpl | 1 + templates/repo/settings/githook_edit.tmpl | 1 + templates/repo/settings/githooks.tmpl | 1 + templates/repo/settings/hook_new.tmpl | 1 + templates/repo/settings/hooks.tmpl | 1 + templates/repo/settings/options.tmpl | 1 + 13 files changed, 33 insertions(+), 10 deletions(-) (limited to 'modules/ssh') diff --git a/README.md b/README.md index 03cb070e..02e624c0 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?bra ![](public/img/gogs-large-resize.png) -##### Current version: 0.7.9 Beta +##### Current version: 0.7.10 Beta diff --git a/cmd/web.go b/cmd/web.go index e51b1bb9..950c3d48 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -87,6 +87,7 @@ func checkVersion() { {"github.com/go-macaron/csrf", csrf.Version, "0.0.3"}, {"github.com/go-macaron/i18n", i18n.Version, "0.0.7"}, {"github.com/go-macaron/session", session.Version, "0.1.6"}, + {"github.com/go-macaron/toolbox", toolbox.Version, "0.1.0"}, {"gopkg.in/ini.v1", ini.Version, "1.3.4"}, } for _, c := range checkers { @@ -463,7 +464,7 @@ func runWeb(ctx *cli.Context) { }) }) - }, reqSignIn, middleware.RepoAssignment(true), reqRepoAdmin) + }, reqSignIn, middleware.RepoAssignment(true), reqRepoAdmin, middleware.RepoRef()) m.Group("/:username/:reponame", func() { m.Get("/action/:action", repo.Action) diff --git a/gogs.go b/gogs.go index 37259d36..95b8e931 100644 --- a/gogs.go +++ b/gogs.go @@ -17,7 +17,7 @@ import ( "github.com/gogits/gogs/modules/setting" ) -const APP_VER = "0.7.9.1114 Beta" +const APP_VER = "0.7.10.1114 Beta" func init() { runtime.GOMAXPROCS(runtime.NumCPU()) diff --git a/modules/ssh/ssh.go b/modules/ssh/ssh.go index 5e3761ca..706f5e75 100644 --- a/modules/ssh/ssh.go +++ b/modules/ssh/ssh.go @@ -7,6 +7,7 @@ package ssh import ( + "fmt" "io" "io/ioutil" "net" @@ -82,14 +83,16 @@ func handleServerConn(keyID string, chans <-chan ssh.NewChannel) { return } - go io.Copy(ch, stdout) - go io.Copy(ch.Stderr(), stderr) - go io.Copy(input, ch) - if err = cmd.Start(); err != nil { log.Error(3, "Start: %v", err) return - } else if err = cmd.Wait(); err != nil { + } + + go io.Copy(input, ch) + io.Copy(ch, stdout) + io.Copy(ch.Stderr(), stderr) + + if err = cmd.Wait(); err != nil { log.Error(3, "Wait: %v", err) return } @@ -142,7 +145,16 @@ func Listen(port int) { }, } - privateBytes, err := ioutil.ReadFile(filepath.Join(models.SSHPath, "id_rsa")) + keyPath := filepath.Join(setting.AppDataPath, "ssh/gogs.rsa") + if !com.IsExist(keyPath) { + os.MkdirAll(filepath.Dir(keyPath), os.ModePerm) + _, stderr, err := com.ExecCmd("ssh-keygen", "-f", keyPath, "-t", "rsa", "-N", "") + if err != nil { + panic(fmt.Sprintf("Fail to generate private key: %v - %s", err, stderr)) + } + } + + privateBytes, err := ioutil.ReadFile(keyPath) if err != nil { panic("Fail to load private key") } diff --git a/routers/repo/commit.go b/routers/repo/commit.go index 101cb5c5..0c9e7817 100644 --- a/routers/repo/commit.go +++ b/routers/repo/commit.go @@ -17,6 +17,8 @@ import ( "github.com/gogits/gogs/modules/setting" ) +import "github.com/davecheney/profile" + const ( COMMITS base.TplName = "repo/commits" DIFF base.TplName = "repo/diff" @@ -43,6 +45,7 @@ func RenderIssueLinks(oldCommits *list.List, repoLink string) *list.List { } func Commits(ctx *middleware.Context) { + defer profile.Start(profile.CPUProfile).Stop() ctx.Data["PageIsCommits"] = true commitsCount, err := ctx.Repo.Commit.CommitsCount() diff --git a/templates/.VERSION b/templates/.VERSION index 548d9a0e..32d6c06d 100644 --- a/templates/.VERSION +++ b/templates/.VERSION @@ -1 +1 @@ -0.7.9.1114 Beta \ No newline at end of file +0.7.10.1114 Beta \ No newline at end of file diff --git a/templates/repo/commits.tmpl b/templates/repo/commits.tmpl index e54c9ed7..769841de 100644 --- a/templates/repo/commits.tmpl +++ b/templates/repo/commits.tmpl @@ -2,6 +2,7 @@
{{template "repo/header" .}}
+ {{template "repo/sidebar" .}} {{template "repo/commits_table" .}}
diff --git a/templates/repo/settings/deploy_keys.tmpl b/templates/repo/settings/deploy_keys.tmpl index 0574e9d8..5a695838 100644 --- a/templates/repo/settings/deploy_keys.tmpl +++ b/templates/repo/settings/deploy_keys.tmpl @@ -2,6 +2,7 @@
{{template "repo/header" .}}
+ {{template "repo/sidebar" .}}
{{template "repo/settings/navbar" .}}
diff --git a/templates/repo/settings/githook_edit.tmpl b/templates/repo/settings/githook_edit.tmpl index b9b75a3a..2f79481a 100644 --- a/templates/repo/settings/githook_edit.tmpl +++ b/templates/repo/settings/githook_edit.tmpl @@ -2,6 +2,7 @@
{{template "repo/header" .}}
+ {{template "repo/sidebar" .}}
{{template "repo/settings/navbar" .}}
diff --git a/templates/repo/settings/githooks.tmpl b/templates/repo/settings/githooks.tmpl index 8120b80e..980b98fd 100644 --- a/templates/repo/settings/githooks.tmpl +++ b/templates/repo/settings/githooks.tmpl @@ -2,6 +2,7 @@
{{template "repo/header" .}}
+ {{template "repo/sidebar" .}}
{{template "repo/settings/navbar" .}}
diff --git a/templates/repo/settings/hook_new.tmpl b/templates/repo/settings/hook_new.tmpl index 7c9a5de1..ac69b02f 100644 --- a/templates/repo/settings/hook_new.tmpl +++ b/templates/repo/settings/hook_new.tmpl @@ -2,6 +2,7 @@
{{template "repo/header" .}}
+ {{template "repo/sidebar" .}}
{{template "repo/settings/navbar" .}}
diff --git a/templates/repo/settings/hooks.tmpl b/templates/repo/settings/hooks.tmpl index e3f6f4dd..187bd563 100644 --- a/templates/repo/settings/hooks.tmpl +++ b/templates/repo/settings/hooks.tmpl @@ -2,6 +2,7 @@
{{template "repo/header" .}}
+ {{template "repo/sidebar" .}}
{{template "repo/settings/navbar" .}} {{template "repo/settings/hook_list" .}} diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 474d719e..e109ec11 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -2,6 +2,7 @@
{{template "repo/header" .}}
+ {{template "repo/sidebar" .}}
{{template "repo/settings/navbar" .}}
-- cgit v1.2.3 From e030109b5af9015c018cdc6f18655e201f6008bf Mon Sep 17 00:00:00 2001 From: Unknwon Date: Sun, 15 Nov 2015 17:07:44 -0500 Subject: fix api broken --- cmd/cert.go | 12 ++++++------ cmd/cmd.go | 42 ++++++++++++++++++++++++++++++++++++++++++ cmd/dump.go | 4 ++-- cmd/serve.go | 2 +- cmd/update.go | 2 +- cmd/web.go | 4 ++-- models/action.go | 4 ++++ modules/ssh/ssh.go | 1 + 8 files changed, 59 insertions(+), 12 deletions(-) create mode 100644 cmd/cmd.go (limited to 'modules/ssh') diff --git a/cmd/cert.go b/cmd/cert.go index 5b182da9..7b68f330 100644 --- a/cmd/cert.go +++ b/cmd/cert.go @@ -32,12 +32,12 @@ var CmdCert = cli.Command{ Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`, Action: runCert, Flags: []cli.Flag{ - cli.StringFlag{"host", "", "Comma-separated hostnames and IPs to generate a certificate for", ""}, - cli.StringFlag{"ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521", ""}, - cli.IntFlag{"rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set", ""}, - cli.StringFlag{"start-date", "", "Creation date formatted as Jan 1 15:04:05 2011", ""}, - cli.DurationFlag{"duration", 365 * 24 * time.Hour, "Duration that certificate is valid for", ""}, - cli.BoolFlag{"ca", "whether this cert should be its own Certificate Authority", ""}, + stringFlag("host", "", "Comma-separated hostnames and IPs to generate a certificate for"), + stringFlag("ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521"), + intFlag("rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set"), + stringFlag("start-date", "", "Creation date formatted as Jan 1 15:04:05 2011"), + durationFlag("duration", 365*24*time.Hour, "Duration that certificate is valid for"), + boolFlag("ca", "whether this cert should be its own Certificate Authority"), }, } diff --git a/cmd/cmd.go b/cmd/cmd.go new file mode 100644 index 00000000..8df02d5c --- /dev/null +++ b/cmd/cmd.go @@ -0,0 +1,42 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package cmd + +import ( + "time" + + "github.com/codegangsta/cli" +) + +func stringFlag(name, value, usage string) cli.StringFlag { + return cli.StringFlag{ + Name: name, + Value: value, + Usage: usage, + } +} + +func boolFlag(name, usage string) cli.BoolFlag { + return cli.BoolFlag{ + Name: name, + Usage: usage, + } +} + +func intFlag(name string, value int, usage string) cli.IntFlag { + return cli.IntFlag{ + Name: name, + Value: value, + Usage: usage, + } +} + +func durationFlag(name string, value time.Duration, usage string) cli.DurationFlag { + return cli.DurationFlag{ + Name: name, + Value: value, + Usage: usage, + } +} diff --git a/cmd/dump.go b/cmd/dump.go index 44b180c3..0bf385d0 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -25,8 +25,8 @@ var CmdDump = cli.Command{ It can be used for backup and capture Gogs server image to send to maintainer`, Action: runDump, Flags: []cli.Flag{ - cli.StringFlag{"config, c", "custom/conf/app.ini", "Custom configuration file path", ""}, - cli.BoolFlag{"verbose, v", "show process details", ""}, + stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"), + boolFlag("verbose, v", "show process details"), }, } diff --git a/cmd/serve.go b/cmd/serve.go index b5713752..b6ab9bb8 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -33,7 +33,7 @@ var CmdServ = cli.Command{ Description: `Serv provide access auth for repositories`, Action: runServ, Flags: []cli.Flag{ - cli.StringFlag{"config, c", "custom/conf/app.ini", "Custom configuration file path", ""}, + stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"), }, } diff --git a/cmd/update.go b/cmd/update.go index 289aedbf..4cd62a7f 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -20,7 +20,7 @@ var CmdUpdate = cli.Command{ Description: `Update get pushed info and insert into database`, Action: runUpdate, Flags: []cli.Flag{ - cli.StringFlag{"config, c", "custom/conf/app.ini", "Custom configuration file path", ""}, + stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"), }, } diff --git a/cmd/web.go b/cmd/web.go index 950c3d48..dabea0ba 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -56,8 +56,8 @@ var CmdWeb = cli.Command{ and it takes care of all the other things for you`, Action: runWeb, Flags: []cli.Flag{ - cli.StringFlag{"port, p", "3000", "Temporary port number to prevent conflict", ""}, - cli.StringFlag{"config, c", "custom/conf/app.ini", "Custom configuration file path", ""}, + stringFlag("port, p", "3000", "Temporary port number to prevent conflict"), + stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"), }, } diff --git a/models/action.go b/models/action.go index bb15d4a3..8dd80074 100644 --- a/models/action.go +++ b/models/action.go @@ -418,6 +418,10 @@ func CommitRepoAction( isNewBranch = true } + // NOTE: limit to detect latest 100 commits. + if len(commit.Commits) > 100 { + commit.Commits = commit.Commits[len(commit.Commits)-100:] + } if err = updateIssuesCommit(u, repo, repoUserName, repoName, commit.Commits); err != nil { log.Error(4, "updateIssuesCommit: %v", err) } diff --git a/modules/ssh/ssh.go b/modules/ssh/ssh.go index 706f5e75..fec43b79 100644 --- a/modules/ssh/ssh.go +++ b/modules/ssh/ssh.go @@ -83,6 +83,7 @@ func handleServerConn(keyID string, chans <-chan ssh.NewChannel) { return } + // FIXME: check timeout if err = cmd.Start(); err != nil { log.Error(3, "Start: %v", err) return -- cgit v1.2.3