aboutsummaryrefslogtreecommitdiffstats
path: root/cmd/serv.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/serv.go')
-rw-r--r--cmd/serv.go98
1 files changed, 34 insertions, 64 deletions
diff --git a/cmd/serv.go b/cmd/serv.go
index b18508459f..8c6001e727 100644
--- a/cmd/serv.go
+++ b/cmd/serv.go
@@ -11,7 +11,6 @@ import (
"os"
"os/exec"
"path/filepath"
- "regexp"
"strconv"
"strings"
"time"
@@ -20,7 +19,7 @@ import (
asymkey_model "code.gitea.io/gitea/models/asymkey"
git_model "code.gitea.io/gitea/models/git"
"code.gitea.io/gitea/models/perm"
- "code.gitea.io/gitea/modules/container"
+ "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/lfstransfer"
@@ -34,15 +33,7 @@ import (
"github.com/golang-jwt/jwt/v5"
"github.com/kballard/go-shellquote"
- "github.com/urfave/cli/v2"
-)
-
-const (
- verbUploadPack = "git-upload-pack"
- verbUploadArchive = "git-upload-archive"
- verbReceivePack = "git-receive-pack"
- verbLfsAuthenticate = "git-lfs-authenticate"
- verbLfsTransfer = "git-lfs-transfer"
+ "github.com/urfave/cli/v3"
)
// CmdServ represents the available serv sub-command.
@@ -78,22 +69,6 @@ func setup(ctx context.Context, debug bool) {
}
}
-var (
- // keep getAccessMode() in sync
- allowedCommands = container.SetOf(
- verbUploadPack,
- verbUploadArchive,
- verbReceivePack,
- verbLfsAuthenticate,
- verbLfsTransfer,
- )
- allowedCommandsLfs = container.SetOf(
- verbLfsAuthenticate,
- verbLfsTransfer,
- )
- alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
-)
-
// fail prints message to stdout, it's mainly used for git serv and git hook commands.
// The output will be passed to git client and shown to user.
func fail(ctx context.Context, userMessage, logMsgFmt string, args ...any) error {
@@ -139,19 +114,20 @@ func handleCliResponseExtra(extra private.ResponseExtra) error {
func getAccessMode(verb, lfsVerb string) perm.AccessMode {
switch verb {
- case verbUploadPack, verbUploadArchive:
+ case git.CmdVerbUploadPack, git.CmdVerbUploadArchive:
return perm.AccessModeRead
- case verbReceivePack:
+ case git.CmdVerbReceivePack:
return perm.AccessModeWrite
- case verbLfsAuthenticate, verbLfsTransfer:
+ case git.CmdVerbLfsAuthenticate, git.CmdVerbLfsTransfer:
switch lfsVerb {
- case "upload":
+ case git.CmdSubVerbLfsUpload:
return perm.AccessModeWrite
- case "download":
+ case git.CmdSubVerbLfsDownload:
return perm.AccessModeRead
}
}
// should be unreachable
+ setting.PanicInDevOrTesting("unknown verb: %s %s", verb, lfsVerb)
return perm.AccessModeNone
}
@@ -176,10 +152,7 @@ func getLFSAuthToken(ctx context.Context, lfsVerb string, results *private.ServC
return "Bearer " + tokenString, nil
}
-func runServ(c *cli.Context) error {
- ctx, cancel := installSignals()
- defer cancel()
-
+func runServ(ctx context.Context, c *cli.Command) error {
// FIXME: This needs to internationalised
setup(ctx, c.Bool("debug"))
@@ -230,41 +203,37 @@ func runServ(c *cli.Context) error {
log.Debug("SSH_ORIGINAL_COMMAND: %s", os.Getenv("SSH_ORIGINAL_COMMAND"))
}
- words, err := shellquote.Split(cmd)
+ sshCmdArgs, err := shellquote.Split(cmd)
if err != nil {
return fail(ctx, "Error parsing arguments", "Failed to parse arguments: %v", err)
}
- if len(words) < 2 {
+ if len(sshCmdArgs) < 2 {
if git.DefaultFeatures().SupportProcReceive {
// for AGit Flow
if cmd == "ssh_info" {
- fmt.Print(`{"type":"gitea","version":1}`)
+ fmt.Print(`{"type":"agit","version":1}`)
return nil
}
}
return fail(ctx, "Too few arguments", "Too few arguments in cmd: %s", cmd)
}
- verb := words[0]
- repoPath := strings.TrimPrefix(words[1], "/")
-
- var lfsVerb string
-
- rr := strings.SplitN(repoPath, "/", 2)
- if len(rr) != 2 {
+ repoPath := strings.TrimPrefix(sshCmdArgs[1], "/")
+ repoPathFields := strings.SplitN(repoPath, "/", 2)
+ if len(repoPathFields) != 2 {
return fail(ctx, "Invalid repository path", "Invalid repository path: %v", repoPath)
}
- username := rr[0]
- reponame := strings.TrimSuffix(rr[1], ".git")
+ username := repoPathFields[0]
+ reponame := strings.TrimSuffix(repoPathFields[1], ".git") // “the-repo-name" or "the-repo-name.wiki"
// LowerCase and trim the repoPath as that's how they are stored.
// This should be done after splitting the repoPath into username and reponame
// so that username and reponame are not affected.
repoPath = strings.ToLower(strings.TrimSpace(repoPath))
- if alphaDashDotPattern.MatchString(reponame) {
+ if !repo.IsValidSSHAccessRepoName(reponame) {
return fail(ctx, "Invalid repo name", "Invalid repo name: %s", reponame)
}
@@ -286,22 +255,23 @@ func runServ(c *cli.Context) error {
}()
}
- if allowedCommands.Contains(verb) {
- if allowedCommandsLfs.Contains(verb) {
- if !setting.LFS.StartServer {
- return fail(ctx, "LFS Server is not enabled", "")
- }
- if verb == verbLfsTransfer && !setting.LFS.AllowPureSSH {
- return fail(ctx, "LFS SSH transfer is not enabled", "")
- }
- if len(words) > 2 {
- lfsVerb = words[2]
- }
- }
- } else {
+ verb, lfsVerb := sshCmdArgs[0], ""
+ if !git.IsAllowedVerbForServe(verb) {
return fail(ctx, "Unknown git command", "Unknown git command %s", verb)
}
+ if git.IsAllowedVerbForServeLfs(verb) {
+ if !setting.LFS.StartServer {
+ return fail(ctx, "LFS Server is not enabled", "")
+ }
+ if verb == git.CmdVerbLfsTransfer && !setting.LFS.AllowPureSSH {
+ return fail(ctx, "LFS SSH transfer is not enabled", "")
+ }
+ if len(sshCmdArgs) > 2 {
+ lfsVerb = sshCmdArgs[2]
+ }
+ }
+
requestedMode := getAccessMode(verb, lfsVerb)
results, extra := private.ServCommand(ctx, keyID, username, reponame, requestedMode, verb, lfsVerb)
@@ -310,7 +280,7 @@ func runServ(c *cli.Context) error {
}
// LFS SSH protocol
- if verb == verbLfsTransfer {
+ if verb == git.CmdVerbLfsTransfer {
token, err := getLFSAuthToken(ctx, lfsVerb, results)
if err != nil {
return err
@@ -319,7 +289,7 @@ func runServ(c *cli.Context) error {
}
// LFS token authentication
- if verb == verbLfsAuthenticate {
+ if verb == git.CmdVerbLfsAuthenticate {
url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, url.PathEscape(results.OwnerName), url.PathEscape(results.RepoName))
token, err := getLFSAuthToken(ctx, lfsVerb, results)