From ab747f279088c9ed6114c4227c71173ebd1e6f00 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sun, 16 Mar 2014 05:24:13 -0400 Subject: Fix delete SSH key in file --- models/publickey.go | 88 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 81 insertions(+), 7 deletions(-) (limited to 'models/publickey.go') diff --git a/models/publickey.go b/models/publickey.go index 49d7f308..2f32dc3f 100644 --- a/models/publickey.go +++ b/models/publickey.go @@ -1,21 +1,30 @@ +// 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. + package models import ( + "bufio" "fmt" + "io" "os" "os/exec" "path/filepath" + "strings" + "sync" "time" "github.com/Unknwon/com" ) var ( + sshOpLocker = sync.Mutex{} //publicKeyRootPath string - sshPath string - appPath string - tmplPublicKey = "### autogenerated by gitgos, DO NOT EDIT\n" + - "command=\"%s serv key-%d\",no-port-forwarding," + + sshPath string + appPath string + // "### autogenerated by gitgos, DO NOT EDIT\n" + tmplPublicKey = "command=\"%s serv key-%d\",no-port-forwarding," + "no-X11-forwarding,no-agent-forwarding,no-pty %s\n" ) @@ -77,9 +86,69 @@ func AddPublicKey(key *PublicKey) error { return nil } -func DeletePublicKey(key *PublicKey) error { - _, err := orm.Delete(key) - return err +// DeletePublicKey deletes SSH key information both in database and authorized_keys file. +func DeletePublicKey(key *PublicKey) (err error) { + if _, err = orm.Delete(key); err != nil { + return err + } + + sshOpLocker.Lock() + defer sshOpLocker.Unlock() + + p := filepath.Join(sshPath, "authorized_keys") + tmpP := filepath.Join(sshPath, "authorized_keys.tmp") + fr, err := os.Open(p) + if err != nil { + return err + } + defer fr.Close() + + fw, err := os.Create(tmpP) + if err != nil { + return err + } + defer fw.Close() + + buf := bufio.NewReader(fr) + for { + line, errRead := buf.ReadString('\n') + line = strings.TrimSpace(line) + + if errRead != nil { + if errRead != io.EOF { + return errRead + } + + // Reached end of file, if nothing to read then break, + // otherwise handle the last line. + if len(line) == 0 { + break + } + } + + // Found the line and copy rest of file. + if strings.Contains(line, key.Content) { + if _, err = io.Copy(fw, fr); err != nil { + return err + } + break + } + + // Still finding the line, copy the line that currently read. + if _, err = fw.WriteString(line + "\n"); err != nil { + return err + } + + if errRead == io.EOF { + break + } + } + + if err = os.Remove(p); err != nil { + return err + } + + return os.Rename(tmpP, p) } func ListPublicKey(userId int64) ([]PublicKey, error) { @@ -89,11 +158,16 @@ func ListPublicKey(userId int64) ([]PublicKey, error) { } func SaveAuthorizedKeyFile(key *PublicKey) error { + sshOpLocker.Lock() + defer sshOpLocker.Unlock() + p := filepath.Join(sshPath, "authorized_keys") f, err := os.OpenFile(p, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) if err != nil { return err } + defer f.Close() + //os.Chmod(p, 0600) _, err = f.WriteString(GenAuthorizedKey(key.Id, key.Content)) return err -- cgit v1.2.3 From bcafba47e8c384a13315d998eb1ba17e9aaf16f9 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sun, 16 Mar 2014 05:48:20 -0400 Subject: Bug fix --- models/publickey.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'models/publickey.go') diff --git a/models/publickey.go b/models/publickey.go index 2f32dc3f..3171e268 100644 --- a/models/publickey.go +++ b/models/publickey.go @@ -6,6 +6,7 @@ package models import ( "bufio" + "errors" "fmt" "io" "os" @@ -88,6 +89,12 @@ func AddPublicKey(key *PublicKey) error { // DeletePublicKey deletes SSH key information both in database and authorized_keys file. func DeletePublicKey(key *PublicKey) (err error) { + has, err := orm.Id(key.Id).Get(key) + if err != nil { + return err + } else if !has { + return errors.New("Public key does not exist") + } if _, err = orm.Delete(key); err != nil { return err } @@ -128,12 +135,8 @@ func DeletePublicKey(key *PublicKey) (err error) { // Found the line and copy rest of file. if strings.Contains(line, key.Content) { - if _, err = io.Copy(fw, fr); err != nil { - return err - } - break + continue } - // Still finding the line, copy the line that currently read. if _, err = fw.WriteString(line + "\n"); err != nil { return err -- cgit v1.2.3 From c83657307e4ba5d414389c0e012ecf789053f763 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sun, 16 Mar 2014 05:53:06 -0400 Subject: Fix delete SSH key in file --- models/publickey.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'models/publickey.go') diff --git a/models/publickey.go b/models/publickey.go index 3171e268..6aed7c57 100644 --- a/models/publickey.go +++ b/models/publickey.go @@ -134,7 +134,7 @@ func DeletePublicKey(key *PublicKey) (err error) { } // Found the line and copy rest of file. - if strings.Contains(line, key.Content) { + if strings.Contains(line, fmt.Sprintf("key-%d", key.Id)) && strings.Contains(line, key.Content) { continue } // Still finding the line, copy the line that currently read. -- cgit v1.2.3 From ca956d5cec34fd99d88494af3cafb214606fe27b Mon Sep 17 00:00:00 2001 From: Unknown Date: Sun, 16 Mar 2014 06:16:03 -0400 Subject: Add generate fingerprint of ssh key --- models/publickey.go | 46 +++++++++++++++++++++++++++++++------------ templates/user/publickey.tmpl | 2 +- 2 files changed, 34 insertions(+), 14 deletions(-) (limited to 'models/publickey.go') diff --git a/models/publickey.go b/models/publickey.go index 6aed7c57..bd0b7ee9 100644 --- a/models/publickey.go +++ b/models/publickey.go @@ -11,6 +11,7 @@ import ( "io" "os" "os/exec" + "path" "path/filepath" "strings" "sync" @@ -57,29 +58,48 @@ func init() { } type PublicKey struct { - Id int64 - OwnerId int64 `xorm:"index"` - Name string `xorm:"unique not null"` - Content string `xorm:"text not null"` - Created time.Time `xorm:"created"` - Updated time.Time `xorm:"updated"` + Id int64 + OwnerId int64 `xorm:"index"` + Name string `xorm:"unique not null"` + Fingerprint string + Content string `xorm:"text not null"` + Created time.Time `xorm:"created"` + Updated time.Time `xorm:"updated"` } func GenAuthorizedKey(keyId int64, key string) string { return fmt.Sprintf(tmplPublicKey, appPath, keyId, key) } -func AddPublicKey(key *PublicKey) error { - _, err := orm.Insert(key) +func AddPublicKey(key *PublicKey) (err error) { + // Calculate fingerprint. + tmpPath := filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()), + "id_rsa.pub") + os.MkdirAll(path.Dir(tmpPath), os.ModePerm) + f, err := os.Create(tmpPath) if err != nil { + return + } + if _, err = f.WriteString(key.Content); err != nil { return err } - - err = SaveAuthorizedKeyFile(key) + f.Close() + stdout, _, err := com.ExecCmd("ssh-keygen", "-l", "-f", tmpPath) if err != nil { - _, err2 := orm.Delete(key) - if err2 != nil { - // TODO: log the error + return err + } else if len(stdout) < 2 { + return errors.New("Not enough output for calculating fingerprint") + } + key.Fingerprint = strings.Split(stdout, " ")[1] + + // Save SSH key. + if _, err = orm.Insert(key); err != nil { + return err + } + + if err = SaveAuthorizedKeyFile(key); err != nil { + if _, err2 := orm.Delete(key); err2 != nil { + return err2 } return err } diff --git a/templates/user/publickey.tmpl b/templates/user/publickey.tmpl index 60d2c246..b671f63f 100644 --- a/templates/user/publickey.tmpl +++ b/templates/user/publickey.tmpl @@ -21,7 +21,7 @@
  • SSH Key's name
  • {{range .Keys}}
  • {{.Name}} - (print code) + ({{.Fingerprint}}) Delete
  • {{end}}
  • -- cgit v1.2.3 From fb960db6afa5fa84e60556f0c7d240b4af165a8d Mon Sep 17 00:00:00 2001 From: Unknown Date: Sun, 16 Mar 2014 06:25:16 -0400 Subject: Add check if public key name has been used --- models/publickey.go | 12 ++++++++++++ routers/user/setting.go | 4 ++++ 2 files changed, 16 insertions(+) (limited to 'models/publickey.go') diff --git a/models/publickey.go b/models/publickey.go index bd0b7ee9..ee6bd531 100644 --- a/models/publickey.go +++ b/models/publickey.go @@ -67,11 +67,23 @@ type PublicKey struct { Updated time.Time `xorm:"updated"` } +var ( + ErrKeyAlreadyExist = errors.New("Public key already exist") +) + func GenAuthorizedKey(keyId int64, key string) string { return fmt.Sprintf(tmplPublicKey, appPath, keyId, key) } func AddPublicKey(key *PublicKey) (err error) { + // Check if public key name has been used. + has, err := orm.Get(key) + if err != nil { + return err + } else if has { + return ErrKeyAlreadyExist + } + // Calculate fingerprint. tmpPath := filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()), "id_rsa.pub") diff --git a/routers/user/setting.go b/routers/user/setting.go index cd12bb62..91e992b1 100644 --- a/routers/user/setting.go +++ b/routers/user/setting.go @@ -128,6 +128,10 @@ func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) { } if err := models.AddPublicKey(k); err != nil { + if err.Error() == models.ErrKeyAlreadyExist.Error() { + ctx.RenderWithErr("Public key name has been used", "user/publickey", &form) + return + } ctx.Handle(200, "ssh.AddPublicKey", err) return } else { -- cgit v1.2.3