UseRecoveryCode validates a recovery code of given user and marks it as used if valid. It returns ErrTwoFactorRecoveryCodeNotFound if the code is invalid or already used.
(ctx context.Context, userID int64, code string)
| 114 | // if valid. It returns ErrTwoFactorRecoveryCodeNotFound if the code is invalid |
| 115 | // or already used. |
| 116 | func (s *TwoFactorsStore) UseRecoveryCode(ctx context.Context, userID int64, code string) error { |
| 117 | return s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { |
| 118 | var recoveryCode TwoFactorRecoveryCode |
| 119 | err := tx.Where("user_id = ? AND code = ? AND is_used = ?", userID, code, false).First(&recoveryCode).Error |
| 120 | if err != nil { |
| 121 | if err == gorm.ErrRecordNotFound { |
| 122 | return ErrTwoFactorRecoveryCodeNotFound{Code: code} |
| 123 | } |
| 124 | return errors.Wrap(err, "get unused recovery code") |
| 125 | } |
| 126 | |
| 127 | err = tx.Model(&recoveryCode).Update("is_used", true).Error |
| 128 | if err != nil { |
| 129 | return errors.Wrap(err, "mark recovery code as used") |
| 130 | } |
| 131 | return nil |
| 132 | }) |
| 133 | } |
| 134 | |
| 135 | // generateRecoveryCodes generates N number of recovery codes for 2FA. |
| 136 | func generateRecoveryCodes(userID int64, n int) ([]*TwoFactorRecoveryCode, error) { |