Signed-off-by: Winter winter@winter.cafe
+14
-3
knotserver/routes.go
+14
-3
knotserver/routes.go
···
361
361
362
362
ref := strings.TrimSuffix(file, ".tar.gz")
363
363
364
+
unescapedRef, err := url.PathUnescape(ref)
365
+
if err != nil {
366
+
notFound(w)
367
+
return
368
+
}
369
+
370
+
// refs/tags/* is way more common than refs/heads/*, so we can live with an ugly file/directory
371
+
// name in the odd cases (e.g. refs-heads-master.tar.gz, but in that case the user should just
372
+
// request master.tar.gz)
373
+
safeRefFilename := strings.ReplaceAll(strings.TrimPrefix(unescapedRef, "refs/tags/"), "/", "-")
374
+
364
375
// This allows the browser to use a proper name for the file when
365
376
// downloading
366
-
filename := fmt.Sprintf("%s-%s.tar.gz", name, ref)
377
+
filename := fmt.Sprintf("%s-%s.tar.gz", name, safeRefFilename)
367
378
setContentDisposition(w, filename)
368
379
setGZipMIME(w)
369
380
370
381
path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r))
371
-
gr, err := git.Open(path, ref)
382
+
gr, err := git.Open(path, unescapedRef)
372
383
if err != nil {
373
384
notFound(w)
374
385
return
···
377
388
gw := gzip.NewWriter(w)
378
389
defer gw.Close()
379
390
380
-
prefix := fmt.Sprintf("%s-%s", name, ref)
391
+
prefix := fmt.Sprintf("%s-%s", name, safeRefFilename)
381
392
err = gr.WriteTar(gw, prefix)
382
393
if err != nil {
383
394
// once we start writing to the body we can't report error anymore