Some work on ikey stuff

This commit is contained in:
Paul Schaub 2020-12-17 14:15:26 +01:00
parent acec4ed05f
commit bc94467689
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
12 changed files with 160 additions and 102 deletions

View File

@ -172,6 +172,7 @@ public class ContactDetailFragment extends Fragment {
viewModel.getContactAccountAddress().observe(this, address -> contactAccount.setText(address));
viewModel.getContactGroups().observe(this, this::setRosterGroups);
viewModel.getContactFingerprints().observe(this, this::setFingerprints);
viewModel.getContactIkeyFingerprint().observe(this, this::setIkeyFingerprint);
}
private void setRosterGroups(List<String> groups) {

View File

@ -13,6 +13,7 @@ import org.jivesoftware.smack.roster.PresenceEventListener;
import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smack.roster.RosterEntry;
import org.jivesoftware.smack.roster.RosterGroup;
import org.jivesoftware.smackx.ikey.util.IkeyTrust;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.Jid;
@ -20,6 +21,7 @@ import org.jxmpp.jid.impl.JidCreate;
import org.mercury_im.messenger.android.MercuryImApplication;
import org.mercury_im.messenger.core.Messenger;
import org.mercury_im.messenger.core.SchedulersFacade;
import org.mercury_im.messenger.core.crypto.ikey.IkeyRepository;
import org.mercury_im.messenger.core.data.repository.DirectChatRepository;
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
import org.mercury_im.messenger.core.data.repository.PeerRepository;
@ -32,6 +34,7 @@ import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.UUID;
@ -52,6 +55,9 @@ public class ContactDetailViewModel extends ViewModel {
@Inject
OpenPgpRepository openPgpRepository;
@Inject
IkeyRepository ikeyRepository;
@Inject
SchedulersFacade schedulers;
@ -67,6 +73,7 @@ public class ContactDetailViewModel extends ViewModel {
private MutableLiveData<String> contactAccountAddress = new MutableLiveData<>("mad@hatter.lit");
private MutableLiveData<List<String>> contactGroups = new MutableLiveData<>(Collections.emptyList());
private MutableLiveData<List<FingerprintViewItem>> contactFingerprints = new MutableLiveData<>(Collections.emptyList());
private MutableLiveData<Optional<FingerprintViewItem>> contactIkeyFingerprint = new MutableLiveData<>(new Optional<>());
private Roster roster;
private UUID peerId;
@ -121,6 +128,26 @@ public class ContactDetailViewModel extends ViewModel {
contactGroups.postValue(groupNames);
}
}));
disposable.add(ikeyRepository.loadRecord(
getAccountId().getValue(),
JidCreate.entityBareFromOrThrowUnchecked(getContactAccountAddress().getValue()))
.compose(schedulers.executeUiSafeObservable())
.subscribe(r -> {
Optional<IkeyTrust> trustOptional = ikeyRepository.loadSuperordinateTrust(
getAccountId().getValue(),
JidCreate.entityBareFromOrThrowUnchecked(getContactAccountAddress().getValue()),
new OpenPgpV4Fingerprint(r.getSuperordinate())
).blockingFirst();
contactIkeyFingerprint.postValue(
new Optional<>(new FingerprintViewItem(
getAccountId().getValue(),
JidCreate.entityBareFromOrThrowUnchecked(getContactAccountAddress().getValue()),
new OpenPgpV4Fingerprint(r.getSuperordinate()),
r.getTimestamp(),
new Date(),
trustOptional.isPresent() ? trustOptional.getItem().getTrust() : OpenPgpTrustStore.Trust.undecided)));
}));
}
public LiveData<String> getContactAddress() {
@ -222,6 +249,10 @@ public class ContactDetailViewModel extends ViewModel {
JidCreate.entityBareFromOrThrowUnchecked(contactAddress.getValue()),
fingerprint,
checked ? OpenPgpTrustStore.Trust.trusted : OpenPgpTrustStore.Trust.untrusted)
.subscribe();
.subscribe();
}
public LiveData<Optional<FingerprintViewItem>> getContactIkeyFingerprint() {
return contactIkeyFingerprint;
}
}

View File

@ -1,57 +0,0 @@
package org.mercury_im.messenger.data.mapping;
import org.jivesoftware.smackx.ikey.record.IkeyRecord;
import org.jivesoftware.smackx.ikey.record.IkeySubordinateRecord;
import org.jivesoftware.smackx.ikey.record.OxSubordinateRecord;
import org.mercury_im.messenger.data.model.IkeyRecordModel;
import org.mercury_im.messenger.data.model.IkeySubordinateModel;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import lombok.NonNull;
public class IkeyRecordMapping extends AbstractMapping<IkeyRecord, IkeyRecordModel> {
@Override
protected IkeyRecord newEntity(@NonNull IkeyRecordModel model) {
List<IkeySubordinateRecord> subordinateRecords = mapToSubordinateRecords(model.getSubordinates());
return new IkeyRecord(UUID.randomUUID(), model.getJid(), model.getTimestamp(), model.getSuperordinate(), subordinateRecords);
}
private List<IkeySubordinateRecord> mapToSubordinateRecords(List<IkeySubordinateModel> subordinates) {
List<IkeySubordinateRecord> records = new ArrayList<>();
for (IkeySubordinateModel m : subordinates) {
if (m.getType().equals("urn:xmpp:openpgp:0")) {
OxSubordinateRecord r = new OxSubordinateRecord();
r.setOxFingerprint(new OpenPgpV4Fingerprint(m.getFpr()));
r.setUri(m.getUri());
records.add(r);
}
}
return records;
}
@Override
protected IkeyRecordModel newModel(@NonNull IkeyRecord entity) {
IkeyRecordModel model = new IkeyRecordModel();
model.setJid(entity.getJid());
model.setTimestamp(entity.getTimestamp());
model.setSuperordinate(entity.getSuperordinate());
model.setFingerprint(new OpenPgpV4Fingerprint(entity.getSuperordinate()));
return model;
}
@Override
protected IkeyRecordModel mapToModel(@NonNull IkeyRecord entity, @NonNull IkeyRecordModel model) {
return null;
}
@Override
protected IkeyRecord mapToEntity(@NonNull IkeyRecordModel model, @NonNull IkeyRecord entity) {
return null;
}
}

View File

@ -2,6 +2,7 @@ package org.mercury_im.messenger.data.model;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.data.converter.Base64PGPPublicKeyRingConverter;
import org.mercury_im.messenger.data.converter.EntityBareJidConverter;
import org.mercury_im.messenger.data.converter.OpenPgpV4FingerprintConverter;
import org.pgpainless.key.OpenPgpV4Fingerprint;
@ -14,14 +15,12 @@ import io.requery.CascadeAction;
import io.requery.Column;
import io.requery.Convert;
import io.requery.Entity;
import io.requery.Generated;
import io.requery.Index;
import io.requery.Key;
import io.requery.OneToMany;
import io.requery.Table;
import io.requery.converter.UUIDConverter;
@Table(name = "ikey_record", uniqueIndexes = {"record_index"})
@Table(name = "ikey_record")
@Entity
public class AbstractIkeyRecordModel {
@ -29,16 +28,17 @@ public class AbstractIkeyRecordModel {
@Convert(UUIDConverter.class)
UUID id;
@Column(name = "account", unique = true)
@Index("record_index")
@Column(name = "account")
@Convert(UUIDConverter.class)
UUID accountId;
@Column(name = "jid", unique = true)
@Index("record_index")
@Column(name = "jid")
@Convert(EntityBareJidConverter.class)
EntityBareJid jid;
@Column(name = "contender")
boolean contender;
@Column(name = "\"timestamp\"")
Date timestamp;
@ -47,19 +47,10 @@ public class AbstractIkeyRecordModel {
List<IkeySubordinateModel> subordinates;
@Column(name = "superordinate")
@Convert(Base64PGPPublicKeyRingConverter.class)
PGPPublicKeyRing superordinate;
@Column(name = "fingerprint")
@Convert(OpenPgpV4FingerprintConverter.class)
OpenPgpV4Fingerprint fingerprint;
@Column(name = "trusted")
boolean trusted;
@Column(name = "contender")
boolean contender;
@Column(name = "proof")
String proof;
}

View File

@ -6,6 +6,7 @@ import java.util.UUID;
import io.requery.Column;
import io.requery.Convert;
import io.requery.Entity;
import io.requery.ForeignKey;
import io.requery.Generated;
import io.requery.Key;
import io.requery.ManyToOne;
@ -32,5 +33,6 @@ public class AbstractIkeySubordinateModel {
String fpr;
@ManyToOne
@ForeignKey(referencedColumn = "id")
AbstractIkeyRecordModel record;
}

View File

@ -0,0 +1,41 @@
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.Column;
import io.requery.Convert;
import io.requery.Entity;
import io.requery.ForeignKey;
import io.requery.Key;
import io.requery.ReferentialAction;
import io.requery.Table;
import io.requery.converter.UUIDConverter;
@Table(name = "ikey_trust")
@Entity
public class AbstractIkeyTrustModel {
@Key
@ForeignKey(references = AbstractAccountModel.class, delete = ReferentialAction.CASCADE)
@Convert(UUIDConverter.class)
UUID accountId;
@Key
@Convert(EntityBareJidConverter.class)
EntityBareJid jid;
@Key
@Convert(OpenPgpV4FingerprintConverter.class)
OpenPgpV4Fingerprint fingerprint;
@Column(name = "trust")
@Convert(OpenPgpTrustConverter.class)
OpenPgpTrustStore.Trust trust;
}

View File

@ -4,6 +4,7 @@ import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.jivesoftware.smackx.ikey.record.IkeyRecord;
import org.jivesoftware.smackx.ikey.record.IkeySubordinateRecord;
import org.jivesoftware.smackx.ikey.record.OxSubordinateRecord;
import org.jivesoftware.smackx.ikey.util.IkeyTrust;
import org.jivesoftware.smackx.ox.OpenPgpSecretKeyBackupPassphrase;
import org.jivesoftware.smackx.ox.element.OpenPgpElement;
import org.jxmpp.jid.EntityBareJid;
@ -12,6 +13,7 @@ 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.mercury_im.messenger.data.model.IkeyTrustModel;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.util.ArrayList;
@ -99,6 +101,33 @@ public class RxIkeyRepository implements IkeyRepository {
.ignoreElement();
}
@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();
}
@Override
public Observable<IkeyRecord> loadRecord(UUID accountId, EntityBareJid jid) {
return getRecordModel(accountId, jid, false)
@ -111,8 +140,9 @@ public class RxIkeyRepository implements IkeyRepository {
r.setUri(sub.getUri());
}
}
return new IkeyRecord(m.getId(), jid, m.getTimestamp(), m.getSuperordinate(), subordinateRecords);
});
return new IkeyRecord(jid, m.getTimestamp(), m.getSuperordinate(), subordinateRecords);
})
.doOnError(e -> LOGGER.log(Level.SEVERE, "Error loading ikey record", e));
}
@Override
@ -121,17 +151,17 @@ public class RxIkeyRepository implements IkeyRepository {
return getRecordModel(accountId, jid, false)
.single(new IkeyRecordModel())
.map(m -> {
m.setId(record.getId());
if (m.getId() == null) m.setId(UUID.randomUUID());
m.setAccountId(accountId);
m.setJid(jid);
m.setContender(false);
// m.setProof(record.getProof().getBase64Signature());
m.setFingerprint(new OpenPgpV4Fingerprint(record.getSuperordinate()));
m.setSuperordinate(record.getSuperordinate());
m.setTimestamp(record.getTimestamp());
for (IkeySubordinateRecord s : record.getSubordinates()) {
IkeySubordinateModel sm = new IkeySubordinateModel();
sm.setId(UUID.randomUUID());
sm.setRecord(m);
sm.setFpr(s.getFingerprint());
sm.setType(s.getType());
@ -142,7 +172,8 @@ public class RxIkeyRepository implements IkeyRepository {
return m;
})
.flatMap(data::upsert)
.ignoreElement();
.ignoreElement()
.doOnError(e -> LOGGER.log(Level.SEVERE, "Error storing ikey record", e));
}
@Override
@ -158,8 +189,9 @@ public class RxIkeyRepository implements IkeyRepository {
subordinateRecords.add(sr);
}
}
return new IkeyRecord(m.getId(), m.getJid(), m.getTimestamp(), m.getSuperordinate(), subordinateRecords);
});
return new IkeyRecord(m.getJid(), m.getTimestamp(), m.getSuperordinate(), subordinateRecords);
})
.doOnError(e -> LOGGER.log(Level.SEVERE, "Error loading contender ikey record", e));
}
@Override
@ -168,17 +200,17 @@ public class RxIkeyRepository implements IkeyRepository {
return getRecordModel(accountId, jid, true)
.single(new IkeyRecordModel())
.map(m -> {
m.setId(record.getId());
if (m.getId() == null) m.setId(UUID.randomUUID());
m.setAccountId(accountId);
m.setJid(jid);
m.setContender(true);
// m.setProof(record.getProof().getBase64Signature());
m.setFingerprint(new OpenPgpV4Fingerprint(record.getSuperordinate()));
m.setSuperordinate(record.getSuperordinate());
m.setTimestamp(record.getTimestamp());
for (IkeySubordinateRecord s : record.getSubordinates()) {
IkeySubordinateModel sm = new IkeySubordinateModel();
sm.setId(UUID.randomUUID());
sm.setRecord(m);
sm.setFpr(s.getFingerprint());
sm.setType(s.getType());
@ -189,7 +221,8 @@ public class RxIkeyRepository implements IkeyRepository {
return m;
})
.flatMap(data::upsert)
.ignoreElement();
.ignoreElement()
.doOnError(e -> LOGGER.log(Level.SEVERE, "Error storing contender ikey record", e));
}
@Override

View File

@ -7,17 +7,12 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import lombok.Getter;
import lombok.Setter;
public class IkeyRecord implements Serializable {
@Getter
@Setter
private UUID id;
@Getter
@Setter
private PGPPublicKeyRing superordinate;
@ -35,11 +30,10 @@ public class IkeyRecord implements Serializable {
private EntityBareJid jid;
public IkeyRecord() {
this.id = UUID.randomUUID();
}
public IkeyRecord(UUID id, EntityBareJid jid, Date timestamp, PGPPublicKeyRing superordinate, List<IkeySubordinateRecord> subordinates) {
this.id = id;
public IkeyRecord(EntityBareJid jid, Date timestamp, PGPPublicKeyRing superordinate, List<IkeySubordinateRecord> subordinates) {
this.jid = jid;
this.timestamp = timestamp;
this.superordinate = superordinate;

View File

@ -0,0 +1,13 @@
package org.jivesoftware.smackx.ikey.util;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
import lombok.Getter;
import lombok.Setter;
public class IkeyTrust {
@Getter
@Setter
OpenPgpTrustStore.Trust trust;
}

View File

@ -1,7 +1,6 @@
package org.mercury_im.messenger.core.crypto.ikey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.jivesoftware.smackx.ikey.element.IkeyElement;
import org.jivesoftware.smackx.ikey.record.IkeyRecord;
import org.jivesoftware.smackx.ikey.record.IkeyStore;
import org.jivesoftware.smackx.ox.OpenPgpSecretKeyBackupPassphrase;

View File

@ -1,9 +1,12 @@
package org.mercury_im.messenger.core.data.repository;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.jivesoftware.smackx.ikey.util.IkeyTrust;
import org.jivesoftware.smackx.ox.OpenPgpSecretKeyBackupPassphrase;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.core.util.Optional;
import org.mercury_im.messenger.entity.Account;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.util.UUID;
@ -43,4 +46,16 @@ public interface IkeyKeyRepository {
}
Completable storeBackupPassphrase(UUID accountID, OpenPgpSecretKeyBackupPassphrase passphrase);
default Observable<Optional<IkeyTrust>> loadSuperordinateTrust(Account account, EntityBareJid jid, OpenPgpV4Fingerprint fingerprint) {
return loadSuperordinateTrust(account.getId(), jid, fingerprint);
}
Observable<Optional<IkeyTrust>> loadSuperordinateTrust(UUID accountId, EntityBareJid jid, OpenPgpV4Fingerprint fingerprint);
default Completable storeSuperordinateTrust(Account account, EntityBareJid jid, OpenPgpV4Fingerprint fingerprint, IkeyTrust trust) {
return storeSuperordinateTrust(account.getId(), jid, fingerprint, trust);
}
Completable storeSuperordinateTrust(UUID accountId, EntityBareJid jid, OpenPgpV4Fingerprint fingerprint, IkeyTrust trust);
}

View File

@ -2,13 +2,10 @@ package org.mercury_im.messenger.core.viewmodel.account.detail;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smackx.ikey.IkeyManager;
import org.jivesoftware.smackx.ikey.element.IkeyElement;
import org.jivesoftware.smackx.ikey.element.SubordinateElement;
import org.jivesoftware.smackx.ikey.mechanism.IkeyType;
import org.jivesoftware.smackx.ikey_ox.OxIkeySignatureCreationMechanism;
import org.jivesoftware.smackx.ox.element.PublicKeysListElement;
import org.jivesoftware.smackx.ox.element.SecretkeyElement;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
@ -40,10 +37,7 @@ import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -51,7 +45,6 @@ import java.util.logging.Logger;
import javax.inject.Inject;
import io.reactivex.Completable;
import io.reactivex.Maybe;
import io.reactivex.Observable;
import io.reactivex.Single;
@ -115,7 +108,9 @@ public class AccountDetailsViewModel implements MercuryViewModel {
.map(l -> {
List<OpenPgpV4Fingerprint> fps = new ArrayList<>();
for (FingerprintViewItem vi : l) {
fps.add(vi.getFingerprint());
if (vi.getTrusted() == OpenPgpTrustStore.Trust.trusted) {
fps.add(vi.getFingerprint());
}
}
return fps;
}).blockingGet();