Skip to content

Commit

Permalink
encrypt messages copied into encrypted mailbox
Browse files Browse the repository at this point in the history
  • Loading branch information
NickOvt committed Nov 11, 2024
1 parent 076f2c6 commit fa849f2
Showing 1 changed file with 90 additions and 0 deletions.
90 changes: 90 additions & 0 deletions lib/handlers/on-copy.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ async function copyHandler(server, messageHandler, connection, mailbox, update,

notifyLongRunning();

let targetMailboxEncrypted = false;

if (targetData.encryptMessages) {
targetMailboxEncrypted = true;
}

try {
while ((messageData = await cursor.next())) {
tools.checkSocket(socket); // do we even have to copy anything?
Expand All @@ -141,6 +147,12 @@ async function copyHandler(server, messageHandler, connection, mailbox, update,
uid: messageData.uid,
_id: messageData._id
};

const parsedHeader = (messageData.mimeTree && messageData.mimeTree.parsedHeader) || {};
const parsedContentType = parsedHeader['content-type'];

const isMessageEncrypted = parsedContentType ? parsedContentType.subtype === 'encrypted' : false;

// Copying is not done in bulk to minimize risk of going out of sync with incremental UIDs
sourceUid.unshift(messageData.uid);
let item = await db.database.collection('mailboxes').findOneAndUpdate(
Expand Down Expand Up @@ -218,6 +230,84 @@ async function copyHandler(server, messageHandler, connection, mailbox, update,
{ writeConcern: 'majority' }
);

const newPrepared = await new Promise((resolve, reject) => {
if (targetMailboxEncrypted && !isMessageEncrypted && userData.pubKey) {
// encrypt message
const outputStream = messageHandler.indexer.rebuild(messageData.mimeTree).value; // get raw rebuilder stream
let raw = Buffer.from([], 'binary'); // set initial raw

outputStream
.on('data', data => {
raw = Buffer.concat([raw, data]);
})
.on('end', () => {
messageHandler.encryptMessages(userData.pubKey || '', raw, (err, res) => {
if (err) {
return reject(err);
}

// encrypted rebuilt raw

if (res) {
messageHandler.prepareMessage({ raw: res }, (err, prepared) => {
if (err) {
return reject(err);
}
// prepared new message structure from encrypted raw

const maildata = messageHandler.indexer.getMaildata(prepared.mimeTree);

// add attachments of encrypted messages
if (maildata.attachments && maildata.attachments.length) {
messageData.attachments = maildata.attachments;
messageData.ha = maildata.attachments.some(a => !a.related);
} else {
messageData.ha = false;
}

// remove fields that may leak data in FE or DB
delete messageData.text;
delete messageData.html;
messageData.intro = '';

messageHandler.indexer.storeNodeBodies(maildata, prepared.mimeTree, err => {
// store new attachments
let cleanup = () => {
let attachmentIds = Object.keys(prepared.mimeTree.attachmentMap || {}).map(
key => prepared.mimeTree.attachmentMap[key]
);

messageHandler.attachmentStorage.deleteMany(attachmentIds, maildata.magic);

if (err) {
return reject(err);
}
};

if (err) {
return cleanup(err);
}

return resolve(prepared);
});
});
}
});
});
} else {
resolve(false);
}
});

// replace fields
if (newPrepared) {
messageData.mimeTree = newPrepared.mimeTree;
messageData.size = newPrepared.size;
messageData.bodystructure = newPrepared.bodystructure;
messageData.envelope = newPrepared.envelope;
messageData.headers = newPrepared.headers;
}

let r = await db.database.collection('messages').insertOne(messageData, { writeConcern: 'majority' });

if (!r || !r.acknowledged) {
Expand Down

0 comments on commit fa849f2

Please sign in to comment.