Compare commits
2 Commits
dcf054046f
...
02a764c736
| Author | SHA1 | Date | |
|---|---|---|---|
| 02a764c736 | |||
| 6834ad7764 |
@@ -1,12 +1,93 @@
|
|||||||
package services
|
package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/mail"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"goyco/internal/config"
|
"goyco/internal/config"
|
||||||
"goyco/internal/database"
|
"goyco/internal/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultTokenExpirationHours = 24
|
||||||
|
verificationTokenBytes = 32
|
||||||
|
deletionTokenExpirationHours = 24
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidCredentials = errors.New("invalid credentials")
|
||||||
|
ErrInvalidToken = errors.New("invalid or expired token")
|
||||||
|
ErrUsernameTaken = errors.New("username already exists")
|
||||||
|
ErrEmailTaken = errors.New("email already exists")
|
||||||
|
ErrInvalidEmail = errors.New("invalid email address")
|
||||||
|
ErrPasswordTooShort = errors.New("password too short")
|
||||||
|
ErrEmailNotVerified = errors.New("email not verified")
|
||||||
|
ErrAccountLocked = errors.New("account is locked")
|
||||||
|
ErrInvalidVerificationToken = errors.New("invalid verification token")
|
||||||
|
ErrEmailSenderUnavailable = errors.New("email sender not configured")
|
||||||
|
ErrDeletionEmailFailed = errors.New("account deletion email failed")
|
||||||
|
ErrInvalidDeletionToken = errors.New("invalid account deletion token")
|
||||||
|
ErrUserNotFound = errors.New("user not found")
|
||||||
|
ErrDeletionRequestNotFound = errors.New("deletion request not found")
|
||||||
|
)
|
||||||
|
|
||||||
|
type AuthResult struct {
|
||||||
|
AccessToken string `json:"access_token" example:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."`
|
||||||
|
RefreshToken string `json:"refresh_token" example:"a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"`
|
||||||
|
User *database.User `json:"user"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RegistrationResult struct {
|
||||||
|
User *database.User `json:"user"`
|
||||||
|
VerificationSent bool `json:"verification_sent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizeEmail(email string) (string, error) {
|
||||||
|
trimmed := strings.TrimSpace(email)
|
||||||
|
if trimmed == "" {
|
||||||
|
return "", fmt.Errorf("email is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed, err := mail.ParseAddress(trimmed)
|
||||||
|
if err != nil {
|
||||||
|
return "", ErrInvalidEmail
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.ToLower(parsed.Address), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateVerificationToken() (string, string, error) {
|
||||||
|
buf := make([]byte, verificationTokenBytes)
|
||||||
|
if _, err := rand.Read(buf); err != nil {
|
||||||
|
return "", "", fmt.Errorf("generate verification token: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
token := hex.EncodeToString(buf)
|
||||||
|
hashed := HashVerificationToken(token)
|
||||||
|
return token, hashed, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func HashVerificationToken(token string) string {
|
||||||
|
sum := sha256.Sum256([]byte(token))
|
||||||
|
return hex.EncodeToString(sum[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func sanitizeUser(user *database.User) *database.User {
|
||||||
|
if user == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
copy := *user
|
||||||
|
copy.Password = ""
|
||||||
|
copy.EmailVerificationToken = ""
|
||||||
|
return ©
|
||||||
|
}
|
||||||
|
|
||||||
type AuthFacade struct {
|
type AuthFacade struct {
|
||||||
registrationService *RegistrationService
|
registrationService *RegistrationService
|
||||||
passwordResetService *PasswordResetService
|
passwordResetService *PasswordResetService
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package services
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"goyco/internal/database"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrInvalidCredentials = errors.New("invalid credentials")
|
|
||||||
ErrInvalidToken = errors.New("invalid or expired token")
|
|
||||||
ErrUsernameTaken = errors.New("username already exists")
|
|
||||||
ErrEmailTaken = errors.New("email already exists")
|
|
||||||
ErrInvalidEmail = errors.New("invalid email address")
|
|
||||||
ErrPasswordTooShort = errors.New("password too short")
|
|
||||||
ErrEmailNotVerified = errors.New("email not verified")
|
|
||||||
ErrAccountLocked = errors.New("account is locked")
|
|
||||||
ErrInvalidVerificationToken = errors.New("invalid verification token")
|
|
||||||
ErrEmailSenderUnavailable = errors.New("email sender not configured")
|
|
||||||
ErrDeletionEmailFailed = errors.New("account deletion email failed")
|
|
||||||
ErrInvalidDeletionToken = errors.New("invalid account deletion token")
|
|
||||||
ErrUserNotFound = errors.New("user not found")
|
|
||||||
ErrDeletionRequestNotFound = errors.New("deletion request not found")
|
|
||||||
)
|
|
||||||
|
|
||||||
type AuthResult struct {
|
|
||||||
AccessToken string `json:"access_token" example:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."`
|
|
||||||
RefreshToken string `json:"refresh_token" example:"a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"`
|
|
||||||
User *database.User `json:"user"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type RegistrationResult struct {
|
|
||||||
User *database.User `json:"user"`
|
|
||||||
VerificationSent bool `json:"verification_sent"`
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
package services
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
"net/mail"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"goyco/internal/database"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
defaultTokenExpirationHours = 24
|
|
||||||
verificationTokenBytes = 32
|
|
||||||
deletionTokenExpirationHours = 24
|
|
||||||
)
|
|
||||||
|
|
||||||
func normalizeEmail(email string) (string, error) {
|
|
||||||
trimmed := strings.TrimSpace(email)
|
|
||||||
if trimmed == "" {
|
|
||||||
return "", fmt.Errorf("email is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
parsed, err := mail.ParseAddress(trimmed)
|
|
||||||
if err != nil {
|
|
||||||
return "", ErrInvalidEmail
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.ToLower(parsed.Address), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateVerificationToken() (string, string, error) {
|
|
||||||
buf := make([]byte, verificationTokenBytes)
|
|
||||||
if _, err := rand.Read(buf); err != nil {
|
|
||||||
return "", "", fmt.Errorf("generate verification token: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
token := hex.EncodeToString(buf)
|
|
||||||
hashed := HashVerificationToken(token)
|
|
||||||
return token, hashed, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func HashVerificationToken(token string) string {
|
|
||||||
sum := sha256.Sum256([]byte(token))
|
|
||||||
return hex.EncodeToString(sum[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
func sanitizeUser(user *database.User) *database.User {
|
|
||||||
if user == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
copy := *user
|
|
||||||
copy.Password = ""
|
|
||||||
copy.EmailVerificationToken = ""
|
|
||||||
return ©
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user