all repos

mugit @ 1ea9b7f

馃惍 git server that your cow will love
6 files changed, 60 insertions(+), 26 deletions(-)
dont allow to see private repos for unauthorized users
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2026-01-21 01:49:14 +0200
Authored at: 2026-01-21 01:44:48 +0200
Change ID: ytwpnunotkptnzqvoxsttzplswyrtqou
Parent: 3d9ab8a
M internal/handlers/git.go
路路路
        7
        7
         	"net/http"

      
        8
        8
         	"path/filepath"

      
        9
        9
         

      
        
        10
        +	"olexsmir.xyz/mugit/internal/git"

      
        10
        11
         	"olexsmir.xyz/mugit/internal/git/gitservice"

      
        11
        12
         )

      
        12
        13
         

      
        
        14
        +// multiplex, check if the request smells like gitprotocol-http(5), if so, it

      
        
        15
        +// passes it to git smart http, otherwise renders templates

      
        
        16
        +func (h *handlers) multiplex(w http.ResponseWriter, r *http.Request) {

      
        
        17
        +	if r.URL.RawQuery == "service=git-receive-pack" {

      
        
        18
        +		w.WriteHeader(http.StatusBadRequest)

      
        
        19
        +		w.Write([]byte("http pushing isn't supported"))

      
        
        20
        +		return

      
        
        21
        +	}

      
        
        22
        +

      
        
        23
        +	path := r.PathValue("rest")

      
        
        24
        +	if path == "info/refs" && r.Method == "GET" && r.URL.RawQuery == "service=git-upload-pack" {

      
        
        25
        +		h.infoRefs(w, r)

      
        
        26
        +	} else if path == "git-upload-pack" && r.Method == "POST" {

      
        
        27
        +		h.uploadPack(w, r)

      
        
        28
        +	} else if r.Method == "GET" {

      
        
        29
        +		h.repoIndex(w, r)

      
        
        30
        +	}

      
        
        31
        +}

      
        
        32
        +

      
        13
        33
         func (h *handlers) infoRefs(w http.ResponseWriter, r *http.Request) {

      
        14
        
        -	// TODO: 404 for private repos

      
        15
        
        -

      
        16
        34
         	name := filepath.Clean(r.PathValue("name"))

      
        
        35
        +	repo, err := git.Open(filepath.Join(h.c.Repo.Dir, name), "")

      
        
        36
        +	if err != nil {

      
        
        37
        +		h.write404(w, err)

      
        
        38
        +		return

      
        
        39
        +	}

      
        
        40
        +

      
        
        41
        +	isPrivate, err := repo.IsPrivate()

      
        
        42
        +	if isPrivate || err != nil {

      
        
        43
        +		h.write404(w, err)

      
        
        44
        +		return

      
        
        45
        +	}

      
        17
        46
         

      
        18
        47
         	w.Header().Set("content-type", "application/x-git-upload-pack-advertisement")

      
        19
        48
         	w.WriteHeader(http.StatusOK)

      路路路
        28
        57
         }

      
        29
        58
         

      
        30
        59
         func (h *handlers) uploadPack(w http.ResponseWriter, r *http.Request) {

      
        31
        
        -	// TODO: 404 for private repos

      
        
        60
        +	name := filepath.Clean(r.PathValue("name"))

      
        
        61
        +	repo, err := git.Open(filepath.Join(h.c.Repo.Dir, name), "")

      
        
        62
        +	if err != nil {

      
        
        63
        +		h.write404(w, err)

      
        
        64
        +		return

      
        
        65
        +	}

      
        32
        66
         

      
        33
        
        -	name := filepath.Clean(r.PathValue("name"))

      
        
        67
        +	isPrivate, err := repo.IsPrivate()

      
        
        68
        +	if isPrivate || err != nil {

      
        
        69
        +		h.write404(w, err)

      
        
        70
        +		return

      
        
        71
        +	}

      
        34
        72
         

      
        35
        73
         	w.Header().Set("content-type", "application/x-git-upload-pack-result")

      
        36
        74
         	w.Header().Set("Connection", "Keep-Alive")

      
M internal/handlers/handlers.go
路路路
        39
        39
         	return mux

      
        40
        40
         }

      
        41
        41
         

      
        42
        
        -// multiplex, check if the request smells like gitprotocol-http(5), if so, it

      
        43
        
        -// passes it to git smart http, otherwise renders templates

      
        44
        
        -func (h *handlers) multiplex(w http.ResponseWriter, r *http.Request) {

      
        45
        
        -	if r.URL.RawQuery == "service=git-receive-pack" {

      
        46
        
        -		w.WriteHeader(http.StatusBadRequest)

      
        47
        
        -		w.Write([]byte("http pushing isn't supported"))

      
        48
        
        -		return

      
        49
        
        -	}

      
        50
        
        -

      
        51
        
        -	path := r.PathValue("rest")

      
        52
        
        -	if path == "info/refs" && r.Method == "GET" && r.URL.RawQuery == "service=git-upload-pack" {

      
        53
        
        -		h.infoRefs(w, r)

      
        54
        
        -	} else if path == "git-upload-pack" && r.Method == "POST" {

      
        55
        
        -		h.uploadPack(w, r)

      
        56
        
        -	} else if r.Method == "GET" {

      
        57
        
        -		h.repoIndex(w, r)

      
        58
        
        -	}

      
        59
        
        -}

      
        60
        42
         

      
        61
        43
         func (h *handlers) serveStatic(w http.ResponseWriter, r *http.Request) {

      
        62
        44
         	f := filepath.Clean(r.PathValue("file"))

      
M internal/handlers/repo.go
路路路
        54
        54
         			continue

      
        55
        55
         		}

      
        56
        56
         

      
        
        57
        +		if isPrivate, err := repo.IsPrivate(); err != nil || isPrivate {

      
        
        58
        +			slog.Error("", "err", err)

      
        
        59
        +			continue

      
        
        60
        +		}

      
        
        61
        +

      
        57
        62
         		repoInfos = append(repoInfos, repoInfo{

      
        58
        63
         			Name: name,

      
        59
        64
         			Desc: desc,

      路路路
        88
        93
         	}

      
        89
        94
         

      
        90
        95
         	isPrivate, err := repo.IsPrivate()

      
        91
        
        -	if isPrivate || err != nil { // FIX: private = 404, err = 500

      
        
        96
        +	if isPrivate || err != nil {

      
        92
        97
         		h.write404(w, err)

      
        93
        98
         		return

      
        94
        99
         	}

      
M internal/ssh/server.go
路路路
        79
        79
         	repoPath := cmd[1]

      
        80
        80
         

      
        81
        81
         	repoPath = filepath.Join(s.c.Repo.Dir, filepath.Clean(repoPath))

      
        82
        
        -	_, err := git.Open(repoPath, "")

      
        
        82
        +	repo, err := git.Open(repoPath, "")

      
        83
        83
         	if err != nil {

      
        84
        84
         		slog.Error("ssh: failed to open repo", "err", err)

      
        85
        85
         		s.repoNotFound(sess)

      路路路
        88
        88
         

      
        89
        89
         	switch gitCmd {

      
        90
        90
         	case "git-upload-pack":

      
        
        91
        +		isPrivate, err := repo.IsPrivate()

      
        
        92
        +		if err != nil {

      
        
        93
        +			s.error(sess, err)

      
        
        94
        +			return

      
        
        95
        +		}

      
        
        96
        +

      
        
        97
        +		if isPrivate && !authorized {

      
        
        98
        +			s.repoNotFound(sess)

      
        
        99
        +			return

      
        
        100
        +		}

      
        
        101
        +

      
        91
        102
         		if err := gitservice.UploadPack(repoPath, false, sess, sess); err != nil {

      
        92
        103
         			s.error(sess, err)

      
        93
        104
         			return

      
M web/templates/404.html
路路路
        5
        5
         {{ template "head" . }}

      
        6
        6
           </head>

      
        7
        7
           <body>

      
        8
        
        -    <!-- {{ template "nav" . }} -->

      
        9
        8
             <main>

      
        10
        9
               <h3>404 &mdash; nothing like that here.</h3>

      
        11
        10
             </main>

      
M web/templates/500.html
路路路
        5
        5
         {{ template "head" . }}

      
        6
        6
           </head>

      
        7
        7
           <body>

      
        8
        
        -    <!-- {{ template "nav" . }} -->

      
        9
        8
             <main>

      
        10
        9
               <h3>500 &mdash; something broke!</h3>

      
        11
        10
             </main>