154 lines
6.6 KiB
Java
154 lines
6.6 KiB
Java
package org.mercury_im.messenger.data.repository;
|
|
|
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
|
import org.jivesoftware.smackx.ikey.element.IkeyElement;
|
|
import org.jivesoftware.smackx.ikey.element.ProofElement;
|
|
import org.jivesoftware.smackx.ikey.element.SignedElement;
|
|
import org.jivesoftware.smackx.ikey.element.SubordinateElement;
|
|
import org.jivesoftware.smackx.ikey.element.SubordinateListElement;
|
|
import org.jivesoftware.smackx.ikey.element.SuperordinateElement;
|
|
import org.jivesoftware.smackx.ikey.mechanism.IkeyType;
|
|
import org.jivesoftware.smackx.ox.OpenPgpSecretKeyBackupPassphrase;
|
|
import org.jxmpp.jid.EntityBareJid;
|
|
import org.mercury_im.messenger.core.crypto.ikey.IkeyRepository;
|
|
import org.mercury_im.messenger.core.util.Optional;
|
|
import org.mercury_im.messenger.data.model.IkeyRecordModel;
|
|
import org.mercury_im.messenger.data.model.IkeySecretKeyModel;
|
|
import org.mercury_im.messenger.data.model.IkeySubordinateModel;
|
|
import org.pgpainless.PGPainless;
|
|
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
import java.util.UUID;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
|
|
import io.reactivex.Completable;
|
|
import io.reactivex.Observable;
|
|
import io.reactivex.Single;
|
|
import io.requery.Persistable;
|
|
import io.requery.query.ResultDelegate;
|
|
import io.requery.reactivex.ReactiveEntityStore;
|
|
|
|
public class RxIkeyRepository implements IkeyRepository {
|
|
|
|
private static final Logger LOGGER = Logger.getLogger(RxIkeyRepository.class.getName());
|
|
|
|
private final ReactiveEntityStore<Persistable> data;
|
|
|
|
public RxIkeyRepository(ReactiveEntityStore<Persistable> data) {
|
|
this.data = data;
|
|
}
|
|
|
|
@Override
|
|
public Observable<Optional<PGPSecretKeyRing>> loadSecretKey(UUID accountId) {
|
|
return data.select(IkeySecretKeyModel.class)
|
|
.where(IkeySecretKeyModel.ACCOUNT_ID.eq(accountId))
|
|
.get()
|
|
.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()));
|
|
}
|
|
|
|
@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
|
|
public Single<Optional<OpenPgpSecretKeyBackupPassphrase>> loadBackupPassphrase(UUID accountID) {
|
|
return data.select(IkeySecretKeyModel.class)
|
|
.where(IkeySecretKeyModel.ACCOUNT_ID.eq(accountID))
|
|
.get()
|
|
.observable()
|
|
.map(m -> new Optional<>(m.getBackupPassphrase()))
|
|
.single(new Optional<>());
|
|
}
|
|
|
|
@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);
|
|
m.setBackupPassphrase(passphrase);
|
|
return m;
|
|
})
|
|
.flatMap(data::upsert)
|
|
.ignoreElement();
|
|
}
|
|
|
|
@Override
|
|
public Observable<IkeyElement> loadRecord(UUID accountId, EntityBareJid jid) {
|
|
return data.select(IkeyRecordModel.class)
|
|
.where(IkeyRecordModel.ACCOUNT_ID.eq(accountId).and(IkeyRecordModel.JID.eq(jid)))
|
|
.get().observable()
|
|
.map(m -> {
|
|
SuperordinateElement superordinateElement = new SuperordinateElement(m.getSuperordinate().getEncoded());
|
|
List<SubordinateElement> subList = new ArrayList<>();
|
|
for (IkeySubordinateModel s : m.getSubordinates()) {
|
|
subList.add(new SubordinateElement(s.getType(), s.getUri(), s.getFpr()));
|
|
}
|
|
SubordinateListElement subs = new SubordinateListElement(m.getJid(), m.getTimestamp(), subList);
|
|
SignedElement signedElement = new SignedElement(subs.toBase64EncodedString());
|
|
IkeyElement ikeyElement = new IkeyElement(IkeyType.OX, superordinateElement, signedElement, new ProofElement(m.getProof()));
|
|
return ikeyElement;
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public Completable storeRecord(UUID accountId, EntityBareJid jid, IkeyElement record) {
|
|
assert jid.equals(record.getSignedElement().getChildElement().getJid());
|
|
return data.select(IkeyRecordModel.class)
|
|
.where(IkeyRecordModel.ACCOUNT_ID.eq(accountId).and(IkeyRecordModel.JID.eq(jid)))
|
|
.get().observable()
|
|
.single(new IkeyRecordModel())
|
|
.map(m -> {
|
|
m.setAccountId(accountId);
|
|
m.setJid(jid);
|
|
m.setProof(record.getProof().getBase64Signature());
|
|
m.setFingerprint(new OpenPgpV4Fingerprint(record.getSuperordinate().getPubKeyBytes()));
|
|
m.setSuperordinate(PGPainless.readKeyRing().publicKeyRing(record.getSuperordinate().getPubKeyBytes()));
|
|
m.setTimestamp(record.getSignedElement().getChildElement().getTimestamp());
|
|
|
|
for (SubordinateElement s : record.getSignedElement().getChildElement().getSubordinates()) {
|
|
IkeySubordinateModel sm = new IkeySubordinateModel();
|
|
sm.setRecord(m);
|
|
sm.setFpr(s.getFingerprint());
|
|
sm.setType(s.getType());
|
|
sm.setUri(s.getUri());
|
|
m.getSubordinates().add(sm);
|
|
}
|
|
|
|
return m;
|
|
})
|
|
.flatMap(data::upsert)
|
|
.ignoreElement();
|
|
}
|
|
}
|