#89 also encrypt draft on save

This commit is contained in:
the-djmaze 2022-02-04 09:00:28 +01:00
parent 384230f7bf
commit d7ed6ce423

View file

@ -337,9 +337,33 @@ class ComposePopupView extends AbstractViewPopup {
}); });
} }
getMessageRequestParams(sSaveFolder) async getMessageRequestParams(sSaveFolder, draft)
{ {
let TextIsHtml = this.oEditor.isHtml(), let
identity = this.currentIdentity(),
params = {
IdentityID: identity.id(),
MessageFolder: this.draftsFolder(),
MessageUid: this.draftUid(),
SaveFolder: sSaveFolder,
To: this.to(),
Cc: this.cc(),
Bcc: this.bcc(),
ReplyTo: this.replyTo(),
Subject: this.subject(),
DraftInfo: this.aDraftInfo,
InReplyTo: this.sInReplyTo,
References: this.sReferences,
MarkAsImportant: this.markAsImportant() ? 1 : 0,
Attachments: this.prepareAttachmentsForSendOrSave(),
// Only used at send, not at save:
Dsn: this.requestDsn() ? 1 : 0,
ReadReceiptRequest: this.requestReadReceipt() ? 1 : 0
},
recipients = draft ? [identity.email()] : this.allRecipients(),
sign = !draft && this.pgpSign() && this.canPgpSign(),
encrypt = this.pgpEncrypt() && this.canPgpEncrypt(),
TextIsHtml = this.oEditor.isHtml(),
Text = this.oEditor.getData(true); Text = this.oEditor.getData(true);
if (TextIsHtml) { if (TextIsHtml) {
let l; let l;
@ -352,27 +376,37 @@ class ComposePopupView extends AbstractViewPopup {
.replace(/(<[^>]+)\s+data-hs-[a-z-]+=("[^"]+"|'[^']+')/gi, '$1'); .replace(/(<[^>]+)\s+data-hs-[a-z-]+=("[^"]+"|'[^']+')/gi, '$1');
} while (l != Text.length) } while (l != Text.length)
} }
return { if (this.mailvelope && 'mailvelope' === this.viewArea()) {
IdentityID: this.currentIdentity() ? this.currentIdentity().id() : '', params.Encrypted = draft
MessageFolder: this.draftsFolder(), ? await this.mailvelope.createDraft()
MessageUid: this.draftUid(), : await this.mailvelope.encrypt(recipients);
SaveFolder: sSaveFolder, } else if (encrypt) {
To: this.to(), if ('openpgp' != encrypt) {
Cc: this.cc(), throw 'Encryption with ' + encrypt + ' not yet implemented';
Bcc: this.bcc(), }
ReplyTo: this.replyTo(), if (sign && 'openpgp' != sign[0]) {
Subject: this.subject(), throw 'Signing with ' + sign[0] + ' not yet implemented';
Html: TextIsHtml ? Text : '', }
Text: TextIsHtml ? '' : Text, if (sign && sign[1]) {
DraftInfo: this.aDraftInfo, if (TextIsHtml) {
InReplyTo: this.sInReplyTo, throw 'Encrypt HTML with ' + encrypt + ' not yet implemented';
References: this.sReferences, }
MarkAsImportant: this.markAsImportant() ? 1 : 0, Text = await OpenPGPUserStore.encrypt(Text, recipients, sign[1]);
Attachments: this.prepareAttachmentsForSendOrSave(), // throw i18n('PGP_NOTIFICATIONS/PGP_ERROR', { ERROR: 'Encryption failed' })
// Only used at send, not at save: } else {
Dsn: this.requestDsn() ? 1 : 0, let data = [
ReadReceiptRequest: this.requestReadReceipt() ? 1 : 0 'Content-Transfer-Encoding: base64',
}; 'Content-Type: text/'+(TextIsHtml?'html':'plain')+'; charset="utf-8"',
'',
base64_encode(Text)
].join("\r\n");
params.Encrypted = await OpenPGPUserStore.encrypt(data, recipients, sign && sign[1]);
}
} else {
params.Html = TextIsHtml ? Text : '';
params.Text = TextIsHtml ? '' : Text;
}
return params;
} }
sendCommand() { sendCommand() {
@ -423,14 +457,7 @@ class ComposePopupView extends AbstractViewPopup {
sSentFolder = UNUSED_OPTION_VALUE === sSentFolder ? '' : sSentFolder; sSentFolder = UNUSED_OPTION_VALUE === sSentFolder ? '' : sSentFolder;
setFolderHash(this.draftsFolder(), ''); this.getMessageRequestParams(sSentFolder).then(params => {
setFolderHash(sSentFolder, '');
const
params = this.getMessageRequestParams(sSentFolder),
sign = this.pgpSign() && this.canPgpSign(),
encrypt = this.pgpEncrypt() && this.canPgpEncrypt(),
send = () =>
Remote.request('SendMessage', Remote.request('SendMessage',
(iError, data) => { (iError, data) => {
this.sending(false); this.sending(false);
@ -448,123 +475,19 @@ class ComposePopupView extends AbstractViewPopup {
this.closeCommand(); this.closeCommand();
} }
} }
setFolderHash(this.draftsFolder(), '');
setFolderHash(sSentFolder, '');
this.reloadDraftFolder(); this.reloadDraftFolder();
}, },
params, params,
30000 30000
); );
}).catch(e => {
if (this.mailvelope && 'mailvelope' === this.viewArea()) { console.error(e);
this.mailvelope.encrypt(this.allRecipients()).then(armored => {
params.Text = params.Html = '';
params.Encrypted = armored;
send();
});
} else if (encrypt) {
if ('openpgp' != encrypt) {
throw 'Encryption with ' + encrypt + ' not yet implemented';
}
if (sign && 'openpgp' != sign[0]) {
throw 'Signing with ' + sign[0] + ' not yet implemented';
}
if (sign && sign[1]) {
if (params.Html) {
throw 'Encrypt HTML with ' + encrypt + ' not yet implemented';
}
OpenPGPUserStore.encrypt(params.Text, this.allRecipients(), sign[1]).then(armored => {
if (armored) {
params.Text = armored;
send();
} else {
this.sendError(true); this.sendError(true);
this.sendErrorDesc(i18n('PGP_NOTIFICATIONS/PGP_ERROR', { ERROR: 'Encryption failed' })); this.sendErrorDesc(e);
this.sending(false); this.sending(false);
}
}); });
} else {
let data = [
'Content-Transfer-Encoding: base64',
'Content-Type: text/'+(params.Html?'html':'plain')+'; charset="utf-8"',
'',
base64_encode(params.Html || params.Text)
].join("\r\n");
OpenPGPUserStore.encrypt(data, this.allRecipients(), sign && sign[1]).then(armored => {
if (armored) {
params.Text = params.Html = '';
params.Encrypted = armored;
send();
} else {
this.sendError(true);
this.sendErrorDesc(i18n('PGP_NOTIFICATIONS/PGP_ERROR', { ERROR: 'Encryption failed' }));
this.sending(false);
}
});
}
} else if (sign) {
if (params.Html) {
throw 'Signing HTML with ' + sign[0] + ' not yet implemented';
}
if ('openpgp' != sign[0]) {
throw 'Signing with ' + sign[0] + ' not yet implemented';
}
const detached = false;
if (detached) {
// Append headers
params.Text = [
'Content-Type: text/plain; charset="utf-8"; protected-headers="v1"',
'Content-Transfer-Encoding: base64',
// 'From: Demo <demo@snappymail.eu>',
// 'To: Demo <demo@snappymail.eu>',
// 'Subject: text detached signed'
''
]
// Now the body in base64
.concat(base64_encode(params.Text))
.join("\r\n");
}
OpenPGPUserStore.sign(params.Text, sign[1]).then(text => {
if (text) {
if (detached) {
params.Signature = text;
} else {
params.Text = text;
}
send();
} else {
this.sendError(true);
this.sendErrorDesc(i18n('PGP_NOTIFICATIONS/PGP_ERROR', { ERROR: 'Signing failed' }));
this.sending(false);
}
});
} else {
send();
}
/*
if (encrypt && sign && encrypt != sign) {
// error 'sign and encrypt must be same engine';
} else if ('openpgp' == encrypt) {
this.allRecipients().forEach(recEmail => {
cfg.publicKeys = cfg.publicKeys.concat(OpenPGPUserStore.getPublicKeyFor(recEmail));
});
pgpPromise = openpgp.encrypt(cfg);
} else if ('openpgp' == sign) {
pgpPromise = openpgp.sign(cfg);
} else {
params.Sign = sign;
params.Encrypt = encrypt;
}
pgpPromise
? pgpPromise
.then(mData => {
params.Text = mData.data;
send();
})
.catch(e => {
this.sendError(true);
this.sendErrorDesc(i18n('PGP_NOTIFICATIONS/PGP_ERROR', { ERROR: '' + e }));
})
: send();
*/
} catch (e) { } catch (e) {
console.error(e); console.error(e);
this.sendError(true); this.sendError(true);
@ -580,14 +503,8 @@ class ComposePopupView extends AbstractViewPopup {
} else { } else {
this.savedError(false); this.savedError(false);
this.saving(true); this.saving(true);
this.autosaveStart(); this.autosaveStart();
this.getMessageRequestParams(FolderUserStore.draftsFolder(), 1).then(params => {
setFolderHash(FolderUserStore.draftsFolder(), '');
const
params = this.getMessageRequestParams(FolderUserStore.draftsFolder()),
save = () =>
Remote.request('SaveMessage', Remote.request('SaveMessage',
(iError, oData) => { (iError, oData) => {
let result = false; let result = false;
@ -613,6 +530,7 @@ class ComposePopupView extends AbstractViewPopup {
if (this.bFromDraft) { if (this.bFromDraft) {
setFolderHash(this.draftsFolder(), ''); setFolderHash(this.draftsFolder(), '');
} }
setFolderHash(FolderUserStore.draftsFolder(), '');
} }
} }
@ -626,20 +544,10 @@ class ComposePopupView extends AbstractViewPopup {
params, params,
200000 200000
); );
if (this.mailvelope && 'mailvelope' === this.viewArea()) {
this.mailvelope.createDraft().then(armored => {
params.Text = armored;
save();
}); });
} else {
save();
} }
} }
return true;
}
deleteCommand() { deleteCommand() {
if (!isPopupVisible(AskPopupView) && this.modalVisibility()) { if (!isPopupVisible(AskPopupView) && this.modalVisibility()) {
showScreenPopup(AskPopupView, [ showScreenPopup(AskPopupView, [
@ -1229,13 +1137,13 @@ class ComposePopupView extends AbstractViewPopup {
// initUploader // initUploader
if (this.composeUploaderButton()) { if (this.composeUploaderButton()) {
const uploadCache = {}, const oJua = new Jua({
attachmentSizeLimit = pInt(SettingsGet('AttachmentLimit')),
oJua = new Jua({
action: serverRequest('Upload'), action: serverRequest('Upload'),
clickElement: this.composeUploaderButton(), clickElement: this.composeUploaderButton(),
dragAndDropElement: this.composeUploaderDropPlace() dragAndDropElement: this.composeUploaderDropPlace()
}); }),
uploadCache = {},
attachmentSizeLimit = pInt(SettingsGet('AttachmentLimit'));
oJua oJua
// .on('onLimitReached', (limit) => { // .on('onLimitReached', (limit) => {
@ -1593,12 +1501,14 @@ class ComposePopupView extends AbstractViewPopup {
} }
mailvelopeArea() { mailvelopeArea() {
if (!this.mailvelope) {
/** /**
* Creates an iframe with an editor for a new encrypted mail. * Creates an iframe with an editor for a new encrypted mail.
* The iframe will be injected into the container identified by selector. * The iframe will be injected into the container identified by selector.
* https://mailvelope.github.io/mailvelope/Editor.html * https://mailvelope.github.io/mailvelope/Editor.html
*/ */
let text = this.oEditor.getData(true), let text = this.oEditor.getData(true),
encrypted = text.includes('-----BEGIN PGP MESSAGE-----'),
size = SettingsGet('PhpUploadSizes')['post_max_size'], size = SettingsGet('PhpUploadSizes')['post_max_size'],
quota = pInt(size); quota = pInt(size);
switch (size.slice(-1)) { switch (size.slice(-1)) {
@ -1606,20 +1516,20 @@ class ComposePopupView extends AbstractViewPopup {
case 'M': quota *= 1024; // fallthrough case 'M': quota *= 1024; // fallthrough
case 'K': quota *= 1024; case 'K': quota *= 1024;
} }
this.mailvelope ||
mailvelope.createEditorContainer('#mailvelope-editor', PgpUserStore.mailvelopeKeyring, { mailvelope.createEditorContainer('#mailvelope-editor', PgpUserStore.mailvelopeKeyring, {
// https://mailvelope.github.io/mailvelope/global.html#EditorContainerOptions // https://mailvelope.github.io/mailvelope/global.html#EditorContainerOptions
quota: Math.max(2048, (quota / 1024)) - 48, // (text + attachments) limit in kilobytes quota: Math.max(2048, (quota / 1024)) - 48, // (text + attachments) limit in kilobytes
predefinedText: this.oEditor.isHtml() ? htmlToPlain(text) : text armoredDraft: encrypted ? text : '', // Ascii Armored PGP Text Block
predefinedText: encrypted ? '' : (this.oEditor.isHtml() ? htmlToPlain(text) : text),
/* /*
signMsg: false, // if true then the mail will be signed (default: false)
armoredDraft: '', // Ascii Armored PGP Text Block
quotedMail: '', // Ascii Armored PGP Text Block mail that should be quoted quotedMail: '', // Ascii Armored PGP Text Block mail that should be quoted
quotedMailIndent: true, // if true the quoted mail will be indented (default: true) quotedMailIndent: true, // if true the quoted mail will be indented (default: true)
quotedMailHeader: '', // header to be added before the quoted mail quotedMailHeader: '', // header to be added before the quoted mail
keepAttachments: false, // add attachments of quotedMail to editor (default: false) keepAttachments: false, // add attachments of quotedMail to editor (default: false)
*/ */
signMsg: confirm('Also sign this message?')
}).then(editor => this.mailvelope = editor); }).then(editor => this.mailvelope = editor);
}
this.viewArea('mailvelope'); this.viewArea('mailvelope');
} }
attachmentsArea() { attachmentsArea() {