mirror of
https://codeberg.org/git-pages/git-pages.git
synced 2026-05-14 11:11:35 +00:00
Add Codeberg Pages v2 specific DNS authorization mechanism.
Feature-gated behind `codeberg-pages-compat` since it has no generic use outside of that specific deployment.
This commit is contained in:
79
src/auth.go
79
src/auth.go
@@ -240,6 +240,72 @@ func authorizeWildcardMatchSite(r *http.Request, pattern *WildcardPattern) (*Aut
|
||||
}
|
||||
}
|
||||
|
||||
// used for compatibility with Codeberg Pages v2
|
||||
// see https://docs.codeberg.org/codeberg-pages/using-custom-domain/
|
||||
func authorizeCodebergPagesV2(r *http.Request) (*Authorization, error) {
|
||||
host, err := GetHost(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dnsRecords := []string{}
|
||||
|
||||
cnameRecord, err := net.LookupCNAME(host)
|
||||
// "LookupCNAME does not return an error if host does not contain DNS "CNAME" records,
|
||||
// as long as host resolves to address records.
|
||||
if err == nil && cnameRecord != host {
|
||||
// LookupCNAME() returns a domain with the root label, i.e. `username.codeberg.page.`,
|
||||
// with the trailing dot
|
||||
dnsRecords = append(dnsRecords, strings.TrimSuffix(cnameRecord, "."))
|
||||
}
|
||||
|
||||
txtRecords, err := net.LookupTXT(host)
|
||||
if err == nil {
|
||||
dnsRecords = append(dnsRecords, txtRecords...)
|
||||
}
|
||||
|
||||
if len(dnsRecords) > 0 {
|
||||
log.Printf("auth: %s TXT/CNAME: %v\n", host, dnsRecords)
|
||||
}
|
||||
|
||||
for _, dnsRecord := range dnsRecords {
|
||||
domainParts := strings.Split(dnsRecord, ".")
|
||||
slices.Reverse(domainParts)
|
||||
if len(domainParts) >= 3 && len(domainParts) <= 5 {
|
||||
if domainParts[0] == "page" && domainParts[1] == "codeberg" {
|
||||
// map of domain names to allowed repository and branch:
|
||||
// * {username}.codeberg.page =>
|
||||
// https://codeberg.org/{username}/pages.git#main
|
||||
// * {reponame}.{username}.codeberg.page =>
|
||||
// https://codeberg.org/{username}/{reponame}.git#pages
|
||||
// * {branch}.{reponame}.{username}.codeberg.page =>
|
||||
// https://codeberg.org/{username}/{reponame}.git#{branch}
|
||||
username := domainParts[2]
|
||||
reponame := "pages"
|
||||
branch := "main"
|
||||
if len(domainParts) >= 4 {
|
||||
reponame = domainParts[3]
|
||||
branch = "pages"
|
||||
}
|
||||
if len(domainParts) == 5 {
|
||||
branch = domainParts[4]
|
||||
}
|
||||
return &Authorization{
|
||||
repoURLs: []string{
|
||||
fmt.Sprintf("https://codeberg.org/%s/%s.git", username, reponame),
|
||||
},
|
||||
branch: branch,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, AuthError{
|
||||
http.StatusUnauthorized,
|
||||
fmt.Sprintf("domain %s does not have Codeberg Pages TXT or CNAME records", host),
|
||||
}
|
||||
}
|
||||
|
||||
func AuthorizeMetadataRetrieval(r *http.Request) (*Authorization, error) {
|
||||
causes := []error{AuthError{http.StatusUnauthorized, "unauthorized"}}
|
||||
|
||||
@@ -325,6 +391,19 @@ func AuthorizeUpdateFromRepository(r *http.Request) (*Authorization, error) {
|
||||
return auth, nil
|
||||
}
|
||||
}
|
||||
|
||||
if config.Feature("codeberg-pages-compat") {
|
||||
auth, err = authorizeCodebergPagesV2(r)
|
||||
if err != nil && IsUnauthorized(err) {
|
||||
causes = append(causes, err)
|
||||
} else if err != nil { // bad request
|
||||
return nil, err
|
||||
} else {
|
||||
log.Printf("auth: codeberg %s: allow %v branch %s\n",
|
||||
r.Host, auth.repoURLs, auth.branch)
|
||||
return auth, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.Join(causes...)
|
||||
|
||||
10
src/pages.go
10
src/pages.go
@@ -412,9 +412,11 @@ func postPage(w http.ResponseWriter, r *http.Request) error {
|
||||
}
|
||||
|
||||
eventRef := event["ref"].(string)
|
||||
if eventRef != "refs/heads/pages" {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprintf(w, "ignored %s\n", eventRef)
|
||||
if eventRef != fmt.Sprintf("refs/heads/%s", auth.branch) {
|
||||
http.Error(w,
|
||||
fmt.Sprintf("ref %s not in allowlist [refs/heads/%v])",
|
||||
eventRef, auth.branch),
|
||||
http.StatusUnauthorized)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -425,7 +427,7 @@ func postPage(w http.ResponseWriter, r *http.Request) error {
|
||||
|
||||
ctx, cancel := context.WithTimeout(r.Context(), time.Duration(config.Limits.UpdateTimeout))
|
||||
defer cancel()
|
||||
result := UpdateFromRepository(ctx, webRoot, repoURL, "pages")
|
||||
result := UpdateFromRepository(ctx, webRoot, repoURL, auth.branch)
|
||||
switch result.outcome {
|
||||
case UpdateError:
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
|
||||
Reference in New Issue
Block a user