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

204 lines
9.1 KiB
Java

package org.mercury_im.messenger.core.store.crypto;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.jivesoftware.smackx.ox.store.abstr.AbstractOpenPgpKeyStore;
import org.jivesoftware.smackx.ox.store.abstr.AbstractOpenPgpMetadataStore;
import org.jivesoftware.smackx.ox.store.abstr.AbstractOpenPgpStore;
import org.jivesoftware.smackx.ox.store.abstr.AbstractOpenPgpTrustStore;
import org.jxmpp.jid.BareJid;
import org.mercury_im.messenger.core.SchedulersFacade;
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.Date;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import io.reactivex.disposables.CompositeDisposable;
public class MercuryOpenPgpStore extends AbstractOpenPgpStore {
protected static final Logger LOGGER = Logger.getLogger(MercuryOpenPgpStore.class.getName());
public MercuryOpenPgpStore(UUID accountId, OpenPgpRepository repository, OpenPgpTrustRepository trustRepository, SchedulersFacade schedulers) {
this(
new KeyStore(accountId, repository, schedulers),
new MetadataStore(accountId, repository, schedulers),
new TrustStore(accountId, trustRepository, schedulers));
}
public MercuryOpenPgpStore(AbstractOpenPgpKeyStore keyStore,
AbstractOpenPgpMetadataStore metadataStore,
AbstractOpenPgpTrustStore trustStore) {
super(keyStore, metadataStore, trustStore);
}
public static class KeyStore extends AbstractOpenPgpKeyStore {
private final CompositeDisposable disposable = new CompositeDisposable();
private final OpenPgpRepository repository;
private final SchedulersFacade schedulers;
private final UUID accountId;
public KeyStore(UUID accountId, OpenPgpRepository repository, SchedulersFacade schedulers) {
this.accountId = accountId;
this.repository = repository;
this.schedulers = schedulers;
}
@Override
protected PGPPublicKeyRingCollection readPublicKeysOf(BareJid owner)
throws IOException, PGPException {
try {
return repository.loadPublicKeysOf(accountId, owner.asEntityBareJidIfPossible())
.blockingGet();
} catch (NoSuchElementException e) {
return null;
}
}
@Override
protected void writePublicKeysOf(BareJid owner, PGPPublicKeyRingCollection publicKeys)
throws IOException {
disposable.add(repository.storePublicKeysOf(accountId, owner.asEntityBareJidIfPossible(), publicKeys)
.subscribeOn(schedulers.getIoScheduler())
.subscribe(
() -> MercuryOpenPgpStore.LOGGER.log(Level.FINER, "Successfully wrote OX public keys for " + owner + " (accountId=" + accountId + ")"),
e -> MercuryOpenPgpStore.LOGGER.log(Level.SEVERE, "Error writing OX public keys for " + owner + " (accountId=" + accountId + ")")
));
}
@Override
protected PGPSecretKeyRingCollection readSecretKeysOf(BareJid owner)
throws IOException, PGPException {
try {
return repository.loadSecretKeysOf(accountId, owner.asEntityBareJidIfPossible())
.blockingGet();
} catch (NoSuchElementException e) {
return null;
}
}
@Override
protected void writeSecretKeysOf(BareJid owner, PGPSecretKeyRingCollection secretKeys)
throws IOException {
disposable.add(repository.storeSecretKeysOf(accountId, owner.asEntityBareJidIfPossible(), secretKeys)
.subscribeOn(schedulers.getIoScheduler())
.subscribe(
() -> MercuryOpenPgpStore.LOGGER.log(Level.FINER, "Successfully wrote OX secret keys for " + owner + " (accountId=" + accountId + ")"),
e -> MercuryOpenPgpStore.LOGGER.log(Level.SEVERE, "Error writing OX secret keys for " + owner + " (accountId=" + accountId + ")")
));
}
@Override
protected Map<OpenPgpV4Fingerprint, Date> readKeyFetchDates(BareJid owner)
throws IOException {
return repository.loadPublicKeyFetchDates(accountId, owner.asEntityBareJidIfPossible())
.blockingGet();
}
@Override
protected void writeKeyFetchDates(BareJid owner, Map<OpenPgpV4Fingerprint, Date> dates)
throws IOException {
disposable.add(repository.storePublicKeyFetchDates(accountId, owner.asEntityBareJidIfPossible(), dates)
.subscribeOn(schedulers.getIoScheduler())
.subscribe(
() -> MercuryOpenPgpStore.LOGGER.log(Level.FINER, "Successfully updated OX fetch dates for " + owner + " (accountId=" + accountId + ")"),
e -> MercuryOpenPgpStore.LOGGER.log(Level.SEVERE, "Error updating OX key fetch dates for " + owner + " (accountId=" + accountId + ")")
));
}
@Override
protected void finalize() throws Throwable {
disposable.dispose();
super.finalize();
}
}
public static class MetadataStore extends AbstractOpenPgpMetadataStore {
private final CompositeDisposable disposable = new CompositeDisposable();
private final OpenPgpRepository repository;
private final SchedulersFacade schedulers;
private final UUID accountId;
public MetadataStore(UUID accountId, OpenPgpRepository repository, SchedulersFacade schedulers) {
this.accountId = accountId;
this.repository = repository;
this.schedulers = schedulers;
}
@Override
protected Map<OpenPgpV4Fingerprint, Date> readAnnouncedFingerprintsOf(BareJid contact)
throws IOException {
return repository.loadAnnouncedFingerprints(accountId, contact.asEntityBareJidIfPossible())
.blockingGet();
}
@Override
protected void writeAnnouncedFingerprintsOf(BareJid contact, Map<OpenPgpV4Fingerprint, Date> metadata)
throws IOException {
disposable.add(
repository.storeAnnouncedFingerprints(accountId, contact.asEntityBareJidIfPossible(), metadata)
.subscribeOn(schedulers.getIoScheduler())
.subscribe(
() -> MercuryOpenPgpStore.LOGGER.log(Level.FINER, "Successfully updated announced OX fingerprints for " + contact + " (accountId=" + accountId + ")"),
e -> MercuryOpenPgpStore.LOGGER.log(Level.SEVERE, "Error updating announced OX fingerprints for " + contact + " (accountId=" + accountId + ")")
));
}
@Override
protected void finalize() throws Throwable {
disposable.dispose();
super.finalize();
}
}
public static class TrustStore extends AbstractOpenPgpTrustStore {
private final CompositeDisposable disposable = new CompositeDisposable();
private final OpenPgpTrustRepository repository;
private final SchedulersFacade schedulers;
private final UUID accountId;
public TrustStore(UUID accountId, OpenPgpTrustRepository repository, SchedulersFacade schedulers) {
this.accountId = accountId;
this.repository = repository;
this.schedulers = schedulers;
}
@Override
protected Trust readTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException {
return repository.loadTrust(accountId, owner.asEntityBareJidIfPossible(), fingerprint)
.blockingGet();
}
@Override
protected void writeTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint, Trust trust) throws IOException {
disposable.add(repository.storeTrust(accountId, owner.asEntityBareJidIfPossible(), fingerprint, trust)
.subscribeOn(schedulers.getIoScheduler())
.subscribe(
() -> MercuryOpenPgpStore.LOGGER.log(Level.FINER, "Successfully set trust in key " + fingerprint + " to " + trust + " for " + owner + " (accountId=" + accountId + ")"),
e -> MercuryOpenPgpStore.LOGGER.log(Level.SEVERE, "Error setting trust in key " + fingerprint + " to " + trust + " for " + owner + " (accountId=" + accountId + ")")
));
}
@Override
protected void finalize() throws Throwable {
disposable.dispose();
super.finalize();
}
}
}