Mercury-IM/domain/src/main/java/org/mercury_im/messenger/core/store/crypto/IkeyAwareOpenPgpStore.java

107 lines
5.5 KiB
Java

package org.mercury_im.messenger.core.store.crypto;
import org.jivesoftware.smackx.ikey.record.IkeyRecord;
import org.jivesoftware.smackx.ox.store.abstr.AbstractOpenPgpTrustStore;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.core.SchedulersFacade;
import org.mercury_im.messenger.core.crypto.ikey.IkeyRepository;
import org.mercury_im.messenger.core.data.repository.IkeyKeyRepository;
import org.mercury_im.messenger.core.data.repository.IkeyRecordRepository;
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
import org.mercury_im.messenger.core.data.repository.OpenPgpTrustRepository;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.io.IOException;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import io.reactivex.Completable;
import io.reactivex.Maybe;
import io.reactivex.Single;
import io.reactivex.disposables.CompositeDisposable;
public class IkeyAwareOpenPgpStore extends MercuryOpenPgpStore {
public IkeyAwareOpenPgpStore(UUID accountId,
OpenPgpRepository openPgpRepository,
OpenPgpTrustRepository openPgpTrustRepository,
IkeyRepository ikeyRepository,
SchedulersFacade schedulersFacade) {
this(accountId, openPgpRepository, openPgpTrustRepository, ikeyRepository, ikeyRepository, schedulersFacade);
}
public IkeyAwareOpenPgpStore(UUID accountId,
OpenPgpRepository openPgpRepository,
OpenPgpTrustRepository openPgpTrustRepository,
IkeyKeyRepository ikeyKeyRepository,
IkeyRecordRepository ikeyRecordRepository,
SchedulersFacade schedulers) {
super(new KeyStore(accountId, openPgpRepository, schedulers),
new MetadataStore(accountId, openPgpRepository, schedulers),
new TrustStore(accountId, openPgpTrustRepository, ikeyKeyRepository, ikeyRecordRepository, schedulers));
}
public static class TrustStore extends AbstractOpenPgpTrustStore {
private static final Logger LOGGER = Logger.getLogger(TrustStore.class.getName());
private final UUID accountId;
private final OpenPgpTrustRepository openPgpTrustRepository;
private final IkeyKeyRepository ikeyKeyRepository;
private final IkeyRecordRepository ikeyRecordRepository;
private final SchedulersFacade schedulers;
private final CompositeDisposable disposable = new CompositeDisposable();
public TrustStore(UUID accountId, OpenPgpTrustRepository openPgpTrustRepository, IkeyKeyRepository ikeyKeyRepository, IkeyRecordRepository ikeyRecordRepository, SchedulersFacade schedulersFacade) {
this.accountId = accountId;
this.openPgpTrustRepository = openPgpTrustRepository;
this.ikeyKeyRepository = ikeyKeyRepository;
this.ikeyRecordRepository = ikeyRecordRepository;
this.schedulers = schedulersFacade;
}
@Override
protected Trust readTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException {
EntityBareJid jid = owner.asEntityBareJidOrThrow();
Trust trust = readIkeyTrust(jid, fingerprint)
.blockingGet();
return trust == null ? Trust.undecided : trust;
}
private Single<Trust> readIkeyTrust(EntityBareJid owner, OpenPgpV4Fingerprint fingerprint) {
return ikeyRecordRepository.loadRecord(accountId, owner)
.filter(record -> record.getTrust() == Trust.trusted)
.filter(record -> record.hasSubordinate(fingerprint))
.map(IkeyRecord::getTrust)
.map(trust -> trust == Trust.trusted ? Trust.ikey_trusted : trust)
.firstElement()
.flatMap(t -> t == Trust.undecided ? readManualTrust(owner, fingerprint).toMaybe() : Maybe.just(t))
.switchIfEmpty(readManualTrust(owner, fingerprint));
}
private Single<Trust> readManualTrust(EntityBareJid owner, OpenPgpV4Fingerprint fingerprint) {
return openPgpTrustRepository.loadTrust(accountId, owner, fingerprint)
.doOnSuccess(trust -> LOGGER.log(Level.INFO, "Read manual trust " + trust + " for device key " + fingerprint + " of contact " + owner));
}
private Completable writeManualTrust(EntityBareJid owner, OpenPgpV4Fingerprint fingerprint, Trust trust) {
return openPgpTrustRepository.storeTrust(accountId, owner.asEntityBareJidIfPossible(), fingerprint, trust)
.doOnComplete(() -> LOGGER.log(Level.INFO,
"Successfully marked device key " + fingerprint + " of " + owner + " as " + trust));
}
@Override
protected void writeTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint, Trust trust) throws IOException {
EntityBareJid jid = owner.asEntityBareJidOrThrow();
disposable.add(
writeManualTrust(jid, fingerprint, trust)
.compose(schedulers.executeUiSafeCompletable())
.subscribe(() -> {},
e -> LOGGER.log(Level.SEVERE, "An error happened while marking device key " + fingerprint + " of " + jid + " as " + trust, e)));
}
}
}