Compare commits

...

26 Commits

Author SHA1 Message Date
Lauris BH
34fe3d390b Changelog for 1.11.8 (#12004) 2020-06-22 00:00:50 +03:00
silverwind
ce51c2bdf6 Really fix __webpack_public_path__ for 1.11 (#11961)
Trailing slash is actually significant, fixed that and i've now tested
it as well.

Ref: https://github.com/go-gitea/gitea/issues/11839#issuecomment-646203505
2020-06-18 21:40:07 +01:00
6543
7937f1463a Changelog v1.11.7 (#11953)
* Changelog v1.11.7

* Update CHANGELOG.md
2020-06-18 11:37:47 -04:00
6543
dbe9c11238 Use ID or Where to instead directly use Get when load object from database (#11925) (#11935)
Backport #11925

Use ID or Where to instead directly use Get when load object from database

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2020-06-17 20:54:26 +01:00
silverwind
313ace93d0 Fix __webpack_public_path__ for 1.11 (#11907)
Fixes: https://github.com/go-gitea/gitea/issues/11839
2020-06-16 11:26:45 -04:00
zeripath
f79a2e193f Fix verification of subkeys of default gpg key (#11713) (#11902)
Backport #11713

* Fix verification of subkeys of default gpg key

Fix #10309

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

* Remove debug log

* Update models/gpg_key.go

* As per @6543

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

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

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2020-06-15 16:04:37 -04:00
6543
5d4251eb78 [Workaround] doctor xorm.Count nil on sqlite error (#11741)
* make it similar to v1.12&master

* workaround from xorm bug

* CI.restart()
2020-06-09 01:37:07 -04:00
pvgoran
88008b681d Remove unnecessary parentheses in wiki/view template (#11781)
It's a backport of #10583 to version 1.11.

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2020-06-06 07:20:32 +01:00
guillep2k
5462fdcbbd Add changelog for 1.11.6 (#11695)
* Add changelog for 1.11.6

* Update CHANGELOG.md

Co-authored-by: techknowlogick <matti@mdranta.net>

* Update CHANGELOG.md

Co-authored-by: techknowlogick <matti@mdranta.net>

* Apply suggestions from @lafriks

* #11459 is bugfix

Co-authored-by: Guillermo Prandi <guillep2k@users.noreply.github.com>
Co-authored-by: techknowlogick <matti@mdranta.net>
2020-05-30 23:21:19 +03:00
guillep2k
161e550200 Add missing check for #11111 backport (#11693)
Co-authored-by: Guillermo Prandi <guillep2k@users.noreply.github.com>
2020-05-30 12:54:57 -03:00
Cirno the Strongest
95af6096fb Fix missing authorization check on pull for public repos of private/limited org (#11656) (#11683)
Fixes #11651

(cherry picked from commit 02fa329a7c)
2020-05-29 22:12:21 +01:00
6543
801f4b9e7a Add tracked time fix to doctor (part of #11111) (#11138)
Backports the tracked-time fix from #11111 (part of #11111)

Fixes tracked time errors following repo deletion (#10280) and adds the fix to the default doctor tasks
2020-05-29 16:41:23 +01:00
silverwind
c0c3a533a0 Fix webpack chunk loading with STATIC_URL_PREFIX (#11526) (#11544)
Previously, we had only set __webpack_public_path__ to a path which
caused webpack chunks to be loaded from the current origin which is
incorrect when STATIC_URL_PREFIX points to another origin.

This should fix the issue curretnly seen on gitea.com.

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lauris BH <lauris@nix.lv>

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lauris BH <lauris@nix.lv>
2020-05-28 19:49:38 -04:00
6543
ed646078e1 Return json on 500 error from API (#11574) (#11660)
Backport #11574

add API specific InternalServerError()

InternalServerError
2020-05-28 19:27:29 +01:00
zeripath
dc0ea133e1 Prevent (caught) panic on login (#11590) (#11598)
Backport #11590

Unfortunately when the virtual session is released it requires that the
real session does not exist. This worked fine when sessions were only
saved at the end of request/response cycle however, now sessions are
saved proactively this does not hold.

The result is a caught panic in the logs during every log-in.  This
panic has no significant side-effects but should not occur.

This PR marks the virtual session as released when released and updates
it if the same session is released again.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2020-05-27 21:37:27 +01:00
Gary Kim
a854846f06 Fix wrong milestone in webhook message (#11596) (#11612)
Backport of #11596

Signed-off-by: Gary Kim <gary@garykim.dev>
2020-05-25 00:03:02 +01:00
silverwind
b52e8de7de Fix commit page js error (1.11 backport) (#11527)
Partial backport of fd094eea95 to 1.11.

Fixes: https://github.com/go-gitea/gitea/issues/11518
2020-05-20 22:01:01 -04:00
zeripath
1b62916393 Use media links for img in post-process (#10515) (#11504)
* use media links for img in post-process

* do not visit text of anchors
2020-05-19 18:55:06 -04:00
pvgoran
1d57c309ef Remove unnecessary parentheses in wiki/revision template (#11481)
This fixes the error on "Page Revision" page, similar to #10552.
2020-05-18 23:05:27 +01:00
6543
cf97e65b66 Ensure public repositories in private organizations are visible and fix admin organizations list (#11465) (#11475)
Partial Backport of #11465

Co-authored-by: zeripath <art27@cantab.net>
2020-05-17 22:18:14 -03:00
zeripath
42a46cff35 Allow all members of private orgs to see public repos (#11442) (#11459)
* Allow all members of private orgs to see public repos (#11442)

Backport (#11442)

Allow all members of private orgs to see public repos

Fix #10144

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

* Update models/repo_list.go

* Oops missed the repos we own!

Signed-off-by: Andrew Thornton <art27@cantab.net>
2020-05-17 23:53:09 +01:00
zeripath
2cb3db2d20 Set correct content_type value for Gogs/Gitea webhooks (#9504) (#10456) (#11461)
The content_type value was defaulting to the string value of the
ContentType, not the integer value as expected by the backend.

Co-authored-by: Jeff Stein <jeff@jeffvstein.org>
2020-05-17 20:08:59 +01:00
zeripath
04e480d477 Whenever the ctx.Session is updated, release it to save it before sending the redirect (#11456) (#11457)
Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: Lauris BH <lauris@nix.lv>

Co-authored-by: Lauris BH <lauris@nix.lv>
2020-05-18 00:30:31 +08:00
zeripath
de9a96c4de Forcibly clean and destroy the session on logout (#11447) (#11451)
Backport #11447

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

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

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2020-05-17 14:32:33 +03:00
guillep2k
878434146f Use session for retrieving org teams (#11438) (#11439)
Co-authored-by: Guillermo Prandi <guillep2k@users.noreply.github.com>
2020-05-17 00:10:04 +03:00
6543
d78be7ddf9 Fix /api/v1/orgs/* endpoints by changing parameter to :org from :orgname (#11381) 2020-05-12 08:46:44 +03:00
35 changed files with 533 additions and 234 deletions

View File

@@ -4,6 +4,41 @@ This changelog goes through all the changes that have been made in each release
without substantial changes to our git log; to see the highlights of what has without substantial changes to our git log; to see the highlights of what has
been added to each release, please refer to the [blog](https://blog.gitea.io). been added to each release, please refer to the [blog](https://blog.gitea.io).
## [1.11.8](https://github.com/go-gitea/gitea/releases/tag/v1.11.8) - 2020-06-21
* BUGFIXES
* Really fix __webpack_public_path__ for 1.11 (#11961)
## [1.11.7](https://github.com/go-gitea/gitea/releases/tag/v1.11.7) - 2020-06-18
* BUGFIXES
* Use ID or Where to instead directly use Get when load object from database (#11925) (#11935)
* Fix __webpack_public_path__ for 1.11 (#11907)
* Fix verification of subkeys of default gpg key (#11713) (#11902)
* Remove unnecessary parentheses in wiki/view template (#11781)
* Doctor fix xorm.Count nil on sqlite error (#11741)
## [1.11.6](https://github.com/go-gitea/gitea/releases/tag/v1.11.6) - 2020-05-30
* SECURITY
* Fix missing authorization check on pull for public repos of private/limited org (#11656) (#11683)
* Use session for retrieving org teams (#11438) (#11439)
* BUGFIXES
* Return json on 500 error from API (#11574) (#11660)
* Fix wrong milestone in webhook message (#11596) (#11612)
* Prevent (caught) panic on login (#11590) (#11598)
* Fix commit page js error (#11527)
* Use media links for img in post-process (#10515) (#11504)
* Ensure public repositories in private organizations are visible and fix admin organizations list (#11465) (#11475)
* Set correct Content-Type value for Gogs/Gitea webhooks (#9504) (#10456) (#11461)
* Allow all members of private orgs to see public repos (#11442) (#11459)
* Whenever the ctx.Session is updated, release it to save it before sending the redirect (#11456) (#11457)
* Forcibly clean and destroy the session on logout (#11447) (#11451)
* Fix /api/v1/orgs/* endpoints by changing parameter to :org from :orgname (#11381)
* Add tracked time fix to doctor (part of #11111) (#11138)
* Fix webpack chunk loading with STATIC_URL_PREFIX (#11526) (#11544)
* Remove unnecessary parentheses in wiki/revision.tmpl to allow 1.11 to build on go1.14 (#11481)
## [1.11.5](https://github.com/go-gitea/gitea/releases/tag/v1.11.5) - 2020-05-09 ## [1.11.5](https://github.com/go-gitea/gitea/releases/tag/v1.11.5) - 2020-05-09
* BUGFIXES * BUGFIXES

View File

@@ -84,7 +84,7 @@ var checklist = []check{
}, },
{ {
title: "Check Database Version", title: "Check Database Version",
name: "check-db", name: "check-db-version",
isDefault: true, isDefault: true,
f: runDoctorCheckDBVersion, f: runDoctorCheckDBVersion,
abortIfFailed: true, abortIfFailed: true,
@@ -113,6 +113,12 @@ var checklist = []check{
isDefault: false, isDefault: false,
f: runDoctorPRMergeBase, f: runDoctorPRMergeBase,
}, },
{
title: "Check consistency of database",
name: "check-db-consistency",
isDefault: true,
f: runDoctorCheckDBConsistency,
},
// more checks please append here // more checks please append here
} }
@@ -494,3 +500,30 @@ func runDoctorScriptType(ctx *cli.Context) ([]string, error) {
} }
return []string{fmt.Sprintf("ScriptType %s is on the current PATH at %s", setting.ScriptType, path)}, nil return []string{fmt.Sprintf("ScriptType %s is on the current PATH at %s", setting.ScriptType, path)}, nil
} }
func runDoctorCheckDBConsistency(ctx *cli.Context) ([]string, error) {
var results []string
// make sure DB version is uptodate
if err := models.NewEngine(context.Background(), migrations.EnsureUpToDate); err != nil {
return nil, fmt.Errorf("model version on the database does not match the current Gitea version. Model consistency will not be checked until the database is upgraded")
}
//find tracked times without existing issues/pulls
count, err := models.CountOrphanedObjects("tracked_time", "issue", "tracked_time.issue_id=issue.id")
if err != nil {
return nil, err
}
if count > 0 {
if ctx.Bool("fix") {
if err = models.DeleteOrphanedObjects("tracked_time", "issue", "tracked_time.issue_id=issue.id"); err != nil {
return nil, err
}
results = append(results, fmt.Sprintf("%d tracked times without existing issue deleted", count))
} else {
results = append(results, fmt.Sprintf("%d tracked times without existing issue", count))
}
}
return results, nil
}

View File

@@ -76,6 +76,53 @@ nARUPZ9SqaUmRm+KGsSyoYnvN9apiDk5KVQoyfrmweNN7DCIIcoh/B9Ax8nmouKz
yBB2fjCM/bJNtN/AsgYbZIScuYK/xqTkwNtbe5WdCyD/QJOHTsPJzx59hgSVo6gf yBB2fjCM/bJNtN/AsgYbZIScuYK/xqTkwNtbe5WdCyD/QJOHTsPJzx59hgSVo6gf
Fe8VBnxHtrY8gPSUU3gkhYLvLzyVX+YLNzRcffobd8gJbfumwFJUkz91oGvYz7xg Fe8VBnxHtrY8gPSUU3gkhYLvLzyVX+YLNzRcffobd8gJbfumwFJUkz91oGvYz7xg
XN2qmsgBNCbTIzWZMpRDMAbY+n2QFImGf+EJZlMdj6gOrIYq8N4+nMW1FwJivsOb XN2qmsgBNCbTIzWZMpRDMAbY+n2QFImGf+EJZlMdj6gOrIYq8N4+nMW1FwJivsOb
muqySyjZnD2AYjEA6OYPXfCVhaB5fTfhQXbIrZbgsEh4ob/eIdM= muqySyjZnD2AYjEA6OYPXfCVhaB5fTfhQXbIrZbgsEh4ob/eIdOdBVgEXta5egEM
=oSDR AMYlmZ47NqBMBeaN0o/ahYMe8eIMaroWkufMfC9VRBSMAkpbDl34oNp0cflmnMYo
AFAl8ucRMFTiUnjiWpo27q14tjSyDVsn/CqwbnrgJgCFNV/MGsYsToEkb4JwDIRC
bky+1BvqvI8RMlO3MlwzrlIaMrlQfx5NtUb9TyO7S4xZTz864+Ty5p3HhRwbdZMe
Ko8sfXFhCcCHFXosI0mX83EyzsrXlbkGRawId7jvrdOAUg/cYP8f/XmV6z1NHHH9
cvz+3oLOGuVxUdG0KuS/jigHrLWdRuKM3xfEeesp870yZU3AbyFdoHnGXROJePTl
FV8j2P5Ahf/yuVhjdyJSKdZC2h6+HtLG9RiGgLviLLYhtlZG2H6pYyKY5Ud3php+
qw1aYL1xtdxrHYkQlAa0vLY/mwpuPfMke9I+rtnrwlLRMCstdiN34ybZ4sRD+gL1
w5VIZ/aM6/Gsczd3s/T8psIi09TKPfEU2gWLMGvlDsgz+aSDdVP7XYQpNglaEPet
PwARAQABAAv8CHg6+hnV2pblTwGTlTU7V8DO3gwMfn/QhQ/8ju66G5a7J6p/ZreQ
nfCJnqYq4AgoW0SuqVSBbbTENF6YjixNmiSlb9iHMZ+ilms24xG0Y3lOMBYYCY3Y
nTSNf6nXyconz31TW7jLmTdG9hpykKEKO9WFgt5UpgWe+2CAgtUoBDZyaLrVBZ2h
te99WmziDbPQZeZPm7UQ0aX0iRBclxy4+dxjcnrcmi1mdQAM/glgs2sHbEjN7JnV
dTOvUSN7/8ixj6I719Wx6MN6jE+BNd0ytZOun6tcDl0vamfT5fBpqbQoJMib2ggo
+FGg9VFnzEMLqyI47LfOKUjCIhwVsxS4q9HXa2FtpO8UfRMPjDKgDZQzRTRJScrP
s1NJ9HiM/eCHS1YjRmgroo60HygxkoLVCHp+Rz/hi0tG/ptv4q6mdnm8Mwb5JJtV
48EvmZoNTWl9xOez1wmQn6caVHipc0qDqn/veoe8N5wdc+3hoMEXbSXqU+kx2KUa
cVxCCVoUeURhBgDUGWtx34j1y17zE92BYhtVJTCU89dDe4wOEqGPyCGvRtgTmZ+1
KwWr66pij91MV9mlY+7Ue2QHUSmgav2EFGIjVes956p4/F/CJ6qaYoekirMSnmX5
jhRt4p6RW7m4omha3LAQ+gN4Fqa4acZUywENBvv1x3v+IWbjGJGn3eBnRrP3o9P+
QUAtyMifiRm0ZN8J767o+bzUVmscXrkh7Qml47lQfDToyRI1UZZQmP2izpwHcwbZ
NtfkgRUdeEq4GJUGAO8o4Oebbt0ALZ54E2LHhk8xi4ofKkFBDCkUFjcqS3bJJNck
rkhfqEkMLETNhPbiC4TRNiunI5PXOinwNPkKI8P/hfp4S49WdIvnARazCoxjZNtl
0Cbo+F1wtOH9FZaaWzNlU2lCQ2JJ3MCpLHz+nEmdYWOIWGQu2/s7smLODVEFbYKR
50VWVRL7mB83v1XdfMFvExdQ7i5MOX4hFvmwi/WJIKClJfhNwTrHp6Jrm9jA66RL
+dNyPKfwcFcYrqt1gwYAruZzP7QgTYVL+cmvGtCaHY4KoR8hanbpqR4YbzzyEXwS
ll2FUCaVSokuRAdH3+/CHF9bqog3Zvn6HYcCS/A/rHVGIU9a+7s5IbRe0Ysc2FAN
Nm9AsC5YnuyoAjW3cJGaZLYxp2WOZcMEXZeLPFYrNz22R1nRoxnUIPRpsKICXcK0
aC4rSMk479jc/8WprWx4d45EVG+6Gsh1AT8LVhDL9yHFrh50ss2jCe1Fnftet6DI
V5zHcxBx4sCs91aPxxe12UiJA2wEGAEKACAWIQQ4G/p4KVUOUEVu5g5R68KXFICq
DwUCXta5egIbAgHACRBR68KXFICqD8D0IAQZAQoAHRYhBKAm5ShdO9gmF/o8jan0
RkmWoKbKBQJe1rl6AAoJEKn0RkmWoKbKacUL/3YYKmiVvcr5LYFzMdwdahkla+6m
hEEkL0l3dJNuU97Ou71tA1ieF0fjbVRSWjXKsntKwhyPoXjaZEZwMmv7iZ8BXV+b
oO/EG5sg2/6iukJFXZqGnQwMdLVo1jPoXDteZU1qYiCoxLHhGhHL7ivtD1ygEi6w
/cMbbOEB5Le1vOWIwqazs8dDcAYyy1PKthRl0ygvh8CpqPwy+AK3uLm0TVwetQAp
taux0bDYWCb5Aft1r1nlV44gU4RiC131TDo+TKd754+UuI+UHk1D+LjTmZxRX2S6
fXgoMXzrWmthGPdqvVOgKWm7Ef18hmaBECvPnp/tUJeDVVe02KrYQi8Bf2kxveSd
8T0N/ExcydU9HgzTL8MuyPI+yp086elQzKJu6vb9tpgxCcglQZrUNT9Uy82pzTRY
z9MmhnCDI2SD5L/CW5PsNpPTPy7s3f9DOV0G5Vka4LTSBOCK64NvAGBmRf8rFjJU
lPtRPhC7h6uHdUIx3Q550Xogvq5sQm8UBCsbG8OJDADT3FJSIulR9Sh96OsES3sc
H09juN4KcbpS03MAeUFwXqw3jBMhDoGKlsjX17Jf31qh/nI/XjigS3XWyj1BLSMG
rJfH0NyYoGDCnff37tf+8lD9km9TlnV4Qjd9ujYbDRsefhaSjLVcy/gqdxZEuNBC
BWmGwsmLI3nyZ4KDtNsa5JUHUNNZLBN20hvmE41Eszmz4Yg9Ho9DxKiFKvzUULMc
bnMHaVHseHHq6+NVUnN1SAcOA0ygjnEid8D57RtdBCD90LXjLB7vlR+HaSMZYOnr
DtseivHvqqy4+rxhwV2S3avnls9vRwE4bV6GCiqhoBnWIZRrARLZc2OTBIya82vS
BIS1eyhjif1mE7Lqhs6aPD+eqQK2mBtQ/sidN8P/IfKfVF5siXfFbuGZLz5nRIho
Yp1z7oO3OZ09lpUk0G1h+ouIFF6goDP48M/AKtbvs9OWk3QKxnOUZD8sRncq95x6
m4q1MVb+aJyxwBqDRGaFY+3TVArB1b+kG1JsAvV5dag=
=511T
-----END PGP PRIVATE KEY BLOCK----- -----END PGP PRIVATE KEY BLOCK-----

View File

@@ -136,9 +136,8 @@ func GetAttachmentByID(id int64) (*Attachment, error) {
} }
func getAttachmentByID(e Engine, id int64) (*Attachment, error) { func getAttachmentByID(e Engine, id int64) (*Attachment, error) {
attach := &Attachment{ID: id} attach := &Attachment{}
if has, err := e.ID(id).Get(attach); err != nil {
if has, err := e.Get(attach); err != nil {
return nil, err return nil, err
} else if !has { } else if !has {
return nil, ErrAttachmentNotExist{ID: id, UUID: ""} return nil, ErrAttachmentNotExist{ID: id, UUID: ""}
@@ -147,8 +146,8 @@ func getAttachmentByID(e Engine, id int64) (*Attachment, error) {
} }
func getAttachmentByUUID(e Engine, uuid string) (*Attachment, error) { func getAttachmentByUUID(e Engine, uuid string) (*Attachment, error) {
attach := &Attachment{UUID: uuid} attach := &Attachment{}
has, err := e.Get(attach) has, err := e.Where("uuid=?", uuid).Get(attach)
if err != nil { if err != nil {
return nil, err return nil, err
} else if !has { } else if !has {

View File

@@ -231,8 +231,8 @@ func getProtectedBranchBy(e Engine, repoID int64, branchName string) (*Protected
// GetProtectedBranchByID getting protected branch by ID // GetProtectedBranchByID getting protected branch by ID
func GetProtectedBranchByID(id int64) (*ProtectedBranch, error) { func GetProtectedBranchByID(id int64) (*ProtectedBranch, error) {
rel := &ProtectedBranch{ID: id} rel := &ProtectedBranch{}
has, err := x.Get(rel) has, err := x.ID(id).Get(rel)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -521,9 +521,9 @@ func (repo *Repository) GetDeletedBranches() ([]*DeletedBranch, error) {
} }
// GetDeletedBranchByID get a deleted branch by its ID // GetDeletedBranchByID get a deleted branch by its ID
func (repo *Repository) GetDeletedBranchByID(ID int64) (*DeletedBranch, error) { func (repo *Repository) GetDeletedBranchByID(id int64) (*DeletedBranch, error) {
deletedBranch := &DeletedBranch{ID: ID} deletedBranch := &DeletedBranch{}
has, err := x.Get(deletedBranch) has, err := x.ID(id).Get(deletedBranch)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -10,6 +10,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"xorm.io/builder"
) )
// consistencyCheckable a type that can be tested for database consistency // consistencyCheckable a type that can be tested for database consistency
@@ -167,3 +168,23 @@ func (action *Action) checkForConsistency(t *testing.T) {
repo := AssertExistsAndLoadBean(t, &Repository{ID: action.RepoID}).(*Repository) repo := AssertExistsAndLoadBean(t, &Repository{ID: action.RepoID}).(*Repository)
assert.Equal(t, repo.IsPrivate, action.IsPrivate, "action: %+v", action) assert.Equal(t, repo.IsPrivate, action.IsPrivate, "action: %+v", action)
} }
// CountOrphanedObjects count subjects with have no existing refobject anymore
func CountOrphanedObjects(subject, refobject, joinCond string) (int64, error) {
var ids []int64
return int64(len(ids)), x.Table("`"+subject+"`").
Join("LEFT", refobject, joinCond).
Where(builder.IsNull{"`" + refobject + "`.id"}).
Select("id").Find(&ids)
}
// DeleteOrphanedObjects delete subjects with have no existing refobject anymore
func DeleteOrphanedObjects(subject, refobject, joinCond string) error {
_, err := x.In("id", builder.Select("`"+subject+"`.id").
From("`"+subject+"`").
Join("LEFT", "`"+refobject+"`", joinCond).
Where(builder.IsNull{"`" + refobject + "`.id"})).
Delete("`" + subject + "`")
return err
}

View File

@@ -736,6 +736,21 @@ func verifyWithGPGSettings(gpgSettings *git.GPGSettings, sig *packet.Signature,
CanSign: pubkey.CanSign(), CanSign: pubkey.CanSign(),
KeyID: pubkey.KeyIdString(), KeyID: pubkey.KeyIdString(),
} }
for _, subKey := range ekey.Subkeys {
content, err := base64EncPubKey(subKey.PublicKey)
if err != nil {
return &CommitVerification{
CommittingUser: committer,
Verified: false,
Reason: "gpg.error.generate_hash",
}
}
k.SubsKey = append(k.SubsKey, &GPGKey{
Content: content,
CanSign: subKey.PublicKey.CanSign(),
KeyID: subKey.PublicKey.KeyIdString(),
})
}
if commitVerification := hashAndVerifyWithSubKeys(sig, payload, k, committer, &User{ if commitVerification := hashAndVerifyWithSubKeys(sig, payload, k, committer, &User{
Name: gpgSettings.Name, Name: gpgSettings.Name,
Email: gpgSettings.Email, Email: gpgSettings.Email,

View File

@@ -241,7 +241,7 @@ func (issue *Issue) loadReactions(e Engine) (err error) {
} }
func (issue *Issue) loadMilestone(e Engine) (err error) { func (issue *Issue) loadMilestone(e Engine) (err error) {
if issue.Milestone == nil && issue.MilestoneID > 0 { if (issue.Milestone == nil || issue.Milestone.ID != issue.MilestoneID) && issue.MilestoneID > 0 {
issue.Milestone, err = getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID) issue.Milestone, err = getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID)
if err != nil && !IsErrMilestoneNotExist(err) { if err != nil && !IsErrMilestoneNotExist(err) {
return fmt.Errorf("getMilestoneByRepoID [repo_id: %d, milestone_id: %d]: %v", issue.RepoID, issue.MilestoneID, err) return fmt.Errorf("getMilestoneByRepoID [repo_id: %d, milestone_id: %d]: %v", issue.RepoID, issue.MilestoneID, err)

View File

@@ -212,11 +212,8 @@ func getLabelInRepoByName(e Engine, repoID int64, labelName string) (*Label, err
return nil, ErrLabelNotExist{0, repoID} return nil, ErrLabelNotExist{0, repoID}
} }
l := &Label{ l := &Label{}
Name: labelName, has, err := e.Where("name=? AND repo_id=?", labelName, repoID).Get(l)
RepoID: repoID,
}
has, err := e.Get(l)
if err != nil { if err != nil {
return nil, err return nil, err
} else if !has { } else if !has {

View File

@@ -300,7 +300,7 @@ func (source *LoginSource) SSPI() *SSPIConfig {
// CreateLoginSource inserts a LoginSource in the DB if not already // CreateLoginSource inserts a LoginSource in the DB if not already
// existing with the given name. // existing with the given name.
func CreateLoginSource(source *LoginSource) error { func CreateLoginSource(source *LoginSource) error {
has, err := x.Get(&LoginSource{Name: source.Name}) has, err := x.Where("name=?", source.Name).Exist(new(LoginSource))
if err != nil { if err != nil {
return err return err
} else if has { } else if has {

View File

@@ -1608,7 +1608,7 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
} }
if newOwner.IsOrganization() { if newOwner.IsOrganization() {
if err := newOwner.GetTeams(); err != nil { if err := newOwner.getTeams(sess); err != nil {
return fmt.Errorf("GetTeams: %v", err) return fmt.Errorf("GetTeams: %v", err)
} }
for _, t := range newOwner.Teams { for _, t := range newOwner.Teams {

View File

@@ -214,14 +214,35 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
} }
if opts.Collaborate != util.OptionalBoolFalse { if opts.Collaborate != util.OptionalBoolFalse {
// A Collaboration is:
collaborateCond := builder.And( collaborateCond := builder.And(
// 1. Repository we don't own
builder.Neq{"owner_id": opts.OwnerID},
// 2. But we can see because of:
builder.Or( builder.Or(
builder.Expr("repository.id IN (SELECT repo_id FROM `access` WHERE access.user_id = ?)", opts.OwnerID), // A. We have access
builder.In("id", builder.Select("`team_repo`.repo_id"). builder.In("`repository`.id",
builder.Select("`access`.repo_id").
From("access").
Where(builder.Eq{"`access`.user_id": opts.OwnerID})),
// B. We are in a team for
builder.In("`repository`.id", builder.Select("`team_repo`.repo_id").
From("team_repo"). From("team_repo").
Where(builder.Eq{"`team_user`.uid": opts.OwnerID}). Where(builder.Eq{"`team_user`.uid": opts.OwnerID}).
Join("INNER", "team_user", "`team_user`.team_id = `team_repo`.team_id"))), Join("INNER", "team_user", "`team_user`.team_id = `team_repo`.team_id")),
builder.Neq{"owner_id": opts.OwnerID}) // C. Public repositories in private organizations that we are member of
builder.And(
builder.Eq{"`repository`.is_private": false},
builder.In("`repository`.owner_id",
builder.Select("`org_user`.org_id").
From("org_user").
Join("INNER", "`user`", "`user`.id = `org_user`.org_id").
Where(builder.Eq{
"`org_user`.uid": opts.OwnerID,
"`user`.type": UserTypeOrganization,
"`user`.visibility": structs.VisibleTypePrivate,
})))),
)
if !opts.Private { if !opts.Private {
collaborateCond = collaborateCond.And(builder.Expr("owner_id NOT IN (SELECT org_id FROM org_user WHERE org_user.uid = ? AND org_user.is_public = ?)", opts.OwnerID, false)) collaborateCond = collaborateCond.And(builder.Expr("owner_id NOT IN (SELECT org_id FROM org_user WHERE org_user.uid = ? AND org_user.is_public = ?)", opts.OwnerID, false))
} }
@@ -340,41 +361,39 @@ func SearchRepositoryByCondition(opts *SearchRepoOptions, cond builder.Cond) (Re
// accessibleRepositoryCondition takes a user a returns a condition for checking if a repository is accessible // accessibleRepositoryCondition takes a user a returns a condition for checking if a repository is accessible
func accessibleRepositoryCondition(userID int64) builder.Cond { func accessibleRepositoryCondition(userID int64) builder.Cond {
if userID <= 0 { if userID <= 0 {
// Public repositories that are not in private or limited organizations
return builder.And( return builder.And(
builder.Eq{"`repository`.is_private": false}, builder.Eq{"`repository`.is_private": false},
builder.Or( builder.NotIn("`repository`.owner_id",
// A. Aren't in organisations __OR__ builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization}).And(builder.Neq{"visibility": structs.VisibleTypePublic})))
builder.NotIn("`repository`.owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization})),
// B. Is a public organisation.
builder.In("`repository`.owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"visibility": structs.VisibleTypePublic}))),
)
} }
return builder.Or( return builder.Or(
// 1. Be able to see all non-private repositories that either: // 1. All public repositories that are not in private organizations
builder.And( builder.And(
builder.Eq{"`repository`.is_private": false}, builder.Eq{"`repository`.is_private": false},
builder.Or( builder.NotIn("`repository`.owner_id",
// A. Aren't in organisations __OR__ builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization}).And(builder.Eq{"visibility": structs.VisibleTypePrivate}))),
builder.NotIn("`repository`.owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization})), // 2. Be able to see all repositories that we own
// B. Isn't a private organisation. (Limited is OK because we're logged in) builder.Eq{"`repository`.owner_id": userID},
builder.NotIn("`repository`.owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"visibility": structs.VisibleTypePrivate}))), // 3. Be able to see all repositories that we have access to
), builder.In("`repository`.id", builder.Select("repo_id").
// 2. Be able to see all repositories that we have access to From("`access`").
builder.Or( Where(builder.And(
builder.In("`repository`.id", builder.Select("repo_id"). builder.Eq{"user_id": userID},
From("`access`"). builder.Gt{"mode": int(AccessModeNone)}))),
Where(builder.And( // 4. Be able to see all repositories that we are in a team
builder.Eq{"user_id": userID},
builder.Gt{"mode": int(AccessModeNone)}))),
builder.In("`repository`.id", builder.Select("id").
From("`repository`").
Where(builder.Eq{"owner_id": userID}))),
// 3. Be able to see all repositories that we are in a team
builder.In("`repository`.id", builder.Select("`team_repo`.repo_id"). builder.In("`repository`.id", builder.Select("`team_repo`.repo_id").
From("team_repo"). From("team_repo").
Where(builder.Eq{"`team_user`.uid": userID}). Where(builder.Eq{"`team_user`.uid": userID}).
Join("INNER", "team_user", "`team_user`.team_id = `team_repo`.team_id"))) Join("INNER", "team_user", "`team_user`.team_id = `team_repo`.team_id")),
// 5. Be able to see all public repos in private organizations that we are an org_user of
builder.And(builder.Eq{"`repository`.is_private": false},
builder.In("`repository`.owner_id",
builder.Select("`org_user`.org_id").
From("org_user").
Where(builder.Eq{"`org_user`.uid": userID}))),
)
} }
// SearchRepositoryByName takes keyword and part of repository name to search, // SearchRepositoryByName takes keyword and part of repository name to search,

View File

@@ -142,8 +142,8 @@ func UpdateTwoFactor(t *TwoFactor) error {
// GetTwoFactorByUID returns the two-factor authentication token associated with // GetTwoFactorByUID returns the two-factor authentication token associated with
// the user, if any. // the user, if any.
func GetTwoFactorByUID(uid int64) (*TwoFactor, error) { func GetTwoFactorByUID(uid int64) (*TwoFactor, error) {
twofa := &TwoFactor{UID: uid} twofa := &TwoFactor{}
has, err := x.Get(twofa) has, err := x.Where("uid=?", uid).Get(twofa)
if err != nil { if err != nil {
return nil, err return nil, err
} else if !has { } else if !has {

View File

@@ -76,8 +76,8 @@ func NewUpload(name string, buf []byte, file multipart.File) (_ *Upload, err err
// GetUploadByUUID returns the Upload by UUID // GetUploadByUUID returns the Upload by UUID
func GetUploadByUUID(uuid string) (*Upload, error) { func GetUploadByUUID(uuid string) (*Upload, error) {
upload := &Upload{UUID: uuid} upload := &Upload{}
has, err := x.Get(upload) has, err := x.Where("uuid=?", uuid).Get(upload)
if err != nil { if err != nil {
return nil, err return nil, err
} else if !has { } else if !has {

View File

@@ -1457,8 +1457,8 @@ func GetUserByEmail(email string) (*User, error) {
// Finally, if email address is the protected email address: // Finally, if email address is the protected email address:
if strings.HasSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) { if strings.HasSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) {
username := strings.TrimSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) username := strings.TrimSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress))
user := &User{LowerName: username} user := &User{}
has, err := x.Get(user) has, err := x.Where("lower_name=?", username).Get(user)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -71,8 +71,8 @@ func GetEmailAddresses(uid int64) ([]*EmailAddress, error) {
// GetEmailAddressByID gets a user's email address by ID // GetEmailAddressByID gets a user's email address by ID
func GetEmailAddressByID(uid, id int64) (*EmailAddress, error) { func GetEmailAddressByID(uid, id int64) (*EmailAddress, error) {
// User ID is required for security reasons // User ID is required for security reasons
email := &EmailAddress{ID: id, UID: uid} email := &EmailAddress{UID: uid}
if has, err := x.Get(email); err != nil { if has, err := x.ID(id).Get(email); err != nil {
return nil, err return nil, err
} else if !has { } else if !has {
return nil, nil return nil, nil
@@ -126,7 +126,7 @@ func isEmailUsed(e Engine, email string) (bool, error) {
return true, nil return true, nil
} }
return e.Get(&EmailAddress{Email: email}) return e.Where("email=?", email).Get(&EmailAddress{})
} }
// IsEmailUsed returns true if the email has been used. // IsEmailUsed returns true if the email has been used.
@@ -251,8 +251,8 @@ func MakeEmailPrimary(email *EmailAddress) error {
return ErrEmailNotActivated return ErrEmailNotActivated
} }
user := &User{ID: email.UID} user := &User{}
has, err = x.Get(user) has, err = x.ID(email.UID).Get(user)
if err != nil { if err != nil {
return err return err
} else if !has { } else if !has {

View File

@@ -111,8 +111,8 @@ func GetUserByOpenID(uri string) (*User, error) {
log.Trace("Normalized OpenID URI: " + uri) log.Trace("Normalized OpenID URI: " + uri)
// Otherwise, check in openid table // Otherwise, check in openid table
oid := &UserOpenID{URI: uri} oid := &UserOpenID{}
has, err := x.Get(oid) has, err := x.Where("uri=?", uri).Get(oid)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -7,6 +7,7 @@ package context
import ( import (
"fmt" "fmt"
"net/http"
"net/url" "net/url"
"strings" "strings"
@@ -64,18 +65,18 @@ type APINotFound struct{}
// swagger:response redirect // swagger:response redirect
type APIRedirect struct{} type APIRedirect struct{}
// Error responses error message to client with given message. // Error responds with an error message to client with given obj as the message.
// If status is 500, also it prints error to log. // If status is 500, also it prints error to log.
func (ctx *APIContext) Error(status int, title string, obj interface{}) { func (ctx *APIContext) Error(status int, title string, obj interface{}) {
var message string var message string
if err, ok := obj.(error); ok { if err, ok := obj.(error); ok {
message = err.Error() message = err.Error()
} else { } else {
message = obj.(string) message = fmt.Sprintf("%s", obj)
} }
if status == 500 { if status == http.StatusInternalServerError {
log.Error("%s: %s", title, message) log.ErrorWithSkip(1, "%s: %s", title, message)
} }
ctx.JSON(status, APIError{ ctx.JSON(status, APIError{
@@ -84,6 +85,22 @@ func (ctx *APIContext) Error(status int, title string, obj interface{}) {
}) })
} }
// InternalServerError responds with an error message to the client with the error as a message
// and the file and line of the caller.
func (ctx *APIContext) InternalServerError(err error) {
log.ErrorWithSkip(1, "InternalServerError: %v", err)
var message string
if macaron.Env != macaron.PROD {
message = err.Error()
}
ctx.JSON(http.StatusInternalServerError, APIError{
Message: message,
URL: setting.API.SwaggerURL,
})
}
func genAPILinks(curURL *url.URL, total, pageSize, curPage int) []string { func genAPILinks(curURL *url.URL, total, pageSize, curPage int) []string {
page := NewPagination(total, pageSize, curPage, 0) page := NewPagination(total, pageSize, curPage, 0)
paginater := page.Paginater paginater := page.Paginater

View File

@@ -290,7 +290,7 @@ func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) {
} }
for _, node := range nodes { for _, node := range nodes {
ctx.visitNode(node) ctx.visitNode(node, true)
} }
// Create buffer in which the data will be placed again. We know that the // Create buffer in which the data will be placed again. We know that the
@@ -313,7 +313,7 @@ func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) {
return res, nil return res, nil
} }
func (ctx *postProcessCtx) visitNode(node *html.Node) { func (ctx *postProcessCtx) visitNode(node *html.Node, visitText bool) {
// Add user-content- to IDs if they don't already have them // Add user-content- to IDs if they don't already have them
for idx, attr := range node.Attr { for idx, attr := range node.Attr {
if attr.Key == "id" && !(strings.HasPrefix(attr.Val, "user-content-") || blackfridayExtRegex.MatchString(attr.Val)) { if attr.Key == "id" && !(strings.HasPrefix(attr.Val, "user-content-") || blackfridayExtRegex.MatchString(attr.Val)) {
@@ -323,13 +323,37 @@ func (ctx *postProcessCtx) visitNode(node *html.Node) {
// We ignore code, pre and already generated links. // We ignore code, pre and already generated links.
switch node.Type { switch node.Type {
case html.TextNode: case html.TextNode:
ctx.textNode(node) if visitText {
ctx.textNode(node)
}
case html.ElementNode: case html.ElementNode:
if node.Data == "a" || node.Data == "code" || node.Data == "pre" { if node.Data == "img" {
attrs := node.Attr
for idx, attr := range attrs {
if attr.Key != "src" {
continue
}
link := []byte(attr.Val)
if len(link) > 0 && !IsLink(link) {
prefix := ctx.urlPrefix
if ctx.isWikiMarkdown {
prefix = util.URLJoin(prefix, "wiki", "raw")
}
prefix = strings.Replace(prefix, "/src/", "/media/", 1)
lnk := string(link)
lnk = util.URLJoin(prefix, lnk)
link = []byte(lnk)
}
node.Attr[idx].Val = string(link)
}
} else if node.Data == "a" {
visitText = false
} else if node.Data == "code" || node.Data == "pre" {
return return
} }
for n := node.FirstChild; n != nil; n = n.NextSibling { for n := node.FirstChild; n != nil; n = n.NextSibling {
ctx.visitNode(n) ctx.visitNode(n, visitText)
} }
} }
// ignore everything else // ignore everything else

View File

@@ -107,10 +107,11 @@ func init() {
// VirtualStore represents a virtual session store implementation. // VirtualStore represents a virtual session store implementation.
type VirtualStore struct { type VirtualStore struct {
p *VirtualSessionProvider p *VirtualSessionProvider
sid string sid string
lock sync.RWMutex lock sync.RWMutex
data map[interface{}]interface{} data map[interface{}]interface{}
released bool
} }
// NewVirtualStore creates and returns a virtual session store. // NewVirtualStore creates and returns a virtual session store.
@@ -164,7 +165,7 @@ func (s *VirtualStore) Release() error {
// Now ensure that we don't exist! // Now ensure that we don't exist!
realProvider := s.p.provider realProvider := s.p.provider
if realProvider.Exist(s.sid) { if !s.released && realProvider.Exist(s.sid) {
// This is an error! // This is an error!
return fmt.Errorf("new sid '%s' already exists", s.sid) return fmt.Errorf("new sid '%s' already exists", s.sid)
} }
@@ -172,12 +173,19 @@ func (s *VirtualStore) Release() error {
if err != nil { if err != nil {
return err return err
} }
if err := realStore.Flush(); err != nil {
return err
}
for key, value := range s.data { for key, value := range s.data {
if err := realStore.Set(key, value); err != nil { if err := realStore.Set(key, value); err != nil {
return err return err
} }
} }
return realStore.Release() err = realStore.Release()
if err == nil {
s.released = true
}
return err
} }
return nil return nil
} }

View File

@@ -382,7 +382,7 @@ func orgAssignment(args ...bool) macaron.Handler {
var err error var err error
if assignOrg { if assignOrg {
ctx.Org.Organization, err = models.GetOrgByName(ctx.Params(":orgname")) ctx.Org.Organization, err = models.GetOrgByName(ctx.Params(":org"))
if err != nil { if err != nil {
if models.IsErrOrgNotExist(err) { if models.IsErrOrgNotExist(err) {
ctx.NotFound() ctx.NotFound()
@@ -808,7 +808,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/user/orgs", reqToken(), org.ListMyOrgs) m.Get("/user/orgs", reqToken(), org.ListMyOrgs)
m.Get("/users/:username/orgs", org.ListUserOrgs) m.Get("/users/:username/orgs", org.ListUserOrgs)
m.Post("/orgs", reqToken(), bind(api.CreateOrgOption{}), org.Create) m.Post("/orgs", reqToken(), bind(api.CreateOrgOption{}), org.Create)
m.Group("/orgs/:orgname", func() { m.Group("/orgs/:org", func() {
m.Get("/repos", user.ListOrgRepos) m.Get("/repos", user.ListOrgRepos)
m.Combo("").Get(org.Get). m.Combo("").Get(org.Get).
Patch(reqToken(), reqOrgOwnership(), bind(api.EditOrgOption{}), org.Edit). Patch(reqToken(), reqOrgOwnership(), bind(api.EditOrgOption{}), org.Edit).
@@ -850,7 +850,7 @@ func RegisterRoutes(m *macaron.Macaron) {
}) })
m.Group("/repos", func() { m.Group("/repos", func() {
m.Get("", org.GetTeamRepos) m.Get("", org.GetTeamRepos)
m.Combo("/:orgname/:reponame"). m.Combo("/:org/:reponame").
Put(org.AddTeamRepository). Put(org.AddTeamRepository).
Delete(org.RemoveTeamRepository) Delete(org.RemoveTeamRepository)
}) })

View File

@@ -384,6 +384,11 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form) ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
return return
} }
if err = ctx.Session.Release(); err != nil {
ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
return
}
} }
log.Info("First-time run install finished!") log.Info("First-time run install finished!")

View File

@@ -201,6 +201,8 @@ func FileHistory(ctx *context.Context) {
func Diff(ctx *context.Context) { func Diff(ctx *context.Context) {
ctx.Data["PageIsDiff"] = true ctx.Data["PageIsDiff"] = true
ctx.Data["RequireHighlightJS"] = true ctx.Data["RequireHighlightJS"] = true
ctx.Data["RequireSimpleMDE"] = true
ctx.Data["RequireTribute"] = true
userName := ctx.Repo.Owner.Name userName := ctx.Repo.Owner.Name
repoName := ctx.Repo.Repository.Name repoName := ctx.Repo.Repository.Name

View File

@@ -29,6 +29,7 @@ import (
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
repo_service "code.gitea.io/gitea/services/repository" repo_service "code.gitea.io/gitea/services/repository"
) )
@@ -135,6 +136,16 @@ func HTTP(ctx *context.Context) {
environ []string environ []string
) )
// don't allow anonymous pulls if organization is not public
if isPublicPull {
if err := repo.GetOwner(); err != nil {
ctx.ServerError("GetOwner", err)
return
}
askAuth = askAuth || (repo.Owner.Visibility != structs.VisibleTypePublic)
}
// check access // check access
if askAuth { if askAuth {
authUsername = ctx.Req.Header.Get(setting.ReverseProxyAuthUser) authUsername = ctx.Req.Header.Get(setting.ReverseProxyAuthUser)

View File

@@ -81,14 +81,18 @@ func AutoSignIn(ctx *context.Context) (bool, error) {
} }
isSucceed = true isSucceed = true
err = ctx.Session.Set("uid", u.ID)
if err != nil { // Set session IDs
if err := ctx.Session.Set("uid", u.ID); err != nil {
return false, err return false, err
} }
err = ctx.Session.Set("uname", u.Name) if err := ctx.Session.Set("uname", u.Name); err != nil {
if err != nil {
return false, err return false, err
} }
if err := ctx.Session.Release(); err != nil {
return false, err
}
ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
return true, nil return true, nil
} }
@@ -203,14 +207,16 @@ func SignInPost(ctx *context.Context, form auth.SignInForm) {
} }
// User needs to use 2FA, save data and redirect to 2FA page. // User needs to use 2FA, save data and redirect to 2FA page.
err = ctx.Session.Set("twofaUid", u.ID) if err := ctx.Session.Set("twofaUid", u.ID); err != nil {
if err != nil { ctx.ServerError("UserSignIn: Unable to set twofaUid in session", err)
ctx.ServerError("UserSignIn", err)
return return
} }
err = ctx.Session.Set("twofaRemember", form.Remember) if err := ctx.Session.Set("twofaRemember", form.Remember); err != nil {
if err != nil { ctx.ServerError("UserSignIn: Unable to set twofaRemember in session", err)
ctx.ServerError("UserSignIn", err) return
}
if err := ctx.Session.Release(); err != nil {
ctx.ServerError("UserSignIn: Unable to save session", err)
return return
} }
@@ -407,10 +413,14 @@ func U2FChallenge(ctx *context.Context) {
ctx.ServerError("u2f.NewChallenge", err) ctx.ServerError("u2f.NewChallenge", err)
return return
} }
if err = ctx.Session.Set("u2fChallenge", challenge); err != nil { if err := ctx.Session.Set("u2fChallenge", challenge); err != nil {
ctx.ServerError("UserSignIn", err) ctx.ServerError("UserSignIn: unable to set u2fChallenge in session", err)
return return
} }
if err := ctx.Session.Release(); err != nil {
ctx.ServerError("UserSignIn: unable to store session", err)
}
ctx.JSON(200, challenge.SignRequest(regs.ToRegistrations())) ctx.JSON(200, challenge.SignRequest(regs.ToRegistrations()))
} }
@@ -494,13 +504,14 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR
_ = ctx.Session.Delete("twofaRemember") _ = ctx.Session.Delete("twofaRemember")
_ = ctx.Session.Delete("u2fChallenge") _ = ctx.Session.Delete("u2fChallenge")
_ = ctx.Session.Delete("linkAccount") _ = ctx.Session.Delete("linkAccount")
err := ctx.Session.Set("uid", u.ID) if err := ctx.Session.Set("uid", u.ID); err != nil {
if err != nil { log.Error("Error setting uid %d in session: %v", u.ID, err)
log.Error(fmt.Sprintf("Error setting session: %v", err))
} }
err = ctx.Session.Set("uname", u.Name) if err := ctx.Session.Set("uname", u.Name); err != nil {
if err != nil { log.Error("Error setting uname %s session: %v", u.Name, err)
log.Error(fmt.Sprintf("Error setting session: %v", err)) }
if err := ctx.Session.Release(); err != nil {
log.Error("Unable to store session: %v", err)
} }
// Language setting of the user overwrites the one previously set // Language setting of the user overwrites the one previously set
@@ -593,9 +604,11 @@ func handleOAuth2SignIn(u *models.User, gothUser goth.User, ctx *context.Context
if u == nil { if u == nil {
// no existing user is found, request attach or new account // no existing user is found, request attach or new account
err = ctx.Session.Set("linkAccountGothUser", gothUser) if err := ctx.Session.Set("linkAccountGothUser", gothUser); err != nil {
if err != nil { log.Error("Error setting linkAccountGothUser in session: %v", err)
log.Error(fmt.Sprintf("Error setting session: %v", err)) }
if err := ctx.Session.Release(); err != nil {
log.Error("Error storing session: %v", err)
} }
ctx.Redirect(setting.AppSubURL + "/user/link_account") ctx.Redirect(setting.AppSubURL + "/user/link_account")
return return
@@ -610,13 +623,14 @@ func handleOAuth2SignIn(u *models.User, gothUser goth.User, ctx *context.Context
return return
} }
err = ctx.Session.Set("uid", u.ID) if err := ctx.Session.Set("uid", u.ID); err != nil {
if err != nil { log.Error("Error setting uid in session: %v", err)
log.Error(fmt.Sprintf("Error setting session: %v", err))
} }
err = ctx.Session.Set("uname", u.Name) if err := ctx.Session.Set("uname", u.Name); err != nil {
if err != nil { log.Error("Error setting uname in session: %v", err)
log.Error(fmt.Sprintf("Error setting session: %v", err)) }
if err := ctx.Session.Release(); err != nil {
log.Error("Error storing session: %v", err)
} }
// Clear whatever CSRF has right now, force to generate a new one // Clear whatever CSRF has right now, force to generate a new one
@@ -645,13 +659,14 @@ func handleOAuth2SignIn(u *models.User, gothUser goth.User, ctx *context.Context
} }
// User needs to use 2FA, save data and redirect to 2FA page. // User needs to use 2FA, save data and redirect to 2FA page.
err = ctx.Session.Set("twofaUid", u.ID) if err := ctx.Session.Set("twofaUid", u.ID); err != nil {
if err != nil { log.Error("Error setting twofaUid in session: %v", err)
log.Error(fmt.Sprintf("Error setting session: %v", err))
} }
err = ctx.Session.Set("twofaRemember", false) if err := ctx.Session.Set("twofaRemember", false); err != nil {
if err != nil { log.Error("Error setting twofaRemember in session: %v", err)
log.Error(fmt.Sprintf("Error setting session: %v", err)) }
if err := ctx.Session.Release(); err != nil {
log.Error("Error storing session: %v", err)
} }
// If U2F is enrolled -> Redirect to U2F instead // If U2F is enrolled -> Redirect to U2F instead
@@ -816,17 +831,17 @@ func LinkAccountPostSignIn(ctx *context.Context, signInForm auth.SignInForm) {
} }
// User needs to use 2FA, save data and redirect to 2FA page. // User needs to use 2FA, save data and redirect to 2FA page.
err = ctx.Session.Set("twofaUid", u.ID) if err := ctx.Session.Set("twofaUid", u.ID); err != nil {
if err != nil { log.Error("Error setting twofaUid in session: %v", err)
log.Error(fmt.Sprintf("Error setting session: %v", err))
} }
err = ctx.Session.Set("twofaRemember", signInForm.Remember) if err := ctx.Session.Set("twofaRemember", signInForm.Remember); err != nil {
if err != nil { log.Error("Error setting twofaRemember in session: %v", err)
log.Error(fmt.Sprintf("Error setting session: %v", err))
} }
err = ctx.Session.Set("linkAccount", true) if err := ctx.Session.Set("linkAccount", true); err != nil {
if err != nil { log.Error("Error setting linkAccount in session: %v", err)
log.Error(fmt.Sprintf("Error setting session: %v", err)) }
if err := ctx.Session.Release(); err != nil {
log.Error("Error storing session: %v", err)
} }
// If U2F is enrolled -> Redirect to U2F instead // If U2F is enrolled -> Redirect to U2F instead
@@ -988,11 +1003,8 @@ func LinkAccountPostRegister(ctx *context.Context, cpt *captcha.Captcha, form au
} }
func handleSignOut(ctx *context.Context) { func handleSignOut(ctx *context.Context) {
_ = ctx.Session.Delete("uid") _ = ctx.Session.Flush()
_ = ctx.Session.Delete("uname") _ = ctx.Session.Destroy(ctx.Context)
_ = ctx.Session.Delete("socialId")
_ = ctx.Session.Delete("socialName")
_ = ctx.Session.Delete("socialEmail")
ctx.SetCookie(setting.CookieUserName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) ctx.SetCookie(setting.CookieUserName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
ctx.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) ctx.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
@@ -1187,14 +1199,16 @@ func Activate(ctx *context.Context) {
log.Trace("User activated: %s", user.Name) log.Trace("User activated: %s", user.Name)
err = ctx.Session.Set("uid", user.ID) if err := ctx.Session.Set("uid", user.ID); err != nil {
if err != nil { log.Error(fmt.Sprintf("Error setting uid in session: %v", err))
log.Error(fmt.Sprintf("Error setting session: %v", err))
} }
err = ctx.Session.Set("uname", user.Name) if err := ctx.Session.Set("uname", user.Name); err != nil {
if err != nil { log.Error(fmt.Sprintf("Error setting uname in session: %v", err))
log.Error(fmt.Sprintf("Error setting session: %v", err))
} }
if err := ctx.Session.Release(); err != nil {
log.Error("Error storing session: %v", err)
}
ctx.Flash.Success(ctx.Tr("auth.account_activated")) ctx.Flash.Success(ctx.Tr("auth.account_activated"))
ctx.Redirect(setting.AppSubURL + "/") ctx.Redirect(setting.AppSubURL + "/")
return return

View File

@@ -128,9 +128,12 @@ func SignInOpenIDPost(ctx *context.Context, form auth.SignInOpenIDForm) {
url += "&openid.sreg.optional=nickname%2Cemail" url += "&openid.sreg.optional=nickname%2Cemail"
log.Trace("Form-passed openid-remember: %t", form.Remember) log.Trace("Form-passed openid-remember: %t", form.Remember)
err = ctx.Session.Set("openid_signin_remember", form.Remember)
if err != nil { if err := ctx.Session.Set("openid_signin_remember", form.Remember); err != nil {
log.Error("SignInOpenIDPost: Could not set session: %v", err.Error()) log.Error("SignInOpenIDPost: Could not set openid_signin_remember in session: %v", err)
}
if err := ctx.Session.Release(); err != nil {
log.Error("SignInOpenIDPost: Unable to save changes to the session: %v", err)
} }
ctx.Redirect(url) ctx.Redirect(url)
@@ -227,23 +230,22 @@ func signInOpenIDVerify(ctx *context.Context) {
} }
} }
err = ctx.Session.Set("openid_verified_uri", id) if err := ctx.Session.Set("openid_verified_uri", id); err != nil {
if err != nil { log.Error("signInOpenIDVerify: Could not set openid_verified_uri in session: %v", err)
log.Error("signInOpenIDVerify: Could not set session: %v", err.Error())
} }
if err := ctx.Session.Set("openid_determined_email", email); err != nil {
err = ctx.Session.Set("openid_determined_email", email) log.Error("signInOpenIDVerify: Could not set openid_determined_email in session: %v", err)
if err != nil {
log.Error("signInOpenIDVerify: Could not set session: %v", err.Error())
} }
if u != nil { if u != nil {
nickname = u.LowerName nickname = u.LowerName
} }
err = ctx.Session.Set("openid_determined_username", nickname) if err := ctx.Session.Set("openid_determined_username", nickname); err != nil {
if err != nil { log.Error("signInOpenIDVerify: Could not set openid_determined_username in session: %v", err)
log.Error("signInOpenIDVerify: Could not set session: %v", err.Error()) }
if err := ctx.Session.Release(); err != nil {
log.Error("signInOpenIDVerify: Unable to save changes to the session: %v", err)
} }
if u != nil || !setting.Service.EnableOpenIDSignUp { if u != nil || !setting.Service.EnableOpenIDSignUp {

View File

@@ -229,6 +229,11 @@ func AuthorizeOAuth(ctx *context.Context, form auth.AuthorizationForm) {
}, form.RedirectURI) }, form.RedirectURI)
return return
} }
// Here we're just going to try to release the session early
if err := ctx.Session.Release(); err != nil {
// we'll tolerate errors here as they *should* get saved elsewhere
log.Error("Unable to save changes to the session: %v", err)
}
case "": case "":
break break
default: default:
@@ -287,6 +292,11 @@ func AuthorizeOAuth(ctx *context.Context, form auth.AuthorizationForm) {
log.Error(err.Error()) log.Error(err.Error())
return return
} }
// Here we're just going to try to release the session early
if err := ctx.Session.Release(); err != nil {
// we'll tolerate errors here as they *should* get saved elsewhere
log.Error("Unable to save changes to the session: %v", err)
}
ctx.HTML(200, tplGrantAccess) ctx.HTML(200, tplGrantAccess)
} }

View File

@@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"github.com/pquerna/otp" "github.com/pquerna/otp"
@@ -28,18 +29,22 @@ func RegenerateScratchTwoFactor(ctx *context.Context) {
t, err := models.GetTwoFactorByUID(ctx.User.ID) t, err := models.GetTwoFactorByUID(ctx.User.ID)
if err != nil { if err != nil {
ctx.ServerError("SettingsTwoFactor", err) if models.IsErrTwoFactorNotEnrolled(err) {
ctx.Flash.Error(ctx.Tr("setting.twofa_not_enrolled"))
ctx.Redirect(setting.AppSubURL + "/user/settings/security")
}
ctx.ServerError("SettingsTwoFactor: Failed to GetTwoFactorByUID", err)
return return
} }
token, err := t.GenerateScratchToken() token, err := t.GenerateScratchToken()
if err != nil { if err != nil {
ctx.ServerError("SettingsTwoFactor", err) ctx.ServerError("SettingsTwoFactor: Failed to GenerateScratchToken", err)
return return
} }
if err = models.UpdateTwoFactor(t); err != nil { if err = models.UpdateTwoFactor(t); err != nil {
ctx.ServerError("SettingsTwoFactor", err) ctx.ServerError("SettingsTwoFactor: Failed to UpdateTwoFactor", err)
return return
} }
@@ -54,12 +59,21 @@ func DisableTwoFactor(ctx *context.Context) {
t, err := models.GetTwoFactorByUID(ctx.User.ID) t, err := models.GetTwoFactorByUID(ctx.User.ID)
if err != nil { if err != nil {
ctx.ServerError("SettingsTwoFactor", err) if models.IsErrTwoFactorNotEnrolled(err) {
ctx.Flash.Error(ctx.Tr("setting.twofa_not_enrolled"))
ctx.Redirect(setting.AppSubURL + "/user/settings/security")
}
ctx.ServerError("SettingsTwoFactor: Failed to GetTwoFactorByUID", err)
return return
} }
if err = models.DeleteTwoFactorByID(t.ID, ctx.User.ID); err != nil { if err = models.DeleteTwoFactorByID(t.ID, ctx.User.ID); err != nil {
ctx.ServerError("SettingsTwoFactor", err) if models.IsErrTwoFactorNotEnrolled(err) {
// There is a potential DB race here - we must have been disabled by another request in the intervening period
ctx.Flash.Success(ctx.Tr("settings.twofa_disabled"))
ctx.Redirect(setting.AppSubURL + "/user/settings/security")
}
ctx.ServerError("SettingsTwoFactor: Failed to DeleteTwoFactorByID", err)
return return
} }
@@ -74,7 +88,7 @@ func twofaGenerateSecretAndQr(ctx *context.Context) bool {
if uri != nil { if uri != nil {
otpKey, err = otp.NewKeyFromURL(uri.(string)) otpKey, err = otp.NewKeyFromURL(uri.(string))
if err != nil { if err != nil {
ctx.ServerError("SettingsTwoFactor: NewKeyFromURL: ", err) ctx.ServerError("SettingsTwoFactor: Failed NewKeyFromURL: ", err)
return false return false
} }
} }
@@ -87,7 +101,7 @@ func twofaGenerateSecretAndQr(ctx *context.Context) bool {
AccountName: ctx.User.Name, AccountName: ctx.User.Name,
}) })
if err != nil { if err != nil {
ctx.ServerError("SettingsTwoFactor", err) ctx.ServerError("SettingsTwoFactor: totpGenerate Failed", err)
return false return false
} }
} }
@@ -95,27 +109,33 @@ func twofaGenerateSecretAndQr(ctx *context.Context) bool {
ctx.Data["TwofaSecret"] = otpKey.Secret() ctx.Data["TwofaSecret"] = otpKey.Secret()
img, err := otpKey.Image(320, 240) img, err := otpKey.Image(320, 240)
if err != nil { if err != nil {
ctx.ServerError("SettingsTwoFactor", err) ctx.ServerError("SettingsTwoFactor: otpKey image generation failed", err)
return false return false
} }
var imgBytes bytes.Buffer var imgBytes bytes.Buffer
if err = png.Encode(&imgBytes, img); err != nil { if err = png.Encode(&imgBytes, img); err != nil {
ctx.ServerError("SettingsTwoFactor", err) ctx.ServerError("SettingsTwoFactor: otpKey png encoding failed", err)
return false return false
} }
ctx.Data["QrUri"] = template.URL("data:image/png;base64," + base64.StdEncoding.EncodeToString(imgBytes.Bytes())) ctx.Data["QrUri"] = template.URL("data:image/png;base64," + base64.StdEncoding.EncodeToString(imgBytes.Bytes()))
err = ctx.Session.Set("twofaSecret", otpKey.Secret())
if err != nil { if err := ctx.Session.Set("twofaSecret", otpKey.Secret()); err != nil {
ctx.ServerError("SettingsTwoFactor", err) ctx.ServerError("SettingsTwoFactor: Failed to set session for twofaSecret", err)
return false return false
} }
err = ctx.Session.Set("twofaUri", otpKey.String())
if err != nil { if err := ctx.Session.Set("twofaUri", otpKey.String()); err != nil {
ctx.ServerError("SettingsTwoFactor", err) ctx.ServerError("SettingsTwoFactor: Failed to set session for twofaUri", err)
return false return false
} }
// Here we're just going to try to release the session early
if err := ctx.Session.Release(); err != nil {
// we'll tolerate errors here as they *should* get saved elsewhere
log.Error("Unable to save changes to the session: %v", err)
}
return true return true
} }
@@ -126,12 +146,14 @@ func EnrollTwoFactor(ctx *context.Context) {
t, err := models.GetTwoFactorByUID(ctx.User.ID) t, err := models.GetTwoFactorByUID(ctx.User.ID)
if t != nil { if t != nil {
// already enrolled // already enrolled - we should redirect back!
ctx.ServerError("SettingsTwoFactor", err) log.Warn("Trying to re-enroll %-v in twofa when already enrolled", ctx.User)
ctx.Flash.Error(ctx.Tr("setting.twofa_is_enrolled"))
ctx.Redirect(setting.AppSubURL + "/user/settings/security")
return return
} }
if err != nil && !models.IsErrTwoFactorNotEnrolled(err) { if err != nil && !models.IsErrTwoFactorNotEnrolled(err) {
ctx.ServerError("SettingsTwoFactor", err) ctx.ServerError("SettingsTwoFactor: GetTwoFactorByUID", err)
return return
} }
@@ -150,11 +172,12 @@ func EnrollTwoFactorPost(ctx *context.Context, form auth.TwoFactorAuthForm) {
t, err := models.GetTwoFactorByUID(ctx.User.ID) t, err := models.GetTwoFactorByUID(ctx.User.ID)
if t != nil { if t != nil {
// already enrolled // already enrolled
ctx.ServerError("SettingsTwoFactor", err) ctx.Flash.Error(ctx.Tr("setting.twofa_is_enrolled"))
ctx.Redirect(setting.AppSubURL + "/user/settings/security")
return return
} }
if err != nil && !models.IsErrTwoFactorNotEnrolled(err) { if err != nil && !models.IsErrTwoFactorNotEnrolled(err) {
ctx.ServerError("SettingsTwoFactor", err) ctx.ServerError("SettingsTwoFactor: Failed to check if already enrolled with GetTwoFactorByUID", err)
return return
} }
@@ -181,30 +204,37 @@ func EnrollTwoFactorPost(ctx *context.Context, form auth.TwoFactorAuthForm) {
} }
err = t.SetSecret(secret) err = t.SetSecret(secret)
if err != nil { if err != nil {
ctx.ServerError("SettingsTwoFactor", err) ctx.ServerError("SettingsTwoFactor: Failed to set secret", err)
return return
} }
token, err := t.GenerateScratchToken() token, err := t.GenerateScratchToken()
if err != nil { if err != nil {
ctx.ServerError("SettingsTwoFactor", err) ctx.ServerError("SettingsTwoFactor: Failed to generate scratch token", err)
return return
} }
// Now we have to delete the secrets - because if we fail to insert then it's highly likely that they have already been used
// If we can detect the unique constraint failure below we can move this to after the NewTwoFactor
if err := ctx.Session.Delete("twofaSecret"); err != nil {
// tolerate this failure - it's more important to continue
log.Error("Unable to delete twofaSecret from the session: Error: %v", err)
}
if err := ctx.Session.Delete("twofaUri"); err != nil {
// tolerate this failure - it's more important to continue
log.Error("Unable to delete twofaUri from the session: Error: %v", err)
}
if err := ctx.Session.Release(); err != nil {
// tolerate this failure - it's more important to continue
log.Error("Unable to save changes to the session: %v", err)
}
if err = models.NewTwoFactor(t); err != nil { if err = models.NewTwoFactor(t); err != nil {
ctx.ServerError("SettingsTwoFactor", err) // FIXME: We need to handle a unique constraint fail here it's entirely possible that another request has beaten us.
// If there is a unique constraint fail we should just tolerate the error
ctx.ServerError("SettingsTwoFactor: Failed to save two factor", err)
return return
} }
err = ctx.Session.Delete("twofaSecret")
if err != nil {
ctx.ServerError("SettingsTwoFactor", err)
return
}
err = ctx.Session.Delete("twofaUri")
if err != nil {
ctx.ServerError("SettingsTwoFactor", err)
return
}
ctx.Flash.Success(ctx.Tr("settings.twofa_enrolled", token)) ctx.Flash.Success(ctx.Tr("settings.twofa_enrolled", token))
ctx.Redirect(setting.AppSubURL + "/user/settings/security") ctx.Redirect(setting.AppSubURL + "/user/settings/security")
} }

View File

@@ -10,6 +10,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"github.com/tstranex/u2f" "github.com/tstranex/u2f"
@@ -26,9 +27,8 @@ func U2FRegister(ctx *context.Context, form auth.U2FRegistrationForm) {
ctx.ServerError("NewChallenge", err) ctx.ServerError("NewChallenge", err)
return return
} }
err = ctx.Session.Set("u2fChallenge", challenge) if err := ctx.Session.Set("u2fChallenge", challenge); err != nil {
if err != nil { ctx.ServerError("Unable to set session key for u2fChallenge", err)
ctx.ServerError("Session.Set", err)
return return
} }
regs, err := models.GetU2FRegistrationsByUID(ctx.User.ID) regs, err := models.GetU2FRegistrationsByUID(ctx.User.ID)
@@ -42,11 +42,15 @@ func U2FRegister(ctx *context.Context, form auth.U2FRegistrationForm) {
return return
} }
} }
err = ctx.Session.Set("u2fName", form.Name) if err := ctx.Session.Set("u2fName", form.Name); err != nil {
if err != nil { ctx.ServerError("Unable to set session key for u2fName", err)
ctx.ServerError("", err)
return return
} }
// Here we're just going to try to release the session early
if err := ctx.Session.Release(); err != nil {
// we'll tolerate errors here as they *should* get saved elsewhere
log.Error("Unable to save changes to the session: %v", err)
}
ctx.JSON(200, u2f.NewWebRegisterRequest(challenge, regs.ToRegistrations())) ctx.JSON(200, u2f.NewWebRegisterRequest(challenge, regs.ToRegistrations()))
} }

View File

@@ -84,7 +84,11 @@
for the JavaScript code in this page. for the JavaScript code in this page.
*/`}} */`}}
</script> </script>
<script>
window.config = {
StaticUrlPrefix: '{{StaticUrlPrefix}}'
}
</script>
<link rel="shortcut icon" href="{{StaticUrlPrefix}}/img/favicon.png" /> <link rel="shortcut icon" href="{{StaticUrlPrefix}}/img/favicon.png" />
<link rel="mask-icon" href="{{StaticUrlPrefix}}/img/gitea-safari.svg" color="#609926"> <link rel="mask-icon" href="{{StaticUrlPrefix}}/img/gitea-safari.svg" color="#609926">
<link rel="preload" href="{{StaticUrlPrefix}}/vendor/assets/font-awesome/css/font-awesome.min.css" as="style" onload="this.rel='stylesheet'"> <link rel="preload" href="{{StaticUrlPrefix}}/vendor/assets/font-awesome/css/font-awesome.min.css" as="style" onload="this.rel='stylesheet'">

View File

@@ -21,7 +21,7 @@
<div class="field"> <div class="field">
<label>{{.i18n.Tr "repo.settings.content_type"}}</label> <label>{{.i18n.Tr "repo.settings.content_type"}}</label>
<div class="ui selection dropdown"> <div class="ui selection dropdown">
<input type="hidden" id="content_type" name="content_type" value="{{if .Webhook.ContentType}}{{.Webhook.ContentType}}{{else}}application/json{{end}}"> <input type="hidden" id="content_type" name="content_type" value="{{if .Webhook.ContentType}}{{.Webhook.ContentType}}{{else}}1{{end}}">
<div class="default text"></div> <div class="default text"></div>
<i class="dropdown icon"></i> <i class="dropdown icon"></i>
<div class="menu"> <div class="menu">

View File

@@ -9,7 +9,7 @@
<div class="field"> <div class="field">
<label>{{.i18n.Tr "repo.settings.content_type"}}</label> <label>{{.i18n.Tr "repo.settings.content_type"}}</label>
<div class="ui selection dropdown"> <div class="ui selection dropdown">
<input type="hidden" id="content_type" name="content_type" value="{{if .Webhook.ContentType}}{{.Webhook.ContentType}}{{else}}application/json{{end}}"> <input type="hidden" id="content_type" name="content_type" value="{{if .Webhook.ContentType}}{{.Webhook.ContentType}}{{else}}1{{end}}">
<div class="default text"></div> <div class="default text"></div>
<i class="dropdown icon"></i> <i class="dropdown icon"></i>
<div class="menu"> <div class="menu">

View File

@@ -21,7 +21,7 @@
{{else if and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}} {{else if and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}}
<input id="repo-clone-url" value="{{$.WikiCloneLink.SSH}}" readonly> <input id="repo-clone-url" value="{{$.WikiCloneLink.SSH}}" readonly>
{{end}} {{end}}
{{if or ((not $.DisableHTTP) (and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH)))}} {{if or (not $.DisableHTTP) (and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH))}}
<button class="ui basic icon button poping up clipboard" id="clipboard-btn" data-original="{{.i18n.Tr "repo.copy_link"}}" data-success="{{.i18n.Tr "repo.copy_link_success"}}" data-error="{{.i18n.Tr "repo.copy_link_error"}}" data-content="{{.i18n.Tr "repo.copy_link"}}" data-variation="inverted tiny" data-clipboard-target="#repo-clone-url"> <button class="ui basic icon button poping up clipboard" id="clipboard-btn" data-original="{{.i18n.Tr "repo.copy_link"}}" data-success="{{.i18n.Tr "repo.copy_link_success"}}" data-error="{{.i18n.Tr "repo.copy_link_error"}}" data-content="{{.i18n.Tr "repo.copy_link"}}" data-variation="inverted tiny" data-clipboard-target="#repo-clone-url">
<i class="octicon octicon-clippy"></i> <i class="octicon octicon-clippy"></i>
</button> </button>

View File

@@ -45,7 +45,7 @@
{{else if and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}} {{else if and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}}
<input id="repo-clone-url" value="{{$.WikiCloneLink.SSH}}" readonly> <input id="repo-clone-url" value="{{$.WikiCloneLink.SSH}}" readonly>
{{end}} {{end}}
{{if or ((not $.DisableHTTP) (and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH)))}} {{if or (not $.DisableHTTP) (and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH))}}
<button class="ui basic icon button poping up clipboard" id="clipboard-btn" data-original="{{.i18n.Tr "repo.copy_link"}}" data-success="{{.i18n.Tr "repo.copy_link_success"}}" data-error="{{.i18n.Tr "repo.copy_link_error"}}" data-content="{{.i18n.Tr "repo.copy_link"}}" data-variation="inverted tiny" data-clipboard-target="#repo-clone-url"> <button class="ui basic icon button poping up clipboard" id="clipboard-btn" data-original="{{.i18n.Tr "repo.copy_link"}}" data-success="{{.i18n.Tr "repo.copy_link_success"}}" data-error="{{.i18n.Tr "repo.copy_link_error"}}" data-content="{{.i18n.Tr "repo.copy_link"}}" data-variation="inverted tiny" data-clipboard-target="#repo-clone-url">
<i class="octicon octicon-clippy"></i> <i class="octicon octicon-clippy"></i>
</button> </button>

View File

@@ -1,8 +1,10 @@
/* This sets up webpack's chunk loading to load resources from the same // This sets up the URL prefix used in webpack's chunk loading.
directory where it loaded index.js from. This file must be imported // This file must be imported before any lazy-loading is being attempted.
before any lazy-loading is being attempted. */ const { StaticUrlPrefix } = window.config;
if (document.currentScript && document.currentScript.src) { if (StaticUrlPrefix) {
__webpack_public_path__ = `${StaticUrlPrefix.endsWith('/') ? StaticUrlPrefix : `${StaticUrlPrefix}/`}js/`;
} else if (document.currentScript && document.currentScript.src) {
const url = new URL(document.currentScript.src); const url = new URL(document.currentScript.src);
__webpack_public_path__ = `${url.pathname.replace(/\/[^/]*$/, '')}/`; __webpack_public_path__ = `${url.pathname.replace(/\/[^/]*$/, '')}/`;
} else { } else {