all repos

mugit @ ac1a0a082f3024019207f55b980990790544a345

馃惍 git server that your cow will love
5 files changed, 39 insertions(+), 18 deletions(-)
support both repo and repo.git as names
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2026-01-28 19:53:53 +0200
Authored at: 2026-01-28 19:52:55 +0200
Change ID: wwryywyqkpzwuxmsqnnvotwoqmqzorky
Parent: cd02956
M internal/git/repo.go
路路路
        51
        51
         }

      
        52
        52
         

      
        53
        53
         func (g *Repo) Name() string {

      
        54
        
        -	return filepath.Base(g.path)

      
        
        54
        +	name := filepath.Base(g.path)

      
        
        55
        +	return strings.TrimSuffix(name, ".git")

      
        55
        56
         }

      
        56
        57
         

      
        57
        58
         func (g *Repo) Commits() ([]*object.Commit, error) {

      
M internal/handlers/git.go
路路路
        30
        30
         }

      
        31
        31
         

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

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

      
        
        33
        +	name := getNormalizedName(r.PathValue("name"))

      
        34
        34
         	_, err := h.openPublicRepo(name, "")

      
        35
        35
         	if err != nil {

      
        36
        36
         		h.write404(w, err)

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

      
        41
        41
         	w.WriteHeader(http.StatusOK)

      
        42
        42
         

      
        43
        
        -	path, err := securejoin.SecureJoin(h.c.Repo.Dir, name)

      
        
        43
        +	repoPath := repoNameToPath(name)

      
        
        44
        +	path, err := securejoin.SecureJoin(h.c.Repo.Dir, repoPath)

      
        44
        45
         	if err != nil {

      
        45
        46
         		w.WriteHeader(http.StatusBadRequest)

      
        46
        47
         		slog.Error("git: info/refs", "err", err)

      路路路
        55
        56
         }

      
        56
        57
         

      
        57
        58
         func (h *handlers) uploadPack(w http.ResponseWriter, r *http.Request) {

      
        58
        
        -	name := r.PathValue("name")

      
        
        59
        +	name := getNormalizedName(r.PathValue("name"))

      
        59
        60
         	_, err := h.openPublicRepo(name, "")

      
        60
        61
         	if err != nil {

      
        61
        62
         		h.write404(w, err)

      路路路
        79
        80
         		reader = gr

      
        80
        81
         	}

      
        81
        82
         

      
        82
        
        -	path, err := securejoin.SecureJoin(h.c.Repo.Dir, name)

      
        
        83
        +	repoPath := repoNameToPath(name)

      
        
        84
        +	path, err := securejoin.SecureJoin(h.c.Repo.Dir, repoPath)

      
        83
        85
         	if err != nil {

      
        84
        86
         		w.WriteHeader(http.StatusBadRequest)

      
        85
        87
         		slog.Error("git: info/refs", "err", err)

      
M internal/handlers/handlers.go
路路路
        46
        46
         	http.ServeFileFS(w, r, web.StaticFS, f)

      
        47
        47
         }

      
        48
        48
         

      
        
        49
        +func repoNameToPath(name string) string { return name + ".git" }

      
        
        50
        +func getNormalizedName(name string) string {

      
        
        51
        +	return strings.TrimSuffix(name, ".git")

      
        
        52
        +}

      
        
        53
        +

      
        49
        54
         var templateFuncs = template.FuncMap{

      
        50
        55
         	"humanizeTime": func(t time.Time) string { return humanize.Time(t) },

      
        51
        56
         	"commitSummary": func(s string) string {

      
M internal/handlers/repo.go
路路路
        43
        43
         	))

      
        44
        44
         

      
        45
        45
         func (h *handlers) repoIndex(w http.ResponseWriter, r *http.Request) {

      
        46
        
        -	name := r.PathValue("name")

      
        
        46
        +	name := getNormalizedName(r.PathValue("name"))

      
        47
        47
         	repo, err := h.openPublicRepo(name, "")

      
        48
        48
         	if err != nil {

      
        49
        49
         		h.write404(w, err)

      路路路
        106
        106
         }

      
        107
        107
         

      
        108
        108
         func (h *handlers) repoTreeHandler(w http.ResponseWriter, r *http.Request) {

      
        109
        
        -	name := r.PathValue("name")

      
        
        109
        +	name := getNormalizedName(r.PathValue("name"))

      
        110
        110
         	ref := r.PathValue("ref")

      
        111
        111
         	treePath := r.PathValue("rest")

      
        112
        112
         

      路路路
        141
        141
         }

      
        142
        142
         

      
        143
        143
         func (h *handlers) fileContentsHandler(w http.ResponseWriter, r *http.Request) {

      
        144
        
        -	name := r.PathValue("name")

      
        
        144
        +	name := getNormalizedName(r.PathValue("name"))

      
        145
        145
         	ref := r.PathValue("ref")

      
        146
        146
         	treePath := r.PathValue("rest")

      
        147
        147
         

      路路路
        201
        201
         }

      
        202
        202
         

      
        203
        203
         func (h *handlers) logHandler(w http.ResponseWriter, r *http.Request) {

      
        204
        
        -	name := r.PathValue("name")

      
        
        204
        +	name := getNormalizedName(r.PathValue("name"))

      
        205
        205
         	ref := r.PathValue("ref")

      
        206
        206
         

      
        207
        207
         	repo, err := h.openPublicRepo(name, ref)

      路路路
        233
        233
         }

      
        234
        234
         

      
        235
        235
         func (h *handlers) commitHandler(w http.ResponseWriter, r *http.Request) {

      
        236
        
        -	name := r.PathValue("name")

      
        
        236
        +	name := getNormalizedName(r.PathValue("name"))

      
        237
        237
         	ref := r.PathValue("ref")

      
        238
        238
         	repo, err := h.openPublicRepo(name, ref)

      
        239
        239
         	if err != nil {

      路路路
        264
        264
         }

      
        265
        265
         

      
        266
        266
         func (h *handlers) refsHandler(w http.ResponseWriter, r *http.Request) {

      
        267
        
        -	name := r.PathValue("name")

      
        
        267
        +	name := getNormalizedName(r.PathValue("name"))

      
        268
        268
         	repo, err := h.openPublicRepo(name, "")

      
        269
        269
         	if err != nil {

      
        270
        270
         		h.write404(w, err)

      路路路
        327
        327
         var errPrivateRepo = errors.New("private err")

      
        328
        328
         

      
        329
        329
         func (h *handlers) openPublicRepo(name, ref string) (*git.Repo, error) {

      
        
        330
        +	// Convert normalized name back to filesystem path with .git suffix

      
        
        331
        +	name = repoNameToPath(name)

      
        
        332
        +

      
        330
        333
         	path, err := securejoin.SecureJoin(h.c.Repo.Dir, name)

      
        331
        334
         	if err != nil {

      
        332
        335
         		return nil, err

      路路路
        368
        371
         		}

      
        369
        372
         

      
        370
        373
         		name := dir.Name()

      
        371
        
        -		repo, err := h.openPublicRepo(name, "")

      
        
        374
        +		normalizedName := getNormalizedName(name)

      
        
        375
        +		repo, err := h.openPublicRepo(normalizedName, "")

      
        372
        376
         		if err != nil {

      
        373
        377
         			if errors.Is(err, errPrivateRepo) {

      
        374
        378
         				continue

      路路路
        390
        394
         		}

      
        391
        395
         

      
        392
        396
         		repos = append(repos, repoList{

      
        393
        
        -			Name:       name,

      
        
        397
        +			Name:       normalizedName,

      
        394
        398
         			Desc:       desc,

      
        395
        399
         			LastCommit: lastComit.Author.When,

      
        396
        400
         		})

      
M internal/ssh/server.go
路路路
        5
        5
         	"log/slog"

      
        6
        6
         	"slices"

      
        7
        7
         	"strconv"

      
        
        8
        +	"strings"

      
        8
        9
         

      
        9
        10
         	securejoin "github.com/cyphar/filepath-securejoin"

      
        10
        11
         	"github.com/gliderlabs/ssh"

      路路路
        76
        77
         	}

      
        77
        78
         

      
        78
        79
         	gitCmd := cmd[0]

      
        79
        
        -	repoPath := cmd[1]

      
        80
        
        -	repoPath, err := securejoin.SecureJoin(s.c.Repo.Dir, repoPath)

      
        
        80
        +	rawRepoPath := cmd[1]

      
        
        81
        +	normalizedRepoName := normalizeRepoName(rawRepoPath)

      
        
        82
        +	repoPath := repoNameToPath(normalizedRepoName)

      
        
        83
        +

      
        
        84
        +	fullPath, err := securejoin.SecureJoin(s.c.Repo.Dir, repoPath)

      
        81
        85
         	if err != nil {

      
        82
        86
         		slog.Error("ssh: invalid path", "err", err)

      
        83
        87
         		s.repoNotFound(sess)

      
        84
        88
         		return

      
        85
        89
         	}

      
        86
        90
         

      
        87
        
        -	repo, err := git.Open(repoPath, "")

      
        
        91
        +	repo, err := git.Open(fullPath, "")

      
        88
        92
         	if err != nil {

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

      
        90
        94
         		s.repoNotFound(sess)

      路路路
        104
        108
         			return

      
        105
        109
         		}

      
        106
        110
         

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

      
        
        111
        +		if err := gitservice.UploadPack(fullPath, false, sess, sess); err != nil {

      
        108
        112
         			s.error(sess, err)

      
        109
        113
         			return

      
        110
        114
         		}

      路路路
        115
        119
         			return

      
        116
        120
         		}

      
        117
        121
         

      
        118
        
        -		if err := gitservice.ReceivePack(repoPath, sess, sess, sess.Stderr()); err != nil {

      
        
        122
        +		if err := gitservice.ReceivePack(fullPath, sess, sess, sess.Stderr()); err != nil {

      
        119
        123
         			s.error(sess, err)

      
        120
        124
         			return

      
        121
        125
         		}

      路路路
        156
        160
         	gitservice.PackError(sess, "Unexpected server error.")

      
        157
        161
         	sess.Exit(1)

      
        158
        162
         }

      
        
        163
        +

      
        
        164
        +func repoNameToPath(name string) string { return name + ".git" }

      
        
        165
        +func normalizeRepoName(name string) string {

      
        
        166
        +	return strings.TrimSuffix(name, ".git")

      
        
        167
        +}