feat: expand companion platform, device controls, and memoir workflows
ci / verify (push) Canceled after 0s
ci / verify (push) Canceled after 0s
Add customer and operator login, BLE provisioning, device fleet controls, call memory, memoir generation, and refreshed family and maintenance portals. Include API contracts, migrations, firmware sources, tests, assets, and deployment documentation.
This commit is contained in:
@@ -7,18 +7,30 @@ import (
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var smsNumericID = regexp.MustCompile(`^[0-9]+$`)
|
||||
|
||||
type OnboardingConfig struct {
|
||||
SaaSCaptchaDisabled bool
|
||||
TencentCaptcha TencentCaptchaConfig
|
||||
TencentSMSTemplateParams map[string][]string
|
||||
Enabled, PauseClaims, ActivationEnabled, SMSLoginEnabled, AllowLocalHTTP bool
|
||||
MasterKey, EntryURL, SMSGatewayURL, SMSGatewayToken string
|
||||
MasterKey, EntryURL, SMSGatewayURL, SMSGatewayToken, SMSProvider string
|
||||
TencentSMSSecretID, TencentSMSSecretKey, TencentSMSAppID string
|
||||
TencentSMSSignName, TencentSMSTemplateID string
|
||||
TencentSMSTemplates map[string]string
|
||||
WeChatAppID, WeChatAppSecret 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} {
|
||||
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")), SMSProvider: strings.TrimSpace(os.Getenv("ONBOARDING_SMS_PROVIDER")), TencentSMSSecretID: secrets["TENCENT_SMS_SECRET_ID"], TencentSMSSecretKey: secrets["TENCENT_SMS_SECRET_KEY"], TencentSMSAppID: strings.TrimSpace(os.Getenv("TENCENT_SMS_SDK_APP_ID")), TencentSMSSignName: strings.TrimSpace(os.Getenv("TENCENT_SMS_SIGN_NAME")), TencentSMSTemplateID: strings.TrimSpace(os.Getenv("TENCENT_SMS_TEMPLATE_ID"))}
|
||||
c.WeChatAppID = strings.TrimSpace(os.Getenv("WECHAT_MINI_APP_ID"))
|
||||
c.WeChatAppSecret = secrets["WECHAT_MINI_APP_SECRET"]
|
||||
for name, target := range map[string]*bool{"ONBOARDING_SAAS_CAPTCHA_DISABLED": &c.SaaSCaptchaDisabled, "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
|
||||
@@ -39,6 +51,14 @@ func loadOnboardingConfig(secrets map[string]string) (OnboardingConfig, error) {
|
||||
return c, nil
|
||||
}
|
||||
func (c OnboardingConfig) validate(environment string) error {
|
||||
if c.WeChatAppSecret != "" {
|
||||
if len(c.WeChatAppID) != 18 || !strings.HasPrefix(c.WeChatAppID, "wx") || len(c.WeChatAppSecret) < 16 {
|
||||
return errors.New("WeChat login requires WECHAT_MINI_APP_ID and WECHAT_MINI_APP_SECRET")
|
||||
}
|
||||
if _, err := hex.DecodeString(c.WeChatAppID[2:]); err != nil {
|
||||
return errors.New("invalid WECHAT_MINI_APP_ID")
|
||||
}
|
||||
}
|
||||
if c.AllowLocalHTTP && environment != EnvironmentLocal && environment != EnvironmentTest {
|
||||
return errors.New("ONBOARDING_ALLOW_LOCAL_HTTP is limited to local/test")
|
||||
}
|
||||
@@ -68,9 +88,42 @@ func (c OnboardingConfig) validate(environment string) error {
|
||||
}
|
||||
}
|
||||
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")
|
||||
switch c.SMSProvider {
|
||||
case "", "gateway":
|
||||
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")
|
||||
}
|
||||
case "tencent":
|
||||
if c.TencentSMSSecretID == "" || c.TencentSMSSecretKey == "" || !smsNumericID.MatchString(c.TencentSMSAppID) || c.TencentSMSSignName == "" {
|
||||
return errors.New("Tencent SMS requires SecretId, SecretKey, SDK AppID and sign name")
|
||||
}
|
||||
if c.TencentSMSTemplates != nil {
|
||||
for _, name := range []string{"login", "register", "change_password", "change_phone"} {
|
||||
if !smsNumericID.MatchString(c.TencentSMSTemplates[name]) {
|
||||
return errors.New("Tencent SMS requires numeric login, register, change_password and change_phone template IDs")
|
||||
}
|
||||
}
|
||||
} else if !smsNumericID.MatchString(c.TencentSMSTemplateID) {
|
||||
return errors.New("Tencent SMS requires a numeric template ID")
|
||||
}
|
||||
for name, params := range c.TencentSMSTemplateParams {
|
||||
if name != "login" && name != "register" && name != "change_password" && name != "change_phone" {
|
||||
return errors.New("Tencent SMS template_params contains an unknown purpose")
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
for _, value := range params {
|
||||
if (value != "code" && value != "expires_minutes") || seen[value] {
|
||||
return errors.New("Tencent SMS template_params must contain code and optionally expires_minutes without duplicates")
|
||||
}
|
||||
seen[value] = true
|
||||
}
|
||||
if !seen["code"] {
|
||||
return errors.New("Tencent SMS template_params must include code")
|
||||
}
|
||||
}
|
||||
default:
|
||||
return errors.New("ONBOARDING_SMS_PROVIDER must be gateway or tencent")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user