From 8c81ba1a782f6cbff8e4ee0043d2dc72c7df89af Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Wed, 19 Dec 2018 09:36:39 -0500 Subject: [PATCH] MM-13526 Add validation when setting a user's Locale field (#10022) --- model/user.go | 18 +++++++++++++++ model/user_test.go | 56 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/model/user.go b/model/user.go index 6b9bfc93dc..2db4be5d74 100644 --- a/model/user.go +++ b/model/user.go @@ -14,6 +14,7 @@ import ( "github.com/mattermost/mattermost-server/services/timezones" "golang.org/x/crypto/bcrypt" + "golang.org/x/text/language" ) const ( @@ -49,6 +50,7 @@ const ( USER_NAME_MAX_LENGTH = 64 USER_NAME_MIN_LENGTH = 1 USER_PASSWORD_MAX_LENGTH = 72 + USER_LOCALE_MAX_LENGTH = 5 ) type User struct { @@ -172,6 +174,10 @@ func (u *User) IsValid() *AppError { return InvalidUserError("password_limit", u.Id) } + if !IsValidLocale(u.Locale) { + return InvalidUserError("locale", u.Id) + } + return nil } @@ -644,3 +650,15 @@ func IsValidEmailBatchingInterval(emailInterval string) bool { emailInterval == PREFERENCE_EMAIL_INTERVAL_FIFTEEN || emailInterval == PREFERENCE_EMAIL_INTERVAL_HOUR } + +func IsValidLocale(locale string) bool { + if locale != "" { + if len(locale) > USER_LOCALE_MAX_LENGTH { + return false + } else if _, err := language.Parse(locale); err != nil { + return false + } + } + + return true +} diff --git a/model/user_test.go b/model/user_test.go index d7f7b67114..bdd8f20038 100644 --- a/model/user_test.go +++ b/model/user_test.go @@ -332,3 +332,59 @@ func TestRoles(t *testing.T) { require.True(t, IsInRole("system_admin junk", "system_admin")) require.False(t, IsInRole("admin", "system_admin")) } + +func TestIsValidLocale(t *testing.T) { + for _, test := range []struct { + Name string + Locale string + Expected bool + }{ + { + Name: "empty locale", + Locale: "", + Expected: true, + }, + { + Name: "locale with only language", + Locale: "fr", + Expected: true, + }, + { + Name: "locale with region", + Locale: "en-DE", // English, as used in Germany + Expected: true, + }, + { + Name: "invalid locale", + Locale: "'", + Expected: false, + }, + + // Note that the following cases are all valid language tags, but they're considered invalid here because of + // the max length of the User.Locale field. + { + Name: "locale with extended language subtag", + Locale: "zh-yue-HK", // Chinese, Cantonese, as used in Hong Kong + Expected: false, + }, + { + Name: "locale with script", + Locale: "hy-Latn-IT-arevela", // Eastern Armenian written in Latin script, as used in Italy + Expected: false, + }, + { + Name: "locale with variant", + Locale: "sl-rozaj-biske", // San Giorgio dialect of Resian dialect of Slovenian + Expected: false, + }, + { + Name: "locale with extension", + Locale: "de-DE-u-co-phonebk", // German, as used in Germany, using German phonebook sort order + Expected: false, + }, + } { + t.Run(test.Name, func(t *testing.T) { + assert.Equal(t, test.Expected, IsValidLocale(test.Locale)) + }) + } +}