Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/api/anonymous_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (ts *AnonymousTestSuite) TestAnonymousLogins() {

func (ts *AnonymousTestSuite) TestConvertAnonymousUserToPermanent() {
ts.Config.External.AnonymousUsers.Enabled = true
ts.Config.Sms.TestOTP = map[string]string{"1234567890": "000000", "1234560000": "000000"}
ts.Config.Sms.TestOTP = conf.TestOTPMap{"1234567890": "000000", "1234560000": "000000"}
// test OTPs still require setting up an sms provider
ts.Config.Sms.Provider = "twilio"
ts.Config.Sms.Twilio.AccountSid = "fake-sid"
Expand Down
2 changes: 1 addition & 1 deletion internal/api/phone_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func doTestSendPhoneConfirmation(ts *PhoneTestSuite, useTestOTP bool) {
}

if useTestOTP {
ts.API.config.Sms.TestOTP = map[string]string{
ts.API.config.Sms.TestOTP = conf.TestOTPMap{
"123456789": "123456",
}
} else {
Expand Down
37 changes: 35 additions & 2 deletions internal/conf/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -652,14 +652,47 @@ type PhoneProviderConfiguration struct {
Enabled bool `json:"enabled" default:"false"`
}

type TestOTPMap map[string]string

func (m *TestOTPMap) Decode(value string) error {
trimmed := strings.TrimSpace(value)
if trimmed == "" {
return nil
}

if err := json.Unmarshal([]byte(trimmed), (*map[string]string)(m)); err == nil {
return nil
}

result := make(map[string]string)
for _, pair := range strings.Split(trimmed, ",") {
pair = strings.TrimSpace(pair)
var k, v string
var found bool
if k, v, found = strings.Cut(pair, "="); !found {
if k, v, found = strings.Cut(pair, ":"); !found {
continue
}
}
result[strings.TrimSpace(k)] = strings.TrimSpace(v)
}

if len(result) == 0 {
return fmt.Errorf("invalid test OTP format: %s", value)
Comment thread
depthfirst-app[bot] marked this conversation as resolved.
Outdated
}

*m = TestOTPMap(result)
return nil
}

type SmsProviderConfiguration struct {
Autoconfirm bool `json:"autoconfirm"`
MaxFrequency time.Duration `json:"max_frequency" split_words:"true"`
OtpExp uint `json:"otp_exp" split_words:"true"`
OtpLength int `json:"otp_length" split_words:"true"`
Provider string `json:"provider"`
Template string `json:"template"`
TestOTP map[string]string `json:"test_otp" split_words:"true"`
TestOTP TestOTPMap `json:"test_otp" split_words:"true"`
TestOTPValidUntil Time `json:"test_otp_valid_until" split_words:"true"`
SMSTemplate *template.Template `json:"-"`

Expand Down Expand Up @@ -1214,7 +1247,7 @@ func (config *GlobalConfiguration) ApplyDefaults() error {
}

if config.Sms.TestOTP != nil {
formatTestOtps := make(map[string]string)
formatTestOtps := make(TestOTPMap)
for phone, otp := range config.Sms.TestOTP {
phone = strings.ReplaceAll(strings.TrimPrefix(phone, "+"), " ", "")
formatTestOtps[phone] = otp
Expand Down
55 changes: 53 additions & 2 deletions internal/conf/configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -998,7 +998,7 @@ func TestMethods(t *testing.T) {
require.Equal(t, "", got)

// valid
val.TestOTP = map[string]string{"13334444": "123456"}
val.TestOTP = TestOTPMap{"13334444": "123456"}
got, ok = val.GetTestOTP("13334444", now)
require.True(t, ok)
require.Equal(t, "123456", got)
Expand All @@ -1021,6 +1021,57 @@ func TestMethods(t *testing.T) {
require.Equal(t, "", got)
}

{
t.Run("DecodeJSON", func(t *testing.T) {
var m TestOTPMap
err := m.Decode(`{"13334444": "123456"}`)
require.NoError(t, err)
require.Equal(t, TestOTPMap{"13334444": "123456"}, m)
})

t.Run("DecodeColonDelimited", func(t *testing.T) {
var m TestOTPMap
err := m.Decode(`13334444:123456`)
require.NoError(t, err)
require.Equal(t, TestOTPMap{"13334444": "123456"}, m)
})

t.Run("DecodeEqualsDelimited", func(t *testing.T) {
var m TestOTPMap
err := m.Decode(`13334444=123456`)
require.NoError(t, err)
require.Equal(t, TestOTPMap{"13334444": "123456"}, m)
})

t.Run("DecodeMultipleEntries", func(t *testing.T) {
var m TestOTPMap
err := m.Decode(`13334444:123456,15550001111:000000`)
require.NoError(t, err)
require.Equal(t, TestOTPMap{"13334444": "123456", "15550001111": "000000"}, m)
})

t.Run("DecodeMixedFormats", func(t *testing.T) {
var m TestOTPMap
err := m.Decode(`13334444:123456,15550001111=000000`)
require.NoError(t, err)
require.Equal(t, TestOTPMap{"13334444": "123456", "15550001111": "000000"}, m)
})

t.Run("DecodeEmptyString", func(t *testing.T) {
var m TestOTPMap
err := m.Decode(``)
require.NoError(t, err)
require.Nil(t, m)
})

t.Run("DecodeInvalidFormat", func(t *testing.T) {
var m TestOTPMap
err := m.Decode(`invalid`)
require.Error(t, err)
require.Contains(t, err.Error(), "invalid test OTP format")
})
}

{
val := &OAuthProviderConfiguration{}

Expand Down Expand Up @@ -1172,7 +1223,7 @@ func TestMethods(t *testing.T) {
Secret: "a",
},
Sms: SmsProviderConfiguration{
TestOTP: map[string]string{"13334444": "123456"},
TestOTP: TestOTPMap{"13334444": "123456"},
},
}
err := val.ApplyDefaults()
Expand Down