feat: #337 unify types for auth module
This commit was merged in pull request #338.
This commit is contained in:
163
service/auth.go
163
service/auth.go
@@ -26,55 +26,25 @@ var (
|
||||
ErrTokenInvalid = errors.New("token is invalid")
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Id uuid.UUID
|
||||
Email string
|
||||
EmailVerified bool
|
||||
}
|
||||
|
||||
func NewUser(user *db.User) *User {
|
||||
return &User{
|
||||
Id: user.Id,
|
||||
Email: user.Email,
|
||||
EmailVerified: user.EmailVerified,
|
||||
}
|
||||
}
|
||||
|
||||
type Session struct {
|
||||
Id string
|
||||
CreatedAt time.Time
|
||||
ExpiresAt time.Time
|
||||
User *User
|
||||
}
|
||||
|
||||
func NewSession(session *db.Session, user *User) *Session {
|
||||
return &Session{
|
||||
Id: session.Id,
|
||||
CreatedAt: session.CreatedAt,
|
||||
ExpiresAt: session.ExpiresAt,
|
||||
User: user,
|
||||
}
|
||||
}
|
||||
|
||||
type Auth interface {
|
||||
SignUp(email string, password string) (*User, error)
|
||||
SignUp(email string, password string) (*types.User, error)
|
||||
SendVerificationMail(userId uuid.UUID, email string)
|
||||
VerifyUserEmail(token string) error
|
||||
|
||||
SignIn(email string, password string) (*Session, error)
|
||||
SignInSession(sessionId string) (*Session, error)
|
||||
SignInAnonymous() (*Session, error)
|
||||
SignIn(email string, password string) (*types.Session, *types.User, error)
|
||||
SignInSession(sessionId string) (*types.Session, *types.User, error)
|
||||
SignInAnonymous() (*types.Session, error)
|
||||
SignOut(sessionId string) error
|
||||
|
||||
DeleteAccount(user *User, currPass string) error
|
||||
DeleteAccount(user *types.User, currPass string) error
|
||||
|
||||
ChangePassword(session *Session, currPass, newPass string) error
|
||||
ChangePassword(user *types.User, sessionId string, currPass, newPass string) error
|
||||
|
||||
SendForgotPasswordMail(email string) error
|
||||
ForgotPassword(token string, newPass string) error
|
||||
|
||||
IsCsrfTokenValid(tokenStr string, sessionId string) bool
|
||||
GetCsrfToken(session *Session) (string, error)
|
||||
GetCsrfToken(session *types.Session) (string, error)
|
||||
}
|
||||
|
||||
type AuthImpl struct {
|
||||
@@ -95,69 +65,65 @@ func NewAuthImpl(db db.Auth, random Random, clock Clock, mail Mail, serverSettin
|
||||
}
|
||||
}
|
||||
|
||||
func (service AuthImpl) SignIn(email string, password string) (*Session, error) {
|
||||
func (service AuthImpl) SignIn(email string, password string) (*types.Session, *types.User, error) {
|
||||
user, err := service.db.GetUserByEmail(email)
|
||||
if err != nil {
|
||||
if errors.Is(err, db.ErrNotFound) {
|
||||
return nil, ErrInvalidCredentials
|
||||
return nil, nil, ErrInvalidCredentials
|
||||
} else {
|
||||
return nil, types.ErrInternal
|
||||
return nil, nil, types.ErrInternal
|
||||
}
|
||||
}
|
||||
|
||||
hash := GetHashPassword(password, user.Salt)
|
||||
|
||||
if subtle.ConstantTimeCompare(hash, user.Password) == 0 {
|
||||
return nil, ErrInvalidCredentials
|
||||
return nil, nil, ErrInvalidCredentials
|
||||
}
|
||||
|
||||
session, err := service.createSession(user.Id)
|
||||
if err != nil {
|
||||
return nil, types.ErrInternal
|
||||
return nil, nil, types.ErrInternal
|
||||
}
|
||||
|
||||
return NewSession(session, NewUser(user)), nil
|
||||
return session, user, nil
|
||||
}
|
||||
|
||||
func (service AuthImpl) SignInSession(sessionId string) (*Session, error) {
|
||||
func (service AuthImpl) SignInSession(sessionId string) (*types.Session, *types.User, error) {
|
||||
if sessionId == "" {
|
||||
return nil, ErrSessionIdInvalid
|
||||
return nil, nil, ErrSessionIdInvalid
|
||||
}
|
||||
|
||||
sessionDb, err := service.db.GetSession(sessionId)
|
||||
session, err := service.db.GetSession(sessionId)
|
||||
if err != nil {
|
||||
return nil, nil, types.ErrInternal
|
||||
}
|
||||
if session.ExpiresAt.Before(service.clock.Now()) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
if session.UserId == uuid.Nil {
|
||||
return session, nil, nil
|
||||
}
|
||||
|
||||
user, err := service.db.GetUser(session.UserId)
|
||||
if err != nil {
|
||||
return nil, nil, types.ErrInternal
|
||||
}
|
||||
|
||||
return session, user, nil
|
||||
}
|
||||
|
||||
func (service AuthImpl) SignInAnonymous() (*types.Session, error) {
|
||||
session, err := service.createSession(uuid.Nil)
|
||||
if err != nil {
|
||||
return nil, types.ErrInternal
|
||||
}
|
||||
|
||||
if sessionDb.ExpiresAt.Before(service.clock.Now()) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if sessionDb.UserId == uuid.Nil {
|
||||
return NewSession(sessionDb, nil), nil
|
||||
}
|
||||
|
||||
userDb, err := service.db.GetUser(sessionDb.UserId)
|
||||
if err != nil {
|
||||
return nil, types.ErrInternal
|
||||
}
|
||||
|
||||
user := NewUser(userDb)
|
||||
session := NewSession(sessionDb, user)
|
||||
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func (service AuthImpl) SignInAnonymous() (*Session, error) {
|
||||
sessionDb, err := service.createSession(uuid.Nil)
|
||||
if err != nil {
|
||||
return nil, types.ErrInternal
|
||||
}
|
||||
|
||||
return NewSession(sessionDb, nil), nil
|
||||
}
|
||||
|
||||
func (service AuthImpl) createSession(userId uuid.UUID) (*db.Session, error) {
|
||||
func (service AuthImpl) createSession(userId uuid.UUID) (*types.Session, error) {
|
||||
sessionId, err := service.random.String(32)
|
||||
if err != nil {
|
||||
return nil, types.ErrInternal
|
||||
@@ -172,7 +138,7 @@ func (service AuthImpl) createSession(userId uuid.UUID) (*db.Session, error) {
|
||||
createAt := service.clock.Now()
|
||||
expiresAt := createAt.Add(24 * time.Hour)
|
||||
|
||||
session := db.NewSession(sessionId, userId, createAt, expiresAt)
|
||||
session := types.NewSession(sessionId, userId, createAt, expiresAt)
|
||||
|
||||
err = service.db.InsertSession(session)
|
||||
if err != nil {
|
||||
@@ -182,7 +148,7 @@ func (service AuthImpl) createSession(userId uuid.UUID) (*db.Session, error) {
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func (service AuthImpl) SignUp(email string, password string) (*User, error) {
|
||||
func (service AuthImpl) SignUp(email string, password string) (*types.User, error) {
|
||||
_, err := mail.ParseAddress(email)
|
||||
if err != nil {
|
||||
return nil, ErrInvalidEmail
|
||||
@@ -204,9 +170,9 @@ func (service AuthImpl) SignUp(email string, password string) (*User, error) {
|
||||
|
||||
hash := GetHashPassword(password, salt)
|
||||
|
||||
dbUser := db.NewUser(userId, email, false, nil, false, hash, salt, service.clock.Now())
|
||||
user := types.NewUser(userId, email, false, nil, false, hash, salt, service.clock.Now())
|
||||
|
||||
err = service.db.InsertUser(dbUser)
|
||||
err = service.db.InsertUser(user)
|
||||
if err != nil {
|
||||
if err == db.ErrAlreadyExists {
|
||||
return nil, ErrAccountExists
|
||||
@@ -215,17 +181,17 @@ func (service AuthImpl) SignUp(email string, password string) (*User, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return NewUser(dbUser), nil
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (service AuthImpl) SendVerificationMail(userId uuid.UUID, email string) {
|
||||
|
||||
tokens, err := service.db.GetTokensByUserIdAndType(userId, db.TokenTypeEmailVerify)
|
||||
tokens, err := service.db.GetTokensByUserIdAndType(userId, types.TokenTypeEmailVerify)
|
||||
if err != nil && err != db.ErrNotFound {
|
||||
return
|
||||
}
|
||||
|
||||
var token *db.Token
|
||||
var token *types.Token
|
||||
|
||||
if len(tokens) > 0 {
|
||||
token = tokens[0]
|
||||
@@ -237,7 +203,7 @@ func (service AuthImpl) SendVerificationMail(userId uuid.UUID, email string) {
|
||||
return
|
||||
}
|
||||
|
||||
token = db.NewToken(userId, "", newTokenStr, db.TokenTypeEmailVerify, service.clock.Now(), service.clock.Now().Add(24*time.Hour))
|
||||
token = types.NewToken(userId, "", newTokenStr, types.TokenTypeEmailVerify, service.clock.Now(), service.clock.Now().Add(24*time.Hour))
|
||||
|
||||
err = service.db.InsertToken(token)
|
||||
if err != nil {
|
||||
@@ -271,7 +237,7 @@ func (service AuthImpl) VerifyUserEmail(tokenStr string) error {
|
||||
return types.ErrInternal
|
||||
}
|
||||
|
||||
if token.Type != db.TokenTypeEmailVerify {
|
||||
if token.Type != types.TokenTypeEmailVerify {
|
||||
return types.ErrInternal
|
||||
}
|
||||
|
||||
@@ -298,7 +264,7 @@ func (service AuthImpl) SignOut(sessionId string) error {
|
||||
return service.db.DeleteSession(sessionId)
|
||||
}
|
||||
|
||||
func (service AuthImpl) DeleteAccount(user *User, currPass string) error {
|
||||
func (service AuthImpl) DeleteAccount(user *types.User, currPass string) error {
|
||||
|
||||
userDb, err := service.db.GetUser(user.Id)
|
||||
if err != nil {
|
||||
@@ -320,7 +286,7 @@ func (service AuthImpl) DeleteAccount(user *User, currPass string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (service AuthImpl) ChangePassword(session *Session, currPass, newPass string) error {
|
||||
func (service AuthImpl) ChangePassword(user *types.User, sessionId string, currPass, newPass string) error {
|
||||
|
||||
if !isPasswordValid(newPass) {
|
||||
return ErrInvalidPassword
|
||||
@@ -330,31 +296,26 @@ func (service AuthImpl) ChangePassword(session *Session, currPass, newPass strin
|
||||
return ErrInvalidPassword
|
||||
}
|
||||
|
||||
userDb, err := service.db.GetUser(session.User.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currHash := GetHashPassword(currPass, user.Salt)
|
||||
|
||||
currHash := GetHashPassword(currPass, userDb.Salt)
|
||||
|
||||
if subtle.ConstantTimeCompare(currHash, userDb.Password) == 0 {
|
||||
if subtle.ConstantTimeCompare(currHash, user.Password) == 0 {
|
||||
return ErrInvalidCredentials
|
||||
}
|
||||
|
||||
newHash := GetHashPassword(newPass, userDb.Salt)
|
||||
userDb.Password = newHash
|
||||
newHash := GetHashPassword(newPass, user.Salt)
|
||||
user.Password = newHash
|
||||
|
||||
err = service.db.UpdateUser(userDb)
|
||||
err := service.db.UpdateUser(user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sessions, err := service.db.GetSessions(userDb.Id)
|
||||
sessions, err := service.db.GetSessions(user.Id)
|
||||
if err != nil {
|
||||
return types.ErrInternal
|
||||
}
|
||||
for _, s := range sessions {
|
||||
if s.Id != session.Id {
|
||||
if s.Id != sessionId {
|
||||
err = service.db.DeleteSession(s.Id)
|
||||
if err != nil {
|
||||
return types.ErrInternal
|
||||
@@ -380,7 +341,7 @@ func (service AuthImpl) SendForgotPasswordMail(email string) error {
|
||||
}
|
||||
}
|
||||
|
||||
token := db.NewToken(user.Id, "", tokenStr, db.TokenTypePasswordReset, service.clock.Now(), service.clock.Now().Add(15*time.Minute))
|
||||
token := types.NewToken(user.Id, "", tokenStr, types.TokenTypePasswordReset, service.clock.Now(), service.clock.Now().Add(15*time.Minute))
|
||||
|
||||
err = service.db.InsertToken(token)
|
||||
if err != nil {
|
||||
@@ -414,7 +375,7 @@ func (service AuthImpl) ForgotPassword(tokenStr string, newPass string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if token.Type != db.TokenTypePasswordReset ||
|
||||
if token.Type != types.TokenTypePasswordReset ||
|
||||
token.ExpiresAt.Before(service.clock.Now()) {
|
||||
return ErrTokenInvalid
|
||||
}
|
||||
@@ -454,7 +415,7 @@ func (service AuthImpl) IsCsrfTokenValid(tokenStr string, sessionId string) bool
|
||||
return false
|
||||
}
|
||||
|
||||
if token.Type != db.TokenTypeCsrf ||
|
||||
if token.Type != types.TokenTypeCsrf ||
|
||||
token.SessionId != sessionId ||
|
||||
token.ExpiresAt.Before(service.clock.Now()) {
|
||||
|
||||
@@ -464,12 +425,12 @@ func (service AuthImpl) IsCsrfTokenValid(tokenStr string, sessionId string) bool
|
||||
return true
|
||||
}
|
||||
|
||||
func (service AuthImpl) GetCsrfToken(session *Session) (string, error) {
|
||||
func (service AuthImpl) GetCsrfToken(session *types.Session) (string, error) {
|
||||
if session == nil {
|
||||
return "", types.ErrInternal
|
||||
}
|
||||
|
||||
tokens, _ := service.db.GetTokensBySessionIdAndType(session.Id, db.TokenTypeCsrf)
|
||||
tokens, _ := service.db.GetTokensBySessionIdAndType(session.Id, types.TokenTypeCsrf)
|
||||
|
||||
if len(tokens) > 0 {
|
||||
return tokens[0].Token, nil
|
||||
@@ -480,7 +441,7 @@ func (service AuthImpl) GetCsrfToken(session *Session) (string, error) {
|
||||
return "", types.ErrInternal
|
||||
}
|
||||
|
||||
token := db.NewToken(uuid.Nil, session.Id, tokenStr, db.TokenTypeCsrf, service.clock.Now(), service.clock.Now().Add(24*time.Hour))
|
||||
token := types.NewToken(uuid.Nil, session.Id, tokenStr, types.TokenTypeCsrf, service.clock.Now(), service.clock.Now().Add(24*time.Hour))
|
||||
err = service.db.InsertToken(token)
|
||||
if err != nil {
|
||||
return "", types.ErrInternal
|
||||
|
||||
Reference in New Issue
Block a user