Differentiate between ikey and manual trusts

This commit is contained in:
Paul Schaub 2021-01-10 15:38:08 +01:00
parent 4b9e9f9ae9
commit 2ea902a081
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
8 changed files with 37 additions and 51 deletions

View File

@ -106,7 +106,7 @@ public class AccountDetailsFragment extends Fragment {
viewModel = new ViewModelProvider(this, factory)
.get(AndroidAccountDetailsViewModel.class);
this.otherFingerprintsAdapter = new ToggleableFingerprintsAdapter(this::markFingerprintTrusted);
this.otherFingerprintsAdapter = new ToggleableFingerprintsAdapter(context, this::markFingerprintTrusted);
this.otherFingerprintsAdapter.setItemLongClickListener(fingerprint -> viewModel.unpublishPublicKey(fingerprint));
}

View File

@ -114,7 +114,7 @@ public class ContactDetailFragment extends Fragment {
contactName.setOnClickListener(v -> displayChangeContactNameDialog());
fingerprintsAdapter = new ToggleableFingerprintsAdapter(
fingerprintsAdapter = new ToggleableFingerprintsAdapter(getContext(),
(fingerprint, checked) -> viewModel.markDeviceFingerprintTrusted(fingerprint, checked));
fingerprintRecyclerView.setAdapter(fingerprintsAdapter);

View File

@ -1,5 +1,7 @@
package org.mercury_im.messenger.android.ui.openpgp;
import android.content.Context;
import android.os.Build;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -9,6 +11,7 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
import org.mercury_im.messenger.R;
import org.mercury_im.messenger.core.viewmodel.openpgp.FingerprintViewItem;
import org.pgpainless.key.OpenPgpV4Fingerprint;
@ -25,8 +28,10 @@ public class ToggleableFingerprintsAdapter extends RecyclerView.Adapter<Toggleab
private OnFingerprintItemLongClickListener longClickListener = null;
private static final DateFormat dateFormat = SimpleDateFormat.getDateInstance();
private Context context;
public ToggleableFingerprintsAdapter(OnFingerprintItemToggleListener toggleListener) {
public ToggleableFingerprintsAdapter(Context context, OnFingerprintItemToggleListener toggleListener) {
this.context = context;
this.toggleListener = toggleListener;
}
@ -61,6 +66,9 @@ public class ToggleableFingerprintsAdapter extends RecyclerView.Adapter<Toggleab
boolean checked = ((Switch) v).isChecked();
toggleListener.onFingerprintToggled(fingerprint, checked);
});
if (f.getTrusted() == OpenPgpTrustStore.Trust.ikey_trusted && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
holder.trustSwitch.setThumbDrawable(context.getDrawable(R.drawable.ic_lock_black_24dp));
}
holder.divider.setVisibility(position == fingerprints.size() - 1 ? View.GONE : View.VISIBLE);
holder.itemView.setOnLongClickListener(v -> {

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z"/>
</vector>

View File

@ -150,11 +150,8 @@ public class RxIkeyRepository implements IkeyRepository {
public Completable storeRecord(UUID accountId, EntityBareJid jid, IkeyRecord record) {
assert jid.equals(record.getJid());
return getRecordModel(accountId, jid, false)
.doOnNext(m -> LOGGER.log(Level.INFO, "Loaded model: " + m))
.single(new IkeyRecordModel())
.doOnSuccess(m -> LOGGER.log(Level.INFO, "Singled model: " + m))
.map(m -> {
LOGGER.log(Level.INFO, "Mapping model: " + m);
if (m.getId() == null) m.setId(UUID.randomUUID());
m.setAccountId(accountId);
m.setJid(jid);
@ -174,14 +171,11 @@ public class RxIkeyRepository implements IkeyRepository {
sm.setUri(s.getUri());
m.getSubordinates().add(sm);
}
LOGGER.log(Level.INFO, "Return model: " + m);
return m;
})
.flatMap(data::upsert)
.doOnSuccess(m -> LOGGER.log(Level.INFO, "Upserting model: " + m))
.ignoreElement()
.doOnComplete(() -> LOGGER.log(Level.INFO, "Updated model"))
.doOnError(e -> LOGGER.log(Level.SEVERE, "Error storing ikey record", e));
}

View File

@ -1,6 +1,6 @@
package org.mercury_im.messenger.core.store.crypto;
import org.jivesoftware.smackx.ikey.mechanism.IkeyType;
import org.jivesoftware.smackx.ikey.record.IkeyRecord;
import org.jivesoftware.smackx.ox.store.abstr.AbstractOpenPgpTrustStore;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.EntityBareJid;
@ -10,7 +10,6 @@ import org.mercury_im.messenger.core.data.repository.IkeyKeyRepository;
import org.mercury_im.messenger.core.data.repository.IkeyRecordRepository;
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
import org.mercury_im.messenger.core.data.repository.OpenPgpTrustRepository;
import org.mercury_im.messenger.core.util.Optional;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.io.IOException;
@ -19,10 +18,9 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import io.reactivex.Completable;
import io.reactivex.Observable;
import io.reactivex.Maybe;
import io.reactivex.Single;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.subjects.BehaviorSubject;
public class IkeyAwareOpenPgpStore extends MercuryOpenPgpStore {
@ -56,7 +54,6 @@ public class IkeyAwareOpenPgpStore extends MercuryOpenPgpStore {
private final SchedulersFacade schedulers;
private final CompositeDisposable disposable = new CompositeDisposable();
private final BehaviorSubject<Boolean> accountIsIkeyAware = BehaviorSubject.createDefault(false);
public TrustStore(UUID accountId, OpenPgpTrustRepository openPgpTrustRepository, IkeyKeyRepository ikeyKeyRepository, IkeyRecordRepository ikeyRecordRepository, SchedulersFacade schedulersFacade) {
this.accountId = accountId;
@ -64,27 +61,24 @@ public class IkeyAwareOpenPgpStore extends MercuryOpenPgpStore {
this.ikeyKeyRepository = ikeyKeyRepository;
this.ikeyRecordRepository = ikeyRecordRepository;
this.schedulers = schedulersFacade;
accountIsIkeyAware().subscribe(accountIsIkeyAware);
}
@Override
protected Trust readTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException {
EntityBareJid jid = owner.asEntityBareJidOrThrow();
Trust trust = accountIsIkeyAware.firstOrError()
.flatMap(isAware -> isAware ?
readIkeyTrust(jid, fingerprint) :
readManualTrust(jid, fingerprint))
Trust trust = readIkeyTrust(jid, fingerprint)
.blockingGet();
return trust == null ? Trust.undecided : trust;
}
private Single<Trust> readIkeyTrust(EntityBareJid owner, OpenPgpV4Fingerprint fingerprint) {
return ikeyRecordRepository.loadRecord(accountId, owner)
.map(record -> record.hasSubordinate(fingerprint) ?
record.getTrust() : Trust.undecided)
.doOnNext(trust -> LOGGER.log(Level.INFO, "Read ikey trust " + trust + " for device key " + fingerprint + " of contact " + owner))
.filter(record -> record.getTrust() == Trust.trusted)
.filter(record -> record.hasSubordinate(fingerprint))
.map(IkeyRecord::getTrust)
.map(trust -> trust == Trust.trusted ? Trust.ikey_trusted : trust)
.firstElement()
.flatMap(t -> t == Trust.undecided ? readManualTrust(owner, fingerprint).toMaybe() : Maybe.just(t))
.switchIfEmpty(readManualTrust(owner, fingerprint));
}
@ -103,31 +97,10 @@ public class IkeyAwareOpenPgpStore extends MercuryOpenPgpStore {
protected void writeTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint, Trust trust) throws IOException {
EntityBareJid jid = owner.asEntityBareJidOrThrow();
disposable.add(
contactHasIkeyRecord(owner.asEntityBareJidIfPossible())
.flatMapCompletable(hasRecord -> hasRecord && accountIsIkeyAware.getValue() ?
skipManualTrustForIkeyContact(jid, fingerprint, trust) :
writeManualTrust(jid, fingerprint, trust))
.compose(schedulers.executeUiSafeCompletable())
.subscribe(() -> {},
e -> LOGGER.log(Level.SEVERE, "An error happened while marking device key " + fingerprint + " of " + jid + " as " + trust, e)));
}
private Completable skipManualTrustForIkeyContact(EntityBareJid owner, OpenPgpV4Fingerprint fingerprint, Trust trust) {
return Completable.complete()
.doOnComplete(() -> LOGGER.log(Level.INFO,
"Contact " + owner + " has an Ikey Record, so do not mark " + fingerprint + " as " + trust));
}
private Single<Boolean> contactHasIkeyRecord(EntityBareJid owner) {
return ikeyRecordRepository.loadRecord(accountId, owner.asEntityBareJidOrThrow())
.isEmpty()
.map(resultEmpty -> !resultEmpty); // negate
}
protected Observable<Boolean> accountIsIkeyAware() {
return ikeyKeyRepository.loadSecretKey(accountId)
.map(Optional::isPresent)
.compose(schedulers.executeUiSafeObservable());
writeManualTrust(jid, fingerprint, trust)
.compose(schedulers.executeUiSafeCompletable())
.subscribe(() -> {},
e -> LOGGER.log(Level.SEVERE, "An error happened while marking device key " + fingerprint + " of " + jid + " as " + trust, e)));
}
}
}

View File

@ -7,6 +7,7 @@ import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smack.roster.RosterEntry;
import org.jivesoftware.smack.roster.RosterGroup;
import org.jivesoftware.smackx.ox.OpenPgpManager;
import org.jivesoftware.smackx.ox.crypto.OpenPgpProvider;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
import org.jxmpp.jid.EntityBareJid;
@ -100,8 +101,9 @@ public class ContactDetailViewModel implements MercuryViewModel {
}
public Completable init(Peer peer) {
this.openPgpStore = OpenPgpManager.getInstanceFor(connectionManager.getConnection(peer.getAccount().getId()).getConnection())
.getOpenPgpProvider().getStore();
OpenPgpManager openPgpManager = OpenPgpManager.getInstanceFor(connectionManager.getConnection(peer.getAccount().getId()).getConnection());
OpenPgpProvider provider = openPgpManager.getOpenPgpProvider();
this.openPgpStore = provider.getStore();
return Completable.fromAction(() -> {
this.peerId = peer.getId();

View File

@ -23,6 +23,6 @@ public class FingerprintViewItem {
OpenPgpTrustStore.Trust trusted;
public boolean isTrusted() {
return trusted == OpenPgpTrustStore.Trust.trusted;
return trusted == OpenPgpTrustStore.Trust.trusted || trusted == OpenPgpTrustStore.Trust.ikey_trusted;
}
}