challenge: implement IPv6 Happy Eyeballs again, use errors to detect this within challenge, cleanup referrer tags

This commit is contained in:
WeebDataHoarder
2025-04-27 18:49:58 +02:00
parent 06c363e55a
commit 666ffa574a

View File

@@ -8,18 +8,33 @@ import (
"git.gammaspectra.live/git/go-away/utils"
"net/http"
"net/url"
"strings"
)
var ErrInvalidToken = errors.New("invalid token")
var ErrMismatchedToken = errors.New("mismatched token")
var ErrMismatchedTokenHappyEyeballs = errors.New("mismatched token: IPv4 to IPv6 upgrade detected, retrying")
func NewKeyVerifier() (verify VerifyFunc, issue func(key Key) string) {
return func(key Key, token []byte, r *http.Request) (VerifyResult, error) {
expectedKey, err := hex.DecodeString(string(token))
if err != nil {
return VerifyResultFail, err
}
if len(expectedKey) != KeySize {
return VerifyResultFail, ErrInvalidToken
}
if subtle.ConstantTimeCompare(key[:], expectedKey) == 1 {
return VerifyResultOK, nil
}
return VerifyResultFail, errors.New("mismatched token")
kk := Key(expectedKey)
// IPv4 -> IPv6 Happy Eyeballs
if key.Get(KeyFlagIsIPv4) == 0 && kk.Get(KeyFlagIsIPv4) > 0 {
return VerifyResultOK, ErrMismatchedTokenHappyEyeballs
}
return VerifyResultFail, ErrMismatchedToken
}, func(key Key) string {
return hex.EncodeToString(key[:])
}
@@ -95,7 +110,9 @@ func RedirectUrl(r *http.Request, reg *Registration) (*url.URL, error) {
data := RequestDataFromContext(r.Context())
values := uri.Query()
values.Set(QueryArgRequestId, data.Id.String())
values.Set(QueryArgReferer, r.Referer())
if ref := r.Referer(); ref != "" {
values.Set(QueryArgReferer, r.Referer())
}
values.Set(QueryArgChallenge, reg.Name)
uri.RawQuery = values.Encode()
@@ -104,6 +121,26 @@ func RedirectUrl(r *http.Request, reg *Registration) (*url.URL, error) {
func VerifyHandlerChallengeResponseFunc(state StateInterface, data *RequestData, w http.ResponseWriter, r *http.Request, verifyResult VerifyResult, err error, redirect string) {
if err != nil {
// Happy Eyeballs! auto retry
if errors.Is(err, ErrMismatchedTokenHappyEyeballs) {
reqUri := *r.URL
q := reqUri.Query()
ref := q.Get(QueryArgReferer)
// delete query parameters that were set by go-away
for k := range q {
if strings.HasPrefix(k, QueryArgPrefix) {
q.Del(k)
}
}
if ref != "" {
q.Set(QueryArgReferer, ref)
}
reqUri.RawQuery = q.Encode()
http.Redirect(w, r, reqUri.String(), http.StatusTemporaryRedirect)
return
}
state.ErrorPage(w, r, http.StatusBadRequest, err, redirect)
return
} else if !verifyResult.Ok() {