/
password.go
104 lines (94 loc) · 2.56 KB
/
password.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package model
import (
"errors"
"github.com/wscherphof/essix/util"
"golang.org/x/crypto/bcrypt"
"time"
)
var (
ErrPasswordEmpty = errors.New("ErrPasswordEmpty")
ErrPasswordsNotEqual = errors.New("ErrPasswordsNotEqual")
ErrNotActivated = errors.New("ErrNotActivated")
ErrPasswordTokenTimedOut = errors.New("ErrPasswordTokenTimedOut")
)
const (
pwdTokenTimeOut = 1 * time.Hour
)
type password struct {
Created time.Time
Value []byte
}
func newPassword(pwd1, pwd2 string) (pwd *password, err error, conflict bool) {
if pwd1 == "" {
err, conflict = ErrPasswordEmpty, true
} else if pwd1 != pwd2 {
err, conflict = ErrPasswordsNotEqual, true
} else if hash, e := bcrypt.GenerateFromPassword([]byte(pwd1), bcrypt.DefaultCost); e != nil {
err, conflict = e, false
} else {
pwd = &password{
Created: time.Now(),
Value: hash,
}
}
return
}
/*
ValidatePassword tests whether the given password is valid for the Account. It
computes a cryptographic hash value that is compared to the hash stored in the
database.
*/
func (a *Account) ValidatePassword(password string) (err error) {
if !a.IsActive() {
err = ErrNotActivated
} else if err = bcrypt.CompareHashAndPassword(a.Password.Value, []byte(password)); err != nil {
err = ErrInvalidCredentials
}
return
}
type passwordToken struct {
Expires time.Time
Value string
}
/*
CreatePasswordToken generates a token that is needed to change the Account's
password.
*/
func (a *Account) CreatePasswordToken() error {
a.PasswordToken = &passwordToken{
Expires: time.Now().Add(pwdTokenTimeOut),
Value: util.NewToken(),
}
return a.Update(a)
}
/*
ClearPasswordToken clears the token to cancel the password changing process.
*/
func ClearPasswordToken(id, token string) {
if account, err, _ := GetAccount(id); err == nil {
if account.PasswordToken != nil && account.PasswordToken.Value == token {
account.PasswordToken = nil
account.Update(account)
}
}
}
/*
ChangePassword sets the Account's Password to the new password, if the given
token and old password are correct.
*/
func (a *Account) ChangePassword(token, pwd1, pwd2 string) (err error, conflict bool) {
if token == "" || a.PasswordToken == nil || token != a.PasswordToken.Value {
err, conflict = ErrInvalidCredentials, true
} else if time.Now().After(a.PasswordToken.Expires) {
a.PasswordToken = nil
a.Update(a)
err, conflict = ErrPasswordTokenTimedOut, true
} else if pwd, e, c := newPassword(pwd1, pwd2); e != nil {
err, conflict = e, c
} else {
a.PasswordToken = nil
a.Password = pwd
err = a.Update(a)
}
return
}