mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +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 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 { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Unknown
					Unknown