@@ -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 | ||||
} | } | ||||
@@ -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) | ||||
@@ -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, | |||||
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 { | if err := models.RegisterUser(u); err != nil { | ||||