diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js index 581fb729c..cb066a2b1 100644 --- a/client/coral-framework/actions/auth.js +++ b/client/coral-framework/actions/auth.js @@ -84,7 +84,9 @@ export const fetchSignUp = formData => (dispatch, getState) => { dispatch(changeView('SIGNIN')); }, 3000); }) - .catch(() => dispatch(signUpFailure(lang.t('error.emailInUse')))); // We need to inprove error handling. TODO (bc) + .catch(error => { + dispatch(signUpFailure(lang.t(`error.${error.message}`))); + }); }; // Forgot Password Actions diff --git a/client/coral-framework/helpers/response.js b/client/coral-framework/helpers/response.js index d8bfd28c4..dc635e08b 100644 --- a/client/coral-framework/helpers/response.js +++ b/client/coral-framework/helpers/response.js @@ -28,7 +28,9 @@ const handleResp = res => { if (res.status === 401) { throw new Error('Not Authorized to make this request'); } else if (res.status > 399) { - throw new Error('Error! Status ', res.status); + return res.json().then(err => { + throw new Error(err.message || res.status); + }); } else if (res.status === 204) { return res.text(); } else { diff --git a/client/coral-framework/translations.json b/client/coral-framework/translations.json index 06a39944a..e52690db2 100644 --- a/client/coral-framework/translations.json +++ b/client/coral-framework/translations.json @@ -8,9 +8,15 @@ "email": "Not a valid E-Mail", "password": "Password must be at least 8 characters", "displayName": "Display name is too short", - "confirmPassword": "Passwords don`t match. Please, check again", + "confirmPassword": "Passwords don't match. Please, check again", "emailPasswordError": "Email and/or password combination incorrect.", - "emailInUse": "Email address already in use" + "EMAIL_REQUIRED": "An email address is required", + "PASSWORD_REQUIRED": "Must input a password", + "PASSWORD_LENGTH": "Password is too short", + "EMAIL_IN_USE": "Email address already in use", + "DISPLAY_NAME_REQUIRED": "Must input a display name", + "NO_SPECIAL_CHARACTERS": "Display names can contain letters, numbers and _ only", + "PROFANITY_ERROR": "Display names must not contain profanity. Please contact the administrator if you believe this to be in error." } }, "es": { @@ -24,7 +30,13 @@ "displayName": "El nombre es muy corto", "confirmPassword": "Las contraseñas no coinciden", "emailPasswordError": "Email y/o contraseña incorrecta.", - "emailInUse": "Email address already in use" + "EMAIL_REQUIRED": "An email address is required", + "PASSWORD_REQUIRED": "Must input a password", + "PASSWORD_LENGTH": "Password is too short", + "EMAIL_IN_USE": "Email address already in use", + "DISPLAY_NAME_REQUIRED": "Must input a display name", + "NO_SPECIAL_CHARACTERS": "Display names can contain letters, numbers and _", + "PROFANITY_ERROR": "Display names must not contain profanity. Please contact the administrator if you believe this to be an error" } } } diff --git a/models/naughty-words.json b/models/naughty-words.json new file mode 100644 index 000000000..3e7b8a383 --- /dev/null +++ b/models/naughty-words.json @@ -0,0 +1,444 @@ +[ +"4r5e", +"5h1t", +"5hit", +"a55", +"anal", +"anus", +"ar5e", +"arrse", +"arse", +"ass", +"ass-fucker", +"asses", +"assfucker", +"assfukka", +"asshole", +"assholes", +"asswhole", +"a_s_s", +"b!tch", +"b00bs", +"b17ch", +"b1tch", +"ballbag", +"balls", +"ballsack", +"bastard", +"beastial", +"beastiality", +"bellend", +"bestial", +"bestiality", +"bi+ch", +"biatch", +"bitch", +"bitcher", +"bitchers", +"bitches", +"bitchin", +"bitching", +"blow job", +"blowjob", +"blowjobs", +"boiolas", +"bollock", +"bollok", +"boner", +"boob", +"boobs", +"booobs", +"boooobs", +"booooobs", +"booooooobs", +"breasts", +"buceta", +"bugger", +"bum", +"bunny fucker", +"butt", +"butthole", +"buttmuch", +"buttplug", +"c0ck", +"c0cksucker", +"carpet muncher", +"cawk", +"chink", +"cipa", +"cl1t", +"clit", +"clitoris", +"clits", +"cnut", +"cock", +"cock-sucker", +"cockface", +"cockhead", +"cockmunch", +"cockmuncher", +"cocks", +"cocksuck", +"cocksucked", +"cocksucker", +"cocksucking", +"cocksucks", +"cocksuka", +"cocksukka", +"cok", +"cokmuncher", +"coksucka", +"coon", +"cox", +"crap", +"cum", +"cummer", +"cumming", +"cums", +"cumshot", +"cunilingus", +"cunillingus", +"cunnilingus", +"cunt", +"cuntlick", +"cuntlicker", +"cuntlicking", +"cunts", +"cyalis", +"cyberfuc", +"cyberfuck", +"cyberfucked", +"cyberfucker", +"cyberfuckers", +"cyberfucking", +"d1ck", +"dick", +"dickhead", +"dildo", +"dildos", +"dink", +"dinks", +"dirsa", +"dlck", +"dog-fucker", +"doggin", +"dogging", +"donkeyribber", +"doosh", +"duche", +"dyke", +"ejaculate", +"ejaculated", +"ejaculates", +"ejaculating", +"ejaculatings", +"ejaculation", +"ejakulate", +"f u c k", +"f u c k e r", +"f4nny", +"fag", +"fagging", +"faggitt", +"faggot", +"faggs", +"fagot", +"fagots", +"fags", +"fanny", +"fannyflaps", +"fannyfucker", +"fanyy", +"fatass", +"fcuk", +"fcuker", +"fcuking", +"feck", +"fecker", +"felching", +"fellate", +"fellatio", +"fingerfuck", +"fingerfucked", +"fingerfucker", +"fingerfuckers", +"fingerfucking", +"fingerfucks", +"fistfuck", +"fistfucked", +"fistfucker", +"fistfuckers", +"fistfucking", +"fistfuckings", +"fistfucks", +"flange", +"fook", +"fooker", +"fuck", +"fucka", +"fucked", +"fucker", +"fuckers", +"fuckhead", +"fuckheads", +"fuckin", +"fucking", +"fuckings", +"fuckingshitmotherfucker", +"fuckme", +"fucks", +"fuckwhit", +"fuckwit", +"fudge packer", +"fudgepacker", +"fuk", +"fuker", +"fukker", +"fukkin", +"fuks", +"fukwhit", +"fukwit", +"fux", +"fux0r", +"f_u_c_k", +"gangbang", +"gangbanged", +"gangbangs", +"gaylord", +"gaysex", +"goatse", +"hardcoresex", +"heshe", +"hoar", +"hoare", +"hoer", +"homo", +"hore", +"horniest", +"horny", +"hotsex", +"jack-off", +"jackoff", +"jap", +"jerk-off", +"jism", +"jiz", +"jizm", +"jizz", +"kawk", +"knob", +"knobead", +"knobed", +"knobend", +"knobhead", +"knobjocky", +"knobjokey", +"kock", +"kondum", +"kondums", +"kum", +"kummer", +"kumming", +"kums", +"kunilingus", +"l3i+ch", +"l3itch", +"labia", +"lmfao", +"lust", +"lusting", +"m0f0", +"m0fo", +"m45terbate", +"ma5terb8", +"ma5terbate", +"masochist", +"master-bate", +"masterb8", +"masterbat*", +"masterbat3", +"masterbate", +"masterbation", +"masterbations", +"masturbate", +"mo-fo", +"mof0", +"mofo", +"mothafuck", +"mothafucka", +"mothafuckas", +"mothafuckaz", +"mothafucked", +"mothafucker", +"mothafuckers", +"mothafuckin", +"mothafucking", +"mothafuckings", +"mothafucks", +"mother fucker", +"motherfuck", +"motherfucked", +"motherfucker", +"motherfuckers", +"motherfuckin", +"motherfucking", +"motherfuckings", +"motherfuckka", +"motherfucks", +"muff", +"mutha", +"muthafecker", +"muthafuckker", +"muther", +"mutherfucker", +"n1gga", +"n1gger", +"nazi", +"nigg3r", +"nigg4h", +"nigga", +"niggah", +"niggas", +"niggaz", +"nigger", +"niggers", +"nob", +"nob jokey", +"nobhead", +"nobjocky", +"nobjokey", +"numbnuts", +"nutsack", +"orgasim", +"orgasims", +"orgasm", +"orgasms", +"p0rn", +"pecker", +"penis", +"penisfucker", +"phonesex", +"phuck", +"phuk", +"phuked", +"phuking", +"phukked", +"phukking", +"phuks", +"phuq", +"pigfucker", +"pimpis", +"piss", +"pissed", +"pisser", +"pissers", +"pisses", +"pissflaps", +"pissin", +"pissing", +"pissoff", +"poop", +"porn", +"porno", +"pornography", +"pornos", +"prick", +"pricks", +"pron", +"pube", +"pusse", +"pussi", +"pussies", +"pussy", +"pussys", +"rectum", +"retard", +"rimjaw", +"rimming", +"s hit", +"s.o.b.", +"sadist", +"schlong", +"screwing", +"scroat", +"scrote", +"scrotum", +"semen", +"sex", +"sh!+", +"sh!t", +"sh1t", +"shag", +"shagger", +"shaggin", +"shagging", +"shemale", +"shi+", +"shit", +"shitdick", +"shite", +"shited", +"shitey", +"shitfuck", +"shitfull", +"shithead", +"shiting", +"shitings", +"shits", +"shitted", +"shitter", +"shitters", +"shitting", +"shittings", +"shitty", +"skank", +"slut", +"sluts", +"smegma", +"smut", +"snatch", +"son-of-a-bitch", +"spac", +"spunk", +"s_h_i_t", +"t1tt1e5", +"t1tties", +"teets", +"teez", +"testical", +"testicle", +"tit", +"titfuck", +"tits", +"titt", +"tittie5", +"tittiefucker", +"titties", +"tittyfuck", +"tittywank", +"titwank", +"tosser", +"turd", +"tw4t", +"twat", +"twathead", +"twatty", +"twunt", +"twunter", +"v14gra", +"v1gra", +"vagina", +"viagra", +"vulva", +"w00se", +"wang", +"wank", +"wanker", +"wanky", +"whoar", +"whore", +"willies", +"willy", +"xrated", +"xxx" +] diff --git a/models/user.js b/models/user.js index 7df713337..967244f54 100644 --- a/models/user.js +++ b/models/user.js @@ -4,9 +4,10 @@ const _ = require('lodash'); const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken'); const Action = require('./action'); - const Comment = require('./comment'); +const naughtyWords = require('./naughty-words.json'); + // SALT_ROUNDS is the number of rounds that the bcrypt algorithm will run // through during the salting process. const SALT_ROUNDS = 10; @@ -295,6 +296,41 @@ UserService.createLocalUsers = (users) => { })); }; +/** + * Check the requested displayname for naughty words (currently in English) and special chars + * @param {String} displayName word to be checked for profanity + * @return {Promise} rejected if the machine's sensibilites are offended + */ +const isValidDisplayName = (displayName) => { + const onlyLettersNumbersUnderscore = /^[a-z0-9_]+$/; + + if (!displayName) { + const ErrMissingDisplay = new Error('DISPLAY_NAME_REQUIRED'); + ErrMissingDisplay.status = 400; + return Promise.reject(ErrMissingDisplay); + } + + if (!onlyLettersNumbersUnderscore.test(displayName)) { + const ErrSpecialChars = new Error('NO_SPECIAL_CHARACTERS'); + ErrSpecialChars.status = 400; + return Promise.reject(ErrSpecialChars); + } + + const hasBadWords = naughtyWords.some(badWord => { + + // test the word AFTER the interspersed _ characters are removed. + return new RegExp(badWord, 'ig').test(displayName.replace(/_/g, '')); + }); + + if (hasBadWords) { + const ErrProfanity = new Error('PROFANITY_ERROR'); + ErrProfanity.status = 400; + return Promise.reject(ErrProfanity); + } else { + return Promise.resolve(displayName); + } +}; + /** * Creates the local user with a given email, password, and name. * @param {String} email email of the new user @@ -303,49 +339,62 @@ UserService.createLocalUsers = (users) => { * @param {Function} done callback */ UserService.createLocalUser = (email, password, displayName) => { + if (!email) { - return Promise.reject('email is required'); + const ErrMissingEmail = new Error('EMAIL_REQUIRED'); + ErrMissingEmail.status = 400; + return Promise.reject(ErrMissingEmail); } - email = email.toLowerCase(); + email = email.toLowerCase().trim(); + displayName = displayName.toLowerCase().trim(); if (!password) { - return Promise.reject('password is required'); + const ErrMissingPassword = new Error('PASSWORD_REQUIRED'); + ErrMissingPassword.status = 400; + return Promise.reject(ErrMissingPassword); } - if (!displayName) { - return Promise.reject('displayName is required'); + if (password.length < 8) { + const ErrPasswordTooShort = new Error('PASSWORD_LENGTH'); + ErrPasswordTooShort.status = 400; + return Promise.reject(ErrPasswordTooShort); } - return new Promise((resolve, reject) => { - bcrypt.hash(password, SALT_ROUNDS, (err, hashedPassword) => { - if (err) { - return reject(err); - } - - let user = new UserModel({ - displayName: displayName, - password: hashedPassword, - roles: [], - profiles: [ - { - id: email, - provider: 'local' + return isValidDisplayName(displayName) + .then(() => { // displayName is valid + return new Promise((resolve, reject) => { + bcrypt.hash(password, SALT_ROUNDS, (err, hashedPassword) => { + if (err) { + return reject(err); } - ] - }); - user.save((err) => { - if (err) { - if (err.code === 11000) { - return reject('Email address already in use'); - } - return reject(err); - } - return resolve(user); + let user = new UserModel({ + displayName: displayName, + password: hashedPassword, + roles: [], + profiles: [ + { + id: email, + provider: 'local' + } + ] + }); + + user.save((err) => { + if (err) { + if (err.code === 11000) { + const ErrEmailTaken = new Error('EMAIL_IN_USE'); + ErrEmailTaken.status = 400; + return reject(ErrEmailTaken); + } + return reject(err); + } + return resolve(user); + }); + }); }); }); - }); }; /**