Split OpenPGP.js and GnuPG from PgpUserStore

This commit is contained in:
the-djmaze 2022-01-30 02:35:53 +01:00
parent 76226f45ca
commit 76361a13da
6 changed files with 453 additions and 369 deletions

View file

@ -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;

154
dev/Stores/User/GnuPG.js Normal file
View file

@ -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);
}
};

268
dev/Stores/User/OpenPGP.js Normal file
View file

@ -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;
}
};

View file

@ -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.

View file

@ -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) {

View file

@ -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;