Working on register mail confirmation
This commit is contained in:
parent
9a666f3377
commit
fbbae2b721
8 changed files with 189 additions and 14 deletions
12
conf/app.ini
12
conf/app.ini
|
@ -1,5 +1,6 @@
|
||||||
; App name that shows on every page title
|
; App name that shows on every page title
|
||||||
APP_NAME = Gogs: Go Git Service
|
APP_NAME = Gogs: Go Git Service
|
||||||
|
APP_LOGO = img/favicon.png
|
||||||
; !!MUST CHANGE TO YOUR USER NAME!!
|
; !!MUST CHANGE TO YOUR USER NAME!!
|
||||||
RUN_USER = lunny
|
RUN_USER = lunny
|
||||||
; Either "dev", "prod" or "test", default is "dev"
|
; Either "dev", "prod" or "test", default is "dev"
|
||||||
|
@ -11,7 +12,8 @@ LANG_IGNS = Google Go|C|Python|Ruby|C Sharp
|
||||||
LICENSES = Apache v2 License|GPL v2|MIT License|Affero GPL|BSD (3-Clause) License
|
LICENSES = Apache v2 License|GPL v2|MIT License|Affero GPL|BSD (3-Clause) License
|
||||||
|
|
||||||
[server]
|
[server]
|
||||||
DOMAIN = gogits.org
|
DOMAIN = localhost
|
||||||
|
ROOT_URL = http://%(DOMAIN)s:%(HTTP_PORT)s/
|
||||||
HTTP_ADDR =
|
HTTP_ADDR =
|
||||||
HTTP_PORT = 3000
|
HTTP_PORT = 3000
|
||||||
|
|
||||||
|
@ -27,7 +29,13 @@ SSL_MODE = disable
|
||||||
|
|
||||||
[security]
|
[security]
|
||||||
; !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!!
|
; !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!!
|
||||||
USER_PASSWD_SALT = !#@FDEWREWR&*(
|
SECRET_KEY = !#@FDEWREWR&*(
|
||||||
|
|
||||||
|
[service]
|
||||||
|
ACTIVE_CODE_LIVE_MINUTES = 180
|
||||||
|
RESET_PASSWD_CODE_LIVE_MINUTES = 180
|
||||||
|
; User need to confirm e-mail for registration
|
||||||
|
REGISTER_EMAIL_CONFIRM = true
|
||||||
|
|
||||||
[mailer]
|
[mailer]
|
||||||
ENABLED = false
|
ENABLED = false
|
||||||
|
|
|
@ -19,14 +19,6 @@ import (
|
||||||
"github.com/gogits/gogs/modules/base"
|
"github.com/gogits/gogs/modules/base"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
UserPasswdSalt string
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
UserPasswdSalt = base.Cfg.MustValue("security", "USER_PASSWD_SALT")
|
|
||||||
}
|
|
||||||
|
|
||||||
// User types.
|
// User types.
|
||||||
const (
|
const (
|
||||||
UT_INDIVIDUAL = iota + 1
|
UT_INDIVIDUAL = iota + 1
|
||||||
|
@ -56,6 +48,9 @@ type User struct {
|
||||||
AvatarEmail string `xorm:"not null"`
|
AvatarEmail string `xorm:"not null"`
|
||||||
Location string
|
Location string
|
||||||
Website string
|
Website string
|
||||||
|
IsActive bool
|
||||||
|
Rands string `xorm:"VARCHAR(10)"`
|
||||||
|
Expired time.Time
|
||||||
Created time.Time `xorm:"created"`
|
Created time.Time `xorm:"created"`
|
||||||
Updated time.Time `xorm:"updated"`
|
Updated time.Time `xorm:"updated"`
|
||||||
}
|
}
|
||||||
|
@ -104,6 +99,11 @@ func (user *User) NewGitSig() *git.Signature {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return a user salt token
|
||||||
|
func GetUserSalt() string {
|
||||||
|
return base.GetRandomString(10)
|
||||||
|
}
|
||||||
|
|
||||||
// RegisterUser creates record of a new user.
|
// RegisterUser creates record of a new user.
|
||||||
func RegisterUser(user *User) (err error) {
|
func RegisterUser(user *User) (err error) {
|
||||||
isExist, err := IsUserExist(user.Name)
|
isExist, err := IsUserExist(user.Name)
|
||||||
|
@ -123,6 +123,8 @@ func RegisterUser(user *User) (err error) {
|
||||||
user.LowerName = strings.ToLower(user.Name)
|
user.LowerName = strings.ToLower(user.Name)
|
||||||
user.Avatar = base.EncodeMd5(user.Email)
|
user.Avatar = base.EncodeMd5(user.Email)
|
||||||
user.AvatarEmail = user.Email
|
user.AvatarEmail = user.Email
|
||||||
|
user.Expired = time.Now().Add(3 * 24 * time.Hour)
|
||||||
|
user.Rands = GetUserSalt()
|
||||||
if err = user.EncodePasswd(); err != nil {
|
if err = user.EncodePasswd(); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if _, err = orm.Insert(user); err != nil {
|
} else if _, err = orm.Insert(user); err != nil {
|
||||||
|
@ -134,6 +136,11 @@ func RegisterUser(user *User) (err error) {
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send confirmation e-mail.
|
||||||
|
if base.Service.RegisterEmailConfitm {
|
||||||
|
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +190,7 @@ func DeleteUser(user *User) error {
|
||||||
|
|
||||||
// EncodePasswd encodes password to safe format.
|
// EncodePasswd encodes password to safe format.
|
||||||
func (user *User) EncodePasswd() error {
|
func (user *User) EncodePasswd() error {
|
||||||
newPasswd, err := scrypt.Key([]byte(user.Passwd), []byte(UserPasswdSalt), 16384, 8, 1, 64)
|
newPasswd, err := scrypt.Key([]byte(user.Passwd), []byte(base.SecretKey), 16384, 8, 1, 64)
|
||||||
user.Passwd = fmt.Sprintf("%x", newPasswd)
|
user.Passwd = fmt.Sprintf("%x", newPasswd)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
42
modules/auth/mail.go
Normal file
42
modules/auth/mail.go
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/models"
|
||||||
|
"github.com/gogits/gogs/modules/base"
|
||||||
|
"github.com/gogits/gogs/modules/mailer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// create a time limit code for user active
|
||||||
|
func CreateUserActiveCode(user *models.User, startInf interface{}) string {
|
||||||
|
hours := base.Service.ActiveCodeLives / 60
|
||||||
|
data := fmt.Sprintf("%d", user.Id) + user.Email + user.LowerName + user.Passwd + user.Rands
|
||||||
|
code := base.CreateTimeLimitCode(data, hours, startInf)
|
||||||
|
|
||||||
|
// add tail hex username
|
||||||
|
code += hex.EncodeToString([]byte(user.LowerName))
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send user register mail with active code
|
||||||
|
func SendRegisterMail(user *models.User) {
|
||||||
|
code := CreateUserActiveCode(user, nil)
|
||||||
|
subject := "Register success, Welcome"
|
||||||
|
|
||||||
|
data := mailer.GetMailTmplData(user)
|
||||||
|
data["Code"] = code
|
||||||
|
body := base.RenderTemplate("mail/auth/register_success.html", data)
|
||||||
|
_, _, _ = code, subject, body
|
||||||
|
|
||||||
|
// msg := mailer.NewMailMessage([]string{user.Email}, subject, body)
|
||||||
|
// msg.Info = fmt.Sprintf("UID: %d, send register mail", user.Id)
|
||||||
|
|
||||||
|
// // async send mail
|
||||||
|
// mailer.SendAsync(msg)
|
||||||
|
}
|
|
@ -28,11 +28,20 @@ type Mailer struct {
|
||||||
var (
|
var (
|
||||||
AppVer string
|
AppVer string
|
||||||
AppName string
|
AppName string
|
||||||
|
AppLogo string
|
||||||
|
AppUrl string
|
||||||
Domain string
|
Domain string
|
||||||
|
SecretKey string
|
||||||
Cfg *goconfig.ConfigFile
|
Cfg *goconfig.ConfigFile
|
||||||
MailService *Mailer
|
MailService *Mailer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var Service struct {
|
||||||
|
RegisterEmailConfitm bool
|
||||||
|
ActiveCodeLives int
|
||||||
|
ResetPwdCodeLives int
|
||||||
|
}
|
||||||
|
|
||||||
func exeDir() (string, error) {
|
func exeDir() (string, error) {
|
||||||
file, err := exec.LookPath(os.Args[0])
|
file, err := exec.LookPath(os.Args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -54,6 +63,11 @@ var logLevels = map[string]string{
|
||||||
"Critical": "5",
|
"Critical": "5",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newService() {
|
||||||
|
Service.ActiveCodeLives = Cfg.MustInt("service", "ACTIVE_CODE_LIVE_MINUTES", 180)
|
||||||
|
Service.ResetPwdCodeLives = Cfg.MustInt("service", "RESET_PASSWD_CODE_LIVE_MINUTES", 180)
|
||||||
|
}
|
||||||
|
|
||||||
func newLogService() {
|
func newLogService() {
|
||||||
// Get and check log mode.
|
// Get and check log mode.
|
||||||
mode := Cfg.MustValue("log", "MODE", "console")
|
mode := Cfg.MustValue("log", "MODE", "console")
|
||||||
|
@ -117,6 +131,17 @@ func newMailService() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newRegisterService() {
|
||||||
|
if !Cfg.MustBool("service", "REGISTER_EMAIL_CONFIRM") {
|
||||||
|
return
|
||||||
|
} else if MailService == nil {
|
||||||
|
log.Warn("Register Service: Mail Service is not enabled")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Service.RegisterEmailConfitm = true
|
||||||
|
log.Info("Register Service Enabled")
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
var err error
|
var err error
|
||||||
workDir, err := exeDir()
|
workDir, err := exeDir()
|
||||||
|
@ -143,9 +168,13 @@ func init() {
|
||||||
Cfg.BlockMode = false
|
Cfg.BlockMode = false
|
||||||
|
|
||||||
AppName = Cfg.MustValue("", "APP_NAME", "Gogs: Go Git Service")
|
AppName = Cfg.MustValue("", "APP_NAME", "Gogs: Go Git Service")
|
||||||
|
AppLogo = Cfg.MustValue("", "APP_LOGO", "img/favicon.png")
|
||||||
|
AppUrl = Cfg.MustValue("server", "ROOT_URL")
|
||||||
Domain = Cfg.MustValue("server", "DOMAIN")
|
Domain = Cfg.MustValue("server", "DOMAIN")
|
||||||
|
SecretKey = Cfg.MustValue("security", "SECRET_KEY")
|
||||||
|
|
||||||
// Extensions.
|
// Extensions.
|
||||||
newLogService()
|
newLogService()
|
||||||
newMailService()
|
newMailService()
|
||||||
|
newRegisterService()
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ package base
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/sha1"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -22,6 +24,66 @@ func EncodeMd5(str string) string {
|
||||||
return hex.EncodeToString(m.Sum(nil))
|
return hex.EncodeToString(m.Sum(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Random generate string
|
||||||
|
func GetRandomString(n int) string {
|
||||||
|
const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||||
|
var bytes = make([]byte, n)
|
||||||
|
rand.Read(bytes)
|
||||||
|
for i, b := range bytes {
|
||||||
|
bytes[i] = alphanum[b%byte(len(alphanum))]
|
||||||
|
}
|
||||||
|
return string(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 := "YmdHi"
|
||||||
|
|
||||||
|
var start, end time.Time
|
||||||
|
var startStr, endStr string
|
||||||
|
|
||||||
|
if startInf == nil {
|
||||||
|
// Use now time create code
|
||||||
|
start = time.Now()
|
||||||
|
startStr = DateFormat(start, format)
|
||||||
|
} else {
|
||||||
|
// use start string create code
|
||||||
|
startStr = startInf.(string)
|
||||||
|
start, _ = DateParse(startStr, format)
|
||||||
|
startStr = DateFormat(start, format)
|
||||||
|
}
|
||||||
|
|
||||||
|
end = start.Add(time.Minute * time.Duration(minutes))
|
||||||
|
endStr = DateFormat(end, format)
|
||||||
|
|
||||||
|
// create sha1 encode string
|
||||||
|
sh := sha1.New()
|
||||||
|
sh.Write([]byte(data + SecretKey + startStr + endStr + fmt.Sprintf("%d", minutes)))
|
||||||
|
encoded := hex.EncodeToString(sh.Sum(nil))
|
||||||
|
|
||||||
|
code := fmt.Sprintf("%s%06d%s", startStr, minutes, encoded)
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
func RenderTemplate(TplNames string, Data map[interface{}]interface{}) string {
|
||||||
|
// if beego.RunMode == "dev" {
|
||||||
|
// beego.BuildTemplate(beego.ViewsPath)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ibytes := bytes.NewBufferString("")
|
||||||
|
// if _, ok := beego.BeeTemplates[TplNames]; !ok {
|
||||||
|
// panic("can't find templatefile in the path:" + TplNames)
|
||||||
|
// }
|
||||||
|
// err := beego.BeeTemplates[TplNames].ExecuteTemplate(ibytes, TplNames, Data)
|
||||||
|
// if err != nil {
|
||||||
|
// beego.Trace("template Execute err:", err)
|
||||||
|
// }
|
||||||
|
// icontent, _ := ioutil.ReadAll(ibytes)
|
||||||
|
// return string(icontent)
|
||||||
|
return "not implement yet"
|
||||||
|
}
|
||||||
|
|
||||||
// AvatarLink returns avatar link by given e-mail.
|
// AvatarLink returns avatar link by given e-mail.
|
||||||
func AvatarLink(email string) string {
|
func AvatarLink(email string) string {
|
||||||
return "http://1.gravatar.com/avatar/" + EncodeMd5(email)
|
return "http://1.gravatar.com/avatar/" + EncodeMd5(email)
|
||||||
|
|
24
modules/mailer/mail.go
Normal file
24
modules/mailer/mail.go
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package mailer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gogits/gogs/models"
|
||||||
|
"github.com/gogits/gogs/modules/base"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetMailTmplData(user *models.User) map[interface{}]interface{} {
|
||||||
|
data := make(map[interface{}]interface{}, 10)
|
||||||
|
data["AppName"] = base.AppName
|
||||||
|
data["AppVer"] = base.AppVer
|
||||||
|
data["AppUrl"] = base.AppUrl
|
||||||
|
data["AppLogo"] = base.AppLogo
|
||||||
|
data["ActiveCodeLives"] = base.Service.ActiveCodeLives
|
||||||
|
data["ResetPwdCodeLives"] = base.Service.ResetPwdCodeLives
|
||||||
|
if user != nil {
|
||||||
|
data["User"] = user
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
|
@ -37,6 +37,8 @@ func Logger() martini.Handler {
|
||||||
content = fmt.Sprintf("\033[1;33m%s\033[0m", content)
|
content = fmt.Sprintf("\033[1;33m%s\033[0m", content)
|
||||||
case 404:
|
case 404:
|
||||||
content = fmt.Sprintf("\033[1;31m%s\033[0m", content)
|
content = fmt.Sprintf("\033[1;31m%s\033[0m", content)
|
||||||
|
case 500:
|
||||||
|
content = fmt.Sprintf("\033[1;36m%s\033[0m", content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Println(content)
|
log.Println(content)
|
||||||
|
|
|
@ -131,9 +131,10 @@ func SignUp(ctx *middleware.Context, form auth.RegisterForm) {
|
||||||
}
|
}
|
||||||
|
|
||||||
u := &models.User{
|
u := &models.User{
|
||||||
Name: form.UserName,
|
Name: form.UserName,
|
||||||
Email: form.Email,
|
Email: form.Email,
|
||||||
Passwd: form.Password,
|
Passwd: form.Password,
|
||||||
|
IsActive: !base.Service.RegisterEmailConfitm,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := models.RegisterUser(u); err != nil {
|
if err := models.RegisterUser(u); err != nil {
|
||||||
|
|
Loading…
Reference in a new issue