mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-27 14:32:06 +01:00
Add method to decrypt OmemoElements from a MamQueryResult
This commit is contained in:
parent
2b71b20a3e
commit
ba0b81f750
2 changed files with 115 additions and 7 deletions
|
@ -25,6 +25,7 @@ import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
@ -49,7 +50,9 @@ import org.jivesoftware.smackx.carbons.CarbonManager;
|
||||||
import org.jivesoftware.smackx.carbons.packet.CarbonExtension;
|
import org.jivesoftware.smackx.carbons.packet.CarbonExtension;
|
||||||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||||
import org.jivesoftware.smackx.eme.element.ExplicitMessageEncryptionElement;
|
import org.jivesoftware.smackx.eme.element.ExplicitMessageEncryptionElement;
|
||||||
|
import org.jivesoftware.smackx.forward.packet.Forwarded;
|
||||||
import org.jivesoftware.smackx.hints.element.StoreHint;
|
import org.jivesoftware.smackx.hints.element.StoreHint;
|
||||||
|
import org.jivesoftware.smackx.mam.MamManager;
|
||||||
import org.jivesoftware.smackx.muc.MultiUserChat;
|
import org.jivesoftware.smackx.muc.MultiUserChat;
|
||||||
import org.jivesoftware.smackx.muc.MultiUserChatManager;
|
import org.jivesoftware.smackx.muc.MultiUserChatManager;
|
||||||
import org.jivesoftware.smackx.muc.RoomInfo;
|
import org.jivesoftware.smackx.muc.RoomInfo;
|
||||||
|
@ -396,6 +399,34 @@ public final class OmemoManager extends Manager {
|
||||||
return getOmemoService().decryptMessage(managerGuard, sender, omemoElement);
|
return getOmemoService().decryptMessage(managerGuard, sender, omemoElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt OmemoMessages of a {@link org.jivesoftware.smackx.mam.MamManager.MamQueryResult}.
|
||||||
|
* Return a map of Stanzas and their decrypted counterparts.
|
||||||
|
*
|
||||||
|
* Note: This method does not repair broken sessions.
|
||||||
|
*
|
||||||
|
* @param result MamQueryResult
|
||||||
|
* @return map of encrypted stanzas and decrypted messages.
|
||||||
|
*
|
||||||
|
* @throws SmackException.NotLoggedInException if the OmemoManager is not authenticated
|
||||||
|
*/
|
||||||
|
public Map<Stanza, OmemoMessage.Received> decryptMAMQueryResult(MamManager.MamQueryResult result)
|
||||||
|
throws SmackException.NotLoggedInException
|
||||||
|
{
|
||||||
|
LoggedInOmemoManager managerGuard = new LoggedInOmemoManager(this);
|
||||||
|
HashMap<Stanza, OmemoMessage.Received> decryptedMessages = new HashMap<>();
|
||||||
|
|
||||||
|
for (Forwarded forwarded : result.forwardedMessages) {
|
||||||
|
Stanza stanza = forwarded.getForwardedStanza();
|
||||||
|
OmemoMessage.Received decrypted = getOmemoService().decryptStanza(stanza, managerGuard);
|
||||||
|
if (decrypted != null) {
|
||||||
|
decryptedMessages.put(stanza, decrypted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return decryptedMessages;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trust that a fingerprint belongs to an OmemoDevice.
|
* Trust that a fingerprint belongs to an OmemoDevice.
|
||||||
* The fingerprint must be the lowercase, hexadecimal fingerprint of the identityKey of the device and must
|
* The fingerprint must be the lowercase, hexadecimal fingerprint of the identityKey of the device and must
|
||||||
|
@ -489,11 +520,8 @@ public final class OmemoManager extends Manager {
|
||||||
|
|
||||||
// Set MAM Storage hint
|
// Set MAM Storage hint
|
||||||
StoreHint.set(message);
|
StoreHint.set(message);
|
||||||
|
message.addExtension(new ExplicitMessageEncryptionElement(
|
||||||
if (OmemoConfiguration.getAddEmeEncryptionHint()) {
|
ExplicitMessageEncryptionElement.ExplicitMessageEncryptionProtocol.omemoVAxolotl));
|
||||||
message.addExtension(new ExplicitMessageEncryptionElement(
|
|
||||||
ExplicitMessageEncryptionElement.ExplicitMessageEncryptionProtocol.omemoVAxolotl));
|
|
||||||
}
|
|
||||||
connection().sendStanza(message);
|
connection().sendStanza(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1079,7 +1079,7 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
|
||||||
OmemoManager.LoggedInOmemoManager managerGuard) {
|
OmemoManager.LoggedInOmemoManager managerGuard) {
|
||||||
OmemoManager manager = managerGuard.get();
|
OmemoManager manager = managerGuard.get();
|
||||||
// Avoid the ratchet being manipulated and the bundle being published multiple times simultaneously
|
// Avoid the ratchet being manipulated and the bundle being published multiple times simultaneously
|
||||||
synchronized (manager) {
|
synchronized (manager.LOCK) {
|
||||||
OmemoDevice userDevice = manager.getOwnDevice();
|
OmemoDevice userDevice = manager.getOwnDevice();
|
||||||
OmemoElement element = carbonCopy.getExtension(OmemoElement.NAME_ENCRYPTED, OmemoElement_VAxolotl.NAMESPACE);
|
OmemoElement element = carbonCopy.getExtension(OmemoElement.NAME_ENCRYPTED, OmemoElement_VAxolotl.NAMESPACE);
|
||||||
if (element == null) {
|
if (element == null) {
|
||||||
|
@ -1207,6 +1207,86 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt the OmemoElement inside the given Stanza and return it.
|
||||||
|
* Return null if something goes wrong.
|
||||||
|
*
|
||||||
|
* @param stanza stanza
|
||||||
|
* @param managerGuard authenticated OmemoManager
|
||||||
|
* @return decrypted OmemoMessage or null
|
||||||
|
*/
|
||||||
|
OmemoMessage.Received decryptStanza(Stanza stanza, OmemoManager.LoggedInOmemoManager managerGuard) {
|
||||||
|
OmemoManager manager = managerGuard.get();
|
||||||
|
// Avoid the ratchet being manipulated and the bundle being published multiple times simultaneously
|
||||||
|
synchronized (manager.LOCK) {
|
||||||
|
OmemoDevice userDevice = manager.getOwnDevice();
|
||||||
|
OmemoElement element = stanza.getExtension(OmemoElement.NAME_ENCRYPTED, OmemoElement_VAxolotl.NAMESPACE);
|
||||||
|
if (element == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
OmemoMessage.Received decrypted = null;
|
||||||
|
BareJid sender;
|
||||||
|
|
||||||
|
try {
|
||||||
|
MultiUserChat muc = getMuc(manager.getConnection(), stanza.getFrom());
|
||||||
|
if (muc != null) {
|
||||||
|
Occupant occupant = muc.getOccupant(stanza.getFrom().asEntityFullJidIfPossible());
|
||||||
|
Jid occupantJid = occupant.getJid();
|
||||||
|
|
||||||
|
if (occupantJid == null) {
|
||||||
|
LOGGER.log(Level.WARNING, "MUC message received, but there is no way to retrieve the senders Jid. " +
|
||||||
|
stanza.getFrom());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
sender = occupantJid.asBareJid();
|
||||||
|
|
||||||
|
// try is for this
|
||||||
|
decrypted = decryptMessage(managerGuard, sender, element);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
sender = stanza.getFrom().asBareJid();
|
||||||
|
|
||||||
|
// and this
|
||||||
|
decrypted = decryptMessage(managerGuard, sender, element);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decrypted.isPreKeyMessage() && OmemoConfiguration.getCompleteSessionWithEmptyMessage()) {
|
||||||
|
LOGGER.log(Level.FINE, "Received a preKeyMessage from " + decrypted.getSenderDevice() + ".\n" +
|
||||||
|
"Complete the session by sending an empty response message.");
|
||||||
|
try {
|
||||||
|
sendRatchetUpdate(managerGuard, decrypted.getSenderDevice());
|
||||||
|
} catch (CannotEstablishOmemoSessionException e) {
|
||||||
|
throw new AssertionError("Since we successfully received a message, we MUST be able to " +
|
||||||
|
"establish a session. " + e);
|
||||||
|
} catch (NoSuchAlgorithmException | InterruptedException | SmackException.NotConnectedException | SmackException.NoResponseException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Cannot send a ratchet update message.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (NoRawSessionException e) {
|
||||||
|
OmemoDevice device = e.getDeviceWithoutSession();
|
||||||
|
LOGGER.log(Level.WARNING, "No raw session found for contact " + device + ". ", e);
|
||||||
|
|
||||||
|
} catch (CorruptedOmemoKeyException | CryptoFailedException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Could not decrypt incoming message: ", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload fresh bundle.
|
||||||
|
if (getOmemoStoreBackend().loadOmemoPreKeys(userDevice).size() < OmemoConstants.PRE_KEY_COUNT_PER_BUNDLE) {
|
||||||
|
LOGGER.log(Level.FINE, "We used up a preKey. Upload a fresh bundle.");
|
||||||
|
try {
|
||||||
|
getOmemoStoreBackend().replenishKeys(userDevice);
|
||||||
|
OmemoBundleElement bundleElement = getOmemoStoreBackend().packOmemoBundle(userDevice);
|
||||||
|
publishBundle(manager.getConnection(), userDevice, bundleElement);
|
||||||
|
} catch (CorruptedOmemoKeyException | InterruptedException | SmackException.NoResponseException | SmackException.NotConnectedException | XMPPException.XMPPErrorException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Could not republish replenished bundle.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return decrypted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch and process a fresh bundle and send an empty preKeyMessage in order to establish a fresh session.
|
* Fetch and process a fresh bundle and send an empty preKeyMessage in order to establish a fresh session.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue