mirror of
https://github.com/thomiceli/opengist.git
synced 2024-12-23 04:52:40 +00:00
Merge pull request #22 from thomiceli/fix/ssh-keys
Fix SSH pubkey detection
This commit is contained in:
commit
0362cd8a6a
6 changed files with 21 additions and 28 deletions
|
@ -48,7 +48,7 @@ func GetSSHKeyByID(sshKeyId uint) (*SSHKey, error) {
|
||||||
return sshKey, err
|
return sshKey, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSSHKeyByContent(sshKeyContent string) (*SSHKey, error) {
|
func SSHKeyDoesExists(sshKeyContent string) (*SSHKey, error) {
|
||||||
sshKey := new(SSHKey)
|
sshKey := new(SSHKey)
|
||||||
err := db.
|
err := db.
|
||||||
Where("content like ?", sshKeyContent+"%").
|
Where("content like ?", sshKeyContent+"%").
|
||||||
|
@ -65,9 +65,9 @@ func (sshKey *SSHKey) Delete() error {
|
||||||
return db.Delete(&sshKey).Error
|
return db.Delete(&sshKey).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func SSHKeyLastUsedNow(sshKeyID uint) error {
|
func SSHKeyLastUsedNow(sshKeyContent string) error {
|
||||||
return db.Model(&SSHKey{}).
|
return db.Model(&SSHKey{}).
|
||||||
Where("id = ?", sshKeyID).
|
Where("content = ?", sshKeyContent).
|
||||||
Update("last_used_at", time.Now().Unix()).Error
|
Update("last_used_at", time.Now().Unix()).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,15 +81,14 @@ func GetUserById(userId uint) (*User, error) {
|
||||||
return user, err
|
return user, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUserBySSHKeyID(sshKeyId uint) (*User, error) {
|
func SSHKeyExistsForUser(sshKey string, userId uint) (*SSHKey, error) {
|
||||||
user := new(User)
|
key := new(SSHKey)
|
||||||
err := db.
|
err := db.
|
||||||
Preload("SSHKeys").
|
Where("content = ?", sshKey).
|
||||||
Joins("join ssh_keys on users.id = ssh_keys.user_id").
|
Where("user_id = ?", userId).
|
||||||
Where("ssh_keys.id = ?", sshKeyId).
|
First(&key).Error
|
||||||
First(&user).Error
|
|
||||||
|
|
||||||
return user, err
|
return key, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUserByProvider(id string, provider string) (*User, error) {
|
func GetUserByProvider(id string, provider string) (*User, error) {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func runGitCommand(ch ssh.Channel, gitCmd string, keyID uint, ip string) error {
|
func runGitCommand(ch ssh.Channel, gitCmd string, key string, ip string) error {
|
||||||
verb, args := parseCommand(gitCmd)
|
verb, args := parseCommand(gitCmd)
|
||||||
if !strings.HasPrefix(verb, "git-") {
|
if !strings.HasPrefix(verb, "git-") {
|
||||||
verb = ""
|
verb = ""
|
||||||
|
@ -43,7 +43,7 @@ func runGitCommand(ch ssh.Channel, gitCmd string, keyID uint, ip string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if verb == "receive-pack" || requireLogin == "1" {
|
if verb == "receive-pack" || requireLogin == "1" {
|
||||||
user, err := models.GetUserBySSHKeyID(keyID)
|
pubKey, err := models.SSHKeyExistsForUser(key, gist.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
log.Warn().Msg("Invalid SSH authentication attempt from " + ip)
|
log.Warn().Msg("Invalid SSH authentication attempt from " + ip)
|
||||||
|
@ -52,15 +52,9 @@ func runGitCommand(ch ssh.Channel, gitCmd string, keyID uint, ip string) error {
|
||||||
errorSsh("Failed to get user by SSH key id", err)
|
errorSsh("Failed to get user by SSH key id", err)
|
||||||
return errors.New("internal server error")
|
return errors.New("internal server error")
|
||||||
}
|
}
|
||||||
|
_ = models.SSHKeyLastUsedNow(pubKey.Content)
|
||||||
if user.ID != gist.UserID {
|
|
||||||
log.Warn().Msg("Invalid SSH authentication attempt from " + ip)
|
|
||||||
return errors.New("unauthorized")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = models.SSHKeyLastUsedNow(keyID)
|
|
||||||
|
|
||||||
repositoryPath := git.RepositoryPath(gist.User.Username, gist.Uuid)
|
repositoryPath := git.RepositoryPath(gist.User.Username, gist.Uuid)
|
||||||
|
|
||||||
cmd := exec.Command("git", verb, repositoryPath)
|
cmd := exec.Command("git", verb, repositoryPath)
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
@ -24,7 +23,8 @@ func Start() {
|
||||||
|
|
||||||
sshConfig := &ssh.ServerConfig{
|
sshConfig := &ssh.ServerConfig{
|
||||||
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
|
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
|
||||||
pkey, err := models.GetSSHKeyByContent(strings.TrimSpace(string(ssh.MarshalAuthorizedKey(key))))
|
strKey := strings.TrimSpace(string(ssh.MarshalAuthorizedKey(key)))
|
||||||
|
_, err := models.SSHKeyDoesExists(strKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -33,7 +33,7 @@ func Start() {
|
||||||
log.Warn().Msg("Invalid SSH authentication attempt from " + conn.RemoteAddr().String())
|
log.Warn().Msg("Invalid SSH authentication attempt from " + conn.RemoteAddr().String())
|
||||||
return nil, errors.New("unknown public key")
|
return nil, errors.New("unknown public key")
|
||||||
}
|
}
|
||||||
return &ssh.Permissions{Extensions: map[string]string{"key-id": strconv.Itoa(int(pkey.ID))}}, nil
|
return &ssh.Permissions{Extensions: map[string]string{"key": strKey}}, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,13 +71,12 @@ func listen(serverConfig *ssh.ServerConfig) {
|
||||||
}
|
}
|
||||||
|
|
||||||
go ssh.DiscardRequests(reqs)
|
go ssh.DiscardRequests(reqs)
|
||||||
keyID, _ := strconv.Atoi(sConn.Permissions.Extensions["key-id"])
|
go handleConnexion(channels, sConn.Permissions.Extensions["key"], sConn.RemoteAddr().String())
|
||||||
go handleConnexion(channels, uint(keyID), sConn.RemoteAddr().String())
|
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleConnexion(channels <-chan ssh.NewChannel, keyID uint, ip string) {
|
func handleConnexion(channels <-chan ssh.NewChannel, key string, ip string) {
|
||||||
for channel := range channels {
|
for channel := range channels {
|
||||||
if channel.ChannelType() != "session" {
|
if channel.ChannelType() != "session" {
|
||||||
_ = channel.Reject(ssh.UnknownChannelType, "Unknown channel type")
|
_ = channel.Reject(ssh.UnknownChannelType, "Unknown channel type")
|
||||||
|
@ -109,7 +108,7 @@ func handleConnexion(channels <-chan ssh.NewChannel, keyID uint, ip string) {
|
||||||
payloadCmd = payloadCmd[i:]
|
payloadCmd = payloadCmd[i:]
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = runGitCommand(ch, payloadCmd, keyID, ip); err != nil {
|
if err = runGitCommand(ch, payloadCmd, key, ip); err != nil {
|
||||||
_, _ = ch.Stderr().Write([]byte("Opengist: " + err.Error() + "\r\n"))
|
_, _ = ch.Stderr().Write([]byte("Opengist: " + err.Error() + "\r\n"))
|
||||||
}
|
}
|
||||||
_, _ = ch.SendRequest("exit-status", false, []byte{0, 0, 0, 0})
|
_, _ = ch.SendRequest("exit-status", false, []byte{0, 0, 0, 0})
|
||||||
|
|
|
@ -74,11 +74,12 @@ func sshKeysProcess(ctx echo.Context) error {
|
||||||
|
|
||||||
key.UserID = user.ID
|
key.UserID = user.ID
|
||||||
|
|
||||||
_, _, _, _, err := ssh.ParseAuthorizedKey([]byte(key.Content))
|
pubKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(key.Content))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
addFlash(ctx, "Invalid SSH key", "error")
|
addFlash(ctx, "Invalid SSH key", "error")
|
||||||
return redirect(ctx, "/settings")
|
return redirect(ctx, "/settings")
|
||||||
}
|
}
|
||||||
|
key.Content = strings.TrimSpace(string(ssh.MarshalAuthorizedKey(pubKey)))
|
||||||
|
|
||||||
if err := key.Create(); err != nil {
|
if err := key.Create(); err != nil {
|
||||||
return errorRes(500, "Cannot add SSH key", err)
|
return errorRes(500, "Cannot add SSH key", err)
|
||||||
|
|
2
templates/pages/settings.html
vendored
2
templates/pages/settings.html
vendored
|
@ -83,7 +83,7 @@
|
||||||
Add SSH Key
|
Add SSH Key
|
||||||
</h2>
|
</h2>
|
||||||
<h3 class="text-sm text-gray-400 italic mb-4">
|
<h3 class="text-sm text-gray-400 italic mb-4">
|
||||||
Used only to push gists using Git via SSH
|
Used only to pull/push gists using Git via SSH
|
||||||
</h3>
|
</h3>
|
||||||
<form class="space-y-6" action="/settings/ssh-keys" method="post">
|
<form class="space-y-6" action="/settings/ssh-keys" method="post">
|
||||||
<div>
|
<div>
|
||||||
|
|
Loading…
Reference in a new issue