-
Notifications
You must be signed in to change notification settings - Fork 10.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[NEW] Implement a local password policy (#9857)
* Implement a local password policy * Improve ValidatePasswordPolicy and create tests * Validate user’s password on method saveUserProfile * Fix typo PasswordPoliceClass
- Loading branch information
1 parent
1070edf
commit 3ed656b
Showing
10 changed files
with
396 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
class PasswordPolicy { | ||
constructor({ | ||
enabled = false, | ||
minLength = -1, | ||
maxLength = -1, | ||
forbidRepeatingCharacters = false, | ||
forbidRepeatingCharactersCount = 3, //the regex is this number minus one | ||
mustContainAtLeastOneLowercase = false, // /[A-Z]{3,}/ could do this instead of at least one | ||
mustContainAtLeastOneUppercase = false, | ||
mustContainAtLeastOneNumber = false, | ||
mustContainAtLeastOneSpecialCharacter = false, | ||
throwError = true | ||
} = {}) { | ||
this.regex = { | ||
mustContainAtLeastOneLowercase: new RegExp('[a-z]'), | ||
mustContainAtLeastOneUppercase: new RegExp('[A-Z]'), | ||
mustContainAtLeastOneNumber: new RegExp('[0-9]'), | ||
mustContainAtLeastOneSpecialCharacter: new RegExp('[^A-Za-z0-9 ]') | ||
}; | ||
|
||
this.enabled = enabled; | ||
this.minLength = minLength; | ||
this.maxLength = maxLength; | ||
this.forbidRepeatingCharacters = forbidRepeatingCharacters; | ||
this.forbidRepeatingCharactersCount = forbidRepeatingCharactersCount; | ||
this.mustContainAtLeastOneLowercase = mustContainAtLeastOneLowercase; | ||
this.mustContainAtLeastOneUppercase = mustContainAtLeastOneUppercase; | ||
this.mustContainAtLeastOneNumber = mustContainAtLeastOneNumber; | ||
this.mustContainAtLeastOneSpecialCharacter = mustContainAtLeastOneSpecialCharacter; | ||
this.throwError = throwError; | ||
} | ||
|
||
set forbidRepeatingCharactersCount(value) { | ||
this._forbidRepeatingCharactersCount = value; | ||
this.regex.forbiddingRepeatingCharacters = new RegExp(`(.)\\1{${ this.forbidRepeatingCharactersCount },}`); | ||
} | ||
|
||
get forbidRepeatingCharactersCount() { | ||
return this._forbidRepeatingCharactersCount; | ||
} | ||
|
||
error(error, message) { | ||
if (this.throwError) { | ||
throw new Meteor.Error(error, message); | ||
} | ||
|
||
return false; | ||
} | ||
|
||
validate(password) { | ||
if (!this.enabled) { | ||
return true; | ||
} | ||
|
||
if (!password || typeof password !== 'string' || !password.length) { | ||
return this.error('error-password-policy-not-met', 'The password provided does not meet the server\'s password policy.'); | ||
} | ||
|
||
if (this.minLength >= 1 && password.length < this.minLength) { | ||
return this.error('error-password-policy-not-met-minLength', 'The password does not meet the minimum length password policy.'); | ||
} | ||
|
||
if (this.maxLength >= 1 && password.length > this.maxLength) { | ||
return this.error('error-password-policy-not-met-maxLength', 'The password does not meet the maximum length password policy.'); | ||
} | ||
|
||
if (this.forbidRepeatingCharacters && this.regex.forbiddingRepeatingCharacters.test(password)) { | ||
return this.error('error-password-policy-not-met-repeatingCharacters', 'The password contains repeating characters which is against the password policy.'); | ||
} | ||
|
||
if (this.mustContainAtLeastOneLowercase && !this.regex.mustContainAtLeastOneLowercase.test(password)) { | ||
return this.error('error-password-policy-not-met-oneLowercase', 'The password does not contain at least one lowercase character which is against the password policy.'); | ||
} | ||
|
||
if (this.mustContainAtLeastOneUppercase && !this.regex.mustContainAtLeastOneUppercase.test(password)) { | ||
return this.error('error-password-policy-not-met-oneUppercase', 'The password does not contain at least one uppercase character which is against the password policy.'); | ||
} | ||
|
||
if (this.mustContainAtLeastOneNumber && !this.regex.mustContainAtLeastOneNumber.test(password)) { | ||
return this.error('error-password-policy-not-met-oneNumber', 'The password does not contain at least one numerical character which is against the password policy.'); | ||
} | ||
|
||
if (this.mustContainAtLeastOneSpecialCharacter && !this.regex.mustContainAtLeastOneSpecialCharacter.test(password)) { | ||
return this.error('error-password-policy-not-met-oneSpecial', 'The password does not contain at least one special character which is against the password policy.'); | ||
} | ||
|
||
return true; | ||
} | ||
} | ||
|
||
export default PasswordPolicy; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import PasswordPolicy from './PasswordPolicyClass'; | ||
|
||
RocketChat.passwordPolicy = new PasswordPolicy(); | ||
|
||
RocketChat.settings.get('Accounts_Password_Policy_Enabled', (key, value) => RocketChat.passwordPolicy.enabled = value); | ||
RocketChat.settings.get('Accounts_Password_Policy_MinLength', (key, value) => RocketChat.passwordPolicy.minLength = value); | ||
RocketChat.settings.get('Accounts_Password_Policy_MaxLength', (key, value) => RocketChat.passwordPolicy.maxLength = value); | ||
RocketChat.settings.get('Accounts_Password_Policy_ForbidRepeatingCharacters', (key, value) => RocketChat.passwordPolicy.forbidRepeatingCharacters = value); | ||
RocketChat.settings.get('Accounts_Password_Policy_ForbidRepeatingCharactersCount', (key, value) => RocketChat.passwordPolicy.forbidRepeatingCharactersCount = value); | ||
RocketChat.settings.get('Accounts_Password_Policy_AtLeastOneLowercase', (key, value) => RocketChat.passwordPolicy.mustContainAtLeastOneLowercase = value); | ||
RocketChat.settings.get('Accounts_Password_Policy_AtLeastOneUppercase', (key, value) => RocketChat.passwordPolicy.mustContainAtLeastOneUppercase = value); | ||
RocketChat.settings.get('Accounts_Password_Policy_AtLeastOneNumber', (key, value) => RocketChat.passwordPolicy.mustContainAtLeastOneNumber = value); | ||
RocketChat.settings.get('Accounts_Password_Policy_AtLeastOneSpecialCharacter', (key, value) => RocketChat.passwordPolicy.mustContainAtLeastOneSpecialCharacter = value); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.