@@ -132,6 +132,12 @@ async function copyHandler(server, messageHandler, connection, mailbox, update,
132
132
133
133
notifyLongRunning ( ) ;
134
134
135
+ let targetMailboxEncrypted = false ;
136
+
137
+ if ( targetData . encryptMessages ) {
138
+ targetMailboxEncrypted = true ;
139
+ }
140
+
135
141
try {
136
142
while ( ( messageData = await cursor . next ( ) ) ) {
137
143
tools . checkSocket ( socket ) ; // do we even have to copy anything?
@@ -141,6 +147,12 @@ async function copyHandler(server, messageHandler, connection, mailbox, update,
141
147
uid : messageData . uid ,
142
148
_id : messageData . _id
143
149
} ;
150
+
151
+ const parsedHeader = ( messageData . mimeTree && messageData . mimeTree . parsedHeader ) || { } ;
152
+ const parsedContentType = parsedHeader [ 'content-type' ] ;
153
+
154
+ const isMessageEncrypted = parsedContentType ? parsedContentType . subtype === 'encrypted' : false ;
155
+
144
156
// Copying is not done in bulk to minimize risk of going out of sync with incremental UIDs
145
157
sourceUid . unshift ( messageData . uid ) ;
146
158
let item = await db . database . collection ( 'mailboxes' ) . findOneAndUpdate (
@@ -218,6 +230,96 @@ async function copyHandler(server, messageHandler, connection, mailbox, update,
218
230
{ writeConcern : 'majority' }
219
231
) ;
220
232
233
+ const newPrepared = await new Promise ( ( resolve , reject ) => {
234
+ if ( targetMailboxEncrypted && ! isMessageEncrypted && userData . pubKey ) {
235
+ // encrypt message
236
+ // get raw from existing mimetree
237
+ let outputStream = messageHandler . indexer . rebuild ( messageData . mimeTree ) ; // get raw rebuilder response obj (.value is the stream)
238
+
239
+ if ( ! outputStream || outputStream . type !== 'stream' || ! outputStream . value ) {
240
+ return reject ( new Error ( 'Cannot fetch message' ) ) ;
241
+ }
242
+ outputStream = outputStream . value ; // set stream to actual stream object (.value)
243
+
244
+ let chunks = [ ] ;
245
+ let chunklen = 0 ;
246
+ outputStream
247
+ . on ( 'readable' , ( ) => {
248
+ let chunk ;
249
+ while ( ( chunk = outputStream . read ( ) ) !== null ) {
250
+ chunks . push ( chunk ) ;
251
+ chunklen += chunk . length ;
252
+ }
253
+ } )
254
+ . on ( 'end' , ( ) => {
255
+ const raw = Buffer . concat ( chunks , chunklen ) ;
256
+ messageHandler . encryptMessages ( userData . pubKey , raw , ( err , res ) => {
257
+ if ( err ) {
258
+ return reject ( err ) ;
259
+ }
260
+
261
+ // encrypted rebuilt raw
262
+
263
+ if ( res ) {
264
+ messageHandler . prepareMessage ( { raw : res } , ( err , prepared ) => {
265
+ if ( err ) {
266
+ return reject ( err ) ;
267
+ }
268
+ // prepared new message structure from encrypted raw
269
+
270
+ const maildata = messageHandler . indexer . getMaildata ( prepared . mimeTree ) ;
271
+
272
+ // add attachments of encrypted messages
273
+ if ( maildata . attachments && maildata . attachments . length ) {
274
+ messageData . attachments = maildata . attachments ;
275
+ messageData . ha = maildata . attachments . some ( a => ! a . related ) ;
276
+ } else {
277
+ messageData . ha = false ;
278
+ }
279
+
280
+ // remove fields that may leak data in FE or DB
281
+ delete messageData . text ;
282
+ delete messageData . html ;
283
+ messageData . intro = '' ;
284
+
285
+ messageHandler . indexer . storeNodeBodies ( maildata , prepared . mimeTree , err => {
286
+ // store new attachments
287
+ let cleanup = ( ) => {
288
+ let attachmentIds = Object . keys ( prepared . mimeTree . attachmentMap || { } ) . map (
289
+ key => prepared . mimeTree . attachmentMap [ key ]
290
+ ) ;
291
+
292
+ messageHandler . attachmentStorage . deleteMany ( attachmentIds , maildata . magic ) ;
293
+
294
+ if ( err ) {
295
+ return reject ( err ) ;
296
+ }
297
+ } ;
298
+
299
+ if ( err ) {
300
+ return cleanup ( err ) ;
301
+ }
302
+
303
+ return resolve ( prepared ) ;
304
+ } ) ;
305
+ } ) ;
306
+ }
307
+ } ) ;
308
+ } ) ;
309
+ } else {
310
+ resolve ( false ) ;
311
+ }
312
+ } ) ;
313
+
314
+ // replace fields
315
+ if ( newPrepared ) {
316
+ messageData . mimeTree = newPrepared . mimeTree ;
317
+ messageData . size = newPrepared . size ;
318
+ messageData . bodystructure = newPrepared . bodystructure ;
319
+ messageData . envelope = newPrepared . envelope ;
320
+ messageData . headers = newPrepared . headers ;
321
+ }
322
+
221
323
let r = await db . database . collection ( 'messages' ) . insertOne ( messageData , { writeConcern : 'majority' } ) ;
222
324
223
325
if ( ! r || ! r . acknowledged ) {
0 commit comments