mirror of
https://codeberg.org/git-pages/git-pages.git
synced 2026-05-14 03:01:48 +00:00
Add a relaxed-idna feature to allow some uses of _ in hostnames.
This is added to aid migration from Codeberg Pages v2. Forgejo allows both `_` and `-` in usernames, and it is necessary to be able to accept host names like `user_name.codeberg.page` under a wildcard domain. (It is not possible to get a TLS certificate for a host name like this, so only a wildcard certificate will be able to cover it.)
This commit is contained in:
@@ -28,6 +28,9 @@ jobs:
|
||||
- name: Build service
|
||||
run: |
|
||||
go build
|
||||
- name: Run tests
|
||||
run: |
|
||||
go test ./src
|
||||
- name: Run static analysis
|
||||
run: |
|
||||
go vet
|
||||
|
||||
21
src/auth.go
21
src/auth.go
@@ -54,12 +54,25 @@ func GetHost(r *http.Request) (string, error) {
|
||||
// this also rejects invalid characters and labels
|
||||
host, err = idnaProfile.ToASCII(host)
|
||||
if err != nil {
|
||||
return "", AuthError{http.StatusBadRequest,
|
||||
fmt.Sprintf("malformed host name %q", host)}
|
||||
if config.Feature("relaxed-idna") {
|
||||
// unfortunately, the go IDNA library has some significant issues around its
|
||||
// Unicode TR46 implementation: https://github.com/golang/go/issues/76804
|
||||
// we would like to allow *just* the _ here, but adding `idna.StrictDomainName(false)`
|
||||
// would also accept domains like `*.foo.bar` which should clearly be disallowed.
|
||||
// as a workaround, accept a domain name if it is valid with all `_` characters
|
||||
// replaced with an alphanumeric character (we use `a`); this allows e.g. `foo_bar.xxx`
|
||||
// and `foo__bar.xxx`, as well as `_foo.xxx` and `foo_.xxx`. labels starting with
|
||||
// an underscore are explicitly rejected below.
|
||||
_, err = idnaProfile.ToASCII(strings.ReplaceAll(host, "_", "a"))
|
||||
}
|
||||
if err != nil {
|
||||
return "", AuthError{http.StatusBadRequest,
|
||||
fmt.Sprintf("malformed host name %q", host)}
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(host, ".") {
|
||||
if strings.HasPrefix(host, ".") || strings.HasPrefix(host, "_") {
|
||||
return "", AuthError{http.StatusBadRequest,
|
||||
fmt.Sprintf("host name %q is reserved", host)}
|
||||
fmt.Sprintf("reserved host name %q", host)}
|
||||
}
|
||||
host = strings.TrimSuffix(host, ".")
|
||||
return host, nil
|
||||
|
||||
55
src/pages_test.go
Normal file
55
src/pages_test.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package git_pages
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func checkHost(t *testing.T, host string, expectOk string, expectErr string) {
|
||||
host, err := GetHost(&http.Request{Host: host})
|
||||
if expectErr != "" {
|
||||
if err == nil || !strings.HasPrefix(err.Error(), expectErr) {
|
||||
t.Errorf("%s: expect err %s, got err %s", host, expectErr, err)
|
||||
}
|
||||
}
|
||||
if expectOk != "" {
|
||||
if err != nil {
|
||||
t.Errorf("%s: expect ok %s, got err %s", host, expectOk, err)
|
||||
} else if host != expectOk {
|
||||
t.Errorf("%s: expect ok %s, got ok %s", host, expectOk, host)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHelloName(t *testing.T) {
|
||||
config = &Config{Features: []string{}}
|
||||
|
||||
checkHost(t, "foo.bar", "foo.bar", "")
|
||||
checkHost(t, "foo-baz.bar", "foo-baz.bar", "")
|
||||
checkHost(t, "foo--baz.bar", "foo--baz.bar", "")
|
||||
checkHost(t, "foo.bar.", "foo.bar", "")
|
||||
checkHost(t, ".foo.bar", "", "reserved host name")
|
||||
checkHost(t, "..foo.bar", "", "reserved host name")
|
||||
|
||||
checkHost(t, "ß.bar", "xn--zca.bar", "")
|
||||
checkHost(t, "xn--zca.bar", "xn--zca.bar", "")
|
||||
|
||||
checkHost(t, "foo-.bar", "", "malformed host name")
|
||||
checkHost(t, "-foo.bar", "", "malformed host name")
|
||||
checkHost(t, "foo_.bar", "", "malformed host name")
|
||||
checkHost(t, "_foo.bar", "", "malformed host name")
|
||||
checkHost(t, "foo_baz.bar", "", "malformed host name")
|
||||
checkHost(t, "foo__baz.bar", "", "malformed host name")
|
||||
checkHost(t, "*.foo.bar", "", "malformed host name")
|
||||
|
||||
config = &Config{Features: []string{"relaxed-idna"}}
|
||||
|
||||
checkHost(t, "foo-.bar", "", "malformed host name")
|
||||
checkHost(t, "-foo.bar", "", "malformed host name")
|
||||
checkHost(t, "foo_.bar", "foo_.bar", "")
|
||||
checkHost(t, "_foo.bar", "", "reserved host name")
|
||||
checkHost(t, "foo_baz.bar", "foo_baz.bar", "")
|
||||
checkHost(t, "foo__baz.bar", "foo__baz.bar", "")
|
||||
checkHost(t, "*.foo.bar", "", "malformed host name")
|
||||
}
|
||||
Reference in New Issue
Block a user