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

247 lines
10 KiB
Java
Raw Normal View History

2020-10-11 11:44:47 +02:00
package org.mercury_im.messenger.data.repository;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
2020-12-15 14:38:10 +01:00
import org.jivesoftware.smackx.ikey.record.IkeyRecord;
import org.jivesoftware.smackx.ikey.record.IkeySubordinateRecord;
import org.jivesoftware.smackx.ikey.record.OxSubordinateRecord;
2020-12-17 14:15:26 +01:00
import org.jivesoftware.smackx.ikey.util.IkeyTrust;
2020-10-11 11:44:47 +02:00
import org.jivesoftware.smackx.ox.OpenPgpSecretKeyBackupPassphrase;
2020-12-15 14:38:10 +01:00
import org.jivesoftware.smackx.ox.element.OpenPgpElement;
2020-10-11 11:44:47 +02:00
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.core.crypto.ikey.IkeyRepository;
2020-10-24 19:25:28 +02:00
import org.mercury_im.messenger.core.util.Optional;
2020-10-11 11:44:47 +02:00
import org.mercury_im.messenger.data.model.IkeyRecordModel;
import org.mercury_im.messenger.data.model.IkeySecretKeyModel;
import org.mercury_im.messenger.data.model.IkeySubordinateModel;
2020-12-17 14:15:26 +01:00
import org.mercury_im.messenger.data.model.IkeyTrustModel;
2020-10-11 11:44:47 +02:00
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.util.ArrayList;
2020-10-24 19:25:28 +02:00
import java.util.Arrays;
2020-10-11 11:44:47 +02:00
import java.util.List;
import java.util.UUID;
2020-10-24 19:25:28 +02:00
import java.util.logging.Level;
import java.util.logging.Logger;
2020-10-11 11:44:47 +02:00
import io.reactivex.Completable;
2020-10-24 19:25:28 +02:00
import io.reactivex.Observable;
2020-10-11 11:44:47 +02:00
import io.reactivex.Single;
import io.requery.Persistable;
2020-10-24 19:25:28 +02:00
import io.requery.query.ResultDelegate;
2020-10-11 11:44:47 +02:00
import io.requery.reactivex.ReactiveEntityStore;
public class RxIkeyRepository implements IkeyRepository {
2020-10-24 19:25:28 +02:00
private static final Logger LOGGER = Logger.getLogger(RxIkeyRepository.class.getName());
2020-10-11 11:44:47 +02:00
private final ReactiveEntityStore<Persistable> data;
public RxIkeyRepository(ReactiveEntityStore<Persistable> data) {
this.data = data;
}
@Override
2020-10-24 19:25:28 +02:00
public Observable<Optional<PGPSecretKeyRing>> loadSecretKey(UUID accountId) {
2020-10-11 11:44:47 +02:00
return data.select(IkeySecretKeyModel.class)
.where(IkeySecretKeyModel.ACCOUNT_ID.eq(accountId))
.get()
2020-10-24 19:25:28 +02:00
.observableResult()
.map(ResultDelegate::toList)
.doOnNext(l -> LOGGER.log(Level.INFO, "new Result: " + Arrays.toString(l.toArray())))
.map(l -> l.isEmpty() ? new Optional<>() : new Optional<>(l.get(0).getKey()));
2020-10-11 11:44:47 +02:00
}
@Override
public Completable storeSecretKey(UUID accountId, PGPSecretKeyRing secretKey) {
return data.select(IkeySecretKeyModel.class)
.where(IkeySecretKeyModel.ACCOUNT_ID.eq(accountId))
.get().observable()
.single(new IkeySecretKeyModel())
.map(m -> {
m.setAccountId(accountId);
m.setKey(secretKey);
m.setFingerprint(new OpenPgpV4Fingerprint(secretKey.getPublicKey()));
return m;
})
.flatMap(data::upsert)
.ignoreElement();
}
@Override
public Single<Integer> deleteSecretKey(UUID accountId) {
return data.delete().from(IkeySecretKeyModel.class)
.where(IkeySecretKeyModel.ACCOUNT_ID.eq(accountId))
.get()
.single();
}
@Override
2020-10-24 19:25:28 +02:00
public Single<Optional<OpenPgpSecretKeyBackupPassphrase>> loadBackupPassphrase(UUID accountID) {
2020-10-11 11:44:47 +02:00
return data.select(IkeySecretKeyModel.class)
.where(IkeySecretKeyModel.ACCOUNT_ID.eq(accountID))
.get()
.observable()
2020-11-19 23:36:49 +01:00
.map(m -> new Optional<>(m.getBackupPassphrase()))
2020-10-24 19:25:28 +02:00
.single(new Optional<>());
2020-10-11 11:44:47 +02:00
}
@Override
public Completable storeBackupPassphrase(UUID accountId, OpenPgpSecretKeyBackupPassphrase passphrase) {
return data.select(IkeySecretKeyModel.class)
.where(IkeySecretKeyModel.ACCOUNT_ID.eq(accountId))
.get().observable()
.single(new IkeySecretKeyModel())
.map(m -> {
m.setAccountId(accountId);
2020-11-19 23:36:49 +01:00
m.setBackupPassphrase(passphrase);
2020-10-11 11:44:47 +02:00
return m;
})
.flatMap(data::upsert)
.ignoreElement();
}
2020-12-17 14:15:26 +01:00
@Override
public Observable<Optional<IkeyTrust>> loadSuperordinateTrust(UUID accountId, EntityBareJid jid, OpenPgpV4Fingerprint fingerprint) {
return data.select(IkeyTrustModel.class)
.where(IkeyTrustModel.ACCOUNT_ID.eq(accountId).and(IkeyTrustModel.JID.eq(jid).and(IkeyTrustModel.FINGERPRINT.eq(fingerprint))))
.get()
.observableResult()
.map(r -> {
IkeyTrustModel m = r.firstOrNull();
if (m == null) {
return new Optional<>();
}
IkeyTrust e = new IkeyTrust();
e.setTrust(m.getTrust());
return new Optional<>(e);
});
}
@Override
public Completable storeSuperordinateTrust(UUID accountId, EntityBareJid jid, OpenPgpV4Fingerprint fingerprint, IkeyTrust trust) {
IkeyTrustModel model = new IkeyTrustModel();
model.setAccountId(accountId);
model.setJid(jid);
model.setFingerprint(fingerprint);
model.setTrust(trust.getTrust());
return data.upsert(model).ignoreElement();
}
2020-10-11 11:44:47 +02:00
@Override
2020-12-15 14:38:10 +01:00
public Observable<IkeyRecord> loadRecord(UUID accountId, EntityBareJid jid) {
return getRecordModel(accountId, jid, false)
.map(m -> {
List<IkeySubordinateRecord> subordinateRecords = new ArrayList<>();
for (IkeySubordinateModel sub : m.getSubordinates()) {
if (sub.getType().equals(OpenPgpElement.NAMESPACE)) {
OxSubordinateRecord r = new OxSubordinateRecord();
r.setOxFingerprint(new OpenPgpV4Fingerprint(sub.getFpr()));
r.setUri(sub.getUri());
}
}
2020-12-17 14:15:26 +01:00
return new IkeyRecord(jid, m.getTimestamp(), m.getSuperordinate(), subordinateRecords);
})
.doOnError(e -> LOGGER.log(Level.SEVERE, "Error loading ikey record", e));
2020-12-15 14:38:10 +01:00
}
@Override
public Completable storeRecord(UUID accountId, EntityBareJid jid, IkeyRecord record) {
assert jid.equals(record.getJid());
return getRecordModel(accountId, jid, false)
.single(new IkeyRecordModel())
2020-10-11 11:44:47 +02:00
.map(m -> {
2020-12-17 14:15:26 +01:00
if (m.getId() == null) m.setId(UUID.randomUUID());
2020-12-15 14:38:10 +01:00
m.setAccountId(accountId);
m.setJid(jid);
m.setContender(false);
m.setFingerprint(new OpenPgpV4Fingerprint(record.getSuperordinate()));
m.setSuperordinate(record.getSuperordinate());
m.setTimestamp(record.getTimestamp());
2020-12-21 21:07:28 +01:00
m.getSubordinates().clear();
2020-12-15 14:38:10 +01:00
for (IkeySubordinateRecord s : record.getSubordinates()) {
IkeySubordinateModel sm = new IkeySubordinateModel();
2020-12-17 14:15:26 +01:00
sm.setId(UUID.randomUUID());
2020-12-15 14:38:10 +01:00
sm.setRecord(m);
sm.setFpr(s.getFingerprint());
sm.setType(s.getType());
sm.setUri(s.getUri());
m.getSubordinates().add(sm);
}
return m;
})
.flatMap(data::upsert)
2020-12-17 14:15:26 +01:00
.ignoreElement()
.doOnError(e -> LOGGER.log(Level.SEVERE, "Error storing ikey record", e));
2020-12-15 14:38:10 +01:00
}
@Override
public Observable<IkeyRecord> loadContenderRecord(UUID accountId, EntityBareJid jid) {
return getRecordModel(accountId, jid, false)
.map(m -> {
List<IkeySubordinateRecord> subordinateRecords = new ArrayList<>();
2020-10-11 11:44:47 +02:00
for (IkeySubordinateModel s : m.getSubordinates()) {
2020-12-15 14:38:10 +01:00
if (s.getType().equals(OpenPgpElement.NAMESPACE)) {
OxSubordinateRecord sr = new OxSubordinateRecord();
sr.setUri(s.getUri());
sr.setOxFingerprint(new OpenPgpV4Fingerprint(s.getFpr()));
subordinateRecords.add(sr);
}
2020-10-11 11:44:47 +02:00
}
2020-12-17 14:15:26 +01:00
return new IkeyRecord(m.getJid(), m.getTimestamp(), m.getSuperordinate(), subordinateRecords);
})
.doOnError(e -> LOGGER.log(Level.SEVERE, "Error loading contender ikey record", e));
2020-10-11 11:44:47 +02:00
}
@Override
2020-12-15 14:38:10 +01:00
public Completable storeContenderRecord(UUID accountId, EntityBareJid jid, IkeyRecord record) {
assert jid.equals(record.getJid());
return getRecordModel(accountId, jid, true)
2020-10-11 11:44:47 +02:00
.single(new IkeyRecordModel())
.map(m -> {
2020-12-17 14:15:26 +01:00
if (m.getId() == null) m.setId(UUID.randomUUID());
2020-10-11 11:44:47 +02:00
m.setAccountId(accountId);
m.setJid(jid);
2020-12-15 14:38:10 +01:00
m.setContender(true);
m.setFingerprint(new OpenPgpV4Fingerprint(record.getSuperordinate()));
m.setSuperordinate(record.getSuperordinate());
m.setTimestamp(record.getTimestamp());
2020-10-11 11:44:47 +02:00
2020-12-15 14:38:10 +01:00
for (IkeySubordinateRecord s : record.getSubordinates()) {
2020-10-11 11:44:47 +02:00
IkeySubordinateModel sm = new IkeySubordinateModel();
2020-12-17 14:15:26 +01:00
sm.setId(UUID.randomUUID());
2020-10-11 11:44:47 +02:00
sm.setRecord(m);
sm.setFpr(s.getFingerprint());
sm.setType(s.getType());
sm.setUri(s.getUri());
m.getSubordinates().add(sm);
}
return m;
})
.flatMap(data::upsert)
2020-12-17 14:15:26 +01:00
.ignoreElement()
.doOnError(e -> LOGGER.log(Level.SEVERE, "Error storing contender ikey record", e));
2020-10-11 11:44:47 +02:00
}
2020-12-15 14:38:10 +01:00
@Override
public Completable clearContenderRecord(UUID accountId, EntityBareJid jid) {
return data.delete(IkeyRecordModel.class)
.where(IkeyRecordModel.ACCOUNT_ID.eq(accountId)
.and(IkeyRecordModel.JID.eq(jid))
.and(IkeyRecordModel.CONTENDER.eq(true)))
.get().single().ignoreElement();
}
private Observable<IkeyRecordModel> getRecordModel(UUID accountId, EntityBareJid jid, boolean isContender) {
return data.select(IkeyRecordModel.class)
.where(IkeyRecordModel.ACCOUNT_ID.eq(accountId)
.and(IkeyRecordModel.JID.eq(jid))
.and(IkeyRecordModel.CONTENDER.eq(isContender)))
.get().observable();
}
2020-10-11 11:44:47 +02:00
}