The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/services/notifications/codes.go

107 lines
2.6 KiB

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
}