From 8b8431201b4bd6e46851f978044f8a06647d2b6b Mon Sep 17 00:00:00 2001 From: Catherine Date: Tue, 16 Sep 2025 15:57:02 +0000 Subject: [PATCH] Allow `Authorization: Basic` as a fallback for GitHub, etc. --- README.md | 2 +- src/auth.go | 26 +++++++++++++++++++++++++- src/pages.go | 7 ------- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 328d474..56cc630 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ DNS is used for authorization of content updates. - If a `[wildcard]` configuration section is specified, and if the suffix of a hostname in a `POST` request is equal to `[wildcard].domain`, then the request is authorized when and only when the repository URL in the event body matches the repository URL computed from the configuration file. Otherwise the next rule is used. -- If a `PUT` or `POST` request is received at `` with an `Authorization: Pages ` header (or, in absence of such, with an `?Authorization=Pages+` query parameter), then the request is authorized when any of the the TXT records at `_git-pages-challenge.` are equal to `SHA256(" ")`. +- If a `PUT` or `POST` request is received at `` with an `Authorization: Pages ` header (or, in absence of such, with an `Authorization: Basic ` header, where `` is equal to `Base64("Pages ")`), then the request is authorized when any of the the TXT records at `_git-pages-challenge.` are equal to `SHA256(" ")`. Architecture diff --git a/src/auth.go b/src/auth.go index 37955a8..6f71023 100644 --- a/src/auth.go +++ b/src/auth.go @@ -2,6 +2,7 @@ package main import ( "crypto/sha256" + "encoding/base64" "fmt" "net" "net/http" @@ -34,11 +35,34 @@ func Authorize(w http.ResponseWriter, r *http.Request) error { return fmt.Errorf("malformed Authorization header") } - if scheme != "Pages" { + if scheme != "Pages" && scheme != "Basic" { http.Error(w, "unknown Authorization scheme", http.StatusBadRequest) return fmt.Errorf("unknown Authorization scheme") } + // services like GitHub and Gogs cannot send a custom Authorization: header, but supplying + // username and password in the URL is basically just as good + if scheme == "Basic" { + basicParam, err := base64.StdEncoding.DecodeString(param) + if err != nil { + http.Error(w, "malformed Authorization: Basic header", http.StatusBadRequest) + return fmt.Errorf("malformed Authorization: Basic header") + } + + username, password, found := strings.Cut(string(basicParam), ":") + if !found { + http.Error(w, "malformed Authorization: Basic parameter", http.StatusBadRequest) + return fmt.Errorf("malformed Authorization: Basic parameter") + } + + if username != "Pages" { + http.Error(w, "unexpected Authorization: Basic username", http.StatusUnauthorized) + return fmt.Errorf("unexpected Authorization: Basic username") + } + + param = password + } + challengeHostname := fmt.Sprintf("_git-pages-challenge.%s", host) actualChallenges, err := net.LookupTXT(challengeHostname) if err != nil { diff --git a/src/pages.go b/src/pages.go index 1a90c5d..ad61b27 100644 --- a/src/pages.go +++ b/src/pages.go @@ -196,13 +196,6 @@ func postPage(w http.ResponseWriter, r *http.Request) error { } allowRepoURL = fmt.Sprintf(config.Wildcard.CloneURL, userName, repoName) } else { - // GitHub and Gogs cannot supply an `Authorization:` header. - if r.Header.Get("Authorization") == "" { - if value := r.URL.Query().Get("Authorization"); value != "" { - r.Header.Set("Authorization", value) - } - } - if err := Authorize(w, r); err != nil { return err }