Skip to content

Commit 338491f

Browse files
committed
fix: support = delimiter in GOTRUE_SMS_TEST_OTP env var
1 parent 52cf3d9 commit 338491f

4 files changed

Lines changed: 90 additions & 6 deletions

File tree

internal/api/anonymous_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ func (ts *AnonymousTestSuite) TestAnonymousLogins() {
8686

8787
func (ts *AnonymousTestSuite) TestConvertAnonymousUserToPermanent() {
8888
ts.Config.External.AnonymousUsers.Enabled = true
89-
ts.Config.Sms.TestOTP = map[string]string{"1234567890": "000000", "1234560000": "000000"}
89+
ts.Config.Sms.TestOTP = conf.TestOTPMap{"1234567890": "000000", "1234560000": "000000"}
9090
// test OTPs still require setting up an sms provider
9191
ts.Config.Sms.Provider = "twilio"
9292
ts.Config.Sms.Twilio.AccountSid = "fake-sid"

internal/api/phone_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func doTestSendPhoneConfirmation(ts *PhoneTestSuite, useTestOTP bool) {
105105
}
106106

107107
if useTestOTP {
108-
ts.API.config.Sms.TestOTP = map[string]string{
108+
ts.API.config.Sms.TestOTP = conf.TestOTPMap{
109109
"123456789": "123456",
110110
}
111111
} else {

internal/conf/configuration.go

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -652,14 +652,47 @@ type PhoneProviderConfiguration struct {
652652
Enabled bool `json:"enabled" default:"false"`
653653
}
654654

655+
type TestOTPMap map[string]string
656+
657+
func (m *TestOTPMap) Decode(value string) error {
658+
trimmed := strings.TrimSpace(value)
659+
if trimmed == "" {
660+
return nil
661+
}
662+
663+
if err := json.Unmarshal([]byte(trimmed), (*map[string]string)(m)); err == nil {
664+
return nil
665+
}
666+
667+
result := make(map[string]string)
668+
for _, pair := range strings.Split(trimmed, ",") {
669+
pair = strings.TrimSpace(pair)
670+
var k, v string
671+
var found bool
672+
if k, v, found = strings.Cut(pair, "="); !found {
673+
if k, v, found = strings.Cut(pair, ":"); !found {
674+
continue
675+
}
676+
}
677+
result[strings.TrimSpace(k)] = strings.TrimSpace(v)
678+
}
679+
680+
if len(result) == 0 {
681+
return fmt.Errorf("invalid test OTP format: %s", value)
682+
}
683+
684+
*m = TestOTPMap(result)
685+
return nil
686+
}
687+
655688
type SmsProviderConfiguration struct {
656689
Autoconfirm bool `json:"autoconfirm"`
657690
MaxFrequency time.Duration `json:"max_frequency" split_words:"true"`
658691
OtpExp uint `json:"otp_exp" split_words:"true"`
659692
OtpLength int `json:"otp_length" split_words:"true"`
660693
Provider string `json:"provider"`
661694
Template string `json:"template"`
662-
TestOTP map[string]string `json:"test_otp" split_words:"true"`
695+
TestOTP TestOTPMap `json:"test_otp" split_words:"true"`
663696
TestOTPValidUntil Time `json:"test_otp_valid_until" split_words:"true"`
664697
SMSTemplate *template.Template `json:"-"`
665698

@@ -1214,7 +1247,7 @@ func (config *GlobalConfiguration) ApplyDefaults() error {
12141247
}
12151248

12161249
if config.Sms.TestOTP != nil {
1217-
formatTestOtps := make(map[string]string)
1250+
formatTestOtps := make(TestOTPMap)
12181251
for phone, otp := range config.Sms.TestOTP {
12191252
phone = strings.ReplaceAll(strings.TrimPrefix(phone, "+"), " ", "")
12201253
formatTestOtps[phone] = otp

internal/conf/configuration_test.go

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -998,7 +998,7 @@ func TestMethods(t *testing.T) {
998998
require.Equal(t, "", got)
999999

10001000
// valid
1001-
val.TestOTP = map[string]string{"13334444": "123456"}
1001+
val.TestOTP = TestOTPMap{"13334444": "123456"}
10021002
got, ok = val.GetTestOTP("13334444", now)
10031003
require.True(t, ok)
10041004
require.Equal(t, "123456", got)
@@ -1021,6 +1021,57 @@ func TestMethods(t *testing.T) {
10211021
require.Equal(t, "", got)
10221022
}
10231023

1024+
{
1025+
t.Run("DecodeJSON", func(t *testing.T) {
1026+
var m TestOTPMap
1027+
err := m.Decode(`{"13334444": "123456"}`)
1028+
require.NoError(t, err)
1029+
require.Equal(t, TestOTPMap{"13334444": "123456"}, m)
1030+
})
1031+
1032+
t.Run("DecodeColonDelimited", func(t *testing.T) {
1033+
var m TestOTPMap
1034+
err := m.Decode(`13334444:123456`)
1035+
require.NoError(t, err)
1036+
require.Equal(t, TestOTPMap{"13334444": "123456"}, m)
1037+
})
1038+
1039+
t.Run("DecodeEqualsDelimited", func(t *testing.T) {
1040+
var m TestOTPMap
1041+
err := m.Decode(`13334444=123456`)
1042+
require.NoError(t, err)
1043+
require.Equal(t, TestOTPMap{"13334444": "123456"}, m)
1044+
})
1045+
1046+
t.Run("DecodeMultipleEntries", func(t *testing.T) {
1047+
var m TestOTPMap
1048+
err := m.Decode(`13334444:123456,15550001111:000000`)
1049+
require.NoError(t, err)
1050+
require.Equal(t, TestOTPMap{"13334444": "123456", "15550001111": "000000"}, m)
1051+
})
1052+
1053+
t.Run("DecodeMixedFormats", func(t *testing.T) {
1054+
var m TestOTPMap
1055+
err := m.Decode(`13334444:123456,15550001111=000000`)
1056+
require.NoError(t, err)
1057+
require.Equal(t, TestOTPMap{"13334444": "123456", "15550001111": "000000"}, m)
1058+
})
1059+
1060+
t.Run("DecodeEmptyString", func(t *testing.T) {
1061+
var m TestOTPMap
1062+
err := m.Decode(``)
1063+
require.NoError(t, err)
1064+
require.Nil(t, m)
1065+
})
1066+
1067+
t.Run("DecodeInvalidFormat", func(t *testing.T) {
1068+
var m TestOTPMap
1069+
err := m.Decode(`invalid`)
1070+
require.Error(t, err)
1071+
require.Contains(t, err.Error(), "invalid test OTP format")
1072+
})
1073+
}
1074+
10241075
{
10251076
val := &OAuthProviderConfiguration{}
10261077

@@ -1172,7 +1223,7 @@ func TestMethods(t *testing.T) {
11721223
Secret: "a",
11731224
},
11741225
Sms: SmsProviderConfiguration{
1175-
TestOTP: map[string]string{"13334444": "123456"},
1226+
TestOTP: TestOTPMap{"13334444": "123456"},
11761227
},
11771228
}
11781229
err := val.ApplyDefaults()

0 commit comments

Comments
 (0)