fix(validation): Add validation rules for resume and utm_* (#4956), r=@shane-tomlinson, @philbooth
This commit is contained in:
Родитель
eb057d3e06
Коммит
bb8d298701
|
@ -11,7 +11,9 @@ const joi = require('joi');
|
|||
const validation = require('../validation');
|
||||
|
||||
const fxaAccountUrl = config.get('fxaccount_url');
|
||||
const RESUME_TYPE = validation.TYPES.RESUME;
|
||||
const STRING_TYPE = validation.TYPES.STRING;
|
||||
const UTM_TYPE = validation.TYPES.UTM;
|
||||
|
||||
const VERIFICATION_ENDPOINT = `${fxaAccountUrl}/v1/recovery_email/verify_code`;
|
||||
const VERIFICATION_TIMEOUT = 5000;
|
||||
|
@ -27,13 +29,13 @@ const REQUIRED_SCHEMA = {
|
|||
const REPORT_ONLY_SCHEMA = {
|
||||
'code': STRING_TYPE.alphanum().min(32).max(32).required(),
|
||||
// resume token can be long, do not use the limited STRING_TYPE
|
||||
'resume': joi.string().alphanum().optional(),
|
||||
'resume': RESUME_TYPE.optional(),
|
||||
'service': STRING_TYPE.alphanum().max(100).optional(),
|
||||
'uid': STRING_TYPE.alphanum().min(32).max(32).required(),
|
||||
'utm_campaign': STRING_TYPE.alphanum().optional(),
|
||||
'utm_content': STRING_TYPE.alphanum().optional(),
|
||||
'utm_medium': STRING_TYPE.alphanum().optional(),
|
||||
'utm_source': STRING_TYPE.alphanum().optional()
|
||||
'utm_campaign': UTM_TYPE.optional(),
|
||||
'utm_content': UTM_TYPE.optional(),
|
||||
'utm_medium': UTM_TYPE.optional(),
|
||||
'utm_source': UTM_TYPE.optional()
|
||||
};
|
||||
|
||||
module.exports = function () {
|
||||
|
|
|
@ -27,6 +27,7 @@ module.exports = {
|
|||
INTEGER: joi.number().integer(),
|
||||
OFFSET: joi.number().integer().min(0),
|
||||
REFERRER: joi.string().max(2048).uri({ scheme: [ 'android-app', 'http', 'https' ]}).allow('none'),
|
||||
RESUME: joi.string().regex(/^[a-zA-Z0-9\/+]+={0,2}$/), // match any valid base64 character
|
||||
STRING: joi.string().max(1024), // 1024 is arbitrary, seems like it should give CSP reports plenty of space.
|
||||
TIME: joi.number().integer().min(0),
|
||||
URL: joi.string().max(2048).uri({ scheme: [ 'http', 'https' ]}), // 2048 is also arbitrary, the same limit we use on the front end.
|
||||
|
|
|
@ -153,6 +153,76 @@ define([
|
|||
});
|
||||
|
||||
return dfd.dojoPromise;
|
||||
},
|
||||
|
||||
'logs error with invalid utm param' () {
|
||||
const dfd = this.async(1000);
|
||||
const req = {
|
||||
query: {
|
||||
/*eslint-disable camelcase*/
|
||||
code: '12345678912345678912345678912312',
|
||||
uid: '12345678912345678912345678912312',
|
||||
utm_campaign: '!'
|
||||
/*eslint-enable camelcase*/
|
||||
},
|
||||
url: '/verify_email'
|
||||
};
|
||||
|
||||
mocks.got = {
|
||||
post: () => {
|
||||
return new Promise((resolve) => {
|
||||
resolve({});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
mockModule(mocks).process(req, res, () => {
|
||||
// We have to use a setTimeout here because the log is performed passively after the response has
|
||||
// been sent.
|
||||
setTimeout(() => {
|
||||
const c = ravenMock.ravenMiddleware.captureMessage;
|
||||
const arg = c.args[0];
|
||||
assert.equal(c.calledOnce, true);
|
||||
assert.equal(arg[0], 'VerificationValidationInfo');
|
||||
const errorMessage = '"utm_campaign" with value "!" fails to match the required pattern: /^[\\w\\/.%-]+/';
|
||||
assert.equal(arg[1].extra.details[0].message, errorMessage);
|
||||
dfd.resolve();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
return dfd.promise;
|
||||
},
|
||||
|
||||
'no logs with valid resume param' () {
|
||||
const dfd = this.async(1000);
|
||||
const req = {
|
||||
query: {
|
||||
code: '12345678912345678912345678912312',
|
||||
resume: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', // All possible base64 characters
|
||||
uid: '12345678912345678912345678912312'
|
||||
},
|
||||
url: '/verify_email'
|
||||
};
|
||||
|
||||
mocks.got = {
|
||||
post: () => {
|
||||
return new Promise((resolve) => {
|
||||
resolve({});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
mockModule(mocks).process(req, res, () => {
|
||||
// We have to use a setTimeout here because the log is performed passively after the response has
|
||||
// been sent.
|
||||
setTimeout(() => {
|
||||
const c = ravenMock.ravenMiddleware.captureMessage;
|
||||
assert.equal(c.callCount, 0);
|
||||
dfd.resolve();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
return dfd.promise;
|
||||
}
|
||||
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче