Browse Source

Working on register mail confirmation

Unknown 11 years ago
parent
commit
fbbae2b721
8 changed files with 189 additions and 14 deletions
  1. 10 2
      conf/app.ini
  2. 16 9
      models/user.go
  3. 42 0
      modules/auth/mail.go
  4. 29 0
      modules/base/conf.go
  5. 62 0
      modules/base/tool.go
  6. 24 0
      modules/mailer/mail.go
  7. 2 0
      modules/middleware/logger.go
  8. 4 3
      routers/user/user.go

+ 10 - 2
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

+ 16 - 9
models/user.go

@@ -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 - 0
modules/auth/mail.go

@@ -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)
+}

+ 29 - 0
modules/base/conf.go

@@ -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()
 }

+ 62 - 0
modules/base/tool.go

@@ -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 - 0
modules/mailer/mail.go

@@ -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
+}

+ 2 - 0
modules/middleware/logger.go

@@ -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)

+ 4 - 3
routers/user/user.go

@@ -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 {