From 61de3cb22c6539356368c9fce9f6aec4a8379408 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Sat, 13 Jun 2020 19:14:38 +0200 Subject: [PATCH] Start OX implementation --- data/build.gradle | 2 + .../converter/EntityBareJidConverter.java | 37 +++++ .../OpenPgpV4FingerprintConverter.java | 33 +++++ .../data/model/AbstractMessageModel.java | 2 +- .../model/AbstractOpenPgpPublicKeyRing.java | 46 ++++++ .../model/AbstractOpenPgpSecretKeyRing.java | 46 ++++++ .../data/repository/RxOpenPgpRepository.java | 53 +++++++ .../data/repository/OpenPgpRepository.java | 18 +++ .../store/crypto/MercuryOpenPgpStore.java | 136 ++++++++++++++++++ 9 files changed, 372 insertions(+), 1 deletion(-) create mode 100644 data/src/main/java/org/mercury_im/messenger/data/converter/EntityBareJidConverter.java create mode 100644 data/src/main/java/org/mercury_im/messenger/data/converter/OpenPgpV4FingerprintConverter.java create mode 100644 data/src/main/java/org/mercury_im/messenger/data/model/AbstractOpenPgpPublicKeyRing.java create mode 100644 data/src/main/java/org/mercury_im/messenger/data/model/AbstractOpenPgpSecretKeyRing.java create mode 100644 data/src/main/java/org/mercury_im/messenger/data/repository/RxOpenPgpRepository.java create mode 100644 domain/src/main/java/org/mercury_im/messenger/core/data/repository/OpenPgpRepository.java create mode 100644 domain/src/main/java/org/mercury_im/messenger/core/store/crypto/MercuryOpenPgpStore.java diff --git a/data/build.gradle b/data/build.gradle index 5e3a293..e80abdc 100644 --- a/data/build.gradle +++ b/data/build.gradle @@ -27,6 +27,8 @@ dependencies { api "io.requery:requery:$requeryVersion" annotationProcessor "io.requery:requery-processor:$requeryVersion" + implementation 'com.google.code.findbugs:jsr305:3.0.2' + // JUnit for testing testImplementation "junit:junit:$junitVersion" diff --git a/data/src/main/java/org/mercury_im/messenger/data/converter/EntityBareJidConverter.java b/data/src/main/java/org/mercury_im/messenger/data/converter/EntityBareJidConverter.java new file mode 100644 index 0000000..9ab023d --- /dev/null +++ b/data/src/main/java/org/mercury_im/messenger/data/converter/EntityBareJidConverter.java @@ -0,0 +1,37 @@ +package org.mercury_im.messenger.data.converter; + +import org.jxmpp.jid.EntityBareJid; +import org.jxmpp.jid.impl.JidCreate; + +import javax.annotation.Nullable; + +import io.requery.Converter; + +public class EntityBareJidConverter implements Converter { + + @Override + public Class getMappedType() { + return EntityBareJid.class; + } + + @Override + public Class getPersistedType() { + return String.class; + } + + @Nullable + @Override + public Integer getPersistedSize() { + return null; + } + + @Override + public String convertToPersisted(EntityBareJid value) { + return value == null ? null : value.asEntityBareJidString(); + } + + @Override + public EntityBareJid convertToMapped(Class type, @Nullable String value) { + return value == null ? null : JidCreate.entityBareFromOrThrowUnchecked(value); + } +} diff --git a/data/src/main/java/org/mercury_im/messenger/data/converter/OpenPgpV4FingerprintConverter.java b/data/src/main/java/org/mercury_im/messenger/data/converter/OpenPgpV4FingerprintConverter.java new file mode 100644 index 0000000..a8b4172 --- /dev/null +++ b/data/src/main/java/org/mercury_im/messenger/data/converter/OpenPgpV4FingerprintConverter.java @@ -0,0 +1,33 @@ +package org.mercury_im.messenger.data.converter; + +import org.pgpainless.key.OpenPgpV4Fingerprint; + +import io.requery.Converter; + +public class OpenPgpV4FingerprintConverter implements Converter { + @Override + public Class getMappedType() { + return OpenPgpV4Fingerprint.class; + } + + @Override + public Class getPersistedType() { + return String.class; + } + + @javax.annotation.Nullable + @Override + public Integer getPersistedSize() { + return null; + } + + @Override + public String convertToPersisted(OpenPgpV4Fingerprint value) { + return value == null ? null : value.toString(); + } + + @Override + public OpenPgpV4Fingerprint convertToMapped(Class type, @javax.annotation.Nullable String value) { + return value == null ? null : new OpenPgpV4Fingerprint(value); + } +} diff --git a/data/src/main/java/org/mercury_im/messenger/data/model/AbstractMessageModel.java b/data/src/main/java/org/mercury_im/messenger/data/model/AbstractMessageModel.java index 89e45b2..edfebfb 100644 --- a/data/src/main/java/org/mercury_im/messenger/data/model/AbstractMessageModel.java +++ b/data/src/main/java/org/mercury_im/messenger/data/model/AbstractMessageModel.java @@ -22,7 +22,7 @@ import io.requery.converter.UUIDConverter; public abstract class AbstractMessageModel implements Persistable { @Key - @Convert(UUIDConverter.class) + @Convert(UUIDConverter.class) UUID id; @Column(nullable = false) diff --git a/data/src/main/java/org/mercury_im/messenger/data/model/AbstractOpenPgpPublicKeyRing.java b/data/src/main/java/org/mercury_im/messenger/data/model/AbstractOpenPgpPublicKeyRing.java new file mode 100644 index 0000000..18c98df --- /dev/null +++ b/data/src/main/java/org/mercury_im/messenger/data/model/AbstractOpenPgpPublicKeyRing.java @@ -0,0 +1,46 @@ +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; + + @Column(name = "data", nullable = false) + byte[] bytes; +} diff --git a/data/src/main/java/org/mercury_im/messenger/data/model/AbstractOpenPgpSecretKeyRing.java b/data/src/main/java/org/mercury_im/messenger/data/model/AbstractOpenPgpSecretKeyRing.java new file mode 100644 index 0000000..29ab420 --- /dev/null +++ b/data/src/main/java/org/mercury_im/messenger/data/model/AbstractOpenPgpSecretKeyRing.java @@ -0,0 +1,46 @@ +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; + + @Column(name = "data", nullable = false) + byte[] bytes; +} diff --git a/data/src/main/java/org/mercury_im/messenger/data/repository/RxOpenPgpRepository.java b/data/src/main/java/org/mercury_im/messenger/data/repository/RxOpenPgpRepository.java new file mode 100644 index 0000000..eb50ea5 --- /dev/null +++ b/data/src/main/java/org/mercury_im/messenger/data/repository/RxOpenPgpRepository.java @@ -0,0 +1,53 @@ +package org.mercury_im.messenger.data.repository; + +import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; +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 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 data; + + public RxOpenPgpRepository(ReactiveEntityStore data) { + this.data = data; + } + + @Override + public Single 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()).) + } + + @Override + public Single deletePublicKeyRing(UUID accountId, EntityBareJid jid, OpenPgpV4Fingerprint fingerprint) { + return data.delete(OpenPgpPublicKeyRing.class) + .where(OpenPgpPublicKeyRing.ACCOUNT_ID.eq(accountId)) + .and(OpenPgpPublicKeyRing.OWNER.eq(jid)) + .and(OpenPgpPublicKeyRing.FINGERPRINT.eq(fingerprint)) + .get().single(); + } + + @Override + public Single deleteSecretKeyRing(UUID accountId, EntityBareJid jid, OpenPgpV4Fingerprint fingerprint) { + return data.delete(OpenPgpSecretKeyRing.class) + .where(OpenPgpSecretKeyRing.ACCOUNT_ID.eq(accountId)) + .and(OpenPgpPublicKeyRing.OWNER.eq(jid)) + .and(OpenPgpSecretKeyRing.FINGERPRINT.eq(fingerprint)) + .get().single(); + } +} diff --git a/domain/src/main/java/org/mercury_im/messenger/core/data/repository/OpenPgpRepository.java b/domain/src/main/java/org/mercury_im/messenger/core/data/repository/OpenPgpRepository.java new file mode 100644 index 0000000..990b500 --- /dev/null +++ b/domain/src/main/java/org/mercury_im/messenger/core/data/repository/OpenPgpRepository.java @@ -0,0 +1,18 @@ +package org.mercury_im.messenger.core.data.repository; + +import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; +import org.jxmpp.jid.EntityBareJid; +import org.pgpainless.key.OpenPgpV4Fingerprint; + +import java.util.UUID; + +import io.reactivex.Single; + +public interface OpenPgpRepository { + + Single loadPublicKeysOfContact(UUID accountId, EntityBareJid jid); + + Single deletePublicKeyRing(UUID accountId, EntityBareJid jid, OpenPgpV4Fingerprint fingerprint); + + Single deleteSecretKeyRing(UUID accountId, EntityBareJid jid, OpenPgpV4Fingerprint fingerprint); +} diff --git a/domain/src/main/java/org/mercury_im/messenger/core/store/crypto/MercuryOpenPgpStore.java b/domain/src/main/java/org/mercury_im/messenger/core/store/crypto/MercuryOpenPgpStore.java new file mode 100644 index 0000000..4ee5bda --- /dev/null +++ b/domain/src/main/java/org/mercury_im/messenger/core/store/crypto/MercuryOpenPgpStore.java @@ -0,0 +1,136 @@ +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.jxmpp.jid.BareJid; +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.Map; +import java.util.UUID; + +import javax.inject.Inject; + +public class MercuryOpenPgpStore implements OpenPgpStore { + + private final UUID accountId; + private SecretKeyRingProtector keyRingProtector; + private SecretKeyPassphraseCallback passphraseCallback; + + @Inject + OpenPgpRepository repository; + + public MercuryOpenPgpStore(UUID accountId) { + this.accountId = accountId; + } + + @Override + public OpenPgpContact getOpenPgpContact(BareJid contactsJid) { + return null; + } + + @Override + public void setKeyRingProtector(SecretKeyRingProtector unlocker) { + this.keyRingProtector = unlocker; + } + + @Override + public SecretKeyRingProtector getKeyRingProtector() { + return keyRingProtector; + } + + @Override + public void setSecretKeyPassphraseCallback(SecretKeyPassphraseCallback callback) { + passphraseCallback = callback; + } + + @Override + public PGPPublicKeyRingCollection getPublicKeysOf(BareJid owner) throws IOException, PGPException { + return null; + } + + @Override + public PGPSecretKeyRingCollection getSecretKeysOf(BareJid owner) throws IOException, PGPException { + return null; + } + + @Override + public PGPPublicKeyRing getPublicKeyRing(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException, PGPException { + return null; + } + + @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 getPublicKeyFetchDates(BareJid contact) throws IOException { + return null; + } + + @Override + public void setPublicKeyFetchDates(BareJid contact, Map dates) throws IOException { + + } + + @Override + public Map getAnnouncedFingerprintsOf(BareJid contact) throws IOException { + return null; + } + + @Override + public void setAnnouncedFingerprintsOf(BareJid contact, Map 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 { + + } +}