mirror of
https://github.com/nodemailer/wildduck.git
synced 2025-11-03 19:50:14 +08:00
messages
This commit is contained in:
parent
e0f7eb89bf
commit
ebd9e50e14
1 changed files with 130 additions and 110 deletions
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue