@@ -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