diff --git a/internal/models/identity.go b/internal/models/identity.go index 1f5ee5f853..88626a0ca6 100644 --- a/internal/models/identity.go +++ b/internal/models/identity.go @@ -59,8 +59,12 @@ func NewIdentity(user *User, provider string, identityData map[string]interface{ Provider: provider, LastSignInAt: &now, } - if email, ok := identityData["email"]; ok { - identity.Email = storage.NullString(email.(string)) + // identityData may originate from user-supplied metadata (e.g. the + // signup `data` field), so the email may be absent or a non-string + // value. Only set the email when it is actually a string to avoid a + // panic from an unchecked type assertion. + if email, ok := identityData["email"].(string); ok { + identity.Email = storage.NullString(email) } return identity, nil @@ -71,8 +75,8 @@ func (i *Identity) BeforeCreate(tx *pop.Connection) error { } func (i *Identity) BeforeUpdate(tx *pop.Connection) error { - if _, ok := i.IdentityData["email"]; ok { - i.IdentityData["email"] = strings.ToLower(i.IdentityData["email"].(string)) + if email, ok := i.IdentityData["email"].(string); ok { + i.IdentityData["email"] = strings.ToLower(email) } return nil } diff --git a/internal/models/identity_test.go b/internal/models/identity_test.go index ddf1881a33..cc04e42390 100644 --- a/internal/models/identity_test.go +++ b/internal/models/identity_test.go @@ -49,6 +49,25 @@ func (ts *IdentityTestSuite) TestNewIdentity() { require.NoError(ts.T(), err) require.Equal(ts.T(), u.ID, identity.UserID) }) + + ts.Run("Test create identity with string email", func() { + identityData := map[string]interface{}{"sub": uuid.Nil.String(), "email": "test@supabase.io"} + identity, err := NewIdentity(u, "email", identityData) + require.NoError(ts.T(), err) + require.Equal(ts.T(), "test@supabase.io", identity.GetEmail()) + }) + + // A phone signup omits the (empty) email claim, so a user-supplied + // `data.email` can reach identityData as a non-string value. NewIdentity + // must not panic on it. Regression test for supabase/auth#2268. + ts.Run("Test create identity with non-string email does not panic", func() { + for _, email := range []interface{}{nil, 123, true, map[string]interface{}{}} { + identityData := map[string]interface{}{"sub": uuid.Nil.String(), "email": email} + identity, err := NewIdentity(u, "phone", identityData) + require.NoError(ts.T(), err) + require.Empty(ts.T(), identity.GetEmail(), "email should be unset for non-string value %#v", email) + } + }) } func (ts *IdentityTestSuite) TestFindUserIdentities() {