diff --git a/services/web/app/src/Features/Authentication/AuthenticationManager.js b/services/web/app/src/Features/Authentication/AuthenticationManager.js index 75b7078186..9195352313 100644 --- a/services/web/app/src/Features/Authentication/AuthenticationManager.js +++ b/services/web/app/src/Features/Authentication/AuthenticationManager.js @@ -14,6 +14,7 @@ const util = require('util') const HaveIBeenPwned = require('./HaveIBeenPwned') const UserAuditLogHandler = require('../User/UserAuditLogHandler') const logger = require('@overleaf/logger') +const Metrics = require('@overleaf/metrics') const BCRYPT_ROUNDS = Settings.security.bcryptRounds || 12 const BCRYPT_MINOR_VERSION = Settings.security.bcryptMinorVersion || 'a' @@ -38,6 +39,14 @@ function _validatePasswordNotTooLong(password) { return null } +function _metricsForSuccessfulPasswordMatch(password) { + const validationResult = AuthenticationManager.validatePassword(password) + const status = + validationResult === null ? 'success' : validationResult?.info?.code + Metrics.inc('check-password', { status }) + return null +} + const AuthenticationManager = { _checkUserPassword(query, password, callback) { // Using Mongoose for legacy reasons here. The returned User instance @@ -54,6 +63,9 @@ const AuthenticationManager = { if (error) { return callback(error) } + if (match) { + _metricsForSuccessfulPasswordMatch(password) + } return callback(null, user, match) }) }) @@ -157,7 +169,7 @@ const AuthenticationManager = { } } allowAnyChars = !!allowAnyChars - min = min || 6 + min = min || 8 max = max || 72 // we don't support passwords > 72 characters in length, because bcrypt truncates them diff --git a/services/web/app/views/user/setPassword.pug b/services/web/app/views/user/setPassword.pug index 859cb656d6..9ff95fbad2 100644 --- a/services/web/app/views/user/setPassword.pug +++ b/services/web/app/views/user/setPassword.pug @@ -63,7 +63,7 @@ block content div(data-ol-hide-on-error-message="token-expired") div #{translate('in_order_to_have_a_secure_account_make_sure_your_password')} ul.mb-4.ps-4 - li #{translate('is_longer_than_n_characters', {n: 6})} + li #{translate('is_longer_than_n_characters', {n: settings.passwordStrengthOptions.length.min})} li #{translate('does_not_contain_or_significantly_match_your_email')} li !{translate('is_not_a_common_or_obvious_password_as_defined_by_the_have_i_been_pwned_database', {}, [{name: 'a', attrs: {href: 'https://haveibeenpwned.com', rel: 'noopener noreferrer', target: '_blank'}}])} .actions diff --git a/services/web/config/settings.defaults.js b/services/web/config/settings.defaults.js index 103289f38a..3862fcac13 100644 --- a/services/web/config/settings.defaults.js +++ b/services/web/config/settings.defaults.js @@ -444,7 +444,7 @@ module.exports = { // opts are from http://antelle.github.io/passfield passwordStrengthOptions: { length: { - min: 6, + min: 8, // Bcrypt does not support longer passwords than that. max: 72, }, diff --git a/services/web/frontend/js/features/settings/components/password-section.tsx b/services/web/frontend/js/features/settings/components/password-section.tsx index 9cc846d561..70620d13b0 100644 --- a/services/web/frontend/js/features/settings/components/password-section.tsx +++ b/services/web/frontend/js/features/settings/components/password-section.tsx @@ -128,7 +128,7 @@ function PasswordForm() { label={t('new_password')} value={newPassword1} handleChange={handleNewPassword1Change} - minLength={passwordStrengthOptions?.length?.min || 6} + minLength={passwordStrengthOptions?.length?.min || 8} autoComplete="new-password" />