Implement publishing ikey elements
This commit is contained in:
parent
b8185b30ae
commit
3cbe527959
|
@ -57,6 +57,9 @@ public class AccountDetailsFragment extends Fragment {
|
||||||
@BindView(R.id.btn_backup_ikey)
|
@BindView(R.id.btn_backup_ikey)
|
||||||
Button ikeyCreateBackupButton;
|
Button ikeyCreateBackupButton;
|
||||||
|
|
||||||
|
@BindView(R.id.btn_send_ikey_element)
|
||||||
|
Button ikeySendDecisions;
|
||||||
|
|
||||||
@BindView(R.id.ikey_fingerprint)
|
@BindView(R.id.ikey_fingerprint)
|
||||||
TextView ikeyFingerprint;
|
TextView ikeyFingerprint;
|
||||||
|
|
||||||
|
@ -81,6 +84,19 @@ public class AccountDetailsFragment extends Fragment {
|
||||||
this.accountId = accountId;
|
this.accountId = accountId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_account_details, container, false);
|
||||||
|
ButterKnife.bind(this, view);
|
||||||
|
setHasOptionsMenu(true);
|
||||||
|
|
||||||
|
externalFingerprintRecyclerView.setAdapter(otherFingerprintsAdapter);
|
||||||
|
observeViewModel();
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(@NonNull Context context) {
|
public void onAttach(@NonNull Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
|
@ -89,8 +105,7 @@ public class AccountDetailsFragment extends Fragment {
|
||||||
viewModel = new ViewModelProvider(this, factory)
|
viewModel = new ViewModelProvider(this, factory)
|
||||||
.get(AndroidAccountDetailsViewModel.class);
|
.get(AndroidAccountDetailsViewModel.class);
|
||||||
|
|
||||||
this.otherFingerprintsAdapter = new ToggleableFingerprintsAdapter(
|
this.otherFingerprintsAdapter = new ToggleableFingerprintsAdapter(this::markFingerprintTrusted);
|
||||||
(fingerprint, checked) -> viewModel.markFingerprintTrusted(fingerprint, checked));
|
|
||||||
this.otherFingerprintsAdapter.setItemLongClickListener(fingerprint -> viewModel.unpublishPublicKey(fingerprint));
|
this.otherFingerprintsAdapter.setItemLongClickListener(fingerprint -> viewModel.unpublishPublicKey(fingerprint));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,21 +130,22 @@ public class AccountDetailsFragment extends Fragment {
|
||||||
case R.id.action_restore_ikey_backup:
|
case R.id.action_restore_ikey_backup:
|
||||||
viewModel.onRestoreIkeyBackup();
|
viewModel.onRestoreIkeyBackup();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
// case R.id.action_setup_ikey:
|
||||||
|
// getParentFragmentManager().beginTransaction()
|
||||||
|
// .replace(R.id.fragment, IkeySetupFragment.newInstance(accountId))
|
||||||
|
// .commit();
|
||||||
|
// return true;
|
||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
private void markFingerprintTrusted(OpenPgpV4Fingerprint fingerprint, boolean trusted) {
|
||||||
@Override
|
viewModel.markFingerprintTrusted(fingerprint, trusted);
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
}
|
||||||
View view = inflater.inflate(R.layout.fragment_account_details, container, false);
|
|
||||||
ButterKnife.bind(this, view);
|
|
||||||
setHasOptionsMenu(true);
|
|
||||||
|
|
||||||
externalFingerprintRecyclerView.setAdapter(otherFingerprintsAdapter);
|
private void sendIkeyElement() {
|
||||||
observeViewModel();
|
viewModel.sendIkeyElement(accountId);
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void observeViewModel() {
|
private void observeViewModel() {
|
||||||
|
@ -165,6 +181,8 @@ public class AccountDetailsFragment extends Fragment {
|
||||||
ikeyCreateBackupButton.setEnabled(authenticated);
|
ikeyCreateBackupButton.setEnabled(authenticated);
|
||||||
localKeyCreateBackupButton.setEnabled(authenticated);
|
localKeyCreateBackupButton.setEnabled(authenticated);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ikeySendDecisions.setOnClickListener(v -> sendIkeyElement());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startShareFingerprintIntent(OpenPgpV4Fingerprint fingerprint) {
|
private void startShareFingerprintIntent(OpenPgpV4Fingerprint fingerprint) {
|
||||||
|
|
|
@ -105,6 +105,10 @@ public class AndroidAccountDetailsViewModel extends AndroidViewModel implements
|
||||||
getCommonViewModel().markFingerprintTrusted(accountId, fingerprint, trusted);
|
getCommonViewModel().markFingerprintTrusted(accountId, fingerprint, trusted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendIkeyElement(UUID accountId) {
|
||||||
|
getCommonViewModel().sendIkeyElement(accountId);
|
||||||
|
}
|
||||||
|
|
||||||
public LiveData<Optional<OpenPgpV4Fingerprint>> getIkeyFingerprint() {
|
public LiveData<Optional<OpenPgpV4Fingerprint>> getIkeyFingerprint() {
|
||||||
return ikeyFingerprint;
|
return ikeyFingerprint;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<de.hdodenhof.circleimageview.CircleImageView
|
<de.hdodenhof.circleimageview.CircleImageView
|
||||||
|
android:visibility="gone"
|
||||||
android:id="@+id/avatar"
|
android:id="@+id/avatar"
|
||||||
android:layout_width="196dp"
|
android:layout_width="196dp"
|
||||||
android:layout_height="196dp"
|
android:layout_height="196dp"
|
||||||
|
@ -77,7 +78,7 @@
|
||||||
android:id="@+id/title_ikey"
|
android:id="@+id/title_ikey"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Account Identity Key"
|
android:text="Identity Key"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
@ -134,7 +135,7 @@
|
||||||
android:id="@+id/title"
|
android:id="@+id/title"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Local Fingerprint"
|
android:text="Device Key"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
@ -153,6 +154,7 @@
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/btn_backup"
|
android:id="@+id/btn_backup"
|
||||||
|
android:visibility="gone"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/btn_server_backup"
|
android:text="@string/btn_server_backup"
|
||||||
|
@ -180,6 +182,14 @@
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginBottom="8dp"/>
|
android:layout_marginBottom="8dp"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/btn_send_ikey_element"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:text="Publish Decisions" />
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
android:id="@+id/title"
|
android:id="@+id/title"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Other Fingerprints"
|
android:text="Other Devices"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
|
@ -23,4 +23,8 @@
|
||||||
android:title="Restore Identity Key Backup"
|
android:title="Restore Identity Key Backup"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_setup_ikey"
|
||||||
|
android:title="Ikey Setup" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
|
@ -1,7 +1,14 @@
|
||||||
package org.mercury_im.messenger.core.viewmodel.account.detail;
|
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.smack.XMPPConnection;
|
||||||
import org.jivesoftware.smackx.ikey.IkeyManager;
|
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.PublicKeysListElement;
|
||||||
import org.jivesoftware.smackx.ox.element.SecretkeyElement;
|
import org.jivesoftware.smackx.ox.element.SecretkeyElement;
|
||||||
import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
|
import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
|
||||||
|
@ -10,6 +17,8 @@ import org.jivesoftware.smackx.pep.PepManager;
|
||||||
import org.jivesoftware.smackx.pubsub.LeafNode;
|
import org.jivesoftware.smackx.pubsub.LeafNode;
|
||||||
import org.jivesoftware.smackx.pubsub.PayloadItem;
|
import org.jivesoftware.smackx.pubsub.PayloadItem;
|
||||||
import org.jivesoftware.smackx.pubsub.PubSubManager;
|
import org.jivesoftware.smackx.pubsub.PubSubManager;
|
||||||
|
import org.jivesoftware.smackx.pubsub.PubSubUri;
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
import org.jxmpp.jid.EntityBareJid;
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.mercury_im.messenger.core.SchedulersFacade;
|
import org.mercury_im.messenger.core.SchedulersFacade;
|
||||||
import org.mercury_im.messenger.core.connection.MercuryConnection;
|
import org.mercury_im.messenger.core.connection.MercuryConnection;
|
||||||
|
@ -25,14 +34,24 @@ import org.mercury_im.messenger.core.viewmodel.MercuryViewModel;
|
||||||
import org.mercury_im.messenger.core.viewmodel.openpgp.FingerprintViewItem;
|
import org.mercury_im.messenger.core.viewmodel.openpgp.FingerprintViewItem;
|
||||||
import org.mercury_im.messenger.entity.Account;
|
import org.mercury_im.messenger.entity.Account;
|
||||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||||
|
import org.pgpainless.key.protection.UnprotectedKeysProtector;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import io.reactivex.Completable;
|
import io.reactivex.Completable;
|
||||||
|
import io.reactivex.Maybe;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
|
|
||||||
|
@ -40,6 +59,8 @@ import static org.jivesoftware.smackx.ox.util.OpenPgpPubSubUtil.PEP_NODE_PUBLIC_
|
||||||
|
|
||||||
public class AccountDetailsViewModel implements MercuryViewModel {
|
public class AccountDetailsViewModel implements MercuryViewModel {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(AccountDetailsViewModel.class.getName());
|
||||||
|
|
||||||
private MercuryConnectionManager connectionManager;
|
private MercuryConnectionManager connectionManager;
|
||||||
private final OpenPgpRepository openPgpRepository;
|
private final OpenPgpRepository openPgpRepository;
|
||||||
private final IkeyRepository ikeyRepository;
|
private final IkeyRepository ikeyRepository;
|
||||||
|
@ -68,6 +89,61 @@ public class AccountDetailsViewModel implements MercuryViewModel {
|
||||||
.subscribe());
|
.subscribe());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendIkeyElement(UUID accountId) {
|
||||||
|
addDisposable(Completable
|
||||||
|
.fromAction(() -> {
|
||||||
|
IkeyElement ikeyElement = syncCreateIkeyElement(accountId);
|
||||||
|
IkeyManager ikeyManager = IkeyManager.getInstanceFor(connectionManager.getConnection(accountId).getConnection());
|
||||||
|
|
||||||
|
ikeyManager.publishIkeyElement(ikeyElement);
|
||||||
|
})
|
||||||
|
.compose(schedulers.executeUiSafeCompletable())
|
||||||
|
.subscribe(
|
||||||
|
() -> LOGGER.log(Level.INFO, "Successfully published ikey element."),
|
||||||
|
e -> LOGGER.log(Level.SEVERE, "Error publishing ikey element:", e)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private IkeyElement syncCreateIkeyElement(UUID accountId) throws URISyntaxException, PGPException, IOException {
|
||||||
|
MercuryConnection connection = connectionManager.getConnection(accountId);
|
||||||
|
IkeyManager ikeyManager = ikeyInitializer.initFor(connection);
|
||||||
|
|
||||||
|
Account account = accountRepository.getAccount(accountId).blockingGet();
|
||||||
|
OpenPgpV4Fingerprint localFp = openPgpRepository.observeLocalFingerprintOf(accountId).blockingFirst().getItem();
|
||||||
|
// Why does openPgpRepository.loadAnnouncedFingerprints() never return?
|
||||||
|
List<OpenPgpV4Fingerprint> fingerprintList =
|
||||||
|
openPgpRepository.observeFingerprints(accountId, account.getJid()).first(new ArrayList<>())
|
||||||
|
.map(l -> {
|
||||||
|
List<OpenPgpV4Fingerprint> fps = new ArrayList<>();
|
||||||
|
for (FingerprintViewItem vi : l) {
|
||||||
|
fps.add(vi.getFingerprint());
|
||||||
|
}
|
||||||
|
return fps;
|
||||||
|
}).blockingGet();
|
||||||
|
|
||||||
|
List<SubordinateElement> subordinateElements = new ArrayList<>();
|
||||||
|
URI uri = new URI(getOxKeyNodeUri(connection, localFp).toString());
|
||||||
|
subordinateElements.add(new SubordinateElement("urn:xmpp:openpgp:0", uri, localFp.toString()));
|
||||||
|
|
||||||
|
for (OpenPgpV4Fingerprint fp : fingerprintList) {
|
||||||
|
URI u = new URI(getOxKeyNodeUri(connection, fp).toString());
|
||||||
|
subordinateElements.add(new SubordinateElement("urn:xmpp:openpgp:0", u, fp.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
PGPSecretKeyRing secretKeys = openPgpRepository.loadSecretKeysOf(accountId, account.getJid())
|
||||||
|
.blockingGet().getSecretKeyRing(localFp.getKeyId());
|
||||||
|
|
||||||
|
IkeyElement ikeyElement = ikeyManager.createOxIkeyElement(secretKeys,
|
||||||
|
new UnprotectedKeysProtector(), subordinateElements.toArray(new SubordinateElement[]{}));
|
||||||
|
|
||||||
|
return ikeyElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PubSubUri getOxKeyNodeUri(MercuryConnection connection, OpenPgpV4Fingerprint fingerprint) {
|
||||||
|
PubSubManager pubSubManager = PubSubManager.getInstanceFor(connection.getConnection());
|
||||||
|
BareJid serviceJid = pubSubManager.getServiceJid();
|
||||||
|
return new PubSubUri(serviceJid, OpenPgpPubSubUtil.PEP_NODE_PUBLIC_KEY(fingerprint), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
public Single<EntityBareJid> getJid(UUID accountId) {
|
public Single<EntityBareJid> getJid(UUID accountId) {
|
||||||
return accountRepository.getAccount(accountId).toSingle()
|
return accountRepository.getAccount(accountId).toSingle()
|
||||||
.compose(schedulers.executeUiSafeSingle())
|
.compose(schedulers.executeUiSafeSingle())
|
||||||
|
|
Loading…
Reference in New Issue