Add OX store implementation
This commit is contained in:
parent
13ccdbc6e4
commit
6efd8a1940
|
@ -44,8 +44,7 @@ import dagger.Component;
|
|||
ViewModelModule.class,
|
||||
XmppTcpConnectionFactoryModule.class,
|
||||
RxMercuryMessageStoreFactoryModule.class,
|
||||
RxMercuryRosterStoreFactoryModule.class,
|
||||
OpenPgpModule.class
|
||||
RxMercuryRosterStoreFactoryModule.class
|
||||
})
|
||||
public interface AppComponent {
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue