@@ -36,7 +36,10 @@ import (
3636)
3737
3838const (
39- lfsAuthenticateVerb = "git-lfs-authenticate"
39+ verbUploadPack = "git-upload-pack"
40+ verbUploadArchive = "git-upload-archive"
41+ verbReceivePack = "git-receive-pack"
42+ verbLfsAuthenticate = "git-lfs-authenticate"
4043)
4144
4245// CmdServ represents the available serv sub-command.
@@ -73,11 +76,16 @@ func setup(ctx context.Context, debug bool) {
7376}
7477
7578var (
76- allowedCommands = map [string ]perm.AccessMode {
77- "git-upload-pack" : perm .AccessModeRead ,
78- "git-upload-archive" : perm .AccessModeRead ,
79- "git-receive-pack" : perm .AccessModeWrite ,
80- lfsAuthenticateVerb : perm .AccessModeNone ,
79+ // anything not in map will return false (zero value)
80+ // keep getAccessMode() in sync
81+ allowedCommands = map [string ]bool {
82+ verbUploadPack : true ,
83+ verbUploadArchive : true ,
84+ verbReceivePack : true ,
85+ verbLfsAuthenticate : true ,
86+ }
87+ allowedCommandsLfs = map [string ]bool {
88+ verbLfsAuthenticate : true ,
8189 }
8290 alphaDashDotPattern = regexp .MustCompile (`[^\w-\.]` )
8391)
@@ -124,6 +132,24 @@ func handleCliResponseExtra(extra private.ResponseExtra) error {
124132 return nil
125133}
126134
135+ func getAccessMode (verb string , lfsVerb string ) perm.AccessMode {
136+ switch verb {
137+ case verbUploadPack , verbUploadArchive :
138+ return perm .AccessModeRead
139+ case verbReceivePack :
140+ return perm .AccessModeWrite
141+ case verbLfsAuthenticate :
142+ switch lfsVerb {
143+ case "upload" :
144+ return perm .AccessModeWrite
145+ case "download" :
146+ return perm .AccessModeRead
147+ }
148+ }
149+ // should be unreachable
150+ return perm .AccessModeNone
151+ }
152+
127153func runServ (c * cli.Context ) error {
128154 ctx , cancel := installSignals ()
129155 defer cancel ()
@@ -193,17 +219,7 @@ func runServ(c *cli.Context) error {
193219 if repoPath [0 ] == '/' {
194220 repoPath = repoPath [1 :]
195221 }
196-
197222 var lfsVerb string
198- if verb == lfsAuthenticateVerb {
199- if ! setting .LFS .StartServer {
200- return fail (ctx , "Unknown git command" , "LFS authentication request over SSH denied, LFS support is disabled" )
201- }
202-
203- if len (words ) > 2 {
204- lfsVerb = words [2 ]
205- }
206- }
207223
208224 rr := strings .SplitN (repoPath , "/" , 2 )
209225 if len (rr ) != 2 {
@@ -240,28 +256,28 @@ func runServ(c *cli.Context) error {
240256 }()
241257 }
242258
243- requestedMode , has := allowedCommands [verb ]
244- if ! has {
259+ if allowedCommands [verb ] {
260+ if allowedCommandsLfs [verb ] {
261+ if ! setting .LFS .StartServer {
262+ return fail (ctx , "Unknown git command" , "LFS authentication request over SSH denied, LFS support is disabled" )
263+ }
264+ if len (words ) > 2 {
265+ lfsVerb = words [2 ]
266+ }
267+ }
268+ } else {
245269 return fail (ctx , "Unknown git command" , "Unknown git command %s" , verb )
246270 }
247271
248- if verb == lfsAuthenticateVerb {
249- if lfsVerb == "upload" {
250- requestedMode = perm .AccessModeWrite
251- } else if lfsVerb == "download" {
252- requestedMode = perm .AccessModeRead
253- } else {
254- return fail (ctx , "Unknown LFS verb" , "Unknown lfs verb %s" , lfsVerb )
255- }
256- }
272+ requestedMode := getAccessMode (verb , lfsVerb )
257273
258274 results , extra := private .ServCommand (ctx , keyID , username , reponame , requestedMode , verb , lfsVerb )
259275 if extra .HasError () {
260276 return fail (ctx , extra .UserMsg , "ServCommand failed: %s" , extra .Error )
261277 }
262278
263279 // LFS token authentication
264- if verb == lfsAuthenticateVerb {
280+ if verb == verbLfsAuthenticate {
265281 url := fmt .Sprintf ("%s%s/%s.git/info/lfs" , setting .AppURL , url .PathEscape (results .OwnerName ), url .PathEscape (results .RepoName ))
266282
267283 now := time .Now ()
@@ -296,22 +312,22 @@ func runServ(c *cli.Context) error {
296312 return nil
297313 }
298314
299- var gitcmd * exec.Cmd
300315 gitBinPath := filepath .Dir (git .GitExecutable ) // e.g. /usr/bin
301316 gitBinVerb := filepath .Join (gitBinPath , verb ) // e.g. /usr/bin/git-upload-pack
317+ gitExe := gitBinVerb
318+ gitArgs := make ([]string , 0 , 3 ) // capacity to accommodate max args
302319 if _ , err := os .Stat (gitBinVerb ); err != nil {
303320 // if the command "git-upload-pack" doesn't exist, try to split "git-upload-pack" to use the sub-command with git
304321 // ps: Windows only has "git.exe" in the bin path, so Windows always uses this way
305322 verbFields := strings .SplitN (verb , "-" , 2 )
306323 if len (verbFields ) == 2 {
307324 // use git binary with the sub-command part: "C:\...\bin\git.exe", "upload-pack", ...
308- gitcmd = exec .CommandContext (ctx , git .GitExecutable , verbFields [1 ], repoPath )
325+ gitExe = git .GitExecutable
326+ gitArgs = append (gitArgs , verbFields [1 ])
309327 }
310328 }
311- if gitcmd == nil {
312- // by default, use the verb (it has been checked above by allowedCommands)
313- gitcmd = exec .CommandContext (ctx , gitBinVerb , repoPath )
314- }
329+ gitArgs = append (gitArgs , repoPath )
330+ gitcmd := exec .CommandContext (ctx , gitExe , gitArgs ... )
315331
316332 process .SetSysProcAttribute (gitcmd )
317333 gitcmd .Dir = setting .RepoRootPath
0 commit comments