diff --git a/go.mod b/go.mod index 4ae7090..3b51ad2 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/yuin/goldmark-meta v1.1.0 golang.org/x/crypto v0.8.0 golang.org/x/exp v0.0.0-20230321023759-10a507213a29 + golang.org/x/net v0.9.0 golang.org/x/sync v0.1.0 golang.org/x/term v0.7.0 gopkg.in/yaml.v3 v3.0.1 @@ -63,8 +64,8 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect golang.org/x/mod v0.9.0 // indirect - golang.org/x/net v0.9.0 // indirect golang.org/x/sys v0.7.0 // indirect + golang.org/x/text v0.9.0 // indirect golang.org/x/time v0.1.0 // indirect golang.org/x/tools v0.7.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect diff --git a/go.sum b/go.sum index 3f88717..80cc7de 100644 --- a/go.sum +++ b/go.sum @@ -180,6 +180,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/internal/config/http.go b/internal/config/http.go index 81e5b97..fe8f90d 100644 --- a/internal/config/http.go +++ b/internal/config/http.go @@ -5,7 +5,7 @@ import ( "net/url" "strings" - "github.com/tkw1536/pkglib/collection" + "golang.org/x/net/idna" ) type HTTPConfig struct { @@ -80,10 +80,7 @@ func (hcfg HTTPConfig) Domains(sub string) []string { // HostRule returns a HostRule for the provided subdomain. // See Domains() for usage of sub. func (hcfg HTTPConfig) HostRule(sub string) string { - quoted := collection.MapSlice(hcfg.Domains(sub), func(name string) string { - return "`" + name + "`" - }) - return fmt.Sprintf("Host(%s)", strings.Join(quoted, ",")) + return MakeHostRule(hcfg.Domains(sub)...) } // HTTPSEnabledEnv returns "true" if https is enabled, and "false" otherwise. @@ -141,3 +138,36 @@ func TrimSuffixFold(s string, suffix string) string { func (cfg HTTPConfig) DefaultHostRule() string { return cfg.HostRule("") } + +// MakeHostRule builds a new Host() rule string to be used by traefik. +func MakeHostRule(hosts ...string) string { + var builder strings.Builder + + first := true + for _, host := range hosts { + // HACK HACK HACK: Very minimal domain validation to prevent validation. + // Just skip everything that isn't a domain. + if strings.Contains(host, "`") { + continue + } + + if first { + builder.WriteString("||Host(`") + } else { + builder.WriteString("Host(`") + } + + // domain should be punycode! + domain, err := idna.ToASCII(host) + if err != nil { + domain = host + } + + builder.WriteString(domain) + builder.WriteString("`)") + + first = false + } + + return builder.String() +} diff --git a/internal/wisski/ingredient/barrel/barrel.env b/internal/wisski/ingredient/barrel/barrel.env index 791e9ac..86c5d95 100644 --- a/internal/wisski/ingredient/barrel/barrel.env +++ b/internal/wisski/ingredient/barrel/barrel.env @@ -2,7 +2,8 @@ DATA_PATH=${DATA_PATH} RUNTIME_DIR=${RUNTIME_DIR} SLUG=${SLUG} -VIRTUAL_HOST=${VIRTUAL_HOST} +HOSTNAME=${HOSTNAME} +HOST_RULE=${HOST_RULE} DOCKER_NETWORK_NAME=${DOCKER_NETWORK_NAME} HTTPS_ENABLED=${HTTPS_ENABLED} \ No newline at end of file diff --git a/internal/wisski/ingredient/barrel/barrel/docker-compose.yml b/internal/wisski/ingredient/barrel/barrel/docker-compose.yml index 781235e..d0fcba2 100644 --- a/internal/wisski/ingredient/barrel/barrel/docker-compose.yml +++ b/internal/wisski/ingredient/barrel/barrel/docker-compose.yml @@ -4,14 +4,14 @@ services: barrel: build: . restart: always - hostname: ${VIRTUAL_HOST}.wisski + hostname: ${HOSTNAME} # label it with the current slug labels: - "traefik.enable=True" - "eu.wiss-ki.barrel.distillery=${DOCKER_NETWORK_NAME}" - - "traefik.http.routers.wisski_${SLUG}.rule=Host(`${VIRTUAL_HOST}`)" + - "traefik.http.routers.wisski_${SLUG}.rule=${HOST_RULE}" - "traefik.http.routers.wisski_${SLUG}.tls=${HTTPS_ENABLED}" - "traefik.http.routers.wisski_${SLUG}.tls.certresolver=distillery" - "traefik.http.services.wisski_${SLUG}.loadbalancer.server.port=8080" diff --git a/internal/wisski/ingredient/barrel/stack.go b/internal/wisski/ingredient/barrel/stack.go index 20991ad..01c1999 100644 --- a/internal/wisski/ingredient/barrel/stack.go +++ b/internal/wisski/ingredient/barrel/stack.go @@ -25,7 +25,8 @@ func (barrel *Barrel) Stack() component.StackWithResources { "DOCKER_NETWORK_NAME": barrel.Malt.Config.Docker.Network(), "SLUG": barrel.Slug, - "VIRTUAL_HOST": barrel.Domain(), + "HOST_RULE": barrel.HostRule(), + "HOSTNAME": barrel.Hostname(), "HTTPS_ENABLED": barrel.Malt.Config.HTTP.HTTPSEnabledEnv(), "DATA_PATH": filepath.Join(barrel.FilesystemBase, "data"), diff --git a/internal/wisski/ingredient/reserve/reserve.env b/internal/wisski/ingredient/reserve/reserve.env index b72c195..159fcd5 100644 --- a/internal/wisski/ingredient/reserve/reserve.env +++ b/internal/wisski/ingredient/reserve/reserve.env @@ -1,5 +1,5 @@ SLUG=${SLUG} -VIRTUAL_HOST=${VIRTUAL_HOST} +HOST_RULE=${HOST_RULE} DOCKER_NETWORK_NAME=${DOCKER_NETWORK_NAME} HTTPS_ENABLED=${HTTPS_ENABLED} diff --git a/internal/wisski/ingredient/reserve/reserve.go b/internal/wisski/ingredient/reserve/reserve.go index 172cdc8..7999cd3 100644 --- a/internal/wisski/ingredient/reserve/reserve.go +++ b/internal/wisski/ingredient/reserve/reserve.go @@ -32,7 +32,8 @@ func (reserve *Reserve) Stack() component.StackWithResources { "DOCKER_NETWORK_NAME": reserve.Malt.Config.Docker.Network(), "SLUG": reserve.Slug, - "VIRTUAL_HOST": reserve.Domain(), + "HOST_RULE": reserve.HostRule(), + "HOSTNAME": reserve.Hostname(), "HTTPS_ENABLED": reserve.Malt.Config.HTTP.HTTPSEnabledEnv(), }, } diff --git a/internal/wisski/ingredient/reserve/reserve/docker-compose.yml b/internal/wisski/ingredient/reserve/reserve/docker-compose.yml index acb2e42..17d2dca 100644 --- a/internal/wisski/ingredient/reserve/reserve/docker-compose.yml +++ b/internal/wisski/ingredient/reserve/reserve/docker-compose.yml @@ -11,7 +11,7 @@ services: - "traefik.enable=True" - "eu.wiss-ki.barrel.distillery=${DOCKER_NETWORK_NAME}" - - "traefik.http.routers.reserve_${SLUG}.rule=Host(`${VIRTUAL_HOST}`)" + - "traefik.http.routers.reserve_${SLUG}.rule=${HOST_RULE}" - "traefik.http.routers.reserve_${SLUG}.tls=${HTTPS_ENABLED}" - "traefik.http.routers.reserve_${SLUG}.tls.certresolver=distillery" - "traefik.http.services.reserve_${SLUG}.loadbalancer.server.port=8043" diff --git a/internal/wisski/liquid/domain.go b/internal/wisski/liquid/domain.go index 7f174c8..ed062cf 100644 --- a/internal/wisski/liquid/domain.go +++ b/internal/wisski/liquid/domain.go @@ -2,6 +2,8 @@ package liquid import ( "net/url" + + "github.com/FAU-CDI/wisski-distillery/internal/config" ) // Domain returns the full domain name of this WissKI @@ -9,6 +11,15 @@ func (liquid *Liquid) Domain() string { return liquid.Config.HTTP.HostFromSlug(liquid.Slug) } +func (liquid *Liquid) Hostname() string { + return liquid.Domain() + ".wisski" +} + +// HostRule returns a host rule for this wisski +func (liquid *Liquid) HostRule() string { + return config.MakeHostRule(liquid.Domain()) +} + // URL returns the public URL of this instance func (liquid *Liquid) URL() *url.URL { // setup domain and path