Compare commits

...

12 Commits

Author SHA1 Message Date
techknowlogick
bafa9ff432 1.7.6 changelog (#6596) 2019-04-13 10:12:00 +08:00
zeripath
bac388d27c Correctly adjust mirror url (#6593) (#6595) 2019-04-12 21:26:09 -04:00
Lauris BH
4ff6effe04 fix bug when user login and want to resend register confirmation email (#6482) (#6487) 2019-04-02 11:57:26 -04:00
John Olheiser
84a5b81d27 Changelog 1.7.5 (#6444)
Signed-off-by: jolheiser <john.olheiser@gmail.com>
2019-03-27 11:40:39 -04:00
kolaente
84f41d9d92 Fixed unitTypeCode not being used (#6423) 2019-03-24 17:31:01 +00:00
Lunny Xiao
acb9ae4c4d fix bug manifest.json will not request with cookie so that session will created every request (#6372) (#6383) 2019-03-19 22:19:54 -04:00
mrsdizzie
b76d899f7a Fix ParsePatch function to work with quoted diff --git strings (#6323) (#6332)
Backport of #6323
2019-03-14 19:59:29 +00:00
John Olheiser
9f33aa61bd Proposed changelog for 1.7.4 (#6316)
* Proposed changelog for 1.7.4

Signed-off-by: jolheiser <john.olheiser@gmail.com>

* Updated security fix description with @zeripath suggestion.

* Added 6292

* Update CHANGELOG.md

* Update CHANGELOG.md
2019-03-13 09:02:58 +08:00
Lunny Xiao
d0bbfd835f update git vendor to fix wrong release commit id and add migrations (#6224) (#6300) 2019-03-12 13:39:20 -04:00
techknowlogick
c7bbfd8f5e backport 6306 (#6308) 2019-03-12 18:58:49 +08:00
Muhammed TİFTİKÇİ
59a64c0e1d Fix #5580 : Make organization dropdown scrollable when using mouse wh… (#6246)
* Fix #5580 : Make organization dropdown scrollable when using mouse wheel.

* build less file with old makefile
2019-03-05 13:27:50 -05:00
Lunny Xiao
6a86a82368 fix display dashboard even if require to change password (#6214) (#6215)
* fix display dashboard even if require to change password

* fix comments
2019-02-28 19:36:57 +08:00
34 changed files with 2423 additions and 116 deletions

View File

@@ -82,7 +82,7 @@ pipeline:
when: when:
event: [ push, tag, pull_request ] event: [ push, tag, pull_request ]
test: unit-test:
image: golang:1.11 image: golang:1.11
pull: true pull: true
group: test group: test
@@ -94,7 +94,7 @@ pipeline:
event: [ push, pull_request ] event: [ push, pull_request ]
branch: [ master ] branch: [ master ]
test: release-test:
image: golang:1.11 image: golang:1.11
pull: true pull: true
group: test group: test
@@ -106,7 +106,7 @@ pipeline:
event: [ push, pull_request ] event: [ push, pull_request ]
branch: [ release/* ] branch: [ release/* ]
test: tag-test:
image: golang:1.11 image: golang:1.11
pull: true pull: true
group: test group: test
@@ -146,7 +146,7 @@ pipeline:
event: [ push, pull_request ] event: [ push, pull_request ]
branch: [ master ] branch: [ master ]
test-mysql: tag-test-mysql:
image: golang:1.11 image: golang:1.11
pull: true pull: true
group: test group: test
@@ -240,12 +240,13 @@ pipeline:
event: [ push ] event: [ push ]
branch: [ master ] branch: [ master ]
docker: release-docker:
image: plugins/docker:17.12 image: plugins/docker:17.12
pull: true pull: true
secrets: [ docker_username, docker_password ] secrets: [ docker_username, docker_password ]
repo: gitea/gitea repo: gitea/gitea
tags: [ '${DRONE_BRANCH##release/v}' ] tags: [ '${DRONE_BRANCH##release/v}' ]
cache_from: gitea/gitea
when: when:
event: [ push ] event: [ push ]
branch: [ release/* ] branch: [ release/* ]
@@ -255,6 +256,7 @@ pipeline:
secrets: [ docker_username, docker_password ] secrets: [ docker_username, docker_password ]
pull: true pull: true
repo: gitea/gitea repo: gitea/gitea
cache_from: gitea/gitea
default_tags: true default_tags: true
when: when:
event: [ push, tag ] event: [ push, tag ]
@@ -271,7 +273,7 @@ pipeline:
when: when:
event: [ push, tag ] event: [ push, tag ]
release: tag-release:
image: plugins/s3:1 image: plugins/s3:1
pull: true pull: true
secrets: [ aws_access_key_id, aws_secret_access_key ] secrets: [ aws_access_key_id, aws_secret_access_key ]
@@ -285,7 +287,7 @@ pipeline:
when: when:
event: [ tag ] event: [ tag ]
release: release-branch-release:
image: plugins/s3:1 image: plugins/s3:1
pull: true pull: true
secrets: [ aws_access_key_id, aws_secret_access_key ] secrets: [ aws_access_key_id, aws_secret_access_key ]

View File

@@ -4,6 +4,27 @@ This changelog goes through all the changes that have been made in each release
without substantial changes to our git log; to see the highlights of what has without substantial changes to our git log; to see the highlights of what has
been added to each release, please refer to the [blog](https://blog.gitea.io). been added to each release, please refer to the [blog](https://blog.gitea.io).
## [1.7.6](https://github.com/go-gitea/gitea/releases/tag/v1.7.6) - 2019-04-12
* SECURITY
* Prevent remote code execution vulnerability with mirror repo URL settings (#6593) (#6595)
* BUGFIXES
* Allow resend of confirmation email when logged in (#6482) (#6487)
## [1.7.5](https://github.com/go-gitea/gitea/releases/tag/v1.7.5) - 2019-03-27
* BUGFIXES
* Fix unitTypeCode not being used in accessLevelUnit (#6419) (#6423)
* Fix bug where manifest.json was being requested without cookies and continuously creating new sessions (#6372) (#6383)
* Fix ParsePatch function to work with quoted diff --git strings (#6323) (#6332)
## [1.7.4](https://github.com/go-gitea/gitea/releases/tag/v1.7.4) - 2019-03-12
* SECURITY
* Fix potential XSS vulnerability in repository description. (#6306) (#6308)
* BUGFIXES
* Fix wrong release commit id (#6224) (#6300)
* Fix panic on empty signed commits (#6292) (#6300)
* Fix organization dropdown not being scrollable when using mouse wheel (#5988) (#6246)
* Fix displaying dashboard even if required to change password (#6214) (#6215)
## [1.7.3](https://github.com/go-gitea/gitea/releases/tag/v1.7.3) - 2019-02-27 ## [1.7.3](https://github.com/go-gitea/gitea/releases/tag/v1.7.3) - 2019-02-27
* BUGFIXES * BUGFIXES
* Fix server 500 when trying to migrate to an already existing repository (#6188) (#6197) * Fix server 500 when trying to migrate to an already existing repository (#6188) (#6197)

14
Gopkg.lock generated
View File

@@ -3,11 +3,11 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:ab875622908a804a327a95a1701002b150806a3c5406df51ec231eac16d3a1ca" digest = "1:e1fa64238b0a2dbf1edf98c4af8d1b8cb65179e286d7f28006b50fa9f508ee9d"
name = "code.gitea.io/git" name = "code.gitea.io/git"
packages = ["."] packages = ["."]
pruneopts = "NUT" pruneopts = "NUT"
revision = "389d3c803e12a30dffcbb54a15c2242521bc4333" revision = "74d7c14dd4a3ed9c5def0dc3c1aeede399ddc5c5"
[[projects]] [[projects]]
branch = "master" branch = "master"
@@ -666,6 +666,14 @@
pruneopts = "NUT" pruneopts = "NUT"
revision = "02ccfbfaf0cc627aa3aec8ef7ed5cfeec5b43f63" revision = "02ccfbfaf0cc627aa3aec8ef7ed5cfeec5b43f63"
[[projects]]
digest = "1:63953ffb90bbc880c612d576fcfd973a5904277d25ec9e2d8d5719bf67969662"
name = "github.com/mvdan/xurls"
packages = ["."]
pruneopts = "NUT"
revision = "e52e821cbfe8fe163ff6f8628ab5869b11fc05af"
version = "v2.0.0"
[[projects]] [[projects]]
digest = "1:2be1d891535ce3d6d2a3db9087f07415e909744e9eff1a30f8f0b2519df60ae6" digest = "1:2be1d891535ce3d6d2a3db9087f07415e909744e9eff1a30f8f0b2519df60ae6"
name = "github.com/nfnt/resize" name = "github.com/nfnt/resize"
@@ -1173,7 +1181,6 @@
"github.com/keybase/go-crypto/openpgp", "github.com/keybase/go-crypto/openpgp",
"github.com/keybase/go-crypto/openpgp/armor", "github.com/keybase/go-crypto/openpgp/armor",
"github.com/keybase/go-crypto/openpgp/packet", "github.com/keybase/go-crypto/openpgp/packet",
"github.com/klauspost/compress/gzip",
"github.com/lafriks/xormstore", "github.com/lafriks/xormstore",
"github.com/lib/pq", "github.com/lib/pq",
"github.com/lunny/dingtalk_webhook", "github.com/lunny/dingtalk_webhook",
@@ -1191,6 +1198,7 @@
"github.com/mcuadros/go-version", "github.com/mcuadros/go-version",
"github.com/microcosm-cc/bluemonday", "github.com/microcosm-cc/bluemonday",
"github.com/msteinert/pam", "github.com/msteinert/pam",
"github.com/mvdan/xurls",
"github.com/nfnt/resize", "github.com/nfnt/resize",
"github.com/pquerna/otp", "github.com/pquerna/otp",
"github.com/pquerna/otp/totp", "github.com/pquerna/otp/totp",

View File

@@ -550,7 +550,12 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
beg := len(cmdDiffHead) beg := len(cmdDiffHead)
a := line[beg+2 : middle] a := line[beg+2 : middle]
b := line[middle+3:] b := line[middle+3:]
if hasQuote { if hasQuote {
// Keep the entire string in double quotes for now
a = line[beg:middle]
b = line[middle+1:]
var err error var err error
a, err = strconv.Unquote(a) a, err = strconv.Unquote(a)
if err != nil { if err != nil {
@@ -560,6 +565,10 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
if err != nil { if err != nil {
return nil, fmt.Errorf("Unquote: %v", err) return nil, fmt.Errorf("Unquote: %v", err)
} }
// Now remove the /a /b
a = a[2:]
b = b[2:]
} }
curFile = &DiffFile{ curFile = &DiffFile{
@@ -637,6 +646,7 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
} }
} }
} }
return diff, nil return diff, nil
} }

View File

@@ -5,6 +5,8 @@ import (
"strings" "strings"
"testing" "testing"
"code.gitea.io/gitea/modules/setting"
dmp "github.com/sergi/go-diff/diffmatchpatch" dmp "github.com/sergi/go-diff/diffmatchpatch"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@@ -99,6 +101,59 @@ func ExampleCutDiffAroundLine() {
println(result) println(result)
} }
func TestParsePatch(t *testing.T) {
var diff = `diff --git "a/README.md" "b/README.md"
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
# gitea-github-migrator
+
+ Build Status
- Latest Release
Docker Pulls
+ cut off
+ cut off`
result, err := ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff))
if err != nil {
t.Errorf("ParsePatch failed: %s", err)
}
println(result)
var diff2 = `diff --git "a/A \\ B" "b/A \\ B"
--- "a/A \\ B"
+++ "b/A \\ B"
@@ -1,3 +1,6 @@
# gitea-github-migrator
+
+ Build Status
- Latest Release
Docker Pulls
+ cut off
+ cut off`
result, err = ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff2))
if err != nil {
t.Errorf("ParsePatch failed: %s", err)
}
println(result)
var diff3 = `diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
# gitea-github-migrator
+
+ Build Status
- Latest Release
Docker Pulls
+ cut off
+ cut off`
result, err = ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff3))
if err != nil {
t.Errorf("ParsePatch failed: %s", err)
}
println(result)
}
func setupDefaultDiff() *Diff { func setupDefaultDiff() *Diff {
return &Diff{ return &Diff{
Files: []*DiffFile{ Files: []*DiffFile{

View File

@@ -616,9 +616,9 @@ func ExternalUserLogin(user *User, login, password string, source *LoginSource,
return nil, err return nil, err
} }
if !user.IsActive { // WARN: DON'T check user.IsActive, that will be checked on reqSign so that
return nil, ErrUserInactive{user.ID, user.Name} // user could be hint to resend confirm email.
} else if user.ProhibitLogin { if user.ProhibitLogin {
return nil, ErrUserProhibitLogin{user.ID, user.Name} return nil, ErrUserProhibitLogin{user.ID, user.Name}
} }
@@ -658,9 +658,9 @@ func UserSignIn(username, password string) (*User, error) {
switch user.LoginType { switch user.LoginType {
case LoginNoType, LoginPlain, LoginOAuth2: case LoginNoType, LoginPlain, LoginOAuth2:
if user.IsPasswordSet() && user.ValidatePassword(password) { if user.IsPasswordSet() && user.ValidatePassword(password) {
if !user.IsActive { // WARN: DON'T check user.IsActive, that will be checked on reqSign so that
return nil, ErrUserInactive{user.ID, user.Name} // user could be hint to resend confirm email.
} else if user.ProhibitLogin { if user.ProhibitLogin {
return nil, ErrUserProhibitLogin{user.ID, user.Name} return nil, ErrUserProhibitLogin{user.ID, user.Name}
} }

View File

@@ -719,10 +719,12 @@ var (
// DescriptionHTML does special handles to description and return HTML string. // DescriptionHTML does special handles to description and return HTML string.
func (repo *Repository) DescriptionHTML() template.HTML { func (repo *Repository) DescriptionHTML() template.HTML {
sanitize := func(s string) string { desc, err := markup.RenderDescriptionHTML([]byte(repo.Description), repo.HTMLURL(), repo.ComposeMetas())
return fmt.Sprintf(`<a href="%[1]s" target="_blank" rel="noopener noreferrer">%[1]s</a>`, s) if err != nil {
log.Error(4, "Failed to render description for %s (ID: %d): %v", repo.Name, repo.ID, err)
return template.HTML(markup.Sanitize(repo.Description))
} }
return template.HTML(descPattern.ReplaceAllStringFunc(markup.Sanitize(repo.Description), sanitize)) return template.HTML(markup.Sanitize(string(desc)))
} }
// LocalCopyPath returns the local repository copy path. // LocalCopyPath returns the local repository copy path.
@@ -1064,9 +1066,11 @@ func CleanUpMigrateInfo(repo *Repository) (*Repository, error) {
} }
} }
if err := cleanUpMigrateGitConfig(repo.GitConfigPath()); err != nil { _, err := git.NewCommand("remote", "remove", "origin").RunInDir(repoPath)
return repo, fmt.Errorf("cleanUpMigrateGitConfig: %v", err) if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
return repo, fmt.Errorf("CleanUpMigrateInfo: %v", err)
} }
if repo.HasWiki() { if repo.HasWiki() {
if err := cleanUpMigrateGitConfig(path.Join(repo.WikiPath(), "config")); err != nil { if err := cleanUpMigrateGitConfig(path.Join(repo.WikiPath(), "config")); err != nil {
return repo, fmt.Errorf("cleanUpMigrateGitConfig (wiki): %v", err) return repo, fmt.Errorf("cleanUpMigrateGitConfig (wiki): %v", err)

View File

@@ -70,10 +70,6 @@ func (repo *Repository) CheckBranchName(name string) error {
return err return err
} }
if _, err := gitRepo.GetTag(name); err == nil {
return ErrTagAlreadyExists{name}
}
branches, err := repo.GetBranches() branches, err := repo.GetBranches()
if err != nil { if err != nil {
return err return err
@@ -87,6 +83,11 @@ func (repo *Repository) CheckBranchName(name string) error {
return ErrBranchNameConflict{branch.Name} return ErrBranchNameConflict{branch.Name}
} }
} }
if _, err := gitRepo.GetTag(name); err == nil {
return ErrTagAlreadyExists{name}
}
return nil return nil
} }

View File

@@ -20,7 +20,6 @@ import (
"github.com/Unknwon/com" "github.com/Unknwon/com"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
"gopkg.in/ini.v1"
) )
// MirrorQueue holds an UniqueQueue object of the mirror // MirrorQueue holds an UniqueQueue object of the mirror
@@ -71,11 +70,18 @@ func (m *Mirror) ScheduleNextUpdate() {
} }
func remoteAddress(repoPath string) (string, error) { func remoteAddress(repoPath string) (string, error) {
cfg, err := ini.Load(GitConfigPath(repoPath)) cmd := git.NewCommand("remote", "get-url", "origin")
result, err := cmd.RunInDir(repoPath)
if err != nil { if err != nil {
if strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
return "", nil
}
return "", err return "", err
} }
return cfg.Section("remote \"origin\"").Key("url").Value(), nil if len(result) > 0 {
return result[:len(result)-1], nil
}
return "", nil
} }
func (m *Mirror) readAddress() { func (m *Mirror) readAddress() {
@@ -115,14 +121,15 @@ func (m *Mirror) FullAddress() string {
// SaveAddress writes new address to Git repository config. // SaveAddress writes new address to Git repository config.
func (m *Mirror) SaveAddress(addr string) error { func (m *Mirror) SaveAddress(addr string) error {
configPath := m.Repo.GitConfigPath() repoPath := m.Repo.RepoPath()
cfg, err := ini.Load(configPath) // Remove old origin
if err != nil { _, err := git.NewCommand("remote", "remove", "origin").RunInDir(repoPath)
return fmt.Errorf("Load: %v", err) if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
return err
} }
cfg.Section("remote \"origin\"").Key("url").SetValue(addr) _, err = git.NewCommand("remote", "add", "origin", addr).RunInDir(repoPath)
return cfg.SaveToIndent(configPath, "\t") return err
} }
// gitShortEmptySha Git short empty SHA // gitShortEmptySha Git short empty SHA

View File

@@ -238,7 +238,7 @@ func accessLevelUnit(e Engine, user *User, repo *Repository, unitType UnitType)
if err != nil { if err != nil {
return AccessModeNone, err return AccessModeNone, err
} }
return perm.UnitAccessMode(UnitTypeCode), nil return perm.UnitAccessMode(unitType), nil
} }
func hasAccessUnit(e Engine, user *User, repo *Repository, unitType UnitType, testMode AccessMode) (bool, error) { func hasAccessUnit(e Engine, user *User, repo *Repository, unitType UnitType, testMode AccessMode) (bool, error) {

View File

@@ -44,23 +44,19 @@ func Toggle(options *ToggleOptions) macaron.Handler {
return return
} }
// prevent infinite redirection
// also make sure that the form cannot be accessed by
// users who don't need this
if ctx.Req.URL.Path == "/user/settings/change_password" {
if !ctx.User.MustChangePassword {
ctx.Redirect(setting.AppSubURL + "/")
}
return
}
if ctx.User.MustChangePassword { if ctx.User.MustChangePassword {
if ctx.Req.URL.Path != "/user/settings/change_password" {
ctx.Data["Title"] = ctx.Tr("auth.must_change_password") ctx.Data["Title"] = ctx.Tr("auth.must_change_password")
ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/change_password" ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/change_password"
ctx.SetCookie("redirect_to", url.QueryEscape(setting.AppSubURL+ctx.Req.RequestURI), 0, setting.AppSubURL) ctx.SetCookie("redirect_to", url.QueryEscape(setting.AppSubURL+ctx.Req.RequestURI), 0, setting.AppSubURL)
ctx.Redirect(setting.AppSubURL + "/user/settings/change_password") ctx.Redirect(setting.AppSubURL + "/user/settings/change_password")
return return
} }
} else if ctx.Req.URL.Path == "/user/settings/change_password" {
// make sure that the form cannot be accessed by users who don't need this
ctx.Redirect(setting.AppSubURL + "/")
return
}
} }
// Redirect to dashboard if user tries to visit any non-login page. // Redirect to dashboard if user tries to visit any non-login page.

View File

@@ -234,6 +234,23 @@ func RenderCommitMessage(
return ctx.postProcess(rawHTML) return ctx.postProcess(rawHTML)
} }
// RenderDescriptionHTML will use similar logic as PostProcess, but will
// use a single special linkProcessor.
func RenderDescriptionHTML(
rawHTML []byte,
urlPrefix string,
metas map[string]string,
) ([]byte, error) {
ctx := &postProcessCtx{
metas: metas,
urlPrefix: urlPrefix,
procs: []processor{
descriptionLinkProcessor,
},
}
return ctx.postProcess(rawHTML)
}
var byteBodyTag = []byte("<body>") var byteBodyTag = []byte("<body>")
var byteBodyTagClosing = []byte("</body>") var byteBodyTagClosing = []byte("</body>")
@@ -668,3 +685,34 @@ func genDefaultLinkProcessor(defaultLink string) processor {
node.FirstChild, node.LastChild = ch, ch node.FirstChild, node.LastChild = ch, ch
} }
} }
// descriptionLinkProcessor creates links for DescriptionHTML
func descriptionLinkProcessor(ctx *postProcessCtx, node *html.Node) {
m := linkRegex.FindStringIndex(node.Data)
if m == nil {
return
}
uri := node.Data[m[0]:m[1]]
replaceContent(node, m[0], m[1], createDescriptionLink(uri, uri))
}
func createDescriptionLink(href, content string) *html.Node {
textNode := &html.Node{
Type: html.TextNode,
Data: content,
}
linkNode := &html.Node{
FirstChild: textNode,
LastChild: textNode,
Type: html.ElementNode,
Data: "a",
DataAtom: atom.A,
Attr: []html.Attribute{
{Key: "href", Val: href},
{Key: "target", Val: "_blank"},
{Key: "rel", Val: "noopener noreferrer"},
},
}
textNode.Parent = linkNode
return linkNode
}

View File

@@ -528,7 +528,9 @@ mirror_prune_desc = Remove obsolete remote-tracking references
mirror_interval = Mirror Interval (valid time units are 'h', 'm', 's'). 0 to disable automatic sync. mirror_interval = Mirror Interval (valid time units are 'h', 'm', 's'). 0 to disable automatic sync.
mirror_interval_invalid = The mirror interval is not valid. mirror_interval_invalid = The mirror interval is not valid.
mirror_address = Clone From URL mirror_address = Clone From URL
mirror_address_desc = Include any required authorization credentials in the URL. mirror_address_desc = Include any required authorization credentials in the URL. These must be url escaped as appropriate
mirror_address_url_invalid = The provided url is invalid. You must escape all components of the url correctly.
mirror_address_protocol_invalid = The provided url is invalid. Only http(s):// or git:// locations can be mirrored from.
mirror_last_synced = Last Synchronized mirror_last_synced = Last Synchronized
watchers = Watchers watchers = Watchers
stargazers = Stargazers stargazers = Stargazers

File diff suppressed because one or more lines are too long

View File

@@ -384,33 +384,12 @@ pre, code {
} }
.overflow.menu { .ui.floating.dropdown {
.items { .overflow.menu {
max-height: 300px; .scrolling.menu.items {
overflow-y: auto; border-radius: 0px !important;
.item { box-shadow: none !important;
position: relative; border-bottom: 1px solid rgba(34, 36, 38, 0.15);
cursor: pointer;
display: block;
border: none;
height: auto;
border-top: none;
line-height: 1em;
color: rgba(0,0,0,.8);
padding: .71428571em 1.14285714em !important;
font-size: 1rem;
text-transform: none;
font-weight: 400;
box-shadow: none;
-webkit-touch-callout: none;
&.active {
font-weight: 700;
}
&:hover {
background: rgba(0,0,0,.05);
color: rgba(0,0,0,.8);
z-index: 13;
}
} }
} }
} }

View File

@@ -6,6 +6,7 @@ package routers
import ( import (
"bytes" "bytes"
"net/url"
"strings" "strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
@@ -43,6 +44,11 @@ func Home(ctx *context.Context) {
log.Info("Failed authentication attempt for %s from %s", ctx.User.Name, ctx.RemoteAddr()) log.Info("Failed authentication attempt for %s from %s", ctx.User.Name, ctx.RemoteAddr())
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
ctx.HTML(200, "user/auth/prohibit_login") ctx.HTML(200, "user/auth/prohibit_login")
} else if ctx.User.MustChangePassword {
ctx.Data["Title"] = ctx.Tr("auth.must_change_password")
ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/change_password"
ctx.SetCookie("redirect_to", url.QueryEscape(setting.AppSubURL+ctx.Req.RequestURI), 0, setting.AppSubURL)
ctx.Redirect(setting.AppSubURL + "/user/settings/change_password")
} else { } else {
user.Dashboard(ctx) user.Dashboard(ctx)
} }

View File

@@ -7,6 +7,8 @@ package repo
import ( import (
"errors" "errors"
"net/url"
"regexp"
"strings" "strings"
"time" "time"
@@ -21,6 +23,8 @@ import (
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/modules/validation"
"code.gitea.io/gitea/routers/utils" "code.gitea.io/gitea/routers/utils"
"github.com/mvdan/xurls"
) )
const ( const (
@@ -33,6 +37,8 @@ const (
tplProtectedBranch base.TplName = "repo/settings/protected_branch" tplProtectedBranch base.TplName = "repo/settings/protected_branch"
) )
var validFormAddress *regexp.Regexp
// Settings show a repository's settings page // Settings show a repository's settings page
func Settings(ctx *context.Context) { func Settings(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.settings") ctx.Data["Title"] = ctx.Tr("repo.settings")
@@ -140,7 +146,38 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
return return
} }
} }
if err := ctx.Repo.Mirror.SaveAddress(form.MirrorAddress); err != nil {
// Validate the form.MirrorAddress
u, err := url.Parse(form.MirrorAddress)
if err != nil {
ctx.Data["Err_MirrorAddress"] = true
ctx.RenderWithErr(ctx.Tr("repo.mirror_address_url_invalid"), tplSettingsOptions, &form)
return
}
if u.Opaque != "" || !(u.Scheme == "http" || u.Scheme == "https" || u.Scheme == "git") {
ctx.Data["Err_MirrorAddress"] = true
ctx.RenderWithErr(ctx.Tr("repo.mirror_address_protocol_invalid"), tplSettingsOptions, &form)
return
}
// Now use xurls
address := validFormAddress.FindString(form.MirrorAddress)
if address != form.MirrorAddress && form.MirrorAddress != "" {
ctx.Data["Err_MirrorAddress"] = true
ctx.RenderWithErr(ctx.Tr("repo.mirror_address_url_invalid"), tplSettingsOptions, &form)
return
}
if u.EscapedPath() == "" || u.Host == "" || !u.IsAbs() {
ctx.Data["Err_MirrorAddress"] = true
ctx.RenderWithErr(ctx.Tr("repo.mirror_address_url_invalid"), tplSettingsOptions, &form)
return
}
address = u.String()
if err := ctx.Repo.Mirror.SaveAddress(address); err != nil {
ctx.ServerError("SaveAddress", err) ctx.ServerError("SaveAddress", err)
return return
} }
@@ -618,3 +655,11 @@ func DeleteDeployKey(ctx *context.Context) {
"redirect": ctx.Repo.RepoLink + "/settings/keys", "redirect": ctx.Repo.RepoLink + "/settings/keys",
}) })
} }
func init() {
var err error
validFormAddress, err = xurls.StrictMatchingScheme(`(https?)|(git)://`)
if err != nil {
panic(err)
}
}

View File

@@ -50,7 +50,7 @@ func renderDirectory(ctx *context.Context, treeLink string) {
} }
entries.CustomSort(base.NaturalSortLess) entries.CustomSort(base.NaturalSortLess)
ctx.Data["Files"], err = entries.GetCommitsInfo(ctx.Repo.Commit, ctx.Repo.TreePath) ctx.Data["Files"], err = entries.GetCommitsInfo(ctx.Repo.Commit, ctx.Repo.TreePath, nil)
if err != nil { if err != nil {
ctx.ServerError("GetCommitsInfo", err) ctx.ServerError("GetCommitsInfo", err)
return return

View File

@@ -296,7 +296,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/user", func() { m.Group("/user", func() {
// r.Get("/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds) // r.Get("/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds)
m.Any("/activate", user.Activate) m.Any("/activate", user.Activate, reqSignIn)
m.Any("/activate_email", user.ActivateEmail) m.Any("/activate_email", user.ActivateEmail)
m.Get("/email2user", user.Email2User) m.Get("/email2user", user.Email2User)
m.Get("/forgot_password", user.ForgotPasswd) m.Get("/forgot_password", user.ForgotPasswd)

View File

@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge"> <meta http-equiv="x-ua-compatible" content="ie=edge">
<title>{{if .Title}}{{.Title}} - {{end}}{{AppName}}</title> <title>{{if .Title}}{{.Title}} - {{end}}{{AppName}}</title>
<link rel="manifest" href="{{AppSubUrl}}/manifest.json"> <link rel="manifest" href="{{AppSubUrl}}/manifest.json" crossorigin="use-credentials">
<script> <script>
if ('serviceWorker' in navigator) { if ('serviceWorker' in navigator) {

View File

@@ -58,7 +58,7 @@
<label for="interval">{{.i18n.Tr "repo.mirror_interval"}}</label> <label for="interval">{{.i18n.Tr "repo.mirror_interval"}}</label>
<input id="interval" name="interval" value="{{.MirrorInterval}}"> <input id="interval" name="interval" value="{{.MirrorInterval}}">
</div> </div>
<div class="field"> <div class="field {{if .Err_MirrorAddress}}error{{end}}">
<label for="mirror_address">{{.i18n.Tr "repo.mirror_address"}}</label> <label for="mirror_address">{{.i18n.Tr "repo.mirror_address"}}</label>
<input id="mirror_address" name="mirror_address" value="{{.Mirror.FullAddress}}" required> <input id="mirror_address" name="mirror_address" value="{{.Mirror.FullAddress}}" required>
<p class="help">{{.i18n.Tr "repo.mirror_address_desc"}}</p> <p class="help">{{.i18n.Tr "repo.mirror_address_desc"}}</p>

View File

@@ -11,7 +11,7 @@
<div class="ui header"> <div class="ui header">
{{.i18n.Tr "home.switch_dashboard_context"}} {{.i18n.Tr "home.switch_dashboard_context"}}
</div> </div>
<div class="items"> <div class="scrolling menu items">
<a class="{{if eq .ContextUser.ID .SignedUser.ID}}active selected{{end}} item" href="{{AppSubUrl}}/{{if .PageIsIssues}}issues{{else if .PageIsPulls}}pulls{{end}}"> <a class="{{if eq .ContextUser.ID .SignedUser.ID}}active selected{{end}} item" href="{{AppSubUrl}}/{{if .PageIsIssues}}issues{{else if .PageIsPulls}}pulls{{end}}">
<img class="ui avatar image" src="{{.SignedUser.RelAvatarLink}}"> <img class="ui avatar image" src="{{.SignedUser.RelAvatarLink}}">
{{.SignedUser.Name}} {{.SignedUser.Name}}

11
vendor/code.gitea.io/git/cache.go generated vendored Normal file
View File

@@ -0,0 +1,11 @@
// Copyright 2019 The Gitea 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
// LastCommitCache cache
type LastCommitCache interface {
Get(repoPath, ref, entryPath string) (*Commit, error)
Put(repoPath, ref, entryPath string, commit *Commit) error
}

53
vendor/code.gitea.io/git/commit.go generated vendored
View File

@@ -1,4 +1,5 @@
// Copyright 2015 The Gogs Authors. All rights reserved. // Copyright 2015 The Gogs Authors. All rights reserved.
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@@ -9,6 +10,7 @@ import (
"bytes" "bytes"
"container/list" "container/list"
"fmt" "fmt"
"io"
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
@@ -16,6 +18,7 @@ import (
// Commit represents a git commit. // Commit represents a git commit.
type Commit struct { type Commit struct {
Branch string // Branch this commit belongs to
Tree Tree
ID SHA1 // The ID of this commit object ID SHA1 // The ID of this commit object
Author *Signature Author *Signature
@@ -279,6 +282,56 @@ func (c *Commit) GetSubModule(entryname string) (*SubModule, error) {
return nil, nil return nil, nil
} }
// CommitFileStatus represents status of files in a commit.
type CommitFileStatus struct {
Added []string
Removed []string
Modified []string
}
// NewCommitFileStatus creates a CommitFileStatus
func NewCommitFileStatus() *CommitFileStatus {
return &CommitFileStatus{
[]string{}, []string{}, []string{},
}
}
// GetCommitFileStatus returns file status of commit in given repository.
func GetCommitFileStatus(repoPath, commitID string) (*CommitFileStatus, error) {
stdout, w := io.Pipe()
done := make(chan struct{})
fileStatus := NewCommitFileStatus()
go func() {
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
fields := strings.Fields(scanner.Text())
if len(fields) < 2 {
continue
}
switch fields[0][0] {
case 'A':
fileStatus.Added = append(fileStatus.Added, fields[1])
case 'D':
fileStatus.Removed = append(fileStatus.Removed, fields[1])
case 'M':
fileStatus.Modified = append(fileStatus.Modified, fields[1])
}
}
done <- struct{}{}
}()
stderr := new(bytes.Buffer)
err := NewCommand("show", "--name-status", "--pretty=format:''", commitID).RunInDirPipeline(repoPath, w, stderr)
w.Close() // Close writer to exit parsing goroutine
if err != nil {
return nil, concatenateError(err, stderr.String())
}
<-done
return fileStatus, nil
}
// GetFullCommitID returns full length (40) of commit ID by given short SHA in a repository. // GetFullCommitID returns full length (40) of commit ID by given short SHA in a repository.
func GetFullCommitID(repoPath, shortID string) (string, error) { func GetFullCommitID(repoPath, shortID string) (string, error) {
if len(shortID) >= 40 { if len(shortID) >= 40 {

View File

@@ -72,13 +72,20 @@ func (state *getCommitsInfoState) getTargetedEntryPath() string {
} }
// repeatedly perform targeted searches for unpopulated entries // repeatedly perform targeted searches for unpopulated entries
func targetedSearch(state *getCommitsInfoState, done chan error) { func targetedSearch(state *getCommitsInfoState, done chan error, cache LastCommitCache) {
for { for {
entryPath := state.getTargetedEntryPath() entryPath := state.getTargetedEntryPath()
if len(entryPath) == 0 { if len(entryPath) == 0 {
done <- nil done <- nil
return return
} }
if cache != nil {
commit, err := cache.Get(state.headCommit.repo.Path, state.headCommit.ID.String(), entryPath)
if err == nil && commit != nil {
state.update(entryPath, commit)
continue
}
}
command := NewCommand("rev-list", "-1", state.headCommit.ID.String(), "--", entryPath) command := NewCommand("rev-list", "-1", state.headCommit.ID.String(), "--", entryPath)
output, err := command.RunInDir(state.headCommit.repo.Path) output, err := command.RunInDir(state.headCommit.repo.Path)
if err != nil { if err != nil {
@@ -96,6 +103,9 @@ func targetedSearch(state *getCommitsInfoState, done chan error) {
return return
} }
state.update(entryPath, commit) state.update(entryPath, commit)
if cache != nil {
cache.Put(state.headCommit.repo.Path, state.headCommit.ID.String(), entryPath, commit)
}
} }
} }
@@ -118,9 +128,9 @@ func initGetCommitInfoState(entries Entries, headCommit *Commit, treePath string
} }
// GetCommitsInfo gets information of all commits that are corresponding to these entries // GetCommitsInfo gets information of all commits that are corresponding to these entries
func (tes Entries) GetCommitsInfo(commit *Commit, treePath string) ([][]interface{}, error) { func (tes Entries) GetCommitsInfo(commit *Commit, treePath string, cache LastCommitCache) ([][]interface{}, error) {
state := initGetCommitInfoState(tes, commit, treePath) state := initGetCommitInfoState(tes, commit, treePath)
if err := getCommitsInfo(state); err != nil { if err := getCommitsInfo(state, cache); err != nil {
return nil, err return nil, err
} }
if len(state.commits) < len(state.entryPaths) { if len(state.commits) < len(state.entryPaths) {
@@ -188,7 +198,7 @@ func (state *getCommitsInfoState) update(entryPath string, commit *Commit) bool
const getCommitsInfoPretty = "--pretty=format:%H %ct %s" const getCommitsInfoPretty = "--pretty=format:%H %ct %s"
func getCommitsInfo(state *getCommitsInfoState) error { func getCommitsInfo(state *getCommitsInfoState, cache LastCommitCache) error {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
defer cancel() defer cancel()
@@ -215,7 +225,7 @@ func getCommitsInfo(state *getCommitsInfoState) error {
numThreads := runtime.NumCPU() numThreads := runtime.NumCPU()
done := make(chan error, numThreads) done := make(chan error, numThreads)
for i := 0; i < numThreads; i++ { for i := 0; i < numThreads; i++ {
go targetedSearch(state, done) go targetedSearch(state, done, cache)
} }
scanner := bufio.NewScanner(readCloser) scanner := bufio.NewScanner(readCloser)

View File

@@ -10,7 +10,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/mcuadros/go-version" version "github.com/mcuadros/go-version"
) )
// GetRefCommitID returns the last commit ID string of given reference (branch or tag). // GetRefCommitID returns the last commit ID string of given reference (branch or tag).
@@ -32,7 +32,14 @@ func (repo *Repository) GetBranchCommitID(name string) (string, error) {
// GetTagCommitID returns last commit ID string of given tag. // GetTagCommitID returns last commit ID string of given tag.
func (repo *Repository) GetTagCommitID(name string) (string, error) { func (repo *Repository) GetTagCommitID(name string) (string, error) {
return repo.GetRefCommitID(TagPrefix + name) stdout, err := NewCommand("rev-list", "-n", "1", name).RunInDir(repo.Path)
if err != nil {
if strings.Contains(err.Error(), "unknown revision or path") {
return "", ErrNotExist{name, ""}
}
return "", err
}
return strings.TrimSpace(stdout), nil
} }
// parseCommitData parses commit information from the (uncompressed) raw // parseCommitData parses commit information from the (uncompressed) raw
@@ -94,7 +101,11 @@ l:
sig, err := newGPGSignatureFromCommitline(data, (nextline+1)+sigindex, true) sig, err := newGPGSignatureFromCommitline(data, (nextline+1)+sigindex, true)
if err == nil && sig != nil { if err == nil && sig != nil {
// remove signature from commit message // remove signature from commit message
if sigindex == 0 {
cm = ""
} else {
cm = cm[:sigindex-1] cm = cm[:sigindex-1]
}
commit.Signature = sig commit.Signature = sig
} }
} }
@@ -130,6 +141,14 @@ func (repo *Repository) getCommit(id SHA1) (*Commit, error) {
commit.repo = repo commit.repo = repo
commit.ID = id commit.ID = id
data, err = NewCommand("name-rev", id.String()).RunInDirBytes(repo.Path)
if err != nil {
return nil, err
}
// name-rev commitID ouput will be "COMMIT_ID master" or "COMMIT_ID master~12"
commit.Branch = strings.Split(strings.Split(string(data), " ")[1], "~")[0]
repo.commitCache.Set(id.String(), commit) repo.commitCache.Set(id.String(), commit)
return commit, nil return commit, nil
} }
@@ -138,10 +157,14 @@ func (repo *Repository) getCommit(id SHA1) (*Commit, error) {
func (repo *Repository) GetCommit(commitID string) (*Commit, error) { func (repo *Repository) GetCommit(commitID string) (*Commit, error) {
if len(commitID) != 40 { if len(commitID) != 40 {
var err error var err error
commitID, err = NewCommand("rev-parse", commitID).RunInDir(repo.Path) actualCommitID, err := NewCommand("rev-parse", commitID).RunInDir(repo.Path)
if err != nil { if err != nil {
if strings.Contains(err.Error(), "unknown revision or path") {
return nil, ErrNotExist{commitID, ""}
}
return nil, err return nil, err
} }
commitID = actualCommitID
} }
id, err := NewIDFromString(commitID) id, err := NewIDFromString(commitID)
if err != nil { if err != nil {

20
vendor/code.gitea.io/git/repo_tag.go generated vendored
View File

@@ -76,12 +76,12 @@ func (repo *Repository) getTag(id SHA1) (*Tag, error) {
// GetTag returns a Git tag by given name. // GetTag returns a Git tag by given name.
func (repo *Repository) GetTag(name string) (*Tag, error) { func (repo *Repository) GetTag(name string) (*Tag, error) {
stdout, err := NewCommand("show-ref", "--tags", name).RunInDir(repo.Path) idStr, err := repo.GetTagCommitID(name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
id, err := NewIDFromString(strings.Split(stdout, " ")[0]) id, err := NewIDFromString(idStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -103,26 +103,18 @@ func (repo *Repository) GetTagInfos() ([]*Tag, error) {
} }
tagNames := strings.Split(stdout, "\n") tagNames := strings.Split(stdout, "\n")
var tags []*Tag var tags = make([]*Tag, 0, len(tagNames))
for _, tagName := range tagNames { for _, tagName := range tagNames {
tagName = strings.TrimSpace(tagName) tagName = strings.TrimSpace(tagName)
if len(tagName) == 0 { if len(tagName) == 0 {
continue continue
} }
commitID, err := NewCommand("rev-parse", tagName).RunInDir(repo.Path)
tag, err := repo.GetTag(tagName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
commit, err := repo.GetCommit(commitID) tags = append(tags, tag)
if err != nil {
return nil, err
}
tags = append(tags, &Tag{
Name: tagName,
Message: commit.Message(),
Object: commit.ID,
Tagger: commit.Author,
})
} }
sortTagsByTime(tags) sortTagsByTime(tags)
return tags, nil return tags, nil

View File

@@ -29,13 +29,12 @@ func NewSubModuleFile(c *Commit, refURL, refID string) *SubModuleFile {
} }
} }
// RefURL guesses and returns reference URL. func getRefURL(refURL, urlPrefix, parentPath string) string {
func (sf *SubModuleFile) RefURL(urlPrefix string, parentPath string) string { if refURL == "" {
if sf.refURL == "" {
return "" return ""
} }
url := strings.TrimSuffix(sf.refURL, ".git") url := strings.TrimSuffix(refURL, ".git")
// git://xxx/user/repo // git://xxx/user/repo
if strings.HasPrefix(url, "git://") { if strings.HasPrefix(url, "git://") {
@@ -67,12 +66,21 @@ func (sf *SubModuleFile) RefURL(urlPrefix string, parentPath string) string {
if strings.Contains(urlPrefix, url[i+1:j]) { if strings.Contains(urlPrefix, url[i+1:j]) {
return urlPrefix + url[j+1:] return urlPrefix + url[j+1:]
} }
if strings.HasPrefix(url, "ssh://") || strings.HasPrefix(url, "git+ssh://") {
k := strings.Index(url[j+1:], "/")
return "http://" + url[i+1:j] + "/" + url[j+1:][k+1:]
}
return "http://" + url[i+1:j] + "/" + url[j+1:] return "http://" + url[i+1:j] + "/" + url[j+1:]
} }
return url return url
} }
// RefURL guesses and returns reference URL.
func (sf *SubModuleFile) RefURL(urlPrefix string, parentPath string) string {
return getRefURL(sf.refURL, urlPrefix, parentPath)
}
// RefID returns reference ID. // RefID returns reference ID.
func (sf *SubModuleFile) RefID() string { func (sf *SubModuleFile) RefID() string {
return sf.refID return sf.refID

22
vendor/code.gitea.io/git/tree.go generated vendored
View File

@@ -18,6 +18,9 @@ type Tree struct {
entries Entries entries Entries
entriesParsed bool entriesParsed bool
entriesRecursive Entries
entriesRecursiveParsed bool
} }
// NewTree create a new tree according the repository and commit id // NewTree create a new tree according the repository and commit id
@@ -67,20 +70,29 @@ func (t *Tree) ListEntries() (Entries, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
t.entries, err = parseTreeEntries(stdout, t) t.entries, err = parseTreeEntries(stdout, t)
if err == nil {
t.entriesParsed = true
}
return t.entries, err return t.entries, err
} }
// ListEntriesRecursive returns all entries of current tree recursively including all subtrees // ListEntriesRecursive returns all entries of current tree recursively including all subtrees
func (t *Tree) ListEntriesRecursive() (Entries, error) { func (t *Tree) ListEntriesRecursive() (Entries, error) {
if t.entriesParsed { if t.entriesRecursiveParsed {
return t.entries, nil return t.entriesRecursive, nil
} }
stdout, err := NewCommand("ls-tree", "-t", "-r", t.ID.String()).RunInDirBytes(t.repo.Path) stdout, err := NewCommand("ls-tree", "-t", "-r", t.ID.String()).RunInDirBytes(t.repo.Path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
t.entries, err = parseTreeEntries(stdout, t)
return t.entries, err t.entriesRecursive, err = parseTreeEntries(stdout, t)
if err == nil {
t.entriesRecursiveParsed = true
}
return t.entriesRecursive, err
} }

27
vendor/github.com/mvdan/xurls/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,27 @@
Copyright (c) 2015, Daniel Martí. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

299
vendor/github.com/mvdan/xurls/schemes.go generated vendored Normal file
View File

@@ -0,0 +1,299 @@
// Generated by schemesgen
package xurls
// Schemes is a sorted list of all IANA assigned schemes.
//
// Source:
// https://www.iana.org/assignments/uri-schemes/uri-schemes-1.csv
var Schemes = []string{
`aaa`,
`aaas`,
`about`,
`acap`,
`acct`,
`acr`,
`adiumxtra`,
`afp`,
`afs`,
`aim`,
`appdata`,
`apt`,
`attachment`,
`aw`,
`barion`,
`beshare`,
`bitcoin`,
`bitcoincash`,
`blob`,
`bolo`,
`browserext`,
`callto`,
`cap`,
`chrome`,
`chrome-extension`,
`cid`,
`coap`,
`coap+tcp`,
`coap+ws`,
`coaps`,
`coaps+tcp`,
`coaps+ws`,
`com-eventbrite-attendee`,
`content`,
`conti`,
`crid`,
`cvs`,
`data`,
`dav`,
`diaspora`,
`dict`,
`did`,
`dis`,
`dlna-playcontainer`,
`dlna-playsingle`,
`dns`,
`dntp`,
`dtn`,
`dvb`,
`ed2k`,
`elsi`,
`example`,
`facetime`,
`fax`,
`feed`,
`feedready`,
`file`,
`filesystem`,
`finger`,
`fish`,
`ftp`,
`geo`,
`gg`,
`git`,
`gizmoproject`,
`go`,
`gopher`,
`graph`,
`gtalk`,
`h323`,
`ham`,
`hcap`,
`hcp`,
`http`,
`https`,
`hxxp`,
`hxxps`,
`hydrazone`,
`iax`,
`icap`,
`icon`,
`im`,
`imap`,
`info`,
`iotdisco`,
`ipn`,
`ipp`,
`ipps`,
`irc`,
`irc6`,
`ircs`,
`iris`,
`iris.beep`,
`iris.lwz`,
`iris.xpc`,
`iris.xpcs`,
`isostore`,
`itms`,
`jabber`,
`jar`,
`jms`,
`keyparc`,
`lastfm`,
`ldap`,
`ldaps`,
`lvlt`,
`magnet`,
`mailserver`,
`mailto`,
`maps`,
`market`,
`message`,
`microsoft.windows.camera`,
`microsoft.windows.camera.multipicker`,
`microsoft.windows.camera.picker`,
`mid`,
`mms`,
`modem`,
`mongodb`,
`moz`,
`ms-access`,
`ms-browser-extension`,
`ms-drive-to`,
`ms-enrollment`,
`ms-excel`,
`ms-gamebarservices`,
`ms-gamingoverlay`,
`ms-getoffice`,
`ms-help`,
`ms-infopath`,
`ms-inputapp`,
`ms-lockscreencomponent-config`,
`ms-media-stream-id`,
`ms-mixedrealitycapture`,
`ms-officeapp`,
`ms-people`,
`ms-project`,
`ms-powerpoint`,
`ms-publisher`,
`ms-restoretabcompanion`,
`ms-screenclip`,
`ms-screensketch`,
`ms-search`,
`ms-search-repair`,
`ms-secondary-screen-controller`,
`ms-secondary-screen-setup`,
`ms-settings`,
`ms-settings-airplanemode`,
`ms-settings-bluetooth`,
`ms-settings-camera`,
`ms-settings-cellular`,
`ms-settings-cloudstorage`,
`ms-settings-connectabledevices`,
`ms-settings-displays-topology`,
`ms-settings-emailandaccounts`,
`ms-settings-language`,
`ms-settings-location`,
`ms-settings-lock`,
`ms-settings-nfctransactions`,
`ms-settings-notifications`,
`ms-settings-power`,
`ms-settings-privacy`,
`ms-settings-proximity`,
`ms-settings-screenrotation`,
`ms-settings-wifi`,
`ms-settings-workplace`,
`ms-spd`,
`ms-sttoverlay`,
`ms-transit-to`,
`ms-useractivityset`,
`ms-virtualtouchpad`,
`ms-visio`,
`ms-walk-to`,
`ms-whiteboard`,
`ms-whiteboard-cmd`,
`ms-word`,
`msnim`,
`msrp`,
`msrps`,
`mtqp`,
`mumble`,
`mupdate`,
`mvn`,
`news`,
`nfs`,
`ni`,
`nih`,
`nntp`,
`notes`,
`ocf`,
`oid`,
`onenote`,
`onenote-cmd`,
`opaquelocktoken`,
`openpgp4fpr`,
`pack`,
`palm`,
`paparazzi`,
`pkcs11`,
`platform`,
`pop`,
`pres`,
`prospero`,
`proxy`,
`pwid`,
`psyc`,
`qb`,
`query`,
`redis`,
`rediss`,
`reload`,
`res`,
`resource`,
`rmi`,
`rsync`,
`rtmfp`,
`rtmp`,
`rtsp`,
`rtsps`,
`rtspu`,
`secondlife`,
`service`,
`session`,
`sftp`,
`sgn`,
`shttp`,
`sieve`,
`simpleledger`,
`sip`,
`sips`,
`skype`,
`smb`,
`sms`,
`smtp`,
`snews`,
`snmp`,
`soap.beep`,
`soap.beeps`,
`soldat`,
`spiffe`,
`spotify`,
`ssh`,
`steam`,
`stun`,
`stuns`,
`submit`,
`svn`,
`tag`,
`teamspeak`,
`tel`,
`teliaeid`,
`telnet`,
`tftp`,
`things`,
`thismessage`,
`tip`,
`tn3270`,
`tool`,
`turn`,
`turns`,
`tv`,
`udp`,
`unreal`,
`urn`,
`ut2004`,
`v-event`,
`vemmi`,
`ventrilo`,
`videotex`,
`vnc`,
`view-source`,
`wais`,
`webcal`,
`wpid`,
`ws`,
`wss`,
`wtai`,
`wyciwyg`,
`xcon`,
`xcon-userid`,
`xfire`,
`xmlrpc.beep`,
`xmlrpc.beeps`,
`xmpp`,
`xri`,
`ymsgr`,
`z39.50`,
`z39.50r`,
`z39.50s`,
}

1557
vendor/github.com/mvdan/xurls/tlds.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

24
vendor/github.com/mvdan/xurls/tlds_pseudo.go generated vendored Normal file
View File

@@ -0,0 +1,24 @@
// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information
package xurls
// PseudoTLDs is a sorted list of some widely used unofficial TLDs.
//
// Sources:
// * https://en.wikipedia.org/wiki/Pseudo-top-level_domain
// * https://en.wikipedia.org/wiki/Category:Pseudo-top-level_domains
// * https://tools.ietf.org/html/draft-grothoff-iesg-special-use-p2p-names-00
// * https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml
var PseudoTLDs = []string{
`bit`, // Namecoin
`example`, // Example domain
`exit`, // Tor exit node
`gnu`, // GNS by public key
`i2p`, // I2P network
`invalid`, // Invalid domain
`local`, // Local network
`localhost`, // Local network
`test`, // Test domain
`zkey`, // GNS domain name
}

107
vendor/github.com/mvdan/xurls/xurls.go generated vendored Normal file
View File

@@ -0,0 +1,107 @@
// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information
// Package xurls extracts urls from plain text using regular expressions.
package xurls
import (
"bytes"
"regexp"
)
//go:generate go run generate/tldsgen/main.go
//go:generate go run generate/schemesgen/main.go
const (
letter = `\p{L}`
mark = `\p{M}`
number = `\p{N}`
iriChar = letter + mark + number
currency = `\p{Sc}`
otherSymb = `\p{So}`
endChar = iriChar + `/\-+_&~*%=#` + currency + otherSymb
otherPunc = `\p{Po}`
midChar = endChar + `|` + otherPunc
wellParen = `\([` + midChar + `]*(\([` + midChar + `]*\)[` + midChar + `]*)*\)`
wellBrack = `\[[` + midChar + `]*(\[[` + midChar + `]*\][` + midChar + `]*)*\]`
wellBrace = `\{[` + midChar + `]*(\{[` + midChar + `]*\}[` + midChar + `]*)*\}`
wellAll = wellParen + `|` + wellBrack + `|` + wellBrace
pathCont = `([` + midChar + `]*(` + wellAll + `|[` + endChar + `])+)+`
iri = `[` + iriChar + `]([` + iriChar + `\-]*[` + iriChar + `])?`
domain = `(` + iri + `\.)+`
octet = `(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])`
ipv4Addr = `\b` + octet + `\.` + octet + `\.` + octet + `\.` + octet + `\b`
ipv6Addr = `([0-9a-fA-F]{1,4}:([0-9a-fA-F]{1,4}:([0-9a-fA-F]{1,4}:([0-9a-fA-F]{1,4}:([0-9a-fA-F]{1,4}:[0-9a-fA-F]{0,4}|:[0-9a-fA-F]{1,4})?|(:[0-9a-fA-F]{1,4}){0,2})|(:[0-9a-fA-F]{1,4}){0,3})|(:[0-9a-fA-F]{1,4}){0,4})|:(:[0-9a-fA-F]{1,4}){0,5})((:[0-9a-fA-F]{1,4}){2}|:(25[0-5]|(2[0-4]|1[0-9]|[1-9])?[0-9])(\.(25[0-5]|(2[0-4]|1[0-9]|[1-9])?[0-9])){3})|(([0-9a-fA-F]{1,4}:){1,6}|:):[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){7}:`
ipAddr = `(` + ipv4Addr + `|` + ipv6Addr + `)`
port = `(:[0-9]*)?`
)
// AnyScheme can be passed to StrictMatchingScheme to match any possibly valid
// scheme, and not just the known ones.
var AnyScheme = `([a-zA-Z][a-zA-Z.\-+]*://|` + anyOf(SchemesNoAuthority...) + `:)`
// SchemesNoAuthority is a sorted list of some well-known url schemes that are
// followed by ":" instead of "://".
var SchemesNoAuthority = []string{
`bitcoin`, // Bitcoin
`file`, // Files
`magnet`, // Torrent magnets
`mailto`, // Mail
`sms`, // SMS
`tel`, // Telephone
`xmpp`, // XMPP
}
func anyOf(strs ...string) string {
var b bytes.Buffer
b.WriteByte('(')
for i, s := range strs {
if i != 0 {
b.WriteByte('|')
}
b.WriteString(regexp.QuoteMeta(s))
}
b.WriteByte(')')
return b.String()
}
func strictExp() string {
schemes := `(` + anyOf(Schemes...) + `://|` + anyOf(SchemesNoAuthority...) + `:)`
return `(?i)` + schemes + `(?-i)` + pathCont
}
func relaxedExp() string {
site := domain + `(?i)` + anyOf(append(TLDs, PseudoTLDs...)...) + `(?-i)`
hostName := `(` + site + `|` + ipAddr + `)`
webURL := hostName + port + `(/|/` + pathCont + `?|\b|$)`
return strictExp() + `|` + webURL
}
// Strict produces a regexp that matches any URL with a scheme in either the
// Schemes or SchemesNoAuthority lists.
func Strict() *regexp.Regexp {
re := regexp.MustCompile(strictExp())
re.Longest()
return re
}
// Relaxed produces a regexp that matches any URL matched by Strict, plus any
// URL with no scheme.
func Relaxed() *regexp.Regexp {
re := regexp.MustCompile(relaxedExp())
re.Longest()
return re
}
// StrictMatchingScheme produces a regexp similar to Strict, but requiring that
// the scheme match the given regular expression. See AnyScheme too.
func StrictMatchingScheme(exp string) (*regexp.Regexp, error) {
strictMatching := `(?i)(` + exp + `)(?-i)` + pathCont
re, err := regexp.Compile(strictMatching)
if err != nil {
return nil, err
}
re.Longest()
return re, nil
}