Send violations to ip service (#148), r=@vbudhram
This adds the tigerblood-js-client to the customs server. This is used to report when a request has been blocked to the Tigerblood service. It is disabled by default.
This commit is contained in:
Родитель
3442392198
Коммит
9b94bd1bdd
|
@ -216,13 +216,10 @@ curl -v \
|
||||||
|
|
||||||
### Response
|
### Response
|
||||||
|
|
||||||
Successful requests will produce a "200 OK" response with the lockout
|
Successful requests will produce a "200 OK" response:
|
||||||
advice in the JSON body:
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{}
|
||||||
"lockout": false
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`lockout` indicates whether or not the account should be locked out.
|
`lockout` indicates whether or not the account should be locked out.
|
||||||
|
|
|
@ -211,6 +211,44 @@ module.exports = function (fs, path, url, convict) {
|
||||||
format: 'nat',
|
format: 'nat',
|
||||||
env: 'IP_BLOCKLIST_POLL_INTERVAL_SECONDS'
|
env: 'IP_BLOCKLIST_POLL_INTERVAL_SECONDS'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
reputationService: {
|
||||||
|
enable: {
|
||||||
|
doc: 'Flag to enable using the IP Reputation Service',
|
||||||
|
format: Boolean,
|
||||||
|
default: false,
|
||||||
|
env: 'REPUTATION_SERVICE_ENABLE'
|
||||||
|
},
|
||||||
|
host: {
|
||||||
|
doc: 'The reputation service IP address',
|
||||||
|
default: '127.0.0.1',
|
||||||
|
format: 'ipaddress',
|
||||||
|
env: 'REPUTATION_SERVICE_IP_ADDRESS'
|
||||||
|
},
|
||||||
|
port: {
|
||||||
|
doc: 'The reputation service port',
|
||||||
|
default: 8080,
|
||||||
|
format: 'port',
|
||||||
|
env: 'REPUTATION_SERVICE_PORT'
|
||||||
|
},
|
||||||
|
hawkId: {
|
||||||
|
doc: 'HAWK ID for sending blocked IPs to the IP Reputation Service',
|
||||||
|
default: 'root',
|
||||||
|
format: String,
|
||||||
|
env: 'REPUTATION_SERVICE_HAWK_ID'
|
||||||
|
},
|
||||||
|
hawkKey: {
|
||||||
|
doc: 'HAWK key for sending blocked IPs to the IP Reputation Service',
|
||||||
|
default: 'toor',
|
||||||
|
format: String,
|
||||||
|
env: 'REPUTATION_SERVICE_HAWK_KEY'
|
||||||
|
},
|
||||||
|
timeout: {
|
||||||
|
doc: 'timeout in ms to wait for requests sent to the IP Reputation Service',
|
||||||
|
default: 50,
|
||||||
|
format: 'int',
|
||||||
|
env: 'REPUTATION_SERVICE_TIMEOUT'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,16 @@ module.exports = function createServer(config, log) {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (config.reputationService.enable) {
|
||||||
|
var IPReputationClient = require('ip-reputation-js-client')
|
||||||
|
var ipClient = new IPReputationClient({
|
||||||
|
host: config.reputationService.host,
|
||||||
|
port: config.reputationService.port,
|
||||||
|
id: config.reputationService.hawkId,
|
||||||
|
key: config.reputationService.hawkKey,
|
||||||
|
timeout: config.reputationService.timeout
|
||||||
|
})
|
||||||
|
}
|
||||||
var limits = require('./limits')(config, mc, log)
|
var limits = require('./limits')(config, mc, log)
|
||||||
var allowedIPs = require('./allowed_ips')(config, mc, log)
|
var allowedIPs = require('./allowed_ips')(config, mc, log)
|
||||||
var allowedEmailDomains = require('./allowed_email_domains')(config, mc, log)
|
var allowedEmailDomains = require('./allowed_email_domains')(config, mc, log)
|
||||||
|
@ -215,6 +225,13 @@ module.exports = function createServer(config, log) {
|
||||||
suspect: result.suspect
|
suspect: result.suspect
|
||||||
})
|
})
|
||||||
res.send(result)
|
res.send(result)
|
||||||
|
|
||||||
|
if (config.reputationService.enable && result.block) {
|
||||||
|
ipClient.sendViolation(ip, 'fxa:request.check.block.' + action)
|
||||||
|
.catch(function (err) {
|
||||||
|
log.error({ op: 'request.check.sendViolation.block.' + action, ip: ip, err: err })
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
function (err) {
|
function (err) {
|
||||||
log.error({ op: 'request.check', email: email, ip: ip, action: action, err: err })
|
log.error({ op: 'request.check', email: email, ip: ip, action: action, err: err })
|
||||||
|
@ -266,6 +283,13 @@ module.exports = function createServer(config, log) {
|
||||||
function (result) {
|
function (result) {
|
||||||
log.info({ op: 'request.checkAuthenticated', block: result.block })
|
log.info({ op: 'request.checkAuthenticated', block: result.block })
|
||||||
res.send(result)
|
res.send(result)
|
||||||
|
|
||||||
|
if (config.reputationService.enable && result.block) {
|
||||||
|
ipClient.sendViolation(ip, 'fxa:request.checkAuthenticated.block.' + action)
|
||||||
|
.catch(function (err) {
|
||||||
|
log.error({ op: 'request.checkAuthenticated.sendViolation.block.' + action, ip: ip, err: err })
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
function (err) {
|
function (err) {
|
||||||
log.error({ op: 'request.checkAuthenticated', err: err })
|
log.error({ op: 'request.checkAuthenticated', err: err })
|
||||||
|
@ -274,6 +298,13 @@ module.exports = function createServer(config, log) {
|
||||||
block: true,
|
block: true,
|
||||||
retryAfter: limits.blockIntervalSeconds
|
retryAfter: limits.blockIntervalSeconds
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (config.reputationService.enable) {
|
||||||
|
ipClient.sendViolation(ip, 'fxa:request.checkAuthenticated.block.' + action)
|
||||||
|
.catch(function (err) {
|
||||||
|
log.error({ op: 'request.checkAuthenticated.sendViolation.block.' + action, ip: ip, err: err })
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.done(next, next)
|
.done(next, next)
|
||||||
|
@ -299,6 +330,14 @@ module.exports = function createServer(config, log) {
|
||||||
function (emailRecord, ipRecord, ipEmailRecord) {
|
function (emailRecord, ipRecord, ipEmailRecord) {
|
||||||
ipRecord.addBadLogin({ email: email, errno: errno })
|
ipRecord.addBadLogin({ email: email, errno: errno })
|
||||||
ipEmailRecord.addBadLogin()
|
ipEmailRecord.addBadLogin()
|
||||||
|
|
||||||
|
if (config.reputationService.enable && ipRecord.isOverBadLogins()) {
|
||||||
|
ipClient.sendViolation(ip, 'fxa:request.failedLoginAttempt.isOverBadLogins')
|
||||||
|
.catch(function (err) {
|
||||||
|
log.error({ op: 'request.failedLoginAttempt.sendViolation.rateLimited', ip: ip, err: err })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return setRecords(email, ip, emailRecord, ipRecord, ipEmailRecord)
|
return setRecords(email, ip, emailRecord, ipRecord, ipEmailRecord)
|
||||||
.then(
|
.then(
|
||||||
function () {
|
function () {
|
||||||
|
@ -408,6 +447,16 @@ module.exports = function createServer(config, log) {
|
||||||
res.send(500, err)
|
res.send(500, err)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
.then(
|
||||||
|
function () {
|
||||||
|
if (config.reputationService.enable) {
|
||||||
|
ipClient.sendViolation(ip, 'fxa:request.blockIp')
|
||||||
|
.catch(function (err) {
|
||||||
|
log.error({ op: 'request.blockIp.sendViolation', ip: ip, err: err })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
.done(next, next)
|
.done(next, next)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,11 +2,41 @@
|
||||||
"name": "fxa-customs-server",
|
"name": "fxa-customs-server",
|
||||||
"version": "0.72.1",
|
"version": "0.72.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"ansi-regex": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"from": "ansi-regex@>=2.0.0 <3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
|
||||||
|
},
|
||||||
|
"ansi-styles": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"from": "ansi-styles@>=2.2.1 <3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz"
|
||||||
|
},
|
||||||
|
"asn1": {
|
||||||
|
"version": "0.2.3",
|
||||||
|
"from": "asn1@>=0.2.3 <0.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz"
|
||||||
|
},
|
||||||
|
"assert-plus": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"from": "assert-plus@>=0.2.0 <0.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz"
|
||||||
|
},
|
||||||
|
"asynckit": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"from": "asynckit@>=0.4.0 <0.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
|
||||||
|
},
|
||||||
"aws-sdk": {
|
"aws-sdk": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"from": "aws-sdk@2.3.3",
|
"from": "aws-sdk@2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.3.3.tgz",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"jmespath": {
|
||||||
|
"version": "0.15.0",
|
||||||
|
"from": "jmespath@0.15.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz"
|
||||||
|
},
|
||||||
"sax": {
|
"sax": {
|
||||||
"version": "1.1.5",
|
"version": "1.1.5",
|
||||||
"from": "sax@1.1.5",
|
"from": "sax@1.1.5",
|
||||||
|
@ -28,14 +58,25 @@
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.5.0.tgz"
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.5.0.tgz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"jmespath": {
|
|
||||||
"version": "0.15.0",
|
|
||||||
"from": "jmespath@0.15.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"aws-sign2": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"from": "aws-sign2@>=0.6.0 <0.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
|
||||||
|
},
|
||||||
|
"aws4": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"from": "aws4@>=1.2.1 <2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.5.0.tgz"
|
||||||
|
},
|
||||||
|
"bcrypt-pbkdf": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"from": "bcrypt-pbkdf@>=1.0.0 <2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"bl": {
|
"bl": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"from": "bl@1.1.2",
|
"from": "bl@1.1.2",
|
||||||
|
@ -85,6 +126,11 @@
|
||||||
"from": "bluebird@3.3.4",
|
"from": "bluebird@3.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.3.4.tgz"
|
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.3.4.tgz"
|
||||||
},
|
},
|
||||||
|
"boom": {
|
||||||
|
"version": "2.10.1",
|
||||||
|
"from": "boom@2.x.x",
|
||||||
|
"resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
|
||||||
|
},
|
||||||
"bunyan": {
|
"bunyan": {
|
||||||
"version": "1.8.0",
|
"version": "1.8.0",
|
||||||
"from": "bunyan@1.8.0",
|
"from": "bunyan@1.8.0",
|
||||||
|
@ -94,82 +140,103 @@
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"from": "dtrace-provider@>=0.6.0 <0.7.0",
|
"from": "dtrace-provider@>=0.6.0 <0.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.6.0.tgz",
|
||||||
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nan": {
|
"nan": {
|
||||||
"version": "2.4.0",
|
"version": "2.4.0",
|
||||||
"from": "nan@>=2.0.8 <3.0.0",
|
"from": "nan@>=2.0.8 <3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.4.0.tgz"
|
"resolved": "https://registry.npmjs.org/nan/-/nan-2.4.0.tgz",
|
||||||
|
"optional": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"moment": {
|
||||||
|
"version": "2.15.0",
|
||||||
|
"from": "moment@>=2.10.6 <3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.15.0.tgz",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"mv": {
|
"mv": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"from": "mv@>=2.0.0 <3.0.0",
|
"from": "mv@>=2.0.0 <3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz",
|
||||||
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mkdirp": {
|
"mkdirp": {
|
||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
"from": "mkdirp@>=0.5.1 <0.6.0",
|
"from": "mkdirp@>=0.5.1 <0.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||||
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.8",
|
||||||
"from": "minimist@0.0.8",
|
"from": "minimist@0.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||||
|
"optional": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ncp": {
|
"ncp": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"from": "ncp@>=2.0.0 <2.1.0",
|
"from": "ncp@>=2.0.0 <2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz"
|
"resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz",
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"rimraf": {
|
"rimraf": {
|
||||||
"version": "2.4.5",
|
"version": "2.4.5",
|
||||||
"from": "rimraf@>=2.4.0 <2.5.0",
|
"from": "rimraf@>=2.4.0 <2.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz",
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz",
|
||||||
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"glob": {
|
"glob": {
|
||||||
"version": "6.0.4",
|
"version": "6.0.4",
|
||||||
"from": "glob@>=6.0.1 <7.0.0",
|
"from": "glob@>=6.0.1 <7.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz",
|
||||||
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"inflight": {
|
"inflight": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"from": "inflight@>=1.0.4 <2.0.0",
|
"from": "inflight@>=1.0.4 <2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz",
|
||||||
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"wrappy": {
|
"wrappy": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"from": "wrappy@>=1.0.0 <2.0.0",
|
"from": "wrappy@>=1.0.0 <2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
|
"optional": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"inherits": {
|
"inherits": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"from": "inherits@>=2.0.0 <3.0.0",
|
"from": "inherits@>=2.0.0 <3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz"
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"minimatch": {
|
"minimatch": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0",
|
"from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz",
|
||||||
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.6",
|
"version": "1.1.6",
|
||||||
"from": "brace-expansion@>=1.0.0 <2.0.0",
|
"from": "brace-expansion@>=1.0.0 <2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz",
|
||||||
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "0.4.2",
|
"version": "0.4.2",
|
||||||
"from": "balanced-match@>=0.4.1 <0.5.0",
|
"from": "balanced-match@>=0.4.1 <0.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz"
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"from": "concat-map@0.0.1",
|
"from": "concat-map@0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
|
"optional": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,7 +257,8 @@
|
||||||
"path-is-absolute": {
|
"path-is-absolute": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"from": "path-is-absolute@>=1.0.0 <2.0.0",
|
"from": "path-is-absolute@>=1.0.0 <2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz"
|
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz",
|
||||||
|
"optional": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,15 +269,31 @@
|
||||||
"safe-json-stringify": {
|
"safe-json-stringify": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"from": "safe-json-stringify@>=1.0.0 <2.0.0",
|
"from": "safe-json-stringify@>=1.0.0 <2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.0.3.tgz"
|
"resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.0.3.tgz",
|
||||||
},
|
"optional": true
|
||||||
"moment": {
|
|
||||||
"version": "2.15.0",
|
|
||||||
"from": "moment@>=2.10.6 <3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.15.0.tgz"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"caseless": {
|
||||||
|
"version": "0.11.0",
|
||||||
|
"from": "caseless@>=0.11.0 <0.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
|
||||||
|
},
|
||||||
|
"chalk": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"from": "chalk@>=1.1.1 <1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz"
|
||||||
|
},
|
||||||
|
"combined-stream": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"from": "combined-stream@>=1.0.5 <1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz"
|
||||||
|
},
|
||||||
|
"commander": {
|
||||||
|
"version": "2.9.0",
|
||||||
|
"from": "commander@>=2.9.0 <3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz"
|
||||||
|
},
|
||||||
"convict": {
|
"convict": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"from": "convict@1.2.0",
|
"from": "convict@1.2.0",
|
||||||
|
@ -249,15 +333,15 @@
|
||||||
"from": "optimist@0.6.1",
|
"from": "optimist@0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"wordwrap": {
|
|
||||||
"version": "0.0.3",
|
|
||||||
"from": "wordwrap@>=0.0.2 <0.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
|
|
||||||
},
|
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "0.0.10",
|
"version": "0.0.10",
|
||||||
"from": "minimist@>=0.0.1 <0.1.0",
|
"from": "minimist@>=0.0.1 <0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz"
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz"
|
||||||
|
},
|
||||||
|
"wordwrap": {
|
||||||
|
"version": "0.0.3",
|
||||||
|
"from": "wordwrap@>=0.0.2 <0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -271,11 +355,6 @@
|
||||||
"from": "varify@0.1.1",
|
"from": "varify@0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/varify/-/varify-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/varify/-/varify-0.1.1.tgz",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"through": {
|
|
||||||
"version": "2.3.8",
|
|
||||||
"from": "through@>=2.3.4 <2.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
|
|
||||||
},
|
|
||||||
"redeyed": {
|
"redeyed": {
|
||||||
"version": "0.4.4",
|
"version": "0.4.4",
|
||||||
"from": "redeyed@>=0.4.2 <0.5.0",
|
"from": "redeyed@>=0.4.2 <0.5.0",
|
||||||
|
@ -287,26 +366,239 @@
|
||||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz"
|
"resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"through": {
|
||||||
|
"version": "2.3.8",
|
||||||
|
"from": "through@>=2.3.4 <2.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"cryptiles": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"from": "cryptiles@>=2.0.0 <3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz"
|
||||||
|
},
|
||||||
"csv-parse": {
|
"csv-parse": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"from": "csv-parse@1.0.4",
|
"from": "csv-parse@1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-1.0.4.tgz"
|
"resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-1.0.4.tgz"
|
||||||
},
|
},
|
||||||
|
"dashdash": {
|
||||||
|
"version": "1.14.0",
|
||||||
|
"from": "dashdash@>=1.12.0 <2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.0.tgz",
|
||||||
|
"dependencies": {
|
||||||
|
"assert-plus": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"from": "assert-plus@>=1.0.0 <2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"deep-equal": {
|
"deep-equal": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"from": "deep-equal@1.0.1",
|
"from": "deep-equal@1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz"
|
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz"
|
||||||
},
|
},
|
||||||
|
"delayed-stream": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"from": "delayed-stream@>=1.0.0 <1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
|
||||||
|
},
|
||||||
|
"ecc-jsbn": {
|
||||||
|
"version": "0.1.1",
|
||||||
|
"from": "ecc-jsbn@>=0.1.1 <0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"escape-string-regexp": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"from": "escape-string-regexp@>=1.0.2 <2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
|
||||||
|
},
|
||||||
|
"extend": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"from": "extend@~3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz"
|
||||||
|
},
|
||||||
|
"extsprintf": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"from": "extsprintf@1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz"
|
||||||
|
},
|
||||||
|
"forever-agent": {
|
||||||
|
"version": "0.6.1",
|
||||||
|
"from": "forever-agent@>=0.6.1 <0.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz"
|
||||||
|
},
|
||||||
|
"generate-function": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"from": "generate-function@>=2.0.0 <3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
|
||||||
|
},
|
||||||
|
"generate-object-property": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"from": "generate-object-property@>=1.1.0 <2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz"
|
||||||
|
},
|
||||||
|
"getpass": {
|
||||||
|
"version": "0.1.6",
|
||||||
|
"from": "getpass@>=0.1.1 <0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz",
|
||||||
|
"dependencies": {
|
||||||
|
"assert-plus": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"from": "assert-plus@>=1.0.0 <2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"graceful-readlink": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"from": "graceful-readlink@>=1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
|
||||||
|
},
|
||||||
|
"har-validator": {
|
||||||
|
"version": "2.0.6",
|
||||||
|
"from": "har-validator@>=2.0.6 <2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz"
|
||||||
|
},
|
||||||
|
"has-ansi": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"from": "has-ansi@>=2.0.0 <3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
|
||||||
|
},
|
||||||
|
"hawk": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"from": "hawk@>=3.1.3 <3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz"
|
||||||
|
},
|
||||||
|
"hoek": {
|
||||||
|
"version": "2.16.3",
|
||||||
|
"from": "hoek@2.x.x",
|
||||||
|
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
|
||||||
|
},
|
||||||
|
"http-signature": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"from": "http-signature@>=1.1.0 <1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz"
|
||||||
|
},
|
||||||
"ip": {
|
"ip": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"from": "ip@1.1.3",
|
"from": "ip@1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.3.tgz"
|
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.3.tgz"
|
||||||
},
|
},
|
||||||
|
"ip-reputation-js-client": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"from": "ip-reputation-js-client@1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ip-reputation-js-client/-/ip-reputation-js-client-1.0.1.tgz",
|
||||||
|
"dependencies": {
|
||||||
|
"bluebird": {
|
||||||
|
"version": "3.4.6",
|
||||||
|
"from": "bluebird@3.4.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.6.tgz"
|
||||||
|
},
|
||||||
|
"form-data": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"from": "form-data@>=2.0.0 <2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.0.0.tgz"
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"version": "2.75.0",
|
||||||
|
"from": "request@2.75.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/request/-/request-2.75.0.tgz"
|
||||||
|
},
|
||||||
|
"tough-cookie": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"from": "tough-cookie@>=2.3.0 <2.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"is-my-json-valid": {
|
||||||
|
"version": "2.15.0",
|
||||||
|
"from": "is-my-json-valid@>=2.10.0 <3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz",
|
||||||
|
"dependencies": {
|
||||||
|
"xtend": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"from": "xtend@>=4.0.0 <5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"is-property": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"from": "is-property@>=1.0.0 <2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz"
|
||||||
|
},
|
||||||
|
"is-typedarray": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"from": "is-typedarray@>=1.0.0 <1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz"
|
||||||
|
},
|
||||||
|
"isemail": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"from": "isemail@>=2.0.0 <3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/isemail/-/isemail-2.2.1.tgz"
|
||||||
|
},
|
||||||
|
"isstream": {
|
||||||
|
"version": "0.1.2",
|
||||||
|
"from": "isstream@>=0.1.2 <0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"from": "items@>=2.0.0 <3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/items/-/items-2.1.1.tgz"
|
||||||
|
},
|
||||||
|
"jodid25519": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"from": "jodid25519@>=1.0.0 <2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"joi": {
|
||||||
|
"version": "9.2.0",
|
||||||
|
"from": "joi@9.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/joi/-/joi-9.2.0.tgz",
|
||||||
|
"dependencies": {
|
||||||
|
"hoek": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"from": "hoek@>=4.0.0 <5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/hoek/-/hoek-4.1.0.tgz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jsbn": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"from": "jsbn@>=0.1.0 <0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"json-schema": {
|
||||||
|
"version": "0.2.3",
|
||||||
|
"from": "json-schema@0.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz"
|
||||||
|
},
|
||||||
|
"json-stringify-safe": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"from": "json-stringify-safe@>=5.0.1 <5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
|
||||||
|
},
|
||||||
|
"jsonpointer": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"from": "jsonpointer@>=4.0.0 <5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.0.tgz"
|
||||||
|
},
|
||||||
|
"jsprim": {
|
||||||
|
"version": "1.3.1",
|
||||||
|
"from": "jsprim@>=1.2.2 <2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.3.1.tgz"
|
||||||
|
},
|
||||||
"memcached": {
|
"memcached": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"from": "memcached@2.2.1",
|
"from": "memcached@2.2.1",
|
||||||
|
@ -343,6 +635,21 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mime-db": {
|
||||||
|
"version": "1.25.0",
|
||||||
|
"from": "mime-db@>=1.25.0 <1.26.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.25.0.tgz"
|
||||||
|
},
|
||||||
|
"mime-types": {
|
||||||
|
"version": "2.1.13",
|
||||||
|
"from": "mime-types@>=2.1.7 <2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.13.tgz"
|
||||||
|
},
|
||||||
|
"moment": {
|
||||||
|
"version": "2.17.0",
|
||||||
|
"from": "moment@>=2.0.0 <3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.17.0.tgz"
|
||||||
|
},
|
||||||
"newrelic": {
|
"newrelic": {
|
||||||
"version": "1.30.1",
|
"version": "1.30.1",
|
||||||
"from": "newrelic@1.30.1",
|
"from": "newrelic@1.30.1",
|
||||||
|
@ -358,11 +665,6 @@
|
||||||
"from": "inherits@>=2.0.1 <2.1.0",
|
"from": "inherits@>=2.0.1 <2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
|
||||||
},
|
},
|
||||||
"typedarray": {
|
|
||||||
"version": "0.0.6",
|
|
||||||
"from": "typedarray@>=0.0.5 <0.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
|
|
||||||
},
|
|
||||||
"readable-stream": {
|
"readable-stream": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.6",
|
||||||
"from": "readable-stream@>=2.0.0 <2.1.0",
|
"from": "readable-stream@>=2.0.0 <2.1.0",
|
||||||
|
@ -394,6 +696,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"typedarray": {
|
||||||
|
"version": "0.0.6",
|
||||||
|
"from": "typedarray@>=0.0.5 <0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -441,6 +748,11 @@
|
||||||
"from": "core-util-is@>=1.0.0 <1.1.0",
|
"from": "core-util-is@>=1.0.0 <1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz"
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz"
|
||||||
},
|
},
|
||||||
|
"inherits": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"from": "inherits@>=2.0.1 <2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
|
||||||
|
},
|
||||||
"isarray": {
|
"isarray": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"from": "isarray@0.0.1",
|
"from": "isarray@0.0.1",
|
||||||
|
@ -450,11 +762,6 @@
|
||||||
"version": "0.10.31",
|
"version": "0.10.31",
|
||||||
"from": "string_decoder@>=0.10.0 <0.11.0",
|
"from": "string_decoder@>=0.10.0 <0.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
|
||||||
},
|
|
||||||
"inherits": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"from": "inherits@>=2.0.1 <2.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -470,6 +777,36 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node-uuid": {
|
||||||
|
"version": "1.4.7",
|
||||||
|
"from": "node-uuid@>=1.4.7 <1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz"
|
||||||
|
},
|
||||||
|
"oauth-sign": {
|
||||||
|
"version": "0.8.2",
|
||||||
|
"from": "oauth-sign@>=0.8.1 <0.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz"
|
||||||
|
},
|
||||||
|
"pinkie": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"from": "pinkie@>=2.0.0 <3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz"
|
||||||
|
},
|
||||||
|
"pinkie-promise": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"from": "pinkie-promise@>=2.0.0 <3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz"
|
||||||
|
},
|
||||||
|
"punycode": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"from": "punycode@>=1.4.1 <2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz"
|
||||||
|
},
|
||||||
|
"qs": {
|
||||||
|
"version": "6.2.1",
|
||||||
|
"from": "qs@>=6.2.0 <6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.2.1.tgz"
|
||||||
|
},
|
||||||
"restify": {
|
"restify": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"from": "restify@4.1.1",
|
"from": "restify@4.1.1",
|
||||||
|
@ -507,15 +844,29 @@
|
||||||
"from": "csv-parse@>=1.0.0 <2.0.0",
|
"from": "csv-parse@>=1.0.0 <2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-1.1.7.tgz"
|
"resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-1.1.7.tgz"
|
||||||
},
|
},
|
||||||
"stream-transform": {
|
|
||||||
"version": "0.1.1",
|
|
||||||
"from": "stream-transform@>=0.1.0 <0.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-0.1.1.tgz"
|
|
||||||
},
|
|
||||||
"csv-stringify": {
|
"csv-stringify": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.8",
|
||||||
"from": "csv-stringify@>=0.0.8 <0.0.9",
|
"from": "csv-stringify@>=0.0.8 <0.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-0.0.8.tgz"
|
"resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-0.0.8.tgz"
|
||||||
|
},
|
||||||
|
"stream-transform": {
|
||||||
|
"version": "0.1.1",
|
||||||
|
"from": "stream-transform@>=0.1.0 <0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-0.1.1.tgz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dtrace-provider": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"from": "dtrace-provider@>=0.6.0 <0.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.6.0.tgz",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"nan": {
|
||||||
|
"version": "2.4.0",
|
||||||
|
"from": "nan@>=2.0.8 <3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nan/-/nan-2.4.0.tgz",
|
||||||
|
"optional": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -762,20 +1113,68 @@
|
||||||
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz"
|
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"dtrace-provider": {
|
|
||||||
"version": "0.6.0",
|
|
||||||
"from": "dtrace-provider@>=0.6.0 <0.7.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.6.0.tgz",
|
|
||||||
"dependencies": {
|
|
||||||
"nan": {
|
|
||||||
"version": "2.4.0",
|
|
||||||
"from": "nan@>=2.0.8 <3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.4.0.tgz"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"sntp": {
|
||||||
|
"version": "1.0.9",
|
||||||
|
"from": "sntp@>=1.0.0 <2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
|
||||||
|
},
|
||||||
|
"sshpk": {
|
||||||
|
"version": "1.10.1",
|
||||||
|
"from": "sshpk@>=1.7.0 <2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.10.1.tgz",
|
||||||
|
"dependencies": {
|
||||||
|
"assert-plus": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"from": "assert-plus@>=1.0.0 <2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"stringstream": {
|
||||||
|
"version": "0.0.5",
|
||||||
|
"from": "stringstream@>=0.0.4 <0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
|
||||||
|
},
|
||||||
|
"strip-ansi": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"from": "strip-ansi@>=3.0.0 <4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz"
|
||||||
|
},
|
||||||
|
"supports-color": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"from": "supports-color@>=2.0.0 <3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
|
||||||
|
},
|
||||||
|
"topo": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"from": "topo@>=2.0.0 <3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/topo/-/topo-2.0.2.tgz",
|
||||||
|
"dependencies": {
|
||||||
|
"hoek": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"from": "hoek@4.x.x",
|
||||||
|
"resolved": "https://registry.npmjs.org/hoek/-/hoek-4.1.0.tgz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tunnel-agent": {
|
||||||
|
"version": "0.4.3",
|
||||||
|
"from": "tunnel-agent@>=0.4.1 <0.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz"
|
||||||
|
},
|
||||||
|
"tweetnacl": {
|
||||||
|
"version": "0.14.3",
|
||||||
|
"from": "tweetnacl@>=0.14.0 <0.15.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.3.tgz",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"verror": {
|
||||||
|
"version": "1.3.6",
|
||||||
|
"from": "verror@1.3.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
"csv-parse": "1.0.4",
|
"csv-parse": "1.0.4",
|
||||||
"deep-equal": "1.0.1",
|
"deep-equal": "1.0.1",
|
||||||
"ip": "1.1.3",
|
"ip": "1.1.3",
|
||||||
|
"ip-reputation-js-client": "1.0.1",
|
||||||
"memcached": "2.2.1",
|
"memcached": "2.2.1",
|
||||||
"newrelic": "1.30.1",
|
"newrelic": "1.30.1",
|
||||||
"restify": "4.1.1"
|
"restify": "4.1.1"
|
||||||
|
|
|
@ -46,7 +46,10 @@ var mc = new Memcached(
|
||||||
module.exports.mc = mc
|
module.exports.mc = mc
|
||||||
|
|
||||||
var TEST_EMAIL = 'test@example.com'
|
var TEST_EMAIL = 'test@example.com'
|
||||||
|
var TEST_EMAIL_2 = 'test+2@example.com'
|
||||||
var TEST_IP = '192.0.2.1'
|
var TEST_IP = '192.0.2.1'
|
||||||
|
var ALLOWED_IP = '192.0.3.1'
|
||||||
|
var TEST_UID = 'test-uid'
|
||||||
|
|
||||||
var limits = require('../lib/limits')(config, mc, console)
|
var limits = require('../lib/limits')(config, mc, console)
|
||||||
var allowedIPs = require('../lib/allowed_ips')(config, mc, console)
|
var allowedIPs = require('../lib/allowed_ips')(config, mc, console)
|
||||||
|
@ -118,8 +121,14 @@ function clearEverything(cb) {
|
||||||
mc.delAsync('allowedEmailDomains'),
|
mc.delAsync('allowedEmailDomains'),
|
||||||
mc.delAsync('requestChecks'),
|
mc.delAsync('requestChecks'),
|
||||||
mc.delAsync(TEST_EMAIL),
|
mc.delAsync(TEST_EMAIL),
|
||||||
|
mc.delAsync(TEST_EMAIL_2),
|
||||||
|
mc.delAsync(TEST_IP),
|
||||||
|
mc.delAsync(ALLOWED_IP),
|
||||||
|
mc.delAsync(ALLOWED_IP + TEST_EMAIL),
|
||||||
|
mc.delAsync(ALLOWED_IP + TEST_EMAIL_2),
|
||||||
mc.delAsync(TEST_IP + TEST_EMAIL),
|
mc.delAsync(TEST_IP + TEST_EMAIL),
|
||||||
mc.delAsync(TEST_IP)
|
mc.delAsync(TEST_IP + TEST_EMAIL_2),
|
||||||
|
mc.delAsync(TEST_UID)
|
||||||
])
|
])
|
||||||
.then(function () {
|
.then(function () {
|
||||||
mc.end()
|
mc.end()
|
||||||
|
|
|
@ -0,0 +1,317 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
var test = require('tap').test
|
||||||
|
var TestServer = require('../test_server')
|
||||||
|
var ReputationServerStub = require('../test_reputation_server')
|
||||||
|
var Promise = require('bluebird')
|
||||||
|
var restify = require('restify')
|
||||||
|
var mcHelper = require('../memcache-helper')
|
||||||
|
|
||||||
|
var TEST_EMAIL = 'test@example.com'
|
||||||
|
var TEST_EMAIL_2 = 'test+2@example.com'
|
||||||
|
var TEST_IP = '192.0.2.1'
|
||||||
|
var ALLOWED_IP = '192.0.3.1'
|
||||||
|
var TEST_UID = 'test-uid'
|
||||||
|
var TEST_ACTION = 'action1'
|
||||||
|
var TEST_CHECK_ACTION = 'recoveryEmailVerifyCode'
|
||||||
|
|
||||||
|
// wait for the violation to be sent for endpoints that respond
|
||||||
|
// before sending violation
|
||||||
|
var TEST_DELAY_MS = 500
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
listen: {
|
||||||
|
port: 7000
|
||||||
|
},
|
||||||
|
limits: {
|
||||||
|
rateLimitIntervalSeconds: 1
|
||||||
|
},
|
||||||
|
reputationService: {
|
||||||
|
enable: true,
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: 9009,
|
||||||
|
timeout: 25
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override limit values for testing
|
||||||
|
process.env.ALLOWED_IPS = ALLOWED_IP
|
||||||
|
process.env.MAX_VERIFY_CODES = 2
|
||||||
|
process.env.MAX_BAD_LOGINS_PER_IP = 1
|
||||||
|
process.env.UID_RATE_LIMIT = 3
|
||||||
|
process.env.UID_RATE_LIMIT_INTERVAL_SECONDS = 2
|
||||||
|
process.env.UID_RATE_LIMIT_BAN_DURATION_SECONDS = 2
|
||||||
|
process.env.RATE_LIMIT_INTERVAL_SECONDS = config.limits.rateLimitIntervalSeconds
|
||||||
|
|
||||||
|
// Enable reputation test server
|
||||||
|
process.env.REPUTATION_SERVICE_ENABLE = config.reputationService.enable
|
||||||
|
process.env.REPUTATION_SERVICE_IP_ADDRESS = config.reputationService.host
|
||||||
|
process.env.REPUTATION_SERVICE_PORT = config.reputationService.port
|
||||||
|
process.env.REPUTATION_SERVICE_TIMEOUT = config.reputationService.timeout
|
||||||
|
|
||||||
|
var testServer = new TestServer(config)
|
||||||
|
var reputationServer = new ReputationServerStub(config)
|
||||||
|
|
||||||
|
var client = restify.createJsonClient({
|
||||||
|
url: 'http://127.0.0.1:' + config.listen.port
|
||||||
|
})
|
||||||
|
var reputationClient = restify.createJsonClient({
|
||||||
|
url: 'http://' + config.reputationService.host + ':' + config.reputationService.port
|
||||||
|
})
|
||||||
|
|
||||||
|
Promise.promisifyAll(client, { multiArgs: true })
|
||||||
|
Promise.promisifyAll(reputationClient, { multiArgs: true })
|
||||||
|
|
||||||
|
test(
|
||||||
|
'startup',
|
||||||
|
function (t) {
|
||||||
|
testServer.start(function (err) {
|
||||||
|
t.type(testServer.server, 'object', 'test server was started')
|
||||||
|
t.notOk(err, 'no errors were returned')
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
test(
|
||||||
|
'clear everything',
|
||||||
|
function (t) {
|
||||||
|
mcHelper.clearEverything(
|
||||||
|
function (err) {
|
||||||
|
t.notOk(err, 'no errors were returned')
|
||||||
|
t.end()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
test(
|
||||||
|
'/check resulting in lockout runs when send violation fails',
|
||||||
|
function (t) {
|
||||||
|
return client.postAsync('/check', { email: TEST_EMAIL, ip: TEST_IP, action: TEST_CHECK_ACTION })
|
||||||
|
.spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'first action noted')
|
||||||
|
t.equal(obj.block, false, 'first action not blocked')
|
||||||
|
return client.postAsync('/check', { email: TEST_EMAIL, ip: TEST_IP, action: TEST_CHECK_ACTION })
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'second action noted')
|
||||||
|
t.equal(obj.block, false, 'second action not blocked')
|
||||||
|
return client.postAsync('/check', { email: TEST_EMAIL, ip: TEST_IP, action: TEST_CHECK_ACTION })
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'third action attempt noted')
|
||||||
|
t.equal(obj.block, true, 'third action blocked')
|
||||||
|
}).catch(function(err) {
|
||||||
|
t.fail(err)
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
test(
|
||||||
|
'/checkAuthenticated rate limited runs when sends violation fails',
|
||||||
|
function (t) {
|
||||||
|
return client.postAsync('/checkAuthenticated', { action: TEST_ACTION, ip: TEST_IP, uid: TEST_UID })
|
||||||
|
.spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'returns 200 for /checkAuthenticated 1')
|
||||||
|
t.equal(obj.block, false, 'not rate limited')
|
||||||
|
return client.postAsync('/checkAuthenticated', { action: TEST_ACTION, ip: TEST_IP, uid: TEST_UID })
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'returns 200 for /checkAuthenticated 2')
|
||||||
|
t.equal(obj.block, false, 'not rate limited')
|
||||||
|
return client.postAsync('/checkAuthenticated', { action: TEST_ACTION, ip: TEST_IP, uid: TEST_UID })
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'returns 200 for /checkAuthenticated 3')
|
||||||
|
t.equal(obj.block, true, 'rate limited')
|
||||||
|
t.end()
|
||||||
|
}).catch(function(err) {
|
||||||
|
t.fail(err)
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
test(
|
||||||
|
'/failedLoginAttempt resulting in lockout runs when send violation fails',
|
||||||
|
function (t) {
|
||||||
|
return client.postAsync('/failedLoginAttempt', { email: TEST_EMAIL, ip: TEST_IP })
|
||||||
|
.spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'first login attempt noted')
|
||||||
|
return client.postAsync('/failedLoginAttempt', { email: TEST_EMAIL_2, ip: TEST_IP })
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'second login attempt noted')
|
||||||
|
return client.postAsync('/failedLoginAttempt', { email: TEST_EMAIL, ip: TEST_IP })
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'third login attempt noted')
|
||||||
|
return client.postAsync('/failedLoginAttempt', { email: TEST_EMAIL, ip: TEST_IP })
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'fourth login attempt noted')
|
||||||
|
return mcHelper.badLoginCheck()
|
||||||
|
}).then(function (records) {
|
||||||
|
t.equal(records.ipEmailRecord.isOverBadLogins(), true, 'is now over bad logins')
|
||||||
|
t.end()
|
||||||
|
}).catch(function(err) {
|
||||||
|
t.fail(err)
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
test(
|
||||||
|
'/blockIp returns when send violation fails',
|
||||||
|
function (t) {
|
||||||
|
return client.postAsync('/blockIp', { ip: TEST_IP })
|
||||||
|
.spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'blockIp returns 200')
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
test(
|
||||||
|
'clear everything again',
|
||||||
|
function (t) {
|
||||||
|
mcHelper.clearEverything(
|
||||||
|
function (err) {
|
||||||
|
t.notOk(err, 'no errors were returned')
|
||||||
|
t.end()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
test(
|
||||||
|
'startup reputation service',
|
||||||
|
function (t) {
|
||||||
|
reputationServer.start(function (err) {
|
||||||
|
t.type(reputationServer.server, 'object', 'test server was started')
|
||||||
|
t.notOk(err, 'no errors were returned')
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
test(
|
||||||
|
'sends violation /check resulting in lockout',
|
||||||
|
function (t) {
|
||||||
|
return client.postAsync('/check', { email: TEST_EMAIL, ip: TEST_IP, action: TEST_CHECK_ACTION })
|
||||||
|
.spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'first action noted')
|
||||||
|
t.equal(obj.block, false, 'first action not blocked')
|
||||||
|
return client.postAsync('/check', { email: TEST_EMAIL, ip: TEST_IP, action: TEST_CHECK_ACTION })
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'second action noted')
|
||||||
|
t.equal(obj.block, false, 'second action not blocked')
|
||||||
|
return client.postAsync('/check', { email: TEST_EMAIL, ip: TEST_IP, action: TEST_CHECK_ACTION })
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'third action attempt noted')
|
||||||
|
t.equal(obj.block, true, 'third action blocked')
|
||||||
|
return Promise.delay(TEST_DELAY_MS)
|
||||||
|
}).then(function () {
|
||||||
|
return reputationClient.getAsync('/mostRecentViolation/' + TEST_IP)
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.body, '"fxa:request.check.block.' + TEST_CHECK_ACTION + '"', 'sends violation when /check')
|
||||||
|
return reputationClient.delAsync('/mostRecentViolation/' + TEST_IP)
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'Failed to clear sent violation from test server.')
|
||||||
|
t.end()
|
||||||
|
}).catch(function(err) {
|
||||||
|
t.fail(err)
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
test(
|
||||||
|
'sends violation when /checkAuthenticated rate limited',
|
||||||
|
function (t) {
|
||||||
|
return client.postAsync('/checkAuthenticated', { action: TEST_ACTION, ip: TEST_IP, uid: TEST_UID })
|
||||||
|
.spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'returns 200 for /checkAuthenticated 1')
|
||||||
|
t.equal(obj.block, false, 'not rate limited')
|
||||||
|
return client.postAsync('/checkAuthenticated', { action: TEST_ACTION, ip: TEST_IP, uid: TEST_UID })
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'returns 200 for /checkAuthenticated 2')
|
||||||
|
t.equal(obj.block, false, 'not rate limited')
|
||||||
|
return client.postAsync('/checkAuthenticated', { action: TEST_ACTION, ip: TEST_IP, uid: TEST_UID })
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'returns 200 for /checkAuthenticated 3')
|
||||||
|
t.equal(obj.block, true, 'rate limited')
|
||||||
|
return Promise.delay(TEST_DELAY_MS)
|
||||||
|
}).then(function () {
|
||||||
|
return reputationClient.getAsync('/mostRecentViolation/' + TEST_IP)
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.body, '"fxa:request.checkAuthenticated.block.action1"', 'Violation sent.')
|
||||||
|
return reputationClient.delAsync('/mostRecentViolation/' + TEST_IP)
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'Failed to clear sent violation from test server.')
|
||||||
|
t.end()
|
||||||
|
}).catch(function(err) {
|
||||||
|
t.fail(err)
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
test(
|
||||||
|
'sends violation /failedLoginAttempt results in lockout',
|
||||||
|
function (t) {
|
||||||
|
return client.postAsync('/failedLoginAttempt', { email: TEST_EMAIL, ip: TEST_IP })
|
||||||
|
.spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'first login attempt noted')
|
||||||
|
return client.postAsync('/failedLoginAttempt', { email: TEST_EMAIL_2, ip: TEST_IP })
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'second login attempt noted')
|
||||||
|
return reputationClient.getAsync('/mostRecentViolation/' + TEST_IP)
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.body, '"fxa:request.failedLoginAttempt.isOverBadLogins"', 'sends violation.')
|
||||||
|
return reputationClient.delAsync('/mostRecentViolation/' + TEST_IP)
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'Failed to clear sent violation from test server.')
|
||||||
|
t.end()
|
||||||
|
}).catch(function(err) {
|
||||||
|
t.fail(err)
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
test(
|
||||||
|
'sends violation for blocked IP from /blockIp request',
|
||||||
|
function (t) {
|
||||||
|
return client.postAsync('/blockIp', { ip: TEST_IP })
|
||||||
|
.spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'blockIp returns 200')
|
||||||
|
return Promise.delay(TEST_DELAY_MS)
|
||||||
|
}).then(function () {
|
||||||
|
return reputationClient.getAsync('/mostRecentViolation/' + TEST_IP)
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.body, '"fxa:request.blockIp"', 'sends violation when IP blocked')
|
||||||
|
return reputationClient.delAsync('/mostRecentViolation/' + TEST_IP)
|
||||||
|
}).spread(function (req, res, obj) {
|
||||||
|
t.equal(res.statusCode, 200, 'Failed to clear sent violation from test server.')
|
||||||
|
t.end()
|
||||||
|
}).catch(function(err) {
|
||||||
|
t.fail(err)
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
test(
|
||||||
|
'teardown test reptuation server',
|
||||||
|
function (t) {
|
||||||
|
reputationServer.stop()
|
||||||
|
t.equal(reputationServer.server.killed, true, 'test reputation server killed')
|
||||||
|
t.end()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
test(
|
||||||
|
'teardown test server',
|
||||||
|
function (t) {
|
||||||
|
testServer.stop()
|
||||||
|
t.equal(testServer.server.killed, true, 'test server killed')
|
||||||
|
t.end()
|
||||||
|
}
|
||||||
|
)
|
|
@ -55,6 +55,54 @@ test(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
test(
|
||||||
|
'/checkAuthenticated requires action',
|
||||||
|
function (t) {
|
||||||
|
return client.postAsync('/checkAuthenticated', { ip: TEST_IP, uid: TEST_UID})
|
||||||
|
.spread(function(req, res, obj){
|
||||||
|
t.fail('Success response from request missing param.')
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
.catch(function(err){
|
||||||
|
t.equal(err.statusCode, 400, 'returns a 400')
|
||||||
|
t.equal(err.body.code, 'MissingParameters')
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
test(
|
||||||
|
'/checkAuthenticated requires ip',
|
||||||
|
function (t) {
|
||||||
|
return client.postAsync('/checkAuthenticated', { action: ACTION_ONE, uid: TEST_UID})
|
||||||
|
.spread(function(req, res, obj){
|
||||||
|
t.fail('Success response from request missing param.')
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
.catch(function(err){
|
||||||
|
t.equal(err.statusCode, 400, 'returns a 400')
|
||||||
|
t.equal(err.body.code, 'MissingParameters')
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
test(
|
||||||
|
'/checkAuthenticated requires uid',
|
||||||
|
function (t) {
|
||||||
|
return client.postAsync('/checkAuthenticated', { action: ACTION_ONE, ip: TEST_IP})
|
||||||
|
.spread(function(req, res, obj){
|
||||||
|
t.fail('Success response from request missing param.')
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
.catch(function(err){
|
||||||
|
t.equal(err.statusCode, 400, 'returns a 400')
|
||||||
|
t.equal(err.body.code, 'MissingParameters')
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'/checkAuthenticated with same action',
|
'/checkAuthenticated with same action',
|
||||||
function (t) {
|
function (t) {
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
/* eslint-disable no-console */
|
||||||
|
|
||||||
|
var cp = require('child_process')
|
||||||
|
var request = require('request')
|
||||||
|
|
||||||
|
function ReputationServerStub(config) {
|
||||||
|
this.url = 'http://' + config.reputationService.host + ':' + config.reputationService.port
|
||||||
|
this.server = null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function waitLoop(testServer, url, cb) {
|
||||||
|
request(
|
||||||
|
url + '/',
|
||||||
|
function (err, res/*, body*/) {
|
||||||
|
if (err) {
|
||||||
|
if (err.errno !== 'ECONNREFUSED') {
|
||||||
|
console.log('ERROR: unexpected result from ' + url)
|
||||||
|
console.log(err)
|
||||||
|
return cb(err)
|
||||||
|
}
|
||||||
|
return setTimeout(waitLoop.bind(null, testServer, url, cb), 100)
|
||||||
|
}
|
||||||
|
if (res.statusCode !== 200) {
|
||||||
|
console.log('ERROR: bad status code: ' + res.statusCode)
|
||||||
|
return cb(res.statusCode)
|
||||||
|
}
|
||||||
|
return cb()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ReputationServerStub.prototype.start = function (cb) {
|
||||||
|
if (!this.server) {
|
||||||
|
this.server = cp.spawn(
|
||||||
|
'node',
|
||||||
|
['./test_reputation_server_stub.js'],
|
||||||
|
{
|
||||||
|
cwd: __dirname,
|
||||||
|
stdio: 'ignore'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.server.on('error', function (err) {
|
||||||
|
console.log('Failed to start child process.')
|
||||||
|
cb(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
waitLoop(this, this.url, function (err) {
|
||||||
|
if (err) {
|
||||||
|
cb(err)
|
||||||
|
} else {
|
||||||
|
cb(null)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ReputationServerStub.prototype.stop = function () {
|
||||||
|
if (this.server) {
|
||||||
|
this.server.kill('SIGINT')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ReputationServerStub
|
|
@ -0,0 +1,46 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
/* eslint-disable no-console */
|
||||||
|
|
||||||
|
var restify = require('restify')
|
||||||
|
|
||||||
|
// a dummy reputation server to receive violations
|
||||||
|
var server = restify.createServer()
|
||||||
|
server.timeout = process.env.REPUTATION_SERVICE_TIMEOUT
|
||||||
|
server.use(restify.bodyParser())
|
||||||
|
|
||||||
|
// hashmap of ip -> list of violations
|
||||||
|
var mostRecentViolationByIp = {}
|
||||||
|
|
||||||
|
server.put('/violations/:ip', function (req, res, next) {
|
||||||
|
var ip = req.params.ip
|
||||||
|
mostRecentViolationByIp[ip] = req.body.Violation
|
||||||
|
console.log('put req', req.url)
|
||||||
|
res.send(200)
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
// not real tigerblood endpoints
|
||||||
|
server.get('/mostRecentViolation/:ip', function (req, res, next) {
|
||||||
|
var ip = req.params.ip
|
||||||
|
console.log('get req', req.url)
|
||||||
|
res.send(200, mostRecentViolationByIp[ip] || null)
|
||||||
|
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
server.del('/mostRecentViolation/:ip', function (req, res, next) {
|
||||||
|
var ip = req.params.ip
|
||||||
|
console.log('delete req', req.url)
|
||||||
|
delete mostRecentViolationByIp[ip]
|
||||||
|
res.send(200)
|
||||||
|
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
server.get('/', function (req, res, next) {
|
||||||
|
res.send(200)
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
server.listen(process.env.REPUTATION_SERVICE_PORT)
|
Загрузка…
Ссылка в новой задаче