import ko from 'ko'; import { isArray, arrayLength, pString, addComputablesTo } from 'Common/Utils'; import { AccountUserStore } from 'Stores/User/Account'; import { showScreenPopup } from 'Knoin/Knoin'; import { MessageOpenPgpPopupView } from 'View/Popup/MessageOpenPgp'; export const PgpUserStore = new class { constructor() { this.openpgp = null; this.openpgpkeys = ko.observableArray(); this.openpgpKeyring = null; addComputablesTo(this, { openpgpkeysPublic: () => this.openpgpkeys.filter(item => item && !item.isPrivate), openpgpkeysPrivate: () => this.openpgpkeys.filter(item => item && item.isPrivate) }); } /** * @returns {boolean} */ isSupported() { return !!this.openpgp; } findKeyByHex(keys, hash) { return keys.find(item => hash && item && (hash === item.id || item.ids.includes(hash))); } findPublicKeyByHex(hash) { return this.findKeyByHex(this.openpgpkeysPublic(), hash); } findPrivateKeyByHex(hash) { return this.findKeyByHex(this.openpgpkeysPrivate(), hash); } findPublicKeysByEmail(email) { return this.openpgpkeysPublic().map(item => { const key = item && item.emails.includes(email) ? item : null; return key ? key.getNativeKeys() : [null]; }).flat().filter(v => v); } findPublicKeysBySigningKeyIds(signingKeyIds) { return signingKeyIds.map(id => { const key = id && id.toHex ? this.findPublicKeyByHex(id.toHex()) : null; return key ? key.getNativeKeys() : [null]; }).flat().filter(v => v); } findPrivateKeysByEncryptionKeyIds(encryptionKeyIds, recipients, returnWrapKeys) { let result = isArray(encryptionKeyIds) ? encryptionKeyIds.map(id => { const key = id && id.toHex ? this.findPrivateKeyByHex(id.toHex()) : null; return key ? (returnWrapKeys ? [key] : key.getNativeKeys()) : [null]; }).flat().filter(v => v) : []; if (!result.length && arrayLength(recipients)) { result = recipients.map(sEmail => { const keys = sEmail ? this.findAllPrivateKeysByEmailNotNative(sEmail) : null; return keys ? returnWrapKeys ? keys : keys.map(key => key.getNativeKeys()).flat() : [null]; }).flat().validUnique(key => key.id); } return result; } /** * @param {string} email * @returns {?} */ findPublicKeyByEmailNotNative(email) { return this.openpgpkeysPublic().find(item => item && item.emails.includes(email)) || null; } /** * @param {string} email * @returns {?} */ findPrivateKeyByEmailNotNative(email) { return this.openpgpkeysPrivate().find(item => item && item.emails.includes(email)) || null; } /** * @param {string} email * @returns {?} */ findAllPublicKeysByEmailNotNative(email) { return this.openpgpkeysPublic().filter(item => item && item.emails.includes(email)) || null; } /** * @param {string} email * @returns {?} */ findAllPrivateKeysByEmailNotNative(email) { return this.openpgpkeysPrivate().filter(item => item && item.emails.includes(email)) || null; } /** * @param {string} email * @param {string=} password * @returns {?} */ findPrivateKeyByEmail(email, password) { let privateKey = null; const key = this.openpgpkeysPrivate().find(item => item && item.emails.includes(email)); if (key) { try { privateKey = key.getNativeKeys()[0] || null; if (privateKey) { privateKey.decrypt(pString(password)); } } catch (e) { privateKey = null; } } return privateKey; } /** * @param {string=} password * @returns {?} */ findSelfPrivateKey(password) { return this.findPrivateKeyByEmail(AccountUserStore.email(), password); } decryptMessage(message, recipients, fCallback) { if (message && message.getEncryptionKeyIds) { const privateKeys = this.findPrivateKeysByEncryptionKeyIds(message.getEncryptionKeyIds(), recipients, true); if (privateKeys && privateKeys.length) { showScreenPopup(MessageOpenPgpPopupView, [ (decryptedKey) => { if (decryptedKey) { message.decrypt(decryptedKey).then( (decryptedMessage) => { let privateKey = null; if (decryptedMessage) { privateKey = this.findPrivateKeyByHex(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) { const publicKeys = this.findPublicKeysBySigningKeyIds(signingKeyIds); 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(this.findPublicKeyByHex(valid.keyid.toHex())); return true; } } catch (e) { console.log(e); } } fCallback(null, signingKeyIds); return false; } } fCallback(null); return false; } };