Store and restore OX keys
This commit is contained in:
parent
61de3cb22c
commit
f208a9f769
|
@ -3,6 +3,7 @@ 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;
|
||||||
|
@ -43,7 +44,8 @@ import dagger.Component;
|
||||||
ViewModelModule.class,
|
ViewModelModule.class,
|
||||||
XmppTcpConnectionFactoryModule.class,
|
XmppTcpConnectionFactoryModule.class,
|
||||||
RxMercuryMessageStoreFactoryModule.class,
|
RxMercuryMessageStoreFactoryModule.class,
|
||||||
RxMercuryRosterStoreFactoryModule.class
|
RxMercuryRosterStoreFactoryModule.class,
|
||||||
|
OpenPgpModule.class
|
||||||
})
|
})
|
||||||
public interface AppComponent {
|
public interface AppComponent {
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import org.mercury_im.messenger.core.data.repository.DirectChatRepository;
|
||||||
import org.mercury_im.messenger.core.data.repository.EntityCapsRepository;
|
import org.mercury_im.messenger.core.data.repository.EntityCapsRepository;
|
||||||
import org.mercury_im.messenger.core.data.repository.GroupChatRepository;
|
import org.mercury_im.messenger.core.data.repository.GroupChatRepository;
|
||||||
import org.mercury_im.messenger.core.data.repository.MessageRepository;
|
import org.mercury_im.messenger.core.data.repository.MessageRepository;
|
||||||
|
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
|
||||||
import org.mercury_im.messenger.core.data.repository.PeerRepository;
|
import org.mercury_im.messenger.core.data.repository.PeerRepository;
|
||||||
import org.mercury_im.messenger.core.data.repository.Repositories;
|
import org.mercury_im.messenger.core.data.repository.Repositories;
|
||||||
import org.mercury_im.messenger.data.mapping.AccountMapping;
|
import org.mercury_im.messenger.data.mapping.AccountMapping;
|
||||||
|
@ -18,6 +19,7 @@ import org.mercury_im.messenger.data.repository.RxDirectChatRepository;
|
||||||
import org.mercury_im.messenger.data.repository.RxEntityCapsRepository;
|
import org.mercury_im.messenger.data.repository.RxEntityCapsRepository;
|
||||||
import org.mercury_im.messenger.data.repository.RxGroupChatRepository;
|
import org.mercury_im.messenger.data.repository.RxGroupChatRepository;
|
||||||
import org.mercury_im.messenger.data.repository.RxMessageRepository;
|
import org.mercury_im.messenger.data.repository.RxMessageRepository;
|
||||||
|
import org.mercury_im.messenger.data.repository.RxOpenPgpRepository;
|
||||||
import org.mercury_im.messenger.data.repository.RxPeerRepository;
|
import org.mercury_im.messenger.data.repository.RxPeerRepository;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
@ -84,6 +86,13 @@ public class RepositoryModule {
|
||||||
return new RxEntityCapsRepository(data, entityCapsMapping);
|
return new RxEntityCapsRepository(data, entityCapsMapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
static OpenPgpRepository provideOpenPgpRepository(
|
||||||
|
ReactiveEntityStore<Persistable> data) {
|
||||||
|
return new RxOpenPgpRepository(data);
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
static Repositories provideRepositories(
|
static Repositories provideRepositories(
|
||||||
|
@ -92,8 +101,9 @@ public class RepositoryModule {
|
||||||
GroupChatRepository groupChatRepository,
|
GroupChatRepository groupChatRepository,
|
||||||
MessageRepository messageRepository,
|
MessageRepository messageRepository,
|
||||||
PeerRepository peerRepository,
|
PeerRepository peerRepository,
|
||||||
RxEntityCapsRepository entityCapsRepository) {
|
EntityCapsRepository entityCapsRepository,
|
||||||
|
OpenPgpRepository openPgpRepository) {
|
||||||
return new Repositories(accountRepository, directChatRepository, groupChatRepository,
|
return new Repositories(accountRepository, directChatRepository, groupChatRepository,
|
||||||
messageRepository, peerRepository, entityCapsRepository);
|
messageRepository, peerRepository, entityCapsRepository, openPgpRepository);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
package org.mercury_im.messenger.data.model;
|
||||||
|
|
||||||
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
|
import org.mercury_im.messenger.data.converter.EntityBareJidConverter;
|
||||||
|
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.requery.Column;
|
||||||
|
import io.requery.Convert;
|
||||||
|
import io.requery.Entity;
|
||||||
|
import io.requery.Key;
|
||||||
|
import io.requery.Table;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "ox_key_fetch_dates")
|
||||||
|
public class AbstractOpenPgpKeyFetchDates {
|
||||||
|
|
||||||
|
@Key
|
||||||
|
@Column(name = "owner")
|
||||||
|
@Convert(EntityBareJidConverter.class)
|
||||||
|
EntityBareJid owner;
|
||||||
|
|
||||||
|
@Column(name = "fetch_dates")
|
||||||
|
Map<OpenPgpV4Fingerprint, Date> fetchDates;
|
||||||
|
}
|
|
@ -2,41 +2,18 @@ package org.mercury_im.messenger.data.model;
|
||||||
|
|
||||||
import org.jxmpp.jid.EntityBareJid;
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.mercury_im.messenger.data.converter.EntityBareJidConverter;
|
import org.mercury_im.messenger.data.converter.EntityBareJidConverter;
|
||||||
import org.mercury_im.messenger.data.converter.OpenPgpV4FingerprintConverter;
|
|
||||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import io.requery.CascadeAction;
|
|
||||||
import io.requery.Column;
|
import io.requery.Column;
|
||||||
import io.requery.Convert;
|
import io.requery.Convert;
|
||||||
import io.requery.Entity;
|
import io.requery.Entity;
|
||||||
import io.requery.ForeignKey;
|
|
||||||
import io.requery.Index;
|
|
||||||
import io.requery.Key;
|
import io.requery.Key;
|
||||||
import io.requery.ManyToOne;
|
|
||||||
import io.requery.Table;
|
import io.requery.Table;
|
||||||
import io.requery.converter.UUIDConverter;
|
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "ox_public_keys")
|
@Table(name = "ox_public_keys")
|
||||||
public class AbstractOpenPgpPublicKeyRing {
|
public class AbstractOpenPgpPublicKeyRing {
|
||||||
|
|
||||||
@Key
|
@Key
|
||||||
@Convert(UUIDConverter.class)
|
|
||||||
UUID id;
|
|
||||||
|
|
||||||
@Index("unique_address")
|
|
||||||
@ManyToOne(cascade = CascadeAction.NONE)
|
|
||||||
@ForeignKey(referencedColumn = "id")
|
|
||||||
AccountModel account;
|
|
||||||
|
|
||||||
@Column(name = "key_id", nullable = false)
|
|
||||||
long keyId;
|
|
||||||
|
|
||||||
@Column(name = "fingerprint", nullable = false)
|
|
||||||
@Convert(OpenPgpV4FingerprintConverter.class)
|
|
||||||
OpenPgpV4Fingerprint fingerprint;
|
|
||||||
|
|
||||||
@Column(name = "owner", nullable = false)
|
@Column(name = "owner", nullable = false)
|
||||||
@Convert(EntityBareJidConverter.class)
|
@Convert(EntityBareJidConverter.class)
|
||||||
EntityBareJid owner;
|
EntityBareJid owner;
|
||||||
|
|
|
@ -2,41 +2,18 @@ package org.mercury_im.messenger.data.model;
|
||||||
|
|
||||||
import org.jxmpp.jid.EntityBareJid;
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.mercury_im.messenger.data.converter.EntityBareJidConverter;
|
import org.mercury_im.messenger.data.converter.EntityBareJidConverter;
|
||||||
import org.mercury_im.messenger.data.converter.OpenPgpV4FingerprintConverter;
|
|
||||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import io.requery.CascadeAction;
|
|
||||||
import io.requery.Column;
|
import io.requery.Column;
|
||||||
import io.requery.Convert;
|
import io.requery.Convert;
|
||||||
import io.requery.Entity;
|
import io.requery.Entity;
|
||||||
import io.requery.ForeignKey;
|
|
||||||
import io.requery.Index;
|
|
||||||
import io.requery.Key;
|
import io.requery.Key;
|
||||||
import io.requery.ManyToOne;
|
|
||||||
import io.requery.Table;
|
import io.requery.Table;
|
||||||
import io.requery.converter.UUIDConverter;
|
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "ox_secret_keys")
|
@Table(name = "ox_secret_keys")
|
||||||
public class AbstractOpenPgpSecretKeyRing {
|
public class AbstractOpenPgpSecretKeyRing {
|
||||||
|
|
||||||
@Key
|
@Key
|
||||||
@Convert(UUIDConverter.class)
|
|
||||||
UUID id;
|
|
||||||
|
|
||||||
@Index("unique_address")
|
|
||||||
@ManyToOne(cascade = CascadeAction.NONE)
|
|
||||||
@ForeignKey(referencedColumn = "id")
|
|
||||||
AccountModel account;
|
|
||||||
|
|
||||||
@Column(name = "key_id", nullable = false)
|
|
||||||
long keyId;
|
|
||||||
|
|
||||||
@Column(name = "fingerprint", nullable = false)
|
|
||||||
@Convert(OpenPgpV4FingerprintConverter.class)
|
|
||||||
OpenPgpV4Fingerprint fingerprint;
|
|
||||||
|
|
||||||
@Column(name = "owner", nullable = false)
|
@Column(name = "owner", nullable = false)
|
||||||
@Convert(EntityBareJidConverter.class)
|
@Convert(EntityBareJidConverter.class)
|
||||||
EntityBareJid owner;
|
EntityBareJid owner;
|
||||||
|
|
|
@ -1,53 +1,78 @@
|
||||||
package org.mercury_im.messenger.data.repository;
|
package org.mercury_im.messenger.data.repository;
|
||||||
|
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||||
import org.jxmpp.jid.EntityBareJid;
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
|
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
|
||||||
import org.mercury_im.messenger.data.model.OpenPgpPublicKeyRing;
|
import org.mercury_im.messenger.data.model.OpenPgpPublicKeyRing;
|
||||||
import org.mercury_im.messenger.data.model.OpenPgpSecretKeyRing;
|
import org.mercury_im.messenger.data.model.OpenPgpSecretKeyRing;
|
||||||
import org.pgpainless.PGPainless;
|
import org.pgpainless.PGPainless;
|
||||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import io.reactivex.Completable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
import io.requery.Persistable;
|
import io.requery.Persistable;
|
||||||
import io.requery.query.ResultDelegate;
|
|
||||||
import io.requery.reactivex.ReactiveEntityStore;
|
import io.requery.reactivex.ReactiveEntityStore;
|
||||||
|
|
||||||
public class RxOpenPgpRepository implements OpenPgpRepository {
|
public class RxOpenPgpRepository implements OpenPgpRepository {
|
||||||
|
|
||||||
private final ReactiveEntityStore<Persistable> data;
|
private final ReactiveEntityStore<Persistable> data;
|
||||||
|
|
||||||
|
@Inject
|
||||||
public RxOpenPgpRepository(ReactiveEntityStore<Persistable> data) {
|
public RxOpenPgpRepository(ReactiveEntityStore<Persistable> data) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Single<PGPPublicKeyRingCollection> loadPublicKeysOfContact(UUID accountId, EntityBareJid jid) {
|
public Completable storePublicKeysOf(EntityBareJid owner, PGPPublicKeyRingCollection keys) {
|
||||||
return data.select(OpenPgpPublicKeyRing.class)
|
return Single.fromCallable(() -> {
|
||||||
.where(OpenPgpPublicKeyRing.ACCOUNT_ID.eq(accountId))
|
OpenPgpPublicKeyRing keyRing = new OpenPgpPublicKeyRing();
|
||||||
.and(OpenPgpPublicKeyRing.OWNER.eq(jid))
|
keyRing.setOwner(owner);
|
||||||
.get().observableResult()
|
keyRing.setBytes(keys.getEncoded());
|
||||||
.map(ResultDelegate::toList)
|
return keyRing;
|
||||||
.map(keys -> PGPainless.readKeyRing().publicKeyRing(keys.get(0).getBytes()).)
|
}).flatMap(data::upsert).ignoreElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Single<Integer> deletePublicKeyRing(UUID accountId, EntityBareJid jid, OpenPgpV4Fingerprint fingerprint) {
|
public Single<PGPPublicKeyRingCollection> loadPublicKeysOf(EntityBareJid owner) {
|
||||||
|
return data.select(OpenPgpPublicKeyRing.class)
|
||||||
|
.where(OpenPgpPublicKeyRing.OWNER.eq(owner))
|
||||||
|
.limit(1).get()
|
||||||
|
.maybe().toSingle()
|
||||||
|
.map(keyring -> PGPainless.readKeyRing().publicKeyRingCollection(keyring.getBytes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Single<Integer> deletePublicKeysOf(EntityBareJid owner) {
|
||||||
return data.delete(OpenPgpPublicKeyRing.class)
|
return data.delete(OpenPgpPublicKeyRing.class)
|
||||||
.where(OpenPgpPublicKeyRing.ACCOUNT_ID.eq(accountId))
|
.where(OpenPgpPublicKeyRing.OWNER.eq(owner))
|
||||||
.and(OpenPgpPublicKeyRing.OWNER.eq(jid))
|
|
||||||
.and(OpenPgpPublicKeyRing.FINGERPRINT.eq(fingerprint))
|
|
||||||
.get().single();
|
.get().single();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Single<Integer> deleteSecretKeyRing(UUID accountId, EntityBareJid jid, OpenPgpV4Fingerprint fingerprint) {
|
public Completable storeSecretKeysOf(EntityBareJid owner, PGPSecretKeyRingCollection keys) {
|
||||||
|
return Single.fromCallable(() -> {
|
||||||
|
OpenPgpSecretKeyRing keyRing = new OpenPgpSecretKeyRing();
|
||||||
|
keyRing.setOwner(owner);
|
||||||
|
keyRing.setBytes(keys.getEncoded());
|
||||||
|
return keyRing;
|
||||||
|
}).flatMap(data::upsert).ignoreElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Single<PGPSecretKeyRingCollection> loadSecretKeysOf(EntityBareJid owner) {
|
||||||
|
return data.select(OpenPgpSecretKeyRing.class)
|
||||||
|
.where(OpenPgpSecretKeyRing.OWNER.eq(owner))
|
||||||
|
.limit(1).get()
|
||||||
|
.maybe().toSingle()
|
||||||
|
.map(keyring -> PGPainless.readKeyRing().secretKeyRingCollection(keyring.getBytes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Single<Integer> deleteSecretKeysOf(EntityBareJid owner) {
|
||||||
return data.delete(OpenPgpSecretKeyRing.class)
|
return data.delete(OpenPgpSecretKeyRing.class)
|
||||||
.where(OpenPgpSecretKeyRing.ACCOUNT_ID.eq(accountId))
|
.where(OpenPgpPublicKeyRing.OWNER.eq(owner))
|
||||||
.and(OpenPgpPublicKeyRing.OWNER.eq(jid))
|
|
||||||
.and(OpenPgpSecretKeyRing.FINGERPRINT.eq(fingerprint))
|
|
||||||
.get().single();
|
.get().single();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
package org.mercury_im.messenger.core.crypto;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.AbstractConnectionListener;
|
||||||
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
|
import org.jivesoftware.smackx.ox.OpenPgpManager;
|
||||||
|
import org.jivesoftware.smackx.ox.crypto.OpenPgpProvider;
|
||||||
|
import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException;
|
||||||
|
import org.jivesoftware.smackx.ox.exception.NoBackupFoundException;
|
||||||
|
import org.jivesoftware.smackx.ox_im.OXInstantMessagingManager;
|
||||||
|
import org.jivesoftware.smackx.pubsub.PubSubException;
|
||||||
|
import org.mercury_im.messenger.core.xmpp.MercuryConnection;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
public class MercuryOpenPgpManager {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(MercuryOpenPgpManager.class.getName());
|
||||||
|
|
||||||
|
private final OpenPgpProvider openPgpProvider;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public MercuryOpenPgpManager(OpenPgpProvider openPgpProvider) {
|
||||||
|
this.openPgpProvider = openPgpProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initialize(MercuryConnection connection) {
|
||||||
|
if (connection.getConnection().isAuthenticated()) {
|
||||||
|
setup(connection);
|
||||||
|
} else {
|
||||||
|
connection.getConnection().addConnectionListener(new AbstractConnectionListener() {
|
||||||
|
@Override
|
||||||
|
public void authenticated(XMPPConnection con, boolean resumed) {
|
||||||
|
if (!resumed) {
|
||||||
|
setup(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setup(MercuryConnection connection) {
|
||||||
|
try {
|
||||||
|
OpenPgpManager oxManager = OpenPgpManager.getInstanceFor(connection.getConnection());
|
||||||
|
oxManager.setOpenPgpProvider(openPgpProvider);
|
||||||
|
if (!oxManager.hasSecretKeysAvailable()) {
|
||||||
|
try {
|
||||||
|
oxManager.restoreSecretKeyServerBackup(
|
||||||
|
//() -> "RW8X-367S-A2C3-QYAL-VG6E-Z2IM");
|
||||||
|
() -> "KISJ-5Z1T-FGDW-WMDK-SC2U-SQUA");
|
||||||
|
LOGGER.log(Level.INFO, "Successfully restored secret key backup!");
|
||||||
|
} catch (NoBackupFoundException | PubSubException.NotALeafNodeException | InvalidBackupCodeException e) {
|
||||||
|
LOGGER.log(Level.INFO, "Error restoring secret key backup.", e);
|
||||||
|
oxManager.generateAndImportKeyPair(connection.getAccount().getJid());
|
||||||
|
oxManager.backupSecretKeyToServer(
|
||||||
|
backupCode -> LOGGER.log(Level.INFO, "OpenPGP Backup Code: " + backupCode),
|
||||||
|
availableSecretKeys -> availableSecretKeys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oxManager.announceSupportAndPublish();
|
||||||
|
OXInstantMessagingManager oximManager = OXInstantMessagingManager.getInstanceFor(connection.getConnection());
|
||||||
|
oximManager.announceSupportForOxInstantMessaging();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,18 +1,23 @@
|
||||||
package org.mercury_im.messenger.core.data.repository;
|
package org.mercury_im.messenger.core.data.repository;
|
||||||
|
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||||
import org.jxmpp.jid.EntityBareJid;
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
|
import io.reactivex.Completable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
|
|
||||||
public interface OpenPgpRepository {
|
public interface OpenPgpRepository {
|
||||||
|
|
||||||
Single<PGPPublicKeyRingCollection> loadPublicKeysOfContact(UUID accountId, EntityBareJid jid);
|
Completable storePublicKeysOf(EntityBareJid owner, PGPPublicKeyRingCollection keys);
|
||||||
|
|
||||||
Single<Integer> deletePublicKeyRing(UUID accountId, EntityBareJid jid, OpenPgpV4Fingerprint fingerprint);
|
Single<PGPPublicKeyRingCollection> loadPublicKeysOf(EntityBareJid owner);
|
||||||
|
|
||||||
Single<Integer> deleteSecretKeyRing(UUID accountId, EntityBareJid jid, OpenPgpV4Fingerprint fingerprint);
|
Single<Integer> deletePublicKeysOf(EntityBareJid owner);
|
||||||
|
|
||||||
|
Completable storeSecretKeysOf(EntityBareJid owner, PGPSecretKeyRingCollection keys);
|
||||||
|
|
||||||
|
Single<PGPSecretKeyRingCollection> loadSecretKeysOf(EntityBareJid owner);
|
||||||
|
|
||||||
|
Single<Integer> deleteSecretKeysOf(EntityBareJid owner);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,15 +3,19 @@ package org.mercury_im.messenger.core.data.repository;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
|
@Value
|
||||||
public class Repositories {
|
public class Repositories {
|
||||||
|
|
||||||
private final AccountRepository accountRepository;
|
AccountRepository accountRepository;
|
||||||
private final DirectChatRepository directChatRepository;
|
DirectChatRepository directChatRepository;
|
||||||
private final GroupChatRepository groupChatRepository;
|
GroupChatRepository groupChatRepository;
|
||||||
private final MessageRepository messageRepository;
|
MessageRepository messageRepository;
|
||||||
private final PeerRepository peerRepository;
|
PeerRepository peerRepository;
|
||||||
private final EntityCapsRepository entityCapsRepository;
|
EntityCapsRepository entityCapsRepository;
|
||||||
|
OpenPgpRepository openPgpRepository;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public Repositories(AccountRepository accountRepository,
|
public Repositories(AccountRepository accountRepository,
|
||||||
|
@ -19,36 +23,14 @@ public class Repositories {
|
||||||
GroupChatRepository groupChatRepository,
|
GroupChatRepository groupChatRepository,
|
||||||
MessageRepository messageRepository,
|
MessageRepository messageRepository,
|
||||||
PeerRepository peerRepository,
|
PeerRepository peerRepository,
|
||||||
EntityCapsRepository entityCapsRepository) {
|
EntityCapsRepository entityCapsRepository,
|
||||||
|
OpenPgpRepository openPgpRepository) {
|
||||||
this.accountRepository = accountRepository;
|
this.accountRepository = accountRepository;
|
||||||
this.directChatRepository = directChatRepository;
|
this.directChatRepository = directChatRepository;
|
||||||
this.groupChatRepository = groupChatRepository;
|
this.groupChatRepository = groupChatRepository;
|
||||||
this.messageRepository = messageRepository;
|
this.messageRepository = messageRepository;
|
||||||
this.peerRepository = peerRepository;
|
this.peerRepository = peerRepository;
|
||||||
this.entityCapsRepository = entityCapsRepository;
|
this.entityCapsRepository = entityCapsRepository;
|
||||||
}
|
this.openPgpRepository = openPgpRepository;
|
||||||
|
|
||||||
public AccountRepository getAccountRepository() {
|
|
||||||
return accountRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DirectChatRepository getDirectChatRepository() {
|
|
||||||
return directChatRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GroupChatRepository getGroupChatRepository() {
|
|
||||||
return groupChatRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MessageRepository getMessageRepository() {
|
|
||||||
return messageRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PeerRepository getPeerRepository() {
|
|
||||||
return peerRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntityCapsRepository getEntityCapsRepository() {
|
|
||||||
return entityCapsRepository;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package org.mercury_im.messenger.core.di.module;
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.ox.crypto.OpenPgpProvider;
|
||||||
|
import org.jivesoftware.smackx.ox.crypto.PainlessOpenPgpProvider;
|
||||||
|
import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore;
|
||||||
|
import org.mercury_im.messenger.core.SchedulersFacade;
|
||||||
|
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
|
||||||
|
import org.mercury_im.messenger.core.store.crypto.MercuryOpenPgpStore;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class OpenPgpModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
static OpenPgpStore provideOpenPgpStore(OpenPgpRepository openPgpRepository, SchedulersFacade schedulersFacade) {
|
||||||
|
return new MercuryOpenPgpStore(openPgpRepository, schedulersFacade);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
static OpenPgpProvider provideOpenPgpProvider(OpenPgpStore openPgpStore) {
|
||||||
|
return new PainlessOpenPgpProvider(openPgpStore);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,136 +1,106 @@
|
||||||
package org.mercury_im.messenger.core.store.crypto;
|
package org.mercury_im.messenger.core.store.crypto;
|
||||||
|
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpContact;
|
import org.jivesoftware.smackx.ox.store.abstr.AbstractOpenPgpKeyStore;
|
||||||
import org.jivesoftware.smackx.ox.callback.SecretKeyPassphraseCallback;
|
import org.jivesoftware.smackx.ox.store.abstr.AbstractOpenPgpMetadataStore;
|
||||||
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException;
|
import org.jivesoftware.smackx.ox.store.abstr.AbstractOpenPgpStore;
|
||||||
import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore;
|
import org.jivesoftware.smackx.ox.store.abstr.AbstractOpenPgpTrustStore;
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
|
import org.mercury_im.messenger.core.SchedulersFacade;
|
||||||
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
|
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
|
||||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||||
import org.pgpainless.key.collection.PGPKeyRing;
|
|
||||||
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
|
||||||
import org.pgpainless.key.protection.UnprotectedKeysProtector;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.NoSuchProviderException;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
public class MercuryOpenPgpStore implements OpenPgpStore {
|
public class MercuryOpenPgpStore extends AbstractOpenPgpStore {
|
||||||
|
|
||||||
private final UUID accountId;
|
private final OpenPgpRepository repository;
|
||||||
private SecretKeyRingProtector keyRingProtector;
|
private final SchedulersFacade schedulers;
|
||||||
private SecretKeyPassphraseCallback passphraseCallback;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
OpenPgpRepository repository;
|
public MercuryOpenPgpStore(OpenPgpRepository repository, SchedulersFacade schedulers) {
|
||||||
|
super(new AbstractOpenPgpKeyStore() {
|
||||||
|
@Override
|
||||||
|
protected PGPPublicKeyRingCollection readPublicKeysOf(BareJid owner)
|
||||||
|
throws IOException, PGPException {
|
||||||
|
try {
|
||||||
|
return repository.loadPublicKeysOf(owner.asEntityBareJidIfPossible())
|
||||||
|
.blockingGet();
|
||||||
|
} catch (NoSuchElementException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public MercuryOpenPgpStore(UUID accountId) {
|
@Override
|
||||||
this.accountId = accountId;
|
protected void writePublicKeysOf(BareJid owner, PGPPublicKeyRingCollection publicKeys)
|
||||||
}
|
throws IOException {
|
||||||
|
repository.storePublicKeysOf(owner.asEntityBareJidIfPossible(), publicKeys)
|
||||||
|
.subscribeOn(schedulers.getIoScheduler()).subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OpenPgpContact getOpenPgpContact(BareJid contactsJid) {
|
protected PGPSecretKeyRingCollection readSecretKeysOf(BareJid owner)
|
||||||
return null;
|
throws IOException, PGPException {
|
||||||
}
|
try {
|
||||||
|
return repository.loadSecretKeysOf(owner.asEntityBareJidIfPossible())
|
||||||
|
.blockingGet();
|
||||||
|
} catch (NoSuchElementException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setKeyRingProtector(SecretKeyRingProtector unlocker) {
|
protected void writeSecretKeysOf(BareJid owner, PGPSecretKeyRingCollection secretKeys)
|
||||||
this.keyRingProtector = unlocker;
|
throws IOException {
|
||||||
}
|
repository.storeSecretKeysOf(owner.asEntityBareJidIfPossible(), secretKeys)
|
||||||
|
.subscribeOn(schedulers.getIoScheduler()).subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SecretKeyRingProtector getKeyRingProtector() {
|
protected Map<OpenPgpV4Fingerprint, Date> readKeyFetchDates(BareJid owner)
|
||||||
return keyRingProtector;
|
throws IOException {
|
||||||
}
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSecretKeyPassphraseCallback(SecretKeyPassphraseCallback callback) {
|
protected void writeKeyFetchDates(BareJid owner, Map<OpenPgpV4Fingerprint, Date> dates)
|
||||||
passphraseCallback = callback;
|
throws IOException {
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
}
|
||||||
public PGPPublicKeyRingCollection getPublicKeysOf(BareJid owner) throws IOException, PGPException {
|
}, new AbstractOpenPgpMetadataStore() {
|
||||||
return null;
|
@Override
|
||||||
}
|
protected Map<OpenPgpV4Fingerprint, Date> readAnnouncedFingerprintsOf(BareJid contact)
|
||||||
|
throws IOException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PGPSecretKeyRingCollection getSecretKeysOf(BareJid owner) throws IOException, PGPException {
|
protected void writeAnnouncedFingerprintsOf(BareJid contact, Map<OpenPgpV4Fingerprint, Date> metadata)
|
||||||
return null;
|
throws IOException {
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
}
|
||||||
public PGPPublicKeyRing getPublicKeyRing(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException, PGPException {
|
}, new AbstractOpenPgpTrustStore() {
|
||||||
return null;
|
@Override
|
||||||
}
|
protected Trust readTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint)
|
||||||
|
throws IOException {
|
||||||
|
return Trust.trusted;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PGPSecretKeyRing getSecretKeyRing(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException, PGPException {
|
protected void writeTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint, Trust trust)
|
||||||
return null;
|
throws IOException {
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deletePublicKeyRing(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException, PGPException {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteSecretKeyRing(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException, PGPException {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PGPKeyRing generateKeyRing(BareJid owner) throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void importSecretKey(BareJid owner, PGPSecretKeyRing secretKeys) throws IOException, PGPException, MissingUserIdOnKeyException {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void importPublicKey(BareJid owner, PGPPublicKeyRing publicKeys) throws IOException, PGPException, MissingUserIdOnKeyException {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<OpenPgpV4Fingerprint, Date> getPublicKeyFetchDates(BareJid contact) throws IOException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPublicKeyFetchDates(BareJid contact, Map<OpenPgpV4Fingerprint, Date> dates) throws IOException {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<OpenPgpV4Fingerprint, Date> getAnnouncedFingerprintsOf(BareJid contact) throws IOException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAnnouncedFingerprintsOf(BareJid contact, Map<OpenPgpV4Fingerprint, Date> data) throws IOException {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Trust getTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint, Trust trust) throws IOException {
|
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.repository = repository;
|
||||||
|
this.schedulers = schedulers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ public class MercuryMessageStore implements IncomingChatMessageListener, Outgoin
|
||||||
message.setSender(account.getAddress());
|
message.setSender(account.getAddress());
|
||||||
message.setRecipient(to.asBareJid().toString());
|
message.setRecipient(to.asBareJid().toString());
|
||||||
if (smackMessage.getBody() != null) {
|
if (smackMessage.getBody() != null) {
|
||||||
message.setBody(smackMessage.getBody().getMessage());
|
message.setBody(smackMessage.getBody());
|
||||||
}
|
}
|
||||||
disposable.add(writeMessageToStore(to.asEntityBareJidString(), message));
|
disposable.add(writeMessageToStore(to.asEntityBareJidString(), message));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package org.mercury_im.messenger.core.xmpp;
|
||||||
import org.jivesoftware.smack.chat2.ChatManager;
|
import org.jivesoftware.smack.chat2.ChatManager;
|
||||||
import org.jivesoftware.smackx.caps.EntityCapsManager;
|
import org.jivesoftware.smackx.caps.EntityCapsManager;
|
||||||
import org.mercury_im.messenger.core.SchedulersFacade;
|
import org.mercury_im.messenger.core.SchedulersFacade;
|
||||||
|
import org.mercury_im.messenger.core.crypto.MercuryOpenPgpManager;
|
||||||
import org.mercury_im.messenger.core.data.repository.AccountRepository;
|
import org.mercury_im.messenger.core.data.repository.AccountRepository;
|
||||||
import org.mercury_im.messenger.core.data.repository.DirectChatRepository;
|
import org.mercury_im.messenger.core.data.repository.DirectChatRepository;
|
||||||
import org.mercury_im.messenger.core.data.repository.MessageRepository;
|
import org.mercury_im.messenger.core.data.repository.MessageRepository;
|
||||||
|
@ -48,6 +49,7 @@ public class MercuryConnectionManager {
|
||||||
private final PeerRepository peerRepository;
|
private final PeerRepository peerRepository;
|
||||||
private final DirectChatRepository directChatRepository;
|
private final DirectChatRepository directChatRepository;
|
||||||
private final MessageRepository messageRepository;
|
private final MessageRepository messageRepository;
|
||||||
|
private final MercuryOpenPgpManager cryptoManager;
|
||||||
private final SchedulersFacade schedulers;
|
private final SchedulersFacade schedulers;
|
||||||
|
|
||||||
private final Map<UUID, MercuryConnection> connectionsMap = new ConcurrentHashMap<>();
|
private final Map<UUID, MercuryConnection> connectionsMap = new ConcurrentHashMap<>();
|
||||||
|
@ -67,6 +69,7 @@ public class MercuryConnectionManager {
|
||||||
MercuryEntityCapsStore entityCapsStore,
|
MercuryEntityCapsStore entityCapsStore,
|
||||||
MercuryMessageStoreFactory messageStoreFactory,
|
MercuryMessageStoreFactory messageStoreFactory,
|
||||||
XmppConnectionFactory connectionFactory,
|
XmppConnectionFactory connectionFactory,
|
||||||
|
MercuryOpenPgpManager cryptoManager,
|
||||||
SchedulersFacade schedulers) {
|
SchedulersFacade schedulers) {
|
||||||
this.accountRepository = repositories.getAccountRepository();
|
this.accountRepository = repositories.getAccountRepository();
|
||||||
this.rosterStoreBinder = rosterStoreBinder;
|
this.rosterStoreBinder = rosterStoreBinder;
|
||||||
|
@ -76,6 +79,7 @@ public class MercuryConnectionManager {
|
||||||
this.messageRepository = repositories.getMessageRepository();
|
this.messageRepository = repositories.getMessageRepository();
|
||||||
this.connectionFactory = connectionFactory;
|
this.connectionFactory = connectionFactory;
|
||||||
this.messageStoreFactory = messageStoreFactory;
|
this.messageStoreFactory = messageStoreFactory;
|
||||||
|
this.cryptoManager = cryptoManager;
|
||||||
this.schedulers = schedulers;
|
this.schedulers = schedulers;
|
||||||
|
|
||||||
EntityCapsManager.setPersistentCache(entityCapsStore);
|
EntityCapsManager.setPersistentCache(entityCapsStore);
|
||||||
|
@ -156,7 +160,7 @@ public class MercuryConnectionManager {
|
||||||
chatManager.addIncomingListener(mercuryMessageStore);
|
chatManager.addIncomingListener(mercuryMessageStore);
|
||||||
chatManager.addOutgoingListener(mercuryMessageStore);
|
chatManager.addOutgoingListener(mercuryMessageStore);
|
||||||
}));
|
}));
|
||||||
|
cryptoManager.initialize(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleOptionalAccountChangedEvent(MercuryConnection connection, Optional<Account> event) {
|
private void handleOptionalAccountChangedEvent(MercuryConnection connection, Optional<Account> event) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.mercury_im.messenger.core.xmpp;
|
package org.mercury_im.messenger.core.xmpp;
|
||||||
|
|
||||||
import org.jivesoftware.smack.ReconnectionManager;
|
import org.jivesoftware.smack.ReconnectionManager;
|
||||||
|
import org.jivesoftware.smack.SmackConfiguration;
|
||||||
import org.jivesoftware.smack.roster.Roster;
|
import org.jivesoftware.smack.roster.Roster;
|
||||||
import org.jivesoftware.smackx.carbons.CarbonManager;
|
import org.jivesoftware.smackx.carbons.CarbonManager;
|
||||||
import org.jivesoftware.smackx.iqversion.VersionManager;
|
import org.jivesoftware.smackx.iqversion.VersionManager;
|
||||||
|
@ -11,6 +12,7 @@ import org.jivesoftware.smackx.sid.StableUniqueStanzaIdManager;
|
||||||
public class SmackConfig {
|
public class SmackConfig {
|
||||||
|
|
||||||
static void staticConfiguration() {
|
static void staticConfiguration() {
|
||||||
|
SmackConfiguration.DEBUG = true;
|
||||||
ReconnectionManager.setEnabledPerDefault(true);
|
ReconnectionManager.setEnabledPerDefault(true);
|
||||||
ReconnectionManager.setDefaultReconnectionPolicy(ReconnectionManager.ReconnectionPolicy.RANDOM_INCREASING_DELAY);
|
ReconnectionManager.setDefaultReconnectionPolicy(ReconnectionManager.ReconnectionPolicy.RANDOM_INCREASING_DELAY);
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@ apply plugin: 'java-library'
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly "org.projectlombok:lombok:$lombokVersion"
|
compileOnly "org.projectlombok:lombok:$lombokVersion"
|
||||||
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
|
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
|
||||||
|
|
||||||
|
implementation "org.jxmpp:jxmpp-jid:$jxmppVersion"
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceCompatibility = "8"
|
sourceCompatibility = "8"
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package org.mercury_im.messenger.entity;
|
package org.mercury_im.messenger.entity;
|
||||||
|
|
||||||
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
|
import org.jxmpp.jid.impl.JidCreate;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
@ -21,4 +24,8 @@ public class Account {
|
||||||
this.id = UUID.randomUUID();
|
this.id = UUID.randomUUID();
|
||||||
this.rosterVersion = "";
|
this.rosterVersion = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EntityBareJid getJid() {
|
||||||
|
return JidCreate.entityBareFromOrThrowUnchecked(getAddress());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.mercury_im.messenger.entity.contact;
|
package org.mercury_im.messenger.entity.contact;
|
||||||
|
|
||||||
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
|
import org.jxmpp.jid.impl.JidCreate;
|
||||||
import org.mercury_im.messenger.entity.Account;
|
import org.mercury_im.messenger.entity.Account;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -32,4 +34,8 @@ public class Peer {
|
||||||
}
|
}
|
||||||
return address.substring(0, address.indexOf('@'));
|
return address.substring(0, address.indexOf('@'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EntityBareJid getJid() {
|
||||||
|
return JidCreate.entityBareFromOrThrowUnchecked(getAddress());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 219efa564c222b7add06870bb51ba85dfe353cc7
|
Subproject commit 58ce1dd62f11b40a7063802fa079d827c90b0f84
|
|
@ -4,6 +4,7 @@ ext {
|
||||||
// Smack Versions
|
// Smack Versions
|
||||||
// Quickly switch between unique and normal releases using the toggle below
|
// Quickly switch between unique and normal releases using the toggle below
|
||||||
|
|
||||||
|
jxmppVersion = '0.7.0-alpha6'
|
||||||
// Version Strings for non-unique releases
|
// Version Strings for non-unique releases
|
||||||
//*
|
//*
|
||||||
smackVersion = shortVersion
|
smackVersion = shortVersion
|
||||||
|
|
Loading…
Reference in New Issue