Compare commits

...

34 Commits

Author SHA1 Message Date
Lunny Xiao
afa7f22dd8 Add changelog for v1.13.1 (#14172)
* Add changelog for v1.13.1

* Update CHANGELOG.md

Co-authored-by: John Olheiser <john.olheiser@gmail.com>

* Update CHANGELOG.md

* Update CHANGELOG.md

Co-authored-by: John Olheiser <john.olheiser@gmail.com>

* Update CHANGELOG.md

Co-authored-by: John Olheiser <john.olheiser@gmail.com>

* Update CHANGELOG.md

Co-authored-by: John Olheiser <john.olheiser@gmail.com>
Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2020-12-28 12:36:22 -05:00
Lunny Xiao
182be90655 Fix bug of link query order on markdown render (#14156) (#14171)
* Fix bug of link query order on markdown render

* Fix bluemonday bug and fix one wrong test

Co-authored-by: 6543 <6543@obermui.de>

Co-authored-by: 6543 <6543@obermui.de>
2020-12-28 12:08:55 -05:00
6543
4a738a8f16 Migration: drop too long repo topics (#14152) (#14155)
* Migration: drop to long repo topics

* Update modules/migrations/gitea_uploader.go
2020-12-26 21:57:06 -05:00
zeripath
206b66a184 Fix escaping issue in diff (#14154)
Ensure that linecontent is escaped before passing to template.HTML

Signed-off-by: Andrew Thornton <art27@cantab.net>
2020-12-26 22:15:42 +00:00
Daniil Pankratov
205be63bc1 Fix creation OAuth2 auth source from CLI. (#14146)
Fix #8356
2020-12-25 20:02:52 +08:00
zeripath
bf1441b1e1 Ensure that search term and page are not lost on adoption page-turn (#14133) (#14143)
Backport #14133

Fix #14111

Signed-off-by: Andrew Thornton <art27@cantab.net>
2020-12-24 21:54:15 +00:00
6543
fae18bdac0 more test case for STORAGE_TYPE overrides (and fixes) (#14096) (#14104)
Signed-off-by: 胡玮文 <huww98@outlook.com>

Co-authored-by: 胡玮文 <huww98@outlook.com>
2020-12-22 09:13:57 +02:00
6543
661e3e2bdc Fix storage config implementation (#14091) (#14095)
The design is very flexible, but not implemented correctly.
This commit fixes several issues:
* Costom storage type stated in https://docs.gitea.io/en-us/config-cheat-sheet/#storage-storage
  not working
* [storage.attachments], [storage.minio] section not respected

Signed-off-by: 胡玮文 <huww98@outlook.com>

Co-authored-by: 胡玮文 <huww98@outlook.com>
2020-12-22 00:56:18 +02:00
techknowlogick
70038719bf dep: update crypto. info: https://golangtutorial.dev/news/fix-in-crypto-package/ (#14078) 2020-12-21 14:02:40 +08:00
silverwind
55d7e53d99 Fix panic in BasicAuthDecode (#14046) (#14048)
* Fix panic in BasicAuthDecode

If the string does not contain ":" that function would run into an
`index out of range [1] with length 1` error. prevent that.

* Update BasicAuthDecode()

Co-authored-by: 6543 <6543@obermui.de>

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: zeripath <art27@cantab.net>
2020-12-19 00:19:43 +08:00
6543
96d41287e5 [API] GetCombinedCommitStatusByRef always return json & swagger doc fixes (#14047)
* Fix swagger docs

* always return json
2020-12-18 13:38:47 +00:00
6543
df11075389 HotFix: Hide private partisipation in Orgs (#13994) (#14031)
* HotFix: Hide private partisipation in Orgs

Co-authored-by: zeripath <art27@cantab.net>
2020-12-17 22:32:24 +01:00
zeripath
b8a2cd9f40 Always wait for the cmd to finish (#14006) (#14039)
Backport #14006

After cancelling the context we still need to wait for the
command to finish otherwise zombie processes may occur

Fix #13987
2020-12-17 21:06:51 +01:00
mrsdizzie
4f296f7436 Don't use simpleMDE editor on mobile devices for 1.13 (#14029)
* Don't use simpleMDE editor on mobile devices

simpleMDE doesn't work properly on mobile devices -- We've replaced it with the slightly more working easyMDE in 1.14 but since that change can't be backported to 1.13 we will just disable the editor on mobile here.

* make isMobile function per code review -- disable simpleMDE for code review and replies

* Fix issue with plain text and wiki

Co-authored-by: silverwind <me@silverwind.io>
2020-12-17 17:39:12 +01:00
6543
78b9ef3586 Add emoji in label to project boards (#13978) (#14021)
* Update view.tmpl

Added rendering of emoji to project label

* Add RenderEmojiPlain to the title and remove has-emoji

Co-authored-by: zeripath <art27@cantab.net>

Co-authored-by: Rakshith Ravi <rakshith.ravi@gmx.com>
Co-authored-by: zeripath <art27@cantab.net>
2020-12-16 15:15:58 -05:00
Cirno the Strongest
90dfe445c2 Send webhook when tag is removed via Web UI (#14015) (#14019)
* Send webhook when tag is removed via Web UI

* Stray code (cherry picked from commit 53308de0bf)

* Fix for 1.13
2020-12-16 18:24:02 +01:00
Jimmy Praet
a728d1e046 always use headCommitID for review comment diff (#14011) 2020-12-16 18:50:30 +08:00
zeripath
7f85728cf9 Trim the branch prefix from action.GetBranch (#13981) (#13986)
Backport #13981

 #13882 has revealed that the refname of an action is actually only a
refname pattern and necessarily a branch. For examplem pushing to
refs/heads/master will result in action with refname refs/heads/master
but pushing to master will result in a refname master.

The simplest solution to providing a fix here is to trim the prefix
therefore this PR proposes this.

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: a1012112796 <1012112796@qq.com>

Co-authored-by: a1012112796 <1012112796@qq.com>
2020-12-14 15:35:40 -05:00
zeripath
d2b308ae35 Ensure template renderer is available before storage handler (#13982)
`ctx.Error` requires that templates are available for this to
render the error page otherwise there will be a panic at this
time.

This was fixed in #13164 but was not completely backported.

Fix #13971

Signed-off-by: Andrew Thornton <art27@cantab.net>
2020-12-14 20:45:33 +08:00
zeripath
8e8e8ee150 Whenever the password is updated ensure that the hash algorithm is too (#13966) (#13967)
Backport #13966

`user.HashPassword` may potentially - and in fact now likely does - change
the `passwd_hash_algo` therefore whenever the `passwd` is updated, this
also needs to be updated.

Fix #13832

Thanks @fblaese for the hint

Signed-off-by: Andrew Thornton <art27@cantab.net>
2020-12-13 01:01:44 +01:00
6543
05ee88e576 Enforce setting HEAD in wiki to master (#13950) (#13961)
The default branch in wikis must be master - therefore forcibly set the HEAD
to master.

Fix #13846

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: 6543 <6543@obermui.de>

Co-authored-by: zeripath <art27@cantab.net>
2020-12-12 17:21:26 +00:00
Lunny Xiao
0d7cb2323f Fix feishu webhook caused by API changed (#13937) (#13938)
fix #13858
2020-12-11 16:11:32 +01:00
Lunny Xiao
5cdffc2b0c log error when login failed (#13903) (#13913)
Co-authored-by: techknowlogick <techknowlogick@gitea.io>

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Co-authored-by: 6543 <6543@obermui.de>
2020-12-09 10:37:15 -05:00
Jimmy Praet
a0101c61a4 Fix Quote Reply button on review diff (#13830) (#13898)
Backport of #13830 

Co-authored-by: 6543 <6543@obermui.de>
2020-12-08 22:12:35 +00:00
a1012112796
c0b1197a64 Fix Pull Merge when tag with same name as base branch exist (#13882) (#13896)
fix dst refspec error in 'Push back to upstream' when base branch have
same name with a tag.

fix #13851
Signed-off-by: a1012112796 <1012112796@qq.com>

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: zeripath <art27@cantab.net>
2020-12-08 12:58:44 +01:00
6543
e39ed0b1d9 [API] return original URL of Repositories (#13885) (#13886) 2020-12-08 05:59:19 +01:00
manuelluis
cb24cbc1fc Fix branch/tag notifications in mirror sync (#13855) (#13862)
Co-authored-by: Gitea <gitea@fake.local>
Co-authored-by: 6543 <6543@obermui.de>
2020-12-05 23:30:28 -05:00
silverwind
584d01cf2c Fix mermaid chart size (#13865) 2020-12-05 22:13:31 -05:00
mrsdizzie
798fdeae45 Fix crash in short link processor (#13839) (#13841)
Fixes #13819
2020-12-04 04:08:48 +01:00
silverwind
87997cccbb Update font stack to bootstrap's latest (#13834) (#13837)
Backport #13834
2020-12-04 02:21:34 +01:00
John Olheiser
0d5111c5c3 Make sure email recipients can see issue (#13820) (#13827)
* Initial pass

* Remove over-op

Signed-off-by: jolheiser <john.olheiser@gmail.com>
2020-12-03 22:37:33 +01:00
Jimmy Praet
10fff12da4 Reply button is not removed when deleting a code review comment (#13824)
Backport #13774
2020-12-03 20:26:47 +00:00
zeripath
0d43a2a069 When reinitialising DBConfig reset the database use flags (#13796) (#13811)
Backport #13796

One perennial issue is users running the install page,
changing the database dialect and then suffering with issues

This PR simply resets all of the database.Use flags on
initDBConfig. This should prevent this issue from occuring.

Fix #13788
Fix #5480

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: techknowlogick <techknowlogick@gitea.io>

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2020-12-03 11:13:19 +01:00
6543
8396b792f8 Migrations: Use Process Manager to create own Context (#13793) 2020-12-02 15:11:11 -06:00
85 changed files with 1044 additions and 339 deletions

View File

@@ -4,6 +4,42 @@ 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
been added to each release, please refer to the [blog](https://blog.gitea.io).
## [1.13.1](https://github.com/go-gitea/gitea/releases/tag/v1.13.1) - 2020-12-29
* SECURITY
* Hide private participation in Orgs (#13994) (#14031)
* Fix escaping issue in diff (#14153) (#14154)
* BUGFIXES
* Fix bug of link query order on markdown render (#14156) (#14171)
* Drop long repo topics during migration (#14152) (#14155)
* Ensure that search term and page are not lost on adoption page-turn (#14133) (#14143)
* Fix storage config implementation (#14091) (#14095)
* Fix panic in BasicAuthDecode (#14046) (#14048)
* Always wait for the cmd to finish (#14006) (#14039)
* Don't use simpleMDE editor on mobile devices for 1.13 (#14029)
* Fix incorrect review comment diffs (#14002) (#14011)
* Trim the branch prefix from action.GetBranch (#13981) (#13986)
* Ensure template renderer is available before storage handler (#13164) (#13982)
* Whenever the password is updated ensure that the hash algorithm is too (#13966) (#13967)
* Enforce setting HEAD in wiki to master (#13950) (#13961)
* Fix feishu webhook caused by API changed (#13938)
* Fix Quote Reply button on review diff (#13830) (#13898)
* Fix Pull Merge when tag with same name as base branch exist (#13882) (#13896)
* Fix mermaid chart size (#13865)
* Fix branch/tag notifications in mirror sync (#13855) (#13862)
* Fix crash in short link processor (#13839) (#13841)
* Update font stack to bootstrap's latest (#13834) (#13837)
* Make sure email recipients can see issue (#13820) (#13827)
* Reply button is not removed when deleting a code review comment (#13824)
* When reinitialising DBConfig reset the database use flags (#13796) (#13811)
* ENHANCEMENTS
* Add emoji in label to project boards (#13978) (#14021)
* Send webhook when tag is removed via Web UI (#14015) (#14019)
* Use Process Manager to create own Context (#13792) (#13793)
* API
* GetCombinedCommitStatusByRef always return json & swagger doc fixes (#14047)
* Return original URL of Repositories (#13885) (#13886)
## [1.13.0](https://github.com/go-gitea/gitea/releases/tag/v1.13.0) - 2020-12-01
* SECURITY
* Add Allow-/Block-List for Migrate & Mirrors (#13610) (#13776)

View File

@@ -283,7 +283,7 @@ func runChangePassword(c *cli.Context) error {
}
user.HashPassword(c.String("password"))
if err := models.UpdateUserCols(user, "passwd", "salt"); err != nil {
if err := models.UpdateUserCols(user, "passwd", "passwd_hash_algo", "salt"); err != nil {
return err
}

4
go.mod
View File

@@ -104,7 +104,7 @@ require (
github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60
go.jolheiser.com/hcaptcha v0.0.4
go.jolheiser.com/pwn v0.0.3
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620
golang.org/x/net v0.0.0-20200904194848-62affa334b73
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff
@@ -124,3 +124,5 @@ require (
)
replace github.com/hashicorp/go-version => github.com/6543/go-version v1.2.4
replace github.com/microcosm-cc/bluemonday => github.com/lunny/bluemonday v1.0.5-0.20201227154428-ca34796141e8

10
go.sum
View File

@@ -598,6 +598,8 @@ github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.8.1-0.20200908161135-083382b7e6fc h1:ERSU1OvZ6MdWhHieo2oT7xwR/HCksqKdgK6iYPU5pHI=
github.com/lib/pq v1.8.1-0.20200908161135-083382b7e6fc/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lunny/bluemonday v1.0.5-0.20201227154428-ca34796141e8 h1:1omo92DLtxQu6VwVPSZAmduHaK5zssed6cvkHyl1XOg=
github.com/lunny/bluemonday v1.0.5-0.20201227154428-ca34796141e8/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w=
github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 h1:uNwtsDp7ci48vBTTxDuwcoTXz4lwtDTe7TjCQ0noaWY=
github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96/go.mod h1:mmIfjCSQlGYXmJ95jFN84AkQFnVABtKuJL8IrzwvUKQ=
github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de h1:nyxwRdWHAVxpFcDThedEgQ07DbcRc5xgNObtbTp76fk=
@@ -649,8 +651,6 @@ github.com/mgechev/revive v1.0.3-0.20200921231451-246eac737dc7 h1:ydVkpU/M4/c45y
github.com/mgechev/revive v1.0.3-0.20200921231451-246eac737dc7/go.mod h1:no/hfevHbndpXR5CaJahkYCfM/FFpmM/dSOwFGU7Z1o=
github.com/mholt/archiver/v3 v3.3.0 h1:vWjhY8SQp5yzM9P6OJ/eZEkmi3UAbRrxCq48MxjAzig=
github.com/mholt/archiver/v3 v3.3.0/go.mod h1:YnQtqsp+94Rwd0D/rk5cnLrxusUBUXg+08Ebtr1Mqao=
github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912 h1:hJde9rA24hlTcAYSwJoXpDUyGtfKQ/jsofw+WaDqGrI=
github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4=
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
@@ -937,8 +937,9 @@ golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620 h1:3wPMTskHO3+O6jqTEXyFcsnuxMQOqYSaHsDxcbUXpqA=
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1053,6 +1054,8 @@ golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff h1:1CPUrky56AcgSpxz/KfgzQWzfG09u5YOL8MvPYBlrL8=
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@@ -1197,6 +1200,7 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
mvdan.cc/xurls/v2 v2.2.0 h1:NSZPykBXJFCetGZykLAxaL6SIpvbVy/UFEniIfHAa8A=
mvdan.cc/xurls/v2 v2.2.0/go.mod h1:EV1RMtya9D6G5DMYPGD8zTQzaHet6Jh8gFlRgGRJeO8=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3FJbP5Cvdq7Khzn6J9OCUQJaBwgBkCR+MOwSs=

View File

@@ -111,7 +111,7 @@ func onGiteaRun(t *testing.T, callback func(*testing.T, *url.URL), prepare ...bo
func doGitClone(dstLocalPath string, u *url.URL) func(*testing.T) {
return func(t *testing.T) {
assert.NoError(t, git.CloneWithArgs(u.String(), dstLocalPath, allowLFSFilters(), git.CloneRepoOptions{}))
assert.NoError(t, git.CloneWithArgs(context.Background(), u.String(), dstLocalPath, allowLFSFilters(), git.CloneRepoOptions{}))
assert.True(t, com.IsExist(filepath.Join(dstLocalPath, "README.md")))
}
}

View File

@@ -13,6 +13,7 @@ import (
"time"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
@@ -243,7 +244,7 @@ func (a *Action) getCommentLink(e Engine) string {
// GetBranch returns the action's repository branch.
func (a *Action) GetBranch() string {
return a.RefName
return strings.TrimPrefix(a.RefName, git.BranchPrefix)
}
// GetContent returns the action's content.

View File

@@ -119,8 +119,18 @@ func InitOAuth2() error {
if err := oauth2.Init(x); err != nil {
return err
}
loginSources, _ := GetActiveOAuth2ProviderLoginSources()
return initOAuth2LoginSources()
}
// ResetOAuth2 clears existing OAuth2 providers and loads them from DB
func ResetOAuth2() error {
oauth2.ClearProviders()
return initOAuth2LoginSources()
}
// initOAuth2LoginSources is used to load and register all active OAuth2 providers
func initOAuth2LoginSources() error {
loginSources, _ := GetActiveOAuth2ProviderLoginSources()
for _, source := range loginSources {
oAuth2Config := source.OAuth2()
err := oauth2.RegisterProvider(source.Name, oAuth2Config.Provider, oAuth2Config.ClientID, oAuth2Config.ClientSecret, oAuth2Config.OpenIDConnectAutoDiscoveryURL, oAuth2Config.CustomURLMapping)

View File

@@ -426,6 +426,7 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool)
HTMLURL: repo.HTMLURL(),
SSHURL: cloneLink.SSH,
CloneURL: cloneLink.HTTPS,
OriginalURL: repo.SanitizedOriginalURL(),
Website: repo.Website,
Stars: repo.NumStars,
Forks: repo.NumForks,

View File

@@ -551,6 +551,7 @@ func (u *User) GetOwnedOrganizations() (err error) {
}
// GetOrganizations returns paginated organizations that user belongs to.
// TODO: does not respect All and show orgs you privately participate
func (u *User) GetOrganizations(opts *SearchOrganizationsOptions) error {
sess := x.NewSession()
defer sess.Close()

View File

@@ -118,6 +118,11 @@ func RemoveProvider(providerName string) {
delete(goth.GetProviders(), providerName)
}
// ClearProviders clears all OAuth2 providers from the goth lib
func ClearProviders() {
goth.ClearProviders()
}
// used to create different types of goth providers
func createProvider(providerName, providerType, clientID, clientSecret, openIDConnectAutoDiscoveryURL string, customURLMapping *CustomURLMapping) (goth.Provider, error) {
callbackURL := setting.AppURL + "user/oauth2/" + url.PathEscape(providerName) + "/callback"

View File

@@ -10,6 +10,7 @@ import (
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"net/http"
"net/url"
@@ -65,6 +66,11 @@ func BasicAuthDecode(encoded string) (string, string, error) {
}
auth := strings.SplitN(string(s), ":", 2)
if len(auth) != 2 {
return "", "", errors.New("invalid basic authentication")
}
return auth[0], auth[1], nil
}

View File

@@ -46,6 +46,12 @@ func TestBasicAuthDecode(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "foo", user)
assert.Equal(t, "bar", pass)
_, _, err = BasicAuthDecode("aW52YWxpZA==")
assert.Error(t, err)
_, _, err = BasicAuthDecode("invalid")
assert.Error(t, err)
}
func TestBasicAuthEncode(t *testing.T) {

View File

@@ -153,6 +153,7 @@ func (c *Command) RunInDirTimeoutEnvFullPipelineFunc(env []string, timeout time.
err := fn(ctx, cancel)
if err != nil {
cancel()
_ = cmd.Wait()
return err
}
}

View File

@@ -32,6 +32,7 @@ var (
GitExecutable = "git"
// DefaultContext is the default context to run git commands in
// will be overwritten by Init with HammerContext
DefaultContext = context.Background()
gitVersion *version.Version

View File

@@ -8,6 +8,7 @@ package git
import (
"bytes"
"container/list"
"context"
"errors"
"fmt"
"os"
@@ -166,19 +167,24 @@ type CloneRepoOptions struct {
// Clone clones original repository to target path.
func Clone(from, to string, opts CloneRepoOptions) (err error) {
return CloneWithContext(DefaultContext, from, to, opts)
}
// CloneWithContext clones original repository to target path.
func CloneWithContext(ctx context.Context, from, to string, opts CloneRepoOptions) (err error) {
cargs := make([]string, len(GlobalCommandArgs))
copy(cargs, GlobalCommandArgs)
return CloneWithArgs(from, to, cargs, opts)
return CloneWithArgs(ctx, from, to, cargs, opts)
}
// CloneWithArgs original repository to target path.
func CloneWithArgs(from, to string, args []string, opts CloneRepoOptions) (err error) {
func CloneWithArgs(ctx context.Context, from, to string, args []string, opts CloneRepoOptions) (err error) {
toDir := path.Dir(to)
if err = os.MkdirAll(toDir, os.ModePerm); err != nil {
return err
}
cmd := NewCommandNoGlobals(args...).AddArguments("clone")
cmd := NewCommandContextNoGlobals(ctx, args...).AddArguments("clone")
if opts.Mirror {
cmd.AddArguments("--mirror")
}

View File

@@ -632,16 +632,18 @@ func shortLinkProcessorFull(ctx *postProcessCtx, node *html.Node, noLink bool) {
// When parsing HTML, x/net/html will change all quotes which are
// not used for syntax into UTF-8 quotes. So checking val[0] won't
// be enough, since that only checks a single byte.
if (strings.HasPrefix(val, "“") && strings.HasSuffix(val, "”")) ||
(strings.HasPrefix(val, "") && strings.HasSuffix(val, "")) {
const lenQuote = len("")
val = val[lenQuote : len(val)-lenQuote]
} else if (strings.HasPrefix(val, "\"") && strings.HasSuffix(val, "\"")) ||
(strings.HasPrefix(val, "'") && strings.HasSuffix(val, "'")) {
val = val[1 : len(val)-1]
} else if strings.HasPrefix(val, "'") && strings.HasSuffix(val, "") {
const lenQuote = len("")
val = val[1 : len(val)-lenQuote]
if len(val) > 1 {
if (strings.HasPrefix(val, "") && strings.HasSuffix(val, "")) ||
(strings.HasPrefix(val, "") && strings.HasSuffix(val, "")) {
const lenQuote = len("")
val = val[lenQuote : len(val)-lenQuote]
} else if (strings.HasPrefix(val, "\"") && strings.HasSuffix(val, "\"")) ||
(strings.HasPrefix(val, "'") && strings.HasSuffix(val, "'")) {
val = val[1 : len(val)-1]
} else if strings.HasPrefix(val, "'") && strings.HasSuffix(val, "") {
const lenQuote = len("")
val = val[1 : len(val)-lenQuote]
}
}
props[key] = val
}

View File

@@ -142,7 +142,7 @@ func TestRender_links(t *testing.T) {
`<p><a href="ftp://gitea.com/file.txt" rel="nofollow">ftp://gitea.com/file.txt</a></p>`)
test(
"magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download",
`<p><a href="magnet:?dn=download&xt=urn%3Abtih%3A5dee65101db281ac9c46344cd6b175cdcadabcde" rel="nofollow">magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&amp;dn=download</a></p>`)
`<p><a href="magnet:?xt=urn%3Abtih%3A5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download" rel="nofollow">magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&amp;dn=download</a></p>`)
// Test that should *not* be turned into URL
test(

View File

@@ -125,7 +125,7 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.Migrate
}
r.DefaultBranch = repo.DefaultBranch
r, err = repository.MigrateRepositoryGitData(g.doer, owner, r, base.MigrateOptions{
r, err = repository.MigrateRepositoryGitData(g.ctx, owner, r, base.MigrateOptions{
RepoName: g.repoName,
Description: repo.Description,
OriginalURL: repo.OriginalURL,
@@ -154,6 +154,15 @@ func (g *GiteaLocalUploader) Close() {
// CreateTopics creates topics
func (g *GiteaLocalUploader) CreateTopics(topics ...string) error {
// ignore topics to long for the db
c := 0
for i := range topics {
if len(topics[i]) <= 25 {
topics[c] = topics[i]
c++
}
}
topics = topics[:c]
return models.SaveTopics(g.repo.ID, topics...)
}

View File

@@ -5,6 +5,7 @@
package repository
import (
"context"
"fmt"
"path"
"strings"
@@ -41,7 +42,7 @@ func WikiRemoteURL(remote string) string {
}
// MigrateRepositoryGitData starts migrating git related data after created migrating repository
func MigrateRepositoryGitData(doer, u *models.User, repo *models.Repository, opts migration.MigrateOptions) (*models.Repository, error) {
func MigrateRepositoryGitData(ctx context.Context, u *models.User, repo *models.Repository, opts migration.MigrateOptions) (*models.Repository, error) {
repoPath := models.RepoPath(u.Name, opts.RepoName)
if u.IsOrganization() {
@@ -61,7 +62,7 @@ func MigrateRepositoryGitData(doer, u *models.User, repo *models.Repository, opt
return repo, fmt.Errorf("Failed to remove %s: %v", repoPath, err)
}
if err = git.Clone(opts.CloneAddr, repoPath, git.CloneRepoOptions{
if err = git.CloneWithContext(ctx, opts.CloneAddr, repoPath, git.CloneRepoOptions{
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
@@ -77,7 +78,7 @@ func MigrateRepositoryGitData(doer, u *models.User, repo *models.Repository, opt
return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err)
}
if err = git.Clone(wikiRemotePath, wikiPath, git.CloneRepoOptions{
if err = git.CloneWithContext(ctx, wikiRemotePath, wikiPath, git.CloneRepoOptions{
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,

View File

@@ -62,6 +62,11 @@ func InitDBConfig() {
sec := Cfg.Section("database")
Database.Type = sec.Key("DB_TYPE").String()
defaultCharset := "utf8"
Database.UseMySQL = false
Database.UseSQLite3 = false
Database.UsePostgreSQL = false
Database.UseMSSQL = false
switch Database.Type {
case "sqlite3":
Database.UseSQLite3 = true

View File

@@ -31,22 +31,10 @@ func (s *Storage) MapTo(v interface{}) error {
return nil
}
func getStorage(name, typ string, overrides ...*ini.Section) Storage {
func getStorage(name, typ string, targetSec *ini.Section) Storage {
const sectionName = "storage"
sec := Cfg.Section(sectionName)
if len(overrides) == 0 {
overrides = []*ini.Section{
Cfg.Section(sectionName + "." + typ),
Cfg.Section(sectionName + "." + name),
}
}
var storage Storage
storage.Type = sec.Key("STORAGE_TYPE").MustString(typ)
storage.ServeDirect = sec.Key("SERVE_DIRECT").MustBool(false)
// Global Defaults
sec.Key("MINIO_ENDPOINT").MustString("localhost:9000")
sec.Key("MINIO_ACCESS_KEY_ID").MustString("")
@@ -55,17 +43,37 @@ func getStorage(name, typ string, overrides ...*ini.Section) Storage {
sec.Key("MINIO_LOCATION").MustString("us-east-1")
sec.Key("MINIO_USE_SSL").MustBool(false)
storage.Section = sec
var storage Storage
storage.Section = targetSec
storage.Type = typ
overrides := make([]*ini.Section, 0, 3)
nameSec, err := Cfg.GetSection(sectionName + "." + name)
if err == nil {
overrides = append(overrides, nameSec)
}
typeSec, err := Cfg.GetSection(sectionName + "." + typ)
if err == nil {
overrides = append(overrides, typeSec)
nextType := typeSec.Key("STORAGE_TYPE").String()
if len(nextType) > 0 {
storage.Type = nextType // Support custom STORAGE_TYPE
}
}
overrides = append(overrides, sec)
for _, override := range overrides {
for _, key := range storage.Section.Keys() {
if !override.HasKey(key.Name()) {
_, _ = override.NewKey(key.Name(), key.Value())
for _, key := range override.Keys() {
if !targetSec.HasKey(key.Name()) {
_, _ = targetSec.NewKey(key.Name(), key.Value())
}
}
storage.ServeDirect = override.Key("SERVE_DIRECT").MustBool(false)
storage.Section = override
if len(storage.Type) == 0 {
storage.Type = override.Key("STORAGE_TYPE").String()
}
}
storage.ServeDirect = storage.Section.Key("SERVE_DIRECT").MustBool(false)
// Specific defaults
storage.Path = storage.Section.Key("PATH").MustString(filepath.Join(AppDataPath, name))

View File

@@ -0,0 +1,197 @@
// Copyright 2020 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 setting
import (
"testing"
"github.com/stretchr/testify/assert"
ini "gopkg.in/ini.v1"
)
func Test_getStorageCustomType(t *testing.T) {
iniStr := `
[attachment]
STORAGE_TYPE = my_minio
MINIO_BUCKET = gitea-attachment
[storage.my_minio]
STORAGE_TYPE = minio
MINIO_ENDPOINT = my_minio:9000
`
Cfg, _ = ini.Load([]byte(iniStr))
sec := Cfg.Section("attachment")
storageType := sec.Key("STORAGE_TYPE").MustString("")
storage := getStorage("attachments", storageType, sec)
assert.EqualValues(t, "minio", storage.Type)
assert.EqualValues(t, "my_minio:9000", storage.Section.Key("MINIO_ENDPOINT").String())
assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String())
}
func Test_getStorageNameSectionOverridesTypeSection(t *testing.T) {
iniStr := `
[attachment]
STORAGE_TYPE = minio
[storage.attachments]
MINIO_BUCKET = gitea-attachment
[storage.minio]
MINIO_BUCKET = gitea
`
Cfg, _ = ini.Load([]byte(iniStr))
sec := Cfg.Section("attachment")
storageType := sec.Key("STORAGE_TYPE").MustString("")
storage := getStorage("attachments", storageType, sec)
assert.EqualValues(t, "minio", storage.Type)
assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String())
}
func Test_getStorageTypeSectionOverridesStorageSection(t *testing.T) {
iniStr := `
[attachment]
STORAGE_TYPE = minio
[storage.minio]
MINIO_BUCKET = gitea-minio
[storage]
MINIO_BUCKET = gitea
`
Cfg, _ = ini.Load([]byte(iniStr))
sec := Cfg.Section("attachment")
storageType := sec.Key("STORAGE_TYPE").MustString("")
storage := getStorage("attachments", storageType, sec)
assert.EqualValues(t, "minio", storage.Type)
assert.EqualValues(t, "gitea-minio", storage.Section.Key("MINIO_BUCKET").String())
}
func Test_getStorageSpecificOverridesStorage(t *testing.T) {
iniStr := `
[attachment]
STORAGE_TYPE = minio
MINIO_BUCKET = gitea-attachment
[storage.attachments]
MINIO_BUCKET = gitea
[storage]
STORAGE_TYPE = local
`
Cfg, _ = ini.Load([]byte(iniStr))
sec := Cfg.Section("attachment")
storageType := sec.Key("STORAGE_TYPE").MustString("")
storage := getStorage("attachments", storageType, sec)
assert.EqualValues(t, "minio", storage.Type)
assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String())
}
func Test_getStorageGetDefaults(t *testing.T) {
Cfg, _ = ini.Load([]byte(""))
sec := Cfg.Section("attachment")
storageType := sec.Key("STORAGE_TYPE").MustString("")
storage := getStorage("attachments", storageType, sec)
assert.EqualValues(t, "gitea", storage.Section.Key("MINIO_BUCKET").String())
}
func Test_getStorageMultipleName(t *testing.T) {
iniStr := `
[lfs]
MINIO_BUCKET = gitea-lfs
[attachment]
MINIO_BUCKET = gitea-attachment
[storage]
MINIO_BUCKET = gitea-storage
`
Cfg, _ = ini.Load([]byte(iniStr))
{
sec := Cfg.Section("attachment")
storageType := sec.Key("STORAGE_TYPE").MustString("")
storage := getStorage("attachments", storageType, sec)
assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String())
}
{
sec := Cfg.Section("lfs")
storageType := sec.Key("STORAGE_TYPE").MustString("")
storage := getStorage("lfs", storageType, sec)
assert.EqualValues(t, "gitea-lfs", storage.Section.Key("MINIO_BUCKET").String())
}
{
sec := Cfg.Section("avatar")
storageType := sec.Key("STORAGE_TYPE").MustString("")
storage := getStorage("avatars", storageType, sec)
assert.EqualValues(t, "gitea-storage", storage.Section.Key("MINIO_BUCKET").String())
}
}
func Test_getStorageUseOtherNameAsType(t *testing.T) {
iniStr := `
[attachment]
STORAGE_TYPE = lfs
[storage.lfs]
MINIO_BUCKET = gitea-storage
`
Cfg, _ = ini.Load([]byte(iniStr))
{
sec := Cfg.Section("attachment")
storageType := sec.Key("STORAGE_TYPE").MustString("")
storage := getStorage("attachments", storageType, sec)
assert.EqualValues(t, "gitea-storage", storage.Section.Key("MINIO_BUCKET").String())
}
{
sec := Cfg.Section("lfs")
storageType := sec.Key("STORAGE_TYPE").MustString("")
storage := getStorage("lfs", storageType, sec)
assert.EqualValues(t, "gitea-storage", storage.Section.Key("MINIO_BUCKET").String())
}
}
func Test_getStorageInheritStorageType(t *testing.T) {
iniStr := `
[storage]
STORAGE_TYPE = minio
`
Cfg, _ = ini.Load([]byte(iniStr))
sec := Cfg.Section("attachment")
storageType := sec.Key("STORAGE_TYPE").MustString("")
storage := getStorage("attachments", storageType, sec)
assert.EqualValues(t, "minio", storage.Type)
}
func Test_getStorageInheritNameSectionType(t *testing.T) {
iniStr := `
[storage.attachments]
STORAGE_TYPE = minio
`
Cfg, _ = ini.Load([]byte(iniStr))
sec := Cfg.Section("attachment")
storageType := sec.Key("STORAGE_TYPE").MustString("")
storage := getStorage("attachments", storageType, sec)
assert.EqualValues(t, "minio", storage.Type)
}

View File

@@ -5,6 +5,7 @@
package task
import (
"context"
"errors"
"fmt"
"strings"
@@ -15,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/migrations"
migration "code.gitea.io/gitea/modules/migrations/base"
"code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
@@ -82,11 +84,6 @@ func runMigrateTask(t *models.Task) (err error) {
if err = t.LoadOwner(); err != nil {
return
}
t.StartTime = timeutil.TimeStampNow()
t.Status = structs.TaskStatusRunning
if err = t.UpdateCols("start_time", "status"); err != nil {
return
}
var opts *migration.MigrateOptions
opts, err = t.MigrateConfig()
@@ -96,7 +93,20 @@ func runMigrateTask(t *models.Task) (err error) {
opts.MigrateToRepoID = t.RepoID
var repo *models.Repository
repo, err = migrations.MigrateRepository(graceful.GetManager().HammerContext(), t.Doer, t.Owner.Name, *opts)
ctx, cancel := context.WithCancel(graceful.GetManager().ShutdownContext())
defer cancel()
pm := process.GetManager()
pid := pm.Add(fmt.Sprintf("MigrateTask: %s/%s", t.Owner.Name, opts.RepoName), cancel)
defer pm.Remove(pid)
t.StartTime = timeutil.TimeStampNow()
t.Status = structs.TaskStatusRunning
if err = t.UpdateCols("start_time", "status"); err != nil {
return
}
repo, err = migrations.MigrateRepository(ctx, t.Doer, t.Owner.Name, *opts)
if err == nil {
log.Trace("Repository migrated [%d]: %s/%s", repo.ID, t.Owner.Name, repo.Name)
return

View File

@@ -17,11 +17,24 @@ import (
type (
// FeishuPayload represents
FeishuPayload struct {
Title string `json:"title"`
Text string `json:"text"`
MsgType string `json:"msg_type"` // text / post / image / share_chat / interactive
Content struct {
Text string `json:"text"`
} `json:"content"`
}
)
func newFeishuTextPayload(text string) *FeishuPayload {
return &FeishuPayload{
MsgType: "text",
Content: struct {
Text string `json:"text"`
}{
Text: text,
},
}
}
// SetSecret sets the Feishu secret
func (f *FeishuPayload) SetSecret(_ string) {}
@@ -42,34 +55,25 @@ var (
func (f *FeishuPayload) Create(p *api.CreatePayload) (api.Payloader, error) {
// created tag/branch
refName := git.RefEndName(p.Ref)
title := fmt.Sprintf("[%s] %s %s created", p.Repo.FullName, p.RefType, refName)
text := fmt.Sprintf("[%s] %s %s created", p.Repo.FullName, p.RefType, refName)
return &FeishuPayload{
Text: title,
Title: title,
}, nil
return newFeishuTextPayload(text), nil
}
// Delete implements PayloadConvertor Delete method
func (f *FeishuPayload) Delete(p *api.DeletePayload) (api.Payloader, error) {
// created tag/branch
refName := git.RefEndName(p.Ref)
title := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName)
text := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName)
return &FeishuPayload{
Text: title,
Title: title,
}, nil
return newFeishuTextPayload(text), nil
}
// Fork implements PayloadConvertor Fork method
func (f *FeishuPayload) Fork(p *api.ForkPayload) (api.Payloader, error) {
title := fmt.Sprintf("%s is forked to %s", p.Forkee.FullName, p.Repo.FullName)
text := fmt.Sprintf("%s is forked to %s", p.Forkee.FullName, p.Repo.FullName)
return &FeishuPayload{
Text: title,
Title: title,
}, nil
return newFeishuTextPayload(text), nil
}
// Push implements PayloadConvertor Push method
@@ -79,9 +83,7 @@ func (f *FeishuPayload) Push(p *api.PushPayload) (api.Payloader, error) {
commitDesc string
)
title := fmt.Sprintf("[%s:%s] %s", p.Repo.FullName, branchName, commitDesc)
var text string
var text = fmt.Sprintf("[%s:%s] %s\n", p.Repo.FullName, branchName, commitDesc)
// for each commit, generate attachment text
for i, commit := range p.Commits {
var authorName string
@@ -96,40 +98,28 @@ func (f *FeishuPayload) Push(p *api.PushPayload) (api.Payloader, error) {
}
}
return &FeishuPayload{
Text: text,
Title: title,
}, nil
return newFeishuTextPayload(text), nil
}
// Issue implements PayloadConvertor Issue method
func (f *FeishuPayload) Issue(p *api.IssuePayload) (api.Payloader, error) {
text, issueTitle, attachmentText, _ := getIssuesPayloadInfo(p, noneLinkFormatter, true)
return &FeishuPayload{
Text: text + "\r\n\r\n" + attachmentText,
Title: issueTitle,
}, nil
return newFeishuTextPayload(issueTitle + "\r\n" + text + "\r\n\r\n" + attachmentText), nil
}
// IssueComment implements PayloadConvertor IssueComment method
func (f *FeishuPayload) IssueComment(p *api.IssueCommentPayload) (api.Payloader, error) {
text, issueTitle, _ := getIssueCommentPayloadInfo(p, noneLinkFormatter, true)
return &FeishuPayload{
Text: text + "\r\n\r\n" + p.Comment.Body,
Title: issueTitle,
}, nil
return newFeishuTextPayload(issueTitle + "\r\n" + text + "\r\n\r\n" + p.Comment.Body), nil
}
// PullRequest implements PayloadConvertor PullRequest method
func (f *FeishuPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, error) {
text, issueTitle, attachmentText, _ := getPullRequestPayloadInfo(p, noneLinkFormatter, true)
return &FeishuPayload{
Text: text + "\r\n\r\n" + attachmentText,
Title: issueTitle,
}, nil
return newFeishuTextPayload(issueTitle + "\r\n" + text + "\r\n\r\n" + attachmentText), nil
}
// Review implements PayloadConvertor Review method
@@ -147,28 +137,19 @@ func (f *FeishuPayload) Review(p *api.PullRequestPayload, event models.HookEvent
}
return &FeishuPayload{
Text: title + "\r\n\r\n" + text,
Title: title,
}, nil
return newFeishuTextPayload(title + "\r\n\r\n" + text), nil
}
// Repository implements PayloadConvertor Repository method
func (f *FeishuPayload) Repository(p *api.RepositoryPayload) (api.Payloader, error) {
var title string
var text string
switch p.Action {
case api.HookRepoCreated:
title = fmt.Sprintf("[%s] Repository created", p.Repository.FullName)
return &FeishuPayload{
Text: title,
Title: title,
}, nil
text = fmt.Sprintf("[%s] Repository created", p.Repository.FullName)
return newFeishuTextPayload(text), nil
case api.HookRepoDeleted:
title = fmt.Sprintf("[%s] Repository deleted", p.Repository.FullName)
return &FeishuPayload{
Title: title,
Text: title,
}, nil
text = fmt.Sprintf("[%s] Repository deleted", p.Repository.FullName)
return newFeishuTextPayload(text), nil
}
return nil, nil
@@ -178,10 +159,7 @@ func (f *FeishuPayload) Repository(p *api.RepositoryPayload) (api.Payloader, err
func (f *FeishuPayload) Release(p *api.ReleasePayload) (api.Payloader, error) {
text, _ := getReleasePayloadInfo(p, noneLinkFormatter, true)
return &FeishuPayload{
Text: text,
Title: text,
}, nil
return newFeishuTextPayload(text), nil
}
// GetFeishuPayload converts a ding talk webhook into a FeishuPayload

View File

@@ -5,6 +5,8 @@
package admin
import (
"net/url"
"strconv"
"strings"
"code.gitea.io/gitea/models"
@@ -71,6 +73,8 @@ func UnadoptedRepos(ctx *context.Context) {
opts.Page = 1
}
ctx.Data["CurrentPage"] = opts.Page
doSearch := ctx.QueryBool("search")
ctx.Data["search"] = doSearch
@@ -79,6 +83,7 @@ func UnadoptedRepos(ctx *context.Context) {
if !doSearch {
pager := context.NewPagination(0, opts.PageSize, opts.Page, 5)
pager.SetDefaultParams(ctx)
pager.AddParam(ctx, "search", "search")
ctx.Data["Page"] = pager
ctx.HTML(200, tplUnadoptedRepos)
return
@@ -92,6 +97,7 @@ func UnadoptedRepos(ctx *context.Context) {
ctx.Data["Dirs"] = repoNames
pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
pager.SetDefaultParams(ctx)
pager.AddParam(ctx, "search", "search")
ctx.Data["Page"] = pager
ctx.HTML(200, tplUnadoptedRepos)
}
@@ -100,6 +106,9 @@ func UnadoptedRepos(ctx *context.Context) {
func AdoptOrDeleteRepository(ctx *context.Context) {
dir := ctx.Query("id")
action := ctx.Query("action")
page := ctx.QueryInt("page")
q := ctx.Query("q")
dirSplit := strings.SplitN(dir, "/", 2)
if len(dirSplit) != 2 {
ctx.Redirect(setting.AppSubURL + "/admin/repos")
@@ -141,5 +150,5 @@ func AdoptOrDeleteRepository(ctx *context.Context) {
}
ctx.Flash.Success(ctx.Tr("repo.delete_preexisting_success", dir))
}
ctx.Redirect(setting.AppSubURL + "/admin/repos/unadopted")
ctx.Redirect(setting.AppSubURL + "/admin/repos/unadopted?search=true&q=" + url.QueryEscape(q) + "&page=" + strconv.Itoa(page))
}

View File

@@ -17,19 +17,28 @@ import (
"code.gitea.io/gitea/routers/api/v1/utils"
)
func listUserOrgs(ctx *context.APIContext, u *models.User, all bool) {
if err := u.GetOrganizations(&models.SearchOrganizationsOptions{
ListOptions: utils.GetListOptions(ctx),
All: all,
}); err != nil {
ctx.Error(http.StatusInternalServerError, "GetOrganizations", err)
func listUserOrgs(ctx *context.APIContext, u *models.User) {
listOptions := utils.GetListOptions(ctx)
showPrivate := ctx.IsSigned && (ctx.User.IsAdmin || ctx.User.ID == u.ID)
orgs, err := models.GetOrgsByUserID(u.ID, showPrivate)
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetOrgsByUserID", err)
return
}
maxResults := len(orgs)
apiOrgs := make([]*api.Organization, len(u.Orgs))
for i := range u.Orgs {
apiOrgs[i] = convert.ToOrganization(u.Orgs[i])
orgs = utils.PaginateUserSlice(orgs, listOptions.Page, listOptions.PageSize)
apiOrgs := make([]*api.Organization, len(orgs))
for i := range orgs {
apiOrgs[i] = convert.ToOrganization(orgs[i])
}
ctx.SetLinkHeader(int(maxResults), listOptions.PageSize)
ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", maxResults))
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link")
ctx.JSON(http.StatusOK, &apiOrgs)
}
@@ -53,7 +62,7 @@ func ListMyOrgs(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/OrganizationList"
listUserOrgs(ctx, ctx.User, true)
listUserOrgs(ctx, ctx.User)
}
// ListUserOrgs list user's orgs
@@ -85,7 +94,7 @@ func ListUserOrgs(ctx *context.APIContext) {
if ctx.Written() {
return
}
listUserOrgs(ctx, u, ctx.User != nil && (ctx.User.IsAdmin || ctx.User.ID == u.ID))
listUserOrgs(ctx, u)
}
// GetAll return list of all public organizations

View File

@@ -244,7 +244,7 @@ type combinedCommitStatus struct {
// GetCombinedCommitStatusByRef returns the combined status for any given commit hash
func GetCombinedCommitStatusByRef(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/commits/{ref}/statuses repository repoGetCombinedStatusByRef
// swagger:operation GET /repos/{owner}/{repo}/commits/{ref}/status repository repoGetCombinedStatusByRef
// ---
// summary: Get a commit's combined status, by branch/tag/commit reference
// produces:
@@ -272,7 +272,7 @@ func GetCombinedCommitStatusByRef(ctx *context.APIContext) {
// required: false
// responses:
// "200":
// "$ref": "#/responses/Status"
// "$ref": "#/responses/CombinedStatus"
// "400":
// "$ref": "#/responses/error"
@@ -292,7 +292,7 @@ func GetCombinedCommitStatusByRef(ctx *context.APIContext) {
}
if len(statuses) == 0 {
ctx.Status(http.StatusOK)
ctx.JSON(http.StatusOK, &api.CombinedStatus{})
return
}

View File

@@ -309,3 +309,10 @@ type swaggerLanguageStatistics struct {
// in: body
Body map[string]int64 `json:"body"`
}
// CombinedStatus
// swagger:response CombinedStatus
type swaggerCombinedStatus struct {
// in: body
Body api.CombinedStatus `json:"body"`
}

View File

@@ -66,3 +66,22 @@ func GetListOptions(ctx *context.APIContext) models.ListOptions {
PageSize: convert.ToCorrectPageSize(ctx.QueryInt("limit")),
}
}
// PaginateUserSlice cut a slice of Users as per pagination options
// TODO: make it generic
func PaginateUserSlice(items []*models.User, page, pageSize int) []*models.User {
if page != 0 {
page--
}
if page*pageSize >= len(items) {
return items[len(items):]
}
items = items[page*pageSize:]
if len(items) > pageSize {
return items[:pageSize]
}
return items
}

View File

@@ -223,10 +223,11 @@ func NewMacaron() *macaron.Macaron {
},
))
m.Use(templates.HTMLRenderer())
m.Use(storageHandler(setting.Avatar.Storage, "avatars", storage.Avatars))
m.Use(storageHandler(setting.RepoAvatar.Storage, "repo-avatars", storage.RepoAvatars))
m.Use(templates.HTMLRenderer())
mailer.InitMailRender(templates.Mailer())
localeNames, err := options.Dir("locale")

View File

@@ -174,12 +174,12 @@ func SignInPost(ctx *context.Context, form auth.SignInForm) {
if err != nil {
if models.IsErrUserNotExist(err) {
ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tplSignIn, &form)
log.Info("Failed authentication attempt for %s from %s", form.UserName, ctx.RemoteAddr())
log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
} else if models.IsErrEmailAlreadyUsed(err) {
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSignIn, &form)
log.Info("Failed authentication attempt for %s from %s", form.UserName, ctx.RemoteAddr())
log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
} else if models.IsErrUserProhibitLogin(err) {
log.Info("Failed authentication attempt for %s from %s", form.UserName, ctx.RemoteAddr())
log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
ctx.HTML(200, "user/auth/prohibit_login")
} else if models.IsErrUserInactive(err) {
@@ -187,7 +187,7 @@ func SignInPost(ctx *context.Context, form auth.SignInForm) {
ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
ctx.HTML(200, TplActivate)
} else {
log.Info("Failed authentication attempt for %s from %s", form.UserName, ctx.RemoteAddr())
log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
ctx.HTML(200, "user/auth/prohibit_login")
}
@@ -570,8 +570,17 @@ func SignInOAuth(ctx *context.Context) {
return
}
err = oauth2.Auth(loginSource.Name, ctx.Req.Request, ctx.Resp)
if err != nil {
if err = oauth2.Auth(loginSource.Name, ctx.Req.Request, ctx.Resp); err != nil {
if strings.Contains(err.Error(), "no provider for ") {
if err = models.ResetOAuth2(); err != nil {
ctx.ServerError("SignIn", err)
return
}
if err = oauth2.Auth(loginSource.Name, ctx.Req.Request, ctx.Resp); err != nil {
ctx.ServerError("SignIn", err)
}
return
}
ctx.ServerError("SignIn", err)
}
// redirect is done in oauth2.Auth
@@ -1496,7 +1505,7 @@ func ResetPasswdPost(ctx *context.Context) {
}
u.HashPassword(passwd)
u.MustChangePassword = false
if err := models.UpdateUserCols(u, "must_change_password", "passwd", "rands", "salt"); err != nil {
if err := models.UpdateUserCols(u, "must_change_password", "passwd", "passwd_hash_algo", "rands", "salt"); err != nil {
ctx.ServerError("UpdateUser", err)
return
}
@@ -1572,7 +1581,7 @@ func MustChangePasswordPost(ctx *context.Context, cpt *captcha.Captcha, form aut
u.HashPassword(form.Password)
u.MustChangePassword = false
if err := models.UpdateUserCols(u, "must_change_password", "passwd", "salt"); err != nil {
if err := models.UpdateUserCols(u, "must_change_password", "passwd", "passwd_hash_algo", "salt"); err != nil {
ctx.ServerError("UpdateUser", err)
return
}

View File

@@ -68,7 +68,7 @@ func AccountPost(ctx *context.Context, form auth.ChangePasswordForm) {
return
}
ctx.User.HashPassword(form.Password)
if err := models.UpdateUserCols(ctx.User, "salt", "passwd"); err != nil {
if err := models.UpdateUserCols(ctx.User, "salt", "passwd_hash_algo", "passwd"); err != nil {
ctx.ServerError("UpdateUser", err)
return
}

View File

@@ -10,6 +10,7 @@ import (
"bytes"
"context"
"fmt"
"html"
"html/template"
"io"
"io/ioutil"
@@ -164,9 +165,9 @@ func getDiffLineSectionInfo(treePath, line string, lastLeftIdx, lastRightIdx int
// escape a line's content or return <br> needed for copy/paste purposes
func getLineContent(content string) string {
if len(content) > 0 {
return content
return html.EscapeString(content)
}
return "\n"
return "<br>"
}
// DiffSection represents a section of a DiffFile.
@@ -357,8 +358,6 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) tem
diffRecord := diffMatchPatch.DiffMain(highlight.Code(diffSection.FileName, diff1[1:]), highlight.Code(diffSection.FileName, diff2[1:]), true)
diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord)
diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord)
return diffToHTML(diffSection.FileName, diffRecord, diffLine.Type)
}

View File

@@ -122,7 +122,17 @@ func mailIssueCommentBatch(ctx *mailCommentContext, ids []int64, visited map[int
if err != nil {
return err
}
// TODO: Check issue visibility for each user
// Make sure all recipients can still see the issue
idx := 0
for _, r := range recipients {
if ctx.Issue.Repo.CheckUnitUser(r, models.UnitTypeIssues) {
recipients[idx] = r
idx++
}
}
recipients = recipients[:idx]
// TODO: Separate recipients by language for i18n mail templates
tos := make([]string, len(recipients))
for i := range recipients {

View File

@@ -149,6 +149,11 @@ func parseRemoteUpdateOutput(output string) []*mirrorSyncResult {
switch {
case strings.HasPrefix(lines[i], " * "): // New reference
if strings.HasPrefix(lines[i], " * [new tag]") {
refName = git.TagPrefix + refName
} else if strings.HasPrefix(lines[i], " * [new branch]") {
refName = git.BranchPrefix + refName
}
results = append(results, &mirrorSyncResult{
refName: refName,
oldCommitID: gitShortEmptySha,
@@ -434,6 +439,17 @@ func syncMirror(repoID string) {
// Create reference
if result.oldCommitID == gitShortEmptySha {
if tp == git.TagPrefix {
tp = "tag"
} else if tp == git.BranchPrefix {
tp = "branch"
}
commitID, err := gitRepo.GetRefCommitID(result.refName)
if err != nil {
log.Error("gitRepo.GetRefCommitID [repo_id: %s, ref_name: %s]: %v", m.RepoID, result.refName, err)
continue
}
notification.NotifySyncPushCommits(m.Repo.MustOwner(), m.Repo, result.refName, git.EmptySHA, commitID, repo_module.NewPushCommits())
notification.NotifySyncCreateRef(m.Repo.MustOwner(), m.Repo, tp, result.refName)
continue
}

View File

@@ -5,6 +5,7 @@
package mirror
import (
"context"
"path/filepath"
"testing"
@@ -47,7 +48,7 @@ func TestRelease_MirrorDelete(t *testing.T) {
})
assert.NoError(t, err)
mirror, err := repository.MigrateRepositoryGitData(user, user, mirrorRepo, opts)
mirror, err := repository.MigrateRepositoryGitData(context.Background(), user, mirrorRepo, opts)
assert.NoError(t, err)
gitRepo, err := git.OpenRepository(repoPath)

View File

@@ -411,7 +411,7 @@ func rawMerge(pr *models.PullRequest, doer *models.User, mergeStyle models.Merge
)
// Push back to upstream.
if err := git.NewCommand("push", "origin", baseBranch+":"+pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, &outbuf, &errbuf); err != nil {
if err := git.NewCommand("push", "origin", baseBranch+":refs/heads/"+pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, &outbuf, &errbuf); err != nil {
if strings.Contains(errbuf.String(), "non-fast-forward") {
return "", &git.ErrPushOutOfDate{
StdOut: outbuf.String(),

View File

@@ -167,16 +167,16 @@ func createCodeComment(doer *models.User, repo *models.Repository, issue *models
// Only fetch diff if comment is review comment
if len(patch) == 0 && reviewID != 0 {
if len(commitID) == 0 {
commitID, err = gitRepo.GetRefCommitID(pr.GetGitRefName())
if err != nil {
return nil, fmt.Errorf("GetRefCommitID[%s]: %v", pr.GetGitRefName(), err)
}
headCommitID, err := gitRepo.GetRefCommitID(pr.GetGitRefName())
if err != nil {
return nil, fmt.Errorf("GetRefCommitID[%s]: %v", pr.GetGitRefName(), err)
}
if len(commitID) == 0 {
commitID = headCommitID
}
patchBuf := new(bytes.Buffer)
if err := git.GetRepoRawDiffForFile(gitRepo, pr.MergeBase, commitID, git.RawDiffNormal, treePath, patchBuf); err != nil {
return nil, fmt.Errorf("GetRawDiffForLine[%s, %s, %s, %s]: %v", gitRepo.Path, pr.MergeBase, commitID, treePath, err)
if err := git.GetRepoRawDiffForFile(gitRepo, pr.MergeBase, headCommitID, git.RawDiffNormal, treePath, patchBuf); err != nil {
return nil, fmt.Errorf("GetRawDiffForLine[%s, %s, %s, %s]: %v", gitRepo.Path, pr.MergeBase, headCommitID, treePath, err)
}
patch = git.CutDiffAroundLine(patchBuf, int64((&models.Comment{Line: line}).UnsignedLine()), line < 0, setting.UI.CodeCommentLines)
}

View File

@@ -142,6 +142,10 @@ func DeleteReleaseByID(id int64, doer *models.User, delTag bool) error {
return fmt.Errorf("git tag -d: %v", err)
}
notification.NotifyPushCommits(
doer, repo, git.TagPrefix+rel.TagName, rel.Sha1, git.EmptySHA, repository.NewPushCommits())
notification.NotifyDeleteRef(doer, repo, "tag", git.TagPrefix+rel.TagName)
if err := models.DeleteReleaseByID(id); err != nil {
return fmt.Errorf("DeleteReleaseByID: %v", err)
}

View File

@@ -77,6 +77,8 @@ func InitWiki(repo *models.Repository) error {
return fmt.Errorf("InitRepository: %v", err)
} else if err = repo_module.CreateDelegateHooks(repo.WikiPath()); err != nil {
return fmt.Errorf("createDelegateHooks: %v", err)
} else if _, err = git.NewCommand("symbolic-ref", "HEAD", git.BranchPrefix+"master").RunInDir(repo.WikiPath()); err != nil {
return fmt.Errorf("unable to set default wiki branch to master: %v", err)
}
return nil
}

View File

@@ -41,6 +41,8 @@
{{$.CsrfTokenHtml}}
<input type="hidden" name="id" value="{{$dir}}">
<input type="hidden" name="action" value="adopt">
<input type="hidden" name="q" value="{{$.Keyword}}">
<input type="hidden" name="page" value="{{$.CurrentPage}}">
<div class="actions">
<div class="ui red basic inverted cancel button">
<i class="remove icon"></i>
@@ -66,6 +68,8 @@
{{$.CsrfTokenHtml}}
<input type="hidden" name="id" value="{{$dir}}">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="q" value="{{$.Keyword}}">
<input type="hidden" name="page" value="{{$.CurrentPage}}">
<div class="actions">
<div class="ui red basic inverted cancel button">
<i class="remove icon"></i>

View File

@@ -166,74 +166,78 @@
<td class="lines-num"></td>
<td class="lines-type-marker"></td>
<td class="add-comment-left">
{{if and $resolved (eq $line.GetCommentSide "previous")}}
<div class="ui top attached header">
<span class="ui grey text left"><b>{{$resolveDoer.Name}}</b> {{$.i18n.Tr "repo.issues.review.resolved_by"}}</span>
<button id="show-outdated-{{(index $line.Comments 0).ID}}" data-comment="{{(index $line.Comments 0).ID}}" class="ui compact right labeled button show-outdated">
{{svg "octicon-unfold"}}
{{$.i18n.Tr "repo.issues.review.show_resolved"}}
</button>
<button id="hide-outdated-{{(index $line.Comments 0).ID}}" data-comment="{{(index $line.Comments 0).ID}}" class="hide ui compact right labeled button hide-outdated">
{{svg "octicon-fold"}}
{{$.i18n.Tr "repo.issues.review.hide_resolved"}}
</button>
</div>
{{end}}
{{if eq $line.GetCommentSide "previous"}}
<div id="code-comments-{{(index $line.Comments 0).ID}}" class="field comment-code-cloud {{if $resolved}}hide{{end}}">
<div class="comment-list">
<ui class="ui comments">
{{ template "repo/diff/comments" dict "root" $ "comments" $line.Comments}}
</ui>
</div>
{{template "repo/diff/comment_form_datahandler" dict "reply" (index $line.Comments 0).ReviewID "hidden" true "root" $ "comment" (index $line.Comments 0)}}
{{if and $.CanMarkConversation $isNotPending}}
<button class="ui icon tiny button resolve-conversation" data-action="{{if not $resolved}}Resolve{{else}}UnResolve{{end}}" data-comment-id="{{(index $line.Comments 0).ID}}" data-update-url="{{$.RepoLink}}/issues/resolve_conversation" >
{{if $resolved}}
{{$.i18n.Tr "repo.issues.review.un_resolve_conversation"}}
{{else}}
{{$.i18n.Tr "repo.issues.review.resolve_conversation"}}
{{end}}
<div class="conversation-holder">
{{if and $resolved (eq $line.GetCommentSide "previous")}}
<div class="ui top attached header">
<span class="ui grey text left"><b>{{$resolveDoer.Name}}</b> {{$.i18n.Tr "repo.issues.review.resolved_by"}}</span>
<button id="show-outdated-{{(index $line.Comments 0).ID}}" data-comment="{{(index $line.Comments 0).ID}}" class="ui compact right labeled button show-outdated">
{{svg "octicon-unfold"}}
{{$.i18n.Tr "repo.issues.review.show_resolved"}}
</button>
{{end}}
</div>
{{end}}
<button id="hide-outdated-{{(index $line.Comments 0).ID}}" data-comment="{{(index $line.Comments 0).ID}}" class="hide ui compact right labeled button hide-outdated">
{{svg "octicon-fold"}}
{{$.i18n.Tr "repo.issues.review.hide_resolved"}}
</button>
</div>
{{end}}
{{if eq $line.GetCommentSide "previous"}}
<div id="code-comments-{{(index $line.Comments 0).ID}}" class="field comment-code-cloud {{if $resolved}}hide{{end}}">
<div class="comment-list">
<ui class="ui comments">
{{ template "repo/diff/comments" dict "root" $ "comments" $line.Comments}}
</ui>
</div>
{{template "repo/diff/comment_form_datahandler" dict "reply" (index $line.Comments 0).ReviewID "hidden" true "root" $ "comment" (index $line.Comments 0)}}
{{if and $.CanMarkConversation $isNotPending}}
<button class="ui icon tiny button resolve-conversation" data-action="{{if not $resolved}}Resolve{{else}}UnResolve{{end}}" data-comment-id="{{(index $line.Comments 0).ID}}" data-update-url="{{$.RepoLink}}/issues/resolve_conversation" >
{{if $resolved}}
{{$.i18n.Tr "repo.issues.review.un_resolve_conversation"}}
{{else}}
{{$.i18n.Tr "repo.issues.review.resolve_conversation"}}
{{end}}
</button>
{{end}}
</div>
{{end}}
</div>
</td>
<td class="lines-num"></td>
<td class="lines-type-marker"></td>
<td class="add-comment-right">
{{if and $resolved (eq $line.GetCommentSide "proposed")}}
<div class="ui top attached header">
<span class="ui grey text left"><b>{{$resolveDoer.Name}}</b> {{$.i18n.Tr "repo.issues.review.resolved_by"}}</span>
<button id="show-outdated-{{(index $line.Comments 0).ID}}" data-comment="{{(index $line.Comments 0).ID}}" class="ui compact right labeled button show-outdated">
{{svg "octicon-unfold"}}
{{$.i18n.Tr "repo.issues.review.show_resolved"}}
</button>
<button id="hide-outdated-{{(index $line.Comments 0).ID}}" data-comment="{{(index $line.Comments 0).ID}}" class="hide ui compact right labeled button hide-outdated">
{{svg "octicon-fold"}}
{{$.i18n.Tr "repo.issues.review.hide_resolved"}}
</button>
</div>
{{end}}
{{if eq $line.GetCommentSide "proposed"}}
<div id="code-comments-{{(index $line.Comments 0).ID}}" class="field comment-code-cloud {{if $resolved}}hide{{end}}">
<div class="comment-list">
<ui class="ui comments">
{{ template "repo/diff/comments" dict "root" $ "comments" $line.Comments}}
</ui>
</div>
{{template "repo/diff/comment_form_datahandler" dict "reply" (index $line.Comments 0).ReviewID "hidden" true "root" $ "comment" (index $line.Comments 0)}}
{{if and $.CanMarkConversation $isNotPending}}
<button class="ui icon tiny button resolve-conversation" data-action="{{if not $resolved}}Resolve{{else}}UnResolve{{end}}" data-comment-id="{{(index $line.Comments 0).ID}}" data-update-url="{{$.RepoLink}}/issues/resolve_conversation" >
{{if $resolved}}
{{$.i18n.Tr "repo.issues.review.un_resolve_conversation"}}
{{else}}
{{$.i18n.Tr "repo.issues.review.resolve_conversation"}}
{{end}}
<div class="conversation-holder">
{{if and $resolved (eq $line.GetCommentSide "proposed")}}
<div class="ui top attached header">
<span class="ui grey text left"><b>{{$resolveDoer.Name}}</b> {{$.i18n.Tr "repo.issues.review.resolved_by"}}</span>
<button id="show-outdated-{{(index $line.Comments 0).ID}}" data-comment="{{(index $line.Comments 0).ID}}" class="ui compact right labeled button show-outdated">
{{svg "octicon-unfold"}}
{{$.i18n.Tr "repo.issues.review.show_resolved"}}
</button>
{{end}}
</div>
{{end}}
<button id="hide-outdated-{{(index $line.Comments 0).ID}}" data-comment="{{(index $line.Comments 0).ID}}" class="hide ui compact right labeled button hide-outdated">
{{svg "octicon-fold"}}
{{$.i18n.Tr "repo.issues.review.hide_resolved"}}
</button>
</div>
{{end}}
{{if eq $line.GetCommentSide "proposed"}}
<div id="code-comments-{{(index $line.Comments 0).ID}}" class="field comment-code-cloud {{if $resolved}}hide{{end}}">
<div class="comment-list">
<ui class="ui comments">
{{ template "repo/diff/comments" dict "root" $ "comments" $line.Comments}}
</ui>
</div>
{{template "repo/diff/comment_form_datahandler" dict "reply" (index $line.Comments 0).ReviewID "hidden" true "root" $ "comment" (index $line.Comments 0)}}
{{if and $.CanMarkConversation $isNotPending}}
<button class="ui icon tiny button resolve-conversation" data-action="{{if not $resolved}}Resolve{{else}}UnResolve{{end}}" data-comment-id="{{(index $line.Comments 0).ID}}" data-update-url="{{$.RepoLink}}/issues/resolve_conversation" >
{{if $resolved}}
{{$.i18n.Tr "repo.issues.review.un_resolve_conversation"}}
{{else}}
{{$.i18n.Tr "repo.issues.review.resolve_conversation"}}
{{end}}
</button>
{{end}}
</div>
{{end}}
</div>
</td>
</tr>
{{end}}

View File

@@ -39,35 +39,37 @@
<tr>
<td colspan="2" class="lines-num"></td>
<td class="add-comment-left add-comment-right" colspan="2">
{{if $resolved}}
<div class = "ui attached header">
<span class="ui grey text left"><b>{{$resolveDoer.Name}}</b> {{$.root.i18n.Tr "repo.issues.review.resolved_by"}}</span>
<button id="show-outdated-{{(index $line.Comments 0).ID}}" data-comment="{{(index $line.Comments 0).ID}}" class="ui compact right labeled button show-outdated">
{{svg "octicon-unfold"}}
{{$.root.i18n.Tr "repo.issues.review.show_resolved"}}
</button>
<button id="hide-outdated-{{(index $line.Comments 0).ID}}" data-comment="{{(index $line.Comments 0).ID}}" class="hide ui compact right labeled button hide-outdated">
{{svg "octicon-fold"}}
{{$.root.i18n.Tr "repo.issues.review.hide_resolved"}}
</button>
</div>
{{end}}
<div id="code-comments-{{(index $line.Comments 0).ID}}" class="field comment-code-cloud {{if $resolved}}hide{{end}}">
<div class="comment-list">
<ui class="ui comments">
{{ template "repo/diff/comments" dict "root" $.root "comments" $line.Comments}}
</ui>
</div>
{{template "repo/diff/comment_form_datahandler" dict "hidden" true "reply" (index $line.Comments 0).ReviewID "root" $.root "comment" (index $line.Comments 0)}}
{{if and $.root.CanMarkConversation $isNotPending}}
<button class="ui icon tiny button resolve-conversation" data-action="{{if not $resolved}}Resolve{{else}}UnResolve{{end}}" data-comment-id="{{(index $line.Comments 0).ID}}" data-update-url="{{$.root.RepoLink}}/issues/resolve_conversation" >
{{if $resolved}}
{{$.root.i18n.Tr "repo.issues.review.un_resolve_conversation"}}
{{else}}
{{$.root.i18n.Tr "repo.issues.review.resolve_conversation"}}
{{end}}
</button>
<div class="conversation-holder">
{{if $resolved}}
<div class = "ui attached header">
<span class="ui grey text left"><b>{{$resolveDoer.Name}}</b> {{$.root.i18n.Tr "repo.issues.review.resolved_by"}}</span>
<button id="show-outdated-{{(index $line.Comments 0).ID}}" data-comment="{{(index $line.Comments 0).ID}}" class="ui compact right labeled button show-outdated">
{{svg "octicon-unfold"}}
{{$.root.i18n.Tr "repo.issues.review.show_resolved"}}
</button>
<button id="hide-outdated-{{(index $line.Comments 0).ID}}" data-comment="{{(index $line.Comments 0).ID}}" class="hide ui compact right labeled button hide-outdated">
{{svg "octicon-fold"}}
{{$.root.i18n.Tr "repo.issues.review.hide_resolved"}}
</button>
</div>
{{end}}
<div id="code-comments-{{(index $line.Comments 0).ID}}" class="field comment-code-cloud {{if $resolved}}hide{{end}}">
<div class="comment-list">
<ui class="ui comments">
{{ template "repo/diff/comments" dict "root" $.root "comments" $line.Comments}}
</ui>
</div>
{{template "repo/diff/comment_form_datahandler" dict "hidden" true "reply" (index $line.Comments 0).ReviewID "root" $.root "comment" (index $line.Comments 0)}}
{{if and $.root.CanMarkConversation $isNotPending}}
<button class="ui icon tiny button resolve-conversation" data-action="{{if not $resolved}}Resolve{{else}}UnResolve{{end}}" data-comment-id="{{(index $line.Comments 0).ID}}" data-update-url="{{$.root.RepoLink}}/issues/resolve_conversation" >
{{if $resolved}}
{{$.root.i18n.Tr "repo.issues.review.un_resolve_conversation"}}
{{else}}
{{$.root.i18n.Tr "repo.issues.review.resolve_conversation"}}
{{end}}
</button>
{{end}}
</div>
</div>
</td>
</tr>

View File

@@ -130,7 +130,7 @@
</div>
<div class="extra content">
{{ range .Labels }}
<a class="ui label has-emoji" href="{{$.RepoLink}}/issues?labels={{.ID}}" style="color: {{.ForegroundColor}}; background-color: {{.Color}}; margin-bottom: 3px;" title="{{.Description}}">{{.Name}}</a>
<a class="ui label" href="{{$.RepoLink}}/issues?labels={{.ID}}" style="color: {{.ForegroundColor}}; background-color: {{.Color}}; margin-bottom: 3px;" title="{{.Description | RenderEmojiPlain}}">{{.Name | RenderEmoji}}</a>
{{ end }}
</div>
</div>

View File

@@ -2829,7 +2829,7 @@
}
}
},
"/repos/{owner}/{repo}/commits/{ref}/statuses": {
"/repos/{owner}/{repo}/commits/{ref}/status": {
"get": {
"produces": [
"application/json"
@@ -2870,7 +2870,88 @@
],
"responses": {
"200": {
"$ref": "#/responses/Status"
"$ref": "#/responses/CombinedStatus"
},
"400": {
"$ref": "#/responses/error"
}
}
}
},
"/repos/{owner}/{repo}/commits/{ref}/statuses": {
"get": {
"produces": [
"application/json"
],
"tags": [
"repository"
],
"summary": "Get a commit's statuses, by branch/tag/commit reference",
"operationId": "repoListStatusesByRef",
"parameters": [
{
"type": "string",
"description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repo",
"name": "repo",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of branch/tag/commit",
"name": "ref",
"in": "path",
"required": true
},
{
"enum": [
"oldest",
"recentupdate",
"leastupdate",
"leastindex",
"highestindex"
],
"type": "string",
"description": "type of sort",
"name": "sort",
"in": "query"
},
{
"enum": [
"pending",
"success",
"error",
"failure",
"warning"
],
"type": "string",
"description": "type of state",
"name": "state",
"in": "query"
},
{
"type": "integer",
"description": "page number of results to return (1-based)",
"name": "page",
"in": "query"
},
{
"type": "integer",
"description": "page size of results",
"name": "limit",
"in": "query"
}
],
"responses": {
"200": {
"$ref": "#/responses/StatusList"
},
"400": {
"$ref": "#/responses/error"
@@ -11240,6 +11321,43 @@
},
"x-go-package": "code.gitea.io/gitea/modules/structs"
},
"CombinedStatus": {
"description": "CombinedStatus holds the combined state of several statuses for a single commit",
"type": "object",
"properties": {
"commit_url": {
"type": "string",
"x-go-name": "CommitURL"
},
"repository": {
"$ref": "#/definitions/Repository"
},
"sha": {
"type": "string",
"x-go-name": "SHA"
},
"state": {
"$ref": "#/definitions/StatusState"
},
"statuses": {
"type": "array",
"items": {
"$ref": "#/definitions/Status"
},
"x-go-name": "Statuses"
},
"total_count": {
"type": "integer",
"format": "int64",
"x-go-name": "TotalCount"
},
"url": {
"type": "string",
"x-go-name": "URL"
}
},
"x-go-package": "code.gitea.io/gitea/modules/structs"
},
"Comment": {
"description": "Comment represents a comment on a commit or issue",
"type": "object",
@@ -15532,6 +15650,12 @@
}
}
},
"CombinedStatus": {
"description": "CombinedStatus",
"schema": {
"$ref": "#/definitions/CombinedStatus"
}
},
"Comment": {
"description": "Comment",
"schema": {

View File

@@ -122,22 +122,79 @@ func escapeUrlComponent(val string) string {
return w.String()
}
func sanitizedUrl(val string) (string, error) {
// Query represents a query
type Query struct {
Key string
Value string
}
func parseQuery(query string) (values []Query, err error) {
for query != "" {
key := query
if i := strings.IndexAny(key, "&;"); i >= 0 {
key, query = key[:i], key[i+1:]
} else {
query = ""
}
if key == "" {
continue
}
value := ""
if i := strings.Index(key, "="); i >= 0 {
key, value = key[:i], key[i+1:]
}
key, err1 := url.QueryUnescape(key)
if err1 != nil {
if err == nil {
err = err1
}
continue
}
value, err1 = url.QueryUnescape(value)
if err1 != nil {
if err == nil {
err = err1
}
continue
}
values = append(values, Query{
Key: key,
Value: value,
})
}
return values, err
}
func encodeQueries(queries []Query) string {
var b strings.Builder
for i, query := range queries {
b.WriteString(url.QueryEscape(query.Key))
b.WriteString("=")
b.WriteString(url.QueryEscape(query.Value))
if i < len(queries)-1 {
b.WriteString("&")
}
}
return b.String()
}
func sanitizedURL(val string) (string, error) {
u, err := url.Parse(val)
if err != nil {
return "", err
}
// sanitize the url query params
sanitizedQueryValues := make(url.Values, 0)
queryValues := u.Query()
for k, vals := range queryValues {
sk := html.EscapeString(k)
for _, v := range vals {
sv := escapeUrlComponent(v)
sanitizedQueryValues.Set(sk, sv)
}
// we use parseQuery but not u.Query to keep the order not change because
// url.Values is a map which has a random order.
queryValues, err := parseQuery(u.RawQuery)
if err != nil {
return "", err
}
u.RawQuery = sanitizedQueryValues.Encode()
// sanitize the url query params
for i, query := range queryValues {
queryValues[i].Key = html.EscapeString(query.Key)
}
u.RawQuery = encodeQueries(queryValues)
// u.String() will also sanitize host/scheme/user/pass
return u.String(), nil
}
@@ -158,7 +215,7 @@ func (p *Policy) writeLinkableBuf(buff *bytes.Buffer, token *html.Token) {
tokenBuff.WriteString(html.EscapeString(attr.Val))
continue
}
u, err := sanitizedUrl(u)
u, err := sanitizedURL(u)
if err == nil {
tokenBuff.WriteString(u)
} else {
@@ -390,10 +447,10 @@ func (p *Policy) sanitizeAttrs(
hasStylePolicies = true
}
// no specific element policy found, look for a pattern match
if !hasStylePolicies{
for k, v := range p.elsMatchingAndStyles{
if !hasStylePolicies {
for k, v := range p.elsMatchingAndStyles {
if k.MatchString(elementName) {
if len(v) > 0{
if len(v) > 0 {
hasStylePolicies = true
break
}
@@ -669,14 +726,14 @@ func (p *Policy) sanitizeAttrs(
func (p *Policy) sanitizeStyles(attr html.Attribute, elementName string) html.Attribute {
sps := p.elsAndStyles[elementName]
if len(sps) == 0{
if len(sps) == 0 {
sps = map[string]stylePolicy{}
// check for any matching elements, if we don't already have a policy found
// if multiple matches are found they will be overwritten, it's best
// to not have overlapping matchers
for regex, policies :=range p.elsMatchingAndStyles{
if regex.MatchString(elementName){
for k, v := range policies{
for regex, policies := range p.elsMatchingAndStyles {
if regex.MatchString(elementName) {
for k, v := range policies {
sps[k] = v
}
}
@@ -874,7 +931,7 @@ func removeUnicode(value string) string {
return substitutedValue
}
func (p *Policy) matchRegex(elementName string ) (map[string]attrPolicy, bool) {
func (p *Policy) matchRegex(elementName string) (map[string]attrPolicy, bool) {
aps := make(map[string]attrPolicy, 0)
matched := false
for regex, attrs := range p.elsMatchingAndAttrs {

View File

@@ -363,6 +363,10 @@ func AcceptTOS(tosURL string) bool { return true }
// Also see Error's Instance field for when a CA requires already registered accounts to agree
// to an updated Terms of Service.
func (c *Client) Register(ctx context.Context, acct *Account, prompt func(tosURL string) bool) (*Account, error) {
if c.Key == nil {
return nil, errors.New("acme: client.Key must be set to Register")
}
dir, err := c.Discover(ctx)
if err != nil {
return nil, err

View File

@@ -7,17 +7,31 @@ package acme
import (
"crypto"
"crypto/ecdsa"
"crypto/hmac"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/sha512"
_ "crypto/sha512" // need for EC keys
"encoding/asn1"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"hash"
"math/big"
)
// MACAlgorithm represents a JWS MAC signature algorithm.
// See https://tools.ietf.org/html/rfc7518#section-3.1 for more details.
type MACAlgorithm string
const (
MACAlgorithmHS256 = MACAlgorithm("HS256")
MACAlgorithmHS384 = MACAlgorithm("HS384")
MACAlgorithmHS512 = MACAlgorithm("HS512")
)
// keyID is the account identity provided by a CA during registration.
type keyID string
@@ -31,6 +45,14 @@ const noKeyID = keyID("")
// See https://tools.ietf.org/html/rfc8555#section-6.3 for more details.
const noPayload = ""
// jsonWebSignature can be easily serialized into a JWS following
// https://tools.ietf.org/html/rfc7515#section-3.2.
type jsonWebSignature struct {
Protected string `json:"protected"`
Payload string `json:"payload"`
Sig string `json:"signature"`
}
// jwsEncodeJSON signs claimset using provided key and a nonce.
// The result is serialized in JSON format containing either kid or jwk
// fields based on the provided keyID value.
@@ -71,12 +93,7 @@ func jwsEncodeJSON(claimset interface{}, key crypto.Signer, kid keyID, nonce, ur
if err != nil {
return nil, err
}
enc := struct {
Protected string `json:"protected"`
Payload string `json:"payload"`
Sig string `json:"signature"`
}{
enc := jsonWebSignature{
Protected: phead,
Payload: payload,
Sig: base64.RawURLEncoding.EncodeToString(sig),
@@ -84,6 +101,32 @@ func jwsEncodeJSON(claimset interface{}, key crypto.Signer, kid keyID, nonce, ur
return json.Marshal(&enc)
}
// jwsWithMAC creates and signs a JWS using the given key and algorithm.
// "rawProtected" and "rawPayload" should not be base64-URL-encoded.
func jwsWithMAC(key []byte, alg MACAlgorithm, rawProtected, rawPayload []byte) (*jsonWebSignature, error) {
if len(key) == 0 {
return nil, errors.New("acme: cannot sign JWS with an empty MAC key")
}
protected := base64.RawURLEncoding.EncodeToString(rawProtected)
payload := base64.RawURLEncoding.EncodeToString(rawPayload)
// Only HMACs are currently supported.
hmac, err := newHMAC(key, alg)
if err != nil {
return nil, err
}
if _, err := hmac.Write([]byte(protected + "." + payload)); err != nil {
return nil, err
}
mac := hmac.Sum(nil)
return &jsonWebSignature{
Protected: protected,
Payload: payload,
Sig: base64.RawURLEncoding.EncodeToString(mac),
}, nil
}
// jwkEncode encodes public part of an RSA or ECDSA key into a JWK.
// The result is also suitable for creating a JWK thumbprint.
// https://tools.ietf.org/html/rfc7517
@@ -175,6 +218,20 @@ func jwsHasher(pub crypto.PublicKey) (string, crypto.Hash) {
return "", 0
}
// newHMAC returns an appropriate HMAC for the given MACAlgorithm.
func newHMAC(key []byte, alg MACAlgorithm) (hash.Hash, error) {
switch alg {
case MACAlgorithmHS256:
return hmac.New(sha256.New, key), nil
case MACAlgorithmHS384:
return hmac.New(sha512.New384, key), nil
case MACAlgorithmHS512:
return hmac.New(sha512.New, key), nil
default:
return nil, fmt.Errorf("acme: unsupported MAC algorithm: %v", alg)
}
}
// JWKThumbprint creates a JWK thumbprint out of pub
// as specified in https://tools.ietf.org/html/rfc7638.
func JWKThumbprint(pub crypto.PublicKey) (string, error) {

View File

@@ -5,6 +5,7 @@
package acme
import (
"bytes"
"context"
"crypto"
"encoding/base64"
@@ -37,22 +38,32 @@ func (c *Client) DeactivateReg(ctx context.Context) error {
return nil
}
// registerRFC is quivalent to c.Register but for CAs implementing RFC 8555.
// registerRFC is equivalent to c.Register but for CAs implementing RFC 8555.
// It expects c.Discover to have already been called.
// TODO: Implement externalAccountBinding.
func (c *Client) registerRFC(ctx context.Context, acct *Account, prompt func(tosURL string) bool) (*Account, error) {
c.cacheMu.Lock() // guard c.kid access
defer c.cacheMu.Unlock()
req := struct {
TermsAgreed bool `json:"termsOfServiceAgreed,omitempty"`
Contact []string `json:"contact,omitempty"`
TermsAgreed bool `json:"termsOfServiceAgreed,omitempty"`
Contact []string `json:"contact,omitempty"`
ExternalAccountBinding *jsonWebSignature `json:"externalAccountBinding,omitempty"`
}{
Contact: acct.Contact,
}
if c.dir.Terms != "" {
req.TermsAgreed = prompt(c.dir.Terms)
}
// set 'externalAccountBinding' field if requested
if acct.ExternalAccountBinding != nil {
eabJWS, err := c.encodeExternalAccountBinding(acct.ExternalAccountBinding)
if err != nil {
return nil, fmt.Errorf("acme: failed to encode external account binding: %v", err)
}
req.ExternalAccountBinding = eabJWS
}
res, err := c.post(ctx, c.Key, c.dir.RegURL, req, wantStatus(
http.StatusOK, // account with this key already registered
http.StatusCreated, // new account created
@@ -75,7 +86,19 @@ func (c *Client) registerRFC(ctx context.Context, acct *Account, prompt func(tos
return a, nil
}
// updateGegRFC is equivalent to c.UpdateReg but for CAs implementing RFC 8555.
// encodeExternalAccountBinding will encode an external account binding stanza
// as described in https://tools.ietf.org/html/rfc8555#section-7.3.4.
func (c *Client) encodeExternalAccountBinding(eab *ExternalAccountBinding) (*jsonWebSignature, error) {
jwk, err := jwkEncode(c.Key.Public())
if err != nil {
return nil, err
}
var rProtected bytes.Buffer
fmt.Fprintf(&rProtected, `{"alg":%q,"kid":%q,"url":%q}`, eab.Algorithm, eab.KID, c.dir.RegURL)
return jwsWithMAC(eab.Key, eab.Algorithm, rProtected.Bytes(), []byte(jwk))
}
// updateRegRFC is equivalent to c.UpdateReg but for CAs implementing RFC 8555.
// It expects c.Discover to have already been called.
func (c *Client) updateRegRFC(ctx context.Context, a *Account) (*Account, error) {
url := string(c.accountKID(ctx))

View File

@@ -199,6 +199,31 @@ type Account struct {
//
// It is non-RFC 8555 compliant and is obsoleted by OrdersURL.
Certificates string
// ExternalAccountBinding represents an arbitrary binding to an account of
// the CA which the ACME server is tied to.
// See https://tools.ietf.org/html/rfc8555#section-7.3.4 for more details.
ExternalAccountBinding *ExternalAccountBinding
}
// ExternalAccountBinding contains the data needed to form a request with
// an external account binding.
// See https://tools.ietf.org/html/rfc8555#section-7.3.4 for more details.
type ExternalAccountBinding struct {
// KID is the Key ID of the symmetric MAC key that the CA provides to
// identify an external account from ACME.
KID string
// Key is the bytes of the symmetric key that the CA provides to identify
// the account. Key must correspond to the KID.
Key []byte
// Algorithm used to sign the JWS.
Algorithm MACAlgorithm
}
func (e *ExternalAccountBinding) String() string {
return fmt.Sprintf("&{KID: %q, Key: redacted, Algorithm: %v}", e.KID, e.Algorithm)
}
// Directory is ACME server discovery data.

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build amd64,!gccgo,!appengine
// +build amd64,gc,!purego
package argon2

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build amd64,!gccgo,!appengine
// +build amd64,gc,!purego
#include "textflag.h"

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !amd64 appengine gccgo
// +build !amd64 purego !gc
package argon2

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.7,amd64,!gccgo,!appengine
// +build go1.7,amd64,gc,!purego
package blake2b

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.7,amd64,!gccgo,!appengine
// +build go1.7,amd64,gc,!purego
#include "textflag.h"

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.7,amd64,!gccgo,!appengine
// +build !go1.7,amd64,gc,!purego
package blake2b

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build amd64,!gccgo,!appengine
// +build amd64,gc,!purego
#include "textflag.h"

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !amd64 appengine gccgo
// +build !amd64 purego !gc
package blake2b

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.11,!gccgo,!purego
// +build go1.11,gc,!purego
package chacha20

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.11,!gccgo,!purego
// +build go1.11,gc,!purego
#include "textflag.h"

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !arm64,!s390x,!ppc64le arm64,!go1.11 gccgo purego
// +build !arm64,!s390x,!ppc64le arm64,!go1.11 !gc purego
package chacha20

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo,!purego
// +build gc,!purego
package chacha20

View File

@@ -19,7 +19,7 @@
// The differences in this and the original implementation are
// due to the calling conventions and initialization of constants.
// +build !gccgo,!purego
// +build gc,!purego
#include "textflag.h"

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo,!purego
// +build gc,!purego
package chacha20

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo,!purego
// +build gc,!purego
#include "go_asm.h"
#include "textflag.h"

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build amd64,!gccgo,!appengine,!purego
// +build amd64,gc,!purego
package curve25519

View File

@@ -5,7 +5,7 @@
// This code was translated into a form compatible with 6a from the public
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
// +build amd64,!gccgo,!appengine,!purego
// +build amd64,gc,!purego
#define REDMASK51 0x0007FFFFFFFFFFFF

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !amd64 gccgo appengine purego
// +build !amd64 !gc purego
package curve25519

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !appengine
// +build !purego
// Package subtle implements functions that are often useful in cryptographic
// code but require careful thought to use correctly.

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build appengine
// +build purego
// Package subtle implements functions that are often useful in cryptographic
// code but require careful thought to use correctly.

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !amd64,!ppc64le,!s390x gccgo purego
// +build !amd64,!ppc64le,!s390x !gc purego
package poly1305

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo,!purego
// +build gc,!purego
package poly1305

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo,!purego
// +build gc,!purego
#include "textflag.h"

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo,!purego
// +build gc,!purego
package poly1305

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo,!purego
// +build gc,!purego
#include "textflag.h"

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo,!purego
// +build gc,!purego
package poly1305

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo,!purego
// +build gc,!purego
#include "textflag.h"

View File

@@ -471,7 +471,7 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe
}
if len(answers) != len(prompts) {
return authFailure, nil, errors.New("ssh: not enough answers from keyboard-interactive callback")
return authFailure, nil, fmt.Errorf("ssh: incorrect number of answers from keyboard-interactive callback %d (expected %d)", len(answers), len(prompts))
}
responseLength := 1 + 4
for _, a := range answers {

View File

@@ -557,8 +557,6 @@ type dhGEXSHA struct {
hashFunc crypto.Hash
}
const numMRTests = 64
const (
dhGroupExchangeMinimumBits = 2048
dhGroupExchangePreferredBits = 2048
@@ -602,15 +600,8 @@ func (gex dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshake
gex.p = kexDHGexGroup.P
gex.g = kexDHGexGroup.G
// Check if p is safe by verifing that p and (p-1)/2 are primes
one := big.NewInt(1)
var pHalf = &big.Int{}
pHalf.Rsh(gex.p, 1)
if !gex.p.ProbablyPrime(numMRTests) || !pHalf.ProbablyPrime(numMRTests) {
return nil, fmt.Errorf("ssh: server provided gex p is not safe")
}
// Check if g is safe by verifing that g > 1 and g < p - 1
one := big.NewInt(1)
var pMinusOne = &big.Int{}
pMinusOne.Sub(gex.p, one)
if gex.g.Cmp(one) != 1 && gex.g.Cmp(pMinusOne) != -1 {
@@ -618,6 +609,8 @@ func (gex dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshake
}
// Send GexInit
var pHalf = &big.Int{}
pHalf.Rsh(gex.p, 1)
x, err := rand.Int(randSource, pHalf)
if err != nil {
return nil, err

View File

@@ -572,6 +572,10 @@ userAuthLoop:
perms = candidate.perms
}
case "gssapi-with-mic":
if config.GSSAPIWithMICConfig == nil {
authErr = errors.New("ssh: gssapi-with-mic auth not configured")
break
}
gssapiConfig := config.GSSAPIWithMICConfig
userAuthRequestGSSAPI, err := parseGSSAPIPayload(userAuthReq.Payload)
if err != nil {

5
vendor/modules.txt vendored
View File

@@ -566,7 +566,7 @@ github.com/mgechev/revive/rule
# github.com/mholt/archiver/v3 v3.3.0
## explicit
github.com/mholt/archiver/v3
# github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912
# github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912 => github.com/lunny/bluemonday v1.0.5-0.20201227154428-ca34796141e8
## explicit
github.com/microcosm-cc/bluemonday
# github.com/minio/md5-simd v1.1.0
@@ -778,7 +778,7 @@ go.mongodb.org/mongo-driver/bson/bsonrw
go.mongodb.org/mongo-driver/bson/bsontype
go.mongodb.org/mongo-driver/bson/primitive
go.mongodb.org/mongo-driver/x/bsonx/bsoncore
# golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
# golang.org/x/crypto v0.0.0-20201217014255-9d1352758620
## explicit
golang.org/x/crypto/acme
golang.org/x/crypto/acme/autocert
@@ -979,3 +979,4 @@ xorm.io/xorm/names
xorm.io/xorm/schemas
xorm.io/xorm/tags
# github.com/hashicorp/go-version => github.com/6543/go-version v1.2.4
# github.com/microcosm-cc/bluemonday => github.com/lunny/bluemonday v1.0.5-0.20201227154428-ca34796141e8

View File

@@ -25,6 +25,7 @@ import ActivityTopAuthors from './components/ActivityTopAuthors.vue';
import {initNotificationsTable, initNotificationCount} from './features/notification.js';
import {createCodeEditor} from './features/codeeditor.js';
import {svg, svgs} from './svg.js';
import {isMobile} from './utils.js';
const {AppSubUrl, StaticUrlPrefix, csrf} = window.config;
@@ -385,8 +386,14 @@ function initCommentForm() {
if ($('.comment.form').length === 0) {
return;
}
autoSimpleMDE = setCommentSimpleMDE($('.comment.form textarea:not(.review-textarea)'));
// Don't use simpleMDE on mobile due to multiple bug reports which go unfixed
// Other sections rely on it being initialized so just set it back to text area here
if (isMobile()) {
autoSimpleMDE.toTextArea();
}
initBranchSelector();
initCommentPreviewTab($('.comment.form'));
initImagePaste($('.comment.form textarea'));
@@ -862,25 +869,23 @@ async function initRepository() {
const target = $(this).data('target');
const quote = $(`#comment-${target}`).text().replace(/\n/g, '\n> ');
const content = `> ${quote}\n\n`;
let $content;
let $simplemde = autoSimpleMDE;
if ($(this).hasClass('quote-reply-diff')) {
const $parent = $(this).closest('.comment-code-cloud');
$parent.find('button.comment-form-reply').trigger('click');
$content = $parent.find('[name="content"]');
if ($content.val() !== '') {
$content.val(`${$content.val()}\n\n${content}`);
$simplemde = $parent.find('[name="content"]').data('simplemde');
}
if ($simplemde !== null) {
if ($simplemde.value() !== '') {
$simplemde.value(`${$simplemde.value()}\n\n${content}`);
} else {
$content.val(`${content}`);
}
$content.focus();
} else if (autoSimpleMDE !== null) {
if (autoSimpleMDE.value() !== '') {
autoSimpleMDE.value(`${autoSimpleMDE.value()}\n\n${content}`);
} else {
autoSimpleMDE.value(`${content}`);
$simplemde.value(`${content}`);
}
}
requestAnimationFrame(() => {
$simplemde.codemirror.focus();
$simplemde.codemirror.setCursor($simplemde.codemirror.lineCount(), 0);
});
event.preventDefault();
});
@@ -1043,8 +1048,10 @@ async function initRepository() {
$textarea.val($rawContent.text());
$simplemde.value($rawContent.text());
}
$textarea.focus();
$simplemde.codemirror.focus();
requestAnimationFrame(() => {
$textarea.focus();
$simplemde.codemirror.focus();
});
event.preventDefault();
});
@@ -1055,7 +1062,11 @@ async function initRepository() {
$.post($this.data('url'), {
_csrf: csrf
}).done(() => {
const $conversationHolder = $this.closest('.conversation-holder');
$(`#${$this.data('comment-id')}`).remove();
if ($conversationHolder.length && !$conversationHolder.find('.comment').length) {
$conversationHolder.remove();
}
});
}
return false;
@@ -1210,16 +1221,21 @@ function initPullRequestReview() {
const form = $(this).parent().find('.comment-form');
form.removeClass('hide');
const $textarea = form.find('textarea');
let $simplemde;
if ($textarea.data('simplemde')) {
$simplemde = $textarea.data('simplemde');
if (!isMobile()) {
let $simplemde;
if ($textarea.data('simplemde')) {
$simplemde = $textarea.data('simplemde');
} else {
attachTribute($textarea.get(), {mentions: true, emoji: true});
$simplemde = setCommentSimpleMDE($textarea);
$textarea.data('simplemde', $simplemde);
}
$textarea.focus();
$simplemde.codemirror.focus();
} else {
attachTribute($textarea.get(), {mentions: true, emoji: true});
$simplemde = setCommentSimpleMDE($textarea);
$textarea.data('simplemde', $simplemde);
$textarea.focus();
}
$textarea.focus();
$simplemde.codemirror.focus();
assingMenuAttributes(form.find('.menu'));
});
// The following part is only for diff views
@@ -1286,9 +1302,13 @@ function initPullRequestReview() {
const $textarea = commentCloud.find('textarea');
attachTribute($textarea.get(), {mentions: true, emoji: true});
const $simplemde = setCommentSimpleMDE($textarea);
$textarea.focus();
$simplemde.codemirror.focus();
if (!isMobile()) {
const $simplemde = setCommentSimpleMDE($textarea);
$textarea.focus();
$simplemde.codemirror.focus();
} else {
$textarea.focus();
}
});
}
@@ -1334,6 +1354,10 @@ function initWikiForm() {
const $editArea = $('.repository.wiki textarea#edit_area');
let sideBySideChanges = 0;
let sideBySideTimeout = null;
if ($editArea.length > 0 && isMobile) {
$editArea.css('display', 'inline-block');
return;
}
if ($editArea.length > 0) {
const simplemde = new SimpleMDE({
autoDownloadFontAwesome: false,
@@ -1429,6 +1453,7 @@ function initWikiForm() {
name: 'revert-to-textarea',
action(e) {
e.toTextArea();
$editArea.css('display', 'inline-block');
},
className: 'fa fa-file',
title: 'Revert to simple textarea',

View File

@@ -19,6 +19,11 @@ export function isDarkTheme() {
return document.documentElement.classList.contains('theme-arc-green');
}
// returns if mobile device
export function isMobile() {
return /Mobi/.test(navigator.userAgent);
}
// removes duplicate elements in an array
export function uniq(arr) {
return Array.from(new Set(arr));

View File

@@ -18,8 +18,8 @@
url('../fonts/noto-color-emoji/NotoColorEmoji.ttf') format('truetype');
}
@default-fonts: -apple-system, BlinkMacSystemFont, system-ui, 'Segoe UI', Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", "Twemoji Mozilla";
@monospaced-fonts: 'SF Mono', Consolas, Menlo, 'Liberation Mono', Monaco, 'Lucida Console';
@default-fonts: system-ui, -apple-system, "BlinkMacSystemFont", "Segoe UI", "Roboto", "Helvetica Neue", "Arial", "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", "Twemoji Mozilla";
@monospaced-fonts: "SFMono-Regular", "Menlo", "Monaco", "Consolas", "Liberation Mono", "Courier New", monospace;
.override-fonts(@fonts) {
textarea {

View File

@@ -3,7 +3,8 @@
justify-content: center;
align-items: center;
padding: 1rem;
margin: 1rem 0;
margin: 1rem auto;
height: auto;
}
/* mermaid's errorRenderer seems to unavoidably spew stuff into <body>, hide it */