Lots of work on user password reset, #1456
This commit is contained in:
@@ -7,12 +7,15 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
const timeLimitCodeLength = 12 + 6 + 40
|
||||
|
||||
// create a time limit code
|
||||
// code format: 12 length date time string + 6 minutes string + 40 sha1 encoded string
|
||||
func CreateTimeLimitCode(data string, minutes int, startInf interface{}) string {
|
||||
func createTimeLimitCode(data string, minutes int, startInf interface{}) string {
|
||||
format := "200601021504"
|
||||
|
||||
var start, end time.Time
|
||||
@@ -42,11 +45,14 @@ func CreateTimeLimitCode(data string, minutes int, startInf interface{}) string
|
||||
}
|
||||
|
||||
// verify time limit code
|
||||
func VerifyTimeLimitCode(data string, minutes int, code string) bool {
|
||||
func validateUserEmailCode(user *m.User, code string) bool {
|
||||
if len(code) <= 18 {
|
||||
return false
|
||||
}
|
||||
|
||||
minutes := setting.EmailCodeValidMinutes
|
||||
code = code[:timeLimitCodeLength]
|
||||
|
||||
// split code
|
||||
start := code[:12]
|
||||
lives := code[12:18]
|
||||
@@ -55,7 +61,9 @@ func VerifyTimeLimitCode(data string, minutes int, code string) bool {
|
||||
}
|
||||
|
||||
// right active code
|
||||
retCode := CreateTimeLimitCode(data, minutes, start)
|
||||
data := com.ToStr(user.Id) + user.Email + user.Login + user.Password + user.Rands
|
||||
retCode := createTimeLimitCode(data, minutes, start)
|
||||
fmt.Printf("code : %s\ncode2: %s", retCode, code)
|
||||
if retCode == code && minutes > 0 {
|
||||
// check time is expired or not
|
||||
before, _ := time.ParseInLocation("200601021504", start, time.Local)
|
||||
@@ -67,3 +75,24 @@ func VerifyTimeLimitCode(data string, minutes int, code string) bool {
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func getLoginForEmailCode(code string) string {
|
||||
if len(code) <= timeLimitCodeLength {
|
||||
return ""
|
||||
}
|
||||
|
||||
// use tail hex username query user
|
||||
hexStr := code[timeLimitCodeLength:]
|
||||
b, _ := hex.DecodeString(hexStr)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func createUserEmailCode(u *m.User, startInf interface{}) string {
|
||||
minutes := setting.EmailCodeValidMinutes
|
||||
data := com.ToStr(u.Id) + u.Email + u.Login + u.Password + u.Rands
|
||||
code := createTimeLimitCode(data, minutes, startInf)
|
||||
|
||||
// add tail hex username
|
||||
code += hex.EncodeToString([]byte(u.Login))
|
||||
return code
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestEmailCodes(t *testing.T) {
|
||||
|
||||
Convey("When generating code", t, func() {
|
||||
setting.EmailCodeValidMinutes = 120
|
||||
|
||||
user := &m.User{Id: 10, Email: "t@a.com", Login: "asd", Password: "1", Rands: "2"}
|
||||
code := createUserEmailCode(user, nil)
|
||||
|
||||
Convey("getLoginForCode should return login", func() {
|
||||
login := getLoginForEmailCode(code)
|
||||
So(login, ShouldEqual, "asd")
|
||||
})
|
||||
|
||||
Convey("Can verify valid code", func() {
|
||||
So(validateUserEmailCode(user, code), ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Cannot verify in-valid code", func() {
|
||||
code = "ASD"
|
||||
So(validateUserEmailCode(user, code), ShouldBeFalse)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
@@ -2,12 +2,10 @@ package notifications
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"html/template"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@@ -19,6 +17,7 @@ var tmplResetPassword = "reset_password.html"
|
||||
|
||||
func Init() error {
|
||||
bus.AddHandler("email", sendResetPasswordEmail)
|
||||
bus.AddHandler("email", validateResetPasswordCode)
|
||||
|
||||
mailTemplates = template.New("name")
|
||||
mailTemplates.Funcs(template.FuncMap{
|
||||
@@ -55,7 +54,7 @@ func sendResetPasswordEmail(cmd *m.SendResetPasswordEmailCommand) error {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
var data = getMailTmplData(cmd.User)
|
||||
code := CreateUserActiveCode(cmd.User, nil)
|
||||
code := createUserEmailCode(cmd.User, nil)
|
||||
data["Code"] = code
|
||||
|
||||
mailTemplates.ExecuteTemplate(&buffer, tmplResetPassword, data)
|
||||
@@ -70,44 +69,21 @@ func sendResetPasswordEmail(cmd *m.SendResetPasswordEmailCommand) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateUserActiveCode(u *m.User, startInf interface{}) string {
|
||||
minutes := setting.EmailCodeValidMinutes
|
||||
data := com.ToStr(u.Id) + u.Email + u.Login + u.Password + u.Rands
|
||||
code := CreateTimeLimitCode(data, minutes, startInf)
|
||||
func validateResetPasswordCode(query *m.ValidateResetPasswordCodeQuery) error {
|
||||
login := getLoginForEmailCode(query.Code)
|
||||
if login == "" {
|
||||
return m.ErrInvalidEmailCode
|
||||
}
|
||||
|
||||
// add tail hex username
|
||||
code += hex.EncodeToString([]byte(u.Login))
|
||||
return code
|
||||
userQuery := m.GetUserByLoginQuery{LoginOrEmail: login}
|
||||
if err := bus.Dispatch(&userQuery); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !validateUserEmailCode(userQuery.Result, query.Code) {
|
||||
return m.ErrInvalidEmailCode
|
||||
}
|
||||
|
||||
query.Result = userQuery.Result
|
||||
return nil
|
||||
}
|
||||
|
||||
// // verify active code when active account
|
||||
// func VerifyUserActiveCode(code string) (user *User) {
|
||||
// minutes := setting.Service.ActiveCodeLives
|
||||
//
|
||||
// if user = getVerifyUser(code); user != nil {
|
||||
// // time limit code
|
||||
// prefix := code[:base.TimeLimitCodeLength]
|
||||
// data := com.ToStr(user.Id) + user.Email + user.LowerName + user.Passwd + user.Rands
|
||||
//
|
||||
// if base.VerifyTimeLimitCode(data, minutes, prefix) {
|
||||
// return user
|
||||
// }
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
// // verify active code when active account
|
||||
// func VerifyUserActiveCode(code string) (user *User) {
|
||||
// minutes := setting.Service.ActiveCodeLives
|
||||
//
|
||||
// if user = getVerifyUser(code); user != nil {
|
||||
// // time limit code
|
||||
// prefix := code[:base.TimeLimitCodeLength]
|
||||
// data := com.ToStr(user.Id) + user.Email + user.LowerName + user.Passwd + user.Rands
|
||||
//
|
||||
// if base.VerifyTimeLimitCode(data, minutes, prefix) {
|
||||
// return user
|
||||
// }
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
|
||||
Reference in New Issue
Block a user