Skip to content

Commit 2329882

Browse files
committed
Merge remote-tracking branch 'giteaofficial/main'
* giteaofficial/main: Frontport Changelogs (go-gitea#19088) Restrict email address validation (go-gitea#17688) Fix lfs bug (go-gitea#19072)
2 parents d46050d + 2ba72ce commit 2329882

File tree

14 files changed

+291
-12
lines changed

14 files changed

+291
-12
lines changed

CHANGELOG.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,105 @@ This changelog goes through all the changes that have been made in each release
44
without substantial changes to our git log; to see the highlights of what has
55
been added to each release, please refer to the [blog](https://blog.gitea.io).
66

7+
## [1.16.4](https://github.com/go-gitea/gitea/releases/tag/v1.16.4) - 2022-03-14
8+
9+
* SECURITY
10+
* Restrict email address validation (#17688) (#19085)
11+
* Fix lfs bug (#19072) (#19080)
12+
* ENHANCEMENTS
13+
* Improve SyncMirrors logging (#19045) (#19050)
14+
* BUGFIXES
15+
* Refactor mirror code & fix `StartToMirror` (#18904) (#19075)
16+
* Update the webauthn_credential_id_sequence in Postgres (#19048) (#19060)
17+
* Prevent 500 when there is an error during new auth source post (#19041) (#19059)
18+
* If rendering has failed due to a net.OpError stop rendering (attempt 2) (#19049) (#19056)
19+
* Fix flag validation (#19046) (#19051)
20+
* Add pam account authorization check (#19040) (#19047)
21+
* Ignore missing comment for user notifications (#18954) (#19043)
22+
* Set `rel="nofollow noindex"` on new issue links (#19023) (#19042)
23+
* Upgrading binding package (#19034) (#19035)
24+
* Don't show context cancelled errors in attribute reader (#19006) (#19027)
25+
* Fix update hint bug (#18996) (#19002)
26+
* MISC
27+
* Fix potential assignee query for repo (#18994) (#18999)
28+
29+
## [1.16.3](https://github.com/go-gitea/gitea/releases/tag/v1.16.3) - 2022-03-02
30+
31+
* SECURITY
32+
* Git backend ignore replace objects (#18979) (#18980)
33+
* ENHANCEMENTS
34+
* Adjust error for already locked db and prevent level db lock on malformed connstr (#18923) (#18938)
35+
* BUGFIXES
36+
* Set max text height to prevent overflow (#18862) (#18977)
37+
* Fix newAttachmentPaths deletion for DeleteRepository() (#18973) (#18974)
38+
* Accounts with WebAuthn only (no TOTP) now exist ... fix code to handle that case (#18897) (#18964)
39+
* Send 404 on `/{org}.gpg` (#18959) (#18962)
40+
* Fix admin user list pagination (#18957) (#18960)
41+
* Fix lfs management setting (#18947) (#18946)
42+
* Fix login with email panic when email is not exist (#18942)
43+
* Update go-org to v1.6.1 (#18932) (#18933)
44+
* Fix `<strong>` html in translation (#18929) (#18931)
45+
* Fix page and missing return on unadopted repos API (#18848) (#18927)
46+
* Allow adminstrator teams members to see other teams (#18918) (#18919)
47+
* Don't treat BOM escape sequence as hidden character. (#18909) (#18910)
48+
* Correctly link URLs to users/repos with dashes, dots or underscores (… (#18908)
49+
* Fix redirect when using lowercase repo name (#18775) (#18902)
50+
* Fix migration v210 (#18893) (#18892)
51+
* Fix team management UI (#18887) (18886)
52+
* BeforeSourcePath should point to base commit (#18880) (#18799)
53+
* TRANSLATION
54+
* Backport locales from master (#18944)
55+
* MISC
56+
* Don't update email for organisation (#18905) (#18906)
57+
58+
## [1.16.2](https://github.com/go-gitea/gitea/releases/tag/v1.16.2) - 2022-02-24
59+
60+
* ENHANCEMENTS
61+
* Show fullname on issue edits and gpg/ssh signing info (#18828)
62+
* Immediately Hammer if second kill is sent (#18823) (#18826)
63+
* Allow mermaid render error to wrap (#18791)
64+
* BUGFIXES
65+
* Fix ldap user sync missed email in email_address table (#18786) (#18876)
66+
* Update assignees check to include any writing team and change org sidebar (#18680) (#18873)
67+
* Don't report signal: killed errors in serviceRPC (#18850) (#18865)
68+
* Fix bug where certain LDAP settings were reverted (#18859)
69+
* Update go-org to 1.6.0 (#18824) (#18839)
70+
* Fix login with email for ldap users (#18800) (#18836)
71+
* Fix bug for get user by email (#18834)
72+
* Fix panic in EscapeReader (#18820) (#18821)
73+
* Fix ldap loginname (#18789) (#18804)
74+
* Remove redundant call to UpdateRepoStats during migration (#18591) (#18794)
75+
* In disk_channel queues synchronously push to disk on shutdown (#18415) (#18788)
76+
* Fix template bug of LFS lock (#18784) (#18787)
77+
* Attempt to fix the webauthn migration again - part 3 (#18770) (#18771)
78+
* Send mail to issue/pr assignee/reviewer also when OnMention is set (#18707) (#18765)
79+
* Fix a broken link in commits_list_small.tmpl (#18763) (#18764)
80+
* Increase the size of the webauthn_credential credential_id field (#18739) (#18756)
81+
* Prevent dangling GetAttribute calls (#18754) (#18755)
82+
* Fix isempty detection of git repository (#18746) (#18750)
83+
* Fix source code line highlighting on external tracker (#18729) (#18740)
84+
* Prevent double encoding of branch names in delete branch (#18714) (#18738)
85+
* Always set PullRequestWorkInProgressPrefixes in PrepareViewPullInfo (#18713) (#18737)
86+
* Fix forked repositories missed tags (#18719) (#18735)
87+
* Fix release typo (#18728) (#18731)
88+
* Separate the details links of commit-statuses in headers (#18661) (#18730)
89+
* Update object repo with the migrated repository (#18684) (#18726)
90+
* Fix bug for version update hint (#18701) (#18705)
91+
* Fix issue with docker-rootless shimming script (#18690) (#18699)
92+
* Let `MinUnitAccessMode` return correct perm (#18675) (#18689)
93+
* Prevent security failure due to bad APP_ID (#18678) (#18682)
94+
* Restart zero worker if there is still work to do (#18658) (#18672)
95+
* If rendering has failed due to a net.OpError stop rendering (#18642) (#18645)
96+
* TESTING
97+
* Ensure git tag tests and others create test repos in tmpdir (#18447) (#18767)
98+
* BUILD
99+
* Reduce CI go module downloads, add make targets (#18708, #18475, #18443) (#18741)
100+
* MISC
101+
* Put buttons back in org dashboard (#18817) (#18825)
102+
* Various Mermaid improvements (#18776) (#18780)
103+
* C preprocessor colors improvement (#18671) (#18696)
104+
* Fix the missing i18n key for update checker (#18646) (#18665)
105+
7106
## [1.16.1](https://github.com/go-gitea/gitea/releases/tag/v1.16.1) - 2022-02-06
8107

9108
* SECURITY

docs/config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ params:
1818
description: Git with a cup of tea
1919
author: The Gitea Authors
2020
website: https://docs.gitea.io
21-
version: 1.16.3
21+
version: 1.16.4
2222
minGoVersion: 1.16
2323
goVersion: 1.17
2424
minNodeVersion: 12.17

models/user/email_address.go

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"errors"
1111
"fmt"
1212
"net/mail"
13+
"regexp"
1314
"strings"
1415

1516
"code.gitea.io/gitea/models/db"
@@ -22,7 +23,22 @@ import (
2223
)
2324

2425
// ErrEmailNotActivated e-mail address has not been activated error
25-
var ErrEmailNotActivated = errors.New("E-mail address has not been activated")
26+
var ErrEmailNotActivated = errors.New("e-mail address has not been activated")
27+
28+
// ErrEmailCharIsNotSupported e-mail address contains unsupported character
29+
type ErrEmailCharIsNotSupported struct {
30+
Email string
31+
}
32+
33+
// IsErrEmailCharIsNotSupported checks if an error is an ErrEmailCharIsNotSupported
34+
func IsErrEmailCharIsNotSupported(err error) bool {
35+
_, ok := err.(ErrEmailCharIsNotSupported)
36+
return ok
37+
}
38+
39+
func (err ErrEmailCharIsNotSupported) Error() string {
40+
return fmt.Sprintf("e-mail address contains unsupported character [email: %s]", err.Email)
41+
}
2642

2743
// ErrEmailInvalid represents an error where the email address does not comply with RFC 5322
2844
type ErrEmailInvalid struct {
@@ -106,12 +122,24 @@ func (email *EmailAddress) BeforeInsert() {
106122
}
107123
}
108124

125+
var emailRegexp = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
126+
109127
// ValidateEmail check if email is a allowed address
110128
func ValidateEmail(email string) error {
111129
if len(email) == 0 {
112130
return nil
113131
}
114132

133+
if !emailRegexp.MatchString(email) {
134+
return ErrEmailCharIsNotSupported{email}
135+
}
136+
137+
if !(email[0] >= 'a' && email[0] <= 'z') &&
138+
!(email[0] >= 'A' && email[0] <= 'Z') &&
139+
!(email[0] >= '0' && email[0] <= '9') {
140+
return ErrEmailInvalid{email}
141+
}
142+
115143
if _, err := mail.ParseAddress(email); err != nil {
116144
return ErrEmailInvalid{email}
117145
}

models/user/email_address_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,3 +252,58 @@ func TestListEmails(t *testing.T) {
252252
assert.Len(t, emails, 5)
253253
assert.Greater(t, count, int64(len(emails)))
254254
}
255+
256+
func TestEmailAddressValidate(t *testing.T) {
257+
kases := map[string]error{
258+
259+
260+
261+
262+
263+
264+
265+
`first#[email protected]`: nil,
266+
267+
`first%[email protected]`: nil,
268+
`first&[email protected]`: nil,
269+
`first'[email protected]`: nil,
270+
`first*[email protected]`: nil,
271+
272+
`first/[email protected]`: nil,
273+
274+
275+
`first^[email protected]`: nil,
276+
"first`[email protected]": nil,
277+
`first{[email protected]`: nil,
278+
`first|[email protected]`: nil,
279+
`first}[email protected]`: nil,
280+
281+
`first;[email protected]`: ErrEmailCharIsNotSupported{`first;[email protected]`},
282+
"[email protected]": ErrEmailInvalid{"[email protected]"},
283+
"[email protected]": ErrEmailInvalid{"[email protected]"},
284+
"#[email protected]": ErrEmailInvalid{"#[email protected]"},
285+
"[email protected]": ErrEmailInvalid{"[email protected]"},
286+
"%[email protected]": ErrEmailInvalid{"%[email protected]"},
287+
"&[email protected]": ErrEmailInvalid{"&[email protected]"},
288+
"'[email protected]": ErrEmailInvalid{"'[email protected]"},
289+
"*[email protected]": ErrEmailInvalid{"*[email protected]"},
290+
"[email protected]": ErrEmailInvalid{"[email protected]"},
291+
"/[email protected]": ErrEmailInvalid{"/[email protected]"},
292+
"[email protected]": ErrEmailInvalid{"[email protected]"},
293+
"[email protected]": ErrEmailInvalid{"[email protected]"},
294+
"^[email protected]": ErrEmailInvalid{"^[email protected]"},
295+
"`[email protected]": ErrEmailInvalid{"`[email protected]"},
296+
"{[email protected]": ErrEmailInvalid{"{[email protected]"},
297+
"|[email protected]": ErrEmailInvalid{"|[email protected]"},
298+
"}[email protected]": ErrEmailInvalid{"}[email protected]"},
299+
"[email protected]": ErrEmailInvalid{"[email protected]"},
300+
";[email protected]": ErrEmailCharIsNotSupported{";[email protected]"},
301+
"Foo <[email protected]>": ErrEmailCharIsNotSupported{"Foo <[email protected]>"},
302+
string([]byte{0xE2, 0x84, 0xAA}): ErrEmailCharIsNotSupported{string([]byte{0xE2, 0x84, 0xAA})},
303+
}
304+
for kase, err := range kases {
305+
t.Run(kase, func(t *testing.T) {
306+
assert.EqualValues(t, err, ValidateEmail(kase))
307+
})
308+
}
309+
}

models/user/user.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,15 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e
644644
u.Visibility = overwriteDefault[0].Visibility
645645
}
646646

647+
// validate data
648+
if err := validateUser(u); err != nil {
649+
return err
650+
}
651+
652+
if err := ValidateEmail(u.Email); err != nil {
653+
return err
654+
}
655+
647656
ctx, committer, err := db.TxContext()
648657
if err != nil {
649658
return err
@@ -652,11 +661,6 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e
652661

653662
sess := db.GetEngine(ctx)
654663

655-
// validate data
656-
if err := validateUser(u); err != nil {
657-
return err
658-
}
659-
660664
isExist, err := isUserExist(sess, 0, u.Name)
661665
if err != nil {
662666
return err

models/user/user_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ func TestCreateUserInvalidEmail(t *testing.T) {
232232

233233
err := CreateUser(user)
234234
assert.Error(t, err)
235-
assert.True(t, IsErrEmailInvalid(err))
235+
assert.True(t, IsErrEmailCharIsNotSupported(err))
236236
}
237237

238238
func TestCreateUserEmailAlreadyUsed(t *testing.T) {

modules/storage/local.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,20 @@ package storage
66

77
import (
88
"context"
9+
"errors"
910
"io"
1011
"net/url"
1112
"os"
13+
"path"
1214
"path/filepath"
15+
"strings"
1316

1417
"code.gitea.io/gitea/modules/log"
1518
"code.gitea.io/gitea/modules/util"
1619
)
1720

21+
// ErrLocalPathNotSupported represents an error that path is not supported
22+
var ErrLocalPathNotSupported = errors.New("local path is not supported")
1823
var _ ObjectStorage = &LocalStorage{}
1924

2025
// LocalStorageType is the type descriptor for local storage
@@ -59,11 +64,18 @@ func NewLocalStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error
5964

6065
// Open a file
6166
func (l *LocalStorage) Open(path string) (Object, error) {
67+
if !isLocalPathValid(path) {
68+
return nil, ErrLocalPathNotSupported
69+
}
6270
return os.Open(filepath.Join(l.dir, path))
6371
}
6472

6573
// Save a file
6674
func (l *LocalStorage) Save(path string, r io.Reader, size int64) (int64, error) {
75+
if !isLocalPathValid(path) {
76+
return 0, ErrLocalPathNotSupported
77+
}
78+
6779
p := filepath.Join(l.dir, path)
6880
if err := os.MkdirAll(filepath.Dir(p), os.ModePerm); err != nil {
6981
return 0, err
@@ -107,8 +119,19 @@ func (l *LocalStorage) Stat(path string) (os.FileInfo, error) {
107119
return os.Stat(filepath.Join(l.dir, path))
108120
}
109121

122+
func isLocalPathValid(p string) bool {
123+
a := path.Clean(p)
124+
if strings.HasPrefix(a, "../") || strings.HasPrefix(a, "..\\") {
125+
return false
126+
}
127+
return a == p
128+
}
129+
110130
// Delete delete a file
111131
func (l *LocalStorage) Delete(path string) error {
132+
if !isLocalPathValid(path) {
133+
return ErrLocalPathNotSupported
134+
}
112135
p := filepath.Join(l.dir, path)
113136
return util.Remove(p)
114137
}

modules/storage/local_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package storage
6+
7+
import (
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestLocalPathIsValid(t *testing.T) {
14+
kases := []struct {
15+
path string
16+
valid bool
17+
}{
18+
{
19+
"a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
20+
true,
21+
},
22+
{
23+
"../a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
24+
false,
25+
},
26+
{
27+
"a\\0\\a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
28+
true,
29+
},
30+
{
31+
"b/../a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
32+
false,
33+
},
34+
{
35+
"..\\a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
36+
false,
37+
},
38+
}
39+
40+
for _, k := range kases {
41+
t.Run(k.path, func(t *testing.T) {
42+
assert.EqualValues(t, k.valid, isLocalPathValid(k.path))
43+
})
44+
}
45+
}

routers/api/v1/admin/user.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ func CreateUser(ctx *context.APIContext) {
119119
user_model.IsErrEmailAlreadyUsed(err) ||
120120
db.IsErrNameReserved(err) ||
121121
db.IsErrNameCharsNotAllowed(err) ||
122+
user_model.IsErrEmailCharIsNotSupported(err) ||
122123
user_model.IsErrEmailInvalid(err) ||
123124
db.IsErrNamePatternNotAllowed(err) {
124125
ctx.Error(http.StatusUnprocessableEntity, "", err)
@@ -265,7 +266,9 @@ func EditUser(ctx *context.APIContext) {
265266
}
266267

267268
if err := user_model.UpdateUser(u, emailChanged); err != nil {
268-
if user_model.IsErrEmailAlreadyUsed(err) || user_model.IsErrEmailInvalid(err) {
269+
if user_model.IsErrEmailAlreadyUsed(err) ||
270+
user_model.IsErrEmailCharIsNotSupported(err) ||
271+
user_model.IsErrEmailInvalid(err) {
269272
ctx.Error(http.StatusUnprocessableEntity, "", err)
270273
} else {
271274
ctx.Error(http.StatusInternalServerError, "UpdateUser", err)

0 commit comments

Comments
 (0)