FEATURE: enforce admin password validation when signing up via developer email

This commit is contained in:
Arpit Jalan 2016-03-03 23:31:31 +05:30
parent 04990e7c5c
commit 36f82aa68c
4 changed files with 44 additions and 35 deletions

View File

@ -16,6 +16,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
rejectedPasswords: Em.A([]), rejectedPasswords: Em.A([]),
prefilledUsername: null, prefilledUsername: null,
userFields: null, userFields: null,
isDeveloper: false,
hasAuthOptions: Em.computed.notEmpty('authOptions'), hasAuthOptions: Em.computed.notEmpty('authOptions'),
canCreateLocal: setting('enable_local_logins'), canCreateLocal: setting('enable_local_logins'),
@ -37,6 +38,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
rejectedEmails: [], rejectedEmails: [],
rejectedPasswords: [], rejectedPasswords: [],
prefilledUsername: null, prefilledUsername: null,
isDeveloper: false
}); });
this._createUserFields(); this._createUserFields();
}, },
@ -70,8 +72,8 @@ export default Ember.Controller.extend(ModalFunctionality, {
}.property('authOptions.auth_provider'), }.property('authOptions.auth_provider'),
passwordInstructions: function() { passwordInstructions: function() {
return I18n.t('user.password.instructions', {count: Discourse.SiteSettings.min_password_length}); return this.get('isDeveloper') ? I18n.t('user.password.instructions', {count: Discourse.SiteSettings.min_admin_password_length}) : I18n.t('user.password.instructions', {count: Discourse.SiteSettings.min_password_length});
}.property(), }.property('isDeveloper'),
nameInstructions: function() { nameInstructions: function() {
return I18n.t(Discourse.SiteSettings.full_name_required ? 'user.name.instructions_required' : 'user.name.instructions'); return I18n.t(Discourse.SiteSettings.full_name_required ? 'user.name.instructions_required' : 'user.name.instructions');
@ -228,41 +230,27 @@ export default Ember.Controller.extend(ModalFunctionality, {
const _this = this; const _this = this;
if (this.shouldCheckUsernameMatch()) { if (this.shouldCheckUsernameMatch()) {
return Discourse.User.checkUsername(this.get('accountUsername'), this.get('accountEmail')).then(function(result) { return Discourse.User.checkUsername(this.get('accountUsername'), this.get('accountEmail')).then(function(result) {
_this.set('globalNicknameExists', false); _this.set('isDeveloper', false);
if (result.available) { if (result.available) {
if (result.global_match) { if (result.is_developer) {
_this.set('globalNicknameExists', true); _this.set('isDeveloper', true);
return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
ok: true,
reason: I18n.t('user.username.global_match')
}));
} else {
return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
ok: true,
reason: I18n.t('user.username.available')
}));
} }
return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
ok: true,
reason: I18n.t('user.username.available')
}));
} else { } else {
if (result.suggestion) { if (result.suggestion) {
if (result.global_match !== void 0 && result.global_match === false) { return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
_this.set('globalNicknameExists', true); failed: true,
return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({ reason: I18n.t('user.username.not_available', result)
failed: true, }));
reason: I18n.t('user.username.global_mismatch', result)
}));
} else {
return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
failed: true,
reason: I18n.t('user.username.not_available', result)
}));
}
} else if (result.errors) { } else if (result.errors) {
return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({ return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
failed: true, failed: true,
reason: result.errors.join(' ') reason: result.errors.join(' ')
})); }));
} else { } else {
_this.set('globalNicknameExists', true);
return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({ return _this.set('uniqueUsernameValidation', Discourse.InputValidation.create({
failed: true, failed: true,
reason: I18n.t('user.username.enter_email') reason: I18n.t('user.username.enter_email')
@ -296,8 +284,16 @@ export default Ember.Controller.extend(ModalFunctionality, {
return Discourse.InputValidation.create({ failed: true }); return Discourse.InputValidation.create({ failed: true });
} }
// If too short // If too short for Admin
if (password.length < Discourse.SiteSettings.min_password_length) { if (this.get('isDeveloper') && password.length < Discourse.SiteSettings.min_admin_password_length) {
return Discourse.InputValidation.create({
failed: true,
reason: I18n.t('user.password.too_short')
});
}
// If too short for normal user
if (!this.get('isDeveloper') && password.length < Discourse.SiteSettings.min_password_length) {
return Discourse.InputValidation.create({ return Discourse.InputValidation.create({
failed: true, failed: true,
reason: I18n.t('user.password.too_short') reason: I18n.t('user.password.too_short')
@ -330,7 +326,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
ok: true, ok: true,
reason: I18n.t('user.password.ok') reason: I18n.t('user.password.ok')
}); });
}.property('accountPassword', 'rejectedPasswords.@each', 'accountUsername', 'accountEmail'), }.property('accountPassword', 'rejectedPasswords.@each', 'accountUsername', 'accountEmail', 'isDeveloper'),
@on('init') @on('init')
fetchConfirmationValue() { fetchConfirmationValue() {
@ -360,6 +356,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
this.set('formSubmitted', true); this.set('formSubmitted', true);
return Discourse.User.createAccount(attrs).then(function(result) { return Discourse.User.createAccount(attrs).then(function(result) {
self.set('isDeveloper', false);
if (result.success) { if (result.success) {
// Trigger the browser's password manager using the hidden static login form: // Trigger the browser's password manager using the hidden static login form:
const $hidden_login_form = $('#hidden-login-form'); const $hidden_login_form = $('#hidden-login-form');
@ -369,6 +366,9 @@ export default Ember.Controller.extend(ModalFunctionality, {
$hidden_login_form.submit(); $hidden_login_form.submit();
} else { } else {
self.flash(result.message || I18n.t('create_account.failed'), 'error'); self.flash(result.message || I18n.t('create_account.failed'), 'error');
if (result.is_developer) {
self.set('isDeveloper', true);
}
if (result.errors && result.errors.email && result.errors.email.length > 0 && result.values) { if (result.errors && result.errors.email && result.errors.email.length > 0 && result.values) {
self.get('rejectedEmails').pushObject(result.values.email); self.get('rejectedEmails').pushObject(result.values.email);
} }

View File

@ -343,7 +343,8 @@ class UsersController < ApplicationController
errors: user.errors.full_messages.join("\n") errors: user.errors.full_messages.join("\n")
), ),
errors: user.errors.to_hash, errors: user.errors.to_hash,
values: user.attributes.slice('name', 'username', 'email') values: user.attributes.slice('name', 'username', 'email'),
is_developer: UsernameCheckerService.new.is_developer?(user.email)
} }
end end
rescue ActiveRecord::StatementInvalid rescue ActiveRecord::StatementInvalid

View File

@ -6,17 +6,21 @@ class UsernameCheckerService
if !validator.valid_format? if !validator.valid_format?
{errors: validator.errors} {errors: validator.errors}
else else
check_username_availability(username) check_username_availability(username, email)
end end
end end
end end
def check_username_availability(username) def check_username_availability(username, email)
if User.username_available?(username) if User.username_available?(username)
{ available: true } { available: true, is_developer: is_developer?(email) }
else else
{ available: false, suggestion: UserNameSuggester.suggest(username) } { available: false, suggestion: UserNameSuggester.suggest(username) }
end end
end end
def is_developer?(value)
Rails.configuration.respond_to?(:developer_emails) && Rails.configuration.developer_emails.include?(value)
end
end end

View File

@ -6,7 +6,7 @@ class PasswordValidator < ActiveModel::EachValidator
return unless record.password_required? return unless record.password_required?
if value.nil? if value.nil?
record.errors.add(attribute, :blank) record.errors.add(attribute, :blank)
elsif value.length < SiteSetting.min_admin_password_length && record.admin? elsif value.length < SiteSetting.min_admin_password_length && (record.admin? || is_developer?(record.email))
record.errors.add(attribute, :too_short, count: SiteSetting.min_admin_password_length) record.errors.add(attribute, :too_short, count: SiteSetting.min_admin_password_length)
elsif value.length < SiteSetting.min_password_length elsif value.length < SiteSetting.min_password_length
record.errors.add(attribute, :too_short, count: SiteSetting.min_password_length) record.errors.add(attribute, :too_short, count: SiteSetting.min_password_length)
@ -19,4 +19,8 @@ class PasswordValidator < ActiveModel::EachValidator
end end
end end
def is_developer?(value)
Rails.configuration.respond_to?(:developer_emails) && Rails.configuration.developer_emails.include?(value)
end
end end