mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-23 20:42:06 +01:00
Rename store methods and fix access to open pubsub nodes
This commit is contained in:
parent
6a756c9a44
commit
613c5d869a
10 changed files with 110 additions and 60 deletions
|
@ -24,7 +24,6 @@ import java.util.logging.Level;
|
|||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.roster.Roster;
|
||||
import org.jivesoftware.smack.util.FileUtils;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smackx.ox.OXInstantMessagingManager;
|
||||
|
@ -76,15 +75,6 @@ public class BasicOpenPgpInstantMessagingIntegrationTest extends AbstractOpenPgp
|
|||
final SimpleResultSyncPoint bobReceivedMessage = new SimpleResultSyncPoint();
|
||||
final String body = "Writing integration tests is an annoying task, but it has to be done, so lets do it!!!";
|
||||
|
||||
Roster aliceRoster = Roster.getInstanceFor(aliceConnection);
|
||||
Roster bobRoster = Roster.getInstanceFor(bobConnection);
|
||||
|
||||
aliceRoster.setSubscriptionMode(Roster.SubscriptionMode.accept_all);
|
||||
bobRoster.setSubscriptionMode(Roster.SubscriptionMode.accept_all);
|
||||
|
||||
aliceRoster.createEntry(bob, "Bob", null);
|
||||
bobRoster.createEntry(alice, "Alice", null);
|
||||
|
||||
FileBasedPainlessOpenPgpStore aliceStore = new FileBasedPainlessOpenPgpStore(aliceStorePath, new UnprotectedKeysProtector());
|
||||
FileBasedPainlessOpenPgpStore bobStore = new FileBasedPainlessOpenPgpStore(bobStorePath, new UnprotectedKeysProtector());
|
||||
|
||||
|
@ -114,8 +104,8 @@ public class BasicOpenPgpInstantMessagingIntegrationTest extends AbstractOpenPgp
|
|||
aliceFingerprint = aliceOpenPgp.generateAndImportKeyPair(alice);
|
||||
bobFingerprint = bobOpenPgp.generateAndImportKeyPair(bob);
|
||||
|
||||
aliceStore.setPrimaryOpenPgpKeyPairFingerprint(aliceFingerprint);
|
||||
bobStore.setPrimaryOpenPgpKeyPairFingerprint(bobFingerprint);
|
||||
aliceStore.setSigningKeyPairFingerprint(aliceFingerprint);
|
||||
bobStore.setSigningKeyPairFingerprint(bobFingerprint);
|
||||
|
||||
aliceOpenPgp.announceSupportAndPublish();
|
||||
bobOpenPgp.announceSupportAndPublish();
|
||||
|
|
|
@ -101,11 +101,11 @@ public class SecretKeyBackupRestoreIntegrationTest extends AbstractOpenPgpIntegr
|
|||
OpenPgpManager openPgpManager = OpenPgpManager.getInstanceFor(aliceConnection);
|
||||
openPgpManager.setOpenPgpProvider(beforeProvider);
|
||||
|
||||
assertNull(beforeStore.getPrimaryOpenPgpKeyPairFingerprint());
|
||||
assertNull(beforeStore.getSigningKeyPairFingerprint());
|
||||
|
||||
OpenPgpV4Fingerprint keyFingerprint = openPgpManager.generateAndImportKeyPair(alice);
|
||||
beforeStore.setPrimaryOpenPgpKeyPairFingerprint(keyFingerprint);
|
||||
assertEquals(keyFingerprint, beforeStore.getPrimaryOpenPgpKeyPairFingerprint());
|
||||
beforeStore.setSigningKeyPairFingerprint(keyFingerprint);
|
||||
assertEquals(keyFingerprint, beforeStore.getSigningKeyPairFingerprint());
|
||||
|
||||
assertTrue(beforeStore.getAvailableKeyPairFingerprints(alice).contains(keyFingerprint));
|
||||
|
||||
|
@ -125,7 +125,7 @@ public class SecretKeyBackupRestoreIntegrationTest extends AbstractOpenPgpIntegr
|
|||
PainlessOpenPgpProvider afterProvider = new PainlessOpenPgpProvider(alice, afterStore);
|
||||
openPgpManager.setOpenPgpProvider(afterProvider);
|
||||
|
||||
assertNull(afterStore.getPrimaryOpenPgpKeyPairFingerprint());
|
||||
assertNull(afterStore.getSigningKeyPairFingerprint());
|
||||
assertFalse(afterStore.getAvailableKeyPairFingerprints(alice).contains(keyFingerprint));
|
||||
|
||||
OpenPgpV4Fingerprint fingerprint = openPgpManager.restoreSecretKeyServerBackup(new AskForBackupCodeCallback() {
|
||||
|
@ -142,9 +142,9 @@ public class SecretKeyBackupRestoreIntegrationTest extends AbstractOpenPgpIntegr
|
|||
|
||||
assertTrue(afterStore.getAvailableKeyPairFingerprints(alice).contains(keyFingerprint));
|
||||
|
||||
afterStore.setPrimaryOpenPgpKeyPairFingerprint(fingerprint);
|
||||
afterStore.setSigningKeyPairFingerprint(fingerprint);
|
||||
|
||||
assertEquals(keyFingerprint, afterStore.getPrimaryOpenPgpKeyPairFingerprint());
|
||||
assertEquals(keyFingerprint, afterStore.getSigningKeyPairFingerprint());
|
||||
assertTrue(Arrays.equals(beforeStore.getSecretKeyRings(alice).getEncoded(), afterStore.getSecretKeyRings(alice).getEncoded()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,12 +39,12 @@ public abstract class AbstractPainlessOpenPgpStore implements PainlessOpenPgpSto
|
|||
private final SecretKeyRingProtector secretKeyRingProtector;
|
||||
|
||||
@Override
|
||||
public OpenPgpV4Fingerprint getPrimaryOpenPgpKeyPairFingerprint() {
|
||||
public OpenPgpV4Fingerprint getSigningKeyPairFingerprint() {
|
||||
return primaryKeyFingerprint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrimaryOpenPgpKeyPairFingerprint(OpenPgpV4Fingerprint fingerprint) {
|
||||
public void setSigningKeyPairFingerprint(OpenPgpV4Fingerprint fingerprint) {
|
||||
this.primaryKeyFingerprint = fingerprint;
|
||||
}
|
||||
|
||||
|
|
|
@ -220,7 +220,7 @@ public class PainlessOpenPgpProvider implements OpenPgpProvider {
|
|||
secretKeyRings = getStore().getSecretKeyRings(owner);
|
||||
} catch (PGPException | IOException e) {
|
||||
LOGGER.log(Level.INFO, "Could not get secret keys of user " + owner);
|
||||
throw new MissingOpenPgpKeyPairException(owner, getStore().getPrimaryOpenPgpKeyPairFingerprint());
|
||||
throw new MissingOpenPgpKeyPairException(owner, getStore().getSigningKeyPairFingerprint());
|
||||
}
|
||||
|
||||
SecretKeyRingProtector protector = getStore().getSecretKeyProtector();
|
||||
|
|
|
@ -90,8 +90,8 @@ public class DryOxEncryptionTest extends OxTestSuite {
|
|||
OpenPgpV4Fingerprint romeoFinger = romeoProvider.importSecretKey(romemo,
|
||||
BCUtil.getDecodedBytes(TestKeys.ROMEO_PRIV.getBytes(UTF8)));
|
||||
|
||||
julietStore.setPrimaryOpenPgpKeyPairFingerprint(julietFinger);
|
||||
romeoStore.setPrimaryOpenPgpKeyPairFingerprint(romeoFinger);
|
||||
julietStore.setSigningKeyPairFingerprint(julietFinger);
|
||||
romeoStore.setSigningKeyPairFingerprint(romeoFinger);
|
||||
|
||||
byte[] julietPubBytes = julietStore.getPublicKeyRingBytes(juliet, julietFinger);
|
||||
byte[] romeoPubBytes = romeoStore.getPublicKeyRingBytes(romemo, romeoFinger);
|
||||
|
|
|
@ -219,7 +219,7 @@ public final class OpenPgpManager extends Manager {
|
|||
*/
|
||||
public OpenPgpV4Fingerprint getOurFingerprint() {
|
||||
throwIfNoProviderSet();
|
||||
return provider.getStore().getPrimaryOpenPgpKeyPairFingerprint();
|
||||
return provider.getStore().getSigningKeyPairFingerprint();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -362,12 +362,9 @@ public final class OpenPgpManager extends Manager {
|
|||
* @throws SmackOpenPgpException
|
||||
* @throws InterruptedException
|
||||
* @throws XMPPException.XMPPErrorException
|
||||
* @throws SmackException.NotConnectedException
|
||||
* @throws SmackException.NoResponseException
|
||||
*/
|
||||
private OpenPgpFingerprints determineContactsKeys(BareJid jid)
|
||||
throws SmackOpenPgpException, InterruptedException, XMPPException.XMPPErrorException,
|
||||
SmackException.NotConnectedException, SmackException.NoResponseException {
|
||||
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<>();
|
||||
|
@ -382,7 +379,7 @@ public final class OpenPgpManager extends Manager {
|
|||
processPublicKey(pubkeyElement, jid);
|
||||
available.add(f);
|
||||
|
||||
} catch (PubSubException.NotAPubSubNodeException | PubSubException.NotALeafNodeException e) {
|
||||
} 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) {
|
||||
|
@ -422,9 +419,8 @@ public final class OpenPgpManager extends Manager {
|
|||
};
|
||||
|
||||
public void requestMetadataUpdate(BareJid contact)
|
||||
throws InterruptedException, PubSubException.NotALeafNodeException, SmackException.NoResponseException,
|
||||
SmackException.NotConnectedException, XMPPException.XMPPErrorException,
|
||||
PubSubException.NotAPubSubNodeException {
|
||||
throws InterruptedException, SmackException,
|
||||
XMPPException.XMPPErrorException {
|
||||
PublicKeysListElement metadata = PubSubDelegate.fetchPubkeysList(connection(), contact);
|
||||
processPublicKeysListElement(contact, metadata);
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ public interface OpenPgpProvider {
|
|||
throws MissingOpenPgpKeyPairException, MissingOpenPgpPublicKeyException, SmackOpenPgpException, IOException;
|
||||
|
||||
/**
|
||||
* Sign a {@link SignElement} with th users signing key.
|
||||
* Sign a {@link SignElement} with the users signing key.
|
||||
* The resulting byte array contains the signed byte representation of the {@link SignElement}.
|
||||
*
|
||||
* @see <a href="https://xmpp.org/extensions/xep-0373.html#exchange">XEP-0373 §3.1</a>
|
||||
|
|
|
@ -37,7 +37,7 @@ public interface OpenPgpStore {
|
|||
*
|
||||
* @return fingerprint of the primary OpenPGP key pair.
|
||||
*/
|
||||
OpenPgpV4Fingerprint getPrimaryOpenPgpKeyPairFingerprint();
|
||||
OpenPgpV4Fingerprint getSigningKeyPairFingerprint();
|
||||
|
||||
/**
|
||||
* Set the {@link OpenPgpV4Fingerprint} of the primary OpenPGP key pair.
|
||||
|
@ -45,7 +45,7 @@ public interface OpenPgpStore {
|
|||
*
|
||||
* @param fingerprint {@link OpenPgpV4Fingerprint} of the new primary key pair.
|
||||
*/
|
||||
void setPrimaryOpenPgpKeyPairFingerprint(OpenPgpV4Fingerprint fingerprint);
|
||||
void setSigningKeyPairFingerprint(OpenPgpV4Fingerprint fingerprint);
|
||||
|
||||
/**
|
||||
* Return a {@link Set} containing the {@link OpenPgpV4Fingerprint}s of the master keys of all available
|
||||
|
@ -127,6 +127,8 @@ public interface OpenPgpStore {
|
|||
* @param owner owner of the key
|
||||
* @param fingerprint fingerprint of the key
|
||||
* @return byte representation of the public key.
|
||||
*
|
||||
* @throws MissingOpenPgpPublicKeyException if the key does not exist.
|
||||
*/
|
||||
byte[] getPublicKeyRingBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint)
|
||||
throws MissingOpenPgpPublicKeyException;
|
||||
|
@ -137,6 +139,8 @@ public interface OpenPgpStore {
|
|||
* @param owner owner of the key
|
||||
* @param fingerprint fingerprint of the key
|
||||
* @return byte representation of the secret key.
|
||||
*
|
||||
* @throws MissingOpenPgpKeyPairException if the secret key doesn't exist.
|
||||
*/
|
||||
byte[] getSecretKeyRingBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint)
|
||||
throws MissingOpenPgpKeyPairException;
|
||||
|
|
|
@ -57,7 +57,7 @@ public class OpenPgpContact {
|
|||
OpenPgpFingerprints contactsFingerprints) {
|
||||
this.cryptoProvider = cryptoProvider;
|
||||
this.jid = jid;
|
||||
this.singingKey = cryptoProvider.getStore().getPrimaryOpenPgpKeyPairFingerprint();
|
||||
this.singingKey = cryptoProvider.getStore().getSigningKeyPairFingerprint();
|
||||
this.ourFingerprints = ourFingerprints;
|
||||
this.contactsFingerprints = contactsFingerprints;
|
||||
}
|
||||
|
|
|
@ -16,8 +16,12 @@
|
|||
*/
|
||||
package org.jivesoftware.smackx.ox.util;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -35,6 +39,7 @@ import org.jivesoftware.smackx.pubsub.AccessModel;
|
|||
import org.jivesoftware.smackx.pubsub.ConfigureForm;
|
||||
import org.jivesoftware.smackx.pubsub.Item;
|
||||
import org.jivesoftware.smackx.pubsub.LeafNode;
|
||||
import org.jivesoftware.smackx.pubsub.Node;
|
||||
import org.jivesoftware.smackx.pubsub.PayloadItem;
|
||||
import org.jivesoftware.smackx.pubsub.PubSubException;
|
||||
import org.jivesoftware.smackx.pubsub.PubSubManager;
|
||||
|
@ -157,19 +162,16 @@ public class PubSubDelegate {
|
|||
*
|
||||
* @return content of our metadata node.
|
||||
* @throws InterruptedException
|
||||
* @throws PubSubException.NotALeafNodeException
|
||||
* @throws SmackException.NoResponseException
|
||||
* @throws SmackException.NotConnectedException
|
||||
* @throws SmackException
|
||||
* @throws XMPPException.XMPPErrorException
|
||||
* @throws PubSubException.NotAPubSubNodeException
|
||||
*/
|
||||
public static PublicKeysListElement fetchPubkeysList(XMPPConnection connection)
|
||||
throws InterruptedException, PubSubException.NotALeafNodeException, SmackException.NoResponseException,
|
||||
SmackException.NotConnectedException, XMPPException.XMPPErrorException,
|
||||
PubSubException.NotAPubSubNodeException {
|
||||
throws InterruptedException, SmackException,
|
||||
XMPPException.XMPPErrorException {
|
||||
return fetchPubkeysList(connection, connection.getUser().asBareJid());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Consult the public key metadata node of {@code contact} to fetch the list of their published OpenPGP public keys.
|
||||
* TODO: Add @see which points to the (for now missing) respective example in XEP-0373.
|
||||
|
@ -177,19 +179,15 @@ public class PubSubDelegate {
|
|||
* @param contact {@link BareJid} of the user we want to fetch the list from.
|
||||
* @return content of {@code contact}'s metadata node.
|
||||
* @throws InterruptedException
|
||||
* @throws PubSubException.NotALeafNodeException
|
||||
* @throws SmackException.NoResponseException
|
||||
* @throws SmackException.NotConnectedException
|
||||
* @throws SmackException
|
||||
* @throws XMPPException.XMPPErrorException
|
||||
* @throws PubSubException.NotAPubSubNodeException
|
||||
*/
|
||||
public static PublicKeysListElement fetchPubkeysList(XMPPConnection connection, BareJid contact)
|
||||
throws InterruptedException, PubSubException.NotALeafNodeException, SmackException.NoResponseException,
|
||||
SmackException.NotConnectedException, XMPPException.XMPPErrorException,
|
||||
PubSubException.NotAPubSubNodeException {
|
||||
throws InterruptedException, SmackException,
|
||||
XMPPException.XMPPErrorException {
|
||||
PubSubManager pm = PubSubManager.getInstance(connection, contact);
|
||||
|
||||
LeafNode node = pm.getLeafNode(PEP_NODE_PUBLIC_KEYS);
|
||||
LeafNode node = getOpenLeafNode(pm, PEP_NODE_PUBLIC_KEYS);
|
||||
List<PayloadItem<PublicKeysListElement>> list = node.getItems(1);
|
||||
|
||||
if (list.isEmpty()) {
|
||||
|
@ -247,6 +245,7 @@ public class PubSubDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetch the OpenPGP public key of a {@code contact}, identified by its OpenPGP {@code v4_fingerprint}.
|
||||
*
|
||||
|
@ -255,20 +254,16 @@ public class PubSubDelegate {
|
|||
* @param contact {@link BareJid} of the contact we want to fetch a key from.
|
||||
* @param v4_fingerprint upper case, hex encoded v4 fingerprint of the contacts key.
|
||||
* @return {@link PubkeyElement} containing the requested public key.
|
||||
* @throws InterruptedException
|
||||
* @throws PubSubException.NotALeafNodeException
|
||||
* @throws SmackException.NoResponseException
|
||||
* @throws SmackException.NotConnectedException
|
||||
*
|
||||
* @throws InterruptedException if we get interrupted.
|
||||
* @throws SmackException in case the node cannot be fetched.
|
||||
* @throws XMPPException.XMPPErrorException
|
||||
* @throws PubSubException.NotAPubSubNodeException
|
||||
*/
|
||||
public static PubkeyElement fetchPubkey(XMPPConnection connection, BareJid contact, OpenPgpV4Fingerprint v4_fingerprint)
|
||||
throws InterruptedException, PubSubException.NotALeafNodeException, SmackException.NoResponseException,
|
||||
SmackException.NotConnectedException, XMPPException.XMPPErrorException,
|
||||
PubSubException.NotAPubSubNodeException {
|
||||
throws InterruptedException, SmackException, XMPPException.XMPPErrorException {
|
||||
PubSubManager pm = PubSubManager.getInstance(connection, contact);
|
||||
|
||||
LeafNode node = pm.getLeafNode(PEP_NODE_PUBLIC_KEY(v4_fingerprint));
|
||||
LeafNode node = getOpenLeafNode(pm, PEP_NODE_PUBLIC_KEY(v4_fingerprint));
|
||||
List<PayloadItem<PubkeyElement>> list = node.getItems(1);
|
||||
|
||||
if (list.isEmpty()) {
|
||||
|
@ -352,4 +347,69 @@ public class PubSubDelegate {
|
|||
PubSubManager pm = PubSubManager.getInstance(connection);
|
||||
pm.deleteNode(PEP_NODE_SECRET_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use reflection magic to get a {@link LeafNode} without doing a disco#info query.
|
||||
* This method is useful for fetching nodes that are configured with the access model 'open', since
|
||||
* some servers that announce support for that access model do not allow disco#info queries from contacts
|
||||
* which are not subscribed to the node owner. Therefore this method fetches the node directly and puts it
|
||||
* into the {@link PubSubManager}s node map.
|
||||
*
|
||||
* @see <a href="https://github.com/processone/ejabberd/issues/2483">Ejabberd bug tracker about the issue</a>
|
||||
*
|
||||
* @param pubSubManager pubsub manager
|
||||
* @param nodeName name of the node
|
||||
* @return leafNode
|
||||
*
|
||||
* @throws SmackException if something goes wrong with reflections.
|
||||
* @throws PubSubException.NotALeafNodeException if the node is already in the nodeMap, but is NOT a LeafNode.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static LeafNode getOpenLeafNode(PubSubManager pubSubManager, String nodeName)
|
||||
throws SmackException, PubSubException.NotALeafNodeException {
|
||||
|
||||
try {
|
||||
|
||||
// Get access to the PubSubManager's nodeMap
|
||||
Field field = pubSubManager.getClass().getDeclaredField("nodeMap");
|
||||
field.setAccessible(true);
|
||||
// CHECKSTYLE:OFF
|
||||
Map<String, Node> nodeMap = (Map) field.get(pubSubManager);
|
||||
// CHECKSTYLE:ON
|
||||
|
||||
// Check, if the node already exists
|
||||
Node existingNode = nodeMap.get(nodeName);
|
||||
if (existingNode != null) {
|
||||
|
||||
if (existingNode instanceof LeafNode) {
|
||||
// We already know that node
|
||||
return (LeafNode) existingNode;
|
||||
|
||||
} else {
|
||||
// Throw a new NotALeafNodeException, as the node is not a LeafNode.
|
||||
// Again use reflections to access the exceptions constructor.
|
||||
Constructor<PubSubException.NotALeafNodeException> exceptionConstructor =
|
||||
PubSubException.NotALeafNodeException.class.getDeclaredConstructor(String.class, BareJid.class);
|
||||
exceptionConstructor.setAccessible(true);
|
||||
throw exceptionConstructor.newInstance(nodeName, pubSubManager.getServiceJid());
|
||||
}
|
||||
}
|
||||
|
||||
// Node does not exist. Create the node
|
||||
Constructor<LeafNode> constructor;
|
||||
constructor = LeafNode.class.getDeclaredConstructor(PubSubManager.class, String.class);
|
||||
constructor.setAccessible(true);
|
||||
LeafNode node = constructor.newInstance(pubSubManager, nodeName);
|
||||
|
||||
// Add it to the node map
|
||||
nodeMap.put(nodeName, node);
|
||||
|
||||
// And return
|
||||
return node;
|
||||
|
||||
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException |
|
||||
NoSuchFieldException e) {
|
||||
throw new SmackException("Using reflections to create a LeafNode and put it into PubSubManagers nodeMap failed.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue