feat(auth): replace hand-rolled auth with Ory Kratos — phase 2 backend
Delegates all credential management (login, register, password reset, email verification, social sign-in) to Ory Kratos. The Go API now acts as a resource server: the new KratosAuth middleware validates sessions against the Kratos whoami endpoint, writes the local User mirror into Echo context, and all existing domain handlers continue working unchanged. Hand-rolled token auth, AuthToken model, apple_auth/ google_auth services, and the auth refresh flow are removed. Tests are updated to use the fake-token middleware pattern so existing integration assertions require no rewrite. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,50 +2,15 @@ package models
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestUser_SetPassword(t *testing.T) {
|
||||
user := &User{}
|
||||
|
||||
err := user.SetPassword("testPassword123")
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, user.Password)
|
||||
assert.NotEqual(t, "testPassword123", user.Password) // Should be hashed
|
||||
}
|
||||
|
||||
func TestUser_CheckPassword(t *testing.T) {
|
||||
user := &User{}
|
||||
err := user.SetPassword("correctpassword")
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
password string
|
||||
expected bool
|
||||
}{
|
||||
{"correct password", "correctpassword", true},
|
||||
{"wrong password", "wrongpassword", false},
|
||||
{"empty password", "", false},
|
||||
{"similar password", "correctpassword1", false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := user.CheckPassword(tt.password)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUser_GetFullName(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
user User
|
||||
expected string
|
||||
name string
|
||||
user User
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "first and last name",
|
||||
@@ -82,136 +47,7 @@ func TestUser_TableName(t *testing.T) {
|
||||
assert.Equal(t, "auth_user", user.TableName())
|
||||
}
|
||||
|
||||
func TestAuthToken_TableName(t *testing.T) {
|
||||
token := AuthToken{}
|
||||
assert.Equal(t, "user_authtoken", token.TableName())
|
||||
}
|
||||
|
||||
func TestUserProfile_TableName(t *testing.T) {
|
||||
profile := UserProfile{}
|
||||
assert.Equal(t, "user_userprofile", profile.TableName())
|
||||
}
|
||||
|
||||
func TestConfirmationCode_IsValid(t *testing.T) {
|
||||
now := time.Now().UTC()
|
||||
future := now.Add(1 * time.Hour)
|
||||
past := now.Add(-1 * time.Hour)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
code ConfirmationCode
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "valid code",
|
||||
code: ConfirmationCode{IsUsed: false, ExpiresAt: future},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "used code",
|
||||
code: ConfirmationCode{IsUsed: true, ExpiresAt: future},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "expired code",
|
||||
code: ConfirmationCode{IsUsed: false, ExpiresAt: past},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "used and expired",
|
||||
code: ConfirmationCode{IsUsed: true, ExpiresAt: past},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := tt.code.IsValid()
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPasswordResetCode_IsValid(t *testing.T) {
|
||||
now := time.Now().UTC()
|
||||
future := now.Add(1 * time.Hour)
|
||||
past := now.Add(-1 * time.Hour)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
code PasswordResetCode
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "valid code",
|
||||
code: PasswordResetCode{Used: false, ExpiresAt: future, Attempts: 0, MaxAttempts: 5},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "used code",
|
||||
code: PasswordResetCode{Used: true, ExpiresAt: future, Attempts: 0, MaxAttempts: 5},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "expired code",
|
||||
code: PasswordResetCode{Used: false, ExpiresAt: past, Attempts: 0, MaxAttempts: 5},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "max attempts reached",
|
||||
code: PasswordResetCode{Used: false, ExpiresAt: future, Attempts: 5, MaxAttempts: 5},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "attempts under max",
|
||||
code: PasswordResetCode{Used: false, ExpiresAt: future, Attempts: 4, MaxAttempts: 5},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := tt.code.IsValid()
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPasswordResetCode_SetAndCheckCode(t *testing.T) {
|
||||
code := &PasswordResetCode{}
|
||||
|
||||
err := code.SetCode("123456")
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, code.CodeHash)
|
||||
|
||||
// Check correct code
|
||||
assert.True(t, code.CheckCode("123456"))
|
||||
|
||||
// Check wrong code
|
||||
assert.False(t, code.CheckCode("654321"))
|
||||
assert.False(t, code.CheckCode(""))
|
||||
}
|
||||
|
||||
func TestGenerateConfirmationCode(t *testing.T) {
|
||||
code := GenerateConfirmationCode()
|
||||
assert.Len(t, code, 6)
|
||||
|
||||
// Generate multiple codes and ensure they're different
|
||||
codes := make(map[string]bool)
|
||||
for i := 0; i < 10; i++ {
|
||||
c := GenerateConfirmationCode()
|
||||
assert.Len(t, c, 6)
|
||||
codes[c] = true
|
||||
}
|
||||
// Most codes should be unique (very unlikely to have collisions)
|
||||
assert.Greater(t, len(codes), 5)
|
||||
}
|
||||
|
||||
func TestGenerateResetToken(t *testing.T) {
|
||||
token := GenerateResetToken()
|
||||
assert.Len(t, token, 64) // 32 bytes = 64 hex chars
|
||||
|
||||
// Ensure uniqueness
|
||||
token2 := GenerateResetToken()
|
||||
assert.NotEqual(t, token, token2)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user