mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 22:57:21 +01:00
add blocker to block emails from registration
This commit is contained in:
@@ -29,7 +29,7 @@ function checkErrorNotThrown (next) {
|
|||||||
expect(typeof calledWith[0] === 'undefined').to.equal(true);
|
expect(typeof calledWith[0] === 'undefined').to.equal(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('Blocker middleware', () => {
|
describe.only('Blocker middleware', () => {
|
||||||
const pathToBlocker = '../../../../website/server/middlewares/blocker';
|
const pathToBlocker = '../../../../website/server/middlewares/blocker';
|
||||||
|
|
||||||
let res; let req; let next;
|
let res; let req; let next;
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import requireAgain from 'require-again';
|
||||||
import { model as User } from '../../../../website/server/models/user';
|
import { model as User } from '../../../../website/server/models/user';
|
||||||
import { model as NewsPost } from '../../../../website/server/models/newsPost';
|
import { model as NewsPost } from '../../../../website/server/models/newsPost';
|
||||||
import { model as Group } from '../../../../website/server/models/group';
|
import { model as Group } from '../../../../website/server/models/group';
|
||||||
|
import { model as Blocker } from '../../../../website/server/models/blocker';
|
||||||
import common from '../../../../website/common';
|
import common from '../../../../website/common';
|
||||||
|
|
||||||
|
const pathToUserSchema = '../../../../website/server/models/user/schema';
|
||||||
|
|
||||||
describe('User Model', () => {
|
describe('User Model', () => {
|
||||||
describe('.toJSON()', () => {
|
describe('.toJSON()', () => {
|
||||||
it('keeps user._tmp when calling .toJSON', () => {
|
it('keeps user._tmp when calling .toJSON', () => {
|
||||||
@@ -912,4 +916,73 @@ describe('User Model', () => {
|
|||||||
expect(user.toJSON().flags.newStuff).to.equal(true);
|
expect(user.toJSON().flags.newStuff).to.equal(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe.only('validates email', () => {
|
||||||
|
it('does not throw an error for a valid email', () => {
|
||||||
|
const user = new User();
|
||||||
|
user.auth.local.email = 'hello@example.com';
|
||||||
|
const errors = user.validateSync();
|
||||||
|
expect(errors.errors['auth.local.email']).to.not.exist;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error if email is not valid', () => {
|
||||||
|
const user = new User();
|
||||||
|
user.auth.local.email = 'invalid-email';
|
||||||
|
const errors = user.validateSync();
|
||||||
|
expect(errors.errors['auth.local.email'].message).to.equal(common.i18n.t('invalidEmail'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error if email is using a restricted domain', () => {
|
||||||
|
const user = new User();
|
||||||
|
user.auth.local.email = 'scammer@habitica.com';
|
||||||
|
const errors = user.validateSync();
|
||||||
|
expect(errors.errors['auth.local.email'].message).to.equal(common.i18n.t('invalidEmailDomain', { domains: 'habitica.com, habitrpg.com' }));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error if email was blocked specifically', () => {
|
||||||
|
sandbox.stub(Blocker, 'watchBlockers').returns({
|
||||||
|
on: (event, callback) => {
|
||||||
|
callback({ operation: 'add', blocker: { type: 'email', area: 'full', value: 'blocked@example.com' } });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const schema = requireAgain(pathToUserSchema).UserSchema;
|
||||||
|
const valid = schema.paths['auth.local.email'].options.validate.every(v => v.validator('blocked@example.com'))
|
||||||
|
expect(valid).to.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error if email domain was blocked', () => {
|
||||||
|
sandbox.stub(Blocker, 'watchBlockers').returns({
|
||||||
|
on: (event, callback) => {
|
||||||
|
callback({ operation: 'add', blocker: { type: 'email', area: 'full', value: '@example.com' } });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const schema = requireAgain(pathToUserSchema).UserSchema;
|
||||||
|
const valid = schema.paths['auth.local.email'].options.validate.every(v => v.validator('blocked@example.com'));
|
||||||
|
expect(valid).to.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error if user portion of email was blocked', () => {
|
||||||
|
sandbox.stub(Blocker, 'watchBlockers').returns({
|
||||||
|
on: (event, callback) => {
|
||||||
|
callback({ operation: 'add', blocker: { type: 'email', area: 'full', value: 'blocked@' } });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const schema = requireAgain(pathToUserSchema).UserSchema;
|
||||||
|
const valid = schema.paths['auth.local.email'].options.validate.every(v => v.validator('blocked@example.com'));
|
||||||
|
expect(valid).to.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error if email is not blocked', () => {
|
||||||
|
sandbox.stub(Blocker, 'watchBlockers').returns({
|
||||||
|
on: (event, callback) => {
|
||||||
|
callback({ operation: 'add', blocker: { type: 'email', area: 'full', value: '@example.com' } });
|
||||||
|
callback({ operation: 'add', blocker: { type: 'email', area: 'full', value: 'blocked@' } });
|
||||||
|
callback({ operation: 'add', blocker: { type: 'email', area: 'full', value: 'bad@test.com' } });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const schema = requireAgain(pathToUserSchema).UserSchema;
|
||||||
|
const valid = schema.paths['auth.local.email'].options.validate.every(v => v.validator('good@test.com'));
|
||||||
|
expect(valid).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,9 +9,31 @@ import { schema as SubscriptionPlanSchema } from '../subscriptionPlan';
|
|||||||
import { schema as TagSchema } from '../tag';
|
import { schema as TagSchema } from '../tag';
|
||||||
import { schema as UserNotificationSchema } from '../userNotification';
|
import { schema as UserNotificationSchema } from '../userNotification';
|
||||||
import { schema as WebhookSchema } from '../webhook';
|
import { schema as WebhookSchema } from '../webhook';
|
||||||
|
import { model as Blocker } from '../blocker';
|
||||||
|
|
||||||
const RESTRICTED_EMAIL_DOMAINS = Object.freeze(['habitica.com', 'habitrpg.com']);
|
const RESTRICTED_EMAIL_DOMAINS = Object.freeze(['habitica.com', 'habitrpg.com']);
|
||||||
|
|
||||||
|
const BLOCKED_EMAILS = [];
|
||||||
|
|
||||||
|
Blocker.watchBlockers({
|
||||||
|
type: 'email',
|
||||||
|
area: 'full',
|
||||||
|
}, {
|
||||||
|
initial: true,
|
||||||
|
}).on('change', async change => {
|
||||||
|
const { operation, blocker: { value } } = change;
|
||||||
|
if (operation === 'add') {
|
||||||
|
if (value && !BLOCKED_EMAILS.includes(value)) {
|
||||||
|
BLOCKED_EMAILS.push(value);
|
||||||
|
}
|
||||||
|
} else if (operation === 'delete') {
|
||||||
|
const index = BLOCKED_EMAILS.indexOf(value);
|
||||||
|
if (index !== -1) {
|
||||||
|
BLOCKED_EMAILS.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// User schema definition
|
// User schema definition
|
||||||
export const UserSchema = new Schema({
|
export const UserSchema = new Schema({
|
||||||
apiToken: {
|
apiToken: {
|
||||||
@@ -43,6 +65,12 @@ export const UserSchema = new Schema({
|
|||||||
return RESTRICTED_EMAIL_DOMAINS.every(domain => !lowercaseEmail.endsWith(`@${domain}`));
|
return RESTRICTED_EMAIL_DOMAINS.every(domain => !lowercaseEmail.endsWith(`@${domain}`));
|
||||||
},
|
},
|
||||||
message: shared.i18n.t('invalidEmailDomain', { domains: RESTRICTED_EMAIL_DOMAINS.join(', ') }),
|
message: shared.i18n.t('invalidEmailDomain', { domains: RESTRICTED_EMAIL_DOMAINS.join(', ') }),
|
||||||
|
}, {
|
||||||
|
validator (email) {
|
||||||
|
const lowercaseEmail = email.toLowerCase();
|
||||||
|
return BLOCKED_EMAILS.every(block => lowercaseEmail.indexOf(block) === -1);
|
||||||
|
},
|
||||||
|
message: shared.i18n.t('emailBlockedRegistration'),
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
username: {
|
username: {
|
||||||
|
|||||||
Reference in New Issue
Block a user