github.com/Azareal/Gosora@v0.0.0-20210729070923-553e66b59003/common/password_reset.go (about)

     1  package common
     2  
     3  import (
     4  	"crypto/subtle"
     5  	"database/sql"
     6  	"errors"
     7  
     8  	qgen "github.com/Azareal/Gosora/query_gen"
     9  )
    10  
    11  var PasswordResetter *DefaultPasswordResetter
    12  var ErrBadResetToken = errors.New("This reset token has expired.")
    13  
    14  type DefaultPasswordResetter struct {
    15  	getTokens *sql.Stmt
    16  	create    *sql.Stmt
    17  	delete    *sql.Stmt
    18  }
    19  
    20  /*
    21  	type PasswordReset struct {
    22  		Email string `q:"email"`
    23  		Uid int `q:"uid"`
    24  		Validated bool `q:"validated"`
    25  		Token string `q:"token"`
    26  		CreatedAt time.Time `q:"createdAt"`
    27  	}
    28  */
    29  
    30  func NewDefaultPasswordResetter(acc *qgen.Accumulator) (*DefaultPasswordResetter, error) {
    31  	pr := "password_resets"
    32  	return &DefaultPasswordResetter{
    33  		getTokens: acc.Select(pr).Columns("token").Where("uid=?").Prepare(),
    34  		create:    acc.Insert(pr).Columns("email,uid,validated,token,createdAt").Fields("?,?,0,?,UTC_TIMESTAMP()").Prepare(),
    35  		//create: acc.Insert(pr).Cols("email,uid,validated=0,token,createdAt=UTC_TIMESTAMP()").Prep(),
    36  		delete: acc.Delete(pr).Where("uid=?").Prepare(),
    37  		//model:  acc.Model(w).Cols("email,uid,validated=0,token").Key("uid").CreatedAt("createdAt").Prep(),
    38  	}, acc.FirstError()
    39  }
    40  
    41  func (r *DefaultPasswordResetter) Create(email string, uid int, token string) error {
    42  	_, err := r.create.Exec(email, uid, token)
    43  	return err
    44  }
    45  
    46  func (r *DefaultPasswordResetter) FlushTokens(uid int) error {
    47  	_, err := r.delete.Exec(uid)
    48  	return err
    49  }
    50  
    51  func (r *DefaultPasswordResetter) ValidateToken(uid int, token string) error {
    52  	rows, err := r.getTokens.Query(uid)
    53  	if err != nil {
    54  		return err
    55  	}
    56  	defer rows.Close()
    57  
    58  	success := false
    59  	for rows.Next() {
    60  		var rtoken string
    61  		if err := rows.Scan(&rtoken); err != nil {
    62  			return err
    63  		}
    64  		if subtle.ConstantTimeCompare([]byte(token), []byte(rtoken)) == 1 {
    65  			success = true
    66  		}
    67  	}
    68  	if err = rows.Err(); err != nil {
    69  		return err
    70  	}
    71  
    72  	if !success {
    73  		return ErrBadResetToken
    74  	}
    75  	return nil
    76  }