Sending/Receiving encrypted messages barely works now

This commit is contained in:
Paul Schaub 2020-07-04 19:50:10 +02:00
parent 940a223563
commit 30e7bd46a7
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
11 changed files with 71 additions and 43 deletions

View File

@ -35,7 +35,7 @@
android:label="@string/title_activity_settings" /> android:label="@string/title_activity_settings" />
<activity android:name=".android.ui.roster.contacts.detail.ContactDetailActivity" /> <activity android:name=".android.ui.roster.contacts.detail.ContactDetailActivity" />
<service android:name=".android.service.MercuryConnectionService" /> <service android:name=".android.service.MercuryForegroundService" />
</application> </application>
</manifest> </manifest>

View File

@ -11,7 +11,7 @@ import org.mercury_im.messenger.core.data.repository.AccountRepository;
import org.mercury_im.messenger.android.di.component.AppComponent; import org.mercury_im.messenger.android.di.component.AppComponent;
import org.mercury_im.messenger.android.di.module.AppModule; import org.mercury_im.messenger.android.di.module.AppModule;
import org.mercury_im.messenger.entity.Account; import org.mercury_im.messenger.entity.Account;
import org.mercury_im.messenger.android.service.MercuryConnectionService; import org.mercury_im.messenger.android.service.MercuryForegroundService;
import org.mercury_im.messenger.core.xmpp.CsiManager; import org.mercury_im.messenger.core.xmpp.CsiManager;
import java.util.List; import java.util.List;
@ -23,11 +23,6 @@ import io.reactivex.disposables.CompositeDisposable;
public class MercuryImApplication extends Application { public class MercuryImApplication extends Application {
static {
// Initialize Smack etc.
// new MercuryConfiguration();
}
private static MercuryImApplication INSTANCE; private static MercuryImApplication INSTANCE;
private AppComponent appComponent; private AppComponent appComponent;
private ClientStateHandler clientStateHandler = new ClientStateHandler(); private ClientStateHandler clientStateHandler = new ClientStateHandler();
@ -105,8 +100,8 @@ public class MercuryImApplication extends Application {
} }
private void startForegroundService() { private void startForegroundService() {
Intent startIntent = new Intent(getApplicationContext(), MercuryConnectionService.class); Intent startIntent = new Intent(getApplicationContext(), MercuryForegroundService.class);
startIntent.setAction(MercuryConnectionService.ACTION_START); startIntent.setAction(MercuryForegroundService.ACTION_START);
if (Build.VERSION.SDK_INT < 26) { if (Build.VERSION.SDK_INT < 26) {
startService(startIntent); startService(startIntent);
} else { } else {
@ -115,8 +110,8 @@ public class MercuryImApplication extends Application {
} }
private void stopForegroundService() { private void stopForegroundService() {
Intent stopIntent = new Intent(getApplicationContext(), MercuryConnectionService.class); Intent stopIntent = new Intent(getApplicationContext(), MercuryForegroundService.class);
stopIntent.setAction(MercuryConnectionService.ACTION_STOP); stopIntent.setAction(MercuryForegroundService.ACTION_STOP);
startService(stopIntent); startService(stopIntent);
} }
} }

View File

@ -3,14 +3,13 @@ package org.mercury_im.messenger.android.di.component;
import org.mercury_im.messenger.android.MercuryImApplication; import org.mercury_im.messenger.android.MercuryImApplication;
import org.mercury_im.messenger.android.di.module.AndroidDatabaseModule; import org.mercury_im.messenger.android.di.module.AndroidDatabaseModule;
import org.mercury_im.messenger.android.di.module.AndroidSchedulersModule; import org.mercury_im.messenger.android.di.module.AndroidSchedulersModule;
import org.mercury_im.messenger.core.di.module.OpenPgpModule;
import org.mercury_im.messenger.core.di.module.RxMercuryMessageStoreFactoryModule; import org.mercury_im.messenger.core.di.module.RxMercuryMessageStoreFactoryModule;
import org.mercury_im.messenger.core.di.module.RxMercuryRosterStoreFactoryModule; import org.mercury_im.messenger.core.di.module.RxMercuryRosterStoreFactoryModule;
import org.mercury_im.messenger.core.di.module.XmppTcpConnectionFactoryModule; import org.mercury_im.messenger.core.di.module.XmppTcpConnectionFactoryModule;
import org.mercury_im.messenger.data.di.RepositoryModule; import org.mercury_im.messenger.data.di.RepositoryModule;
import org.mercury_im.messenger.android.di.module.AppModule; import org.mercury_im.messenger.android.di.module.AppModule;
import org.mercury_im.messenger.core.di.module.ViewModelModule; import org.mercury_im.messenger.core.di.module.ViewModelModule;
import org.mercury_im.messenger.android.service.MercuryConnectionService; import org.mercury_im.messenger.android.service.MercuryForegroundService;
import org.mercury_im.messenger.core.store.caps.MercuryEntityCapsStore; import org.mercury_im.messenger.core.store.caps.MercuryEntityCapsStore;
import org.mercury_im.messenger.android.ui.MainActivity; import org.mercury_im.messenger.android.ui.MainActivity;
import org.mercury_im.messenger.android.ui.account.AndroidAccountsViewModel; import org.mercury_im.messenger.android.ui.account.AndroidAccountsViewModel;
@ -90,7 +89,7 @@ public interface AppComponent {
// Services // Services
void inject(MercuryConnectionService service); void inject(MercuryForegroundService service);
void inject(MercuryEntityCapsStore store); void inject(MercuryEntityCapsStore store);
} }

View File

@ -10,21 +10,19 @@ import android.os.IBinder;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smackx.ping.android.ServerPingWithAlarmManager; import org.jivesoftware.smackx.ping.android.ServerPingWithAlarmManager;
import org.mercury_im.messenger.R;
import org.mercury_im.messenger.android.MercuryImApplication; import org.mercury_im.messenger.android.MercuryImApplication;
import org.mercury_im.messenger.android.Notifications; import org.mercury_im.messenger.android.Notifications;
import org.mercury_im.messenger.R;
import org.mercury_im.messenger.android.ui.MainActivity; import org.mercury_im.messenger.android.ui.MainActivity;
/** /**
* Started, Bound Service, which is responsible for managing {@link XMPPConnection XMPPConnections} * Started, Bound Service, which is responsible keeping the application alive when the app is not open.
* affiliated with registered accounts.
*/ */
public class MercuryConnectionService extends Service { public class MercuryForegroundService extends Service {
private static final String APP = "org.mercury-im.messenger"; private static final String APP = "org.mercury-im.messenger";
private static final String SERVICE = APP + ".MercuryConnectionService"; private static final String SERVICE = APP + ".MercuryForegroundService";
private static final String ACTION = SERVICE + ".ACTION"; private static final String ACTION = SERVICE + ".ACTION";
@ -105,13 +103,13 @@ public class MercuryConnectionService extends Service {
public class Binder extends android.os.Binder { public class Binder extends android.os.Binder {
private final MercuryConnectionService service; private final MercuryForegroundService service;
public Binder(MercuryConnectionService service) { public Binder(MercuryForegroundService service) {
this.service = service; this.service = service;
} }
public MercuryConnectionService getService() { public MercuryForegroundService getService() {
return service; return service;
} }
} }

View File

@ -133,7 +133,7 @@ public class AndroidChatViewModel extends ViewModel implements MercuryAndroidVie
} }
public void sendMessage(String body) { public void sendMessage(String body) {
disposable.add(messenger.sendMessage(getContact().getValue(), body) disposable.add(messenger.sendEncryptedMessage(getContact().getValue(), body)
.subscribeOn(schedulers.getIoScheduler()) .subscribeOn(schedulers.getIoScheduler())
.observeOn(schedulers.getUiScheduler()) .observeOn(schedulers.getUiScheduler())
.subscribe()); .subscribe());

View File

@ -61,7 +61,8 @@ public class ContactDetailViewModel extends ViewModel {
private MutableLiveData<String> contactName = new MutableLiveData<>("Alice Wonderland"); private MutableLiveData<String> contactName = new MutableLiveData<>("Alice Wonderland");
private MutableLiveData<String> contactAccountAddress = new MutableLiveData<>("mad@hatter.lit"); private MutableLiveData<String> contactAccountAddress = new MutableLiveData<>("mad@hatter.lit");
private MutableLiveData<List<String>> contactGroups = new MutableLiveData<>(Collections.emptyList()); private MutableLiveData<List<String>> contactGroups = new MutableLiveData<>(Collections.emptyList());
private MutableLiveData<List<OpenPgpV4Fingerprint>> contactFingerprints = new MutableLiveData<>(Collections.singletonList(new OpenPgpV4Fingerprint("1357B01865B2503C18453D208CAC2A9678548E35"))); private MutableLiveData<List<OpenPgpV4Fingerprint>> contactFingerprints =
new MutableLiveData<>(Collections.singletonList(new OpenPgpV4Fingerprint("1234567890ABCDEF1234567890ABCDEF01234567")));
private Roster roster; private Roster roster;

View File

@ -184,8 +184,8 @@ public class RxOpenPgpRepository implements OpenPgpRepository {
@Override @Override
public Observable<List<OpenPgpV4Fingerprint>> observeFingerprintsOf(UUID accountId, String peerAddress) { public Observable<List<OpenPgpV4Fingerprint>> observeFingerprintsOf(UUID accountId, String peerAddress) {
return data.select(OpenPgpPublicKeyRing.class) return data.select(OpenPgpPublicKeyRing.class)
//.where(OpenPgpPublicKeyRing.ACCOUNT_ID.eq(accountId)) .where(OpenPgpPublicKeyRing.ACCOUNT_ID.eq(accountId))
.where(OpenPgpPublicKeyRing.OWNER.eq(JidCreate.entityBareFromOrThrowUnchecked(peerAddress))) .and(OpenPgpPublicKeyRing.OWNER.eq(JidCreate.entityBareFromOrThrowUnchecked(peerAddress)))
.get().observableResult() .get().observableResult()
.map(result -> { .map(result -> {
OpenPgpPublicKeyRing model = new ResultDelegate<>(result).firstOrNull(); OpenPgpPublicKeyRing model = new ResultDelegate<>(result).firstOrNull();
@ -203,20 +203,17 @@ public class RxOpenPgpRepository implements OpenPgpRepository {
@Override @Override
public Single<Map<OpenPgpV4Fingerprint, Date>> loadPublicKeyFetchDates(UUID accountId, EntityBareJid owner) { public Single<Map<OpenPgpV4Fingerprint, Date>> loadPublicKeyFetchDates(UUID accountId, EntityBareJid owner) {
return data.select(OpenPgpKeyFetchDate.class) List<OpenPgpKeyFetchDate> fetchDates =
.where(OpenPgpKeyFetchDate.ACCOUNT_ID.eq(accountId)) data.select(OpenPgpKeyFetchDate.class)
.and(OpenPgpKeyFetchDate.OWNER.eq(owner)) .where(OpenPgpKeyFetchDate.ACCOUNT_ID.eq(accountId))
.get() .and(OpenPgpKeyFetchDate.OWNER.eq(owner))
.observableResult() .get()
.map(ResultDelegate::toList) .toList();
.single(Collections.emptyList())
.map(list -> { Map<OpenPgpV4Fingerprint, Date> map = new ConcurrentHashMap<>();
Map<OpenPgpV4Fingerprint, Date> map = new ConcurrentHashMap<>(); for (OpenPgpKeyFetchDate date : fetchDates) {
for (OpenPgpKeyFetchDate date : list) { map.put(date.getFingerprint(), date.getFetchDate());
map.put(date.getFingerprint(), date.getFetchDate()); }
} return Single.just(map);
return map;
})
.doOnError(e -> Logger.getLogger(RxOpenPgpRepository.class.getName()).log(Level.SEVERE, "Error observing public keys", e));
} }
} }

View File

@ -1,10 +1,14 @@
package org.mercury_im.messenger.core; package org.mercury_im.messenger.core;
import org.bouncycastle.openpgp.PGPException;
import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.chat2.ChatManager; import org.jivesoftware.smack.chat2.ChatManager;
import org.jivesoftware.smack.roster.Roster; import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smack.roster.RosterEntry; import org.jivesoftware.smack.roster.RosterEntry;
import org.jivesoftware.smackx.ox.OpenPgpContact;
import org.jivesoftware.smackx.ox.OpenPgpManager;
import org.jivesoftware.smackx.ox_im.OXInstantMessagingManager;
import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException; import org.jxmpp.stringprep.XmppStringprepException;
@ -14,7 +18,9 @@ import org.mercury_im.messenger.core.exception.ContactAlreadyAddedException;
import org.mercury_im.messenger.core.xmpp.MercuryConnection; import org.mercury_im.messenger.core.xmpp.MercuryConnection;
import org.mercury_im.messenger.core.xmpp.MercuryConnectionManager; import org.mercury_im.messenger.core.xmpp.MercuryConnectionManager;
import org.mercury_im.messenger.entity.contact.Peer; import org.mercury_im.messenger.entity.contact.Peer;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.io.IOException;
import java.util.UUID; import java.util.UUID;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -110,6 +116,24 @@ public class Messenger {
.send(body); .send(body);
} }
public Completable sendEncryptedMessage(Peer contact, String body) {
return Completable.fromAction(() -> doSendEncryptedMessage(contact, body));
}
public void doSendEncryptedMessage(Peer contact, String body) throws ConnectionNotFoundException,
InterruptedException, PGPException, SmackException.NotConnectedException,
SmackException.NotLoggedInException, IOException {
MercuryConnection connection = getConnection(contact.getAccount().getId());
OpenPgpManager oxManager = OpenPgpManager.getInstanceFor(connection.getConnection());
OXInstantMessagingManager oximManager = OXInstantMessagingManager.getInstanceFor(connection.getConnection());
OpenPgpContact oxContact = oxManager.getOpenPgpContact(contact.getJid());
for (OpenPgpV4Fingerprint fingerprint : oxContact.getUndecidedFingerprints()) {
oxContact.trust(fingerprint);
}
oxContact.getAnnouncedPublicKeys();
oximManager.sendOxMessage(oxManager.getOpenPgpContact(contact.getJid()), body);
}
private MercuryConnection getConnection(UUID accountId) throws ConnectionNotFoundException { private MercuryConnection getConnection(UUID accountId) throws ConnectionNotFoundException {
MercuryConnection connection = getConnectionManager().getConnection(accountId); MercuryConnection connection = getConnectionManager().getConnection(accountId);
if (connection == null) { if (connection == null) {

View File

@ -1,5 +1,7 @@
package org.mercury_im.messenger.core.crypto; package org.mercury_im.messenger.core.crypto;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.jivesoftware.smack.AbstractConnectionListener; import org.jivesoftware.smack.AbstractConnectionListener;
import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smackx.ox.OpenPgpManager; import org.jivesoftware.smackx.ox.OpenPgpManager;
@ -17,6 +19,7 @@ import org.mercury_im.messenger.core.data.repository.Repositories;
import org.mercury_im.messenger.core.store.crypto.MercuryOpenPgpStore; import org.mercury_im.messenger.core.store.crypto.MercuryOpenPgpStore;
import org.mercury_im.messenger.core.store.message.MercuryMessageStore; import org.mercury_im.messenger.core.store.message.MercuryMessageStore;
import org.mercury_im.messenger.core.xmpp.MercuryConnection; import org.mercury_im.messenger.core.xmpp.MercuryConnection;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -70,6 +73,10 @@ public class MercuryOpenPgpManager {
//() -> "RW8X-367S-A2C3-QYAL-VG6E-Z2IM"); //() -> "RW8X-367S-A2C3-QYAL-VG6E-Z2IM");
//() -> "KISJ-5Z1T-FGDW-WMDK-SC2U-SQUA"); //() -> "KISJ-5Z1T-FGDW-WMDK-SC2U-SQUA");
() -> "71ZA-Y416-UA7A-7NCE-3SNM-88EF"); () -> "71ZA-Y416-UA7A-7NCE-3SNM-88EF");
PGPPublicKeyRingCollection keys = oxManager.getOpenPgpSelf().getAnyPublicKeys();
for (PGPPublicKeyRing key : keys) {
oxManager.getOpenPgpSelf().trust(new OpenPgpV4Fingerprint(key));
}
LOGGER.log(Level.INFO, "Successfully restored secret key backup!"); LOGGER.log(Level.INFO, "Successfully restored secret key backup!");
} catch (NoBackupFoundException | PubSubException.NotALeafNodeException | InvalidBackupCodeException e) { } catch (NoBackupFoundException | PubSubException.NotALeafNodeException | InvalidBackupCodeException e) {
LOGGER.log(Level.INFO, "Error restoring secret key backup.", e); LOGGER.log(Level.INFO, "Error restoring secret key backup.", e);

View File

@ -4,6 +4,7 @@ import org.jivesoftware.smack.chat2.IncomingChatMessageListener;
import org.jivesoftware.smack.chat2.OutgoingChatMessageListener; import org.jivesoftware.smack.chat2.OutgoingChatMessageListener;
import org.jivesoftware.smack.packet.MessageBuilder; import org.jivesoftware.smack.packet.MessageBuilder;
import org.jivesoftware.smackx.delay.packet.DelayInformation; import org.jivesoftware.smackx.delay.packet.DelayInformation;
import org.jivesoftware.smackx.eme.element.ExplicitMessageEncryptionElement;
import org.jivesoftware.smackx.ox.OpenPgpContact; import org.jivesoftware.smackx.ox.OpenPgpContact;
import org.jivesoftware.smackx.ox.element.SigncryptElement; import org.jivesoftware.smackx.ox.element.SigncryptElement;
import org.jivesoftware.smackx.ox_im.OxMessageListener; import org.jivesoftware.smackx.ox_im.OxMessageListener;
@ -58,6 +59,9 @@ public class MercuryMessageStore implements IncomingChatMessageListener, Outgoin
public void newIncomingMessage(EntityBareJid from, public void newIncomingMessage(EntityBareJid from,
org.jivesoftware.smack.packet.Message smackMessage, org.jivesoftware.smack.packet.Message smackMessage,
org.jivesoftware.smack.chat2.Chat smackChat) { org.jivesoftware.smack.chat2.Chat smackChat) {
if (ExplicitMessageEncryptionElement.from(smackMessage) != null) {
return;
}
Message message = new Message(); Message message = new Message();
message.setDirection(MessageDirection.incoming); message.setDirection(MessageDirection.incoming);
DelayInformation delayInformation = DelayInformation.from(smackMessage); DelayInformation delayInformation = DelayInformation.from(smackMessage);
@ -74,6 +78,9 @@ public class MercuryMessageStore implements IncomingChatMessageListener, Outgoin
public void newOutgoingMessage(EntityBareJid to, public void newOutgoingMessage(EntityBareJid to,
MessageBuilder smackMessage, MessageBuilder smackMessage,
org.jivesoftware.smack.chat2.Chat smackChat) { org.jivesoftware.smack.chat2.Chat smackChat) {
if (smackMessage.hasExtension(ExplicitMessageEncryptionElement.QNAME)) {
return;
}
Message message = new Message(); Message message = new Message();
message.setDirection(MessageDirection.outgoing); message.setDirection(MessageDirection.outgoing);
message.setTimestamp(new Date()); message.setTimestamp(new Date());

View File

@ -82,7 +82,7 @@ public class MercuryConnectionManager {
this.cryptoManager = cryptoManager; this.cryptoManager = cryptoManager;
this.schedulers = schedulers; this.schedulers = schedulers;
//EntityCapsManager.setPersistentCache(entityCapsStore); EntityCapsManager.setPersistentCache(entityCapsStore);
start(); start();
} }