Lindenii Project Forge
Commit info | |
---|---|
ID | d212c4606a6eb470067d5302b2350d288d4d9c88 |
Author | Runxi Yu<me@runxiyu.org> |
Author date | Sun, 16 Feb 2025 01:48:39 +0800 |
Committer | Runxi Yu<me@runxiyu.org> |
Committer date | Sun, 16 Feb 2025 01:52:47 +0800 |
Actions | Get patch |
{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
} }