-
Notifications
You must be signed in to change notification settings - Fork 12k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
More work on email and notification infra #1456
- Loading branch information
Showing
14 changed files
with
219 additions
and
63 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package notifications | ||
|
||
import ( | ||
"crypto/sha1" | ||
"encoding/hex" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/Unknwon/com" | ||
"github.com/grafana/grafana/pkg/setting" | ||
) | ||
|
||
// 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 { | ||
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() | ||
sh.Write([]byte(data + setting.SecretKey + startStr + endStr + com.ToStr(minutes))) | ||
encoded := hex.EncodeToString(sh.Sum(nil)) | ||
|
||
code := fmt.Sprintf("%s%06d%s", startStr, minutes, encoded) | ||
return code | ||
} | ||
|
||
// verify time limit code | ||
func VerifyTimeLimitCode(data string, minutes int, code string) bool { | ||
if len(code) <= 18 { | ||
return false | ||
} | ||
|
||
// split code | ||
start := code[:12] | ||
lives := code[12:18] | ||
if d, err := com.StrTo(lives).Int(); err == nil { | ||
minutes = d | ||
} | ||
|
||
// right active code | ||
retCode := CreateTimeLimitCode(data, minutes, start) | ||
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 | ||
} | ||
} | ||
|
||
return false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,77 @@ | ||
package notifications | ||
|
||
import "github.com/grafana/grafana/pkg/bus" | ||
import ( | ||
"bytes" | ||
"encoding/hex" | ||
"errors" | ||
"html/template" | ||
"path/filepath" | ||
|
||
func Init() { | ||
"github.com/Unknwon/com" | ||
"github.com/grafana/grafana/pkg/bus" | ||
m "github.com/grafana/grafana/pkg/models" | ||
"github.com/grafana/grafana/pkg/setting" | ||
"github.com/grafana/grafana/pkg/util" | ||
) | ||
|
||
var mailTemplates *template.Template | ||
var tmplResetPassword = "reset_password.html" | ||
|
||
func Init() error { | ||
bus.AddHandler("email", sendResetPasswordEmail) | ||
|
||
mailTemplates = template.New("name") | ||
mailTemplates.Funcs(template.FuncMap{ | ||
"Subject": subjectTemplateFunc, | ||
}) | ||
|
||
templatePattern := filepath.Join(setting.StaticRootPath, "emails/*.html") | ||
_, err := mailTemplates.ParseGlob(templatePattern) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if !util.IsEmail(setting.Smtp.FromAddress) { | ||
return errors.New("Invalid email address for smpt from_adress config") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
var dispatchMail = func(cmd *m.SendEmailCommand) error { | ||
return bus.Dispatch(cmd) | ||
} | ||
|
||
func sendResetPasswordEmail(cmd *SendResetPasswordEmailCommand) error { | ||
func subjectTemplateFunc(obj map[string]interface{}, value string) string { | ||
obj["value"] = value | ||
return "" | ||
} | ||
|
||
func sendResetPasswordEmail(cmd *m.SendResetPasswordEmailCommand) error { | ||
var buffer bytes.Buffer | ||
|
||
var data = getMailTmplData(nil) | ||
code := CreateUserActiveCode(cmd.User, nil) | ||
data["Code"] = code | ||
|
||
mailTemplates.ExecuteTemplate(&buffer, tmplResetPassword, data) | ||
|
||
dispatchMail(&m.SendEmailCommand{ | ||
To: []string{cmd.User.Email}, | ||
From: setting.Smtp.FromAddress, | ||
Subject: data["Subject"].(map[string]interface{})["value"].(string), | ||
Body: buffer.String(), | ||
}) | ||
|
||
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) | ||
|
||
// add tail hex username | ||
code += hex.EncodeToString([]byte(u.Login)) | ||
return code | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package notifications | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/grafana/grafana/pkg/bus" | ||
m "github.com/grafana/grafana/pkg/models" | ||
"github.com/grafana/grafana/pkg/setting" | ||
. "github.com/smartystreets/goconvey/convey" | ||
) | ||
|
||
func TestNotifications(t *testing.T) { | ||
|
||
Convey("Given the notifications service", t, func() { | ||
bus.ClearBusHandlers() | ||
|
||
setting.StaticRootPath = "../../../public/" | ||
setting.Smtp.FromAddress = "from@address.com" | ||
|
||
err := Init() | ||
So(err, ShouldBeNil) | ||
|
||
var sentMail *m.SendEmailCommand | ||
dispatchMail = func(cmd *m.SendEmailCommand) error { | ||
sentMail = cmd | ||
return nil | ||
} | ||
|
||
Convey("When sending reset email password", func() { | ||
sendResetPasswordEmail(&m.SendResetPasswordEmailCommand{User: &m.User{Email: "asd@asd.com"}}) | ||
So(sentMail.Body, ShouldContainSubstring, "h2") | ||
So(sentMail.Subject, ShouldEqual, "Welcome to Grafana") | ||
So(sentMail.Body, ShouldNotContainSubstring, "Subject") | ||
}) | ||
}) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package util | ||
|
||
import ( | ||
"regexp" | ||
"strings" | ||
) | ||
|
||
const ( | ||
emailRegexPattern string = "^(((([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$" | ||
) | ||
|
||
var ( | ||
regexEmail = regexp.MustCompile(emailRegexPattern) | ||
) | ||
|
||
func IsEmail(str string) bool { | ||
return regexEmail.MatchString(strings.ToLower(str)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{{Subject .Subject "Welcome to Grafana"}} | ||
|
||
<h2> | ||
{{.BuildVersion}} | ||
</h2> |