diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2014-03-16 22:32:50 +0800 |
---|---|---|
committer | Lunny Xiao <xiaolunwen@gmail.com> | 2014-03-16 22:32:50 +0800 |
commit | f824d6a4b11d4d8ddc82d54c5183934b465afbd3 (patch) | |
tree | 3586b1746fd2097834685e0ee589de7b1a0c10b0 /models | |
parent | f620f23c35f76a97f945f210638d4be8920e189e (diff) | |
parent | 9557cfc6534d2a215f6c6da73468aea1e3edd61f (diff) | |
download | gitea-f824d6a4b11d4d8ddc82d54c5183934b465afbd3.tar.gz gitea-f824d6a4b11d4d8ddc82d54c5183934b465afbd3.zip |
Merge branch 'master' of github.com:gogits/gogs
Diffstat (limited to 'models')
-rw-r--r-- | models/action.go | 4 | ||||
-rw-r--r-- | models/publickey.go | 147 | ||||
-rw-r--r-- | models/repo.go | 2 | ||||
-rw-r--r-- | models/user.go | 29 |
4 files changed, 158 insertions, 24 deletions
diff --git a/models/action.go b/models/action.go index 93c1e2768f..9e075646a6 100644 --- a/models/action.go +++ b/models/action.go @@ -43,6 +43,7 @@ func (a Action) GetRepoName() string { return a.RepoName } +// CommitRepoAction records action for commit repository. func CommitRepoAction(userId int64, userName string, repoId int64, repoName string, msg string) error { _, err := orm.InsertOne(&Action{ @@ -57,8 +58,7 @@ func CommitRepoAction(userId int64, userName string, return err } -// NewRepoAction inserts action for create repository. - +// NewRepoAction records action for create repository. func NewRepoAction(user *User, repo *Repository) error { _, err := orm.InsertOne(&Action{ UserId: user.Id, diff --git a/models/publickey.go b/models/publickey.go index 49d7f30828..ee6bd53101 100644 --- a/models/publickey.go +++ b/models/publickey.go @@ -1,21 +1,32 @@ +// 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" + "errors" "fmt" + "io" "os" "os/exec" + "path" "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" ) @@ -47,29 +58,60 @@ 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"` } +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) error { - _, err := orm.Insert(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 } - err = SaveAuthorizedKeyFile(key) + // 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 + } + 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 } @@ -77,9 +119,71 @@ 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) { + 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 + } + + 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, fmt.Sprintf("key-%d", key.Id)) && strings.Contains(line, key.Content) { + continue + } + // 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 +193,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 diff --git a/models/repo.go b/models/repo.go index 3d6255a356..cfca3583f8 100644 --- a/models/repo.go +++ b/models/repo.go @@ -264,7 +264,7 @@ func GetRepositoryById(id int64) (repo *Repository, err error) { // GetRepositories returns the list of repositories of given user. func GetRepositories(user *User) ([]Repository, error) { repos := make([]Repository, 0, 10) - err := orm.Find(&repos, &Repository{OwnerId: user.Id}) + err := orm.Desc("updated").Find(&repos, &Repository{OwnerId: user.Id}) return repos, err } diff --git a/models/user.go b/models/user.go index a0e4bb8004..4b5a110915 100644 --- a/models/user.go +++ b/models/user.go @@ -142,6 +142,7 @@ func UpdateUser(user *User) (err error) { // DeleteUser completely deletes everything of the user. func DeleteUser(user *User) error { + // Check ownership of repository. count, err := GetRepositoryCount(user) if err != nil { return errors.New("modesl.GetRepositories: " + err.Error()) @@ -151,6 +152,22 @@ func DeleteUser(user *User) error { // TODO: check issues, other repos' commits + // Delete all feeds. + if _, err = orm.Delete(&Action{UserId: user.Id}); err != nil { + return err + } + + // Delete all SSH keys. + keys := make([]PublicKey, 0, 10) + if err = orm.Find(&keys, &PublicKey{OwnerId: user.Id}); err != nil { + return err + } + for _, key := range keys { + if err = DeletePublicKey(&key); err != nil { + return err + } + } + _, err = orm.Delete(user) // TODO: delete and update follower information. return err @@ -158,8 +175,8 @@ func DeleteUser(user *User) error { // EncodePasswd encodes password to safe format. func (user *User) EncodePasswd() error { - newPasswd, err := scrypt.Key([]byte(user.Passwd), []byte(UserPasswdSalt), 16384, 8, 1, 64) - user.Passwd = fmt.Sprintf("%x", newPasswd) + var err error + user.Passwd, err = EncodePasswd(user.Passwd) return err } @@ -167,6 +184,14 @@ func UserPath(userName string) string { return filepath.Join(RepoRootPath, userName) } +func EncodePasswd(rawPasswd string) (string, error) { + newPasswd, err := scrypt.Key([]byte(rawPasswd), []byte(UserPasswdSalt), 16384, 8, 1, 64) + if err != nil { + return "", err + } + return fmt.Sprintf("%x", newPasswd), nil +} + func GetUserByKeyId(keyId int64) (*User, error) { user := new(User) has, err := orm.Sql("select a.* from user as a, public_key as b where a.id = b.owner_id and b.id=?", keyId).Get(user) |