Conflicts:
	routers/repo/download.go
This commit is contained in:
Don Bowman 2015-08-12 21:10:00 +00:00
commit 1cb46ede1a
250 changed files with 13805 additions and 6717 deletions

View file

@ -11,6 +11,7 @@ import (
)
type AdminEditUserForm struct {
FullName string `form:"fullname" binding:"MaxSize(100)"`
Email string `binding:"Required;Email;MaxSize(50)"`
Password string `binding:"OmitEmpty;MinSize(6);MaxSize(255)"`
Website string `binding:"MaxSize(50)"`

View file

@ -21,6 +21,10 @@ import (
"github.com/gogits/gogs/modules/uuid"
)
func IsAPIPath(url string) bool {
return strings.HasPrefix(url, "/api/")
}
// SignedInId returns the id of signed in user.
func SignedInId(req *http.Request, sess session.Store) int64 {
if !models.HasEngine {
@ -28,7 +32,7 @@ func SignedInId(req *http.Request, sess session.Store) int64 {
}
// API calls need to check access token.
if strings.HasPrefix(req.URL.Path, "/api/") {
if IsAPIPath(req.URL.Path) {
auHead := req.Header.Get("Authorization")
if len(auHead) > 0 {
auths := strings.Fields(auHead)
@ -51,7 +55,7 @@ func SignedInId(req *http.Request, sess session.Store) int64 {
}
if id, ok := uid.(int64); ok {
if _, err := models.GetUserById(id); err != nil {
if err != models.ErrUserNotExist {
if !models.IsErrUserNotExist(err) {
log.Error(4, "GetUserById: %v", err)
}
return 0
@ -76,7 +80,7 @@ func SignedInUser(req *http.Request, sess session.Store) (*models.User, bool) {
if len(webAuthUser) > 0 {
u, err := models.GetUserByName(webAuthUser)
if err != nil {
if err != models.ErrUserNotExist {
if !models.IsErrUserNotExist(err) {
log.Error(4, "GetUserByName: %v", err)
return nil, false
}
@ -111,7 +115,7 @@ func SignedInUser(req *http.Request, sess session.Store) (*models.User, bool) {
u, err := models.UserSignIn(uname, passwd)
if err != nil {
if err != models.ErrUserNotExist {
if !models.IsErrUserNotExist(err) {
log.Error(4, "UserSignIn: %v", err)
}
return nil, false
@ -167,12 +171,16 @@ func AssignForm(form interface{}, data map[string]interface{}) {
func getSize(field reflect.StructField, prefix string) string {
for _, rule := range strings.Split(field.Tag.Get("binding"), ";") {
if strings.HasPrefix(rule, prefix) {
return rule[8 : len(rule)-1]
return rule[len(prefix) : len(rule)-1]
}
}
return ""
}
func GetSize(field reflect.StructField) string {
return getSize(field, "Size(")
}
func GetMinSize(field reflect.StructField) string {
return getSize(field, "MinSize(")
}
@ -208,7 +216,14 @@ func validate(errs binding.Errors, data map[string]interface{}, f Form, l macaro
if errs[0].FieldNames[0] == field.Name {
data["Err_"+field.Name] = true
trName := l.Tr("form." + field.Name)
trName := field.Tag.Get("locale")
if len(trName) == 0 {
trName = l.Tr("form." + field.Name)
} else {
trName = l.Tr(trName)
}
switch errs[0].Classification {
case binding.ERR_REQUIRED:
data["ErrorMsg"] = trName + l.Tr("form.require_error")
@ -216,6 +231,8 @@ func validate(errs binding.Errors, data map[string]interface{}, f Form, l macaro
data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_error")
case binding.ERR_ALPHA_DASH_DOT:
data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_dot_error")
case binding.ERR_SIZE:
data["ErrorMsg"] = trName + l.Tr("form.size_error", GetSize(field))
case binding.ERR_MIN_SIZE:
data["ErrorMsg"] = trName + l.Tr("form.min_size_error", GetMinSize(field))
case binding.ERR_MAX_SIZE:

View file

@ -30,6 +30,7 @@ type AuthenticationForm struct {
SMTPPort int `form:"smtp_port"`
TLS bool `form:"tls"`
AllowAutoRegister bool `form:"allowautoregister"`
PAMServiceName string
}
func (f *AuthenticationForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {

View file

@ -26,7 +26,7 @@ func (f *CreateOrgForm) Validate(ctx *macaron.Context, errs binding.Errors) bind
}
type UpdateOrgSettingForm struct {
OrgUserName string `form:"uname" binding:"Required;MaxSize(35)"`
OrgUserName string `form:"uname" binding:"Required;AlphaDashDot;MaxSize(30)" locale:"org.org_name_holder"`
OrgFullName string `form:"fullname" binding:"MaxSize(100)"`
Email string `form:"email" binding:"Required;Email;MaxSize(50)"`
Description string `form:"desc" binding:"MaxSize(255)"`

35
modules/auth/pam/pam.go Normal file
View file

@ -0,0 +1,35 @@
// +build pam
// 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 pam
import (
"errors"
"github.com/msteinert/pam"
)
func PAMAuth(serviceName, userName, passwd string) error {
t, err := pam.StartFunc(serviceName, userName, func(s pam.Style, msg string) (string, error) {
switch s {
case pam.PromptEchoOff:
return passwd, nil
case pam.PromptEchoOn, pam.ErrorMsg, pam.TextInfo:
return "", nil
}
return "", errors.New("Unrecognized PAM message style")
})
if err != nil {
return err
}
if err = t.Authenticate(0); err != nil {
return err
}
return nil
}

View file

@ -0,0 +1,15 @@
// +build !pam
// 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 pam
import (
"errors"
)
func PAMAuth(serviceName, userName, passwd string) error {
return errors.New("PAM not supported")
}

View file

@ -117,9 +117,9 @@ func (f *CreateIssueForm) Validate(ctx *macaron.Context, errs binding.Errors) bi
// \/ \/ \/ \/ \/
type CreateMilestoneForm struct {
Title string `form:"title" binding:"Required;MaxSize(50)"`
Content string `form:"content"`
Deadline string `form:"due_date"`
Title string `binding:"Required;MaxSize(50)"`
Content string
Deadline string
}
func (f *CreateMilestoneForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
@ -134,8 +134,9 @@ func (f *CreateMilestoneForm) Validate(ctx *macaron.Context, errs binding.Errors
// \/ \/ \/ \/
type CreateLabelForm struct {
Title string `form:"title" binding:"Required;MaxSize(50)"`
Color string `form:"color" binding:"Required;Size(7)"`
ID int64
Title string `binding:"Required;MaxSize(50)" locale:"repo.issues.label_name"`
Color string `binding:"Required;Size(7)" locale:"repo.issues.label_color"`
}
func (f *CreateLabelForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {

View file

@ -12,27 +12,36 @@ import (
)
type InstallForm struct {
DbType string `binding:"Required"`
DbHost string
DbUser string
DbPasswd string
DbName string
SSLMode string
DbPath string
RepoRootPath string `binding:"Required"`
RunUser string `binding:"Required"`
Domain string `binding:"Required"`
HTTPPort string `binding:"Required"`
AppUrl string `binding:"Required"`
SMTPHost string
SMTPEmail string
SMTPPasswd string
RegisterConfirm string
MailNotify string
AdminName string `binding:"Required;AlphaDashDot;MaxSize(30)"`
AdminPasswd string `binding:"Required;MinSize(6);MaxSize(255)"`
AdminConfirmPasswd string `binding:"Required;MinSize(6);MaxSize(255)"`
AdminEmail string `binding:"Required;Email;MaxSize(50)"`
DbType string `binding:"Required"`
DbHost string
DbUser string
DbPasswd string
DbName string
SSLMode string
DbPath string
AppName string `binding:"Required" locale:"install.app_name"`
RepoRootPath string `binding:"Required"`
RunUser string `binding:"Required"`
Domain string `binding:"Required"`
HTTPPort string `binding:"Required"`
AppUrl string `binding:"Required"`
SMTPHost string
SMTPFrom string
SMTPEmail string `binding:"OmitEmpty;Email;MaxSize(50)" locale:"install.mailer_user"`
SMTPPasswd string
RegisterConfirm bool
MailNotify bool
OfflineMode bool
DisableRegistration bool
RequireSignInView bool
AdminName string `binding:"OmitEmpty;AlphaDashDot;MaxSize(30)" locale:"install.admin_name"`
AdminPasswd string `binding:"OmitEmpty;MinSize(6);MaxSize(255)" locale:"install.admin_password"`
AdminConfirmPasswd string
AdminEmail string `binding:"OmitEmpty;Email;MaxSize(50)" locale:"install.admin_email"`
}
func (f *InstallForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
@ -107,7 +116,7 @@ func (f *AddEmailForm) Validate(ctx *macaron.Context, errs binding.Errors) bindi
}
type ChangePasswordForm struct {
OldPassword string `form:"old_password" binding:"Required;MinSize(6);MaxSize(255)"`
OldPassword string `form:"old_password" binding:"Required;MinSize(1);MaxSize(255)"`
Password string `form:"password" binding:"Required;MinSize(6);MaxSize(255)"`
Retype string `form:"retype"`
}
@ -117,8 +126,8 @@ func (f *ChangePasswordForm) Validate(ctx *macaron.Context, errs binding.Errors)
}
type AddSSHKeyForm struct {
SSHTitle string `form:"title" binding:"Required"`
Content string `form:"content" binding:"Required"`
Title string `binding:"Required;MaxSize(50)"`
Content string `binding:"Required"`
}
func (f *AddSSHKeyForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {

View file

@ -20,6 +20,10 @@ import (
"github.com/gogits/gogs/modules/setting"
)
func Safe(raw string) template.HTML {
return template.HTML(raw)
}
func Str2html(raw string) template.HTML {
return template.HTML(Sanitizer.Sanitize(raw))
}
@ -55,6 +59,9 @@ func ShortSha(sha1 string) string {
func DetectEncoding(content []byte) (string, error) {
detector := chardet.NewTextDetector()
result, err := detector.DetectBest(content)
if result.Charset != "UTF-8" && len(setting.AnsiCharset) > 0 {
return setting.AnsiCharset, err
}
return result.Charset, err
}
@ -64,7 +71,7 @@ func ToUtf8WithErr(content []byte) (error, string) {
return err, ""
}
if charsetLabel == "utf8" {
if charsetLabel == "UTF-8" {
return nil, string(content)
}
@ -125,6 +132,7 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{
return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms"
},
"AvatarLink": AvatarLink,
"Safe": Safe,
"Str2html": Str2html,
"TimeSince": TimeSince,
"FileSize": FileSize,
@ -175,7 +183,7 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{
"Oauth2Name": Oauth2Name,
"ToUtf8": ToUtf8,
"EscapePound": func(str string) string {
return strings.Replace(str, "#", "%23", -1)
return strings.Replace(strings.Replace(str, "%", "%25", -1), "#", "%23", -1)
},
"RenderCommitMessage": RenderCommitMessage,
}

File diff suppressed because one or more lines are too long

View file

@ -15,10 +15,10 @@ var c = New()
func NewCronContext() {
c.AddFunc("Update mirrors", "@every 1h", models.MirrorUpdate)
c.AddFunc("Deliver hooks", fmt.Sprintf("@every %dm", setting.Webhook.TaskInterval), models.DeliverHooks)
if setting.Git.Fsck.Enable {
c.AddFunc("Repository health check", fmt.Sprintf("@every %dh", setting.Git.Fsck.Interval), models.GitFsck)
}
c.AddFunc("Check repository statistics", "@every 24h", models.CheckRepoStats)
c.Start()
}

View file

@ -27,7 +27,7 @@ func (repo *Repository) GetTags() ([]string, error) {
}
stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "tag", "-l")
if err != nil {
return nil, errors.New(stderr)
return nil, concatenateError(err, stderr)
}
tags := strings.Split(stdout, "\n")
return tags[:len(tags)-1], nil

View file

@ -7,6 +7,7 @@ package git
import (
"bytes"
"container/list"
"fmt"
"os"
"path/filepath"
"strings"
@ -67,3 +68,10 @@ func isFile(filePath string) bool {
}
return !f.IsDir()
}
func concatenateError(err error, stderr string) error {
if len(stderr) == 0 {
return err
}
return fmt.Errorf("%v: %s", err, stderr)
}

View file

@ -214,7 +214,11 @@ func (l *Logger) writerMsg(skip, level int, msg string) error {
fnName = strings.TrimLeft(filepath.Ext(fn.Name()), ".") + "()"
}
lm.msg = fmt.Sprintf("[%s:%d %s] %s", filepath.Base(file), line, fnName, msg)
fileName := file
if len(fileName) > 20 {
fileName = "..." + fileName[len(fileName)-20:]
}
lm.msg = fmt.Sprintf("[%s:%d %s] %s", fileName, line, fnName, msg)
} else {
lm.msg = msg
}

View file

@ -104,13 +104,18 @@ func sendMail(settings *setting.Mailer, recipients []string, msgContent []byte)
return err
}
hostname, err := os.Hostname()
if err != nil {
return err
}
if !setting.MailService.DisableHelo {
hostname := setting.MailService.HeloHostname
if len(hostname) == 0 {
hostname, err = os.Hostname()
if err != nil {
return err
}
}
if err = client.Hello(hostname); err != nil {
return err
if err = client.Hello(hostname); err != nil {
return err
}
}
// If not using SMTPS, alway use STARTTLS if available

View file

@ -10,6 +10,7 @@ import (
"github.com/Unknwon/macaron"
"github.com/macaron-contrib/csrf"
"github.com/gogits/gogs/modules/auth"
"github.com/gogits/gogs/modules/setting"
)
@ -49,6 +50,12 @@ func Toggle(options *ToggleOptions) macaron.Handler {
if options.SignInRequire {
if !ctx.IsSigned {
// Restrict API calls with error message.
if auth.IsAPIPath(ctx.Req.URL.Path) {
ctx.HandleAPI(403, "Only signed in user is allowed to call APIs.")
return
}
ctx.SetCookie("redirect_to", url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl)
ctx.Redirect(setting.AppSubUrl + "/user/login")
return
@ -69,6 +76,7 @@ func Toggle(options *ToggleOptions) macaron.Handler {
}
}
// Contexter middleware already checks token for user sign in process.
func ApiReqToken() macaron.Handler {
return func(ctx *Context) {
if !ctx.IsSigned {

View file

@ -106,6 +106,12 @@ func (ctx *Context) HasError() bool {
return hasErr.(bool)
}
// HasValue returns true if value of given name exists.
func (ctx *Context) HasValue(name string) bool {
_, ok := ctx.Data[name]
return ok
}
// HTML calls Context.HTML and converts template name to string.
func (ctx *Context) HTML(status int, name base.TplName) {
ctx.Context.HTML(status, string(name))
@ -139,6 +145,13 @@ func (ctx *Context) Handle(status int, title string, err error) {
ctx.HTML(status, base.TplName(fmt.Sprintf("status/%d", status)))
}
func (ctx *Context) HandleText(status int, title string) {
if (status/100 == 4) || (status/100 == 5) {
log.Error(4, "%s", title)
}
ctx.RenderData(status, []byte(title))
}
func (ctx *Context) HandleAPI(status int, obj interface{}) {
var message string
if err, ok := obj.(error); ok {

View file

@ -34,7 +34,7 @@ func OrgAssignment(redirect bool, args ...bool) macaron.Handler {
var err error
ctx.Org.Organization, err = models.GetUserByName(orgName)
if err != nil {
if err == models.ErrUserNotExist {
if models.IsErrUserNotExist(err) {
ctx.Handle(404, "GetUserByName", err)
} else if redirect {
log.Error(4, "GetUserByName", err)
@ -47,6 +47,12 @@ func OrgAssignment(redirect bool, args ...bool) macaron.Handler {
org := ctx.Org.Organization
ctx.Data["Org"] = org
// Force redirection when username is actually a user.
if !org.IsOrganization() {
ctx.Redirect("/" + org.Name)
return
}
if ctx.IsSigned {
ctx.Org.IsOwner = org.IsOwnedBy(ctx.User.Id)
if ctx.Org.IsOwner {

View file

@ -10,6 +10,8 @@ import (
"strings"
"github.com/Unknwon/macaron"
"github.com/mcuadros/go-version"
"github.com/mssola/user_agent"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/base"
@ -18,6 +20,11 @@ import (
"github.com/gogits/gogs/modules/setting"
)
const (
FIREFOX_COPY_SUPPORT = "41.0"
CHROME_COPY_SUPPORT = "43.0.2356"
)
func ApiRepoAssignment() macaron.Handler {
return func(ctx *Context) {
userName := ctx.Params(":username")
@ -34,7 +41,7 @@ func ApiRepoAssignment() macaron.Handler {
} else {
u, err = models.GetUserByName(userName)
if err != nil {
if err == models.ErrUserNotExist {
if models.IsErrUserNotExist(err) {
ctx.Error(404)
} else {
ctx.JSON(500, &base.ApiJsonErr{"GetUserByName: " + err.Error(), base.DOC_URL})
@ -210,7 +217,7 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
} else {
u, err = models.GetUserByName(userName)
if err != nil {
if err == models.ErrUserNotExist {
if models.IsErrUserNotExist(err) {
ctx.Handle(404, "GetUserByName", err)
} else {
ctx.Handle(500, "GetUserByName", err)
@ -345,10 +352,17 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
ctx.Data["BranchName"] = ctx.Repo.BranchName
ctx.Data["CommitId"] = ctx.Repo.CommitId
userAgent := ctx.Req.Header.Get("User-Agent")
ua := user_agent.New(userAgent)
browserName, browserVer := ua.Browser()
ctx.Data["BrowserSupportsCopy"] = (browserName == "Chrome" && version.Compare(browserVer, CHROME_COPY_SUPPORT, ">=")) ||
(browserName == "Firefox" && version.Compare(browserVer, FIREFOX_COPY_SUPPORT, ">="))
}
}
func RequireAdmin() macaron.Handler {
func RequireRepoAdmin() macaron.Handler {
return func(ctx *Context) {
if ctx.Repo.AccessMode < models.ACCESS_MODE_ADMIN {
if !ctx.IsSigned {

View file

@ -53,6 +53,7 @@ var (
HttpAddr, HttpPort string
DisableSSH bool
SSHPort int
SSHDomain string
OfflineMode bool
DisableRouterLog bool
CertFile, KeyFile string
@ -75,7 +76,7 @@ var (
// Webhook settings.
Webhook struct {
TaskInterval int
QueueLength int
DeliverTimeout int
SkipTLSVerify bool
}
@ -83,6 +84,10 @@ var (
// Repository settings.
RepoRootPath string
ScriptType string
AnsiCharset string
// UI settings.
IssuePagingNum int
// Picture settings.
PictureService string
@ -129,6 +134,7 @@ var (
// I18n settings.
Langs, Names []string
dateLangs map[string]string
// Other settings.
ShowFooterBranding bool
@ -143,6 +149,14 @@ var (
HasRobotsTxt bool
)
func DateLang(lang string) string {
name, ok := dateLangs[lang]
if ok {
return name
}
return "en"
}
func init() {
IsWindows = runtime.GOOS == "windows"
log.NewLogger(0, "console", `{"level": 0}`)
@ -163,7 +177,18 @@ func ExecPath() (string, error) {
// WorkDir returns absolute path of work directory.
func WorkDir() (string, error) {
execPath, err := ExecPath()
return path.Dir(strings.Replace(execPath, "\\", "/", -1)), err
if err != nil {
return execPath, err
}
// Note: we don't use path.Dir here because it does not handle case
// which path starts with two "/" in Windows: "//psf/Home/..."
execPath = strings.Replace(execPath, "\\", "/", -1)
i := strings.LastIndex(execPath, "/")
if i == -1 {
return execPath, nil
}
return execPath[:i], nil
}
func forcePathSeparator(path string) {
@ -187,11 +212,11 @@ func NewConfigContext() {
CustomPath = os.Getenv("GOGS_CUSTOM")
if len(CustomPath) == 0 {
CustomPath = path.Join(workDir, "custom")
CustomPath = workDir + "/custom"
}
if len(CustomConf) == 0 {
CustomConf = path.Join(CustomPath, "conf/app.ini")
CustomConf = CustomPath + "/conf/app.ini"
}
if com.IsFile(CustomConf) {
@ -232,6 +257,7 @@ func NewConfigContext() {
HttpAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0")
HttpPort = sec.Key("HTTP_PORT").MustString("3000")
DisableSSH = sec.Key("DISABLE_SSH").MustBool()
SSHDomain = sec.Key("SSH_DOMAIN").MustString(Domain)
SSHPort = sec.Key("SSH_PORT").MustInt(22)
OfflineMode = sec.Key("OFFLINE_MODE").MustBool()
DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool()
@ -307,6 +333,10 @@ func NewConfigContext() {
RepoRootPath = path.Clean(RepoRootPath)
}
ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash")
AnsiCharset = sec.Key("ANSI_CHARSET").MustString("")
// UI settings.
IssuePagingNum = Cfg.Section("ui").Key("ISSUE_PAGING_NUM").MustInt(10)
sec = Cfg.Section("picture")
PictureService = sec.Key("SERVICE").In("server", []string{"server"})
@ -332,6 +362,7 @@ func NewConfigContext() {
Langs = Cfg.Section("i18n").Key("LANGS").Strings(",")
Names = Cfg.Section("i18n").Key("NAMES").Strings(",")
dateLangs = Cfg.Section("i18n.datelang").KeysHash()
ShowFooterBranding = Cfg.Section("other").Key("SHOW_FOOTER_BRANDING").MustBool()
@ -439,10 +470,10 @@ func newLogService() {
func newCacheService() {
CacheAdapter = Cfg.Section("cache").Key("ADAPTER").In("memory", []string{"memory", "redis", "memcache"})
if EnableRedis {
log.Info("Redis Enabled")
log.Info("Redis Supported")
}
if EnableMemcache {
log.Info("Memcache Enabled")
log.Info("Memcache Supported")
}
switch CacheAdapter {
@ -476,6 +507,8 @@ type Mailer struct {
Host string
From string
User, Passwd string
DisableHelo bool
HeloHostname string
SkipVerify bool
UseCertificate bool
CertFile, KeyFile string
@ -510,6 +543,8 @@ func newMailService() {
Host: sec.Key("HOST").String(),
User: sec.Key("USER").String(),
Passwd: sec.Key("PASSWD").String(),
DisableHelo: sec.Key("DISABLE_HELO").MustBool(),
HeloHostname: sec.Key("HELO_HOSTNAME").String(),
SkipVerify: sec.Key("SKIP_VERIFY").MustBool(),
UseCertificate: sec.Key("USE_CERTIFICATE").MustBool(),
CertFile: sec.Key("CERT_FILE").String(),
@ -543,7 +578,7 @@ func newNotifyMailService() {
func newWebhookService() {
sec := Cfg.Section("webhook")
Webhook.TaskInterval = sec.Key("TASK_INTERVAL").MustInt(1)
Webhook.QueueLength = sec.Key("QUEUE_LENGTH").MustInt(1000)
Webhook.DeliverTimeout = sec.Key("DELIVER_TIMEOUT").MustInt(5)
Webhook.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool()
}