summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorLibravatar tobi <31960611+tsmethurst@users.noreply.github.com>2023-05-25 15:18:15 +0200
committerLibravatar GitHub <noreply@github.com>2023-05-25 15:18:15 +0200
commitfc524f8cf16761f949303a96bca14e63c46ceda8 (patch)
tree7c73a836c4d0d89e3dbc672269ceabad082547e6 /internal
parent[bugfix] allow usernames of length 1 (#1823) (diff)
downloadgotosocial-fc524f8cf16761f949303a96bca14e63c46ceda8.tar.xz
[feature] Configurable custom css length (#1827)
* [feature] Make accounts custom css length configurable * test custom css validation
Diffstat (limited to 'internal')
-rw-r--r--internal/config/config.go1
-rw-r--r--internal/config/defaults.go1
-rw-r--r--internal/config/helpers.gen.go75
-rw-r--r--internal/validate/formvalidation.go3
-rw-r--r--internal/validate/formvalidation_test.go166
5 files changed, 157 insertions, 89 deletions
diff --git a/internal/config/config.go b/internal/config/config.go
index 0b7b527ea..8dcbcaf97 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -85,6 +85,7 @@ type Configuration struct {
AccountsApprovalRequired bool `name:"accounts-approval-required" usage:"Do account signups require approval by an admin or moderator before user can log in? If false, new registrations will be automatically approved."`
AccountsReasonRequired bool `name:"accounts-reason-required" usage:"Do new account signups require a reason to be submitted on registration?"`
AccountsAllowCustomCSS bool `name:"accounts-allow-custom-css" usage:"Allow accounts to enable custom CSS for their profile pages and statuses."`
+ AccountsCustomCSSLength int `name:"accounts-custom-css-length" usage:"Maximum permitted length (characters) of custom CSS for accounts."`
MediaImageMaxSize bytesize.Size `name:"media-image-max-size" usage:"Max size of accepted images in bytes"`
MediaVideoMaxSize bytesize.Size `name:"media-video-max-size" usage:"Max size of accepted videos in bytes"`
diff --git a/internal/config/defaults.go b/internal/config/defaults.go
index 53d994cda..c11f436d6 100644
--- a/internal/config/defaults.go
+++ b/internal/config/defaults.go
@@ -65,6 +65,7 @@ var Defaults = Configuration{
AccountsApprovalRequired: true,
AccountsReasonRequired: true,
AccountsAllowCustomCSS: false,
+ AccountsCustomCSSLength: 10000,
MediaImageMaxSize: 10 * bytesize.MiB,
MediaVideoMaxSize: 40 * bytesize.MiB,
diff --git a/internal/config/helpers.gen.go b/internal/config/helpers.gen.go
index 2a70488e8..16865f32c 100644
--- a/internal/config/helpers.gen.go
+++ b/internal/config/helpers.gen.go
@@ -74,6 +74,31 @@ func GetLogDbQueries() bool { return global.GetLogDbQueries() }
// SetLogDbQueries safely sets the value for global configuration 'LogDbQueries' field
func SetLogDbQueries(v bool) { global.SetLogDbQueries(v) }
+// GetLogClientIP safely fetches the Configuration value for state's 'LogClientIP' field
+func (st *ConfigState) GetLogClientIP() (v bool) {
+ st.mutex.Lock()
+ v = st.config.LogClientIP
+ st.mutex.Unlock()
+ return
+}
+
+// SetLogClientIP safely sets the Configuration value for state's 'LogClientIP' field
+func (st *ConfigState) SetLogClientIP(v bool) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.LogClientIP = v
+ st.reloadToViper()
+}
+
+// LogClientIPFlag returns the flag name for the 'LogClientIP' field
+func LogClientIPFlag() string { return "log-client-ip" }
+
+// GetLogClientIP safely fetches the value for global configuration 'LogClientIP' field
+func GetLogClientIP() bool { return global.GetLogClientIP() }
+
+// SetLogClientIP safely sets the value for global configuration 'LogClientIP' field
+func SetLogClientIP(v bool) { global.SetLogClientIP(v) }
+
// GetApplicationName safely fetches the Configuration value for state's 'ApplicationName' field
func (st *ConfigState) GetApplicationName() (v string) {
st.mutex.Lock()
@@ -924,6 +949,31 @@ func GetAccountsAllowCustomCSS() bool { return global.GetAccountsAllowCustomCSS(
// SetAccountsAllowCustomCSS safely sets the value for global configuration 'AccountsAllowCustomCSS' field
func SetAccountsAllowCustomCSS(v bool) { global.SetAccountsAllowCustomCSS(v) }
+// GetAccountsCustomCSSLength safely fetches the Configuration value for state's 'AccountsCustomCSSLength' field
+func (st *ConfigState) GetAccountsCustomCSSLength() (v int) {
+ st.mutex.Lock()
+ v = st.config.AccountsCustomCSSLength
+ st.mutex.Unlock()
+ return
+}
+
+// SetAccountsCustomCSSLength safely sets the Configuration value for state's 'AccountsCustomCSSLength' field
+func (st *ConfigState) SetAccountsCustomCSSLength(v int) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.AccountsCustomCSSLength = v
+ st.reloadToViper()
+}
+
+// AccountsCustomCSSLengthFlag returns the flag name for the 'AccountsCustomCSSLength' field
+func AccountsCustomCSSLengthFlag() string { return "accounts-custom-css-length" }
+
+// GetAccountsCustomCSSLength safely fetches the value for global configuration 'AccountsCustomCSSLength' field
+func GetAccountsCustomCSSLength() int { return global.GetAccountsCustomCSSLength() }
+
+// SetAccountsCustomCSSLength safely sets the value for global configuration 'AccountsCustomCSSLength' field
+func SetAccountsCustomCSSLength(v int) { global.SetAccountsCustomCSSLength(v) }
+
// GetMediaImageMaxSize safely fetches the Configuration value for state's 'MediaImageMaxSize' field
func (st *ConfigState) GetMediaImageMaxSize() (v bytesize.Size) {
st.mutex.Lock()
@@ -3829,28 +3879,3 @@ func GetRequestIDHeader() string { return global.GetRequestIDHeader() }
// SetRequestIDHeader safely sets the value for global configuration 'RequestIDHeader' field
func SetRequestIDHeader(v string) { global.SetRequestIDHeader(v) }
-
-// GetLogClientIP safely fetches the Configuration value for state's 'LogClientIP' field
-func (st *ConfigState) GetLogClientIP() (v bool) {
- st.mutex.Lock()
- v = st.config.LogClientIP
- st.mutex.Unlock()
- return
-}
-
-// SetLogClientIP safely sets the Configuration value for state's 'LogClientIP' field
-func (st *ConfigState) SetLogClientIP(v bool) {
- st.mutex.Lock()
- defer st.mutex.Unlock()
- st.config.LogClientIP = v
- st.reloadToViper()
-}
-
-// LogClientIPFlag returns the flag name for the 'LogClientIP' field
-func LogClientIPFlag() string { return "log-client-ip" }
-
-// GetLogClientIP safely fetches the value for global configuration 'LogClientIP' field
-func GetLogClientIP() bool { return global.GetLogClientIP() }
-
-// SetLogClientIP safely sets the value for global configuration 'LogClientIP' field
-func SetLogClientIP(v bool) { global.SetLogClientIP(v) }
diff --git a/internal/validate/formvalidation.go b/internal/validate/formvalidation.go
index f9328dc1f..c122bf2bc 100644
--- a/internal/validate/formvalidation.go
+++ b/internal/validate/formvalidation.go
@@ -41,7 +41,6 @@ const (
maximumDescriptionLength = 5000
maximumSiteTermsLength = 5000
maximumUsernameLength = 64
- maximumCustomCSSLength = 5000
maximumEmojiCategoryLength = 64
maximumProfileFieldLength = 255
maximumProfileFields = 6
@@ -170,9 +169,11 @@ func CustomCSS(customCSS string) error {
return errors.New("accounts-allow-custom-css is not enabled for this instance")
}
+ maximumCustomCSSLength := config.GetAccountsCustomCSSLength()
if length := len([]rune(customCSS)); length > maximumCustomCSSLength {
return fmt.Errorf("custom_css must be less than %d characters, but submitted custom_css was %d characters", maximumCustomCSSLength, length)
}
+
return nil
}
diff --git a/internal/validate/formvalidation_test.go b/internal/validate/formvalidation_test.go
index 4dff5b60d..a594c3763 100644
--- a/internal/validate/formvalidation_test.go
+++ b/internal/validate/formvalidation_test.go
@@ -22,8 +22,8 @@ import (
"fmt"
"testing"
- "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
+ "github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/validate"
)
@@ -44,43 +44,43 @@ func (suite *ValidationTestSuite) TestCheckPasswordStrength() {
var err error
err = validate.NewPassword(empty)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("no password provided"), err)
+ if suite.Error(err) {
+ suite.Equal(errors.New("no password provided"), err)
}
err = validate.NewPassword(terriblePassword)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("password is only 62% strength, try including more special characters, using uppercase letters, using numbers or using a longer password"), err)
+ if suite.Error(err) {
+ suite.Equal(errors.New("password is only 62% strength, try including more special characters, using uppercase letters, using numbers or using a longer password"), err)
}
err = validate.NewPassword(weakPassword)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("password is only 95% strength, try including more special characters, using numbers or using a longer password"), err)
+ if suite.Error(err) {
+ suite.Equal(errors.New("password is only 95% strength, try including more special characters, using numbers or using a longer password"), err)
}
err = validate.NewPassword(shortPassword)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("password is only 39% strength, try including more special characters or using a longer password"), err)
+ if suite.Error(err) {
+ suite.Equal(errors.New("password is only 39% strength, try including more special characters or using a longer password"), err)
}
err = validate.NewPassword(specialPassword)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("password is only 53% strength, try including more special characters or using a longer password"), err)
+ if suite.Error(err) {
+ suite.Equal(errors.New("password is only 53% strength, try including more special characters or using a longer password"), err)
}
err = validate.NewPassword(longPassword)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
+ if suite.NoError(err) {
+ suite.Equal(nil, err)
}
err = validate.NewPassword(tooLong)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("password should be no more than 256 chars"), err)
+ if suite.Error(err) {
+ suite.Equal(errors.New("password should be no more than 256 chars"), err)
}
err = validate.NewPassword(strongPassword)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
+ if suite.NoError(err) {
+ suite.Equal(nil, err)
}
}
@@ -133,28 +133,28 @@ func (suite *ValidationTestSuite) TestValidateEmail() {
var err error
err = validate.Email(empty)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("no email provided"), err)
+ if suite.Error(err) {
+ suite.Equal(errors.New("no email provided"), err)
}
err = validate.Email(notAnEmailAddress)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("mail: missing '@' or angle-addr"), err)
+ if suite.Error(err) {
+ suite.Equal(errors.New("mail: missing '@' or angle-addr"), err)
}
err = validate.Email(almostAnEmailAddress)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("mail: no angle-addr"), err)
+ if suite.Error(err) {
+ suite.Equal(errors.New("mail: no angle-addr"), err)
}
err = validate.Email(aWebsite)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("mail: missing '@' or angle-addr"), err)
+ if suite.Error(err) {
+ suite.Equal(errors.New("mail: missing '@' or angle-addr"), err)
}
err = validate.Email(emailAddress)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
+ if suite.NoError(err) {
+ suite.Equal(nil, err)
}
}
@@ -171,48 +171,48 @@ func (suite *ValidationTestSuite) TestValidateLanguage() {
var err error
err = validate.Language(empty)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("no language provided"), err)
+ if suite.Error(err) {
+ suite.Equal(errors.New("no language provided"), err)
}
err = validate.Language(notALanguage)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("language: tag is not well-formed"), err)
+ if suite.Error(err) {
+ suite.Equal(errors.New("language: tag is not well-formed"), err)
}
err = validate.Language(english)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
+ if suite.NoError(err) {
+ suite.Equal(nil, err)
}
err = validate.Language(capitalEnglish)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
+ if suite.NoError(err) {
+ suite.Equal(nil, err)
}
err = validate.Language(arabic3Letters)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
+ if suite.NoError(err) {
+ suite.Equal(nil, err)
}
err = validate.Language(mixedCapsEnglish)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
+ if suite.NoError(err) {
+ suite.Equal(nil, err)
}
err = validate.Language(englishUS)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("language: tag is not well-formed"), err)
+ if suite.Error(err) {
+ suite.Equal(errors.New("language: tag is not well-formed"), err)
}
err = validate.Language(dutch)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
+ if suite.NoError(err) {
+ suite.Equal(nil, err)
}
err = validate.Language(german)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
+ if suite.NoError(err) {
+ suite.Equal(nil, err)
}
}
@@ -226,49 +226,49 @@ func (suite *ValidationTestSuite) TestValidateReason() {
// check with no reason required
err = validate.SignUpReason(empty, false)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
+ if suite.NoError(err) {
+ suite.Equal(nil, err)
}
err = validate.SignUpReason(badReason, false)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
+ if suite.NoError(err) {
+ suite.Equal(nil, err)
}
err = validate.SignUpReason(tooLong, false)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
+ if suite.NoError(err) {
+ suite.Equal(nil, err)
}
err = validate.SignUpReason(goodReason, false)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
+ if suite.NoError(err) {
+ suite.Equal(nil, err)
}
err = validate.SignUpReason(unicode, false)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
+ if suite.NoError(err) {
+ suite.Equal(nil, err)
}
// check with reason required
err = validate.SignUpReason(empty, true)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("no reason provided"), err)
+ if suite.Error(err) {
+ suite.Equal(errors.New("no reason provided"), err)
}
err = validate.SignUpReason(badReason, true)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("reason should be at least 40 chars but 'because' was 7"), err)
+ if suite.Error(err) {
+ suite.Equal(errors.New("reason should be at least 40 chars but 'because' was 7"), err)
}
err = validate.SignUpReason(tooLong, true)
- if assert.Error(suite.T(), err) {
- assert.Equal(suite.T(), errors.New("reason should be no more than 500 chars but given reason was 600"), err)
+ if suite.Error(err) {
+ suite.Equal(errors.New("reason should be no more than 500 chars but given reason was 600"), err)
}
err = validate.SignUpReason(goodReason, true)
- if assert.NoError(suite.T(), err) {
- assert.Equal(suite.T(), nil, err)
+ if suite.NoError(err) {
+ suite.Equal(nil, err)
}
}
@@ -302,6 +302,46 @@ func (suite *ValidationTestSuite) TestValidateProfileField() {
suite.Len(dodgyFields[0].Value, 255)
}
+func (suite *ValidationTestSuite) TestValidateCustomCSSDisabled() {
+ config.SetAccountsAllowCustomCSS(false)
+
+ err := validate.CustomCSS("this will fail")
+ suite.EqualError(err, "accounts-allow-custom-css is not enabled for this instance")
+}
+
+func (suite *ValidationTestSuite) TestValidateCustomCSSEnabled() {
+ config.SetAccountsAllowCustomCSS(true)
+
+ err := validate.CustomCSS("this will pass")
+ suite.NoError(err)
+}
+
+func (suite *ValidationTestSuite) TestValidateCustomCSSTooLong() {
+ config.SetAccountsAllowCustomCSS(true)
+ config.SetAccountsCustomCSSLength(5)
+
+ err := validate.CustomCSS("this will fail")
+ suite.EqualError(err, "custom_css must be less than 5 characters, but submitted custom_css was 14 characters")
+}
+
+func (suite *ValidationTestSuite) TestValidateCustomCSSTooLongZalgo() {
+ config.SetAccountsAllowCustomCSS(true)
+ config.SetAccountsCustomCSSLength(5)
+ zalgo := "p̵̹̜͇̺̜̱͊̓̈́͛̀͊͘͜e̷̡̱̲̼̪̗̙̐͐̃́̄̉͛̔e̷̞̰̜̲̥̘̻͔̜̞̬͚͋̊͑͗̅̓͛͗̎̃̈́̐̂̕͝ ̷̨̢̡̱̖̤͇̻͕̲̤̞̑ͅp̶̰̜̟̠̏̇̇̆̐̒͋̔͘ḛ̵̾͘ę̷̝͙͕͓͓̱̠̤̳̻̜̗͖̞͙̻̆̓̄͋̎͊̀̋̿́̐͛͗̄̈́̚͠ ̵̨̨̫͕̲͚̮͕̳̉̾̔̍͐p̶̘̞̠̘̎̓̍̑̀͗̃̈́͂́̈́͆͘͜͝͝o̶̜͛̒͒̉̑͒̿͗̐̃͝o̵̼̒͌̓ ̵̢̗̦͔͉͈̰̘̋̃̐̑̅̽̏̄̅͐͆̔͊̃̋͝p̵̩̱̆̆͂̂͛̓̋̅͝o̶̪̰̲̝̻̳̦̮̮͔̒ͅơ̸̧̨̟͇̪̰̜̠̦͇̇̎͗̏̏̈́͂̉̏͐́̃̀͆͠ͅ"
+
+ err := validate.CustomCSS(zalgo)
+ suite.EqualError(err, "custom_css must be less than 5 characters, but submitted custom_css was 275 characters")
+}
+
+func (suite *ValidationTestSuite) TestValidateCustomCSSTooLongUnicode() {
+ config.SetAccountsAllowCustomCSS(true)
+ config.SetAccountsCustomCSSLength(5)
+ unicode := "⎾⎿⏀⏁⏂⏃⏄⏅⏆⏇"
+
+ err := validate.CustomCSS(unicode)
+ suite.EqualError(err, "custom_css must be less than 5 characters, but submitted custom_css was 10 characters")
+}
+
func TestValidationTestSuite(t *testing.T) {
suite.Run(t, new(ValidationTestSuite))
}