@@ -424,60 +424,40 @@ func (h *serviceHandler) sendFile(contentType, file string) {
424424// one or more key=value pairs separated by colons
425425var safeGitProtocolHeader = regexp .MustCompile (`^[0-9a-zA-Z]+=[0-9a-zA-Z]+(:[0-9a-zA-Z]+=[0-9a-zA-Z]+)*$` )
426426
427- func getGitConfig (ctx gocontext.Context , option , dir string ) string {
428- out , _ , err := git .NewCommand (ctx , "config" ).AddDynamicArguments (option ).RunStdString (& git.RunOpts {Dir : dir })
429- if err != nil {
430- log .Error ("%v - %s" , err , out )
431- }
432- return out [0 : len (out )- 1 ]
433- }
434-
435- func getConfigSetting (ctx gocontext.Context , service , dir string ) bool {
436- service = strings .ReplaceAll (service , "-" , "" )
437- setting := getGitConfig (ctx , "http." + service , dir )
438-
439- if service == "uploadpack" {
440- return setting != "false"
441- }
442-
443- return setting == "true"
444- }
445-
446- func hasAccess (ctx gocontext.Context , service string , h serviceHandler , checkContentType bool ) bool {
447- if checkContentType {
448- if h .r .Header .Get ("Content-Type" ) != fmt .Sprintf ("application/x-git-%s-request" , service ) {
449- return false
450- }
427+ func prepareGitCmdWithAllowedService (service string , h * serviceHandler ) (* git.Command , error ) {
428+ if service == "receive-pack" && h .cfg .ReceivePack {
429+ return git .NewCommand (h .r .Context (), "receive-pack" ), nil
451430 }
452-
453- if ! (service == "upload-pack" || service == "receive-pack" ) {
454- return false
455- }
456- if service == "receive-pack" {
457- return h .cfg .ReceivePack
458- }
459- if service == "upload-pack" {
460- return h .cfg .UploadPack
431+ if service == "upload-pack" && h .cfg .UploadPack {
432+ return git .NewCommand (h .r .Context (), "upload-pack" ), nil
461433 }
462434
463- return getConfigSetting ( ctx , service , h . dir )
435+ return nil , fmt . Errorf ( " service %q is not allowed" , service )
464436}
465437
466- func serviceRPC (ctx gocontext. Context , h serviceHandler , service string ) {
438+ func serviceRPC (h * serviceHandler , service string ) {
467439 defer func () {
468440 if err := h .r .Body .Close (); err != nil {
469441 log .Error ("serviceRPC: Close: %v" , err )
470442 }
471443 }()
472444
473- if ! hasAccess (ctx , service , h , true ) {
445+ expectedContentType := fmt .Sprintf ("application/x-git-%s-request" , service )
446+ if h .r .Header .Get ("Content-Type" ) != expectedContentType {
447+ log .Error ("Content-Type (%q) doesn't match expected: %q" , h .r .Header .Get ("Content-Type" ), expectedContentType )
448+ h .w .WriteHeader (http .StatusUnauthorized )
449+ return
450+ }
451+
452+ cmd , err := prepareGitCmdWithAllowedService (service , h )
453+ if err != nil {
454+ log .Error ("Failed to prepareGitCmdWithService: %v" , err )
474455 h .w .WriteHeader (http .StatusUnauthorized )
475456 return
476457 }
477458
478459 h .w .Header ().Set ("Content-Type" , fmt .Sprintf ("application/x-git-%s-result" , service ))
479460
480- var err error
481461 reqBody := h .r .Body
482462
483463 // Handle GZIP.
@@ -498,8 +478,7 @@ func serviceRPC(ctx gocontext.Context, h serviceHandler, service string) {
498478 }
499479
500480 var stderr bytes.Buffer
501- // the service is generated by ourselves, so it's safe to trust it
502- cmd := git .NewCommand (h .r .Context (), git .ToTrustedCmdArgs ([]string {service })... ).AddArguments ("--stateless-rpc" ).AddDynamicArguments (h .dir )
481+ cmd .AddArguments ("--stateless-rpc" ).AddDynamicArguments (h .dir )
503482 cmd .SetDescription (fmt .Sprintf ("%s %s %s [repo_path: %s]" , git .GitExecutable , service , "--stateless-rpc" , h .dir ))
504483 if err := cmd .Run (& git.RunOpts {
505484 Dir : h .dir ,
@@ -520,15 +499,15 @@ func serviceRPC(ctx gocontext.Context, h serviceHandler, service string) {
520499func ServiceUploadPack (ctx * context.Context ) {
521500 h := httpBase (ctx )
522501 if h != nil {
523- serviceRPC (ctx , * h , "upload-pack" )
502+ serviceRPC (h , "upload-pack" )
524503 }
525504}
526505
527506// ServiceReceivePack implements Git Smart HTTP protocol
528507func ServiceReceivePack (ctx * context.Context ) {
529508 h := httpBase (ctx )
530509 if h != nil {
531- serviceRPC (ctx , * h , "receive-pack" )
510+ serviceRPC (h , "receive-pack" )
532511 }
533512}
534513
@@ -537,7 +516,7 @@ func getServiceType(r *http.Request) string {
537516 if ! strings .HasPrefix (serviceType , "git-" ) {
538517 return ""
539518 }
540- return strings .Replace (serviceType , "git-" , "" , 1 )
519+ return strings .TrimPrefix (serviceType , "git-" )
541520}
542521
543522func updateServerInfo (ctx gocontext.Context , dir string ) []byte {
@@ -563,16 +542,15 @@ func GetInfoRefs(ctx *context.Context) {
563542 return
564543 }
565544 h .setHeaderNoCache ()
566- if hasAccess ( ctx , getServiceType (h .r ), * h , false ) {
567- service := getServiceType ( h . r )
568-
545+ service := getServiceType (h .r )
546+ cmd , err := prepareGitCmdWithAllowedService ( service , h )
547+ if err == nil {
569548 if protocol := h .r .Header .Get ("Git-Protocol" ); protocol != "" && safeGitProtocolHeader .MatchString (protocol ) {
570549 h .environ = append (h .environ , "GIT_PROTOCOL=" + protocol )
571550 }
572551 h .environ = append (os .Environ (), h .environ ... )
573552
574- // the service is generated by ourselves, so we can trust it
575- refs , _ , err := git .NewCommand (ctx , git .ToTrustedCmdArgs ([]string {service })... ).AddArguments ("--stateless-rpc" , "--advertise-refs" , "." ).RunStdBytes (& git.RunOpts {Env : h .environ , Dir : h .dir })
553+ refs , _ , err := cmd .AddArguments ("--stateless-rpc" , "--advertise-refs" , "." ).RunStdBytes (& git.RunOpts {Env : h .environ , Dir : h .dir })
576554 if err != nil {
577555 log .Error (fmt .Sprintf ("%v - %s" , err , string (refs )))
578556 }
0 commit comments