diff --git a/conf/app.ini b/conf/app.ini index 3d4a25932..72c968b3e 100644 --- a/conf/app.ini +++ b/conf/app.ini @@ -16,3 +16,6 @@ NAME = gogs USER = root PASSWD = PASSWD_jiahua = root + +[security] +USER_PASSWD_SALT = !#@FDEWREWR&*( diff --git a/gogs.go b/gogs.go index 1ce0f7f98..42b1f92ba 100644 --- a/gogs.go +++ b/gogs.go @@ -19,7 +19,7 @@ import ( // Test that go1.1 tag above is included in builds. main.go refers to this definition. const go11tag = true -const APP_VER = "0.0.0.0305" +const APP_VER = "0.0.0.0306" func init() { runtime.GOMAXPROCS(runtime.NumCPU()) diff --git a/models/user.go b/models/user.go index d8469251e..912b04a3e 100644 --- a/models/user.go +++ b/models/user.go @@ -17,6 +17,12 @@ import ( "github.com/gogits/gogs/utils" ) +var UserPasswdSalt string + +func init() { + UserPasswdSalt = utils.Cfg.MustValue("security", "USER_PASSWD_SALT") +} + // User types. const ( UT_INDIVIDUAL = iota + 1 @@ -33,9 +39,9 @@ const ( type User struct { Id int64 LowerName string `xorm:"unique not null"` - Name string `xorm:"unique not null" valid:"AlphaDash;MinSize(5);MaxSize(30)"` - Email string `xorm:"unique not null" valid:"Email"` - Passwd string `xorm:"not null" valid:"MinSize(8)"` + Name string `xorm:"unique not null"` + Email string `xorm:"unique not null"` + Passwd string `xorm:"not null"` LoginType int Type int NumFollowers int @@ -79,6 +85,7 @@ var ( ErrUserOwnRepos = errors.New("User still have ownership of repositories") ErrUserAlreadyExist = errors.New("User already exist") ErrUserNotExist = errors.New("User does not exist") + ErrEmailAlreadyUsed = errors.New("E-mail already used") ) // IsUserExist checks if given user name exist, @@ -87,6 +94,10 @@ func IsUserExist(name string) (bool, error) { return orm.Get(&User{LowerName: strings.ToLower(name)}) } +func IsEmailUsed(email string) (bool, error) { + return orm.Get(&User{Email: email}) +} + // RegisterUser creates record of a new user. func RegisterUser(user *User) (err error) { isExist, err := IsUserExist(user.Name) @@ -96,9 +107,18 @@ func RegisterUser(user *User) (err error) { return ErrUserAlreadyExist } + isExist, err = IsEmailUsed(user.Email) + if err != nil { + return err + } else if isExist { + return ErrEmailAlreadyUsed + } + user.LowerName = strings.ToLower(user.Name) user.Avatar = utils.EncodeMd5(user.Email) - user.EncodePasswd() + if err = user.EncodePasswd(); err != nil { + return err + } if _, err = orm.Insert(user); err != nil { return err } @@ -136,7 +156,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("!#@FDEWREWR&*("), 16384, 8, 1, 64) + newPasswd, err := scrypt.Key([]byte(user.Passwd), []byte(UserPasswdSalt), 16384, 8, 1, 64) user.Passwd = fmt.Sprintf("%x", newPasswd) return err } diff --git a/modules/auth/form.go b/modules/auth/form.go index f918543fe..23c107c86 100644 --- a/modules/auth/form.go +++ b/modules/auth/form.go @@ -17,10 +17,25 @@ import ( "github.com/gogits/gogs/utils/log" ) +type Form interface { + Name(field string) string +} + type RegisterForm struct { - Username string `form:"username" binding:"Required;AlphaDash;MinSize(5);MaxSize(30)"` - Email string `form:"email" binding:"Required;Email;MaxSize(50)"` - Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"` + UserName string `form:"username" binding:"Required;AlphaDash;MinSize(5);MaxSize(30)"` + Email string `form:"email" binding:"Required;Email;MaxSize(50)"` + Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"` + RetypePasswd string `form:"retypepasswd"` +} + +func (r *RegisterForm) Name(field string) string { + names := map[string]string{ + "UserName": "Username", + "Email": "E-mail address", + "Password": "Password", + "RetypePasswd": "Re-type password", + } + return names[field] } func getMinMaxSize(field reflect.StructField) string { @@ -32,7 +47,7 @@ func getMinMaxSize(field reflect.StructField) string { return "" } -func validate(errors *binding.Errors, data base.TmplData, form interface{}) { +func validate(errors *binding.Errors, data base.TmplData, form Form) { typ := reflect.TypeOf(form) val := reflect.ValueOf(form) @@ -54,15 +69,15 @@ func validate(errors *binding.Errors, data base.TmplData, form interface{}) { data["Err_"+field.Name] = true switch err { case binding.RequireError: - data["ErrorMsg"] = field.Name + " cannot be empty" + data["ErrorMsg"] = form.Name(field.Name) + " cannot be empty" case binding.AlphaDashError: - data["ErrorMsg"] = field.Name + " must be valid alpha or numeric or dash(-_) characters" + data["ErrorMsg"] = form.Name(field.Name) + " must be valid alpha or numeric or dash(-_) characters" case binding.MinSizeError: - data["ErrorMsg"] = field.Name + " must contain at least has " + getMinMaxSize(field) + " characters" + data["ErrorMsg"] = form.Name(field.Name) + " must contain at least " + getMinMaxSize(field) + " characters" case binding.MaxSizeError: - data["ErrorMsg"] = field.Name + " must contain at most has " + getMinMaxSize(field) + " characters" + data["ErrorMsg"] = form.Name(field.Name) + " must contain at most " + getMinMaxSize(field) + " characters" case binding.EmailError: - data["ErrorMsg"] = field.Name + " is not valid" + data["ErrorMsg"] = form.Name(field.Name) + " is not valid" default: data["ErrorMsg"] = "Unknown error: " + err } diff --git a/routers/user/user.go b/routers/user/user.go index 9e4e30bbb..c6a2752ca 100644 --- a/routers/user/user.go +++ b/routers/user/user.go @@ -118,30 +118,43 @@ func SignUp(form auth.RegisterForm, data base.TmplData, req *http.Request, r ren return } + if form.Password != form.RetypePasswd { + data["HasError"] = true + data["Err_Password"] = true + data["Err_RetypePasswd"] = true + data["ErrorMsg"] = "Password and re-type password are not same" + auth.AssignForm(form, data) + } + if hasErr, ok := data["HasError"]; ok && hasErr.(bool) { r.HTML(200, "user/signup", data) return } - //Front-end should do double check of password. u := &models.User{ - Name: form.Username, + Name: form.UserName, Email: form.Email, Passwd: form.Password, } if err := models.RegisterUser(u); err != nil { - if err.Error() == models.ErrUserAlreadyExist.Error() { - data["HasError"] = true + data["HasError"] = true + auth.AssignForm(form, data) + + switch err.Error() { + case models.ErrUserAlreadyExist.Error(): data["Err_Username"] = true data["ErrorMsg"] = "Username has been already taken" - auth.AssignForm(form, data) r.HTML(200, "user/signup", data) - return + case models.ErrEmailAlreadyUsed.Error(): + data["Err_Email"] = true + data["ErrorMsg"] = "E-mail address has been already used" + r.HTML(200, "user/signup", data) + default: + data["ErrorMsg"] = err + log.Error("user.SignUp: %v", data) + r.HTML(500, "base/error", nil) } - - log.Error("user.SignUp: %v", err) - r.HTML(500, "status/500", nil) return } diff --git a/templates/base/error.tmpl b/templates/base/error.tmpl index 8d3c36be9..fbd424bff 100644 --- a/templates/base/error.tmpl +++ b/templates/base/error.tmpl @@ -1,6 +1,6 @@ {{template "base/head" .}} {{template "base/navbar" .}}
- An error is occupied : {{.Error}} + An error is occurred : {{.ErrorMsg}}
{{template "base/footer" .}} \ No newline at end of file diff --git a/templates/user/signup.tmpl b/templates/user/signup.tmpl index 265365bfb..76064bf76 100644 --- a/templates/user/signup.tmpl +++ b/templates/user/signup.tmpl @@ -6,7 +6,7 @@ {{if .HasError}}
{{.ErrorMsg}}
{{end}} -
+
@@ -25,7 +25,7 @@
-
+