diff --git a/app/v1/self.go b/app/v1/self.go index fc85a2b..e517e49 100644 --- a/app/v1/self.go +++ b/app/v1/self.go @@ -58,6 +58,12 @@ type userSettingsData struct { func UsersSelfSettingsPOST(md common.MethodData) common.CodeMessager { var d userSettingsData md.RequestData.Unmarshal(&d) + + // input sanitisation + d.UsernameAKA = common.SanitiseString(d.UsernameAKA) + d.CustomBadge.Name = common.SanitiseString(d.CustomBadge.Name) + d.FavouriteMode = intPtrIn(0, d.FavouriteMode, 3) + q := new(common.UpdateQuery). Add("s.username_aka", d.UsernameAKA). Add("s.favourite_mode", d.FavouriteMode). @@ -114,3 +120,16 @@ WHERE u.id = ?`, md.ID()).Scan( } return r } + +func intPtrIn(x int, y *int, z int) *int { + if y == nil { + return nil + } + if *y > z { + return nil + } + if *y < x { + return nil + } + return y +} diff --git a/app/v1/user.go b/app/v1/user.go index 7d2ba44..5709fd7 100644 --- a/app/v1/user.go +++ b/app/v1/user.go @@ -345,7 +345,8 @@ func UserSelfUserpagePOST(md common.MethodData) common.CodeMessager { if d.Data == nil { return ErrMissingField("data") } - _, err := md.DB.Exec("UPDATE users_stats SET userpage_content = ? WHERE id = ? LIMIT 1", *d.Data, md.ID()) + cont := common.SanitiseString(*d.Data) + _, err := md.DB.Exec("UPDATE users_stats SET userpage_content = ? WHERE id = ? LIMIT 1", cont, md.ID()) if err != nil { md.Err(err) } diff --git a/common/sanitisation.go b/common/sanitisation.go new file mode 100644 index 0000000..1b4d61e --- /dev/null +++ b/common/sanitisation.go @@ -0,0 +1,16 @@ +package common + +import ( + "unicode" +) + +// SanitiseString removes all control codes from a string. +func SanitiseString(s string) string { + n := make([]rune, 0, len(s)) + for _, c := range s { + if !unicode.Is(unicode.Other, c) { + n = append(n, c) + } + } + return string(n) +} diff --git a/common/sanitisation_test.go b/common/sanitisation_test.go new file mode 100644 index 0000000..953eb09 --- /dev/null +++ b/common/sanitisation_test.go @@ -0,0 +1,41 @@ +package common + +import "testing" + +const pen = "I trattori di palmizio 나는 펜이있다. 私はリンゴを持っています。" + + "啊! 苹果笔。 у меня есть ручка, Tôi có dứa. අන්නාසි පෑන" + +func TestSanitiseString(t *testing.T) { + tests := []struct { + name string + arg string + want string + }{ + { + "Normal", + pen, + pen, + }, + { + "Arabic (rtl)", + "أناناس", + "أناناس", + }, + { + "Null", + "A\x00B", + "AB", + }, + } + for _, tt := range tests { + if got := SanitiseString(tt.arg); got != tt.want { + t.Errorf("%q. SanitiseString() = %v, want %v", tt.name, got, tt.want) + } + } +} + +func BenchmarkSanitiseString(b *testing.B) { + for i := 0; i < b.N; i++ { + SanitiseString(pen) + } +}