mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-04 01:34:27 +00:00 
			
		
		
		
	Working on register mail confirmation
This commit is contained in:
		
							
								
								
									
										12
									
								
								conf/app.ini
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								conf/app.ini
									
									
									
									
									
								
							@@ -1,5 +1,6 @@
 | 
			
		||||
; App name that shows on every page title
 | 
			
		||||
APP_NAME = Gogs: Go Git Service
 | 
			
		||||
APP_LOGO = img/favicon.png
 | 
			
		||||
; !!MUST CHANGE TO YOUR USER NAME!!
 | 
			
		||||
RUN_USER = lunny
 | 
			
		||||
; 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
 | 
			
		||||
 | 
			
		||||
[server]
 | 
			
		||||
DOMAIN = gogits.org
 | 
			
		||||
DOMAIN = localhost
 | 
			
		||||
ROOT_URL = http://%(DOMAIN)s:%(HTTP_PORT)s/
 | 
			
		||||
HTTP_ADDR = 
 | 
			
		||||
HTTP_PORT = 3000
 | 
			
		||||
 | 
			
		||||
@@ -27,7 +29,13 @@ SSL_MODE = disable
 | 
			
		||||
 | 
			
		||||
[security]
 | 
			
		||||
; !!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]
 | 
			
		||||
ENABLED = false
 | 
			
		||||
 
 | 
			
		||||
@@ -19,14 +19,6 @@ import (
 | 
			
		||||
	"github.com/gogits/gogs/modules/base"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	UserPasswdSalt string
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	UserPasswdSalt = base.Cfg.MustValue("security", "USER_PASSWD_SALT")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// User types.
 | 
			
		||||
const (
 | 
			
		||||
	UT_INDIVIDUAL = iota + 1
 | 
			
		||||
@@ -56,6 +48,9 @@ type User struct {
 | 
			
		||||
	AvatarEmail   string `xorm:"not null"`
 | 
			
		||||
	Location      string
 | 
			
		||||
	Website       string
 | 
			
		||||
	IsActive      bool
 | 
			
		||||
	Rands         string `xorm:"VARCHAR(10)"`
 | 
			
		||||
	Expired       time.Time
 | 
			
		||||
	Created       time.Time `xorm:"created"`
 | 
			
		||||
	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.
 | 
			
		||||
func RegisterUser(user *User) (err error) {
 | 
			
		||||
	isExist, err := IsUserExist(user.Name)
 | 
			
		||||
@@ -123,6 +123,8 @@ func RegisterUser(user *User) (err error) {
 | 
			
		||||
	user.LowerName = strings.ToLower(user.Name)
 | 
			
		||||
	user.Avatar = base.EncodeMd5(user.Email)
 | 
			
		||||
	user.AvatarEmail = user.Email
 | 
			
		||||
	user.Expired = time.Now().Add(3 * 24 * time.Hour)
 | 
			
		||||
	user.Rands = GetUserSalt()
 | 
			
		||||
	if err = user.EncodePasswd(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if _, err = orm.Insert(user); err != nil {
 | 
			
		||||
@@ -134,6 +136,11 @@ func RegisterUser(user *User) (err error) {
 | 
			
		||||
		}
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Send confirmation e-mail.
 | 
			
		||||
	if base.Service.RegisterEmailConfitm {
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -183,7 +190,7 @@ func DeleteUser(user *User) error {
 | 
			
		||||
 | 
			
		||||
// EncodePasswd encodes password to safe format.
 | 
			
		||||
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)
 | 
			
		||||
	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 (
 | 
			
		||||
	AppVer      string
 | 
			
		||||
	AppName     string
 | 
			
		||||
	AppLogo     string
 | 
			
		||||
	AppUrl      string
 | 
			
		||||
	Domain      string
 | 
			
		||||
	SecretKey   string
 | 
			
		||||
	Cfg         *goconfig.ConfigFile
 | 
			
		||||
	MailService *Mailer
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var Service struct {
 | 
			
		||||
	RegisterEmailConfitm bool
 | 
			
		||||
	ActiveCodeLives      int
 | 
			
		||||
	ResetPwdCodeLives    int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func exeDir() (string, error) {
 | 
			
		||||
	file, err := exec.LookPath(os.Args[0])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -54,6 +63,11 @@ var logLevels = map[string]string{
 | 
			
		||||
	"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() {
 | 
			
		||||
	// Get and check log mode.
 | 
			
		||||
	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() {
 | 
			
		||||
	var err error
 | 
			
		||||
	workDir, err := exeDir()
 | 
			
		||||
@@ -143,9 +168,13 @@ func init() {
 | 
			
		||||
	Cfg.BlockMode = false
 | 
			
		||||
 | 
			
		||||
	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")
 | 
			
		||||
	SecretKey = Cfg.MustValue("security", "SECRET_KEY")
 | 
			
		||||
 | 
			
		||||
	// Extensions.
 | 
			
		||||
	newLogService()
 | 
			
		||||
	newMailService()
 | 
			
		||||
	newRegisterService()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,8 @@ package base
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"crypto/md5"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"crypto/sha1"
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
@@ -22,6 +24,66 @@ func EncodeMd5(str string) string {
 | 
			
		||||
	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.
 | 
			
		||||
func AvatarLink(email string) string {
 | 
			
		||||
	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)
 | 
			
		||||
			case 404:
 | 
			
		||||
				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)
 | 
			
		||||
 
 | 
			
		||||
@@ -131,9 +131,10 @@ func SignUp(ctx *middleware.Context, form auth.RegisterForm) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	u := &models.User{
 | 
			
		||||
		Name:   form.UserName,
 | 
			
		||||
		Email:  form.Email,
 | 
			
		||||
		Passwd: form.Password,
 | 
			
		||||
		Name:     form.UserName,
 | 
			
		||||
		Email:    form.Email,
 | 
			
		||||
		Passwd:   form.Password,
 | 
			
		||||
		IsActive: !base.Service.RegisterEmailConfitm,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := models.RegisterUser(u); err != nil {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user