mirror of
https://codeberg.org/Codeberg/pages-server.git
synced 2025-05-12 04:57:50 +00:00
105 lines
3.5 KiB
Go
105 lines
3.5 KiB
Go
package upstream
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
|
|
"codeberg.org/codeberg/pages/server/cache"
|
|
"codeberg.org/codeberg/pages/server/gitea"
|
|
)
|
|
|
|
// canonicalDomainCacheTimeout specifies the timeout for the canonical domain cache.
|
|
var canonicalDomainCacheTimeout = 15 * time.Minute
|
|
|
|
// CheckCanonicalDomain returns the canonical domain specified in the repo (using the `.domains` file).
|
|
func (o *Options) CheckCanonicalDomain(giteaClient *gitea.Client, actualDomain, mainDomainSuffix string, canonicalDomainConfigs []string, canonicalDomainCache cache.ICache) (domain string, valid bool) {
|
|
canonicalDomainCacheKey := o.TargetOwner + "/" + o.TargetRepo + "/" + o.TargetBranch + "/(" + strings.Join(canonicalDomainConfigs, "|") + ")"
|
|
|
|
var domains []string
|
|
|
|
// Check if this request is cached.
|
|
if cachedValue, ok := canonicalDomainCache.Get(canonicalDomainCacheKey); ok {
|
|
domains = cachedValue.([]string)
|
|
} else {
|
|
// Create cache entry for future invocations.
|
|
domains = o.canonicalDomainList(giteaClient, mainDomainSuffix, canonicalDomainConfigs)
|
|
|
|
// Add result to cache.
|
|
_ = canonicalDomainCache.Set(canonicalDomainCacheKey, domains, canonicalDomainCacheTimeout)
|
|
}
|
|
|
|
for _, domain := range domains {
|
|
if domain == actualDomain {
|
|
valid = true
|
|
break
|
|
}
|
|
}
|
|
|
|
// Return the first domain from the list and return if any of the domains
|
|
// matched the requested domain.
|
|
return domains[0], valid
|
|
}
|
|
|
|
// canonicalDomainList returns a list of normalized canonical domains as reported by the repository being served.
|
|
func (o *Options) canonicalDomainList(giteaClient *gitea.Client, mainDomainSuffix string, canonicalDomainConfigs []string) []string {
|
|
domainConfigMerge := ""
|
|
|
|
for _, canonicalDomainConfig := range canonicalDomainConfigs {
|
|
body, err := giteaClient.GiteaRawContent(o.TargetOwner, o.TargetRepo, o.TargetBranch, canonicalDomainConfig)
|
|
if err != nil && !errors.Is(err, gitea.ErrorNotFound) {
|
|
log.Error().Err(err).Msgf("could not read %s of %s/%s", canonicalDomainConfig, o.TargetOwner, o.TargetRepo)
|
|
continue
|
|
}
|
|
|
|
// Ensures files that don't end with a `\n` don't cause domains to be concatenated when combining files.
|
|
domainConfigMerge = domainConfigMerge + "\n" + string(body)
|
|
}
|
|
|
|
domains := normalizeDomainEntries(domainConfigMerge)
|
|
|
|
// Add [owner].[pages-domain] as valid domain.
|
|
domains = append(domains, o.pageMainDomain(mainDomainSuffix))
|
|
|
|
return domains
|
|
}
|
|
|
|
// pageMainDomain returns the [owner].[pages-domain] domain.
|
|
func (o *Options) pageMainDomain(mainDomainSuffix string) string {
|
|
pageMainDomain := o.TargetOwner + mainDomainSuffix
|
|
|
|
// If the target repository isn't called pages, add `/[repository]` to the
|
|
// previous valid domain.
|
|
if o.TargetRepo != "" && o.TargetRepo != "pages" {
|
|
pageMainDomain += "/" + o.TargetRepo
|
|
}
|
|
|
|
return pageMainDomain
|
|
}
|
|
|
|
// normalizeDomainEntries returns a list of domains, ill formatted domains are skipped.
|
|
// domainEntries is a new-line separated list of domains.
|
|
func normalizeDomainEntries(domainEntries string) []string {
|
|
domains := []string{}
|
|
|
|
for _, domain := range strings.Split(domainEntries, "\n") {
|
|
domain = strings.ToLower(domain)
|
|
domain = strings.TrimSpace(domain)
|
|
domain = strings.TrimPrefix(domain, "http://")
|
|
domain = strings.TrimPrefix(domain, "https://")
|
|
|
|
// Skip blank lines.
|
|
// Skip commented lines.
|
|
// Skip poorly formatted lines.
|
|
// Skip domains without '.'.
|
|
if domain == "" || strings.HasPrefix(domain, "#") || strings.ContainsAny(domain, "\t /") || !strings.ContainsRune(domain, '.') {
|
|
continue
|
|
}
|
|
|
|
domains = append(domains, domain)
|
|
}
|
|
|
|
return domains
|
|
}
|