This commit is contained in:
@@ -23,6 +23,7 @@ const (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Onboarding OnboardingConfig
|
||||
VikingResourceID string
|
||||
VikingCollectionName string
|
||||
VikingAPIKey string
|
||||
@@ -254,6 +255,7 @@ func Load(serviceName string) (Config, error) {
|
||||
}
|
||||
environment := stringEnv("APP_ENV", EnvironmentLocal)
|
||||
secretValues, err := loadSecretValues(
|
||||
"ONBOARDING_MASTER_KEY", "ONBOARDING_SMS_GATEWAY_TOKEN",
|
||||
"DATABASE_URL", "REDIS_PASSWORD", "DEVICE_LOCAL_SECRET", "DEVICE_CREDENTIAL_MASTER_KEY", "MODEL_CREDENTIAL_MASTER_KEY", "RTC_APP_KEY", "RTC_TOKEN_SIGNING_SECRET",
|
||||
"CURSOR_SIGNING_SECRET", "SHARE_TOKEN_SIGNING_SECRET", "PROVIDER_CALLBACK_SECRET", "PLATFORM_HEALTH_CALLBACK_SECRET",
|
||||
"VOLC_SUBTITLE_CALLBACK_SECRET", "VIKING_MEMORY_API_KEY",
|
||||
@@ -485,6 +487,10 @@ func Load(serviceName string) (Config, error) {
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
cfg.Onboarding, err = loadOnboardingConfig(secretValues)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
if err := cfg.Validate(); err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
@@ -492,6 +498,9 @@ func Load(serviceName string) (Config, error) {
|
||||
}
|
||||
|
||||
func (c Config) Validate() error {
|
||||
if err := c.Onboarding.validate(c.Environment); err != nil {
|
||||
return err
|
||||
}
|
||||
if c.SubtitleCallbackURL != "" || c.SubtitleCallbackSecret != "" || c.SubtitlePrimary {
|
||||
u, err := url.Parse(c.SubtitleCallbackURL)
|
||||
if err != nil || u.Scheme != "https" || u.Host == "" || u.RawQuery != "" || u.Fragment != "" || u.User != nil || len(c.SubtitleCallbackSecret) < 32 {
|
||||
@@ -607,7 +616,7 @@ func (c Config) Validate() error {
|
||||
if c.VolcHardwareTransport != "high_quality" && c.VolcHardwareTransport != "low_load" {
|
||||
return errors.New("VOLC_HARDWARE_AGENT_TRANSPORT must be high_quality or low_load")
|
||||
}
|
||||
if c.ServiceName == "api" && c.VolcHardwareProvisioningEnabled {
|
||||
if (c.ServiceName == "api" && c.VolcHardwareProvisioningEnabled) || ((c.ServiceName == "api" || c.ServiceName == "worker") && c.Onboarding.ActivationEnabled) {
|
||||
providerKey, err := hex.DecodeString(c.VolcHardwareDeviceCredentialMasterKey)
|
||||
if err != nil || len(providerKey) != 32 {
|
||||
return errors.New("VOLC_HARDWARE_DEVICE_CREDENTIAL_MASTER_KEY must be 32 bytes encoded as 64 hexadecimal characters")
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"github.com/google/uuid"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type OnboardingConfig struct {
|
||||
Enabled, PauseClaims, ActivationEnabled, SMSLoginEnabled, AllowLocalHTTP bool
|
||||
MasterKey, EntryURL, SMSGatewayURL, SMSGatewayToken string
|
||||
TrustedProxyCIDRs, SelfSignupTenantIDs []string
|
||||
}
|
||||
|
||||
func loadOnboardingConfig(secrets map[string]string) (OnboardingConfig, error) {
|
||||
c := OnboardingConfig{MasterKey: secrets["ONBOARDING_MASTER_KEY"], SMSGatewayToken: secrets["ONBOARDING_SMS_GATEWAY_TOKEN"], EntryURL: strings.TrimSpace(os.Getenv("ONBOARDING_ENTRY_URL")), SMSGatewayURL: strings.TrimSpace(os.Getenv("ONBOARDING_SMS_GATEWAY_URL"))}
|
||||
for name, target := range map[string]*bool{"ONBOARDING_ENABLED": &c.Enabled, "ONBOARDING_PAUSE_CLAIMS": &c.PauseClaims, "ONBOARDING_ACTIVATION_ENABLED": &c.ActivationEnabled, "ONBOARDING_SMS_LOGIN_ENABLED": &c.SMSLoginEnabled, "ONBOARDING_ALLOW_LOCAL_HTTP": &c.AllowLocalHTTP} {
|
||||
v, err := boolEnv(name, false)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
*target = v
|
||||
}
|
||||
split := func(name string) []string {
|
||||
items := []string{}
|
||||
for _, v := range strings.Split(os.Getenv(name), ",") {
|
||||
if strings.TrimSpace(v) != "" {
|
||||
items = append(items, strings.TrimSpace(v))
|
||||
}
|
||||
}
|
||||
return items
|
||||
}
|
||||
c.TrustedProxyCIDRs = split("ONBOARDING_TRUSTED_PROXY_CIDRS")
|
||||
c.SelfSignupTenantIDs = split("ONBOARDING_SELF_SIGNUP_TENANT_IDS")
|
||||
return c, nil
|
||||
}
|
||||
func (c OnboardingConfig) validate(environment string) error {
|
||||
if c.AllowLocalHTTP && environment != EnvironmentLocal && environment != EnvironmentTest {
|
||||
return errors.New("ONBOARDING_ALLOW_LOCAL_HTTP is limited to local/test")
|
||||
}
|
||||
if c.MasterKey == "" {
|
||||
if c.Enabled || c.ActivationEnabled || c.SMSLoginEnabled {
|
||||
return errors.New("onboarding requires ONBOARDING_MASTER_KEY")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
key, err := hex.DecodeString(c.MasterKey)
|
||||
if err != nil || len(key) != 32 {
|
||||
return errors.New("ONBOARDING_MASTER_KEY must encode 32 bytes as hex")
|
||||
}
|
||||
u, err := url.Parse(c.EntryURL)
|
||||
if err != nil || u.Host == "" || u.User != nil || u.RawQuery != "" || u.Fragment != "" || (u.Scheme != "https" && !(c.AllowLocalHTTP && u.Scheme == "http" && (u.Hostname() == "localhost" || u.Hostname() == "127.0.0.1"))) {
|
||||
return errors.New("ONBOARDING_ENTRY_URL must be a fixed HTTPS URL")
|
||||
}
|
||||
for _, cidr := range c.TrustedProxyCIDRs {
|
||||
p, err := netip.ParsePrefix(cidr)
|
||||
if err != nil || p.Bits() == 0 {
|
||||
return errors.New("onboarding trusted proxies must be explicit non-global CIDRs")
|
||||
}
|
||||
}
|
||||
for _, id := range c.SelfSignupTenantIDs {
|
||||
if _, err := uuid.Parse(id); err != nil {
|
||||
return errors.New("onboarding signup tenants must be UUIDs")
|
||||
}
|
||||
}
|
||||
if c.SMSLoginEnabled {
|
||||
u, err := url.Parse(c.SMSGatewayURL)
|
||||
if err != nil || u.Scheme != "https" || u.Host == "" || u.User != nil || u.RawQuery != "" || u.Fragment != "" || c.SMSGatewayToken == "" {
|
||||
return errors.New("onboarding SMS requires HTTPS gateway and token")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user