This commit is contained in:
Andris Reinman 2018-08-30 13:18:56 +03:00
parent e0f7eb89bf
commit ebd9e50e14

View file

@ -24,6 +24,7 @@ module.exports = (db, server, messageHandler) => {
});
const updateMessage = util.promisify(messageHandler.update.bind(messageHandler));
const getAttachmentData = util.promisify(messageHandler.attachmentStorage.get.bind(messageHandler.attachmentStorage));
/**
* @api {get} /users/:user/mailboxes/:mailbox/messages List messages in a Mailbox
@ -1493,121 +1494,140 @@ module.exports = (db, server, messageHandler) => {
* "error": "This attachment does not exist"
* }
*/
server.get({ name: 'attachment', path: '/users/:user/mailboxes/:mailbox/messages/:message/attachments/:attachment' }, (req, res, next) => {
const schema = Joi.object().keys({
user: Joi.string()
.hex()
.lowercase()
.length(24)
.required(),
mailbox: Joi.string()
.hex()
.lowercase()
.length(24)
.required(),
message: Joi.number()
.min(1)
.required(),
attachment: Joi.string()
.regex(/^ATT\d+$/i)
.uppercase()
.required()
});
const result = Joi.validate(req.params, schema, {
abortEarly: false,
convert: true
});
if (result.error) {
res.json({
error: result.error.message,
code: 'InputValidationError'
server.get(
{ name: 'attachment', path: '/users/:user/mailboxes/:mailbox/messages/:message/attachments/:attachment' },
tools.asyncifyJson(async (req, res, next) => {
const schema = Joi.object().keys({
user: Joi.string()
.hex()
.lowercase()
.length(24)
.required(),
mailbox: Joi.string()
.hex()
.lowercase()
.length(24)
.required(),
message: Joi.number()
.min(1)
.required(),
attachment: Joi.string()
.regex(/^ATT\d+$/i)
.uppercase()
.required()
});
return next();
}
let user = new ObjectID(result.value.user);
let mailbox = new ObjectID(result.value.mailbox);
let message = result.value.message;
let attachment = result.value.attachment;
const result = Joi.validate(req.params, schema, {
abortEarly: false,
convert: true
});
db.database.collection('messages').findOne(
{
mailbox,
uid: message,
user
},
{
projection: {
_id: true,
user: true,
attachments: true,
'mimeTree.attachmentMap': true
}
},
(err, messageData) => {
if (err) {
res.json({
error: 'MongoDB Error: ' + err.message,
code: 'InternalDatabaseError'
});
return next();
}
if (!messageData || messageData.user.toString() !== user.toString()) {
res.json({
error: 'This message does not exist',
code: 'NoSuchMessage'
});
return next();
}
let attachmentId = messageData.mimeTree.attachmentMap && messageData.mimeTree.attachmentMap[attachment];
if (!attachmentId) {
res.json({
error: 'This attachment does not exist'
});
return next();
}
messageHandler.attachmentStorage.get(attachmentId, (err, attachmentData) => {
if (err) {
res.json({
error: err.message
});
return next();
}
res.writeHead(200, {
'Content-Type': attachmentData.contentType || 'application/octet-stream'
});
let decode = true;
if (attachmentData.metadata.decoded) {
attachmentData.metadata.decoded = false;
decode = false;
}
let attachmentStream = messageHandler.attachmentStorage.createReadStream(attachmentId, attachmentData);
attachmentStream.once('error', err => res.emit('error', err));
if (!decode) {
return attachmentStream.pipe(res);
}
if (attachmentData.transferEncoding === 'base64') {
attachmentStream.pipe(new libbase64.Decoder()).pipe(res);
} else if (attachmentData.transferEncoding === 'quoted-printable') {
attachmentStream.pipe(new libqp.Decoder()).pipe(res);
} else {
attachmentStream.pipe(res);
}
if (result.error) {
res.json({
error: result.error.message,
code: 'InputValidationError'
});
return next();
}
);
});
// permissions check
if (req.user && req.user === result.value.user) {
req.validate(roles.can(req.role).readOwn('messages'));
} else {
req.validate(roles.can(req.role).readAny('messages'));
}
let user = new ObjectID(result.value.user);
let mailbox = new ObjectID(result.value.mailbox);
let message = result.value.message;
let attachment = result.value.attachment;
let messageData;
try {
messageData = await db.database.collection('messages').findOne(
{
mailbox,
uid: message,
user
},
{
projection: {
_id: true,
user: true,
attachments: true,
'mimeTree.attachmentMap': true
}
}
);
} catch (err) {
res.json({
error: 'MongoDB Error: ' + err.message,
code: 'InternalDatabaseError'
});
return next();
}
if (!messageData || messageData.user.toString() !== user.toString()) {
res.json({
error: 'This message does not exist',
code: 'NoSuchMessage'
});
return next();
}
let attachmentId = messageData.mimeTree.attachmentMap && messageData.mimeTree.attachmentMap[attachment];
if (!attachmentId) {
res.json({
error: 'This attachment does not exist'
});
return next();
}
let attachmentData;
try {
attachmentData = await getAttachmentData(attachmentId);
} catch (err) {
res.json({
error: err.message
});
return next();
}
res.writeHead(200, {
'Content-Type': attachmentData.contentType || 'application/octet-stream'
});
let decode = true;
if (attachmentData.metadata.decoded) {
attachmentData.metadata.decoded = false;
decode = false;
}
let attachmentStream = messageHandler.attachmentStorage.createReadStream(attachmentId, attachmentData);
attachmentStream.once('error', err => {
log.error('API', 'message=%s attachment=%s error=%s', messageData._id, attachmentId, err.message);
try {
res.end();
} catch (err) {
//ignore
}
});
if (!decode) {
attachmentStream.pipe(res);
return;
}
if (attachmentData.transferEncoding === 'base64') {
attachmentStream.pipe(new libbase64.Decoder()).pipe(res);
} else if (attachmentData.transferEncoding === 'quoted-printable') {
attachmentStream.pipe(new libqp.Decoder()).pipe(res);
} else {
attachmentStream.pipe(res);
}
})
);
/**
* @api {put} /users/:user/mailboxes/:mailbox/messages/:message Update Message information