part of #1051 but first need to do #1060
from https://github.com/FlowCrypt/flowcrypt-mobile-core/blob/master/source/mobile-interface/endpoints.ts
Unit tests to copy: everything that starts with parseDecryptMsg at https://github.com/FlowCrypt/flowcrypt-mobile-core/blob/master/source/test.ts
current implementation:
publicparseDecryptMsg=async(uncheckedReq: any,data: Buffers): Promise<Buffers>=>{const{keys: kisWithPp, msgPwd, isEmail }=ValidateInput.parseDecryptMsg(uncheckedReq);constrawBlocks: MsgBlock[]=[];// contains parsed, unprocessed / possibly encrypted dataletrawSigned: string|undefined=undefined;letsubject: string|undefined=undefined;if(isEmail){const{ blocks, rawSignedContent, headers }=awaitMime.process(Buf.concat(data));subject=String(headers['subject']);rawSigned=rawSignedContent;rawBlocks.push(...blocks);}else{rawBlocks.push(MsgBlock.fromContent('encryptedMsg',newBuf(Buf.concat(data))));}constsequentialProcessedBlocks: MsgBlock[]=[];// contains decrypted or otherwise formatted datafor(constrawBlockofrawBlocks){if((rawBlock.type==='signedMsg'||rawBlock.type==='signedHtml')&&rawBlock.signature){constverify=awaitPgpMsg.verifyDetached({sigText: Buf.fromUtfStr(rawBlock.signature),plaintext: Buf.with(rawSigned||rawBlock.content)});if(rawBlock.type==='signedHtml'){sequentialProcessedBlocks.push({type: 'verifiedMsg',content: Xss.htmlSanitizeKeepBasicTags(rawBlock.content.toString()),verifyRes: verify,complete: true});}else{// textsequentialProcessedBlocks.push({type: 'verifiedMsg',content: Str.asEscapedHtml(rawBlock.content.toString()),verifyRes: verify,complete: true});}}elseif(rawBlock.type==='encryptedMsg'||rawBlock.type==='signedMsg'){constdecryptRes=awaitPgpMsg.decrypt({ kisWithPp, msgPwd,encryptedData: Buf.with(rawBlock.content)});if(decryptRes.success){if(decryptRes.isEncrypted){constformatted=awaitMsgBlockParser.fmtDecryptedAsSanitizedHtmlBlocks(decryptRes.content);sequentialProcessedBlocks.push(...formatted.blocks);subject=formatted.subject||subject;}else{// treating as text, converting to html - what about plain signed html? This could produce html tags// although hopefully, that would, typically, result in the `(rawBlock.type === 'signedMsg' || rawBlock.type === 'signedHtml')` block above// the only time I can imagine it screwing up down here is if it was a signed-only message that was actually fully armored (text not visible) with a mime msg inside// ... -> in which case the user would I think see full mime content?sequentialProcessedBlocks.push({type: 'verifiedMsg',content: Str.asEscapedHtml(decryptRes.content.toUtfStr()),complete: true,verifyRes: decryptRes.signature});}}else{decryptRes.message=undefined;sequentialProcessedBlocks.push({type: 'decryptErr',content: decryptRes.error.type===DecryptErrTypes.noMdc ? decryptRes.content! : rawBlock.content,decryptErr: decryptRes,complete: true});}}elseif(rawBlock.type==='encryptedAtt'&&rawBlock.attMeta&&/^(0x)?[A-Fa-f0-9]{16,40}\.asc\.pgp$/.test(rawBlock.attMeta.name||'')){// encrypted pubkey attachedconstdecryptRes=awaitPgpMsg.decrypt({ kisWithPp, msgPwd,encryptedData: Buf.with(rawBlock.attMeta.data||'')});if(decryptRes.content){sequentialProcessedBlocks.push({type: 'publicKey',content: decryptRes.content.toString(),complete: true});}else{sequentialProcessedBlocks.push(rawBlock);// will show as encryptedAtt}}else{sequentialProcessedBlocks.push(rawBlock);}}constmsgContentBlocks: MsgBlock[]=[];constblocks: MsgBlock[]=[];letreplyType='plain';for(constblockofsequentialProcessedBlocks){// fix/adjust/format blocks before returning it over JSONif(block.contentinstanceofBuf){// cannot JSON-serialize Bufblock.content=isContentBlock(block.type) ? block.content.toUtfStr() : block.content.toRawBytesStr();}elseif(block.attMeta&&block.attMeta.datainstanceofUint8Array){// converting to base64-encoded string instead of uint8 for JSON serilization// value actually replaced to a string, but type remains Uint8Array type set to satisfy TS// no longer used below, only gets passed to be serialized as JSON - later consumed by iOS or Android appblock.attMeta.data=Buf.fromUint8(block.attMeta.data).toBase64Str()asanyasUint8Array;}if(block.type==='decryptedHtml'||block.type==='decryptedText'||block.type==='decryptedAtt'){replyType='encrypted';}if(block.type==='publicKey'){if(!block.keyDetails){// this could eventually be moved into detectBlocks, which would make it asyncconst{ keys }=awaitPgpKey.normalize(block.content);if(keys.length){for(constpubofkeys){blocks.push({type: 'publicKey',content: pub.armor(),complete: true,keyDetails: awaitPgpKey.details(pub)});}}else{blocks.push({type: 'decryptErr',content: block.content,complete: true,decryptErr: {success: false,error: {type: 'format'asDecryptErrTypes,message: 'Badly formatted public key'},longids: {message: [],matching: [],chosen: [],needPassphrase: []}}});}}else{blocks.push(block);}}elseif(isContentBlock(block.type)){msgContentBlocks.push(block);}elseif(Mime.isPlainImgAtt(block)){msgContentBlocks.push(block);}elseif(block.type!=='plainAtt'){blocks.push(block);}}const{ contentBlock, text }=fmtContentBlock(msgContentBlocks);blocks.unshift(contentBlock);// data represent one JSON-stringified block per line. This is so that it can be read as a stream laterreturnfmtRes({ text, replyType, subject },Buf.fromUtfStr(blocks.map(b=>JSON.stringify(b)).join('\n')));}
part of #1051 but first need to do #1060
from https://github.com/FlowCrypt/flowcrypt-mobile-core/blob/master/source/mobile-interface/endpoints.ts
Unit tests to copy: everything that starts with
parseDecryptMsgat https://github.com/FlowCrypt/flowcrypt-mobile-core/blob/master/source/test.tscurrent implementation: