Mercury-IM/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/account/detail/AccountDetailsViewModel.java

159 lines
7.5 KiB
Java

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<EntityBareJid> getJid(UUID accountId) {
return accountRepository.getAccount(accountId).toSingle()
.compose(schedulers.executeUiSafeSingle())
.map(Account::getJid);
}
public Observable<Optional<OpenPgpV4Fingerprint>> observeIkeyFingerprint(UUID accountId) {
return ikeyRepository.loadSecretKey(accountId)
.map(key -> key.isPresent() ? new Optional<>(new OpenPgpV4Fingerprint(key.getItem().getPublicKey())) : new Optional<>());
}
public Observable<Optional<OpenPgpV4Fingerprint>> observeLocalFingerprint(UUID accountId) {
return openPgpRepository.observeLocalFingerprintOf(accountId);
}
public Observable<List<FingerprintViewItem>> 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<FingerprintViewItem> 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();
});
}
}