mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-23 20:42:06 +01:00
Temp
This commit is contained in:
parent
c4848fffc9
commit
171cb07430
8 changed files with 223 additions and 205 deletions
|
@ -25,18 +25,19 @@ import java.io.IOException;
|
|||
import java.nio.charset.Charset;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jivesoftware.smack.DummyConnection;
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.util.FileUtils;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||
import org.jivesoftware.smackx.ox.TestKeys;
|
||||
import org.jivesoftware.smackx.ox.chat.OpenPgpContact;
|
||||
import org.jivesoftware.smackx.ox.chat.OpenPgpFingerprints;
|
||||
import org.jivesoftware.smackx.ox.element.OpenPgpContentElement;
|
||||
import org.jivesoftware.smackx.ox.element.OpenPgpElement;
|
||||
import org.jivesoftware.smackx.ox.element.PubkeyElement;
|
||||
|
@ -75,26 +76,29 @@ public class DryOxEncryptionTest extends OxTestSuite {
|
|||
@Test
|
||||
public void dryEncryptionTest()
|
||||
throws IOException, SmackOpenPgpException, MissingUserIdOnKeyException, MissingOpenPgpPublicKeyException,
|
||||
MissingOpenPgpKeyPairException, XmlPullParserException {
|
||||
BareJid juliet = TestKeys.JULIET_JID;
|
||||
BareJid romemo = TestKeys.ROMEO_JID;
|
||||
MissingOpenPgpKeyPairException, XmlPullParserException, SmackException.NotLoggedInException {
|
||||
BareJid julietJid = TestKeys.JULIET_JID;
|
||||
BareJid romeoJid = TestKeys.ROMEO_JID;
|
||||
|
||||
XMPPConnection julietCon = new DummyConnection();
|
||||
XMPPConnection romeoCon = new DummyConnection();
|
||||
|
||||
FileBasedPainlessOpenPgpStore julietStore = new FileBasedPainlessOpenPgpStore(julietPath, new UnprotectedKeysProtector());
|
||||
FileBasedPainlessOpenPgpStore romeoStore = new FileBasedPainlessOpenPgpStore(romeoPath, new UnprotectedKeysProtector());
|
||||
|
||||
PainlessOpenPgpProvider julietProvider = new PainlessOpenPgpProvider(juliet, julietStore);
|
||||
PainlessOpenPgpProvider romeoProvider = new PainlessOpenPgpProvider(romemo, romeoStore);
|
||||
PainlessOpenPgpProvider julietProvider = new PainlessOpenPgpProvider(julietJid, julietStore);
|
||||
PainlessOpenPgpProvider romeoProvider = new PainlessOpenPgpProvider(romeoJid, romeoStore);
|
||||
|
||||
OpenPgpV4Fingerprint julietFinger = julietProvider.importSecretKey(juliet,
|
||||
OpenPgpV4Fingerprint julietFinger = julietProvider.importSecretKey(julietJid,
|
||||
BCUtil.getDecodedBytes(TestKeys.JULIET_PRIV.getBytes(UTF8)));
|
||||
OpenPgpV4Fingerprint romeoFinger = romeoProvider.importSecretKey(romemo,
|
||||
OpenPgpV4Fingerprint romeoFinger = romeoProvider.importSecretKey(romeoJid,
|
||||
BCUtil.getDecodedBytes(TestKeys.ROMEO_PRIV.getBytes(UTF8)));
|
||||
|
||||
julietStore.setSigningKeyPairFingerprint(julietFinger);
|
||||
romeoStore.setSigningKeyPairFingerprint(romeoFinger);
|
||||
|
||||
byte[] julietPubBytes = julietStore.getPublicKeyRingBytes(juliet, julietFinger);
|
||||
byte[] romeoPubBytes = romeoStore.getPublicKeyRingBytes(romemo, romeoFinger);
|
||||
byte[] julietPubBytes = julietStore.getPublicKeyRingBytes(julietJid, julietFinger);
|
||||
byte[] romeoPubBytes = romeoStore.getPublicKeyRingBytes(romeoJid, romeoFinger);
|
||||
|
||||
assertNotNull(julietPubBytes);
|
||||
assertNotNull(romeoPubBytes);
|
||||
|
@ -102,29 +106,20 @@ public class DryOxEncryptionTest extends OxTestSuite {
|
|||
assertTrue(romeoPubBytes.length != 0);
|
||||
|
||||
PubkeyElement julietPub = new PubkeyElement(new PubkeyElement.PubkeyDataElement(
|
||||
Base64.encode(julietStore.getPublicKeyRingBytes(juliet, julietFinger))),
|
||||
Base64.encode(julietStore.getPublicKeyRingBytes(julietJid, julietFinger))),
|
||||
new Date());
|
||||
PubkeyElement romeoPub = new PubkeyElement(new PubkeyElement.PubkeyDataElement(
|
||||
Base64.encode(romeoStore.getPublicKeyRingBytes(romemo, romeoFinger))),
|
||||
Base64.encode(romeoStore.getPublicKeyRingBytes(romeoJid, romeoFinger))),
|
||||
new Date());
|
||||
|
||||
julietProvider.importPublicKey(romemo, Base64.decode(romeoPub.getDataElement().getB64Data()));
|
||||
romeoProvider.importPublicKey(juliet, Base64.decode(julietPub.getDataElement().getB64Data()));
|
||||
julietProvider.importPublicKey(romeoJid, Base64.decode(romeoPub.getDataElement().getB64Data()));
|
||||
romeoProvider.importPublicKey(julietJid, Base64.decode(julietPub.getDataElement().getB64Data()));
|
||||
|
||||
julietStore.setAnnouncedKeysFingerprints(romemo, Collections.singletonMap(romeoFinger, new Date()));
|
||||
romeoStore.setAnnouncedKeysFingerprints(juliet, Collections.singletonMap(julietFinger, new Date()));
|
||||
julietStore.setAnnouncedKeysFingerprints(romeoJid, Collections.singletonMap(romeoFinger, new Date()));
|
||||
romeoStore.setAnnouncedKeysFingerprints(julietJid, Collections.singletonMap(julietFinger, new Date()));
|
||||
|
||||
OpenPgpFingerprints julietFingerprints = new OpenPgpFingerprints(juliet,
|
||||
Collections.singleton(julietFinger),
|
||||
Collections.singleton(julietFinger),
|
||||
new HashMap<OpenPgpV4Fingerprint, Throwable>());
|
||||
OpenPgpFingerprints romeoFingerprints = new OpenPgpFingerprints(romemo,
|
||||
Collections.singleton(romeoFinger),
|
||||
Collections.singleton(romeoFinger),
|
||||
new HashMap<OpenPgpV4Fingerprint, Throwable>());
|
||||
|
||||
OpenPgpContact julietForRomeo = new OpenPgpContact(romeoProvider, juliet, romeoFingerprints, julietFingerprints);
|
||||
OpenPgpContact romeoForJuliet = new OpenPgpContact(julietProvider, romemo, julietFingerprints, romeoFingerprints);
|
||||
OpenPgpContact julietForRomeo = new OpenPgpContact(romeoProvider, julietJid, romeoCon);
|
||||
OpenPgpContact romeoForJuliet = new OpenPgpContact(julietProvider, romeoJid, julietCon);
|
||||
|
||||
String bodyText = "Finden wir eine Kompromisslösung – machen wir es so, wie ich es sage.";
|
||||
List<ExtensionElement> payload = Collections.<ExtensionElement>singletonList(new Message.Body("de",
|
||||
|
|
|
@ -127,7 +127,7 @@ public final class OXInstantMessagingManager extends Manager implements Signcryp
|
|||
|
||||
public void sendOxMessage(OpenPgpContact contact, CharSequence body)
|
||||
throws InterruptedException, MissingOpenPgpKeyPairException, IOException,
|
||||
SmackException.NotConnectedException, SmackOpenPgpException {
|
||||
SmackException.NotConnectedException, SmackOpenPgpException, SmackException.NotLoggedInException {
|
||||
Message message = new Message(contact.getJid());
|
||||
List<ExtensionElement> payload = new ArrayList<>();
|
||||
payload.add(new Message.Body(null, body.toString()));
|
||||
|
|
|
@ -18,7 +18,6 @@ package org.jivesoftware.smackx.ox;
|
|||
|
||||
import static org.jivesoftware.smackx.ox.util.PubSubDelegate.PEP_NODE_PUBLIC_KEYS;
|
||||
import static org.jivesoftware.smackx.ox.util.PubSubDelegate.PEP_NODE_PUBLIC_KEYS_NOTIFY;
|
||||
import static org.jivesoftware.smackx.ox.util.PubSubDelegate.fetchPubkey;
|
||||
import static org.jivesoftware.smackx.ox.util.PubSubDelegate.publishPublicKey;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -26,7 +25,6 @@ import java.io.InputStream;
|
|||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -52,7 +50,7 @@ import org.jivesoftware.smackx.ox.callback.DisplayBackupCodeCallback;
|
|||
import org.jivesoftware.smackx.ox.callback.SecretKeyBackupSelectionCallback;
|
||||
import org.jivesoftware.smackx.ox.callback.SecretKeyRestoreSelectionCallback;
|
||||
import org.jivesoftware.smackx.ox.chat.OpenPgpContact;
|
||||
import org.jivesoftware.smackx.ox.chat.OpenPgpFingerprints;
|
||||
import org.jivesoftware.smackx.ox.chat.OpenPgpSelf;
|
||||
import org.jivesoftware.smackx.ox.element.CryptElement;
|
||||
import org.jivesoftware.smackx.ox.element.OpenPgpContentElement;
|
||||
import org.jivesoftware.smackx.ox.element.OpenPgpElement;
|
||||
|
@ -106,6 +104,8 @@ public final class OpenPgpManager extends Manager {
|
|||
private final Set<SignElementReceivedListener> signElementReceivedListeners = new HashSet<>();
|
||||
private final Set<CryptElementReceivedListener> cryptElementReceivedListeners = new HashSet<>();
|
||||
|
||||
private OpenPgpSelf self;
|
||||
|
||||
/**
|
||||
* Private constructor to avoid instantiation without putting the object into {@code INSTANCES}.
|
||||
*
|
||||
|
@ -141,6 +141,16 @@ public final class OpenPgpManager extends Manager {
|
|||
this.provider = provider;
|
||||
}
|
||||
|
||||
public OpenPgpSelf getOpenPgpSelf() throws SmackException.NotLoggedInException {
|
||||
throwIfNotAuthenticated();
|
||||
|
||||
if (self == null) {
|
||||
self = new OpenPgpSelf(provider, connection().getUser().asBareJid(), connection());
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a fresh OpenPGP key pair, given we don't have one already.
|
||||
* Publish the public key to the Public Key Node and update the Public Key Metadata Node with our keys fingerprint.
|
||||
|
@ -220,21 +230,13 @@ public final class OpenPgpManager extends Manager {
|
|||
*
|
||||
* @param jid {@link BareJid} of the contact.
|
||||
* @return {@link OpenPgpContact}.
|
||||
* @throws SmackOpenPgpException if something happens while gathering fingerprints.
|
||||
* @throws InterruptedException
|
||||
* @throws XMPPException.XMPPErrorException
|
||||
*/
|
||||
public OpenPgpContact getOpenPgpContact(EntityBareJid jid)
|
||||
throws SmackOpenPgpException, InterruptedException, XMPPException.XMPPErrorException,
|
||||
SmackException.NotLoggedInException {
|
||||
throwIfNotAuthenticated();
|
||||
public OpenPgpContact getOpenPgpContact(EntityBareJid jid) {
|
||||
|
||||
OpenPgpContact openPgpContact = openPgpCapableContacts.get(jid);
|
||||
|
||||
if (openPgpContact == null) {
|
||||
OpenPgpFingerprints theirKeys = determineContactsKeys(jid);
|
||||
OpenPgpFingerprints ourKeys = determineContactsKeys(connection().getUser().asBareJid());
|
||||
openPgpContact = new OpenPgpContact(provider, jid, ourKeys, theirKeys);
|
||||
openPgpContact = new OpenPgpContact(provider, jid, connection());
|
||||
openPgpCapableContacts.put(jid, openPgpContact);
|
||||
}
|
||||
|
||||
|
@ -343,45 +345,6 @@ public final class OpenPgpManager extends Manager {
|
|||
return fingerprint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine which keys belong to a user and fetch any missing keys.
|
||||
*
|
||||
* @param jid {@link BareJid} of the user in question.
|
||||
* @return {@link OpenPgpFingerprints} object containing the announced, available and unfetchable keys of the user.
|
||||
* @throws SmackOpenPgpException
|
||||
* @throws InterruptedException
|
||||
* @throws XMPPException.XMPPErrorException
|
||||
*/
|
||||
private OpenPgpFingerprints determineContactsKeys(BareJid jid)
|
||||
throws SmackOpenPgpException, InterruptedException, XMPPException.XMPPErrorException {
|
||||
Set<OpenPgpV4Fingerprint> announced = provider.getStore().getAnnouncedKeysFingerprints(jid).keySet();
|
||||
Set<OpenPgpV4Fingerprint> available = provider.getStore().getAvailableKeysFingerprints(jid).keySet();
|
||||
Map<OpenPgpV4Fingerprint, Throwable> unfetched = new HashMap<>();
|
||||
for (OpenPgpV4Fingerprint f : announced) {
|
||||
if (!available.contains(f)) {
|
||||
try {
|
||||
PubkeyElement pubkeyElement = PubSubDelegate.fetchPubkey(connection(), jid, f);
|
||||
if (pubkeyElement == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
processPublicKey(pubkeyElement, jid);
|
||||
available.add(f);
|
||||
|
||||
} catch (SmackException e) {
|
||||
LOGGER.log(Level.WARNING, "Could not fetch public key " + f.toString() + " of user " + jid.toString(), e);
|
||||
unfetched.put(f, e);
|
||||
} catch (MissingUserIdOnKeyException e) {
|
||||
LOGGER.log(Level.WARNING, "Key does not contain user-id of " + jid + ". Ignoring the key.", e);
|
||||
unfetched.put(f, e);
|
||||
} catch (IOException e) {
|
||||
LOGGER.log(Level.WARNING, "Could not import key " + f.toString() + " of user " + jid.toString(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new OpenPgpFingerprints(jid, announced, available, unfetched);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link PEPListener} that listens for changes to the OX public keys metadata node.
|
||||
*
|
||||
|
@ -407,52 +370,13 @@ public final class OpenPgpManager extends Manager {
|
|||
}
|
||||
};
|
||||
|
||||
public void requestMetadataUpdate(BareJid contact)
|
||||
throws InterruptedException, SmackException,
|
||||
XMPPException.XMPPErrorException {
|
||||
PublicKeysListElement metadata = PubSubDelegate.fetchPubkeysList(connection(), contact);
|
||||
processPublicKeysListElement(contact, metadata);
|
||||
}
|
||||
|
||||
private void processPublicKeysListElement(BareJid contact, PublicKeysListElement listElement) {
|
||||
Map<OpenPgpV4Fingerprint, Date> announcedKeys = new HashMap<>();
|
||||
for (OpenPgpV4Fingerprint f : listElement.getMetadata().keySet()) {
|
||||
PublicKeysListElement.PubkeyMetadataElement meta = listElement.getMetadata().get(f);
|
||||
announcedKeys.put(meta.getV4Fingerprint(), meta.getDate());
|
||||
}
|
||||
|
||||
provider.getStore().setAnnouncedKeysFingerprints(contact, announcedKeys);
|
||||
|
||||
Set<OpenPgpV4Fingerprint> availableKeys = Collections.emptySet();
|
||||
OpenPgpContact openPgpContact = getOpenPgpContact(contact.asEntityBareJidIfPossible());
|
||||
try {
|
||||
availableKeys = new HashSet<>(provider.getStore().getAvailableKeysFingerprints(contact).keySet());
|
||||
openPgpContact.updateKeys(listElement);
|
||||
} catch (SmackOpenPgpException e) {
|
||||
LOGGER.log(Level.WARNING, "Could not determine available keys", e);
|
||||
}
|
||||
|
||||
Set<OpenPgpV4Fingerprint> missingKeys = listElement.getMetadata().keySet();
|
||||
Map<OpenPgpV4Fingerprint, Throwable> unfetchable = new HashMap<>();
|
||||
try {
|
||||
missingKeys.removeAll(availableKeys);
|
||||
for (OpenPgpV4Fingerprint missing : missingKeys) {
|
||||
try {
|
||||
PubkeyElement pubkeyElement = fetchPubkey(connection(), contact, missing);
|
||||
if (pubkeyElement != null) {
|
||||
processPublicKey(pubkeyElement, contact);
|
||||
availableKeys.add(missing);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.log(Level.WARNING, "Error fetching missing OpenPGP key " + missing.toString(), e);
|
||||
unfetchable.put(missing, e);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.log(Level.WARNING, "Error processing OpenPGP metadata update from " + contact + ".", e);
|
||||
}
|
||||
|
||||
OpenPgpFingerprints fingerprints = new OpenPgpFingerprints(contact, announcedKeys.keySet(), availableKeys, unfetchable);
|
||||
for (OpenPgpContact openPgpContact : openPgpCapableContacts.values()) {
|
||||
openPgpContact.onFingerprintsChanged(contact, fingerprints);
|
||||
LOGGER.log(Level.WARNING, "Could not read key ring of contact " + contact, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -466,14 +390,7 @@ public final class OpenPgpManager extends Manager {
|
|||
return;
|
||||
}
|
||||
|
||||
OpenPgpContact contact;
|
||||
try {
|
||||
contact = getOpenPgpContact(from);
|
||||
} catch (SmackOpenPgpException | InterruptedException | XMPPException.XMPPErrorException |
|
||||
SmackException.NotLoggedInException e) {
|
||||
LOGGER.log(Level.WARNING, "Could not begin encrypted chat with " + from, e);
|
||||
return;
|
||||
}
|
||||
OpenPgpContact contact = getOpenPgpContact(from);
|
||||
|
||||
OpenPgpContentElement contentElement = null;
|
||||
try {
|
||||
|
@ -506,6 +423,10 @@ public final class OpenPgpManager extends Manager {
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
else {
|
||||
throw new AssertionError("Invalid element received: " + contentElement.getClass().getName());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -142,6 +142,15 @@ public interface OpenPgpProvider {
|
|||
throws SmackOpenPgpException, InvalidAlgorithmParameterException, NoSuchAlgorithmException,
|
||||
NoSuchProviderException, IOException;
|
||||
|
||||
/**
|
||||
* Import a public key. The bytes are expected to be decoded from base64.
|
||||
* @param owner
|
||||
* @param bytes
|
||||
* @return
|
||||
* @throws MissingUserIdOnKeyException
|
||||
* @throws IOException
|
||||
* @throws SmackOpenPgpException
|
||||
*/
|
||||
OpenPgpV4Fingerprint importPublicKey(BareJid owner, byte[] bytes)
|
||||
throws MissingUserIdOnKeyException, IOException, SmackOpenPgpException;
|
||||
|
||||
|
|
|
@ -18,10 +18,17 @@ package org.jivesoftware.smackx.ox.chat;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.chat2.ChatManager;
|
||||
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
|
@ -29,51 +36,168 @@ import org.jivesoftware.smack.util.MultiMap;
|
|||
import org.jivesoftware.smack.util.stringencoder.Base64;
|
||||
import org.jivesoftware.smackx.eme.element.ExplicitMessageEncryptionElement;
|
||||
import org.jivesoftware.smackx.hints.element.StoreHint;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpManager;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpProvider;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||
import org.jivesoftware.smackx.ox.element.OpenPgpContentElement;
|
||||
import org.jivesoftware.smackx.ox.element.OpenPgpElement;
|
||||
import org.jivesoftware.smackx.ox.element.PubkeyElement;
|
||||
import org.jivesoftware.smackx.ox.element.PublicKeysListElement;
|
||||
import org.jivesoftware.smackx.ox.element.SigncryptElement;
|
||||
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpKeyPairException;
|
||||
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpPublicKeyException;
|
||||
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException;
|
||||
import org.jivesoftware.smackx.ox.exception.SmackOpenPgpException;
|
||||
import org.jivesoftware.smackx.ox.listener.internal.FingerprintsChangedListener;
|
||||
import org.jivesoftware.smackx.ox.util.DecryptedBytesAndMetadata;
|
||||
import org.jivesoftware.smackx.ox.util.PubSubDelegate;
|
||||
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.jxmpp.jid.Jid;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
public class OpenPgpContact implements FingerprintsChangedListener {
|
||||
public class OpenPgpContact {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(OpenPgpContact.class.getName());
|
||||
|
||||
private final BareJid jid;
|
||||
private OpenPgpFingerprints contactsFingerprints;
|
||||
private OpenPgpFingerprints ourFingerprints;
|
||||
private final OpenPgpProvider cryptoProvider;
|
||||
private final OpenPgpV4Fingerprint singingKey;
|
||||
protected final OpenPgpProvider cryptoProvider;
|
||||
private final XMPPConnection connection;
|
||||
|
||||
private Map<OpenPgpV4Fingerprint, Date> announcedKeys = null;
|
||||
private Map<OpenPgpV4Fingerprint, Date> availableKeys = null;
|
||||
private final Map<OpenPgpV4Fingerprint, Throwable> unfetchableKeys = new HashMap<>();
|
||||
|
||||
public OpenPgpContact(OpenPgpProvider cryptoProvider,
|
||||
BareJid jid,
|
||||
OpenPgpFingerprints ourFingerprints,
|
||||
OpenPgpFingerprints contactsFingerprints) {
|
||||
this.cryptoProvider = cryptoProvider;
|
||||
XMPPConnection connection) {
|
||||
this.jid = jid;
|
||||
this.singingKey = cryptoProvider.getStore().getSigningKeyPairFingerprint();
|
||||
this.ourFingerprints = ourFingerprints;
|
||||
this.contactsFingerprints = contactsFingerprints;
|
||||
this.cryptoProvider = cryptoProvider;
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
public BareJid getJid() {
|
||||
return jid;
|
||||
}
|
||||
|
||||
public OpenPgpFingerprints getFingerprints() {
|
||||
return contactsFingerprints;
|
||||
public Map<OpenPgpV4Fingerprint, Date> getAnnouncedKeys() {
|
||||
if (announcedKeys == null) {
|
||||
announcedKeys = cryptoProvider.getStore().getAnnouncedKeysFingerprints(getJid());
|
||||
}
|
||||
return announcedKeys;
|
||||
}
|
||||
|
||||
public Map<OpenPgpV4Fingerprint, Date> getAvailableKeys() throws SmackOpenPgpException {
|
||||
if (availableKeys == null) {
|
||||
availableKeys = cryptoProvider.getStore().getAvailableKeysFingerprints(getJid());
|
||||
}
|
||||
return availableKeys;
|
||||
}
|
||||
|
||||
public Map<OpenPgpV4Fingerprint, Throwable> getUnfetchableKeys() {
|
||||
return unfetchableKeys;
|
||||
}
|
||||
|
||||
public Set<OpenPgpV4Fingerprint> getActiveKeys() throws SmackOpenPgpException {
|
||||
Set<OpenPgpV4Fingerprint> fingerprints = getAvailableKeys().keySet();
|
||||
fingerprints.retainAll(getAnnouncedKeys().keySet());
|
||||
return fingerprints;
|
||||
}
|
||||
|
||||
public void updateKeys()
|
||||
throws InterruptedException, XMPPException.XMPPErrorException, SmackException, SmackOpenPgpException {
|
||||
updateKeys(PubSubDelegate.fetchPubkeysList(connection, getJid()));
|
||||
}
|
||||
|
||||
public void updateKeys(PublicKeysListElement metadata)
|
||||
throws SmackOpenPgpException {
|
||||
storePublishedDevices(metadata);
|
||||
this.availableKeys = getAvailableKeys();
|
||||
|
||||
for (OpenPgpV4Fingerprint fingerprint : announcedKeys.keySet()) {
|
||||
Date announcedDate = announcedKeys.get(fingerprint);
|
||||
Date availableDate = availableKeys.get(fingerprint);
|
||||
|
||||
if (availableDate == null || availableDate.before(announcedDate)) {
|
||||
try {
|
||||
updateKey(fingerprint);
|
||||
unfetchableKeys.remove(fingerprint);
|
||||
} catch (IOException | XMPPException.XMPPErrorException | SmackException | InterruptedException |
|
||||
SmackOpenPgpException | MissingUserIdOnKeyException | NullPointerException e) {
|
||||
LOGGER.log(Level.WARNING, "Could not update key " + fingerprint + " of " +getJid());
|
||||
unfetchableKeys.put(fingerprint, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateKey(OpenPgpV4Fingerprint fingerprint)
|
||||
throws InterruptedException, XMPPException.XMPPErrorException, SmackException, IOException,
|
||||
MissingUserIdOnKeyException, SmackOpenPgpException {
|
||||
PubkeyElement pubkeyElement = PubSubDelegate.fetchPubkey(connection, getJid(), fingerprint);
|
||||
if (pubkeyElement == null) {
|
||||
throw new NullPointerException("Fetched pubkeyElement for key " + fingerprint + " of " + getJid() + " is null.");
|
||||
}
|
||||
|
||||
byte[] base64 = pubkeyElement.getDataElement().getB64Data();
|
||||
OpenPgpV4Fingerprint imported = importPublicKey(Base64.decode(base64));
|
||||
|
||||
if (!fingerprint.equals(imported)) {
|
||||
// Not sure, if this can/should happen. Lets be safe and throw, even if its too late at this point.
|
||||
throw new AssertionError("Fingerprint of imported key differs from expected fingerprint. " +
|
||||
"Expected: " + fingerprint + " Imported: " + imported);
|
||||
}
|
||||
}
|
||||
|
||||
private OpenPgpV4Fingerprint importPublicKey(byte[] data)
|
||||
throws SmackOpenPgpException, MissingUserIdOnKeyException, IOException {
|
||||
OpenPgpV4Fingerprint fingerprint = cryptoProvider.importPublicKey(getJid(), data);
|
||||
availableKeys.put(fingerprint, new Date());
|
||||
return fingerprint;
|
||||
}
|
||||
|
||||
public Map<OpenPgpV4Fingerprint, Date> storePublishedDevices(PublicKeysListElement element) {
|
||||
Map<OpenPgpV4Fingerprint, Date> announcedKeys = new HashMap<>();
|
||||
|
||||
for (OpenPgpV4Fingerprint f : element.getMetadata().keySet()) {
|
||||
PublicKeysListElement.PubkeyMetadataElement meta = element.getMetadata().get(f);
|
||||
announcedKeys.put(meta.getV4Fingerprint(), meta.getDate());
|
||||
}
|
||||
|
||||
if (!announcedKeys.equals(this.announcedKeys)) {
|
||||
cryptoProvider.getStore().setAnnouncedKeysFingerprints(getJid(), announcedKeys);
|
||||
this.announcedKeys = announcedKeys;
|
||||
}
|
||||
return announcedKeys;
|
||||
}
|
||||
|
||||
private MultiMap<BareJid, OpenPgpV4Fingerprint> getEncryptionKeys()
|
||||
throws SmackOpenPgpException, SmackException.NotLoggedInException {
|
||||
OpenPgpSelf self = getSelf();
|
||||
|
||||
Set<OpenPgpV4Fingerprint> contactsKeys = getActiveKeys();
|
||||
Set<OpenPgpV4Fingerprint> ourKeys = self.getActiveKeys();
|
||||
|
||||
MultiMap<BareJid, OpenPgpV4Fingerprint> recipientsKeys = new MultiMap<>();
|
||||
for (OpenPgpV4Fingerprint fingerprint : contactsKeys) {
|
||||
recipientsKeys.put(getJid(), fingerprint);
|
||||
}
|
||||
|
||||
for (OpenPgpV4Fingerprint fingerprint : ourKeys) {
|
||||
recipientsKeys.put(self.getJid(), fingerprint);
|
||||
}
|
||||
|
||||
return recipientsKeys;
|
||||
}
|
||||
|
||||
private OpenPgpSelf getSelf() throws SmackException.NotLoggedInException {
|
||||
return OpenPgpManager.getInstanceFor(connection).getOpenPgpSelf();
|
||||
}
|
||||
|
||||
public OpenPgpElement encryptAndSign(List<ExtensionElement> payload)
|
||||
throws IOException, SmackOpenPgpException, MissingOpenPgpKeyPairException {
|
||||
MultiMap<BareJid, OpenPgpV4Fingerprint> fingerprints = oursAndRecipientFingerprints();
|
||||
throws IOException, SmackOpenPgpException, MissingOpenPgpKeyPairException,
|
||||
SmackException.NotLoggedInException {
|
||||
|
||||
OpenPgpSelf self = OpenPgpManager.getInstanceFor(connection).getOpenPgpSelf();
|
||||
|
||||
SigncryptElement preparedPayload = new SigncryptElement(
|
||||
Collections.<Jid>singleton(getJid()),
|
||||
|
@ -85,8 +209,8 @@ public class OpenPgpContact implements FingerprintsChangedListener {
|
|||
try {
|
||||
encryptedBytes = cryptoProvider.signAndEncrypt(
|
||||
preparedPayload,
|
||||
singingKey,
|
||||
fingerprints);
|
||||
self.getSigningKey(),
|
||||
getEncryptionKeys());
|
||||
} catch (MissingOpenPgpPublicKeyException e) {
|
||||
throw new AssertionError("Missing OpenPGP public key, even though this should not happen here.", e);
|
||||
}
|
||||
|
@ -95,7 +219,8 @@ public class OpenPgpContact implements FingerprintsChangedListener {
|
|||
}
|
||||
|
||||
public void addSignedEncryptedPayloadTo(Message message, List<ExtensionElement> payload)
|
||||
throws IOException, SmackOpenPgpException, MissingOpenPgpKeyPairException {
|
||||
throws IOException, SmackOpenPgpException, MissingOpenPgpKeyPairException,
|
||||
SmackException.NotLoggedInException {
|
||||
|
||||
// Add encrypted payload to message
|
||||
OpenPgpElement encryptedPayload = encryptAndSign(payload);
|
||||
|
@ -114,8 +239,8 @@ public class OpenPgpContact implements FingerprintsChangedListener {
|
|||
|
||||
public void send(XMPPConnection connection, Message message, List<ExtensionElement> payload)
|
||||
throws MissingOpenPgpKeyPairException, SmackException.NotConnectedException, InterruptedException,
|
||||
SmackOpenPgpException, IOException {
|
||||
MultiMap<BareJid, OpenPgpV4Fingerprint> fingerprints = oursAndRecipientFingerprints();
|
||||
SmackOpenPgpException, IOException, SmackException.NotLoggedInException {
|
||||
MultiMap<BareJid, OpenPgpV4Fingerprint> fingerprints = getEncryptionKeys();
|
||||
|
||||
SigncryptElement preparedPayload = new SigncryptElement(
|
||||
Collections.<Jid>singleton(getJid()),
|
||||
|
@ -128,7 +253,7 @@ public class OpenPgpContact implements FingerprintsChangedListener {
|
|||
try {
|
||||
encryptedMessage = cryptoProvider.signAndEncrypt(
|
||||
preparedPayload,
|
||||
singingKey,
|
||||
getSelf().getSigningKey(),
|
||||
fingerprints);
|
||||
} catch (MissingOpenPgpPublicKeyException e) {
|
||||
throw new AssertionError("Missing OpenPGP public key, even though this should not happen here.", e);
|
||||
|
@ -154,28 +279,4 @@ public class OpenPgpContact implements FingerprintsChangedListener {
|
|||
|
||||
return openPgpMessage.getOpenPgpContentElement();
|
||||
}
|
||||
|
||||
private MultiMap<BareJid, OpenPgpV4Fingerprint> oursAndRecipientFingerprints() {
|
||||
MultiMap<BareJid, OpenPgpV4Fingerprint> fingerprints = new MultiMap<>();
|
||||
for (OpenPgpV4Fingerprint f : contactsFingerprints.getActiveKeys()) {
|
||||
fingerprints.put(contactsFingerprints.getJid(), f);
|
||||
}
|
||||
|
||||
if (!contactsFingerprints.getJid().equals(ourFingerprints.getJid())) {
|
||||
for (OpenPgpV4Fingerprint f : ourFingerprints.getActiveKeys()) {
|
||||
fingerprints.put(ourFingerprints.getJid(), f);
|
||||
}
|
||||
}
|
||||
|
||||
return fingerprints;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFingerprintsChanged(BareJid contact, OpenPgpFingerprints newFingerprints) {
|
||||
if (ourFingerprints.getJid().equals(contact)) {
|
||||
this.ourFingerprints = newFingerprints;
|
||||
} else if (contactsFingerprints.getJid().equals(contact)) {
|
||||
this.contactsFingerprints = newFingerprints;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package org.jivesoftware.smackx.ox.chat;
|
||||
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpProvider;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||
|
||||
import org.jxmpp.jid.BareJid;
|
||||
|
||||
public class OpenPgpSelf extends OpenPgpContact {
|
||||
|
||||
public OpenPgpSelf(OpenPgpProvider cryptoProvider, BareJid jid, XMPPConnection connection) {
|
||||
super(cryptoProvider, jid, connection);
|
||||
}
|
||||
|
||||
public OpenPgpV4Fingerprint getSigningKey() {
|
||||
return cryptoProvider.getStore().getSigningKeyPairFingerprint();
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.ox.listener.internal;
|
||||
|
||||
import org.jivesoftware.smackx.ox.chat.OpenPgpFingerprints;
|
||||
|
||||
import org.jxmpp.jid.BareJid;
|
||||
|
||||
public interface FingerprintsChangedListener {
|
||||
|
||||
void onFingerprintsChanged(BareJid contact, OpenPgpFingerprints newFingerprints);
|
||||
}
|
|
@ -212,7 +212,7 @@ public class PubSubDelegate {
|
|||
try {
|
||||
pm.deleteNode(PEP_NODE_PUBLIC_KEYS);
|
||||
} catch (XMPPException.XMPPErrorException e) {
|
||||
if (e.getXMPPError().getCondition() == StanzaError.Condition.item_not_found) {
|
||||
if (e.getStanzaError().getCondition() == StanzaError.Condition.item_not_found) {
|
||||
LOGGER.log(Level.FINE, "Node does not exist. No need to delete it.");
|
||||
} else {
|
||||
throw e;
|
||||
|
@ -237,7 +237,7 @@ public class PubSubDelegate {
|
|||
try {
|
||||
pm.deleteNode(PEP_NODE_PUBLIC_KEY(fingerprint));
|
||||
} catch (XMPPException.XMPPErrorException e) {
|
||||
if (e.getXMPPError().getCondition() == StanzaError.Condition.item_not_found) {
|
||||
if (e.getStanzaError().getCondition() == StanzaError.Condition.item_not_found) {
|
||||
LOGGER.log(Level.FINE, "Node does not exist. No need to delete it.");
|
||||
} else {
|
||||
throw e;
|
||||
|
|
Loading…
Reference in a new issue