diff --git a/dev/Settings/User/OpenPgp.js b/dev/Settings/User/OpenPgp.js index 5ebb065a2..7ac5174a8 100644 --- a/dev/Settings/User/OpenPgp.js +++ b/dev/Settings/User/OpenPgp.js @@ -1,4 +1,5 @@ -import { PgpUserStore } from 'Stores/User/Pgp'; +import { GnuPGUserStore } from 'Stores/User/GnuPG'; +import { OpenPGPUserStore } from 'Stores/User/OpenPGP'; import { SettingsUserStore } from 'Stores/User/Settings'; import Remote from 'Remote/User/Fetch'; @@ -13,14 +14,14 @@ import { Settings } from 'Common/Globals'; export class OpenPgpUserSettings /*extends AbstractViewSettings*/ { constructor() { - this.gnupgPublicKeys = PgpUserStore.gnupgPublicKeys; - this.gnupgPrivateKeys = PgpUserStore.gnupgPrivateKeys; + this.gnupgPublicKeys = GnuPGUserStore.publicKeys; + this.gnupgPrivateKeys = GnuPGUserStore.privateKeys; - this.openpgpkeysPublic = PgpUserStore.openpgpPublicKeys; - this.openpgpkeysPrivate = PgpUserStore.openpgpPrivateKeys; + this.openpgpkeysPublic = OpenPGPUserStore.publicKeys; + this.openpgpkeysPrivate = OpenPGPUserStore.privateKeys; this.canOpenPGP = Settings.capa(Capa.OpenPGP); - this.canGnuPG = Settings.capa(Capa.GnuPG); + this.canGnuPG = GnuPGUserStore.isSupported(); this.canMailvelope = !!window.mailvelope; this.allowDraftAutosave = SettingsUserStore.allowDraftAutosave; diff --git a/dev/Stores/User/GnuPG.js b/dev/Stores/User/GnuPG.js new file mode 100644 index 000000000..ffab9007b --- /dev/null +++ b/dev/Stores/User/GnuPG.js @@ -0,0 +1,154 @@ +import ko from 'ko'; + +import { Capa } from 'Common/Enums'; +import { Settings } from 'Common/Globals'; +import { delegateRunOnDestroy } from 'Common/UtilsUser'; + +//import { showScreenPopup } from 'Knoin/Knoin'; + +//import { EmailModel } from 'Model/Email'; +//import { OpenPgpKeyModel } from 'Model/OpenPgpKey'; + +import Remote from 'Remote/User/Fetch'; + +import { showScreenPopup } from 'Knoin/Knoin'; +import { OpenPgpKeyPopupView } from 'View/Popup/OpenPgpKey'; + +const + findGnuPGKey = (keys, query, sign) => + keys.find(key => + key[sign ? 'can_sign' : 'can_decrypt'] + && (key.emails.includes(query) || key.subkeys.find(key => query == key.keyid || query == key.fingerprint)) + ); + +export const GnuPGUserStore = new class { + constructor() { + /** + * PECL gnupg / PEAR Crypt_GPG + * [ {email, can_encrypt, can_sign}, ... ] + */ + this.keyring; + this.publicKeys = ko.observableArray(); + this.privateKeys = ko.observableArray(); + } + + loadKeyrings(/*identifier*/) { + this.keyring = null; + this.publicKeys([]); + this.privateKeys([]); + Remote.request('GnupgGetKeys', + (iError, oData) => { + if (oData && oData.Result) { + this.keyring = oData.Result; + const initKey = (key, isPrivate) => { + const aEmails = []; + key.id = key.subkeys[0].keyid; + key.fingerprint = key.subkeys[0].fingerprint; + key.uids.forEach(uid => uid.email && aEmails.push(uid.email)); + key.emails = aEmails; + key.askDelete = ko.observable(false); + key.openForDeletion = ko.observable(null).askDeleteHelper(); + key.remove = () => { + if (key.askDelete()) { + Remote.request('GnupgDeleteKey', + (iError, oData) => { + if (oData && oData.Result) { + if (isPrivate) { + this.privateKeys.remove(key); + } else { + this.publicKeys.remove(key); + } + delegateRunOnDestroy(key); + } + }, { + KeyId: key.id, + isPrivate: isPrivate + } + ); + } + }; + key.view = () => { + let pass = isPrivate ? prompt('Passphrase') : true; + if (pass) { + Remote.request('GnupgExportKey', + (iError, oData) => { + if (oData && oData.Result) { + key.armor = oData.Result; + showScreenPopup(OpenPgpKeyPopupView, [key]); + } + }, { + KeyId: key.id, + isPrivate: isPrivate, + Passphrase: isPrivate ? pass : '' + } + ); + } + }; + return key; + }; + this.publicKeys(oData.Result.public.map(key => initKey(key, 0))); + this.privateKeys(oData.Result.private.map(key => initKey(key, 1))); + console.log('gnupg ready'); + } + } + ); + } + + /** + * @returns {boolean} + */ + isSupported() { + return Settings.capa(Capa.GnuPG); + } + + importKey(key, callback) { + Remote.request('GnupgImportKey', + (iError, oData) => { + if (oData && oData.Result) { +// this.gnupgKeyring = oData.Result; + } + callback && callback(iError, oData); + }, { + Key: key + } + ); + } + + /** + keyPair.privateKey + keyPair.publicKey + keyPair.revocationCertificate + keyPair.onServer + keyPair.inGnuPG + */ + storeKeyPair(keyPair, callback) { + Remote.request('PgpStoreKeyPair', + (iError, oData) => { + if (oData && oData.Result) { +// this.gnupgKeyring = oData.Result; + } + callback && callback(iError, oData); + }, keyPair + ); + } + + /** + * Checks if verifying/encrypting a message is possible with given email addresses. + */ + hasPublicKeyForEmails(recipients, all) { + const count = recipients.length, + length = count ? recipients.filter(email => +// (key.can_verify || key.can_encrypt) && + this.publicKeys.find(key => key.emails.includes(email)) + ).length : 0; + return length && (!all || length === count); + } + + getPrivateKeyFor(query, sign) { + return findGnuPGKey(this.privateKeys, query, sign); + } + + getPublicKeyFor(query, sign) { + return findGnuPGKey(this.publicKeys, query, sign); + } +}; diff --git a/dev/Stores/User/OpenPGP.js b/dev/Stores/User/OpenPGP.js new file mode 100644 index 000000000..5863dddef --- /dev/null +++ b/dev/Stores/User/OpenPGP.js @@ -0,0 +1,268 @@ +/** + * OpenPGP.js + */ + +import ko from 'ko'; + +import { isArray, arrayLength } from 'Common/Utils'; +import { delegateRunOnDestroy } from 'Common/UtilsUser'; + +import { showScreenPopup } from 'Knoin/Knoin'; +import { OpenPgpKeyPopupView } from 'View/Popup/OpenPgpKey'; + +const + findKeyByHex = (keys, hash) => + keys.find(item => item && (hash === item.id || item.ids.includes(hash))), + + findOpenPGPKey = (keys, query/*, sign*/) => + keys.find(key => + key.emails.includes(query) || query == key.id || query == key.fingerprint + ), + + /** + * OpenPGP.js v5 removed the localStorage (keyring) + * This should be compatible with the old OpenPGP.js v2 + */ + publicKeysItem = 'openpgp-public-keys', + privateKeysItem = 'openpgp-private-keys', + storage = window.localStorage, + loadOpenPgpKeys = async itemname => { + let keys = [], key, + armoredKeys = JSON.parse(storage.getItem(itemname)), + i = arrayLength(armoredKeys); + while (i--) { + key = await openpgp.readKey({armoredKey:armoredKeys[i]}); + if (!key.err) { + keys.push(new OpenPgpKeyModel(armoredKeys[i], key)); + } + } + return keys; + }, + storeOpenPgpKeys = (keys, section) => { + let armoredKeys = keys.map(item => item.armor); + if (armoredKeys.length) { + storage.setItem(section, JSON.stringify(armoredKeys)); + } else { + storage.removeItem(section); + } + }; + +class OpenPgpKeyModel { + constructor(armor, key) { + this.key = key; + const aEmails = []; + if (key.users) { + key.users.forEach(user => user.userID.email && aEmails.push(user.userID.email)); + } + this.id = key.getKeyID().toHex(); + this.fingerprint = key.getFingerprint(); + this.can_encrypt = !!key.getEncryptionKey(); + this.can_sign = !!key.getSigningKey(); + this.emails = aEmails; + this.armor = armor; + this.askDelete = ko.observable(false); + this.openForDeletion = ko.observable(null).askDeleteHelper(); +// key.getUserIDs() +// key.getPrimaryUser() + } + + view() { + showScreenPopup(OpenPgpKeyPopupView, [this]); + } + + remove() { + if (this.askDelete()) { + if (this.key.isPrivate()) { + OpenPGPUserStore.privateKeys.remove(this); + storeOpenPgpKeys(OpenPGPUserStore.privateKeys, privateKeysItem); + } else { + OpenPGPUserStore.publicKeys.remove(this); + storeOpenPgpKeys(OpenPGPUserStore.publicKeys, publicKeysItem); + } + delegateRunOnDestroy(this); + } + } +/* + toJSON() { + return this.armor; + } +*/ +} + +export const OpenPGPUserStore = new class { + constructor() { + this.publicKeys = ko.observableArray(); + this.privateKeys = ko.observableArray(); + } + + loadKeyrings() { + loadOpenPgpKeys(publicKeysItem).then(keys => { + this.publicKeys(keys || []); + console.log('openpgp.js public keys loaded'); + }); + loadOpenPgpKeys(privateKeysItem).then(keys => { + this.privateKeys(keys || []) + console.log('openpgp.js private keys loaded'); + }); + } + + /** + * @returns {boolean} + */ + isSupported() { + return !!window.openpgp; + } + + importKey(armoredKey) { + openpgp.readKey({armoredKey:armoredKey}).then(key => { + if (!key.err) { + if (key.isPrivate()) { + this.privateKeys.push(new OpenPgpKeyModel(armoredKey, key)); + storeOpenPgpKeys(this.privateKeys, privateKeysItem); + } else { + this.publicKeys.push(new OpenPgpKeyModel(armoredKey, key)); + storeOpenPgpKeys(this.publicKeys, publicKeysItem); + } + } + }); + } + + /** + keyPair.privateKey + keyPair.publicKey + keyPair.revocationCertificate + keyPair.onServer + keyPair.inGnuPG + */ + storeKeyPair(keyPair) { + openpgp.readKey({armoredKey:keyPair.publicKey}).then(key => { + this.publicKeys.push(new OpenPgpKeyModel(keyPair.publicKey, key)); + storeOpenPgpKeys(this.publicKeys, publicKeysItem); + }); + openpgp.readKey({armoredKey:keyPair.privateKey}).then(key => { + this.privateKeys.push(new OpenPgpKeyModel(keyPair.privateKey, key)); + storeOpenPgpKeys(this.privateKeys, privateKeysItem); + }); + } + + /** + * Checks if verifying/encrypting a message is possible with given email addresses. + */ + hasPublicKeyForEmails(recipients, all) { + const count = recipients.length, + length = count ? recipients.filter(email => + this.publicKeys().find(key => key.emails.includes(email)) + ).length : 0; + return length && (!all || length === count); + } + + getPrivateKeyFor(query/*, sign*/) { + return findOpenPGPKey(this.privateKeys, query/*, sign*/); + } + + getPublicKeyFor(query/*, sign*/) { + return findOpenPGPKey(this.publicKeys, query/*, sign*/); + } + +/* + decryptMessage(message, recipients, fCallback) { + message = store.openpgp.message.readArmored(armoredMessage); + try { + message = store.openpgp.message.readArmored(armoredMessage); + } catch (e) { + log(e); + } + if (message && message.getText && message.verify && message.decrypt) { + if (message && message.getEncryptionKeyIds) { + // findPrivateKeysByEncryptionKeyIds + const encryptionKeyIds = message.getEncryptionKeyIds(); + let privateKeys = isArray(encryptionKeyIds) + ? encryptionKeyIds.map(id => { + // openpgpKeyring.publicKeys.getForId(id.toHex()) + // openpgpKeyring.privateKeys.getForId(id.toHex()) + const key = id && id.toHex ? findKeyByHex(this.privateKeys, id.toHex()) : null; + return key ? [key] : [null]; + }).flat().filter(v => v) + : []; + if (!privateKeys.length && arrayLength(recipients)) { + privateKeys = recipients.map(sEmail => + (sEmail + ? this.privateKeys.filter(item => item && item.emails.includes(sEmail)) : 0) + || [null] + ).flat().validUnique(key => key.id); + } + + if (privateKeys && privateKeys.length) { + showScreenPopup(OpenPgpSelectorPopupView, [ + (decryptedKey) => { + if (decryptedKey) { + message.decrypt(decryptedKey).then( + (decryptedMessage) => { + let privateKey = null; + if (decryptedMessage) { + privateKey = findKeyByHex(this.privateKeys, decryptedKey.primaryKey.keyid.toHex()); + if (privateKey) { + this.verifyMessage(decryptedMessage, (oValidKey, aSigningKeyIds) => { + fCallback(privateKey, decryptedMessage, oValidKey || null, aSigningKeyIds || null); + }); + } else { + fCallback(privateKey, decryptedMessage); + } + } else { + fCallback(privateKey, decryptedMessage); + } + }, + () => { + fCallback(null, null); + } + ); + } else { + fCallback(null, null); + } + }, + privateKeys + ]); + + return false; + } + } + + fCallback(null, null); + + return false; + } +*/ + + verifyMessage(message, fCallback) { + if (message && message.getSigningKeyIds) { + const signingKeyIds = message.getSigningKeyIds(); + if (signingKeyIds && signingKeyIds.length) { + // findPublicKeysBySigningKeyIds + const publicKeys = signingKeyIds.map(id => { + const key = id && id.toHex ? findKeyByHex(this.publicKeys, id.toHex()) : null; + return key ? key.key : [null]; + }).flat().filter(v => v); + if (publicKeys && publicKeys.length) { + try { + const result = message.verify(publicKeys), + valid = (isArray(result) ? result : []).find(item => item && item.valid && item.keyid); + + if (valid && valid.keyid && valid.keyid && valid.keyid.toHex) { + fCallback(findKeyByHex(this.publicKeys, valid.keyid.toHex())); + return true; + } + } catch (e) { + console.log(e); + } + } + + fCallback(null, signingKeyIds); + return false; + } + } + + fCallback(null); + return false; + } + +}; diff --git a/dev/Stores/User/Pgp.js b/dev/Stores/User/Pgp.js index 1b8ac80e7..8b9068f09 100644 --- a/dev/Stores/User/Pgp.js +++ b/dev/Stores/User/Pgp.js @@ -1,121 +1,17 @@ -import ko from 'ko'; - import { Capa } from 'Common/Enums'; import { doc, createElement, Settings } from 'Common/Globals'; import { staticLink } from 'Common/Links'; -import { isArray, arrayLength } from 'Common/Utils'; -import { delegateRunOnDestroy } from 'Common/UtilsUser'; //import { showScreenPopup } from 'Knoin/Knoin'; //import { EmailModel } from 'Model/Email'; //import { OpenPgpKeyModel } from 'Model/OpenPgpKey'; -import Remote from 'Remote/User/Fetch'; - -import { showScreenPopup } from 'Knoin/Knoin'; -import { OpenPgpKeyPopupView } from 'View/Popup/OpenPgpKey'; - -const - findKeyByHex = (keys, hash) => - keys.find(item => item && (hash === item.id || item.ids.includes(hash))), - - findGnuPGKey = (keys, query, sign) => - keys.find(key => - key[sign ? 'can_sign' : 'can_decrypt'] - && (key.emails.includes(query) || key.subkeys.find(key => query == key.keyid || query == key.fingerprint)) - ), - - findOpenPGPKey = (keys, query/*, sign*/) => - keys.find(key => - key.emails.includes(query) || query == key.id || query == key.fingerprint - ); - -/** - * OpenPGP.js v5 removed the localStorage (keyring) - * This should be compatible with the old OpenPGP.js v2 - */ -const - publicKeysItem = 'openpgp-public-keys', - privateKeysItem = 'openpgp-private-keys', - storage = window.localStorage, - loadOpenPgpKeys = async itemname => { - let keys = [], key, - armoredKeys = JSON.parse(storage.getItem(itemname)), - i = arrayLength(armoredKeys); - while (i--) { - key = await openpgp.readKey({armoredKey:armoredKeys[i]}); - if (!key.err) { - keys.push(new OpenPgpKeyModel(armoredKeys[i], key)); - } - } - return keys; - }, - storeOpenPgpKeys = (keys, section) => { - let armoredKeys = keys.map(item => item.armor); - if (armoredKeys.length) { - storage.setItem(section, JSON.stringify(armoredKeys)); - } else { - storage.removeItem(section); - } - }; - -class OpenPgpKeyModel { - constructor(armor, key) { - this.key = key; - const aEmails = []; - if (key.users) { - key.users.forEach(user => user.userID.email && aEmails.push(user.userID.email)); - } - this.id = key.getKeyID().toHex(); - this.fingerprint = key.getFingerprint(); - this.can_encrypt = !!key.getEncryptionKey(); - this.can_sign = !!key.getSigningKey(); - this.emails = aEmails; - this.armor = armor; - this.askDelete = ko.observable(false); - this.openForDeletion = ko.observable(null).askDeleteHelper(); -// key.getUserIDs() -// key.getPrimaryUser() - } - - view() { - showScreenPopup(OpenPgpKeyPopupView, [this]); - } - - remove() { - if (this.askDelete()) { - if (this.key.isPrivate()) { - PgpUserStore.openpgpPrivateKeys.remove(this); - storeOpenPgpKeys(PgpUserStore.openpgpPrivateKeys, privateKeysItem); - } else { - PgpUserStore.openpgpPublicKeys.remove(this); - storeOpenPgpKeys(PgpUserStore.openpgpPublicKeys, publicKeysItem); - } - delegateRunOnDestroy(this); - } - } -/* - toJSON() { - return this.armor; - } -*/ -} +import { GnuPGUserStore } from 'Stores/User/GnuPG'; +import { OpenPGPUserStore } from 'Stores/User/OpenPGP'; export const PgpUserStore = new class { constructor() { - /** - * PECL gnupg / PEAR Crypt_GPG - * [ {email, can_encrypt, can_sign}, ... ] - */ - this.gnupgKeyring; - this.gnupgPublicKeys = ko.observableArray(); - this.gnupgPrivateKeys = ko.observableArray(); - - // OpenPGP.js - this.openpgpPublicKeys = ko.observableArray(); - this.openpgpPrivateKeys = ko.observableArray(); - // https://mailvelope.github.io/mailvelope/Keyring.html this.mailvelopeKeyring = null; } @@ -155,77 +51,12 @@ export const PgpUserStore = new class { addEventListener('mailvelope', () => this.loadKeyrings(identifier)); } - if (openpgp) { - loadOpenPgpKeys(publicKeysItem).then(keys => { - this.openpgpPublicKeys(keys || []); - console.log('openpgp.js public keys loaded'); - }); - loadOpenPgpKeys(privateKeysItem).then(keys => { - this.openpgpPrivateKeys(keys || []) - console.log('openpgp.js private keys loaded'); - }); + if (OpenPGPUserStore.isSupported()) { + OpenPGPUserStore.loadKeyrings(identifier); } if (Settings.capa(Capa.GnuPG)) { - this.gnupgKeyring = null; - this.gnupgPublicKeys([]); - this.gnupgPrivateKeys([]); - Remote.request('GnupgGetKeys', - (iError, oData) => { - if (oData && oData.Result) { - this.gnupgKeyring = oData.Result; - const initKey = (key, isPrivate) => { - const aEmails = []; - key.id = key.subkeys[0].keyid; - key.fingerprint = key.subkeys[0].fingerprint; - key.uids.forEach(uid => uid.email && aEmails.push(uid.email)); - key.emails = aEmails; - key.askDelete = ko.observable(false); - key.openForDeletion = ko.observable(null).askDeleteHelper(); - key.remove = () => { - if (key.askDelete()) { - Remote.request('GnupgDeleteKey', - (iError, oData) => { - if (oData && oData.Result) { - if (isPrivate) { - PgpUserStore.gnupgPrivateKeys.remove(key); - } else { - PgpUserStore.gnupgPublicKeys.remove(key); - } - delegateRunOnDestroy(key); - } - }, { - KeyId: key.id, - isPrivate: isPrivate - } - ); - } - }; - key.view = () => { - let pass = isPrivate ? prompt('Passphrase') : true; - if (pass) { - Remote.request('GnupgExportKey', - (iError, oData) => { - if (oData && oData.Result) { - key.armor = oData.Result; - showScreenPopup(OpenPgpKeyPopupView, [key]); - } - }, { - KeyId: key.id, - isPrivate: isPrivate, - Passphrase: isPrivate ? pass : '' - } - ); - } - }; - return key; - }; - this.gnupgPublicKeys(oData.Result.public.map(key => initKey(key, 0))); - this.gnupgPrivateKeys(oData.Result.private.map(key => initKey(key, 1))); - console.log('gnupg ready'); - } - } - ); + GnuPGUserStore.loadKeyrings(identifier); } } @@ -233,36 +64,7 @@ export const PgpUserStore = new class { * @returns {boolean} */ isSupported() { - return !!(window.openpgp || window.mailvelope || Settings.capa(Capa.GnuPG)); - } - - openpgpImportKey(armoredKey) { - openpgp && openpgp.readKey({armoredKey:armoredKey}).then(key => { - if (!key.err) { - if (key.isPrivate()) { - this.openpgpPrivateKeys.push(new OpenPgpKeyModel(armoredKey, key)); - storeOpenPgpKeys(this.openpgpPrivateKeys, privateKeysItem); - } else { - this.openpgpPublicKeys.push(new OpenPgpKeyModel(armoredKey, key)); - storeOpenPgpKeys(PgpUserStore.openpgpPublicKeys, publicKeysItem); - } - } - }); - } - - gnupgImportKey(key, callback) { - if (Settings.capa(Capa.GnuPG)) { - Remote.request('GnupgImportKey', - (iError, oData) => { - if (oData && oData.Result) { -// this.gnupgKeyring = oData.Result; - } - callback && callback(iError, oData); - }, { - Key: key - } - ); - } + return !!(OpenPGPUserStore.isSupported() || GnuPGUserStore.isSupported() || window.mailvelope); } /** @@ -273,23 +75,9 @@ export const PgpUserStore = new class { keyPair.inGnuPG */ storeKeyPair(keyPair, callback) { - openpgp.readKey({armoredKey:keyPair.publicKey}).then(key => { - PgpUserStore.openpgpPublicKeys.push(new OpenPgpKeyModel(keyPair.publicKey, key)); - storeOpenPgpKeys(PgpUserStore.openpgpPublicKeys, publicKeysItem); - }); - openpgp.readKey({armoredKey:keyPair.privateKey}).then(key => { - PgpUserStore.openpgpPrivateKeys.push(new OpenPgpKeyModel(keyPair.privateKey, key)); - storeOpenPgpKeys(PgpUserStore.openpgpPrivateKeys, privateKeysItem); - }); + OpenPGPUserStore.isSupported() && OpenPGPUserStore.storeKeyPair(keyPair); // if (Settings.capa(Capa.GnuPG)) { - Remote.request('PgpStoreKeyPair', - (iError, oData) => { - if (oData && oData.Result) { -// this.gnupgKeyring = oData.Result; - } - callback && callback(iError, oData); - }, keyPair - ); + GnuPGUserStore.storeKeyPair(keyPair, callback); } /** @@ -299,18 +87,11 @@ export const PgpUserStore = new class { async hasPublicKeyForEmails(recipients, all) { const count = recipients.length; if (count) { - let length = this.gnupgKeyring && recipients.filter(email => -// (key.can_verify || key.can_encrypt) && - this.gnupgPublicKeys.find(key => key.emails.includes(email)) - ).length; - if (length && (!all || length === count)) { + if (GnuPGUserStore.hasPublicKeyForEmails(recipients, all)) { return 'gnupg'; } - length = recipients.filter(email => - this.openpgpPublicKeys().find(key => key.emails.includes(email)) - ).length; - if (openpgp && (!all || openpgp === count)) { + if (OpenPGPUserStore.hasPublicKeyForEmails(recipients, all)) { return 'openpgp'; } @@ -326,28 +107,14 @@ export const PgpUserStore = new class { } getGnuPGPrivateKeyFor(query, sign) { - let key = findGnuPGKey(this.gnupgPrivateKeys, query, sign); - if (key) { - return ['gnupg', key]; - } - } - - getGnuPGPublicKeyFor(query, sign) { - let key = findGnuPGKey(this.gnupgPublicKeys, query, sign); + let key = GnuPGUserStore.getPrivateKeyFor(query, sign); if (key) { return ['gnupg', key]; } } getOpenPGPPrivateKeyFor(query/*, sign*/) { - let key = findOpenPGPKey(this.openpgpPrivateKeys, query/*, sign*/); - if (key) { - return ['openpgp', key]; - } - } - - getOpenPGPPublicKeyFor(query/*, sign*/) { - let key = findOpenPGPKey(this.openpgpPublicKeys, query/*, sign*/); + let key = OpenPGPUserStore.getPrivateKeyFor(query/*, sign*/); if (key) { return ['openpgp', key]; } @@ -400,6 +167,7 @@ export const PgpUserStore = new class { return key; } } + i = ids.length; while (i--) { key = this.getOpenPGPPrivateKeyFor(ids[i]); @@ -409,104 +177,6 @@ export const PgpUserStore = new class { } } - /** - * OpenPGP.js - */ - -/* - decryptMessage(message, recipients, fCallback) { - if (message && message.getEncryptionKeyIds) { - // findPrivateKeysByEncryptionKeyIds - const encryptionKeyIds = message.getEncryptionKeyIds(); - let privateKeys = isArray(encryptionKeyIds) - ? encryptionKeyIds.map(id => { - // openpgpKeyring.publicKeys.getForId(id.toHex()) - // openpgpKeyring.privateKeys.getForId(id.toHex()) - const key = id && id.toHex ? findKeyByHex(this.openpgpPrivateKeys, id.toHex()) : null; - return key ? [key] : [null]; - }).flat().filter(v => v) - : []; - if (!privateKeys.length && arrayLength(recipients)) { - privateKeys = recipients.map(sEmail => - (sEmail - ? this.openpgpPrivateKeys.filter(item => item && item.emails.includes(sEmail)) : 0) - || [null] - ).flat().validUnique(key => key.id); - } - - if (privateKeys && privateKeys.length) { - showScreenPopup(OpenPgpSelectorPopupView, [ - (decryptedKey) => { - if (decryptedKey) { - message.decrypt(decryptedKey).then( - (decryptedMessage) => { - let privateKey = null; - if (decryptedMessage) { - privateKey = findKeyByHex(this.openpgpPrivateKeys, decryptedKey.primaryKey.keyid.toHex()); - if (privateKey) { - this.verifyMessage(decryptedMessage, (oValidKey, aSigningKeyIds) => { - fCallback(privateKey, decryptedMessage, oValidKey || null, aSigningKeyIds || null); - }); - } else { - fCallback(privateKey, decryptedMessage); - } - } else { - fCallback(privateKey, decryptedMessage); - } - }, - () => { - fCallback(null, null); - } - ); - } else { - fCallback(null, null); - } - }, - privateKeys - ]); - - return false; - } - } - - fCallback(null, null); - - return false; - } -*/ - - verifyMessage(message, fCallback) { - if (message && message.getSigningKeyIds) { - const signingKeyIds = message.getSigningKeyIds(); - if (signingKeyIds && signingKeyIds.length) { - // findPublicKeysBySigningKeyIds - const publicKeys = signingKeyIds.map(id => { - const key = id && id.toHex ? findKeyByHex(this.openpgpPublicKeys, id.toHex()) : null; - return key ? key.key : [null]; - }).flat().filter(v => v); - if (publicKeys && publicKeys.length) { - try { - const result = message.verify(publicKeys), - valid = (isArray(result) ? result : []).find(item => item && item.valid && item.keyid); - - if (valid && valid.keyid && valid.keyid && valid.keyid.toHex) { - fCallback(findKeyByHex(this.openpgpPublicKeys, valid.keyid.toHex())); - return true; - } - } catch (e) { - console.log(e); - } - } - - fCallback(null, signingKeyIds); - return false; - } - } - - fCallback(null); - return false; - } - /** * Creates an iframe with an editor for a new encrypted mail. * The iframe will be injected into the container identified by selector. diff --git a/dev/View/Popup/Compose.js b/dev/View/Popup/Compose.js index 19eb52ae5..62aa1f300 100644 --- a/dev/View/Popup/Compose.js +++ b/dev/View/Popup/Compose.js @@ -29,6 +29,7 @@ import { IdentityUserStore } from 'Stores/User/Identity'; import { AccountUserStore } from 'Stores/User/Account'; import { FolderUserStore } from 'Stores/User/Folder'; import { PgpUserStore } from 'Stores/User/Pgp'; +import { OpenPGPUserStore } from 'Stores/User/OpenPGP'; import { MessageUserStore } from 'Stores/User/Message'; import Remote from 'Remote/User/Fetch'; @@ -458,10 +459,10 @@ class ComposePopupView extends AbstractViewPopup { if ('openpgp' == sign) { let privateKey; try { - const keys = PgpUserStore.getOpenPGPPrivateKeyFor(this.currentIdentity().email()); - if (keys[0]) { - keys[0].decrypt(window.prompt('Passphrase')); - cfg.privateKey = privateKey = keys[0]; + const key = OpenPGPUserStore.getPrivateKeyFor(this.currentIdentity().email()); + if (key) { + key.decrypt(window.prompt('Passphrase')); + cfg.privateKey = privateKey = key; } } catch (e) { console.error(e); @@ -477,7 +478,7 @@ class ComposePopupView extends AbstractViewPopup { // error 'sign and encrypt must be same engine'; } else if ('openpgp' == encrypt) { this.allRecipients().forEach(recEmail => { - cfg.publicKeys = cfg.publicKeys.concat(PgpUserStore.getOpenPGPPublicKeyFor(recEmail)); + cfg.publicKeys = cfg.publicKeys.concat(OpenPGPUserStore.getPublicKeyFor(recEmail)); }); pgpPromise = openpgp.encrypt(cfg); } else if ('openpgp' == sign) { diff --git a/dev/View/Popup/OpenPgpImport.js b/dev/View/Popup/OpenPgpImport.js index 667910208..a4d25bb32 100644 --- a/dev/View/Popup/OpenPgpImport.js +++ b/dev/View/Popup/OpenPgpImport.js @@ -1,10 +1,8 @@ -import { PgpUserStore } from 'Stores/User/Pgp'; +import { GnuPGUserStore } from 'Stores/User/GnuPG'; +import { OpenPGPUserStore } from 'Stores/User/OpenPGP'; import { AbstractViewPopup } from 'Knoin/AbstractViews'; -import { Capa } from 'Common/Enums'; -import { Settings } from 'Common/Globals'; - export class OpenPgpImportPopupView extends AbstractViewPopup { constructor() { super('OpenPgpImport'); @@ -18,7 +16,7 @@ export class OpenPgpImportPopupView extends AbstractViewPopup { saveServer: true }); - this.canGnuPG = Settings.capa(Capa.GnuPG); + this.canGnuPG = GnuPGUserStore.isSupported(); this.key.subscribe(() => { this.keyError(false); @@ -50,16 +48,8 @@ export class OpenPgpImportPopupView extends AbstractViewPopup { match = reg.exec(keyTrimmed); if (match && 0 < count) { if (match[0] && match[1] && match[2] && match[1] === match[2]) { - let err = null; - if (this.saveGnuPG()) { - PgpUserStore.gnupgImportKey(this.key()); - } - PgpUserStore.openpgpImportKey(this.key()); - if (err) { - this.keyError(true); - this.keyErrorMessage(err && err[0] ? '' + err[0] : ''); - console.log(err); - } + this.saveGnuPG() && GnuPGUserStore.isSupported() && GnuPGUserStore.importKey(this.key()); + OpenPGPUserStore.isSupported() && OpenPGPUserStore.importKey(this.key()); } --count;