introduce the password reminder infrastructure
This commit is contained in:
+30
-8
@@ -15,7 +15,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -26,6 +25,33 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// PasswordChangeRequest represents a temporary password change request.
|
||||
type PasswordChangeRequest struct {
|
||||
Uid int32
|
||||
Username string
|
||||
Email string
|
||||
Authentication int32
|
||||
Expires time.Time
|
||||
}
|
||||
|
||||
// passwordRequests contains a map of password change requests currently managed.
|
||||
var passwordRequests map[int32]*PasswordChangeRequest = make(map[int32]*PasswordChangeRequest)
|
||||
|
||||
/* AmNewPasswordChangeRequest creates a new password change request and enrolls it.
|
||||
* Parameters:
|
||||
* uid - The UID of the user.
|
||||
* username - The user name of the user.
|
||||
* email - The E-mail address of the user.
|
||||
* Returns:
|
||||
* Pointer to the new PasswordChangeRequest.
|
||||
*/
|
||||
func AmNewPasswordChangeRequest(uid int32, username string, email string) *PasswordChangeRequest {
|
||||
rc := PasswordChangeRequest{Uid: uid, Username: username, Email: email,
|
||||
Authentication: util.GenerateRandomConfirmationNumber(), Expires: time.Now().Add(time.Hour)}
|
||||
passwordRequests[uid] = &rc
|
||||
return &rc
|
||||
}
|
||||
|
||||
// User represents a user in the Amsterdam database.
|
||||
type User struct {
|
||||
Mutex sync.RWMutex
|
||||
@@ -140,7 +166,7 @@ func (u *User) ConfirmEMailAddress(confnum int32, remoteIP string) error {
|
||||
func (u *User) NewEmailConfirmationNumber() error {
|
||||
u.Mutex.Lock()
|
||||
defer u.Mutex.Unlock()
|
||||
newnum := newEmailConfirmationNumber()
|
||||
newnum := util.GenerateRandomConfirmationNumber()
|
||||
_, err := amdb.Exec("UPDATE user SET email_confnum = ? WHERE uid = ?", newnum, u.Uid)
|
||||
if err != nil {
|
||||
u.EmailConfNum = newnum
|
||||
@@ -384,11 +410,6 @@ func AmAuthenticateUserByToken(authString string, remoteIP string) (*User, error
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// newEmailConfirmationNumber returns a new E-mail confirmation number.
|
||||
func newEmailConfirmationNumber() int32 {
|
||||
return rand.Int31n(9000000) + 1000000
|
||||
}
|
||||
|
||||
/* AmCreateNewUser creates a new user record in the database.
|
||||
* Parameters:
|
||||
* username - New user name.
|
||||
@@ -421,7 +442,8 @@ func AmCreateNewUser(username string, password string, reminder string, dob *tim
|
||||
// Insert the user record.
|
||||
_, err2 := amdb.Exec(`INSERT INTO users (username, passhash, verify_email, lockout, email_confnum,
|
||||
base_lvl, created, lastaccess, passreminder, description, dob) VALUES (?, ?, 0, 0, ?, ?, NOW(), NOW(), ?, '', ?)`,
|
||||
username, hashPassword(password), newEmailConfirmationNumber(), AmDefaultRole("Global.NewUser").Level(), reminder, *dob)
|
||||
username, hashPassword(password), util.GenerateRandomConfirmationNumber(), AmDefaultRole("Global.NewUser").Level(),
|
||||
reminder, *dob)
|
||||
if err2 != nil {
|
||||
return nil, err2
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ If this reminder is not sufficient for you to remember what your password is,
|
||||
then the system can change your password for you. To do so, please visit
|
||||
the following URL:
|
||||
|
||||
http://example.com/passrecovery/{{ change_uid }}.{{ change_auth }}
|
||||
http://example.com/passrecovery/{{ change_uid }}/{{ change_auth }}
|
||||
|
||||
Your password will be changed and a new password will be E-mailed to you
|
||||
at this address.
|
||||
|
||||
@@ -80,13 +80,14 @@ func Login(ctxt ui.AmContext) (string, any, error) {
|
||||
ci, uerr = user.ContactInfo()
|
||||
if uerr == nil {
|
||||
if ci != nil && ci.Email != nil && *ci.Email != "" {
|
||||
pchange := database.AmNewPasswordChangeRequest(user.Uid, user.Username, *ci.Email)
|
||||
msg := email.AmNewEmailMessage(ctxt.CurrentUserId(), ctxt.RemoteIP())
|
||||
msg.AddTo(*ci.Email, "")
|
||||
msg.SetTemplate("pass_remind.jet")
|
||||
msg.AddVariable("username", user.Username)
|
||||
msg.AddVariable("reminder", user.PassReminder)
|
||||
msg.AddVariable("change_uid", user.Uid)
|
||||
msg.AddVariable("change_auth", "TODO") // TODO: add change auth link
|
||||
msg.AddVariable("change_auth", pchange.Authentication)
|
||||
msg.Send()
|
||||
} else {
|
||||
uerr = errors.New("cannot find email address")
|
||||
|
||||
+8
-2
@@ -11,8 +11,9 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
crand "crypto/rand"
|
||||
"io"
|
||||
mrand "math/rand"
|
||||
)
|
||||
|
||||
// authAlphabet is the set of characters from which we generate auth strings.
|
||||
@@ -24,7 +25,7 @@ const authStringLen = 32
|
||||
// GenerateRandomAuthString generates a random authentication string.
|
||||
func GenerateRandomAuthString() string {
|
||||
b := make([]byte, authStringLen)
|
||||
if _, err := io.ReadFull(rand.Reader, b); err != nil {
|
||||
if _, err := io.ReadFull(crand.Reader, b); err != nil {
|
||||
// can't happen (at least on a modern OS)
|
||||
panic("failed to read random: " + err.Error())
|
||||
}
|
||||
@@ -33,3 +34,8 @@ func GenerateRandomAuthString() string {
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// GenerateRandomConfirmationNumber generates a random 7-digit confirmation number.
|
||||
func GenerateRandomConfirmationNumber() int32 {
|
||||
return mrand.Int31n(9000000) + 1000000
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user