Add OX store implementation

This commit is contained in:
Paul Schaub 2020-06-18 21:52:06 +02:00
parent 13ccdbc6e4
commit 6efd8a1940
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
12 changed files with 424 additions and 118 deletions

View File

@ -44,8 +44,7 @@ import dagger.Component;
ViewModelModule.class,
XmppTcpConnectionFactoryModule.class,
RxMercuryMessageStoreFactoryModule.class,
RxMercuryRosterStoreFactoryModule.class,
OpenPgpModule.class
RxMercuryRosterStoreFactoryModule.class
})
public interface AppComponent {

View File

@ -0,0 +1,11 @@
package org.mercury_im.messenger.data.converter;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
import io.requery.converter.EnumStringConverter;
public class OpenPgpTrustConverter extends EnumStringConverter<OpenPgpTrustStore.Trust> {
public OpenPgpTrustConverter() {
super(OpenPgpTrustStore.Trust.class);
}
}

View File

@ -0,0 +1,36 @@
package org.mercury_im.messenger.data.model;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.data.converter.EntityBareJidConverter;
import org.mercury_im.messenger.data.converter.OpenPgpV4FingerprintConverter;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.util.Date;
import java.util.UUID;
import io.requery.Column;
import io.requery.Convert;
import io.requery.Entity;
import io.requery.Key;
import io.requery.Table;
import io.requery.converter.UUIDConverter;
@Entity
@Table(name = "ox_announced_keys")
public class AbstractAnnouncedOpenPgpContactKey {
@Key
@Convert(UUIDConverter.class)
UUID accountId;
@Key
@Convert(EntityBareJidConverter.class)
EntityBareJid owner;
@Key
@Convert(OpenPgpV4FingerprintConverter.class)
OpenPgpV4Fingerprint fingerprint;
@Column(name = "modification_date", nullable = false)
Date modificationDate;
}

View File

@ -2,26 +2,35 @@ package org.mercury_im.messenger.data.model;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.data.converter.EntityBareJidConverter;
import org.mercury_im.messenger.data.converter.OpenPgpV4FingerprintConverter;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import io.requery.Column;
import io.requery.Convert;
import io.requery.Entity;
import io.requery.Key;
import io.requery.Table;
import io.requery.converter.UUIDConverter;
@Entity
@Table(name = "ox_key_fetch_dates")
public class AbstractOpenPgpKeyFetchDates {
@Table(name = "ox_pubkey_fetchdates")
public class AbstractOpenPgpKeyFetchDate {
@Key
@Convert(UUIDConverter.class)
UUID accountId;
@Key
@Column(name = "owner")
@Convert(EntityBareJidConverter.class)
EntityBareJid owner;
@Column(name = "fetch_dates")
Map<OpenPgpV4Fingerprint, Date> fetchDates;
@Key
@Convert(OpenPgpV4FingerprintConverter.class)
OpenPgpV4Fingerprint fingerprint;
@Column(nullable = false)
Date fetchDate;
}

View File

@ -0,0 +1,36 @@
package org.mercury_im.messenger.data.model;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.data.converter.EntityBareJidConverter;
import org.mercury_im.messenger.data.converter.OpenPgpTrustConverter;
import org.mercury_im.messenger.data.converter.OpenPgpV4FingerprintConverter;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.util.UUID;
import io.requery.Convert;
import io.requery.Entity;
import io.requery.Key;
import io.requery.Table;
import io.requery.converter.UUIDConverter;
@Entity
@Table(name = "ox_key_trust")
public class AbstractOpenPgpKeyTrust {
@Key
@Convert(UUIDConverter.class)
UUID accountId;
@Key
@Convert(EntityBareJidConverter.class)
EntityBareJid owner;
@Key
@Convert(OpenPgpV4FingerprintConverter.class)
OpenPgpV4Fingerprint fingerprint;
@Convert(OpenPgpTrustConverter.class)
OpenPgpTrustStore.Trust trust;
}

View File

@ -3,6 +3,8 @@ package org.mercury_im.messenger.data.model;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.data.converter.EntityBareJidConverter;
import java.util.UUID;
import io.requery.Column;
import io.requery.Convert;
import io.requery.Entity;
@ -13,6 +15,10 @@ import io.requery.Table;
@Table(name = "ox_public_keys")
public class AbstractOpenPgpPublicKeyRing {
@Key
@Column(name = "account_id", nullable = false)
UUID accountId;
@Key
@Column(name = "owner", nullable = false)
@Convert(EntityBareJidConverter.class)

View File

@ -3,6 +3,8 @@ package org.mercury_im.messenger.data.model;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.data.converter.EntityBareJidConverter;
import java.util.UUID;
import io.requery.Column;
import io.requery.Convert;
import io.requery.Entity;
@ -13,6 +15,10 @@ import io.requery.Table;
@Table(name = "ox_secret_keys")
public class AbstractOpenPgpSecretKeyRing {
@Key
@Column(name = "account_id", nullable = false)
UUID accountId;
@Key
@Column(name = "owner", nullable = false)
@Convert(EntityBareJidConverter.class)

View File

@ -2,17 +2,31 @@ package org.mercury_im.messenger.data.repository;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
import org.mercury_im.messenger.data.model.AnnouncedOpenPgpContactKey;
import org.mercury_im.messenger.data.model.OpenPgpKeyFetchDate;
import org.mercury_im.messenger.data.model.OpenPgpKeyTrust;
import org.mercury_im.messenger.data.model.OpenPgpPublicKeyRing;
import org.mercury_im.messenger.data.model.OpenPgpSecretKeyRing;
import org.pgpainless.PGPainless;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import javax.inject.Inject;
import io.reactivex.Completable;
import io.reactivex.Single;
import io.requery.Persistable;
import io.requery.query.ResultDelegate;
import io.requery.reactivex.ReactiveEntityStore;
public class RxOpenPgpRepository implements OpenPgpRepository {
@ -25,9 +39,10 @@ public class RxOpenPgpRepository implements OpenPgpRepository {
}
@Override
public Completable storePublicKeysOf(EntityBareJid owner, PGPPublicKeyRingCollection keys) {
public Completable storePublicKeysOf(UUID accountId, EntityBareJid owner, PGPPublicKeyRingCollection keys) {
return Single.fromCallable(() -> {
OpenPgpPublicKeyRing keyRing = new OpenPgpPublicKeyRing();
keyRing.setAccountId(accountId);
keyRing.setOwner(owner);
keyRing.setBytes(keys.getEncoded());
return keyRing;
@ -35,25 +50,28 @@ public class RxOpenPgpRepository implements OpenPgpRepository {
}
@Override
public Single<PGPPublicKeyRingCollection> loadPublicKeysOf(EntityBareJid owner) {
public Single<PGPPublicKeyRingCollection> loadPublicKeysOf(UUID accountId, EntityBareJid owner) {
return data.select(OpenPgpPublicKeyRing.class)
.where(OpenPgpPublicKeyRing.OWNER.eq(owner))
.where(OpenPgpPublicKeyRing.ACCOUNT_ID.eq(accountId))
.and(OpenPgpPublicKeyRing.OWNER.eq(owner))
.limit(1).get()
.maybe().toSingle()
.map(keyring -> PGPainless.readKeyRing().publicKeyRingCollection(keyring.getBytes()));
}
@Override
public Single<Integer> deletePublicKeysOf(EntityBareJid owner) {
public Single<Integer> deletePublicKeysOf(UUID accountId, EntityBareJid owner) {
return data.delete(OpenPgpPublicKeyRing.class)
.where(OpenPgpPublicKeyRing.OWNER.eq(owner))
.where(OpenPgpPublicKeyRing.ACCOUNT_ID.eq(accountId))
.and(OpenPgpPublicKeyRing.OWNER.eq(owner))
.get().single();
}
@Override
public Completable storeSecretKeysOf(EntityBareJid owner, PGPSecretKeyRingCollection keys) {
public Completable storeSecretKeysOf(UUID accountId, EntityBareJid owner, PGPSecretKeyRingCollection keys) {
return Single.fromCallable(() -> {
OpenPgpSecretKeyRing keyRing = new OpenPgpSecretKeyRing();
keyRing.setAccountId(accountId);
keyRing.setOwner(owner);
keyRing.setBytes(keys.getEncoded());
return keyRing;
@ -61,18 +79,107 @@ public class RxOpenPgpRepository implements OpenPgpRepository {
}
@Override
public Single<PGPSecretKeyRingCollection> loadSecretKeysOf(EntityBareJid owner) {
public Single<PGPSecretKeyRingCollection> loadSecretKeysOf(UUID accountId, EntityBareJid owner) {
return data.select(OpenPgpSecretKeyRing.class)
.where(OpenPgpSecretKeyRing.OWNER.eq(owner))
.where(OpenPgpSecretKeyRing.ACCOUNT_ID.eq(accountId))
.and(OpenPgpSecretKeyRing.OWNER.eq(owner))
.limit(1).get()
.maybe().toSingle()
.map(keyring -> PGPainless.readKeyRing().secretKeyRingCollection(keyring.getBytes()));
}
@Override
public Single<Integer> deleteSecretKeysOf(EntityBareJid owner) {
public Single<Integer> deleteSecretKeysOf(UUID accountId, EntityBareJid owner) {
return data.delete(OpenPgpSecretKeyRing.class)
.where(OpenPgpPublicKeyRing.OWNER.eq(owner))
.where(OpenPgpSecretKeyRing.ACCOUNT_ID.eq(accountId))
.and(OpenPgpSecretKeyRing.OWNER.eq(owner))
.get().single();
}
@Override
public Completable storePublicKeyFetchDates(UUID accountId, EntityBareJid owner, Map<OpenPgpV4Fingerprint, Date> dates) {
List<OpenPgpKeyFetchDate> entities = new LinkedList<>();
for (Map.Entry<OpenPgpV4Fingerprint, Date> entry : dates.entrySet()) {
OpenPgpKeyFetchDate entity = new OpenPgpKeyFetchDate();
entity.setAccountId(accountId);
entity.setOwner(owner);
entity.setFingerprint(entry.getKey());
entity.setFetchDate(entry.getValue());
entities.add(entity);
}
return data.upsert(entities).ignoreElement();
}
@Override
public Completable storeAnnouncedFingerprints(UUID accountId, EntityBareJid owner, Map<OpenPgpV4Fingerprint, Date> metadata) {
List<AnnouncedOpenPgpContactKey> entities = new LinkedList<>();
for (Map.Entry<OpenPgpV4Fingerprint, Date> entry : metadata.entrySet()) {
AnnouncedOpenPgpContactKey entity = new AnnouncedOpenPgpContactKey();
entity.setAccountId(accountId);
entity.setOwner(owner);
entity.setFingerprint(entry.getKey());
entity.setModificationDate(entry.getValue());
entities.add(entity);
}
return data.upsert(entities).ignoreElement();
}
@Override
public Single<Map<OpenPgpV4Fingerprint, Date>> loadAnnouncedFingerprints(UUID accountId, EntityBareJid contact) {
return data.select(AnnouncedOpenPgpContactKey.class)
.where(AnnouncedOpenPgpContactKey.ACCOUNT_ID.eq(accountId))
.and(AnnouncedOpenPgpContactKey.OWNER.eq(contact))
.get()
.observableResult()
.map(ResultDelegate::toList)
.single(Collections.emptyList())
.map(list -> {
Map<OpenPgpV4Fingerprint, Date> map = new ConcurrentHashMap<>();
for (AnnouncedOpenPgpContactKey key : list) {
map.put(key.getFingerprint(), key.getModificationDate());
}
return map;
});
}
@Override
public Single<OpenPgpTrustStore.Trust> loadTrust(UUID accountId, EntityBareJid owner, OpenPgpV4Fingerprint fingerprint) {
return data.select(OpenPgpKeyTrust.class)
.where(OpenPgpKeyTrust.ACCOUNT_ID.eq(accountId))
.and(OpenPgpKeyTrust.OWNER.eq(owner))
.and(OpenPgpKeyTrust.FINGERPRINT.eq(fingerprint))
.limit(1)
.get()
.maybe()
.toSingle(new OpenPgpKeyTrust())
.map(entity -> entity.getTrust() != null ? entity.getTrust() : OpenPgpTrustStore.Trust.undecided);
}
@Override
public Completable storeTrust(UUID accountId, EntityBareJid owner, OpenPgpV4Fingerprint fingerprint, OpenPgpTrustStore.Trust trust) {
OpenPgpKeyTrust entity = new OpenPgpKeyTrust();
entity.setAccountId(accountId);
entity.setOwner(owner);
entity.setFingerprint(fingerprint);
entity.setTrust(trust);
return data.upsert(entity).ignoreElement();
}
@Override
public Single<Map<OpenPgpV4Fingerprint, Date>> loadPublicKeyFetchDates(UUID accountId, EntityBareJid owner) {
return data.select(OpenPgpKeyFetchDate.class)
.where(OpenPgpKeyFetchDate.ACCOUNT_ID.eq(accountId))
.and(OpenPgpKeyFetchDate.OWNER.eq(owner))
.get()
.observableResult()
.map(ResultDelegate::toList)
.single(Collections.emptyList())
.map(list -> {
Map<OpenPgpV4Fingerprint, Date> map = new ConcurrentHashMap<>();
for (OpenPgpKeyFetchDate date : list) {
map.put(date.getFingerprint(), date.getFetchDate());
}
return map;
});
}
}

View File

@ -4,10 +4,15 @@ import org.jivesoftware.smack.AbstractConnectionListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smackx.ox.OpenPgpManager;
import org.jivesoftware.smackx.ox.crypto.OpenPgpProvider;
import org.jivesoftware.smackx.ox.crypto.PainlessOpenPgpProvider;
import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException;
import org.jivesoftware.smackx.ox.exception.NoBackupFoundException;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore;
import org.jivesoftware.smackx.ox_im.OXInstantMessagingManager;
import org.jivesoftware.smackx.pubsub.PubSubException;
import org.mercury_im.messenger.core.SchedulersFacade;
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
import org.mercury_im.messenger.core.store.crypto.MercuryOpenPgpStore;
import org.mercury_im.messenger.core.xmpp.MercuryConnection;
import java.util.logging.Level;
@ -19,11 +24,13 @@ public class MercuryOpenPgpManager {
private static final Logger LOGGER = Logger.getLogger(MercuryOpenPgpManager.class.getName());
private final OpenPgpProvider openPgpProvider;
private final OpenPgpRepository openPgpRepository;
private final SchedulersFacade schedulers;
@Inject
public MercuryOpenPgpManager(OpenPgpProvider openPgpProvider) {
this.openPgpProvider = openPgpProvider;
public MercuryOpenPgpManager(OpenPgpRepository openPgpRepository, SchedulersFacade schedulers) {
this.openPgpRepository = openPgpRepository;
this.schedulers = schedulers;
}
public void initialize(MercuryConnection connection) {
@ -42,14 +49,17 @@ public class MercuryOpenPgpManager {
}
private void setup(MercuryConnection connection) {
OpenPgpStore store = new MercuryOpenPgpStore(connection.getAccountId(), openPgpRepository, schedulers);
OpenPgpProvider provider = new PainlessOpenPgpProvider(store);
try {
OpenPgpManager oxManager = OpenPgpManager.getInstanceFor(connection.getConnection());
oxManager.setOpenPgpProvider(openPgpProvider);
oxManager.setOpenPgpProvider(provider);
if (!oxManager.hasSecretKeysAvailable()) {
try {
oxManager.restoreSecretKeyServerBackup(
//() -> "RW8X-367S-A2C3-QYAL-VG6E-Z2IM");
() -> "KISJ-5Z1T-FGDW-WMDK-SC2U-SQUA");
//() -> "KISJ-5Z1T-FGDW-WMDK-SC2U-SQUA");
() -> "71ZA-Y416-UA7A-7NCE-3SNM-88EF");
LOGGER.log(Level.INFO, "Successfully restored secret key backup!");
} catch (NoBackupFoundException | PubSubException.NotALeafNodeException | InvalidBackupCodeException e) {
LOGGER.log(Level.INFO, "Error restoring secret key backup.", e);

View File

@ -2,22 +2,40 @@ package org.mercury_im.messenger.core.data.repository;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
import org.jxmpp.jid.EntityBareJid;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import io.reactivex.Completable;
import io.reactivex.Single;
public interface OpenPgpRepository {
Completable storePublicKeysOf(EntityBareJid owner, PGPPublicKeyRingCollection keys);
Completable storePublicKeysOf(UUID accountId, EntityBareJid owner, PGPPublicKeyRingCollection keys);
Single<PGPPublicKeyRingCollection> loadPublicKeysOf(EntityBareJid owner);
Single<PGPPublicKeyRingCollection> loadPublicKeysOf(UUID accountId, EntityBareJid owner);
Single<Integer> deletePublicKeysOf(EntityBareJid owner);
Single<Integer> deletePublicKeysOf(UUID accountId, EntityBareJid owner);
Completable storeSecretKeysOf(EntityBareJid owner, PGPSecretKeyRingCollection keys);
Completable storeSecretKeysOf(UUID accountId, EntityBareJid owner, PGPSecretKeyRingCollection keys);
Single<PGPSecretKeyRingCollection> loadSecretKeysOf(EntityBareJid owner);
Single<PGPSecretKeyRingCollection> loadSecretKeysOf(UUID accountId, EntityBareJid owner);
Single<Integer> deleteSecretKeysOf(EntityBareJid owner);
Single<Integer> deleteSecretKeysOf(UUID accountId, EntityBareJid owner);
Completable storePublicKeyFetchDates(UUID accountId, EntityBareJid owner, Map<OpenPgpV4Fingerprint, Date> dates);
Single<Map<OpenPgpV4Fingerprint, Date>> loadPublicKeyFetchDates(UUID accountId, EntityBareJid owner);
Completable storeAnnouncedFingerprints(UUID accountId, EntityBareJid owner, Map<OpenPgpV4Fingerprint, Date> metadata);
Single<Map<OpenPgpV4Fingerprint, Date>> loadAnnouncedFingerprints(UUID accountId, EntityBareJid contact);
Single<OpenPgpTrustStore.Trust> loadTrust(UUID accountId, EntityBareJid owner, OpenPgpV4Fingerprint fingerprint);
Completable storeTrust(UUID accountId, EntityBareJid owner, OpenPgpV4Fingerprint fingerprint, OpenPgpTrustStore.Trust trust);
}

View File

@ -1,29 +1,8 @@
package org.mercury_im.messenger.core.di.module;
import org.jivesoftware.smackx.ox.crypto.OpenPgpProvider;
import org.jivesoftware.smackx.ox.crypto.PainlessOpenPgpProvider;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore;
import org.mercury_im.messenger.core.SchedulersFacade;
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
import org.mercury_im.messenger.core.store.crypto.MercuryOpenPgpStore;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class OpenPgpModule {
@Provides
@Singleton
static OpenPgpStore provideOpenPgpStore(OpenPgpRepository openPgpRepository, SchedulersFacade schedulersFacade) {
return new MercuryOpenPgpStore(openPgpRepository, schedulersFacade);
}
@Provides
@Singleton
static OpenPgpProvider provideOpenPgpProvider(OpenPgpStore openPgpStore) {
return new PainlessOpenPgpProvider(openPgpStore);
}
}

View File

@ -14,93 +14,182 @@ import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.inject.Inject;
import io.reactivex.disposables.CompositeDisposable;
public class MercuryOpenPgpStore extends AbstractOpenPgpStore {
private final OpenPgpRepository repository;
private final SchedulersFacade schedulers;
protected static final Logger LOGGER = Logger.getLogger(MercuryOpenPgpStore.class.getName());
@Inject
public MercuryOpenPgpStore(OpenPgpRepository repository, SchedulersFacade schedulers) {
super(new AbstractOpenPgpKeyStore() {
@Override
protected PGPPublicKeyRingCollection readPublicKeysOf(BareJid owner)
throws IOException, PGPException {
try {
return repository.loadPublicKeysOf(owner.asEntityBareJidIfPossible())
.blockingGet();
} catch (NoSuchElementException e) {
return null;
}
}
public MercuryOpenPgpStore(UUID accountId, OpenPgpRepository repository, SchedulersFacade schedulers) {
super(
new KeyStore(accountId, repository, schedulers),
new MetadataStore(accountId, repository, schedulers),
new TrustStore(accountId, repository, schedulers));
}
@Override
protected void writePublicKeysOf(BareJid owner, PGPPublicKeyRingCollection publicKeys)
throws IOException {
repository.storePublicKeysOf(owner.asEntityBareJidIfPossible(), publicKeys)
.subscribeOn(schedulers.getIoScheduler()).subscribe();
}
private static class KeyStore extends AbstractOpenPgpKeyStore {
@Override
protected PGPSecretKeyRingCollection readSecretKeysOf(BareJid owner)
throws IOException, PGPException {
try {
return repository.loadSecretKeysOf(owner.asEntityBareJidIfPossible())
.blockingGet();
} catch (NoSuchElementException e) {
return null;
}
}
private final CompositeDisposable disposable = new CompositeDisposable();
private final OpenPgpRepository repository;
private final SchedulersFacade schedulers;
@Override
protected void writeSecretKeysOf(BareJid owner, PGPSecretKeyRingCollection secretKeys)
throws IOException {
repository.storeSecretKeysOf(owner.asEntityBareJidIfPossible(), secretKeys)
.subscribeOn(schedulers.getIoScheduler()).subscribe();
}
private final UUID accountId;
@Override
protected Map<OpenPgpV4Fingerprint, Date> readKeyFetchDates(BareJid owner)
throws IOException {
return new HashMap<>();
}
@Override
protected void writeKeyFetchDates(BareJid owner, Map<OpenPgpV4Fingerprint, Date> dates)
throws IOException {
public KeyStore(UUID accountId, OpenPgpRepository repository, SchedulersFacade schedulers) {
this.accountId = accountId;
this.repository = repository;
this.schedulers = schedulers;
}
}
}, new AbstractOpenPgpMetadataStore() {
@Override
protected Map<OpenPgpV4Fingerprint, Date> readAnnouncedFingerprintsOf(BareJid contact)
throws IOException {
@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 writeAnnouncedFingerprintsOf(BareJid contact, Map<OpenPgpV4Fingerprint, Date> metadata)
throws IOException {
@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;
}
}, new AbstractOpenPgpTrustStore() {
@Override
protected Trust readTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint)
throws IOException {
return Trust.trusted;
}
}
@Override
protected void writeTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint, Trust trust)
throws IOException {
@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 + ")")
));
}
}
});
this.repository = repository;
this.schedulers = schedulers;
@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();
}
}
private 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 OpenPgpRepository repository;
private final SchedulersFacade schedulers;
private final UUID accountId;
public TrustStore(UUID accountId, OpenPgpRepository 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();
}
}
}