43 lines
1.5 KiB
Go
43 lines
1.5 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"strings"
|
|
)
|
|
|
|
// DefaultThemeCatalogURL is the catalog fetched by the runtime when no
|
|
// override is stored. It is also part of the Admin settings effective-value
|
|
// contract, so the UI never has to duplicate or guess the active default.
|
|
const DefaultThemeCatalogURL = "https://raw.githubusercontent.com/Silo-Server/silo-themes/main/catalog.json"
|
|
|
|
var allowedThemeRemoteHosts = map[string]struct{}{
|
|
"raw.githubusercontent.com": {},
|
|
"github.com": {},
|
|
"objects.githubusercontent.com": {},
|
|
}
|
|
|
|
// ValidateThemeRemoteURL applies the shared allowlist used when accepting a
|
|
// catalog setting and when fetching theme resources. Keeping this contract in
|
|
// one package prevents the Admin UI from persisting a URL the runtime refuses.
|
|
func ValidateThemeRemoteURL(parsed *url.URL) error {
|
|
if parsed == nil || parsed.Scheme != "https" || parsed.Host == "" {
|
|
return url.InvalidHostError("theme URL must use HTTPS on an approved GitHub host")
|
|
}
|
|
if _, allowed := allowedThemeRemoteHosts[parsed.Hostname()]; !allowed {
|
|
return url.InvalidHostError("theme URL must use HTTPS on an approved GitHub host")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func normalizeAdminThemeURL(key, value string) (string, error) {
|
|
if value == "" {
|
|
return "", nil
|
|
}
|
|
parsed, err := url.Parse(value)
|
|
if err != nil || ValidateThemeRemoteURL(parsed) != nil {
|
|
return "", fmt.Errorf("%s must use HTTPS on an approved GitHub host", key)
|
|
}
|
|
return strings.TrimRight(value, "/"), nil
|
|
}
|