|
|
|
@ -5,12 +5,10 @@
|
|
|
|
|
package models
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bufio"
|
|
|
|
|
"encoding/base64"
|
|
|
|
|
"encoding/binary"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"io/ioutil"
|
|
|
|
|
"math/big"
|
|
|
|
|
"os"
|
|
|
|
@ -24,6 +22,7 @@ import (
|
|
|
|
|
"github.com/go-xorm/xorm"
|
|
|
|
|
"golang.org/x/crypto/ssh"
|
|
|
|
|
|
|
|
|
|
"github.com/gogits/gogs/modules/base"
|
|
|
|
|
"github.com/gogits/gogs/modules/log"
|
|
|
|
|
"github.com/gogits/gogs/modules/process"
|
|
|
|
|
"github.com/gogits/gogs/modules/setting"
|
|
|
|
@ -457,96 +456,20 @@ func ListPublicKeys(uid int64) ([]*PublicKey, error) {
|
|
|
|
|
return keys, x.Where("owner_id = ?", uid).Find(&keys)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// rewriteAuthorizedKeys finds and deletes corresponding line in authorized_keys file.
|
|
|
|
|
func rewriteAuthorizedKeys(key *PublicKey, p, tmpP string) error {
|
|
|
|
|
fr, err := os.Open(p)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
defer fr.Close()
|
|
|
|
|
|
|
|
|
|
fw, err := os.OpenFile(tmpP, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
defer fw.Close()
|
|
|
|
|
|
|
|
|
|
isFound := false
|
|
|
|
|
keyword := fmt.Sprintf("key-%d", key.ID)
|
|
|
|
|
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 !isFound && strings.Contains(line, keyword) && strings.Contains(line, key.Content) {
|
|
|
|
|
isFound = true
|
|
|
|
|
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 !isFound {
|
|
|
|
|
log.Warn("SSH key %d not found in authorized_keys file for deletion", key.ID)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UpdatePublicKey updates given public key.
|
|
|
|
|
func UpdatePublicKey(key *PublicKey) error {
|
|
|
|
|
_, err := x.Id(key.ID).AllCols().Update(key)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func deletePublicKey(e *xorm.Session, keyID int64) error {
|
|
|
|
|
sshOpLocker.Lock()
|
|
|
|
|
defer sshOpLocker.Unlock()
|
|
|
|
|
|
|
|
|
|
key := &PublicKey{ID: keyID}
|
|
|
|
|
has, err := e.Get(key)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
} else if !has {
|
|
|
|
|
// deletePublicKeys does the actual key deletion but does not update authorized_keys file.
|
|
|
|
|
func deletePublicKeys(e *xorm.Session, keyIDs ...int64) error {
|
|
|
|
|
if len(keyIDs) == 0 {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if _, err = e.Id(key.ID).Delete(new(PublicKey)); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Don't need to rewrite this file if builtin SSH server is enabled.
|
|
|
|
|
if setting.SSH.StartBuiltinServer {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fpath := filepath.Join(setting.SSH.RootPath, "authorized_keys")
|
|
|
|
|
tmpPath := fpath + ".tmp"
|
|
|
|
|
if err = rewriteAuthorizedKeys(key, fpath, tmpPath); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
} else if err = os.Remove(fpath); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return os.Rename(tmpPath, fpath)
|
|
|
|
|
_, err := e.In("id", strings.Join(base.Int64sToStrings(keyIDs), ",")).Delete(new(PublicKey))
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DeletePublicKey deletes SSH key information both in database and authorized_keys file.
|
|
|
|
@ -570,14 +493,20 @@ func DeletePublicKey(doer *User, id int64) (err error) {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err = deletePublicKey(sess, id); err != nil {
|
|
|
|
|
if err = deletePublicKeys(sess, id); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sess.Commit()
|
|
|
|
|
if err = sess.Commit(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return RewriteAllPublicKeys()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// RewriteAllPublicKeys removes any authorized key and rewrite all keys from database again.
|
|
|
|
|
// Note: x.Iterate does not get latest data after insert/delete, so we have to call this function
|
|
|
|
|
// outsite any session scope independently.
|
|
|
|
|
func RewriteAllPublicKeys() error {
|
|
|
|
|
sshOpLocker.Lock()
|
|
|
|
|
defer sshOpLocker.Unlock()
|
|
|
|
@ -814,7 +743,7 @@ func DeleteDeployKey(doer *User, id int64) error {
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
} else if !has {
|
|
|
|
|
if err = deletePublicKey(sess, key.KeyID); err != nil {
|
|
|
|
|
if err = deletePublicKeys(sess, key.KeyID); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|