feat: expand companion platform, device controls, and memoir workflows
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:
Codex Local
2026-10-08 10:06:44 +08:00
parent 98fb2965d0
commit bf1233d5df
861 changed files with 94614 additions and 3209 deletions
+59 -6
View File
@@ -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