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