mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-12-22 20:47:57 +01:00
Introduce CapsVersionAndHash
Entity Capability versions are useless without the information which hash algorithm was used to calculate those. Right now, only 'sha-1' is used, but this may change in the feature. This commit makes the first steps preparing for such a feature. Also fixes a minor bug: - CAPS_CACHE.put(currentCapsVersion, discoverInfo); currentCapsVersion is not a valid key for the cache, as it does cache "node + '#' + ver" to disco infos.
This commit is contained in:
parent
96f8bee78e
commit
5dd97a363c
3 changed files with 73 additions and 23 deletions
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
*
|
||||
* Copyright © 2014 Florian Schmaus
|
||||
*
|
||||
* 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.caps;
|
||||
|
||||
public class CapsVersionAndHash {
|
||||
public final String version;
|
||||
public final String hash;
|
||||
|
||||
public CapsVersionAndHash(String version, String hash) {
|
||||
this.version = version;
|
||||
this.hash = hash;
|
||||
}
|
||||
}
|
|
@ -34,6 +34,7 @@ import org.jivesoftware.smack.filter.PacketFilter;
|
|||
import org.jivesoftware.smack.filter.AndFilter;
|
||||
import org.jivesoftware.smack.filter.PacketTypeFilter;
|
||||
import org.jivesoftware.smack.filter.PacketExtensionFilter;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smack.util.stringencoder.Base64;
|
||||
import org.jivesoftware.smackx.caps.cache.EntityCapsPersistentCache;
|
||||
import org.jivesoftware.smackx.caps.packet.CapsExtension;
|
||||
|
@ -76,6 +77,12 @@ public class EntityCapsManager extends Manager {
|
|||
public static final String ELEMENT = CapsExtension.ELEMENT;
|
||||
|
||||
private static final Map<String, MessageDigest> SUPPORTED_HASHES = new HashMap<String, MessageDigest>();
|
||||
|
||||
/**
|
||||
* The default hash. Currently 'sha-1'.
|
||||
*/
|
||||
private static final String DEFAULT_HASH = StringUtils.SHA1;
|
||||
|
||||
private static String DEFAULT_ENTITY_NODE = "http://www.igniterealtime.org/projects/smack";
|
||||
|
||||
protected static EntityCapsPersistentCache persistentCache;
|
||||
|
@ -92,7 +99,7 @@ public class EntityCapsManager extends Manager {
|
|||
private static final PacketFilter PRESENCES = PacketTypeFilter.PRESENCE;
|
||||
|
||||
/**
|
||||
* Map of (node + '#" + hash algorithm) to DiscoverInfo data
|
||||
* Map of "node + '#' + hash" to DiscoverInfo data
|
||||
*/
|
||||
private static final LruCache<String, DiscoverInfo> CAPS_CACHE = new LruCache<String, DiscoverInfo>(1000);
|
||||
|
||||
|
@ -112,8 +119,8 @@ public class EntityCapsManager extends Manager {
|
|||
});
|
||||
|
||||
try {
|
||||
MessageDigest sha1MessageDigest = MessageDigest.getInstance("SHA-1");
|
||||
SUPPORTED_HASHES.put("sha-1", sha1MessageDigest);
|
||||
MessageDigest sha1MessageDigest = MessageDigest.getInstance(DEFAULT_HASH);
|
||||
SUPPORTED_HASHES.put(DEFAULT_HASH, sha1MessageDigest);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// Ignore
|
||||
}
|
||||
|
@ -238,9 +245,12 @@ public class EntityCapsManager extends Manager {
|
|||
}
|
||||
|
||||
private static void addCapsExtensionInfo(String from, CapsExtension capsExtension) {
|
||||
String hash = capsExtension.getHash().toLowerCase(Locale.US);
|
||||
if (!SUPPORTED_HASHES.containsKey(hash))
|
||||
String capsExtensionHash = capsExtension.getHash();
|
||||
String hashInUppercase = capsExtensionHash.toUpperCase(Locale.US);
|
||||
// SUPPORTED_HASHES uses the format of MessageDigest, which is uppercase, e.g. "SHA-1" instead of "sha-1"
|
||||
if (!SUPPORTED_HASHES.containsKey(hashInUppercase))
|
||||
return;
|
||||
String hash = capsExtensionHash.toLowerCase(Locale.US);
|
||||
|
||||
String node = capsExtension.getNode();
|
||||
String ver = capsExtension.getVer();
|
||||
|
@ -248,12 +258,12 @@ public class EntityCapsManager extends Manager {
|
|||
JID_TO_NODEVER_CACHE.put(from, new NodeVerHash(node, ver, hash));
|
||||
}
|
||||
|
||||
private final Queue<String> lastLocalCapsVersions = new ConcurrentLinkedQueue<String>();
|
||||
private final Queue<CapsVersionAndHash> lastLocalCapsVersions = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private final ServiceDiscoveryManager sdm;
|
||||
|
||||
private boolean entityCapsEnabled;
|
||||
private String currentCapsVersion;
|
||||
private CapsVersionAndHash currentCapsVersion;
|
||||
private boolean presenceSend = false;
|
||||
|
||||
/**
|
||||
|
@ -346,8 +356,8 @@ public class EntityCapsManager extends Manager {
|
|||
public void processPacket(Packet packet) {
|
||||
if (!entityCapsEnabled)
|
||||
return;
|
||||
|
||||
CapsExtension caps = new CapsExtension(entityNode, getCapsVersion(), "sha-1");
|
||||
CapsVersionAndHash capsVersionAndHash = getCapsVersion();
|
||||
CapsExtension caps = new CapsExtension(entityNode, capsVersionAndHash.version, capsVersionAndHash.hash);
|
||||
packet.addExtension(caps);
|
||||
}
|
||||
};
|
||||
|
@ -407,7 +417,7 @@ public class EntityCapsManager extends Manager {
|
|||
*
|
||||
* @return our own caps version
|
||||
*/
|
||||
public String getCapsVersion() {
|
||||
public CapsVersionAndHash getCapsVersion() {
|
||||
return currentCapsVersion;
|
||||
}
|
||||
|
||||
|
@ -464,17 +474,16 @@ public class EntityCapsManager extends Manager {
|
|||
discoverInfo.setFrom(connection.getUser());
|
||||
sdm.addDiscoverInfoTo(discoverInfo);
|
||||
|
||||
currentCapsVersion = generateVerificationString(discoverInfo, "sha-1");
|
||||
currentCapsVersion = generateVerificationString(discoverInfo);
|
||||
addDiscoverInfoByNode(entityNode + '#' + currentCapsVersion, discoverInfo);
|
||||
if (lastLocalCapsVersions.size() > 10) {
|
||||
String oldCapsVersion = lastLocalCapsVersions.poll();
|
||||
sdm.removeNodeInformationProvider(entityNode + '#' + oldCapsVersion);
|
||||
CapsVersionAndHash oldCapsVersion = lastLocalCapsVersions.poll();
|
||||
sdm.removeNodeInformationProvider(entityNode + '#' + oldCapsVersion.version);
|
||||
}
|
||||
lastLocalCapsVersions.add(currentCapsVersion);
|
||||
|
||||
CAPS_CACHE.put(currentCapsVersion, discoverInfo);
|
||||
if (connection != null)
|
||||
JID_TO_NODEVER_CACHE.put(connection.getUser(), new NodeVerHash(entityNode, currentCapsVersion, "sha-1"));
|
||||
JID_TO_NODEVER_CACHE.put(connection.getUser(), new NodeVerHash(entityNode, currentCapsVersion));
|
||||
|
||||
final List<Identity> identities = new LinkedList<Identity>(ServiceDiscoveryManager.getInstanceFor(connection).getIdentities());
|
||||
sdm.setNodeInformationProvider(entityNode + '#' + currentCapsVersion, new AbstractNodeInformationProvider() {
|
||||
|
@ -535,7 +544,7 @@ public class EntityCapsManager extends Manager {
|
|||
if (verifyPacketExtensions(info))
|
||||
return false;
|
||||
|
||||
String calculatedVer = generateVerificationString(info, hash);
|
||||
String calculatedVer = generateVerificationString(info, hash).version;
|
||||
|
||||
if (!ver.equals(calculatedVer))
|
||||
return false;
|
||||
|
@ -567,6 +576,10 @@ public class EntityCapsManager extends Manager {
|
|||
return false;
|
||||
}
|
||||
|
||||
protected static CapsVersionAndHash generateVerificationString(DiscoverInfo discoverInfo) {
|
||||
return generateVerificationString(discoverInfo, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a XEP-115 Verification String
|
||||
*
|
||||
|
@ -575,12 +588,15 @@ public class EntityCapsManager extends Manager {
|
|||
*
|
||||
* @param discoverInfo
|
||||
* @param hash
|
||||
* the used hash function
|
||||
* the used hash function, if null, default hash will be used
|
||||
* @return The generated verification String or null if the hash is not
|
||||
* supported
|
||||
*/
|
||||
protected static String generateVerificationString(DiscoverInfo discoverInfo, String hash) {
|
||||
MessageDigest md = SUPPORTED_HASHES.get(hash.toLowerCase(Locale.US));
|
||||
protected static CapsVersionAndHash generateVerificationString(DiscoverInfo discoverInfo, String hash) {
|
||||
if (hash == null) {
|
||||
hash = DEFAULT_HASH;
|
||||
}
|
||||
MessageDigest md = SUPPORTED_HASHES.get(hash.toUpperCase(Locale.US));
|
||||
if (md == null)
|
||||
return null;
|
||||
|
||||
|
@ -682,7 +698,8 @@ public class EntityCapsManager extends Manager {
|
|||
synchronized(md) {
|
||||
digest = md.digest(sb.toString().getBytes());
|
||||
}
|
||||
return Base64.encodeToString(digest);
|
||||
String version = Base64.encodeToString(digest);
|
||||
return new CapsVersionAndHash(version, hash);
|
||||
}
|
||||
|
||||
private static void formFieldValuesToCaps(List<String> i, StringBuilder sb) {
|
||||
|
@ -702,6 +719,10 @@ public class EntityCapsManager extends Manager {
|
|||
private String ver;
|
||||
private String nodeVer;
|
||||
|
||||
NodeVerHash(String node, CapsVersionAndHash capsVersionAndHash) {
|
||||
this(node, capsVersionAndHash.version, capsVersionAndHash.hash);
|
||||
}
|
||||
|
||||
NodeVerHash(String node, String ver, String hash) {
|
||||
this.node = node;
|
||||
this.ver = ver;
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.util.LinkedList;
|
|||
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smack.util.stringencoder.Base32;
|
||||
import org.jivesoftware.smack.util.stringencoder.StringEncoder;
|
||||
import org.jivesoftware.smackx.InitExtensions;
|
||||
|
@ -54,8 +55,8 @@ public class EntityCapsManagerTest extends InitExtensions {
|
|||
public void testComplexGenerationExample() {
|
||||
DiscoverInfo di = createComplexSamplePacket();
|
||||
|
||||
String ver = EntityCapsManager.generateVerificationString(di, "sha-1");
|
||||
assertEquals("q07IKJEyjvHSyhy//CH0CxmKi8w=", ver);
|
||||
CapsVersionAndHash versionAndHash = EntityCapsManager.generateVerificationString(di, StringUtils.SHA1);
|
||||
assertEquals("q07IKJEyjvHSyhy//CH0CxmKi8w=", versionAndHash.version);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -82,7 +83,8 @@ public class EntityCapsManagerTest extends InitExtensions {
|
|||
EntityCapsManager.setPersistentCache(cache);
|
||||
|
||||
DiscoverInfo di = createComplexSamplePacket();
|
||||
String nodeVer = di.getNode() + "#" + EntityCapsManager.generateVerificationString(di, "sha-1");
|
||||
CapsVersionAndHash versionAndHash = EntityCapsManager.generateVerificationString(di, StringUtils.SHA1);
|
||||
String nodeVer = di.getNode() + "#" + versionAndHash.version;
|
||||
|
||||
// Save the data in EntityCapsManager
|
||||
EntityCapsManager.addDiscoverInfoByNode(nodeVer, di);
|
||||
|
|
Loading…
Reference in a new issue