* Fix username rendering bug * XSS integration test * Migration to unescape user full namestags/v1.21.12.1
@@ -0,0 +1,37 @@ | |||||
// Copyright 2017 The Gitea Authors. All rights reserved. | |||||
// Use of this source code is governed by a MIT-style | |||||
// license that can be found in the LICENSE file. | |||||
package integrations | |||||
import ( | |||||
"net/http" | |||||
"testing" | |||||
"code.gitea.io/gitea/models" | |||||
"github.com/stretchr/testify/assert" | |||||
) | |||||
func TestXSSUserFullName(t *testing.T) { | |||||
prepareTestEnv(t) | |||||
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User) | |||||
const fullName = `name & <script class="evil">alert('Oh no!');</script>` | |||||
session := loginUser(t, user.Name) | |||||
req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{ | |||||
"_csrf": GetCSRF(t, session, "/user/settings"), | |||||
"name": user.Name, | |||||
"full_name": fullName, | |||||
"email": user.Email, | |||||
}) | |||||
session.MakeRequest(t, req, http.StatusFound) | |||||
req = NewRequestf(t, "GET", "/%s", user.Name) | |||||
resp := session.MakeRequest(t, req, http.StatusOK) | |||||
htmlDoc := NewHTMLParser(t, resp.Body) | |||||
assert.EqualValues(t, 0, htmlDoc.doc.Find("script.evil").Length()) | |||||
assert.EqualValues(t, fullName, | |||||
htmlDoc.doc.Find("div.content").Find(".header.text.center").Text(), | |||||
) | |||||
} |
@@ -122,6 +122,8 @@ var migrations = []Migration{ | |||||
NewMigration("adds comment to an action", addCommentIDToAction), | NewMigration("adds comment to an action", addCommentIDToAction), | ||||
// v36 -> v37 | // v36 -> v37 | ||||
NewMigration("regenerate git hooks", regenerateGitHooks36), | NewMigration("regenerate git hooks", regenerateGitHooks36), | ||||
// v37 -> v38 | |||||
NewMigration("unescape user full names", unescapeUserFullNames), | |||||
} | } | ||||
// Migrate database to current version | // Migrate database to current version | ||||
@@ -0,0 +1,32 @@ | |||||
// Copyright 2017 The Gitea Authors. All rights reserved. | |||||
// Use of this source code is governed by a MIT-style | |||||
// license that can be found in the LICENSE file. | |||||
package migrations | |||||
import ( | |||||
"html" | |||||
"code.gitea.io/gitea/models" | |||||
"github.com/go-xorm/xorm" | |||||
) | |||||
func unescapeUserFullNames(x *xorm.Engine) (err error) { | |||||
const batchSize = 100 | |||||
for start := 0; ; start += batchSize { | |||||
users := make([]*models.User, 0, batchSize) | |||||
if err := x.Limit(start, batchSize).Find(users); err != nil { | |||||
return err | |||||
} | |||||
if len(users) == 0 { | |||||
return nil | |||||
} | |||||
for _, user := range users { | |||||
user.FullName = html.UnescapeString(user.FullName) | |||||
if _, err := x.Cols("full_name").Update(user); err != nil { | |||||
return err | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -35,7 +35,6 @@ import ( | |||||
"code.gitea.io/gitea/modules/avatar" | "code.gitea.io/gitea/modules/avatar" | ||||
"code.gitea.io/gitea/modules/base" | "code.gitea.io/gitea/modules/base" | ||||
"code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
"code.gitea.io/gitea/modules/markdown" | |||||
"code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
) | ) | ||||
@@ -164,8 +163,6 @@ func (u *User) UpdateDiffViewStyle(style string) error { | |||||
// AfterSet is invoked from XORM after setting the value of a field of this object. | // AfterSet is invoked from XORM after setting the value of a field of this object. | ||||
func (u *User) AfterSet(colName string, _ xorm.Cell) { | func (u *User) AfterSet(colName string, _ xorm.Cell) { | ||||
switch colName { | switch colName { | ||||
case "full_name": | |||||
u.FullName = markdown.Sanitize(u.FullName) | |||||
case "created_unix": | case "created_unix": | ||||
u.Created = time.Unix(u.CreatedUnix, 0).Local() | u.Created = time.Unix(u.CreatedUnix, 0).Local() | ||||
case "updated_unix": | case "updated_unix": | ||||
@@ -871,7 +868,6 @@ func updateUser(e Engine, u *User) error { | |||||
u.Website = base.TruncateString(u.Website, 255) | u.Website = base.TruncateString(u.Website, 255) | ||||
u.Description = base.TruncateString(u.Description, 255) | u.Description = base.TruncateString(u.Description, 255) | ||||
u.FullName = markdown.Sanitize(u.FullName) | |||||
_, err := e.Id(u.ID).AllCols().Update(u) | _, err := e.Id(u.ID).AllCols().Update(u) | ||||
return err | return err | ||||
} | } | ||||