diff --git a/e2e-tests/cypress/tests/integration/channels/account_settings/security/password_spec.ts b/e2e-tests/cypress/tests/integration/channels/account_settings/security/password_spec.ts index df4ff2a4f0..1444117535 100644 --- a/e2e-tests/cypress/tests/integration/channels/account_settings/security/password_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/account_settings/security/password_spec.ts @@ -80,8 +80,8 @@ describe('Profile', () => { // # Save cy.uiSave(); - // * Verify for error message: "Must be 5-64 characters long." - cy.get('#clientError').should('be.visible').should('have.text', 'Must be 5-64 characters long.'); + // * Verify for error message: "Must be 5-72 characters long." + cy.get('#clientError').should('be.visible').should('have.text', 'Must be 5-72 characters long.'); }); it('MM-T2084 Password: Cancel out of password changes causes no changes to be made', () => { diff --git a/e2e-tests/cypress/tests/integration/channels/auth_sso/authentication_2_spec.ts b/e2e-tests/cypress/tests/integration/channels/auth_sso/authentication_2_spec.ts index 9f1af61e1b..95d24b9673 100644 --- a/e2e-tests/cypress/tests/integration/channels/auth_sso/authentication_2_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/auth_sso/authentication_2_spec.ts @@ -20,7 +20,7 @@ describe('Authentication', () => { cy.apiAdminLogin(); }); - it('MM-T1771 - Minimum password length error field shows below 5 and above 64', () => { + it('MM-T1771 - Minimum password length error field shows below 5 and above 72', () => { cy.visit('/admin_console/authentication/password'); cy.findByPlaceholderText('E.g.: "5"', {timeout: TIMEOUTS.ONE_MIN}).clear().type('88'); @@ -28,7 +28,7 @@ describe('Authentication', () => { cy.uiSave(); // * Ensure error appears when saving a password outside of the limits - cy.findByText('Minimum password length must be a whole number greater than or equal to 5 and less than or equal to 64.', {timeout: TIMEOUTS.ONE_MIN}). + cy.findByText('Minimum password length must be a whole number greater than or equal to 5 and less than or equal to 72.', {timeout: TIMEOUTS.ONE_MIN}). should('exist'). and('be.visible'); @@ -37,7 +37,7 @@ describe('Authentication', () => { cy.uiSave(); // * Ensure error appears when saving a password outside of the limits - cy.findByText('Minimum password length must be a whole number greater than or equal to 5 and less than or equal to 64.', {timeout: TIMEOUTS.ONE_MIN}). + cy.findByText('Minimum password length must be a whole number greater than or equal to 5 and less than or equal to 72.', {timeout: TIMEOUTS.ONE_MIN}). should('exist'). and('be.visible'); }); @@ -49,7 +49,7 @@ describe('Authentication', () => { cy.uiSave(); - cy.findByText('Must be 7-64 characters long.').should('be.visible'); + cy.findByText('Must be 7-72 characters long.').should('be.visible'); cy.apiLogout(); @@ -65,7 +65,7 @@ describe('Authentication', () => { cy.findByText('Create Account').click(); // * Assert the error is what is expected; - cy.findByText('Must be 7-64 characters long.').should('be.visible'); + cy.findByText('Must be 7-72 characters long.').should('be.visible'); cy.get('#input_password-input').clear().type('greaterthan7'); @@ -118,7 +118,7 @@ describe('Authentication', () => { cy.findByText('Create Account').click(); // * Assert the error is what is expected; - cy.findByText('Must be 5-64 characters long and include both lowercase and uppercase letters, numbers, and special characters.').should('be.visible'); + cy.findByText('Must be 5-72 characters long and include both lowercase and uppercase letters, numbers, and special characters.').should('be.visible'); }); }); diff --git a/e2e-tests/cypress/tests/integration/channels/signin_authentication/signup_spec.js b/e2e-tests/cypress/tests/integration/channels/signin_authentication/signup_spec.js index 1c4fad4344..4cc15da233 100644 --- a/e2e-tests/cypress/tests/integration/channels/signin_authentication/signup_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/signin_authentication/signup_spec.js @@ -75,7 +75,7 @@ describe('Signup Email page', () => { cy.findByText('You can use lowercase letters, numbers, periods, dashes, and underscores.').should('be.visible'); cy.get('#input_password-input').should('be.visible').and('have.attr', 'placeholder', 'Choose a Password'); - cy.findByText('Must be 5-64 characters long.').should('be.visible'); + cy.findByText('Must be 5-72 characters long.').should('be.visible'); cy.get('#saveSetting').scrollIntoView().should('be.visible'); cy.get('#saveSetting').should('contain', 'Create Account'); diff --git a/e2e-tests/cypress/tests/integration/channels/system_console/user_management/users_spec.js b/e2e-tests/cypress/tests/integration/channels/system_console/user_management/users_spec.js index 7a0d7f34bd..53fef951fa 100644 --- a/e2e-tests/cypress/tests/integration/channels/system_console/user_management/users_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/system_console/user_management/users_spec.js @@ -160,7 +160,7 @@ describe('System Console > User Management > Users', () => { // * Verify the appropriate error is returned. cy.get('form.form-horizontal').find('.has-error p.error').should('be.visible'). - and('contain', 'Must be 5-64 characters long.'); + and('contain', 'Must be 5-72 characters long.'); }); it('MM-T936 Users - System admin changes own password - Blank fields', () => { @@ -188,7 +188,7 @@ describe('System Console > User Management > Users', () => { // * Verify the appropriate error is returned. cy.get('form.form-horizontal').find('.has-error p.error').should('be.visible'). - and('contain', 'Must be 5-64 characters long.'); + and('contain', 'Must be 5-72 characters long.'); }); it('MM-T937 Users - System admin changes own password - Successfully changed', () => { diff --git a/e2e-tests/playwright/support/ui/pages/signup.ts b/e2e-tests/playwright/support/ui/pages/signup.ts index 074db6fa5f..6012e70e87 100644 --- a/e2e-tests/playwright/support/ui/pages/signup.ts +++ b/e2e-tests/playwright/support/ui/pages/signup.ts @@ -46,7 +46,7 @@ export default class SignupPage { this.usernameError = page.locator( 'text=Usernames have to begin with a lowercase letter and be 3-22 characters long. You can use lowercase letters, numbers, periods, dashes, and underscores.', ); - this.passwordError = page.locator('text=Must be 5-64 characters long.'); + this.passwordError = page.locator('text=Must be 5-72 characters long.'); const newsletterBlock = page.locator('.check-input'); this.newsLetterCheckBox = newsletterBlock.getByRole('checkbox', {name: 'newsletter checkbox'}); diff --git a/server/channels/app/users/password.go b/server/channels/app/users/password.go index e187f6e099..bc6f6a59b4 100644 --- a/server/channels/app/users/password.go +++ b/server/channels/app/users/password.go @@ -48,8 +48,14 @@ func IsPasswordValidWithSettings(password string, settings *model.PasswordSettin id := "model.user.is_valid.pwd" isError := false - if len(password) < *settings.MinimumLength || len(password) > model.PasswordMaximumLength { + if len(password) < *settings.MinimumLength { isError = true + id = id + "_min_length" + } + + if len(password) > model.PasswordMaximumLength { + isError = true + id = id + "_max_length" } if *settings.Lowercase { diff --git a/server/channels/app/users/password_test.go b/server/channels/app/users/password_test.go index d0f78f082b..f98d8f12b1 100644 --- a/server/channels/app/users/password_test.go +++ b/server/channels/app/users/password_test.go @@ -54,7 +54,7 @@ func TestIsPasswordValidWithSettings(t *testing.T) { Number: model.NewBool(false), Symbol: model.NewBool(false), }, - ExpectedError: "model.user.is_valid.pwd.app_error", + ExpectedError: "model.user.is_valid.pwd_min_length.app_error", }, "TooLong": { Password: strings.Repeat("x", model.PasswordMaximumLength+1), @@ -64,7 +64,7 @@ func TestIsPasswordValidWithSettings(t *testing.T) { Number: model.NewBool(false), Symbol: model.NewBool(false), }, - ExpectedError: "model.user.is_valid.pwd.app_error", + ExpectedError: "model.user.is_valid.pwd_max_length.app_error", }, "MissingLower": { Password: "AAAAAAAAAAASD123!@#", diff --git a/server/i18n/en.json b/server/i18n/en.json index 8bd0903e16..06446acd1c 100644 --- a/server/i18n/en.json +++ b/server/i18n/en.json @@ -10018,10 +10018,6 @@ "id": "model.user.is_valid.position.app_error", "translation": "Invalid position: must not be longer than 128 characters." }, - { - "id": "model.user.is_valid.pwd.app_error", - "translation": "Your password must contain at least {{.Min}} characters." - }, { "id": "model.user.is_valid.pwd_lowercase.app_error", "translation": "Your password must contain at least {{.Min}} characters made up of at least one lowercase letter." @@ -10054,6 +10050,14 @@ "id": "model.user.is_valid.pwd_lowercase_uppercase_symbol.app_error", "translation": "Your password must contain at least {{.Min}} characters made up of at least one lowercase letter, at least one uppercase letter, and at least one symbol (e.g. \"~!@#$%^&*()\")." }, + { + "id": "model.user.is_valid.pwd_max_length.app_error", + "translation": "Your password must contain no more than 72 characters." + }, + { + "id": "model.user.is_valid.pwd_min_length.app_error", + "translation": "Your password must contain at least {{.Min}} characters." + }, { "id": "model.user.is_valid.pwd_number.app_error", "translation": "Your password must contain at least {{.Min}} characters made up of at least one number." diff --git a/server/public/model/config.go b/server/public/model/config.go index 3444349e0b..298a6d7d81 100644 --- a/server/public/model/config.go +++ b/server/public/model/config.go @@ -43,7 +43,7 @@ const ( MinioSecretKey = "miniosecretkey" MinioBucket = "mattermost-test" - PasswordMaximumLength = 64 + PasswordMaximumLength = 72 PasswordMinimumLength = 5 ServiceGitlab = "gitlab" diff --git a/tools/mmgotool/commands/i18n.go b/tools/mmgotool/commands/i18n.go index 909028e21b..be7a1cc70e 100644 --- a/tools/mmgotool/commands/i18n.go +++ b/tools/mmgotool/commands/i18n.go @@ -318,7 +318,8 @@ func checkCmdF(command *cobra.Command, args []string) error { } func addDynamicallyGeneratedStrings(i18nStrings map[string]bool) { - i18nStrings["model.user.is_valid.pwd.app_error"] = true + i18nStrings["model.user.is_valid.pwd_min_length.app_error"] = true + i18nStrings["model.user.is_valid.pwd_max_length.app_error"] = true i18nStrings["model.user.is_valid.pwd_lowercase.app_error"] = true i18nStrings["model.user.is_valid.pwd_lowercase_number.app_error"] = true i18nStrings["model.user.is_valid.pwd_lowercase_number_symbol.app_error"] = true diff --git a/webapp/channels/src/components/signup/__snapshots__/signup.test.tsx.snap b/webapp/channels/src/components/signup/__snapshots__/signup.test.tsx.snap index 5e46252572..ee6751f7fe 100644 --- a/webapp/channels/src/components/signup/__snapshots__/signup.test.tsx.snap +++ b/webapp/channels/src/components/signup/__snapshots__/signup.test.tsx.snap @@ -87,7 +87,7 @@ exports[`components/signup/Signup should match snapshot for all signup options e createMode={true} disabled={false} error="" - info="Must be 5-64 characters long." + info="Must be 5-72 characters long." inputSize="large" onBlur={[Function]} onChange={[Function]} @@ -261,7 +261,7 @@ exports[`components/signup/Signup should match snapshot for all signup options e createMode={true} disabled={false} error="" - info="Must be 5-64 characters long." + info="Must be 5-72 characters long." inputSize="large" onBlur={[Function]} onChange={[Function]} diff --git a/webapp/channels/src/utils/constants.tsx b/webapp/channels/src/utils/constants.tsx index 125ba9595f..d609b97896 100644 --- a/webapp/channels/src/utils/constants.tsx +++ b/webapp/channels/src/utils/constants.tsx @@ -1960,7 +1960,7 @@ export const Constants = { MAX_USERNAME_LENGTH: 22, MAX_NICKNAME_LENGTH: 64, MIN_PASSWORD_LENGTH: 5, - MAX_PASSWORD_LENGTH: 64, + MAX_PASSWORD_LENGTH: 72, MAX_POSITION_LENGTH: 128, MIN_TRIGGER_LENGTH: 1, MAX_TRIGGER_LENGTH: 128, diff --git a/webapp/channels/src/utils/utils.test.tsx b/webapp/channels/src/utils/utils.test.tsx index ceb8eacef2..95fccb02d3 100644 --- a/webapp/channels/src/utils/utils.test.tsx +++ b/webapp/channels/src/utils/utils.test.tsx @@ -124,6 +124,47 @@ describe('Utils.isValidPassword', () => { } }); + test('Maximum length enforced', () => { + for (const data of [ + { + password: 'justright', + config: { + minimumLength: 8, + requireLowercase: false, + requireUppercase: false, + requireNumber: false, + requireSymbol: false, + }, + valid: true, + }, + { + password: 'iamaverylongstringthathas72charactersandwillpasswithoutanyissuesthiscall', + config: { + minimumLength: 8, + requireLowercase: false, + requireUppercase: false, + requireNumber: false, + requireSymbol: false, + }, + valid: true, + }, + { + password: 'iamaverylongstringthathas73charactersandwontpassthisvalidationatall!!!:-(', + config: { + minimumLength: 8, + requireLowercase: false, + requireUppercase: false, + requireNumber: false, + requireSymbol: false, + }, + valid: false, + }, + ]) { + const {valid} = Utils.isValidPassword(data.password, data.config); + expect(data.valid).toEqual(valid); + } + }); + test('Require lowercase enforced', () => { for (const data of [ {