forgejo-aneksajo_auto_patch.../data/45/ref_aneksajo_u.diff
2025-01-23 01:26:39 +01:00

114 lines
4.2 KiB
Diff

--- 9.0.3 2024-12-12 08:06:13.000000000 +0100
+++ aneksajo 2024-12-16 08:23:15.000000000 +0100
@@ -10,6 +10,7 @@
gocontext "context"
"fmt"
"net/http"
+ "net/url"
"os"
"path/filepath"
"regexp"
@@ -78,7 +79,24 @@
strings.HasSuffix(ctx.Req.URL.Path, "git-upload-archive") {
isPull = true
} else {
- isPull = ctx.Req.Method == "GET"
+ // In addition to GET requests, HEAD requests are also "pull"
+ // operations (reads), so they should also not require
+ // authentication. This is necessary for git-annex to operate
+ // properly, as it emits HEAD requests to check for the
+ // existence of keys, e.g. before dropping locally, and asking
+ // for authentication would break unauthenticated http usage in
+ // this situation.
+ // It should be safe to make all HEAD requests require no
+ // authentication, but as it is only necessary for the
+ // annex/objects endpoints to fix git-annex' drop operations it
+ // is limited to those for now.
+ r, err := regexp.Compile("^/?" + username + "/" + reponame + "(.git)?/annex/objects")
+ if err != nil {
+ ctx.ServerError("failed to create URL path regex", err)
+ return nil
+ }
+ isPull = ctx.Req.Method == "GET" ||
+ r.MatchString(ctx.Req.URL.Path) && ctx.Req.Method == "HEAD"
}
var accessMode perm.AccessMode
@@ -545,6 +563,42 @@
}
}
+// GetConfig implements fetching the git config of a repository
+func GetConfig(ctx *context.Context) {
+ h := httpBase(ctx)
+ if h != nil {
+ setHeaderNoCache(ctx)
+ config, err := os.ReadFile(filepath.Join(h.getRepoDir(), "config"))
+ if err != nil {
+ log.Error("Failed to read git config file: %v", err)
+ ctx.Resp.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ if !setting.Annex.DisableP2PHTTP {
+ appURL, err := url.Parse(setting.AppURL)
+ if err != nil {
+ log.Error("Could not parse 'setting.AppURL': %v", err)
+ ctx.Resp.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ if appURL.Port() == "" {
+ // If there is no port set then set the http(s) default ports.
+ // Without this, git-annex would try its own default port (9417) and fail.
+ if appURL.Scheme == "http" {
+ appURL.Host += ":80"
+ }
+ if appURL.Scheme == "https" {
+ appURL.Host += ":443"
+ }
+ }
+ config = append(config, []byte("[annex]\n\turl = annex+"+appURL.String()+"git-annex-p2phttp\n")...)
+ }
+ ctx.Resp.Header().Set("Content-Type", "text/plain")
+ ctx.Resp.Header().Set("Content-Length", fmt.Sprintf("%d", len(config)))
+ http.ServeContent(ctx.Resp, ctx.Req, "config", time.Now(), bytes.NewReader(config))
+ }
+}
+
// GetTextFile implements Git dumb HTTP
func GetTextFile(p string) func(*context.Context) {
return func(ctx *context.Context) {
@@ -597,3 +651,34 @@
h.sendFile(ctx, "application/x-git-packed-objects-toc", "objects/pack/pack-"+ctx.Params("file")+".idx")
}
}
+
+// GetAnnexObject implements git-annex dumb HTTP
+func GetAnnexObject(ctx *context.Context) {
+ h := httpBase(ctx)
+ if h != nil {
+ // git-annex objects are stored in .git/annex/objects/{hash1}/{hash2}/{key}/{key}
+ // where key is a string containing the size and (usually SHA256) checksum of the file,
+ // and hash1+hash2 are the first few bits of the md5sum of key itself.
+ // ({hash1}/{hash2}/ is just there to avoid putting too many files in one directory)
+ // ref: https://git-annex.branchable.com/internals/hashing/
+
+ // keyDir should = key, but we don't enforce that
+ object := filepath.Join(ctx.Params("hash1"), ctx.Params("hash2"), ctx.Params("keyDir"), ctx.Params("key"))
+
+ // Sanitize the input against directory traversals.
+ //
+ // This works because at the filesystem root, "/.." = "/";
+ // So if a path starts rooted ("/"), path.Clean(), which
+ // path.Join() calls internally, removes all '..' prefixes.
+ // After, this unroots the path unconditionally ([1:]), which
+ // works because we know the input is never supposed to be rooted.
+ //
+ // The router code probably also disallows "..", so this
+ // should be redundant, but it's defensive to keep it
+ // whenever touching filesystem paths with user input.
+ object = filepath.Join(string(filepath.Separator), object)[1:]
+
+ setHeaderCacheForever(ctx)
+ h.sendFile(ctx, "application/octet-stream", "annex/objects/"+object)
+ }
+}