|
|
|
|
@@ -65,7 +65,14 @@ func (a *authServiceImpl) RegistrationBegin(request models.RegistrationBeginRequ
|
|
|
|
|
var passwordHash string
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
|
|
helper, db, _ := database.NewDbHelperTransaction(a.dbctx)
|
|
|
|
|
helper, db, err := database.NewDbHelperTransaction(a.dbctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
a.log.Error(
|
|
|
|
|
"Failed to open a transaction",
|
|
|
|
|
zap.Error(err))
|
|
|
|
|
return false, errs.ErrServerError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
defer helper.RollbackOnError(err)
|
|
|
|
|
|
|
|
|
|
// TODO: check occupation with redis
|
|
|
|
|
@@ -184,7 +191,12 @@ func (a *authServiceImpl) RegistrationBegin(request models.RegistrationBeginRequ
|
|
|
|
|
zap.String("code", generatedCode))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
helper.Commit()
|
|
|
|
|
if err = helper.Commit(); err != nil {
|
|
|
|
|
a.log.Error(
|
|
|
|
|
"Failed to commit transaction",
|
|
|
|
|
zap.Error(err))
|
|
|
|
|
return false, errs.ErrServerError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
@@ -198,7 +210,13 @@ func (a *authServiceImpl) RegistrationComplete(request models.RegistrationComple
|
|
|
|
|
var accessToken, refreshToken string
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
|
|
helper, db, _ := database.NewDbHelperTransaction(a.dbctx)
|
|
|
|
|
helper, db, err := database.NewDbHelperTransaction(a.dbctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
a.log.Error(
|
|
|
|
|
"Failed to open a transaction",
|
|
|
|
|
zap.Error(err))
|
|
|
|
|
return nil, errs.ErrServerError
|
|
|
|
|
}
|
|
|
|
|
defer helper.RollbackOnError(err)
|
|
|
|
|
|
|
|
|
|
user, err = db.TXQueries.GetUserByUsername(db.CTX, request.Username)
|
|
|
|
|
@@ -316,7 +334,12 @@ func (a *authServiceImpl) RegistrationComplete(request models.RegistrationComple
|
|
|
|
|
return nil, errs.ErrServerError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
helper.Commit()
|
|
|
|
|
if err = helper.Commit(); err != nil {
|
|
|
|
|
a.log.Error(
|
|
|
|
|
"Failed to commit transaction",
|
|
|
|
|
zap.Error(err))
|
|
|
|
|
return nil, errs.ErrServerError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.log.Info(
|
|
|
|
|
"User verified registration",
|
|
|
|
|
@@ -336,7 +359,13 @@ func (a *authServiceImpl) Login(request models.LoginRequest) (*models.LoginRespo
|
|
|
|
|
var session database.Session
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
|
|
helper, db, _ := database.NewDbHelperTransaction(a.dbctx)
|
|
|
|
|
helper, db, err := database.NewDbHelperTransaction(a.dbctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
a.log.Error(
|
|
|
|
|
"Failed to open a transaction",
|
|
|
|
|
zap.Error(err))
|
|
|
|
|
return nil, errs.ErrServerError
|
|
|
|
|
}
|
|
|
|
|
defer helper.RollbackOnError(err)
|
|
|
|
|
|
|
|
|
|
userRow, err = db.TXQueries.GetValidUserByLoginCredentials(db.CTX, database.GetValidUserByLoginCredentialsParams{
|
|
|
|
|
@@ -395,7 +424,12 @@ func (a *authServiceImpl) Login(request models.LoginRequest) (*models.LoginRespo
|
|
|
|
|
return nil, errs.ErrServerError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
helper.Commit()
|
|
|
|
|
if err = helper.Commit(); err != nil {
|
|
|
|
|
a.log.Error(
|
|
|
|
|
"Failed to commit transaction",
|
|
|
|
|
zap.Error(err))
|
|
|
|
|
return nil, errs.ErrServerError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
response := models.LoginResponse{Tokens: models.Tokens{
|
|
|
|
|
AccessToken: accessToken,
|
|
|
|
|
@@ -416,6 +450,12 @@ func (a *authServiceImpl) PasswordResetBegin(request models.PasswordResetBeginRe
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
|
|
helper, db, err := database.NewDbHelperTransaction(a.dbctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
a.log.Error(
|
|
|
|
|
"Failed to open a transaction",
|
|
|
|
|
zap.Error(err))
|
|
|
|
|
return false, errs.ErrServerError
|
|
|
|
|
}
|
|
|
|
|
defer helper.RollbackOnError(err)
|
|
|
|
|
|
|
|
|
|
ctx := context.TODO()
|
|
|
|
|
@@ -427,16 +467,14 @@ func (a *authServiceImpl) PasswordResetBegin(request models.PasswordResetBeginRe
|
|
|
|
|
zap.String("email", request.Email),
|
|
|
|
|
zap.Error(redisErr))
|
|
|
|
|
return false, errs.ErrServerError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if err == nil {
|
|
|
|
|
current_time := time.Now()
|
|
|
|
|
if current_time.Unix() < cooldownTimeUnix {
|
|
|
|
|
if time.Now().Unix() < cooldownTimeUnix {
|
|
|
|
|
a.log.Warn(
|
|
|
|
|
"Attempted to request a new password reset code for email on active reset cooldown",
|
|
|
|
|
zap.String("email", request.Email))
|
|
|
|
|
return false, errs.ErrTooManyRequests
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if user, err = db.TXQueries.GetUserByEmail(db.CTX, request.Email); err != nil {
|
|
|
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
|
|
|
@@ -501,13 +539,144 @@ func (a *authServiceImpl) PasswordResetBegin(request models.PasswordResetBeginRe
|
|
|
|
|
return false, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
helper.Commit()
|
|
|
|
|
if err = helper.Commit(); err != nil {
|
|
|
|
|
a.log.Error(
|
|
|
|
|
"Failed to commit transaction",
|
|
|
|
|
zap.Error(err))
|
|
|
|
|
return false, errs.ErrServerError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (a *authServiceImpl) PasswordResetComplete(request models.PasswordResetCompleteRequest) (*models.PasswordResetCompleteResponse, error) {
|
|
|
|
|
|
|
|
|
|
return nil, errs.ErrNotImplemented
|
|
|
|
|
var resetCode database.ConfirmationCode
|
|
|
|
|
var user database.User
|
|
|
|
|
var session database.Session
|
|
|
|
|
var hashedPassword, accessToken, refreshToken string
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
|
|
helper, db, err := database.NewDbHelperTransaction(a.dbctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
a.log.Error(
|
|
|
|
|
"Failed to open a transaction",
|
|
|
|
|
zap.Error(err))
|
|
|
|
|
return nil, errs.ErrServerError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if user, err = db.TXQueries.GetUserByEmail(db.CTX, request.Email); err != nil {
|
|
|
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
|
|
|
a.log.Warn(
|
|
|
|
|
"Attempted to complete password reset for unregistered email",
|
|
|
|
|
zap.String("email", request.Email),
|
|
|
|
|
zap.Error(err))
|
|
|
|
|
return nil, errs.ErrForbidden
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.log.Error(
|
|
|
|
|
"Failed to look up user of email while trying to complete password reset",
|
|
|
|
|
zap.String("email", request.Email),
|
|
|
|
|
zap.Error(err))
|
|
|
|
|
return nil, errs.ErrServerError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if resetCode, err = db.TXQueries.GetValidConfirmationCodeByCode(db.CTX, database.GetValidConfirmationCodeByCodeParams{
|
|
|
|
|
UserID: user.ID,
|
|
|
|
|
CodeType: int32(enums.PasswordResetCodeType),
|
|
|
|
|
Code: request.VerificationCode,
|
|
|
|
|
}); err != nil {
|
|
|
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
|
|
|
a.log.Warn(
|
|
|
|
|
"Attempted to reset password for user using incorrect confirmation code",
|
|
|
|
|
zap.String("email", request.Email),
|
|
|
|
|
zap.String("username", user.Username),
|
|
|
|
|
zap.String("provided_code", request.VerificationCode),
|
|
|
|
|
zap.Error(err))
|
|
|
|
|
return nil, errs.ErrForbidden
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err = db.TXQueries.UpdateConfirmationCode(db.CTX, database.UpdateConfirmationCodeParams{
|
|
|
|
|
ID: resetCode.ID,
|
|
|
|
|
Used: utils.NewPointer(true),
|
|
|
|
|
}); err != nil {
|
|
|
|
|
a.log.Error(
|
|
|
|
|
"Failed to invalidate password reset code upon use",
|
|
|
|
|
zap.String("username", user.Username),
|
|
|
|
|
zap.String("email", request.Email),
|
|
|
|
|
zap.Int64("code_id", resetCode.ID),
|
|
|
|
|
zap.Error(err))
|
|
|
|
|
return nil, errs.ErrServerError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if hashedPassword, err = utils.HashPassword(request.NewPassword); err != nil {
|
|
|
|
|
a.log.Error(
|
|
|
|
|
"Failed to hash new password as part of user password reset",
|
|
|
|
|
zap.String("email", request.Email),
|
|
|
|
|
zap.String("username", user.Username),
|
|
|
|
|
zap.Error(err))
|
|
|
|
|
return nil, errs.ErrServerError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err = db.TXQueries.UpdateLoginInformationByUsername(db.CTX, database.UpdateLoginInformationByUsernameParams{
|
|
|
|
|
Username: user.Username,
|
|
|
|
|
PasswordHash: hashedPassword,
|
|
|
|
|
}); err != nil {
|
|
|
|
|
a.log.Error(
|
|
|
|
|
"Failed to save new password to database as part of user password reset",
|
|
|
|
|
zap.String("username", user.Username),
|
|
|
|
|
zap.String("email", request.Email),
|
|
|
|
|
zap.Error(err))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if request.LogOutSessions {
|
|
|
|
|
if err = db.TXQueries.TerminateAllSessionsForUserByUsername(db.CTX, user.Username); err != nil {
|
|
|
|
|
a.log.Error(
|
|
|
|
|
"Failed to log out older sessions as part of user password reset",
|
|
|
|
|
zap.String("email", request.Email),
|
|
|
|
|
zap.String("username", user.Username),
|
|
|
|
|
zap.Error(err))
|
|
|
|
|
return nil, errs.ErrServerError
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if session, err = db.TXQueries.CreateSession(db.CTX, database.CreateSessionParams{
|
|
|
|
|
UserID: user.ID,
|
|
|
|
|
Name: utils.NewPointer("First device"),
|
|
|
|
|
Platform: utils.NewPointer("Unknown"),
|
|
|
|
|
LatestIp: utils.NewPointer("Unknown"),
|
|
|
|
|
}); err != nil {
|
|
|
|
|
a.log.Error(
|
|
|
|
|
"Failed to create new session for user as part of user password reset",
|
|
|
|
|
zap.String("email", request.Email),
|
|
|
|
|
zap.String("username", user.Username),
|
|
|
|
|
zap.Error(err))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if accessToken, refreshToken, err = utils.GenerateTokens(user.Username, session.Guid.String()); err != nil {
|
|
|
|
|
a.log.Error(
|
|
|
|
|
"Failed to generate tokens as part of user password reset",
|
|
|
|
|
zap.String("email", request.Email),
|
|
|
|
|
zap.String("username", user.Username),
|
|
|
|
|
zap.Error(err))
|
|
|
|
|
return nil, errs.ErrServerError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
response := models.PasswordResetCompleteResponse{
|
|
|
|
|
Tokens: models.Tokens{
|
|
|
|
|
AccessToken: accessToken,
|
|
|
|
|
RefreshToken: refreshToken,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err = helper.Commit(); err != nil {
|
|
|
|
|
a.log.Error(
|
|
|
|
|
"Failed to commit transaction",
|
|
|
|
|
zap.Error(err))
|
|
|
|
|
return nil, errs.ErrServerError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &response, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|