mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-13 02:02:53 +09:00
Compare commits
26 Commits
v1.11.5
...
release/v1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34fe3d390b | ||
|
|
ce51c2bdf6 | ||
|
|
7937f1463a | ||
|
|
dbe9c11238 | ||
|
|
313ace93d0 | ||
|
|
f79a2e193f | ||
|
|
5d4251eb78 | ||
|
|
88008b681d | ||
|
|
5462fdcbbd | ||
|
|
161e550200 | ||
|
|
95af6096fb | ||
|
|
801f4b9e7a | ||
|
|
c0c3a533a0 | ||
|
|
ed646078e1 | ||
|
|
dc0ea133e1 | ||
|
|
a854846f06 | ||
|
|
b52e8de7de | ||
|
|
1b62916393 | ||
|
|
1d57c309ef | ||
|
|
cf97e65b66 | ||
|
|
42a46cff35 | ||
|
|
2cb3db2d20 | ||
|
|
04e480d477 | ||
|
|
de9a96c4de | ||
|
|
878434146f | ||
|
|
d78be7ddf9 |
35
CHANGELOG.md
35
CHANGELOG.md
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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-----
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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!")
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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'">
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user