Skip to content

Commit 44371b9

Browse files
zeripathlafriks
authored andcommitted
Ensure valid git author names passed in signatures (#5774)
* Ensure valid git author names passed in signatures Fix #5772 - Git author names are not allowed to include `\n` `<` or `>` and must not be empty. Ensure that the name passed in a signature is valid. * Account for pathologically named external users LDAP and the like usernames are not checked in the same way that users who signup are. Therefore just ensure that user names are also git safe and if totally pathological - Set them to "user-$UID" * Add Tests and adjust test users Make our testcases a little more pathological so that we be sure that integration tests have a chance to spot these cases. Signed-off-by: Andrew Thornton <[email protected]>
1 parent cd83c2c commit 44371b9

File tree

6 files changed

+72
-13
lines changed

6 files changed

+72
-13
lines changed

integrations/api_user_orgs_test.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import (
99
"net/http"
1010
"testing"
1111

12+
"code.gitea.io/gitea/models"
1213
api "code.gitea.io/sdk/gitea"
14+
1315
"github.com/stretchr/testify/assert"
1416
)
1517

@@ -23,14 +25,16 @@ func TestUserOrgs(t *testing.T) {
2325
req := NewRequest(t, "GET", urlStr)
2426
resp := session.MakeRequest(t, req, http.StatusOK)
2527
var orgs []*api.Organization
28+
user3 := models.AssertExistsAndLoadBean(t, &models.User{Name: "user3"}).(*models.User)
29+
2630
DecodeJSON(t, resp, &orgs)
2731

2832
assert.Equal(t, []*api.Organization{
2933
{
3034
ID: 3,
31-
UserName: "user3",
32-
FullName: "User Three",
33-
AvatarURL: "https://secure.gravatar.com/avatar/97d6d9441ff85fdc730e02a6068d267b?d=identicon",
35+
UserName: user3.Name,
36+
FullName: user3.FullName,
37+
AvatarURL: user3.AvatarLink(),
3438
Description: "",
3539
Website: "",
3640
Location: "",
@@ -48,13 +52,14 @@ func TestMyOrgs(t *testing.T) {
4852
resp := session.MakeRequest(t, req, http.StatusOK)
4953
var orgs []*api.Organization
5054
DecodeJSON(t, resp, &orgs)
55+
user3 := models.AssertExistsAndLoadBean(t, &models.User{Name: "user3"}).(*models.User)
5156

5257
assert.Equal(t, []*api.Organization{
5358
{
5459
ID: 3,
55-
UserName: "user3",
56-
FullName: "User Three",
57-
AvatarURL: "https://secure.gravatar.com/avatar/97d6d9441ff85fdc730e02a6068d267b?d=identicon",
60+
UserName: user3.Name,
61+
FullName: user3.FullName,
62+
AvatarURL: user3.AvatarLink(),
5863
Description: "",
5964
Website: "",
6065
Location: "",

integrations/user_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ func TestRenameInvalidUsername(t *testing.T) {
4747
"%2f..",
4848
"%00",
4949
"thisHas ASpace",
50+
"p<A>tho>lo<gical",
5051
}
5152

5253
session := loginUser(t, "user2")

models/fixtures/user.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
id: 2
2020
lower_name: user2
2121
name: user2
22-
full_name: User Two
22+
full_name: " < U<se>r Tw<o > >< "
2323
2424
passwd: 7d93daa0d1e6f2305cc8fa496847d61dc7320bb16262f9c55dd753480207234cdd96a93194e408341971742f4701772a025a # password
2525
type: 0 # individual
@@ -37,7 +37,7 @@
3737
id: 3
3838
lower_name: user3
3939
name: user3
40-
full_name: User Three
40+
full_name: " <<<< >> >> > >> > >>> >> "
4141
4242
passwd: 7d93daa0d1e6f2305cc8fa496847d61dc7320bb16262f9c55dd753480207234cdd96a93194e408341971742f4701772a025a # password
4343
type: 1 # organization
@@ -53,7 +53,7 @@
5353
id: 4
5454
lower_name: user4
5555
name: user4
56-
full_name: User Four
56+
full_name: " "
5757
5858
passwd: 7d93daa0d1e6f2305cc8fa496847d61dc7320bb16262f9c55dd753480207234cdd96a93194e408341971742f4701772a025a # password
5959
type: 0 # individual

models/issue_reaction_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func TestIssueReactionCount(t *testing.T) {
9999
reactions := issue1.Reactions.GroupByType()
100100
assert.Len(t, reactions["heart"], 4)
101101
assert.Equal(t, 2, reactions["heart"].GetMoreUserCount())
102-
assert.Equal(t, "User One, User Two", reactions["heart"].GetFirstUsers())
102+
assert.Equal(t, user1.DisplayName()+", "+user2.DisplayName(), reactions["heart"].GetFirstUsers())
103103
assert.True(t, reactions["heart"].HasUser(1))
104104
assert.False(t, reactions["heart"].HasUser(5))
105105
assert.False(t, reactions["heart"].HasUser(0))

models/user.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ func (u *User) GetFollowing(page int) ([]*User, error) {
417417
// NewGitSig generates and returns the signature of given user.
418418
func (u *User) NewGitSig() *git.Signature {
419419
return &git.Signature{
420-
Name: u.DisplayName(),
420+
Name: u.GitName(),
421421
Email: u.getEmail(),
422422
When: time.Now(),
423423
}
@@ -630,12 +630,33 @@ func (u *User) GetOrganizations(all bool) error {
630630
// DisplayName returns full name if it's not empty,
631631
// returns username otherwise.
632632
func (u *User) DisplayName() string {
633-
if len(u.FullName) > 0 {
634-
return u.FullName
633+
trimmed := strings.TrimSpace(u.FullName)
634+
if len(trimmed) > 0 {
635+
return trimmed
635636
}
636637
return u.Name
637638
}
638639

640+
func gitSafeName(name string) string {
641+
return strings.TrimSpace(strings.NewReplacer("\n", "", "<", "", ">", "").Replace(name))
642+
}
643+
644+
// GitName returns a git safe name
645+
func (u *User) GitName() string {
646+
gitName := gitSafeName(u.FullName)
647+
if len(gitName) > 0 {
648+
return gitName
649+
}
650+
// Although u.Name should be safe if created in our system
651+
// LDAP users may have bad names
652+
gitName = gitSafeName(u.Name)
653+
if len(gitName) > 0 {
654+
return gitName
655+
}
656+
// Totally pathological name so it's got to be:
657+
return fmt.Sprintf("user-%d", u.ID)
658+
}
659+
639660
// ShortName ellipses username to length
640661
func (u *User) ShortName(length int) string {
641662
return base.EllipsisString(u.Name, length)

models/user_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package models
66

77
import (
88
"math/rand"
9+
"strings"
910
"testing"
1011

1112
"code.gitea.io/gitea/modules/setting"
@@ -181,3 +182,34 @@ func TestGetOrgRepositoryIDs(t *testing.T) {
181182
// User 5's team has no access to any repo
182183
assert.Len(t, accessibleRepos, 0)
183184
}
185+
186+
func TestNewGitSig(t *testing.T) {
187+
users := make([]*User, 0, 20)
188+
sess := x.NewSession()
189+
defer sess.Close()
190+
sess.Find(&users)
191+
192+
for _, user := range users {
193+
sig := user.NewGitSig()
194+
assert.NotContains(t, sig.Name, "<")
195+
assert.NotContains(t, sig.Name, ">")
196+
assert.NotContains(t, sig.Name, "\n")
197+
assert.NotEqual(t, len(strings.TrimSpace(sig.Name)), 0)
198+
}
199+
}
200+
201+
func TestDisplayName(t *testing.T) {
202+
users := make([]*User, 0, 20)
203+
sess := x.NewSession()
204+
defer sess.Close()
205+
sess.Find(&users)
206+
207+
for _, user := range users {
208+
displayName := user.DisplayName()
209+
assert.Equal(t, strings.TrimSpace(displayName), displayName)
210+
if len(strings.TrimSpace(user.FullName)) == 0 {
211+
assert.Equal(t, user.Name, displayName)
212+
}
213+
assert.NotEqual(t, len(strings.TrimSpace(displayName)), 0)
214+
}
215+
}

0 commit comments

Comments
 (0)