Hi… I am well aware that this diff view is very suboptimal. It will be fixed when the refactored server comes along!
{ssh_*,acl}.go: Check ACL when receiving packs
package main
import (
"context"
)
func get_path_perm_by_group_repo_key(ctx context.Context, group_name, repo_name, ssh_pubkey string) (filesystem_path string, access bool, err error) {
err = database.QueryRow(ctx,
`SELECT
r.filesystem_path,
CASE
WHEN ugr.user_id IS NOT NULL THEN TRUE
ELSE FALSE
END AS has_role_in_group
FROM
groups g
JOIN
repos r ON r.group_id = g.id
LEFT JOIN
ssh_public_keys s ON s.key_string = $3
LEFT JOIN
users u ON u.id = s.user_id
LEFT JOIN
user_group_roles ugr ON ugr.group_id = g.id AND ugr.user_id = u.id
WHERE
g.name = $1
AND r.name = $2;`,
group_name, repo_name, ssh_pubkey,
).Scan(&filesystem_path, &access)
return
}
package main import (
"errors"
glider_ssh "github.com/gliderlabs/ssh" "github.com/go-git/go-billy/v5/osfs" "github.com/go-git/go-git/v5/plumbing/protocol/packp" "github.com/go-git/go-git/v5/plumbing/transport" transport_server "github.com/go-git/go-git/v5/plumbing/transport/server" )
var err_unauthorized_push = errors.New("You are not authorized to push to this repository")
func ssh_handle_receive_pack(session glider_ssh.Session, pubkey string, repo_identifier string) (err error) {
repo_path, err := get_repo_path_from_ssh_path(session.Context(), repo_identifier)
repo_path, access, err := get_repo_path_perms_from_ssh_path_pubkey(session.Context(), repo_identifier, pubkey)
if err != nil {
return err
}
if !access {
return err_unauthorized_push
}
endpoint, err := transport.NewEndpoint("/")
if err != nil {
return err
}
billy_fs := osfs.New(repo_path)
fs_loader := transport_server.NewFilesystemLoader(billy_fs)
transport := transport_server.NewServer(fs_loader)
receive_pack_session, err := transport.NewReceivePackSession(endpoint, nil)
if err != nil {
return err
}
advertised_references, err := receive_pack_session.AdvertisedReferencesContext(session.Context())
if err != nil {
return err
}
err = advertised_references.Encode(session)
if err != nil {
return err
}
reference_update_request := packp.NewReferenceUpdateRequest()
err = reference_update_request.Decode(session)
if err != nil {
return err
}
report_status, err := receive_pack_session.ReceivePack(session.Context(), reference_update_request)
if err != nil {
return err
}
err = report_status.Encode(session)
if err != nil {
return err
}
return nil
}
package main
import (
glider_ssh "github.com/gliderlabs/ssh"
"github.com/go-git/go-billy/v5/osfs"
"github.com/go-git/go-git/v5/plumbing/protocol/packp"
"github.com/go-git/go-git/v5/plumbing/transport"
"github.com/go-git/go-git/v5/plumbing/transport/server"
)
func ssh_handle_upload_pack(session glider_ssh.Session, pubkey string, repo_identifier string) (err error) {
repo_path, err := get_repo_path_from_ssh_path(session.Context(), repo_identifier)
repo_path, _, err := get_repo_path_perms_from_ssh_path_pubkey(session.Context(), repo_identifier, pubkey)
if err != nil {
return err
}
endpoint, err := transport.NewEndpoint("/")
if err != nil {
return err
}
billy_fs := osfs.New(repo_path)
fs_loader := server.NewFilesystemLoader(billy_fs)
transport := server.NewServer(fs_loader)
upload_pack_session, err := transport.NewUploadPackSession(endpoint, nil)
if err != nil {
return err
}
advertised_references, err := upload_pack_session.AdvertisedReferencesContext(session.Context())
if err != nil {
return err
}
err = advertised_references.Encode(session)
if err != nil {
return err
}
reference_update_request := packp.NewUploadPackRequest()
err = reference_update_request.Decode(session)
if err != nil {
return err
}
report_status, err := upload_pack_session.UploadPack(session.Context(), reference_update_request)
if err != nil {
return err
}
err = report_status.Encode(session)
if err != nil {
return err
}
return nil
}
package main
import (
"context"
"errors"
"net/url"
"strings"
)
var err_ssh_illegal_endpoint = errors.New("Illegal endpoint during SSH access")
func get_repo_path_from_ssh_path(ctx context.Context, ssh_path string) (repo_path string, err error) {
func get_repo_path_perms_from_ssh_path_pubkey(ctx context.Context, ssh_path string, ssh_pubkey string) (repo_path string, access bool, err error) {
segments := strings.Split(strings.TrimPrefix(ssh_path, "/"), "/")
for i, segment := range segments {
var err error
segments[i], err = url.PathUnescape(segment)
if err != nil {
return "", err
return "", false, err
}
}
if segments[0] == ":" {
return "", err_ssh_illegal_endpoint
return "", false, err_ssh_illegal_endpoint
}
separator_index := -1
for i, part := range segments {
if part == ":" {
separator_index = i
break
}
}
if segments[len(segments)-1] == "" {
segments = segments[:len(segments)-1]
}
switch {
case separator_index == -1:
return "", err_ssh_illegal_endpoint
return "", false, err_ssh_illegal_endpoint
case len(segments) <= separator_index+2:
return "", err_ssh_illegal_endpoint
return "", false, err_ssh_illegal_endpoint
}
group_name := segments[0]
module_type := segments[separator_index+1]
module_name := segments[separator_index+2]
switch module_type {
case "repos":
var fs_path string err := database.QueryRow(ctx, "SELECT r.filesystem_path FROM repos r JOIN groups g ON r.group_id = g.id WHERE g.name = $1 AND r.name = $2;", group_name, module_name).Scan(&fs_path) return fs_path, err
return get_path_perm_by_group_repo_key(ctx, group_name, module_name, ssh_pubkey)
default:
return "", err_ssh_illegal_endpoint
return "", false, err_ssh_illegal_endpoint
} }