diff --git a/README.md b/README.md index 18f11d88..cec106a5 100644 --- a/README.md +++ b/README.md @@ -107,18 +107,21 @@ Professional support for Rdiffweb is available by contacting [IKUS Soft](https:/ # Changelog -## 2.4.8 (2022-09-23) +## 2.4.8 (2022-09-24) This releases include a security fix. If you are using an earlier version, you should upgrade to this release immediately. * Clean-up invalid path on error page +* Limit username field length [CVE-2022-3290](https://nvd.nist.gov/vuln/detail/CVE-2022-3290) +* Limit user's email field length [CVE-2022-3272](https://nvd.nist.gov/vuln/detail/CVE-2022-3272) +* Limit user's root directory field length [CVE-2022-3295](https://nvd.nist.gov/vuln/detail/CVE-2022-3295) ## 2.4.7 (2002-09-21) This releases include a security fix. If you are using an earlier version, you should upgrade to this release immediately. -* Generate a new session on login and 2FA #220 -* Mitigate CSRF on user's settings #221 +* Generate a new session on login and 2FA #220 [CVE-2022-3269](https://nvd.nist.gov/vuln/detail/CVE-2022-3269) +* Mitigate CSRF on user's settings #221 [CVE-2022-3274](https://nvd.nist.gov/vuln/detail/CVE-2022-3274) ## 2.4.6 (2022-09-20) @@ -126,7 +129,7 @@ This releases include a security fix. If you are using an earlier version, you s * Support MarkupSafe<3 for Debian bookworm * Mitigate CSRF on user's notification settings #216 [CVE-2022-3233](https://nvd.nist.gov/vuln/detail/CVE-2022-3233) -* Mitigate CSRF on repository settings #217 +* Mitigate CSRF on repository settings #217 [CVE-2022-3267](https://nvd.nist.gov/vuln/detail/CVE-2022-3267) * Use 'Secure' Attribute with Sensitive Cookie in HTTPS Session on HTTP Error #218 [CVE-2022-3174](https://nvd.nist.gov/vuln/detail/CVE-2022-3174) ## 2.4.5 (2002-09-16) diff --git a/rdiffweb/controller/page_admin.py b/rdiffweb/controller/page_admin.py index b67100d5..4cc0a9b9 100644 --- a/rdiffweb/controller/page_admin.py +++ b/rdiffweb/controller/page_admin.py @@ -41,6 +41,9 @@ # Define the logger logger = logging.getLogger(__name__) +# Maximum file path +MAX_PATH = 260 + def get_pyinfo(): try: @@ -166,11 +169,27 @@ def process_formdata(self, valuelist): class UserForm(CherryForm): userid = StringField(_('UserID')) - username = StringField(_('Username'), validators=[validators.data_required()]) - email = EmailField(_('Email'), validators=[validators.optional()]) + username = StringField( + _('Username'), + validators=[ + validators.data_required(), + validators.length(max=256, message=_('Username too long.')), + ], + ) + email = EmailField( + _('Email'), + validators=[ + validators.optional(), + validators.length(max=256, message=_('Email too long.')), + ], + ) password = PasswordField(_('Password'), validators=[validators.optional()]) user_root = StringField( - _('Root directory'), description=_("Absolute path defining the location of the repositories for this user.") + _('Root directory'), + description=_("Absolute path defining the location of the repositories for this user."), + validators=[ + validators.length(max=MAX_PATH, message=_('Root directory too long.')), + ], ) role = SelectField( _('User Role'), diff --git a/rdiffweb/controller/page_login.py b/rdiffweb/controller/page_login.py index 6565aa15..91107824 100644 --- a/rdiffweb/controller/page_login.py +++ b/rdiffweb/controller/page_login.py @@ -19,7 +19,7 @@ import cherrypy from wtforms.fields import PasswordField, StringField from wtforms.fields.simple import HiddenField -from wtforms.validators import InputRequired +from wtforms.validators import InputRequired, Length from rdiffweb.controller import Controller, flash from rdiffweb.controller.cherrypy_wtf import CherryForm @@ -34,7 +34,7 @@ class LoginForm(CherryForm): login = StringField( _('Username'), - validators=[InputRequired()], + validators=[InputRequired(), Length(max=256, message=_('Username too long.'))], render_kw={ "placeholder": _('Username'), "autocorrect": "off", diff --git a/rdiffweb/controller/pref_general.py b/rdiffweb/controller/pref_general.py index 0f2faaa8..d25c4ebd 100644 --- a/rdiffweb/controller/pref_general.py +++ b/rdiffweb/controller/pref_general.py @@ -38,7 +38,14 @@ class UserProfileForm(CherryForm): - email = EmailField(_('Email'), validators=[DataRequired(), Regexp(PATTERN_EMAIL, message=_("Invalid email."))]) + email = EmailField( + _('Email'), + validators=[ + DataRequired(), + Length(max=256, message=_("Invalid email.")), + Regexp(PATTERN_EMAIL, message=_("Invalid email.")), + ], + ) class UserPasswordForm(CherryForm): diff --git a/rdiffweb/controller/tests/test_page_admin.py b/rdiffweb/controller/tests/test_page_admin.py index aa7b1cc5..77cd0535 100644 --- a/rdiffweb/controller/tests/test_page_admin.py +++ b/rdiffweb/controller/tests/test_page_admin.py @@ -239,6 +239,33 @@ def test_add_without_user_root(self): user = self.app.store.get_user('test6') self.assertEqual('', user.user_root) + def test_add_with_username_too_long(self): + # Given a too long username + username = "test2" * 52 + # When trying to create the user + self._add_user(username, None, "password", "/tmp/", USER_ROLE) + # Then an error is raised + self.assertStatus(200) + self.assertInBody("Username too long.") + + def test_add_with_email_too_long(self): + # Given a too long username + email = ("test2" * 50) + "@test.com" + # When trying to create the user + self._add_user("test2", email, "password", "/tmp/", USER_ROLE) + # Then an error is raised + self.assertStatus(200) + self.assertInBody("Email too long.") + + def test_add_with_user_root_too_long(self): + # Given a too long user root + user_root = "/temp/" * 50 + # When trying to create the user + self._add_user("test2", "test@test,com", "password", user_root, USER_ROLE) + # Then an error is raised + self.assertStatus(200) + self.assertInBody("Root directory too long.") + def test_delete_user_with_not_existing_username(self): """ Verify failure to delete invalid username. diff --git a/rdiffweb/controller/tests/test_page_login.py b/rdiffweb/controller/tests/test_page_login.py index e01178c2..9f3a53e6 100644 --- a/rdiffweb/controller/tests/test_page_login.py +++ b/rdiffweb/controller/tests/test_page_login.py @@ -132,6 +132,12 @@ def test_getpage_without_username(self): self.getPage('/login/', method='GET') self.assertStatus('200 OK') + def test_getpage_with_username_too_long(self): + b = {'login': 'admin' * 52, 'password': 'admin123'} + self.getPage('/login/', method='POST', body=b) + self.assertStatus('200 OK') + self.assertInBody('Username too long.') + def test_getpage_with_empty_password(self): """ Check if authentication is failing without a password. diff --git a/rdiffweb/controller/tests/test_page_prefs.py b/rdiffweb/controller/tests/test_page_prefs.py index 77dae001..674fd16b 100644 --- a/rdiffweb/controller/tests/test_page_prefs.py +++ b/rdiffweb/controller/tests/test_page_prefs.py @@ -84,6 +84,10 @@ def test_change_email_with_invalid_email(self): self._set_profile_info("test@test.com, test2@test.com") self.assertInBody("Invalid email") + def test_change_email_with_too_long(self): + self._set_profile_info(("test1" * 50) + "@test.com") + self.assertInBody("Invalid email") + def test_change_password(self): # When udating user's password self._set_password(self.PASSWORD, "newpassword", "newpassword")