package config import ( "os" "path/filepath" "strings" "testing" ) const validTencentSMSJSON = `{"enabled":true,"secret_id":"fixture-id","secret_key":"fixture-private-key","sdk_app_id":"1400006666","sign_name":"安芯伴","templates":{"login":"101","register":"102","change_password":"103","change_phone":"104"}}` func smsConfigFixture(t *testing.T, content string) string { t.Helper() path := filepath.Join(t.TempDir(), "tencent-sms.json") if err := os.WriteFile(path, []byte(content), 0600); err != nil { t.Fatal(err) } return path } func TestTencentSMSFileLoadsAllTemplatesAndOverridesLegacyConfiguration(t *testing.T) { c := OnboardingConfig{MasterKey: strings.Repeat("ab", 32), EntryURL: "https://platform.example/onboarding/entry", SMSProvider: "gateway", TencentSMSTemplateID: "old"} t.Setenv("TENCENT_SMS_CONFIG_FILE", smsConfigFixture(t, "\xef\xbb\xbf"+validTencentSMSJSON)) if err := c.loadTencentSMSFile("api"); err != nil { t.Fatal(err) } if err := c.validate(EnvironmentProd); err != nil { t.Fatal(err) } if !c.SMSLoginEnabled || c.SMSProvider != "tencent" || c.TencentSMSSecretKey != "fixture-private-key" || c.TencentSMSTemplateID != "" || c.TencentSMSTemplates["change_phone"] != "104" { t.Fatal("single-file settings did not take precedence") } if err := c.readTencentSMSFile(smsConfigFixture(t, strings.Replace(validTencentSMSJSON, `"enabled":true`, `"enabled":false`, 1)), true); err != nil || c.SMSLoginEnabled { t.Fatal("file could not disable SMS") } } func TestTencentSMSFileRejectsBrokenConfigurationWithoutLeakingSecrets(t *testing.T) { for _, raw := range []string{ validTencentSMSJSON + `{}`, strings.Replace(validTencentSMSJSON, `"enabled":true,`, "", 1), strings.Replace(validTencentSMSJSON, `"secret_key"`, `"fixture-private-key"`, 1), strings.Replace(validTencentSMSJSON, `"change_phone"`, `"fixture-private-key"`, 1), strings.Replace(validTencentSMSJSON, `"104"`, `"not-an-id"`, 1), strings.Replace(validTencentSMSJSON, `,"change_phone":"104"`, "", 1), } { c := OnboardingConfig{MasterKey: strings.Repeat("ab", 32), EntryURL: "https://platform.example/onboarding/entry"} err := c.readTencentSMSFile(smsConfigFixture(t, raw), true) if err == nil { err = c.validate(EnvironmentProd) } if err == nil || strings.Contains(err.Error(), "fixture-private-key") { t.Fatal("invalid configuration accepted or secret exposed in error") } } } func TestTencentSMSFileMissingAndNonSMSServiceBehavior(t *testing.T) { path := filepath.Join(t.TempDir(), "missing.json") c := OnboardingConfig{} if err := c.readTencentSMSFile(path, false); err != nil { t.Fatal("absent optional file broke existing deployments", err) } t.Setenv("TENCENT_SMS_CONFIG_FILE", path) if err := c.loadTencentSMSFile("api"); err == nil { t.Fatal("explicit missing configuration silently ignored") } if err := c.loadTencentSMSFile("callbacks"); err != nil || c.SMSLoginEnabled { t.Fatal("SMS file affected callbacks service") } } func TestTencentSMSFileTemplateParameterOrder(t *testing.T) { raw := strings.TrimSuffix(validTencentSMSJSON, "}") + `,"template_params":{"register":["code","expires_minutes"]}}` c := OnboardingConfig{MasterKey: strings.Repeat("ab", 32), EntryURL: "https://platform.example/onboarding/entry"} if err := c.readTencentSMSFile(smsConfigFixture(t, raw), true); err != nil { t.Fatal(err) } if err := c.validate(EnvironmentProd); err != nil { t.Fatal(err) } if len(c.TencentSMSTemplateParams["register"]) != 2 || c.TencentSMSTemplateParams["register"][1] != "expires_minutes" { t.Fatal("parameter order was not preserved") } c.TencentSMSTemplateParams["register"] = []string{"code", "unknown"} if err := c.validate(EnvironmentProd); err == nil { t.Fatal("invalid template parameter accepted") } }