@@ -11,7 +11,6 @@ import (
1111 "os"
1212 "os/exec"
1313 "path/filepath"
14- "regexp"
1514 "strconv"
1615 "strings"
1716 "time"
@@ -20,7 +19,7 @@ import (
2019 asymkey_model "code.gitea.io/gitea/models/asymkey"
2120 git_model "code.gitea.io/gitea/models/git"
2221 "code.gitea.io/gitea/models/perm"
23- "code.gitea.io/gitea/modules/container "
22+ "code.gitea.io/gitea/models/repo "
2423 "code.gitea.io/gitea/modules/git"
2524 "code.gitea.io/gitea/modules/json"
2625 "code.gitea.io/gitea/modules/lfstransfer"
@@ -37,14 +36,6 @@ import (
3736 "github.com/urfave/cli/v2"
3837)
3938
40- const (
41- verbUploadPack = "git-upload-pack"
42- verbUploadArchive = "git-upload-archive"
43- verbReceivePack = "git-receive-pack"
44- verbLfsAuthenticate = "git-lfs-authenticate"
45- verbLfsTransfer = "git-lfs-transfer"
46- )
47-
4839// CmdServ represents the available serv sub-command.
4940var CmdServ = & cli.Command {
5041 Name : "serv" ,
@@ -78,22 +69,6 @@ func setup(ctx context.Context, debug bool) {
7869 }
7970}
8071
81- var (
82- // keep getAccessMode() in sync
83- allowedCommands = container .SetOf (
84- verbUploadPack ,
85- verbUploadArchive ,
86- verbReceivePack ,
87- verbLfsAuthenticate ,
88- verbLfsTransfer ,
89- )
90- allowedCommandsLfs = container .SetOf (
91- verbLfsAuthenticate ,
92- verbLfsTransfer ,
93- )
94- alphaDashDotPattern = regexp .MustCompile (`[^\w-\.]` )
95- )
96-
9772// fail prints message to stdout, it's mainly used for git serv and git hook commands.
9873// The output will be passed to git client and shown to user.
9974func fail (ctx context.Context , userMessage , logMsgFmt string , args ... any ) error {
@@ -139,19 +114,20 @@ func handleCliResponseExtra(extra private.ResponseExtra) error {
139114
140115func getAccessMode (verb , lfsVerb string ) perm.AccessMode {
141116 switch verb {
142- case verbUploadPack , verbUploadArchive :
117+ case git . CmdVerbUploadPack , git . CmdVerbUploadArchive :
143118 return perm .AccessModeRead
144- case verbReceivePack :
119+ case git . CmdVerbReceivePack :
145120 return perm .AccessModeWrite
146- case verbLfsAuthenticate , verbLfsTransfer :
121+ case git . CmdVerbLfsAuthenticate , git . CmdVerbLfsTransfer :
147122 switch lfsVerb {
148- case "upload" :
123+ case git . CmdSubVerbLfsUpload :
149124 return perm .AccessModeWrite
150- case "download" :
125+ case git . CmdSubVerbLfsDownload :
151126 return perm .AccessModeRead
152127 }
153128 }
154129 // should be unreachable
130+ setting .PanicInDevOrTesting ("unknown verb: %s %s" , verb , lfsVerb )
155131 return perm .AccessModeNone
156132}
157133
@@ -230,12 +206,12 @@ func runServ(c *cli.Context) error {
230206 log .Debug ("SSH_ORIGINAL_COMMAND: %s" , os .Getenv ("SSH_ORIGINAL_COMMAND" ))
231207 }
232208
233- words , err := shellquote .Split (cmd )
209+ sshCmdArgs , err := shellquote .Split (cmd )
234210 if err != nil {
235211 return fail (ctx , "Error parsing arguments" , "Failed to parse arguments: %v" , err )
236212 }
237213
238- if len (words ) < 2 {
214+ if len (sshCmdArgs ) < 2 {
239215 if git .DefaultFeatures ().SupportProcReceive {
240216 // for AGit Flow
241217 if cmd == "ssh_info" {
@@ -246,25 +222,21 @@ func runServ(c *cli.Context) error {
246222 return fail (ctx , "Too few arguments" , "Too few arguments in cmd: %s" , cmd )
247223 }
248224
249- verb := words [0 ]
250- repoPath := strings .TrimPrefix (words [1 ], "/" )
251-
252- var lfsVerb string
253-
254- rr := strings .SplitN (repoPath , "/" , 2 )
255- if len (rr ) != 2 {
225+ repoPath := strings .TrimPrefix (sshCmdArgs [1 ], "/" )
226+ repoPathFields := strings .SplitN (repoPath , "/" , 2 )
227+ if len (repoPathFields ) != 2 {
256228 return fail (ctx , "Invalid repository path" , "Invalid repository path: %v" , repoPath )
257229 }
258230
259- username := rr [0 ]
260- reponame := strings .TrimSuffix (rr [1 ], ".git" )
231+ username := repoPathFields [0 ]
232+ reponame := strings .TrimSuffix (repoPathFields [1 ], ".git" ) // “the-repo-name" or "the-repo-name.wiki"
261233
262234 // LowerCase and trim the repoPath as that's how they are stored.
263235 // This should be done after splitting the repoPath into username and reponame
264236 // so that username and reponame are not affected.
265237 repoPath = strings .ToLower (strings .TrimSpace (repoPath ))
266238
267- if alphaDashDotPattern . MatchString (reponame ) {
239+ if ! repo . IsValidSSHAccessRepoName (reponame ) {
268240 return fail (ctx , "Invalid repo name" , "Invalid repo name: %s" , reponame )
269241 }
270242
@@ -286,22 +258,23 @@ func runServ(c *cli.Context) error {
286258 }()
287259 }
288260
289- if allowedCommands .Contains (verb ) {
290- if allowedCommandsLfs .Contains (verb ) {
291- if ! setting .LFS .StartServer {
292- return fail (ctx , "LFS Server is not enabled" , "" )
293- }
294- if verb == verbLfsTransfer && ! setting .LFS .AllowPureSSH {
295- return fail (ctx , "LFS SSH transfer is not enabled" , "" )
296- }
297- if len (words ) > 2 {
298- lfsVerb = words [2 ]
299- }
300- }
301- } else {
261+ verb , lfsVerb := sshCmdArgs [0 ], ""
262+ if ! git .IsAllowedVerbForServe (verb ) {
302263 return fail (ctx , "Unknown git command" , "Unknown git command %s" , verb )
303264 }
304265
266+ if git .IsAllowedVerbForServeLfs (verb ) {
267+ if ! setting .LFS .StartServer {
268+ return fail (ctx , "LFS Server is not enabled" , "" )
269+ }
270+ if verb == git .CmdVerbLfsTransfer && ! setting .LFS .AllowPureSSH {
271+ return fail (ctx , "LFS SSH transfer is not enabled" , "" )
272+ }
273+ if len (sshCmdArgs ) > 2 {
274+ lfsVerb = sshCmdArgs [2 ]
275+ }
276+ }
277+
305278 requestedMode := getAccessMode (verb , lfsVerb )
306279
307280 results , extra := private .ServCommand (ctx , keyID , username , reponame , requestedMode , verb , lfsVerb )
@@ -310,7 +283,7 @@ func runServ(c *cli.Context) error {
310283 }
311284
312285 // LFS SSH protocol
313- if verb == verbLfsTransfer {
286+ if verb == git . CmdVerbLfsTransfer {
314287 token , err := getLFSAuthToken (ctx , lfsVerb , results )
315288 if err != nil {
316289 return err
@@ -319,7 +292,7 @@ func runServ(c *cli.Context) error {
319292 }
320293
321294 // LFS token authentication
322- if verb == verbLfsAuthenticate {
295+ if verb == git . CmdVerbLfsAuthenticate {
323296 url := fmt .Sprintf ("%s%s/%s.git/info/lfs" , setting .AppURL , url .PathEscape (results .OwnerName ), url .PathEscape (results .RepoName ))
324297
325298 token , err := getLFSAuthToken (ctx , lfsVerb , results )
0 commit comments