From 9ab833c2ec8dd86506a08f95f8f72ff8eb18cecf Mon Sep 17 00:00:00 2001 From: Michael Mayer Date: Tue, 14 Mar 2023 16:36:30 +0100 Subject: [PATCH] Auth: Improve username validation and parsing Signed-off-by: Michael Mayer --- frontend/src/model/user.js | 9 +++++++++ internal/entity/auth_user.go | 9 ++++----- pkg/clean/auth.go | 9 ++++++--- pkg/clean/auth_test.go | 14 +++++++++++++- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/frontend/src/model/user.js b/frontend/src/model/user.js index d4adc979c..94f6ff055 100644 --- a/frontend/src/model/user.js +++ b/frontend/src/model/user.js @@ -112,6 +112,15 @@ export class User extends RestModel { }; } + getHandle() { + if (!this.Name) { + return ""; + } + + const s = this.Name.split("@"); + return s[0].trim(); + } + getDisplayName() { if (this.DisplayName) { return this.DisplayName; diff --git a/internal/entity/auth_user.go b/internal/entity/auth_user.go index ebc266b55..2b5fcef87 100644 --- a/internal/entity/auth_user.go +++ b/internal/entity/auth_user.go @@ -429,11 +429,11 @@ func (m *User) CanUpload() bool { // DefaultBasePath returns the default base path of the user based on the user name. func (m *User) DefaultBasePath() string { - if m.UserName == "" { + if s := m.Handle(); s == "" { return "" + } else { + return fmt.Sprintf("users/%s", s) } - - return fmt.Sprintf("users/%s", m.UserName) } // GetBasePath returns the user's relative base path. @@ -591,8 +591,7 @@ func (m *User) Email() string { // Handle returns the user's login handle. func (m *User) Handle() string { - handle, _, _ := strings.Cut(m.UserName, "@") - return handle + return clean.Handle(m.UserName) } // FullName returns the name of the user for display purposes. diff --git a/pkg/clean/auth.go b/pkg/clean/auth.go index 7d043c505..807610ed9 100644 --- a/pkg/clean/auth.go +++ b/pkg/clean/auth.go @@ -12,13 +12,16 @@ var EmailRegexp = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0 // Handle returns the sanitized username with trimmed whitespace and in lowercase. func Handle(s string) string { + s, _, _ = strings.Cut(s, "@") + s = strings.TrimSpace(s) + // Remove unwanted characters. s = strings.Map(func(r rune) rune { - if r <= 42 || r == 127 { + if r <= 31 || r == 127 { return -1 } switch r { - case '`', '~', '?', '|', '*', '\\', '%', '$', '@', ':', ';', '<', '>', '{', '}': + case '"', '\'', '(', ')', '#', '&', '$', ',', '+', '=', '`', '~', '?', '|', '*', '\\', '/', ':', ';', '<', '>', '{', '}': return -1 } return r @@ -42,7 +45,7 @@ func Username(s string) string { return -1 } switch r { - case '"', ',', '+', '=', '`', '~', '?', '|', '*', '\\', ':', ';', '<', '>', '{', '}': + case '"', '\'', '(', ')', '#', '&', '$', ',', '+', '=', '`', '~', '?', '|', '*', '\\', '/', ':', ';', '<', '>', '{', '}': return -1 } return r diff --git a/pkg/clean/auth_test.go b/pkg/clean/auth_test.go index a4de93c83..e22257a0f 100644 --- a/pkg/clean/auth_test.go +++ b/pkg/clean/auth_test.go @@ -11,11 +11,17 @@ func TestHandle(t *testing.T) { assert.Equal(t, "admin", Handle("Admin ")) }) t.Run(" Admin ", func(t *testing.T) { - assert.Equal(t, "adminfoo", Handle(" Admin@foo ")) + assert.Equal(t, "admin", Handle(" Admin@foo ")) + }) + t.Run(" Admin ", func(t *testing.T) { + assert.Equal(t, "admin foo", Handle(" Admin foo ")) }) t.Run(" admin ", func(t *testing.T) { assert.Equal(t, "admin", Handle(" admin ")) }) + t.Run("admin/user", func(t *testing.T) { + assert.Equal(t, "adminuser", Handle("admin/user")) + }) } func TestUsername(t *testing.T) { @@ -25,9 +31,15 @@ func TestUsername(t *testing.T) { t.Run(" Admin ", func(t *testing.T) { assert.Equal(t, "admin@foo", Username(" Admin@foo ")) }) + t.Run(" Admin ", func(t *testing.T) { + assert.Equal(t, "admin foo", Username(" Admin foo ")) + }) t.Run(" admin ", func(t *testing.T) { assert.Equal(t, "admin", Username(" admin ")) }) + t.Run("admin/user", func(t *testing.T) { + assert.Equal(t, "adminuser", Username("admin/user")) + }) } func TestEmail(t *testing.T) {