grafana/pkg/services/notifications/codes.go
Kat Yang f582e6c86a
Chore: Remove bus from password (#44482)
* Chore: Remove bus from password

* Refactor: Remove bus from password.go and adjust tests

* remove sqlstore dependency from notifications

* Chore: Remove bus from password

* Refactor: Remove bus from password.go and adjust tests

* remove sqlstore dependency (again)

* remove fmt printf

* fix dependencies in http server

* fix renamed method in tests

Co-authored-by: Serge Zaitsev <serge.zaitsev@grafana.com>
2022-02-03 10:33:46 +01:00

108 lines
2.6 KiB
Go

package notifications
import (
"crypto/sha1" // #nosec
"encoding/hex"
"fmt"
"time"
"github.com/unknwon/com"
"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, error) {
format := "200601021504"
var start, end time.Time
var startStr, endStr string
if startInf == nil {
// Use now time create code
start = time.Now()
startStr = start.Format(format)
} else {
// use start string create code
startStr = startInf.(string)
start, _ = time.ParseInLocation(format, startStr, time.Local)
startStr = start.Format(format)
}
end = start.Add(time.Minute * time.Duration(minutes))
endStr = end.Format(format)
// create sha1 encode string
sh := sha1.New()
if _, err := sh.Write([]byte(data + setting.SecretKey + startStr + endStr +
com.ToStr(minutes))); err != nil {
return "", err
}
encoded := hex.EncodeToString(sh.Sum(nil))
code := fmt.Sprintf("%s%06d%s", startStr, minutes, encoded)
return code, nil
}
// verify time limit code
func validateUserEmailCode(cfg *setting.Cfg, user *models.User, code string) (bool, error) {
if len(code) <= 18 {
return false, nil
}
minutes := cfg.EmailCodeValidMinutes
code = code[:timeLimitCodeLength]
// split code
start := code[:12]
lives := code[12:18]
if d, err := com.StrTo(lives).Int(); err == nil {
minutes = d
}
// right active code
data := com.ToStr(user.Id) + user.Email + user.Login + user.Password + user.Rands
retCode, err := createTimeLimitCode(data, minutes, start)
if err != nil {
return false, err
}
if retCode == code && minutes > 0 {
// check time is expired or not
before, _ := time.ParseInLocation("200601021504", start, time.Local)
now := time.Now()
if before.Add(time.Minute*time.Duration(minutes)).Unix() > now.Unix() {
return true, nil
}
}
return false, nil
}
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(cfg *setting.Cfg, u *models.User, startInf interface{}) (string, error) {
minutes := cfg.EmailCodeValidMinutes
data := com.ToStr(u.Id) + u.Email + u.Login + u.Password + u.Rands
code, err := createTimeLimitCode(data, minutes, startInf)
if err != nil {
return "", err
}
// add tail hex username
code += hex.EncodeToString([]byte(u.Login))
return code, nil
}