diff options
author | evolvedlight <steve@evolvedlight.co.uk> | 2014-10-13 20:30:31 +0100 |
---|---|---|
committer | evolvedlight <steve@evolvedlight.co.uk> | 2014-10-13 20:30:31 +0100 |
commit | 8d2a6fc484b540819e211d52b8d54e97269f0918 (patch) | |
tree | e5bfe7d3937bb2d18ba2fb50ea72514bd5bb4e13 /modules | |
parent | 29ac3980ffdb5faa525d77fddc109c9023ebe257 (diff) | |
parent | 89bd994c836ecc9b6ceb80849f470521e1b15917 (diff) |
Merge remote-tracking branch 'upstream/dev'
Conflicts:
models/repo.go
Diffstat (limited to 'modules')
-rw-r--r-- | modules/auth/repo_form.go | 2 | ||||
-rw-r--r-- | modules/base/markdown.go | 48 | ||||
-rw-r--r-- | modules/base/template.go | 66 | ||||
-rw-r--r-- | modules/base/tool.go | 27 | ||||
-rw-r--r-- | modules/git/hooks.go | 111 | ||||
-rw-r--r-- | modules/git/repo_tag.go | 12 | ||||
-rw-r--r-- | modules/git/utils.go | 21 | ||||
-rw-r--r-- | modules/git/version.go | 4 | ||||
-rw-r--r-- | modules/mailer/mailer.go | 55 | ||||
-rw-r--r-- | modules/middleware/context.go | 8 | ||||
-rw-r--r-- | modules/middleware/repo.go | 10 | ||||
-rw-r--r-- | modules/setting/setting.go | 2 |
12 files changed, 268 insertions, 98 deletions
diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go index 233f7b10..df5b8b69 100644 --- a/modules/auth/repo_form.go +++ b/modules/auth/repo_form.go @@ -102,7 +102,7 @@ func (f *NewSlackHookForm) Validate(ctx *macaron.Context, errs *binding.Errors, // \/ \/ \/ type CreateIssueForm struct { - IssueName string `form:"title" binding:"Required;MaxSize(50)"` + IssueName string `form:"title" binding:"Required;MaxSize(255)"` MilestoneId int64 `form:"milestoneid"` AssigneeId int64 `form:"assigneeid"` Labels string `form:"labels"` diff --git a/modules/base/markdown.go b/modules/base/markdown.go index a3db15df..cb083200 100644 --- a/modules/base/markdown.go +++ b/modules/base/markdown.go @@ -13,7 +13,8 @@ import ( "regexp" "strings" - "github.com/gogits/gfm" + "github.com/russross/blackfriday" + "github.com/gogits/gogs/modules/setting" ) @@ -74,7 +75,7 @@ func IsReadmeFile(name string) bool { } type CustomRender struct { - gfm.Renderer + blackfriday.Renderer urlPrefix string } @@ -154,39 +155,40 @@ func RenderSpecialLink(rawBytes []byte, urlPrefix string) []byte { func RenderRawMarkdown(body []byte, urlPrefix string) []byte { htmlFlags := 0 - // htmlFlags |= gfm.HTML_USE_XHTML - // htmlFlags |= gfm.HTML_USE_SMARTYPANTS - // htmlFlags |= gfm.HTML_SMARTYPANTS_FRACTIONS - // htmlFlags |= gfm.HTML_SMARTYPANTS_LATEX_DASHES - // htmlFlags |= gfm.HTML_SKIP_HTML - htmlFlags |= gfm.HTML_SKIP_STYLE - htmlFlags |= gfm.HTML_SKIP_SCRIPT - htmlFlags |= gfm.HTML_GITHUB_BLOCKCODE - htmlFlags |= gfm.HTML_OMIT_CONTENTS - // htmlFlags |= gfm.HTML_COMPLETE_PAGE + // htmlFlags |= blackfriday.HTML_USE_XHTML + // htmlFlags |= blackfriday.HTML_USE_SMARTYPANTS + // htmlFlags |= blackfriday.HTML_SMARTYPANTS_FRACTIONS + // htmlFlags |= blackfriday.HTML_SMARTYPANTS_LATEX_DASHES + // htmlFlags |= blackfriday.HTML_SKIP_HTML + htmlFlags |= blackfriday.HTML_SKIP_STYLE + // htmlFlags |= blackfriday.HTML_SKIP_SCRIPT + // htmlFlags |= blackfriday.HTML_GITHUB_BLOCKCODE + htmlFlags |= blackfriday.HTML_OMIT_CONTENTS + // htmlFlags |= blackfriday.HTML_COMPLETE_PAGE renderer := &CustomRender{ - Renderer: gfm.HtmlRenderer(htmlFlags, "", ""), + Renderer: blackfriday.HtmlRenderer(htmlFlags, "", ""), urlPrefix: urlPrefix, } // set up the parser extensions := 0 - extensions |= gfm.EXTENSION_NO_INTRA_EMPHASIS - extensions |= gfm.EXTENSION_TABLES - extensions |= gfm.EXTENSION_FENCED_CODE - extensions |= gfm.EXTENSION_AUTOLINK - extensions |= gfm.EXTENSION_STRIKETHROUGH - extensions |= gfm.EXTENSION_HARD_LINE_BREAK - extensions |= gfm.EXTENSION_SPACE_HEADERS - extensions |= gfm.EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK - - body = gfm.Markdown(body, renderer, extensions) + extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS + extensions |= blackfriday.EXTENSION_TABLES + extensions |= blackfriday.EXTENSION_FENCED_CODE + extensions |= blackfriday.EXTENSION_AUTOLINK + extensions |= blackfriday.EXTENSION_STRIKETHROUGH + extensions |= blackfriday.EXTENSION_HARD_LINE_BREAK + extensions |= blackfriday.EXTENSION_SPACE_HEADERS + extensions |= blackfriday.EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK + + body = blackfriday.Markdown(body, renderer, extensions) return body } func RenderMarkdown(rawBytes []byte, urlPrefix string) []byte { body := RenderSpecialLink(rawBytes, urlPrefix) body = RenderRawMarkdown(body, urlPrefix) + body = XSS(body) return body } diff --git a/modules/base/template.go b/modules/base/template.go index b1c8c161..6d25cd45 100644 --- a/modules/base/template.go +++ b/modules/base/template.go @@ -5,7 +5,6 @@ package base import ( - "bytes" "container/list" "encoding/json" "errors" @@ -107,7 +106,6 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{ return a + b }, "ActionIcon": ActionIcon, - "ActionDesc": ActionDesc, "DateFormat": DateFormat, "List": List, "Mail2Domain": func(mail string) string { @@ -162,19 +160,6 @@ func ActionIcon(opType int) string { } } -// FIXME: Legacy -const ( - TPL_CREATE_REPO = `<a href="%s/user/%s">%s</a> created repository <a href="%s">%s</a>` - TPL_COMMIT_REPO = `<a href="%s/user/%s">%s</a> pushed to <a href="%s/src/%s">%s</a> at <a href="%s">%s</a>%s` - TPL_COMMIT_REPO_LI = `<div><img src="%s?s=16" alt="user-avatar"/> <a href="%s/commit/%s" rel="nofollow">%s</a> %s</div>` - TPL_CREATE_ISSUE = `<a href="%s/user/%s">%s</a> opened issue <a href="%s/issues/%s">%s#%s</a> -<div><img src="%s?s=16" alt="user-avatar"/> %s</div>` - TPL_TRANSFER_REPO = `<a href="%s/user/%s">%s</a> transfered repository <code>%s</code> to <a href="%s">%s</a>` - TPL_PUSH_TAG = `<a href="%s/user/%s">%s</a> pushed tag <a href="%s/src/%s" rel="nofollow">%s</a> at <a href="%s">%s</a>` - TPL_COMMENT_ISSUE = `<a href="%s/user/%s">%s</a> commented on issue <a href="%s/issues/%s">%s#%s</a> -<div><img src="%s?s=16" alt="user-avatar"/> %s</div>` -) - type PushCommit struct { Sha1 string Message string @@ -183,8 +168,9 @@ type PushCommit struct { } type PushCommits struct { - Len int - Commits []*PushCommit + Len int + Commits []*PushCommit + CompareUrl string } func ActionContent2Commits(act Actioner) *PushCommits { @@ -195,52 +181,6 @@ func ActionContent2Commits(act Actioner) *PushCommits { return push } -// FIXME: Legacy -// ActionDesc accepts int that represents action operation type -// and returns the description. -func ActionDesc(act Actioner) string { - actUserName := act.GetActUserName() - email := act.GetActEmail() - repoUserName := act.GetRepoUserName() - repoName := act.GetRepoName() - repoLink := repoUserName + "/" + repoName - branch := act.GetBranch() - content := act.GetContent() - switch act.GetOpType() { - case 1: // Create repository. - return fmt.Sprintf(TPL_CREATE_REPO, setting.AppSubUrl, actUserName, actUserName, repoLink, repoName) - case 5: // Commit repository. - var push *PushCommits - if err := json.Unmarshal([]byte(content), &push); err != nil { - return err.Error() - } - buf := bytes.NewBuffer([]byte("\n")) - for _, commit := range push.Commits { - buf.WriteString(fmt.Sprintf(TPL_COMMIT_REPO_LI, AvatarLink(commit.AuthorEmail), repoLink, commit.Sha1, commit.Sha1[:7], commit.Message) + "\n") - } - if push.Len > 3 { - buf.WriteString(fmt.Sprintf(`<div><a href="{{AppRootSubUrl}}/%s/%s/commits/%s" rel="nofollow">%d other commits >></a></div>`, actUserName, repoName, branch, push.Len)) - } - return fmt.Sprintf(TPL_COMMIT_REPO, setting.AppSubUrl, actUserName, actUserName, repoLink, branch, branch, repoLink, repoLink, - buf.String()) - case 6: // Create issue. - infos := strings.SplitN(content, "|", 2) - return fmt.Sprintf(TPL_CREATE_ISSUE, setting.AppSubUrl, actUserName, actUserName, repoLink, infos[0], repoLink, infos[0], - AvatarLink(email), infos[1]) - case 8: // Transfer repository. - newRepoLink := content + "/" + repoName - return fmt.Sprintf(TPL_TRANSFER_REPO, setting.AppSubUrl, actUserName, actUserName, repoLink, newRepoLink, newRepoLink) - case 9: // Push tag. - return fmt.Sprintf(TPL_PUSH_TAG, setting.AppSubUrl, actUserName, actUserName, repoLink, branch, branch, repoLink, repoLink) - case 10: // Comment issue. - infos := strings.SplitN(content, "|", 2) - return fmt.Sprintf(TPL_COMMENT_ISSUE, setting.AppSubUrl, actUserName, actUserName, repoLink, infos[0], repoLink, infos[0], - AvatarLink(email), infos[1]) - default: - return "invalid type" - } -} - func DiffTypeToStr(diffType int) string { diffTypes := map[int]string{ 1: "add", 2: "modify", 3: "del", diff --git a/modules/base/tool.go b/modules/base/tool.go index b4083d09..38fd1e21 100644 --- a/modules/base/tool.go +++ b/modules/base/tool.go @@ -14,6 +14,7 @@ import ( "hash" "html/template" "math" + "regexp" "strings" "time" @@ -446,3 +447,29 @@ func DateFormat(t time.Time, format string) string { format = replacer.Replace(format) return t.Format(format) } + +type xssFilter struct { + reg *regexp.Regexp + repl []byte +} + +var ( + whiteSpace = []byte(" ") + xssFilters = []xssFilter{ + {regexp.MustCompile(`\ [ONon]\w*=["]*`), whiteSpace}, + {regexp.MustCompile(`<[SCRIPTscript]{6}`), whiteSpace}, + {regexp.MustCompile(`=[` + "`" + `'"]*[JAVASCRIPTjavascript \t\0
]*:`), whiteSpace}, + } +) + +// XSS goes through all the XSS filters to make user input content as safe as possible. +func XSS(in []byte) []byte { + for _, filter := range xssFilters { + in = filter.reg.ReplaceAll(in, filter.repl) + } + return in +} + +func XSSString(in string) string { + return string(XSS([]byte(in))) +} diff --git a/modules/git/hooks.go b/modules/git/hooks.go new file mode 100644 index 00000000..5b3c88a9 --- /dev/null +++ b/modules/git/hooks.go @@ -0,0 +1,111 @@ +// 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 git + +import ( + "errors" + "io/ioutil" + "os" + "path" + "strings" +) + +// hookNames is a list of Git hooks' name that are supported. +var hookNames = []string{ + "pre-applypatch", + "applypatch-msg", + "prepare-commit-msg", + "commit-msg", + "pre-commit", + "pre-rebase", + "post-commit", + "post-receive", + "post-update", +} + +var ( + ErrNotValidHook = errors.New("not a valid Git hook") +) + +// IsValidHookName returns true if given name is a valid Git hook. +func IsValidHookName(name string) bool { + for _, hn := range hookNames { + if hn == name { + return true + } + } + return false +} + +// Hook represents a Git hook. +type Hook struct { + name string + IsActive bool // Indicates whether repository has this hook. + Content string // Content of hook if it's active. + Sample string // Sample content from Git. + path string // Hook file path. +} + +// GetHook returns a Git hook by given name and repository. +func GetHook(repoPath, name string) (*Hook, error) { + if !IsValidHookName(name) { + return nil, ErrNotValidHook + } + h := &Hook{ + name: name, + path: path.Join(repoPath, "hooks", name), + } + if isFile(h.path) { + data, err := ioutil.ReadFile(h.path) + if err != nil { + return nil, err + } + h.IsActive = true + h.Content = string(data) + } else if isFile(h.path + ".sample") { + data, err := ioutil.ReadFile(h.path + ".sample") + if err != nil { + return nil, err + } + h.Sample = string(data) + } + return h, nil +} + +func (h *Hook) Name() string { + return h.name +} + +// Update updates hook settings. +func (h *Hook) Update() error { + if len(strings.TrimSpace(h.Content)) == 0 { + return os.Remove(h.path) + } + return ioutil.WriteFile(h.path, []byte(strings.Replace(h.Content, "\r", "", -1)), os.ModePerm) +} + +// ListHooks returns a list of Git hooks of given repository. +func ListHooks(repoPath string) (_ []*Hook, err error) { + if !isDir(path.Join(repoPath, "hooks")) { + return nil, errors.New("hooks path does not exist") + } + + hooks := make([]*Hook, len(hookNames)) + for i, name := range hookNames { + hooks[i], err = GetHook(repoPath, name) + if err != nil { + return nil, err + } + } + return hooks, nil +} + +func (repo *Repository) GetHook(name string) (*Hook, error) { + return GetHook(repo.Path, name) +} + +func (repo *Repository) Hooks() ([]*Hook, error) { + return ListHooks(repo.Path) +} diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index 77ae3db0..ed994d48 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -22,6 +22,9 @@ func (repo *Repository) IsTagExist(tagName string) bool { // GetTags returns all tags of given repository. func (repo *Repository) GetTags() ([]string, error) { + if gitVer.AtLeast(MustParseVersion("2.0.0")) { + return repo.getTagsReversed() + } stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "tag", "-l") if err != nil { return nil, errors.New(stderr) @@ -30,6 +33,15 @@ func (repo *Repository) GetTags() ([]string, error) { return tags[:len(tags)-1], nil } +func (repo *Repository) getTagsReversed() ([]string, error) { + stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "tag", "-l", "--sort=-v:refname") + if err != nil { + return nil, errors.New(stderr) + } + tags := strings.Split(stdout, "\n") + return tags[:len(tags)-1], nil +} + func (repo *Repository) CreateTag(tagName, idStr string) error { _, stderr, err := com.ExecCmdDir(repo.Path, "git", "tag", tagName, idStr) if err != nil { diff --git a/modules/git/utils.go b/modules/git/utils.go index 26eef231..6abbca55 100644 --- a/modules/git/utils.go +++ b/modules/git/utils.go @@ -7,6 +7,7 @@ package git import ( "bytes" "container/list" + "os" "path/filepath" "strings" ) @@ -46,3 +47,23 @@ func RefEndName(refStr string) string { func filepathFromSHA1(rootdir, sha1 string) string { return filepath.Join(rootdir, "objects", sha1[:2], sha1[2:]) } + +// isDir returns true if given path is a directory, +// or returns false when it's a file or does not exist. +func isDir(dir string) bool { + f, e := os.Stat(dir) + if e != nil { + return false + } + return f.IsDir() +} + +// isFile returns true if given path is a file, +// or returns false when it's a directory or does not exist. +func isFile(filePath string) bool { + f, e := os.Stat(filePath) + if e != nil { + return false + } + return !f.IsDir() +} diff --git a/modules/git/version.go b/modules/git/version.go index 9908d11e..b535521e 100644 --- a/modules/git/version.go +++ b/modules/git/version.go @@ -74,6 +74,10 @@ func (v *Version) LessThan(that *Version) bool { return v.Compare(that) < 0 } +func (v *Version) AtLeast(that *Version) bool { + return v.Compare(that) >= 0 +} + // GetVersion returns current Git version installed. func GetVersion() (*Version, error) { if gitVer != nil { diff --git a/modules/mailer/mailer.go b/modules/mailer/mailer.go index 92cdfc7d..758792a3 100644 --- a/modules/mailer/mailer.go +++ b/modules/mailer/mailer.go @@ -5,7 +5,9 @@ package mailer import ( + "crypto/tls" "fmt" + "net" "net/smtp" "strings" @@ -33,7 +35,7 @@ func (m Message) Content() string { } // create mail content - content := "From: " + m.From + "<" + m.User + + content := "From: \"" + m.From + "\" <" + m.User + ">\r\nSubject: " + m.Subject + "\r\nContent-Type: " + contentType + "\r\n\r\n" + m.Body return content } @@ -64,6 +66,53 @@ func processMailQueue() { } } +// sendMail allows mail with self-signed certificates. +func sendMail(hostAddressWithPort string, auth smtp.Auth, from string, recipients []string, msgContent []byte) error { + client, err := smtp.Dial(hostAddressWithPort) + if err != nil { + return err + } + + host, _, _ := net.SplitHostPort(hostAddressWithPort) + tlsConn := &tls.Config{ + InsecureSkipVerify: true, + ServerName: host, + } + if err = client.StartTLS(tlsConn); err != nil { + return err + } + + if auth != nil { + if err = client.Auth(auth); err != nil { + return err + } + } + + if err = client.Mail(from); err != nil { + return err + } + + for _, rec := range recipients { + if err = client.Rcpt(rec); err != nil { + return err + } + } + + w, err := client.Data() + if err != nil { + return err + } + if _, err = w.Write([]byte(msgContent)); err != nil { + return err + } + + if err = w.Close(); err != nil { + return err + } + + return client.Quit() +} + // Direct Send mail message func Send(msg *Message) (int, error) { log.Trace("Sending mails to: %s", strings.Join(msg.To, "; ")) @@ -85,7 +134,7 @@ func Send(msg *Message) (int, error) { num := 0 for _, to := range msg.To { body := []byte("To: " + to + "\r\n" + content) - err := smtp.SendMail(setting.MailService.Host, auth, msg.From, []string{to}, body) + err := sendMail(setting.MailService.Host, auth, msg.From, []string{to}, body) if err != nil { return num, err } @@ -96,7 +145,7 @@ func Send(msg *Message) (int, error) { body := []byte("To: " + strings.Join(msg.To, ";") + "\r\n" + content) // send to multiple emails in one message - err := smtp.SendMail(setting.MailService.Host, auth, msg.From, msg.To, body) + err := sendMail(setting.MailService.Host, auth, msg.From, msg.To, body) if err != nil { return 0, err } else { diff --git a/modules/middleware/context.go b/modules/middleware/context.go index 90716d2c..86e98c90 100644 --- a/modules/middleware/context.go +++ b/modules/middleware/context.go @@ -29,7 +29,6 @@ import ( // Context represents context of a request. type Context struct { *macaron.Context - i18n.Locale Cache cache.Cache csrf csrf.CSRF Flash *session.Flash @@ -76,12 +75,6 @@ type Context struct { } } -// Query querys form parameter. -func (ctx *Context) Query(name string) string { - ctx.Req.ParseForm() - return ctx.Req.Form.Get(name) -} - // HasError returns true if error occurs in form validation. func (ctx *Context) HasApiError() bool { hasErr, ok := ctx.Data["HasError"] @@ -162,7 +155,6 @@ func Contexter() macaron.Handler { return func(c *macaron.Context, l i18n.Locale, cache cache.Cache, sess session.Store, f *session.Flash, x csrf.CSRF) { ctx := &Context{ Context: c, - Locale: l, Cache: cache, csrf: x, Flash: f, diff --git a/modules/middleware/repo.go b/modules/middleware/repo.go index c6250f6d..78af58ea 100644 --- a/modules/middleware/repo.go +++ b/modules/middleware/repo.go @@ -308,3 +308,13 @@ func RequireTrueOwner() macaron.Handler { } } } + +// GitHookService checks if repsitory Git hooks service has been enabled. +func GitHookService() macaron.Handler { + return func(ctx *Context) { + if !setting.Service.EnableGitHooks { + ctx.Handle(404, "GitHookService", nil) + return + } + } +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 67e48108..b8fc4dec 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -275,6 +275,7 @@ var Service struct { LdapAuth bool ActiveCodeLives int ResetPwdCodeLives int + EnableGitHooks bool } func newService() { @@ -284,6 +285,7 @@ func newService() { Service.RequireSignInView = Cfg.MustBool("service", "REQUIRE_SIGNIN_VIEW") Service.EnableCacheAvatar = Cfg.MustBool("service", "ENABLE_CACHE_AVATAR") Service.EnableReverseProxyAuth = Cfg.MustBool("service", "ENABLE_REVERSE_PROXY_AUTHENTICATION") + Service.EnableGitHooks = Cfg.MustBool("service", "ENABLE_GIT_HOOKS") } var logLevels = map[string]string{ |