mirror of
https://github.com/go-gitea/gitea.git
synced 2026-06-22 01:27:16 +02:00
106 lines
3.2 KiB
Go
106 lines
3.2 KiB
Go
// Copyright 2021 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package git
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"gitea.dev/modules/git/gitcmd"
|
|
giturl "gitea.dev/modules/git/url"
|
|
"gitea.dev/modules/util"
|
|
)
|
|
|
|
// GetRemoteAddress returns remote url of git repository in the repoPath with special remote name
|
|
func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (string, error) {
|
|
cmd := gitcmd.NewCommand("remote", "get-url").AddDynamicArguments(remoteName)
|
|
result, _, err := cmd.WithDir(repoPath).RunStdString(ctx)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if len(result) > 0 {
|
|
result = result[:len(result)-1]
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// ErrInvalidCloneAddr represents a "InvalidCloneAddr" kind of error.
|
|
type ErrInvalidCloneAddr struct {
|
|
Host string
|
|
IsURLError bool
|
|
IsInvalidPath bool
|
|
IsProtocolInvalid bool
|
|
IsPermissionDenied bool
|
|
LocalPath bool
|
|
}
|
|
|
|
// IsErrInvalidCloneAddr checks if an error is a ErrInvalidCloneAddr.
|
|
func IsErrInvalidCloneAddr(err error) bool {
|
|
_, ok := err.(*ErrInvalidCloneAddr)
|
|
return ok
|
|
}
|
|
|
|
func (err *ErrInvalidCloneAddr) Error() string {
|
|
if err.IsInvalidPath {
|
|
return fmt.Sprintf("migration/cloning from '%s' is not allowed: the provided path is invalid", err.Host)
|
|
}
|
|
if err.IsProtocolInvalid {
|
|
return fmt.Sprintf("migration/cloning from '%s' is not allowed: the provided url protocol is not allowed", err.Host)
|
|
}
|
|
if err.IsPermissionDenied {
|
|
return fmt.Sprintf("migration/cloning from '%s' is not allowed.", err.Host)
|
|
}
|
|
if err.IsURLError {
|
|
return fmt.Sprintf("migration/cloning from '%s' is not allowed: the provided url is invalid", err.Host)
|
|
}
|
|
|
|
return fmt.Sprintf("migration/cloning from '%s' is not allowed", err.Host)
|
|
}
|
|
|
|
func (err *ErrInvalidCloneAddr) Unwrap() error {
|
|
return util.ErrInvalidArgument
|
|
}
|
|
|
|
// IsRemoteNotExistError checks the prefix of the error message to see whether a remote does not exist.
|
|
func IsRemoteNotExistError(err error) bool {
|
|
return gitcmd.IsStderr(err, gitcmd.StderrNoSuchRemote1) || gitcmd.IsStderr(err, gitcmd.StderrNoSuchRemote2)
|
|
}
|
|
|
|
// normalizeSSHURL converts SSH-SCP format URLs to standard ssh:// format for security
|
|
// ParseRemoteAddr checks if given remote address is valid,
|
|
// and returns composed URL with needed username and password.
|
|
func ParseRemoteAddr(remoteAddr, authUsername, authPassword string) (string, error) {
|
|
remoteAddr = strings.TrimSpace(remoteAddr)
|
|
|
|
u, err := giturl.ParseGitURL(remoteAddr)
|
|
if err != nil {
|
|
return "", &ErrInvalidCloneAddr{IsURLError: true, Host: remoteAddr}
|
|
}
|
|
|
|
switch u.Scheme {
|
|
case "http", "https", "git":
|
|
if len(authUsername)+len(authPassword) > 0 {
|
|
u.User = url.UserPassword(authUsername, authPassword)
|
|
}
|
|
return u.URL.String(), nil
|
|
case "ssh":
|
|
// SSH uses key-based auth only; username/password is not supported
|
|
if len(authUsername)+len(authPassword) > 0 {
|
|
return "", &ErrInvalidCloneAddr{IsURLError: true, Host: remoteAddr}
|
|
}
|
|
// Normalize SCP short syntax (git@host:path) into an ssh:// URL so
|
|
// downstream SSH handling can detect and use it consistently
|
|
if !strings.HasPrefix(u.Path, "/") {
|
|
u.Path = "/" + u.Path
|
|
}
|
|
return u.URL.String(), nil
|
|
default:
|
|
// Local path or unsupported scheme: pass through unchanged
|
|
return remoteAddr, nil
|
|
}
|
|
}
|