package org.mercury_im.messenger.core.viewmodel.account.detail; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smackx.ikey.IkeyManager; import org.jivesoftware.smackx.ox.element.PublicKeysListElement; import org.jivesoftware.smackx.ox.element.SecretkeyElement; import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore; import org.jivesoftware.smackx.ox.util.OpenPgpPubSubUtil; import org.jivesoftware.smackx.pep.PepManager; import org.jivesoftware.smackx.pubsub.LeafNode; import org.jivesoftware.smackx.pubsub.PayloadItem; import org.jivesoftware.smackx.pubsub.PubSubManager; import org.jxmpp.jid.EntityBareJid; import org.mercury_im.messenger.core.SchedulersFacade; import org.mercury_im.messenger.core.connection.MercuryConnection; import org.mercury_im.messenger.core.connection.MercuryConnectionManager; import org.mercury_im.messenger.core.crypto.ikey.IkeyInitializer; import org.mercury_im.messenger.core.crypto.ikey.IkeyRepository; import org.mercury_im.messenger.core.data.repository.AccountRepository; import org.mercury_im.messenger.core.data.repository.OpenPgpRepository; import org.mercury_im.messenger.core.util.Optional; import org.mercury_im.messenger.core.viewmodel.MercuryViewModel; import org.mercury_im.messenger.core.viewmodel.openpgp.FingerprintViewItem; import org.mercury_im.messenger.entity.Account; import org.pgpainless.key.OpenPgpV4Fingerprint; import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; import javax.inject.Inject; import io.reactivex.Completable; import io.reactivex.Observable; import io.reactivex.Single; import io.reactivex.disposables.Disposable; import static org.jivesoftware.smackx.ox.util.OpenPgpPubSubUtil.PEP_NODE_PUBLIC_KEYS; public class AccountDetailsViewModel implements MercuryViewModel { private MercuryConnectionManager connectionManager; private final OpenPgpRepository openPgpRepository; private final IkeyRepository ikeyRepository; private final AccountRepository accountRepository; private final SchedulersFacade schedulers; private final IkeyInitializer ikeyInitializer; @Inject public AccountDetailsViewModel(MercuryConnectionManager connectionManager, OpenPgpRepository openPgpRepository, IkeyRepository ikeyRepository, AccountRepository accountRepository, SchedulersFacade schedulers, IkeyInitializer ikeyInitializer) { this.connectionManager = connectionManager; this.openPgpRepository = openPgpRepository; this.ikeyRepository = ikeyRepository; this.accountRepository = accountRepository; this.schedulers = schedulers; this.ikeyInitializer = ikeyInitializer; } public void markFingerprintTrusted(UUID accountId, OpenPgpV4Fingerprint fingerprint, boolean trusted) { addDisposable(openPgpRepository.storeTrust(accountId, fingerprint, trusted ? OpenPgpTrustStore.Trust.trusted : OpenPgpTrustStore.Trust.untrusted) .compose(schedulers.executeUiSafeCompletable()) .subscribe()); } public Single getJid(UUID accountId) { return accountRepository.getAccount(accountId).toSingle() .compose(schedulers.executeUiSafeSingle()) .map(Account::getJid); } public Observable> observeIkeyFingerprint(UUID accountId) { return ikeyRepository.loadSecretKey(accountId) .map(key -> key.isPresent() ? new Optional<>(new OpenPgpV4Fingerprint(key.getItem().getPublicKey())) : new Optional<>()); } public Observable> observeLocalFingerprint(UUID accountId) { return openPgpRepository.observeLocalFingerprintOf(accountId); } public Observable> observeRemoteFingerprints(UUID accountId) { return observeLocalFingerprint(accountId) .flatMap(optional -> accountRepository.getAccount(accountId).toSingle() .flatMapObservable(account -> openPgpRepository.observeFingerprints(accountId, account.getJid()) .map(list -> { if (!optional.isPresent()) { return list; } List remoteFingerprints = new ArrayList<>(); for(FingerprintViewItem f : list) { if (!f.getFingerprint().equals(optional.getItem())) { remoteFingerprints.add(f); } } return remoteFingerprints; }))); } public Completable unpublishPublicKey(UUID accountId, OpenPgpV4Fingerprint fingerprint) { return deletePublicKeyNode(accountId, fingerprint) .andThen(removePublicKeyFromPubKeyList(accountId, fingerprint)); } private Completable removePublicKeyFromPubKeyList(UUID accountId, OpenPgpV4Fingerprint fingerprint) { return Completable.fromAction(() -> { XMPPConnection xmppConnection = connectionManager.getConnection(accountId).getConnection(); PepManager pepManager = PepManager.getInstanceFor(xmppConnection); PubSubManager pubSubManager = pepManager.getPepPubSubManager(); PublicKeysListElement publishedKeys = OpenPgpPubSubUtil.fetchPubkeysList(xmppConnection); PublicKeysListElement.Builder builder = PublicKeysListElement.builder(); for (PublicKeysListElement.PubkeyMetadataElement meta : publishedKeys.getMetadata().values()) { if (meta.getV4Fingerprint().equals(fingerprint)) { continue; } builder.addMetadata(meta); } publishedKeys = builder.build(); LeafNode metadataNode = pubSubManager.getOrCreateLeafNode(PEP_NODE_PUBLIC_KEYS); metadataNode.publish(new PayloadItem<>(publishedKeys)); }); } private Completable deletePublicKeyNode(UUID accountId, OpenPgpV4Fingerprint fingerprint) { return Completable.fromAction(() -> { XMPPConnection xmppConnection = connectionManager.getConnection(accountId).getConnection(); PepManager pepManager = PepManager.getInstanceFor(xmppConnection); OpenPgpPubSubUtil.deletePublicKeyNode(pepManager, fingerprint); }); } public Completable generateIkey(UUID accountId) { return Completable.fromAction(() -> { MercuryConnection connection = connectionManager.getConnection(accountId); IkeyManager ikeyManager = ikeyInitializer.initFor(connection); ikeyManager.generateIdentityKey(); }); } public Completable deleteIkey(UUID accountId) { return ikeyRepository.deleteSecretKey(accountId).ignoreElement(); } public Completable restoreIkeyBackup(UUID accountId) { return Completable.fromAction(() -> { MercuryConnection connection = connectionManager.getConnection(accountId); IkeyManager ikeyManager = ikeyInitializer.initFor(connection); SecretkeyElement secretkeyElement = ikeyManager.fetchSecretIdentityKey(); }); } }