mirror of
https://codeberg.org/Mercury-IM/Mercury-IM
synced 2025-03-16 05:43:11 +01:00
Store and restore OX keys
This commit is contained in:
parent
61de3cb22c
commit
f208a9f769
19 changed files with 310 additions and 215 deletions
|
@ -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.di.module.AndroidDatabaseModule;
|
||||
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.RxMercuryRosterStoreFactoryModule;
|
||||
import org.mercury_im.messenger.core.di.module.XmppTcpConnectionFactoryModule;
|
||||
|
@ -43,7 +44,8 @@ import dagger.Component;
|
|||
ViewModelModule.class,
|
||||
XmppTcpConnectionFactoryModule.class,
|
||||
RxMercuryMessageStoreFactoryModule.class,
|
||||
RxMercuryRosterStoreFactoryModule.class
|
||||
RxMercuryRosterStoreFactoryModule.class,
|
||||
OpenPgpModule.class
|
||||
})
|
||||
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.GroupChatRepository;
|
||||
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.Repositories;
|
||||
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.RxGroupChatRepository;
|
||||
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 javax.inject.Singleton;
|
||||
|
@ -84,6 +86,13 @@ public class RepositoryModule {
|
|||
return new RxEntityCapsRepository(data, entityCapsMapping);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static OpenPgpRepository provideOpenPgpRepository(
|
||||
ReactiveEntityStore<Persistable> data) {
|
||||
return new RxOpenPgpRepository(data);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static Repositories provideRepositories(
|
||||
|
@ -92,8 +101,9 @@ public class RepositoryModule {
|
|||
GroupChatRepository groupChatRepository,
|
||||
MessageRepository messageRepository,
|
||||
PeerRepository peerRepository,
|
||||
RxEntityCapsRepository entityCapsRepository) {
|
||||
EntityCapsRepository entityCapsRepository,
|
||||
OpenPgpRepository openPgpRepository) {
|
||||
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.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.Convert;
|
||||
import io.requery.Entity;
|
||||
import io.requery.ForeignKey;
|
||||
import io.requery.Index;
|
||||
import io.requery.Key;
|
||||
import io.requery.ManyToOne;
|
||||
import io.requery.Table;
|
||||
import io.requery.converter.UUIDConverter;
|
||||
|
||||
@Entity
|
||||
@Table(name = "ox_public_keys")
|
||||
public class AbstractOpenPgpPublicKeyRing {
|
||||
|
||||
@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)
|
||||
@Convert(EntityBareJidConverter.class)
|
||||
EntityBareJid owner;
|
||||
|
|
|
@ -2,41 +2,18 @@ package org.mercury_im.messenger.data.model;
|
|||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
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.Convert;
|
||||
import io.requery.Entity;
|
||||
import io.requery.ForeignKey;
|
||||
import io.requery.Index;
|
||||
import io.requery.Key;
|
||||
import io.requery.ManyToOne;
|
||||
import io.requery.Table;
|
||||
import io.requery.converter.UUIDConverter;
|
||||
|
||||
@Entity
|
||||
@Table(name = "ox_secret_keys")
|
||||
public class AbstractOpenPgpSecretKeyRing {
|
||||
|
||||
@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)
|
||||
@Convert(EntityBareJidConverter.class)
|
||||
EntityBareJid owner;
|
||||
|
|
|
@ -1,53 +1,78 @@
|
|||
package org.mercury_im.messenger.data.repository;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
|
||||
import org.mercury_im.messenger.data.model.OpenPgpPublicKeyRing;
|
||||
import org.mercury_im.messenger.data.model.OpenPgpSecretKeyRing;
|
||||
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.requery.Persistable;
|
||||
import io.requery.query.ResultDelegate;
|
||||
import io.requery.reactivex.ReactiveEntityStore;
|
||||
|
||||
public class RxOpenPgpRepository implements OpenPgpRepository {
|
||||
|
||||
private final ReactiveEntityStore<Persistable> data;
|
||||
|
||||
@Inject
|
||||
public RxOpenPgpRepository(ReactiveEntityStore<Persistable> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<PGPPublicKeyRingCollection> loadPublicKeysOfContact(UUID accountId, EntityBareJid jid) {
|
||||
return data.select(OpenPgpPublicKeyRing.class)
|
||||
.where(OpenPgpPublicKeyRing.ACCOUNT_ID.eq(accountId))
|
||||
.and(OpenPgpPublicKeyRing.OWNER.eq(jid))
|
||||
.get().observableResult()
|
||||
.map(ResultDelegate::toList)
|
||||
.map(keys -> PGPainless.readKeyRing().publicKeyRing(keys.get(0).getBytes()).)
|
||||
public Completable storePublicKeysOf(EntityBareJid owner, PGPPublicKeyRingCollection keys) {
|
||||
return Single.fromCallable(() -> {
|
||||
OpenPgpPublicKeyRing keyRing = new OpenPgpPublicKeyRing();
|
||||
keyRing.setOwner(owner);
|
||||
keyRing.setBytes(keys.getEncoded());
|
||||
return keyRing;
|
||||
}).flatMap(data::upsert).ignoreElement();
|
||||
}
|
||||
|
||||
@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)
|
||||
.where(OpenPgpPublicKeyRing.ACCOUNT_ID.eq(accountId))
|
||||
.and(OpenPgpPublicKeyRing.OWNER.eq(jid))
|
||||
.and(OpenPgpPublicKeyRing.FINGERPRINT.eq(fingerprint))
|
||||
.where(OpenPgpPublicKeyRing.OWNER.eq(owner))
|
||||
.get().single();
|
||||
}
|
||||
|
||||
@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)
|
||||
.where(OpenPgpSecretKeyRing.ACCOUNT_ID.eq(accountId))
|
||||
.and(OpenPgpPublicKeyRing.OWNER.eq(jid))
|
||||
.and(OpenPgpSecretKeyRing.FINGERPRINT.eq(fingerprint))
|
||||
.where(OpenPgpPublicKeyRing.OWNER.eq(owner))
|
||||
.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;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Single;
|
||||
|
||||
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.Singleton;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
@Singleton
|
||||
@Value
|
||||
public class Repositories {
|
||||
|
||||
private final AccountRepository accountRepository;
|
||||
private final DirectChatRepository directChatRepository;
|
||||
private final GroupChatRepository groupChatRepository;
|
||||
private final MessageRepository messageRepository;
|
||||
private final PeerRepository peerRepository;
|
||||
private final EntityCapsRepository entityCapsRepository;
|
||||
AccountRepository accountRepository;
|
||||
DirectChatRepository directChatRepository;
|
||||
GroupChatRepository groupChatRepository;
|
||||
MessageRepository messageRepository;
|
||||
PeerRepository peerRepository;
|
||||
EntityCapsRepository entityCapsRepository;
|
||||
OpenPgpRepository openPgpRepository;
|
||||
|
||||
@Inject
|
||||
public Repositories(AccountRepository accountRepository,
|
||||
|
@ -19,36 +23,14 @@ public class Repositories {
|
|||
GroupChatRepository groupChatRepository,
|
||||
MessageRepository messageRepository,
|
||||
PeerRepository peerRepository,
|
||||
EntityCapsRepository entityCapsRepository) {
|
||||
EntityCapsRepository entityCapsRepository,
|
||||
OpenPgpRepository openPgpRepository) {
|
||||
this.accountRepository = accountRepository;
|
||||
this.directChatRepository = directChatRepository;
|
||||
this.groupChatRepository = groupChatRepository;
|
||||
this.messageRepository = messageRepository;
|
||||
this.peerRepository = peerRepository;
|
||||
this.entityCapsRepository = entityCapsRepository;
|
||||
}
|
||||
|
||||
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;
|
||||
this.openPgpRepository = openPgpRepository;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpContact;
|
||||
import org.jivesoftware.smackx.ox.callback.SecretKeyPassphraseCallback;
|
||||
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException;
|
||||
import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore;
|
||||
import org.jivesoftware.smackx.ox.store.abstr.AbstractOpenPgpKeyStore;
|
||||
import org.jivesoftware.smackx.ox.store.abstr.AbstractOpenPgpMetadataStore;
|
||||
import org.jivesoftware.smackx.ox.store.abstr.AbstractOpenPgpStore;
|
||||
import org.jivesoftware.smackx.ox.store.abstr.AbstractOpenPgpTrustStore;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.mercury_im.messenger.core.SchedulersFacade;
|
||||
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
|
||||
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.security.InvalidAlgorithmParameterException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class MercuryOpenPgpStore implements OpenPgpStore {
|
||||
public class MercuryOpenPgpStore extends AbstractOpenPgpStore {
|
||||
|
||||
private final UUID accountId;
|
||||
private SecretKeyRingProtector keyRingProtector;
|
||||
private SecretKeyPassphraseCallback passphraseCallback;
|
||||
private final OpenPgpRepository repository;
|
||||
private final SchedulersFacade schedulers;
|
||||
|
||||
@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) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
@Override
|
||||
protected void writePublicKeysOf(BareJid owner, PGPPublicKeyRingCollection publicKeys)
|
||||
throws IOException {
|
||||
repository.storePublicKeysOf(owner.asEntityBareJidIfPossible(), publicKeys)
|
||||
.subscribeOn(schedulers.getIoScheduler()).subscribe();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenPgpContact getOpenPgpContact(BareJid contactsJid) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
protected PGPSecretKeyRingCollection readSecretKeysOf(BareJid owner)
|
||||
throws IOException, PGPException {
|
||||
try {
|
||||
return repository.loadSecretKeysOf(owner.asEntityBareJidIfPossible())
|
||||
.blockingGet();
|
||||
} catch (NoSuchElementException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKeyRingProtector(SecretKeyRingProtector unlocker) {
|
||||
this.keyRingProtector = unlocker;
|
||||
}
|
||||
@Override
|
||||
protected void writeSecretKeysOf(BareJid owner, PGPSecretKeyRingCollection secretKeys)
|
||||
throws IOException {
|
||||
repository.storeSecretKeysOf(owner.asEntityBareJidIfPossible(), secretKeys)
|
||||
.subscribeOn(schedulers.getIoScheduler()).subscribe();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretKeyRingProtector getKeyRingProtector() {
|
||||
return keyRingProtector;
|
||||
}
|
||||
@Override
|
||||
protected Map<OpenPgpV4Fingerprint, Date> readKeyFetchDates(BareJid owner)
|
||||
throws IOException {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSecretKeyPassphraseCallback(SecretKeyPassphraseCallback callback) {
|
||||
passphraseCallback = callback;
|
||||
}
|
||||
@Override
|
||||
protected void writeKeyFetchDates(BareJid owner, Map<OpenPgpV4Fingerprint, Date> dates)
|
||||
throws IOException {
|
||||
|
||||
@Override
|
||||
public PGPPublicKeyRingCollection getPublicKeysOf(BareJid owner) throws IOException, PGPException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}, new AbstractOpenPgpMetadataStore() {
|
||||
@Override
|
||||
protected Map<OpenPgpV4Fingerprint, Date> readAnnouncedFingerprintsOf(BareJid contact)
|
||||
throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PGPSecretKeyRingCollection getSecretKeysOf(BareJid owner) throws IOException, PGPException {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
protected void writeAnnouncedFingerprintsOf(BareJid contact, Map<OpenPgpV4Fingerprint, Date> metadata)
|
||||
throws IOException {
|
||||
|
||||
@Override
|
||||
public PGPPublicKeyRing getPublicKeyRing(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException, PGPException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}, new AbstractOpenPgpTrustStore() {
|
||||
@Override
|
||||
protected Trust readTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint)
|
||||
throws IOException {
|
||||
return Trust.trusted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PGPSecretKeyRing getSecretKeyRing(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException, PGPException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@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 {
|
||||
@Override
|
||||
protected void writeTrust(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.setRecipient(to.asBareJid().toString());
|
||||
if (smackMessage.getBody() != null) {
|
||||
message.setBody(smackMessage.getBody().getMessage());
|
||||
message.setBody(smackMessage.getBody());
|
||||
}
|
||||
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.smackx.caps.EntityCapsManager;
|
||||
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.DirectChatRepository;
|
||||
import org.mercury_im.messenger.core.data.repository.MessageRepository;
|
||||
|
@ -48,6 +49,7 @@ public class MercuryConnectionManager {
|
|||
private final PeerRepository peerRepository;
|
||||
private final DirectChatRepository directChatRepository;
|
||||
private final MessageRepository messageRepository;
|
||||
private final MercuryOpenPgpManager cryptoManager;
|
||||
private final SchedulersFacade schedulers;
|
||||
|
||||
private final Map<UUID, MercuryConnection> connectionsMap = new ConcurrentHashMap<>();
|
||||
|
@ -67,6 +69,7 @@ public class MercuryConnectionManager {
|
|||
MercuryEntityCapsStore entityCapsStore,
|
||||
MercuryMessageStoreFactory messageStoreFactory,
|
||||
XmppConnectionFactory connectionFactory,
|
||||
MercuryOpenPgpManager cryptoManager,
|
||||
SchedulersFacade schedulers) {
|
||||
this.accountRepository = repositories.getAccountRepository();
|
||||
this.rosterStoreBinder = rosterStoreBinder;
|
||||
|
@ -76,6 +79,7 @@ public class MercuryConnectionManager {
|
|||
this.messageRepository = repositories.getMessageRepository();
|
||||
this.connectionFactory = connectionFactory;
|
||||
this.messageStoreFactory = messageStoreFactory;
|
||||
this.cryptoManager = cryptoManager;
|
||||
this.schedulers = schedulers;
|
||||
|
||||
EntityCapsManager.setPersistentCache(entityCapsStore);
|
||||
|
@ -156,7 +160,7 @@ public class MercuryConnectionManager {
|
|||
chatManager.addIncomingListener(mercuryMessageStore);
|
||||
chatManager.addOutgoingListener(mercuryMessageStore);
|
||||
}));
|
||||
|
||||
cryptoManager.initialize(connection);
|
||||
}
|
||||
|
||||
private void handleOptionalAccountChangedEvent(MercuryConnection connection, Optional<Account> event) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.mercury_im.messenger.core.xmpp;
|
||||
|
||||
import org.jivesoftware.smack.ReconnectionManager;
|
||||
import org.jivesoftware.smack.SmackConfiguration;
|
||||
import org.jivesoftware.smack.roster.Roster;
|
||||
import org.jivesoftware.smackx.carbons.CarbonManager;
|
||||
import org.jivesoftware.smackx.iqversion.VersionManager;
|
||||
|
@ -11,6 +12,7 @@ import org.jivesoftware.smackx.sid.StableUniqueStanzaIdManager;
|
|||
public class SmackConfig {
|
||||
|
||||
static void staticConfiguration() {
|
||||
SmackConfiguration.DEBUG = true;
|
||||
ReconnectionManager.setEnabledPerDefault(true);
|
||||
ReconnectionManager.setDefaultReconnectionPolicy(ReconnectionManager.ReconnectionPolicy.RANDOM_INCREASING_DELAY);
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ apply plugin: 'java-library'
|
|||
dependencies {
|
||||
compileOnly "org.projectlombok:lombok:$lombokVersion"
|
||||
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
|
||||
|
||||
implementation "org.jxmpp:jxmpp-jid:$jxmppVersion"
|
||||
}
|
||||
|
||||
sourceCompatibility = "8"
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package org.mercury_im.messenger.entity;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import lombok.Data;
|
||||
|
@ -21,4 +24,8 @@ public class Account {
|
|||
this.id = UUID.randomUUID();
|
||||
this.rosterVersion = "";
|
||||
}
|
||||
|
||||
public EntityBareJid getJid() {
|
||||
return JidCreate.entityBareFromOrThrowUnchecked(getAddress());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
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 java.util.List;
|
||||
|
@ -32,4 +34,8 @@ public class Peer {
|
|||
}
|
||||
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
|
||||
// Quickly switch between unique and normal releases using the toggle below
|
||||
|
||||
jxmppVersion = '0.7.0-alpha6'
|
||||
// Version Strings for non-unique releases
|
||||
//*
|
||||
smackVersion = shortVersion
|
||||
|
|
Loading…
Add table
Reference in a new issue