@@ -16,3 +16,6 @@ NAME = gogs | |||
USER = root | |||
PASSWD = | |||
PASSWD_jiahua = root | |||
[security] | |||
USER_PASSWD_SALT = !#@FDEWREWR&*( |
@@ -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()) | |||
@@ -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 | |||
} | |||
@@ -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 | |||
} | |||
@@ -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 | |||
} | |||
@@ -1,6 +1,6 @@ | |||
{{template "base/head" .}} | |||
{{template "base/navbar" .}} | |||
<div id="gogs-body" class="container"> | |||
An error is occupied : {{.Error}} | |||
An error is occurred : {{.ErrorMsg}} | |||
</div> | |||
{{template "base/footer" .}} |
@@ -6,7 +6,7 @@ | |||
{{if .HasError}} | |||
<div class="alert alert-danger">{{.ErrorMsg}}</div> | |||
{{end}} | |||
<div class="form-group {{if .Err_Username}}has-error has-feedback{{end}}"> | |||
<div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}"> | |||
<label class="col-md-4 control-label">Username: </label> | |||
<div class="col-md-6"> | |||
<input name="username" class="form-control" placeholder="Type your username" value="{{.username}}"> | |||
@@ -25,7 +25,7 @@ | |||
<input name="passwd" type="password" class="form-control" placeholder="Type your password"> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="form-group {{if .Err_RetypePasswd}}has-error has-feedback{{end}}"> | |||
<label class="col-md-4 control-label">Re-type: </label> | |||
<div class="col-md-6"> | |||
<input type="password" class="form-control" placeholder="Re-type your password"> | |||