Skip to content

Commit 5b32677

Browse files
committed
proper Joi validation that matches swagger schema
1 parent 838eb5b commit 5b32677

File tree

4 files changed

+40
-25
lines changed

4 files changed

+40
-25
lines changed

Backend/README.md

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,7 @@ Following variables can be configured:
146146
]
147147

148148

149-
- to schedule a mail to be sent in the future, set `delivery_time`, use ISOString or UTCString format.
150-
151-
"delivery_time": "Mon, 30 May 2016 15:57:25 GMT" or "2016-06-02T21:31:22.145Z"
152-
153-
154-
- in javascript, very easy to format to above timestamp, natively supported in javascript by `date#toUTCString()` method
149+
- to schedule a mail to be sent in the future, set `delivery_time` in ISO 8601 date format.
155150
- for attachments, `content_bytes` should be string in base64 of original binary data.
156151

157152
"attachments": [{

Backend/src/app.js

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const morgan = require('morgan');
1818
const bodyParser = require('body-parser');
1919
const passport = require('passport');
2020
const logger = require('./common/logger');
21+
const _ = require('lodash');
2122

2223
app.use(cors());
2324
app.use(bodyParser.json());
@@ -33,15 +34,26 @@ app.use(passport.initialize());
3334
// eslint-disable-next-line no-unused-vars
3435
app.use((err, req, res, next) => {
3536
logger.logFullError(err, req.signature || `${req.method} ${req.url}`);
36-
let status = err.httpStatus || 500;
37-
if (err.isJoi) {
38-
status = 400;
37+
const errorResponse = {};
38+
const status = (err.isJoi) ? 400 : err.httpStatus || 500;
39+
40+
if (_.isArray(err.details)) {
41+
errorResponse.fields = _.map(err.details, 'path').join(', ');
42+
_.map(err.details, (e) => {
43+
if (e.message) {
44+
if (_.isUndefined(errorResponse.message)) {
45+
errorResponse.message = e.message;
46+
} else {
47+
errorResponse.message += ', ' + e.message;
48+
}
49+
}
50+
});
51+
}
52+
if (_.isUndefined(errorResponse.message)) {
53+
errorResponse.message = 'server error';
3954
}
40-
res.status(status).json({
41-
code: String(status),
42-
message: err.details && err.details[0] && err.details[0].message ?
43-
err.details[0].message : (err.message || 'Server error')
44-
});
55+
errorResponse.code = status;
56+
res.status(status).json(errorResponse);
4557
});
4658

4759
const port = config.port;

Backend/src/common/logger.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,15 @@ logger.decorateWithValidators = function decorateWithValidators(service) {
118118
service[name] = function* serviceMethodWithValidation() {
119119
const args = Array.prototype.slice.call(arguments);
120120
const value = _combineObject(params, args);
121-
const normalized = Joi.attempt(value, method.schema);
121+
const normalized = yield new Promise((resolve) => {
122+
Joi.validate(value, method.schema, { abortEarly: false }, (err, val) => {
123+
if (err) {
124+
throw err;
125+
} else {
126+
resolve(val);
127+
}
128+
});
129+
});
122130
const newArgs = [];
123131
// Joi will normalize values
124132
// for example string number '1' to 1

Backend/src/modules/mail/services/MailService.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,27 @@ const CRUDService = require('../../crud/services/CRUDService');
1919
const attachment = Joi.object().keys({
2020
file_name: Joi.string().required(),
2121
file_type: Joi.string().required(),
22-
content_bytes: Joi.string().required()
22+
content_bytes: Joi.binary().encoding('base64').required()
2323
});
2424

2525
const image = Joi.object().keys({
2626
name: Joi.string().required(),
2727
type: Joi.string().required(),
28-
content_bytes: Joi.string().required()
28+
content_bytes: Joi.binary().encoding('base64').required()
2929
});
3030

3131
const emailSchema = Joi.object().keys({
32-
sender: Joi.string().required(),
33-
recipients: Joi.array().items(Joi.string()).required(),
34-
cc_recipients: Joi.array().items(Joi.string()),
35-
bcc_recipients: Joi.array().items(Joi.string()),
32+
sender: Joi.string().email().required(),
33+
recipients: Joi.array().items(Joi.string().email()).required(),
34+
cc_recipients: Joi.array().items(Joi.string().email()),
35+
bcc_recipients: Joi.array().items(Joi.string().email()),
3636
subject: Joi.string(),
3737
html_body: Joi.string(),
3838
text_body: Joi.string(),
3939
attachments: Joi.array().items(attachment),
4040
images: Joi.array().items(image),
41-
headers: Joi.array().items(Joi.string()),
42-
delivery_time: Joi.string() // in format of ISOString or UTCString
41+
headers: Joi.array().items(Joi.string().regex(/^([^:]+?):(.+)$/)),
42+
delivery_time: Joi.date().iso() // ISO 8601 date format.
4343
});
4444

4545
/**
@@ -75,7 +75,7 @@ function* sendMail(email) {
7575
}
7676
headers should be in "headerName:headerValue" format
7777
attachment content_bytes should be base64 encoded.
78-
delivery_time in format of ISOString or UTCString.
78+
delivery_time in format of ISO 8601 date format
7979
*/
8080

8181
/** @type {Object} data data to be sent to mailgun API */
@@ -226,7 +226,7 @@ function* getMailStatus(id) {
226226
resolve({
227227
delivered: true,
228228
// because mailgun returns unix timestamp in seconds for delivery_time
229-
delivery_time: new Date(deliverEvent.timestamp * 1000).toUTCString()
229+
delivery_time: new Date(deliverEvent.timestamp * 1000).toISOString()
230230
});
231231
} else {
232232
// not yet delivered

0 commit comments

Comments
 (0)