Mercury-IM/data/src/main/java/org/mercury_im/messenger/data/repository/RxOpenPgpRepository.java

220 lines
9.8 KiB
Java
Raw Normal View History

2020-06-13 19:14:38 +02:00
package org.mercury_im.messenger.data.repository;
2020-06-26 16:00:47 +02:00
import org.bouncycastle.openpgp.PGPPublicKeyRing;
2020-06-13 19:14:38 +02:00
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
2020-06-15 17:41:13 +02:00
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
2020-06-18 21:52:06 +02:00
import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
2020-06-13 19:14:38 +02:00
import org.jxmpp.jid.EntityBareJid;
2020-06-26 16:00:47 +02:00
import org.jxmpp.jid.impl.JidCreate;
2020-06-13 19:14:38 +02:00
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
2020-06-18 21:52:06 +02:00
import org.mercury_im.messenger.data.model.AnnouncedOpenPgpContactKey;
import org.mercury_im.messenger.data.model.OpenPgpKeyFetchDate;
import org.mercury_im.messenger.data.model.OpenPgpKeyTrust;
2020-06-13 19:14:38 +02:00
import org.mercury_im.messenger.data.model.OpenPgpPublicKeyRing;
import org.mercury_im.messenger.data.model.OpenPgpSecretKeyRing;
import org.pgpainless.PGPainless;
2020-06-18 21:52:06 +02:00
import org.pgpainless.key.OpenPgpV4Fingerprint;
2020-06-26 16:00:47 +02:00
import java.util.ArrayList;
import java.util.Arrays;
2020-06-18 21:52:06 +02:00
import java.util.Collections;
import java.util.Date;
2020-06-26 16:00:47 +02:00
import java.util.Iterator;
2020-06-18 21:52:06 +02:00
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
2020-06-26 16:00:47 +02:00
import java.util.logging.Level;
import java.util.logging.Logger;
2020-06-13 19:14:38 +02:00
2020-06-15 17:41:13 +02:00
import javax.inject.Inject;
2020-06-13 19:14:38 +02:00
2020-06-15 17:41:13 +02:00
import io.reactivex.Completable;
2020-06-26 16:00:47 +02:00
import io.reactivex.Observable;
2020-06-13 19:14:38 +02:00
import io.reactivex.Single;
import io.requery.Persistable;
2020-06-18 21:52:06 +02:00
import io.requery.query.ResultDelegate;
2020-06-13 19:14:38 +02:00
import io.requery.reactivex.ReactiveEntityStore;
public class RxOpenPgpRepository implements OpenPgpRepository {
2020-06-26 16:00:47 +02:00
private static final Logger LOGGER = Logger.getLogger(RxOpenPgpRepository.class.getName());
2020-06-13 19:14:38 +02:00
private final ReactiveEntityStore<Persistable> data;
2020-06-15 17:41:13 +02:00
@Inject
2020-06-13 19:14:38 +02:00
public RxOpenPgpRepository(ReactiveEntityStore<Persistable> data) {
this.data = data;
}
@Override
2020-06-18 21:52:06 +02:00
public Completable storePublicKeysOf(UUID accountId, EntityBareJid owner, PGPPublicKeyRingCollection keys) {
2020-06-15 17:41:13 +02:00
return Single.fromCallable(() -> {
OpenPgpPublicKeyRing keyRing = new OpenPgpPublicKeyRing();
2020-06-18 21:52:06 +02:00
keyRing.setAccountId(accountId);
2020-06-15 17:41:13 +02:00
keyRing.setOwner(owner);
keyRing.setBytes(keys.getEncoded());
return keyRing;
2020-06-26 16:00:47 +02:00
}).flatMap(data::upsert).ignoreElement()
.doOnComplete(() -> LOGGER.log(Level.INFO, "Successfully stored public keys of " + owner + " for account " + accountId));
2020-06-15 17:41:13 +02:00
}
@Override
2020-06-18 21:52:06 +02:00
public Single<PGPPublicKeyRingCollection> loadPublicKeysOf(UUID accountId, EntityBareJid owner) {
2020-06-13 19:14:38 +02:00
return data.select(OpenPgpPublicKeyRing.class)
2020-06-18 21:52:06 +02:00
.where(OpenPgpPublicKeyRing.ACCOUNT_ID.eq(accountId))
.and(OpenPgpPublicKeyRing.OWNER.eq(owner))
2020-06-15 17:41:13 +02:00
.limit(1).get()
.maybe().toSingle()
.map(keyring -> PGPainless.readKeyRing().publicKeyRingCollection(keyring.getBytes()));
2020-06-13 19:14:38 +02:00
}
@Override
2020-06-18 21:52:06 +02:00
public Single<Integer> deletePublicKeysOf(UUID accountId, EntityBareJid owner) {
2020-06-13 19:14:38 +02:00
return data.delete(OpenPgpPublicKeyRing.class)
2020-06-18 21:52:06 +02:00
.where(OpenPgpPublicKeyRing.ACCOUNT_ID.eq(accountId))
.and(OpenPgpPublicKeyRing.OWNER.eq(owner))
2020-06-26 16:00:47 +02:00
.get().single()
.doOnSuccess(count -> LOGGER.log(Level.INFO, "Successfully deleted " + count + " public keys of " + owner + " for account " + accountId));
2020-06-13 19:14:38 +02:00
}
@Override
2020-06-18 21:52:06 +02:00
public Completable storeSecretKeysOf(UUID accountId, EntityBareJid owner, PGPSecretKeyRingCollection keys) {
2020-06-15 17:41:13 +02:00
return Single.fromCallable(() -> {
OpenPgpSecretKeyRing keyRing = new OpenPgpSecretKeyRing();
2020-06-18 21:52:06 +02:00
keyRing.setAccountId(accountId);
2020-06-15 17:41:13 +02:00
keyRing.setOwner(owner);
keyRing.setBytes(keys.getEncoded());
return keyRing;
2020-06-26 16:00:47 +02:00
}).flatMap(data::upsert).ignoreElement()
.doOnComplete(() -> LOGGER.log(Level.INFO, "Successfully stored secret keys of " + owner + " for account " + accountId));
2020-06-15 17:41:13 +02:00
}
@Override
2020-06-18 21:52:06 +02:00
public Single<PGPSecretKeyRingCollection> loadSecretKeysOf(UUID accountId, EntityBareJid owner) {
2020-06-15 17:41:13 +02:00
return data.select(OpenPgpSecretKeyRing.class)
2020-06-18 21:52:06 +02:00
.where(OpenPgpSecretKeyRing.ACCOUNT_ID.eq(accountId))
.and(OpenPgpSecretKeyRing.OWNER.eq(owner))
2020-06-15 17:41:13 +02:00
.limit(1).get()
.maybe().toSingle()
.map(keyring -> PGPainless.readKeyRing().secretKeyRingCollection(keyring.getBytes()));
}
@Override
2020-06-18 21:52:06 +02:00
public Single<Integer> deleteSecretKeysOf(UUID accountId, EntityBareJid owner) {
2020-06-13 19:14:38 +02:00
return data.delete(OpenPgpSecretKeyRing.class)
2020-06-18 21:52:06 +02:00
.where(OpenPgpSecretKeyRing.ACCOUNT_ID.eq(accountId))
.and(OpenPgpSecretKeyRing.OWNER.eq(owner))
2020-06-26 16:00:47 +02:00
.get().single()
.doOnSuccess(count -> LOGGER.log(Level.INFO, "Successfully deleted " + count + " secret keys of " + owner + " for account " + accountId));
2020-06-13 19:14:38 +02:00
}
2020-06-18 21:52:06 +02:00
@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);
}
2020-06-26 16:00:47 +02:00
return data.upsert(entities).ignoreElement()
.doOnComplete(() -> LOGGER.log(Level.INFO, "Successfully stored announced fingerprints of " +
owner + " for account " + accountId + ": " + Arrays.toString(metadata.keySet().toArray())));
2020-06-18 21:52:06 +02:00
}
@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();
}
2020-06-26 16:00:47 +02:00
@Override
public Observable<List<OpenPgpV4Fingerprint>> observeFingerprintsOf(UUID accountId, String peerAddress) {
return data.select(OpenPgpPublicKeyRing.class)
.where(OpenPgpPublicKeyRing.ACCOUNT_ID.eq(accountId))
.and(OpenPgpPublicKeyRing.OWNER.eq(JidCreate.entityBareFromOrThrowUnchecked(peerAddress)))
2020-06-26 16:00:47 +02:00
.get().observableResult()
.map(result -> {
OpenPgpPublicKeyRing model = new ResultDelegate<>(result).firstOrNull();
if (model == null) {
return Collections.emptyList();
}
List<OpenPgpV4Fingerprint> fingerprints = new ArrayList<>();
PGPPublicKeyRingCollection keys = PGPainless.readKeyRing().publicKeyRingCollection(model.getBytes());
for (PGPPublicKeyRing key : keys) {
fingerprints.add(new OpenPgpV4Fingerprint(key));
}
return fingerprints;
});
}
2020-06-18 21:52:06 +02:00
@Override
public Single<Map<OpenPgpV4Fingerprint, Date>> loadPublicKeyFetchDates(UUID accountId, EntityBareJid owner) {
List<OpenPgpKeyFetchDate> fetchDates =
data.select(OpenPgpKeyFetchDate.class)
.where(OpenPgpKeyFetchDate.ACCOUNT_ID.eq(accountId))
.and(OpenPgpKeyFetchDate.OWNER.eq(owner))
.get()
.toList();
Map<OpenPgpV4Fingerprint, Date> map = new ConcurrentHashMap<>();
for (OpenPgpKeyFetchDate date : fetchDates) {
map.put(date.getFingerprint(), date.getFetchDate());
}
return Single.just(map);
2020-06-18 21:52:06 +02:00
}
2020-06-13 19:14:38 +02:00
}