Merge pull request #1540 from sharelatex/ns-less-spam-mail

add spam checkers on project invite emails

GitOrigin-RevId: 305825efe6a824b1c0f5b347d2ed2427165d2cef
This commit is contained in:
nate stemen 2019-03-06 14:36:50 -05:00 committed by James Allen
parent f5ecc5ad85
commit f699877959
6 changed files with 601 additions and 31 deletions

View file

@ -6,6 +6,7 @@ StringHelper = require "../Helpers/StringHelper"
PersonalEmailLayout = require("./Layouts/PersonalEmailLayout")
NotificationEmailLayout = require("./Layouts/NotificationEmailLayout")
BaseWithHeaderEmailLayout = require("./Layouts/" + settings.brandPrefix + "BaseWithHeaderEmailLayout")
SpamSafe = require("./SpamSafe")
SingleCTAEmailBody = require("./Bodies/" + settings.brandPrefix + "SingleCTAEmailBody")
@ -101,20 +102,20 @@ templates.confirmEmail = CTAEmailTemplate({
})
templates.projectInvite = CTAEmailTemplate({
subject: (opts) -> "#{ _.escape(opts.project.name) } - shared by #{ _.escape(opts.owner.email) }"
title: (opts) -> "#{ _.escape(opts.project.name) } - shared by #{ _.escape(opts.owner.email) }"
message: (opts) -> "#{ _.escape(opts.owner.email) } wants to share '#{ _.escape(opts.project.name) }' with you."
subject: (opts) -> "#{ _.escape(SpamSafe.safeProjectName(opts.project.name, "New Project")) } - shared by #{ _.escape(SpamSafe.safeEmail(opts.owner.email, "a collaborator")) }"
title: (opts) -> "#{ _.escape(SpamSafe.safeProjectName(opts.project.name, "New Project")) } - shared by #{ _.escape(SpamSafe.safeEmail(opts.owner.email, "a collaborator")) }"
message: (opts) -> "#{ _.escape(SpamSafe.safeEmail(opts.owner.email, "a collaborator")) } wants to share '#{ _.escape(SpamSafe.safeProjectName(opts.project.name, "a new Project")) }' with you."
ctaText: () -> "View project"
ctaURL: (opts) -> opts.inviteUrl
gmailGoToAction: (opts) ->
target: opts.inviteUrl
name: "View project"
description: "Join #{ _.escape(opts.project.name) } at #{ settings.appName }"
description: "Join #{ _.escape(SpamSafe.safeProjectName(opts.project.name, "Project")) } at #{ settings.appName }"
})
templates.verifyEmailToJoinTeam = CTAEmailTemplate({
subject: (opts) -> "#{ _.escape(opts.inviterName) } has invited you to join a team on #{ settings.appName }"
title: (opts) -> "#{ _.escape(opts.inviterName) } has invited you to join a team on #{ settings.appName }"
subject: (opts) -> "#{ _.escape(SpamSafe.safeUserName(opts.inviterName, "A collaborator")) } has invited you to join a team on #{ settings.appName }"
title: (opts) -> "#{ _.escape(SpamSafe.safeUserName(opts.inviterName, "A collaborator")) } has invited you to join a team on #{ settings.appName }"
message: (opts) -> "Please click the button below to join the team and enjoy the benefits of an upgraded #{ settings.appName } account."
ctaText: (opts) -> "Join now"
ctaURL: (opts) -> opts.acceptInviteUrl

View file

@ -0,0 +1,38 @@
XRegExp = require('xregexp')
# A note about SAFE_REGEX:
# We have to escape the escape characters because XRegExp compiles it first.
# So it's equivalent to `^[\p{L}\p{N}\s\-_!&\(\)]+$]
# \p{L} = any letter in any language
# \p{N} = any kind of numeric character
# https://www.regular-expressions.info/unicode.html#prop is a good resource for
# more obscure regex features. standard RegExp does not support these
SAFE_REGEX = XRegExp("^[\\p{L}\\p{N}\\s\\-_!&\\(\\)]+$")
EMAIL_REGEX = XRegExp("^[\\p{L}\\p{N}.+_-]+@[\\w.]+$")
SpamSafe =
isSafeUserName: (name) ->
SAFE_REGEX.test(name) && name.length <= 30
isSafeProjectName: (name) ->
if XRegExp("\\p{Han}").test(name)
SAFE_REGEX.test(name) && name.length <= 30
SAFE_REGEX.test(name) && name.length <= 100
isSafeEmail: (email) ->
EMAIL_REGEX.test(email) && email.length <= 40
safeUserName: (name, alternative, project = false) ->
return name if SpamSafe.isSafeUserName name
alternative
safeProjectName: (name, alternative) ->
return name if SpamSafe.isSafeProjectName name
alternative
safeEmail: (email, alternative) ->
return email if SpamSafe.isSafeEmail email
alternative
module.exports = SpamSafe

View file

@ -16,6 +16,23 @@
}
}
},
"@babel/runtime-corejs2": {
"version": "7.3.1",
"from": "@babel/runtime-corejs2@>=7.2.0 <8.0.0",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.3.1.tgz",
"dependencies": {
"core-js": {
"version": "2.6.5",
"from": "core-js@>=2.5.7 <3.0.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz"
},
"regenerator-runtime": {
"version": "0.12.1",
"from": "regenerator-runtime@>=0.12.0 <0.13.0",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz"
}
}
},
"@contentful/axios": {
"version": "0.18.0",
"from": "@contentful/axios@>=0.18.0 <0.19.0",
@ -1897,7 +1914,7 @@
"readable-stream": {
"version": "2.3.6",
"from": "readable-stream@^2.0.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"dev": true
},
"readdirp": {
@ -2000,7 +2017,7 @@
},
"source-map": {
"version": "0.6.1",
"from": "source-map@~0.6.0",
"from": "source-map@>=0.6.0 <0.7.0",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"dev": true
}
@ -2210,7 +2227,7 @@
"readable-stream": {
"version": "2.3.6",
"from": "readable-stream@>=2.2.2 <3.0.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz"
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz"
},
"string_decoder": {
"version": "1.1.1",
@ -4142,6 +4159,466 @@
"from": "fs.realpath@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
},
"fsevents": {
"version": "1.2.7",
"from": "fsevents@^1.0.0",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz",
"dev": true,
"optional": true,
"dependencies": {
"abbrev": {
"version": "1.1.1",
"from": "abbrev@1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"dev": true,
"optional": true
},
"ansi-regex": {
"version": "2.1.1",
"from": "ansi-regex@^2.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"dev": true
},
"aproba": {
"version": "1.2.0",
"from": "aproba@^1.0.3",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
"dev": true,
"optional": true
},
"are-we-there-yet": {
"version": "1.1.5",
"from": "are-we-there-yet@~1.1.2",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
"dev": true,
"optional": true
},
"balanced-match": {
"version": "1.0.0",
"from": "balanced-match@^1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"from": "brace-expansion@^1.1.7",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"dev": true
},
"chownr": {
"version": "1.1.1",
"from": "chownr@^1.1.1",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
"dev": true,
"optional": true
},
"code-point-at": {
"version": "1.1.0",
"from": "code-point-at@^1.0.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"dev": true
},
"concat-map": {
"version": "0.0.1",
"from": "concat-map@0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"dev": true
},
"console-control-strings": {
"version": "1.1.0",
"from": "console-control-strings@~1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"dev": true
},
"core-util-is": {
"version": "1.0.2",
"from": "core-util-is@~1.0.0",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"dev": true,
"optional": true
},
"debug": {
"version": "2.6.9",
"from": "debug@^2.1.2",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"dev": true,
"optional": true
},
"deep-extend": {
"version": "0.6.0",
"from": "deep-extend@^0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"dev": true,
"optional": true
},
"delegates": {
"version": "1.0.0",
"from": "delegates@^1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"dev": true,
"optional": true
},
"detect-libc": {
"version": "1.0.3",
"from": "detect-libc@^1.0.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"dev": true,
"optional": true
},
"fs-minipass": {
"version": "1.2.5",
"from": "fs-minipass@^1.2.5",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
"dev": true,
"optional": true
},
"fs.realpath": {
"version": "1.0.0",
"from": "fs.realpath@^1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"dev": true,
"optional": true
},
"gauge": {
"version": "2.7.4",
"from": "gauge@~2.7.3",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
"dev": true,
"optional": true
},
"glob": {
"version": "7.1.3",
"from": "glob@^7.1.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
"dev": true,
"optional": true
},
"has-unicode": {
"version": "2.0.1",
"from": "has-unicode@^2.0.0",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"dev": true,
"optional": true
},
"iconv-lite": {
"version": "0.4.24",
"from": "iconv-lite@^0.4.4",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"dev": true,
"optional": true
},
"ignore-walk": {
"version": "3.0.1",
"from": "ignore-walk@^3.0.1",
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
"dev": true,
"optional": true
},
"inflight": {
"version": "1.0.6",
"from": "inflight@^1.0.4",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"dev": true,
"optional": true
},
"inherits": {
"version": "2.0.3",
"from": "inherits@~2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"dev": true
},
"ini": {
"version": "1.3.5",
"from": "ini@~1.3.0",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"dev": true,
"optional": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"from": "is-fullwidth-code-point@^1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"dev": true
},
"isarray": {
"version": "1.0.0",
"from": "isarray@>=1.0.0 <1.1.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"dev": true,
"optional": true
},
"minimatch": {
"version": "3.0.4",
"from": "minimatch@^3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"dev": true
},
"minimist": {
"version": "0.0.8",
"from": "minimist@0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"dev": true
},
"minipass": {
"version": "2.3.5",
"from": "minipass@^2.3.4",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
"dev": true,
"dependencies": {
"safe-buffer": {
"version": "5.1.2",
"from": "safe-buffer@^5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"dev": true
}
}
},
"minizlib": {
"version": "1.2.1",
"from": "minizlib@^1.1.1",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
"dev": true,
"optional": true
},
"mkdirp": {
"version": "0.5.1",
"from": "mkdirp@^0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"dev": true
},
"ms": {
"version": "2.0.0",
"from": "ms@2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"dev": true,
"optional": true
},
"nan": {
"version": "2.12.1",
"from": "nan@>=2.9.2 <3.0.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz",
"dev": true,
"optional": true
},
"needle": {
"version": "2.2.4",
"from": "needle@^2.2.1",
"resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz",
"dev": true,
"optional": true
},
"node-pre-gyp": {
"version": "0.10.3",
"from": "node-pre-gyp@^0.10.0",
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz",
"dev": true,
"optional": true
},
"nopt": {
"version": "4.0.1",
"from": "nopt@^4.0.1",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
"dev": true,
"optional": true
},
"npm-bundled": {
"version": "1.0.5",
"from": "npm-bundled@^1.0.1",
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz",
"dev": true,
"optional": true
},
"npm-packlist": {
"version": "1.2.0",
"from": "npm-packlist@^1.1.6",
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.2.0.tgz",
"dev": true,
"optional": true
},
"npmlog": {
"version": "4.1.2",
"from": "npmlog@^4.0.2",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
"dev": true,
"optional": true
},
"number-is-nan": {
"version": "1.0.1",
"from": "number-is-nan@^1.0.0",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"dev": true
},
"object-assign": {
"version": "4.1.1",
"from": "object-assign@^4.1.0",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"dev": true,
"optional": true
},
"os-homedir": {
"version": "1.0.2",
"from": "os-homedir@^1.0.0",
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
"dev": true,
"optional": true
},
"os-tmpdir": {
"version": "1.0.2",
"from": "os-tmpdir@^1.0.0",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"dev": true,
"optional": true
},
"osenv": {
"version": "0.1.5",
"from": "osenv@^0.1.4",
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
"dev": true,
"optional": true
},
"path-is-absolute": {
"version": "1.0.1",
"from": "path-is-absolute@^1.0.0",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"dev": true,
"optional": true
},
"process-nextick-args": {
"version": "2.0.0",
"from": "process-nextick-args@>=2.0.0 <2.1.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"dev": true,
"optional": true
},
"rc": {
"version": "1.2.8",
"from": "rc@^1.2.7",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
"dev": true,
"optional": true,
"dependencies": {
"minimist": {
"version": "1.2.0",
"from": "minimist@^1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"dev": true,
"optional": true
}
}
},
"readable-stream": {
"version": "2.3.6",
"from": "readable-stream@>=2.0.6 <3.0.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"dev": true,
"optional": true
},
"rimraf": {
"version": "2.6.3",
"from": "rimraf@^2.6.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
"from": "safer-buffer@>= 2.1.2 < 3",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"dev": true,
"optional": true
},
"sax": {
"version": "1.2.4",
"from": "sax@^1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"dev": true,
"optional": true
},
"set-blocking": {
"version": "2.0.0",
"from": "set-blocking@~2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"dev": true,
"optional": true
},
"signal-exit": {
"version": "3.0.2",
"from": "signal-exit@^3.0.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"dev": true,
"optional": true
},
"string_decoder": {
"version": "1.1.1",
"from": "string_decoder@>=1.1.1 <1.2.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"dev": true,
"optional": true
},
"string-width": {
"version": "1.0.2",
"from": "string-width@^1.0.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"dev": true
},
"strip-ansi": {
"version": "3.0.1",
"from": "strip-ansi@^3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"dev": true
},
"strip-json-comments": {
"version": "2.0.1",
"from": "strip-json-comments@~2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"dev": true,
"optional": true
},
"tar": {
"version": "4.4.8",
"from": "tar@^4",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz",
"dev": true,
"optional": true,
"dependencies": {
"safe-buffer": {
"version": "5.1.2",
"from": "safe-buffer@>=5.1.2 <6.0.0",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"dev": true,
"optional": true
}
}
},
"util-deprecate": {
"version": "1.0.2",
"from": "util-deprecate@~1.0.1",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"dev": true,
"optional": true
},
"wide-align": {
"version": "1.1.3",
"from": "wide-align@^1.1.0",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
"dev": true,
"optional": true
},
"wrappy": {
"version": "1.0.2",
"from": "wrappy@1",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"dev": true,
"optional": true
},
"yallist": {
"version": "3.0.3",
"from": "yallist@>=3.0.2 <4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
"dev": true
}
}
},
"fstream": {
"version": "1.0.11",
"from": "fstream@>=1.0.2 <2.0.0",
@ -4172,6 +4649,13 @@
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"dev": true,
"optional": true
},
"xregexp": {
"version": "2.0.0",
"from": "xregexp@2.0.0",
"resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz",
"dev": true,
"optional": true
}
}
},
@ -4286,7 +4770,7 @@
"readable-stream": {
"version": "2.3.6",
"from": "readable-stream@2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"dev": true,
"optional": true
},
@ -4973,7 +5457,7 @@
"readable-stream": {
"version": "2.3.6",
"from": "readable-stream@^2.0.1",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"dev": true
},
"string_decoder": {
@ -5956,7 +6440,7 @@
"minimist": {
"version": "1.2.0",
"from": "minimist@1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"dev": true
}
}
@ -7189,7 +7673,7 @@
"readable-stream": {
"version": "2.3.6",
"from": "readable-stream@^2.0.1",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"dev": true
},
"string_decoder": {
@ -7221,7 +7705,7 @@
"minimist": {
"version": "1.2.0",
"from": "minimist@>=1.1.3 <2.0.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"dev": true
},
"path-exists": {
@ -7390,7 +7874,7 @@
"minimist": {
"version": "1.2.0",
"from": "minimist@1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
},
"minipass": {
"version": "2.3.4",
@ -7797,7 +8281,7 @@
"readable-stream": {
"version": "2.3.6",
"from": "readable-stream@^2.3.3",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"dev": true
},
"string_decoder": {
@ -8154,7 +8638,7 @@
"readable-stream": {
"version": "2.3.6",
"from": "readable-stream@^2.0.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"dev": true
},
"readdirp": {
@ -9574,7 +10058,7 @@
"minimist": {
"version": "1.2.0",
"from": "minimist@>=1.2.0 <2.0.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
}
}
},
@ -10720,7 +11204,7 @@
"readable-stream": {
"version": "2.3.6",
"from": "readable-stream@^2.2.9",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"dev": true
},
"string_decoder": {
@ -10815,7 +11299,7 @@
"readable-stream": {
"version": "2.3.6",
"from": "readable-stream@^2.0.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"dev": true
},
"string_decoder": {
@ -10853,7 +11337,7 @@
"readable-stream": {
"version": "2.3.6",
"from": "readable-stream@^2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"dev": true
},
"string_decoder": {
@ -10896,7 +11380,7 @@
"readable-stream": {
"version": "2.3.6",
"from": "readable-stream@^2.3.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"dev": true
},
"string_decoder": {
@ -12218,7 +12702,7 @@
"readable-stream": {
"version": "2.3.6",
"from": "readable-stream@^2.0.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"dev": true
},
"readdirp": {
@ -12422,7 +12906,7 @@
"chokidar": {
"version": "2.0.3",
"from": "chokidar@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz",
"resolved": "http://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz",
"dev": true
},
"cliui": {
@ -12842,7 +13326,7 @@
"readable-stream": {
"version": "2.3.6",
"from": "readable-stream@^2.0.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"dev": true
},
"readdirp": {
@ -13176,11 +13660,9 @@
"resolved": "https://registry.npmjs.org/xpath.js/-/xpath.js-1.1.0.tgz"
},
"xregexp": {
"version": "2.0.0",
"from": "xregexp@2.0.0",
"resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz",
"dev": true,
"optional": true
"version": "4.2.4",
"from": "xregexp@4.2.4",
"resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.2.4.tgz"
},
"xtend": {
"version": "4.0.1",

View file

@ -109,6 +109,7 @@
"v8-profiler": "^5.2.3",
"valid-url": "^1.0.9",
"xml2js": "0.2.0",
"xregexp": "^4.2.4",
"yauzl": "^2.10.0"
},
"devDependencies": {

View file

@ -50,5 +50,25 @@ describe "EmailBuilder", ->
@email = @EmailBuilder.buildEmail("projectInvite", @opts)
it 'should not contain unescaped html in the html part', ->
expect(@email.html).to.contain "&lt;img"
expect(@email.html).to.contain "New Project"
it "should not have undefined in it", ->
@email.html.indexOf("undefined").should.equal -1
@email.subject.indexOf("undefined").should.equal -1
describe "SpamSafe", ->
beforeEach ->
@opts =
to:"bob@joe.com"
first_name:"bob"
owner:
email:"sally@hally.com"
inviteUrl: "http://example.com/invite"
project:
url:"http://www.project.com"
name:"come buy my product at http://notascam.com"
@email = @EmailBuilder.buildEmail("projectInvite", @opts)
it "should replace spammy project name", ->
@email.html.indexOf("a new Project").should.not.equal -1
@email.subject.indexOf("New Project").should.not.equal -1

View file

@ -0,0 +1,28 @@
path = require('path')
modulePath = path.join __dirname, "../../../../app/js/Features/Email/SpamSafe"
SpamSafe = require(modulePath)
expect = require("chai").expect
describe "SpamSafe", ->
it 'should reject spammy names', ->
expect(SpamSafe.isSafeUserName("Charline Wałęsa")).to.equal true
expect(SpamSafe.isSafeUserName("hey come buy this product im selling it's really good for you and it'll make your latex 10x guaranteed")).to.equal false
expect(SpamSafe.isSafeUserName("隆太郎 宮本")).to.equal true
expect(SpamSafe.isSafeUserName("Visit haxx0red.com")).to.equal false
expect(SpamSafe.isSafeUserName('加美汝VXhihi661金沙2001005com the first deposit will be _100%_')).to.equal false
expect(SpamSafe.isSafeProjectName('Neural Networks: good for your health and will solve all your problems')).to.equal false
expect(SpamSafe.isSafeProjectName("An analysis of the questions of the universe!")).to.equal true
expect(SpamSafe.isSafeProjectName('come buy this => http://www.dopeproduct.com/search/?q=user123')).to.equal false
expect(SpamSafe.isSafeEmail("realistic-email+1@domain.sub.com")).to.equal true
expect(SpamSafe.isSafeEmail("notquiteRight\@evil$.com")).to.equal false
expect(SpamSafe.safeUserName("Tammy Weinstįen", "A User")).to.equal "Tammy Weinstįen"
expect(SpamSafe.safeUserName("haxx0red.com", "A User")).to.equal "A User"
expect(SpamSafe.safeUserName("What$ Upp", "A User")).to.equal "A User"
expect(SpamSafe.safeProjectName("Math-ematics!", "A Project")).to.equal "Math-ematics!"
expect(SpamSafe.safeProjectName("A Very long title for a very long book that will never be read" + "a".repeat(250), "A Project")).to.equal "A Project"
expect(SpamSafe.safeEmail("safe-ëmail@domain.com", "A collaborator")).to.equal "safe-ëmail@domain.com"
expect(SpamSafe.safeEmail("Բարեւ@another.domain", "A collaborator")).to.equal "Բարեւ@another.domain"
expect(SpamSafe.safeEmail("me+" + "a".repeat(40) + "@googoole.con", "A collaborator")).to.equal "A collaborator"
expect(SpamSafe.safeEmail("sendME$$$@iAmAprince.com", "A collaborator")).to.equal "A collaborator"