mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-22 06:12:05 +01:00
Smack 4.2.1
-----BEGIN PGP SIGNATURE----- iQGTBAABCgB9FiEEl3UFnzoh3OFr5PuuIjmn6PWFIFIFAlmR75tfFIAAAAAALgAo aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDk3 NzUwNTlGM0EyMURDRTE2QkU0RkJBRTIyMzlBN0U4RjU4NTIwNTIACgkQIjmn6PWF IFLeXggAjdgj7YVUe22NtamnROBj1c3PaWwgSY0gEjcyDPsOz5qeqNUdQLHbmt2j XQQpYZWKg1/1uoQHlsixaFKbGVctKRk72aNEodRfd1osta11WTOwZKEb8nI411Tt 7M0Fhf430WZY6nioZiZIorsmid57fftJ2EMPlmjEDp2FD0AVGAXkEhCneGaPtt9Q hbWbepIy9tApeIH+QgmFLBmPLnFCaSg+X6NUden3Z21bUz5vH8pmcbeUVfsNB7kW nkkDuNwKHPFLgjuhcq7D+KAKRwNU7n8WEuHseRzM7bMCEB+S/rZok5KPXe/tV4v+ YZKN2e+2yh4j5l4FT/fCzELfWcvrgA== =MV3G -----END PGP SIGNATURE----- Merge tag '4.2.1' Smack 4.2.1
This commit is contained in:
commit
43abd52d76
26 changed files with 332 additions and 228 deletions
34
build.gradle
34
build.gradle
|
@ -191,7 +191,10 @@ gradle.taskGraph.whenReady { taskGraph ->
|
||||||
if (signingRequired
|
if (signingRequired
|
||||||
&& taskGraph.allTasks.any { it instanceof Sign }) {
|
&& taskGraph.allTasks.any { it instanceof Sign }) {
|
||||||
// Use Java 6's console to read from the console (no good for a CI environment)
|
// Use Java 6's console to read from the console (no good for a CI environment)
|
||||||
Console console = System.console()
|
def console = System.console()
|
||||||
|
if (console == null) {
|
||||||
|
throw new Exception("Could not obtain system console (Console is 'null'). Did you build with gradle daemon? Try the same Gradle command with \"--no-daemon\".")
|
||||||
|
}
|
||||||
console.printf '\n\nWe have to sign some things in this build.\n\nPlease enter your signing details.\n\n'
|
console.printf '\n\nWe have to sign some things in this build.\n\nPlease enter your signing details.\n\n'
|
||||||
def password = console.readPassword('GnuPG Private Key Password: ')
|
def password = console.readPassword('GnuPG Private Key Password: ')
|
||||||
|
|
||||||
|
@ -245,11 +248,18 @@ task distributionZip(type: Zip, dependsOn: [javadocAll, prepareReleasedocs, mark
|
||||||
|
|
||||||
task maybeCheckForSnapshotDependencies {
|
task maybeCheckForSnapshotDependencies {
|
||||||
// Don't check for Snapshot dependencies if this is a snapshot.
|
// Don't check for Snapshot dependencies if this is a snapshot.
|
||||||
if (isSnapshot) return
|
onlyIf { isReleaseVersion }
|
||||||
allprojects { project ->
|
// Run in the execution phase, not in configuration phase, as the
|
||||||
project.configurations.runtime.each {
|
// 'each' forces the runtime configuration to be resovled, which
|
||||||
if (it.toString().contains("-SNAPSHOT"))
|
// causes "Cannot change dependencies of configuration after it
|
||||||
throw new Exception("Release build contains snapshot dependencies: " + it)
|
// has been included in dependency resolution." errors.
|
||||||
|
// See https://discuss.gradle.org/t/23153
|
||||||
|
doLast {
|
||||||
|
allprojects { project ->
|
||||||
|
project.configurations.runtime.each {
|
||||||
|
if (it.toString().contains("-SNAPSHOT"))
|
||||||
|
throw new Exception("Release build contains snapshot dependencies: " + it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -402,6 +412,18 @@ configure(integrationTestProjects + project(':smack-repl')) {
|
||||||
project(':smack-omemo').clirr.enabled = false
|
project(':smack-omemo').clirr.enabled = false
|
||||||
project(':smack-omemo-signal').clirr.enabled = false
|
project(':smack-omemo-signal').clirr.enabled = false
|
||||||
|
|
||||||
|
configure(
|
||||||
|
[ ':smack-omemo',
|
||||||
|
':smack-omemo-signal',
|
||||||
|
':smack-omemo-signal-integration-test',
|
||||||
|
].collect{ project(it) }) {
|
||||||
|
uploadArchives {
|
||||||
|
// Only enable uploadArchives for the smack-omemo* projects
|
||||||
|
// for snapshots. Not yet for releases.
|
||||||
|
enabled = isSnapshot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subprojects*.jar {
|
subprojects*.jar {
|
||||||
manifest {
|
manifest {
|
||||||
from sharedManifest
|
from sharedManifest
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
smackSmack Extensions User Manual
|
Smack Extensions User Manual
|
||||||
============================
|
============================
|
||||||
|
|
||||||
The XMPP protocol includes a base protocol and many optional extensions
|
The XMPP protocol includes a base protocol and many optional extensions
|
||||||
|
@ -95,7 +95,7 @@ Experimental Smack Extensions and currently supported XEPs of smack-experimental
|
||||||
| [Push Notifications](pushnotifications.md) | [XEP-0357](http://xmpp.org/extensions/xep-0357.html) | Defines a way to manage push notifications from an XMPP Server. |
|
| [Push Notifications](pushnotifications.md) | [XEP-0357](http://xmpp.org/extensions/xep-0357.html) | Defines a way to manage push notifications from an XMPP Server. |
|
||||||
| HTTP File Upload | [XEP-0363](http://xmpp.org/extensions/xep-0363.html) | Protocol to request permissions to upload a file to an HTTP server and get a shareable URL. |
|
| HTTP File Upload | [XEP-0363](http://xmpp.org/extensions/xep-0363.html) | Protocol to request permissions to upload a file to an HTTP server and get a shareable URL. |
|
||||||
| [Multi-User Chat Light](muclight.md) | [XEP-xxxx](http://mongooseim.readthedocs.io/en/latest/open-extensions/xeps/xep-muc-light.html) | Multi-User Chats for mobile XMPP applications and specific enviroment. |
|
| [Multi-User Chat Light](muclight.md) | [XEP-xxxx](http://mongooseim.readthedocs.io/en/latest/open-extensions/xeps/xep-muc-light.html) | Multi-User Chats for mobile XMPP applications and specific enviroment. |
|
||||||
| [OMEMO End Encryption (omemo.md) | [XEP-0384](http://xmpp.org/extensions/xep-0384.html) | Encrypt messages using OMEMO encryption (currently only with smack-omemo-signal -> GPLv3). |
|
| [OMEMO Multi End Message and Object Encryption](omemo.md) | [XEP-XXXX](https://conversations.im/omemo/xep-omemo.html) | Encrypt messages using OMEMO encryption (currently only with smack-omemo-signal -> GPLv3). |
|
||||||
| Google GCM JSON payload | n/a | Semantically the same as XEP-0335: JSON Containers |
|
| Google GCM JSON payload | n/a | Semantically the same as XEP-0335: JSON Containers |
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -141,6 +141,57 @@ hr {
|
||||||
|
|
||||||
<div id="pageBody">
|
<div id="pageBody">
|
||||||
|
|
||||||
|
<h2>4.2.1 -- <span style="font-weight: normal;">2017-08-14</span></h2>
|
||||||
|
|
||||||
|
<h2> Bug
|
||||||
|
</h2>
|
||||||
|
<ul>
|
||||||
|
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-749'>SMACK-749</a>] - SCRAM-SHA-1 and SCRAM-SHA-1-PLUS SASL mechanisms have the same priority, causing SASL authentication failures
|
||||||
|
</li>
|
||||||
|
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-755'>SMACK-755</a>] - DIGEST-MD5 sometimes causes malformed request server response
|
||||||
|
</li>
|
||||||
|
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-756'>SMACK-756</a>] - IoTIsFriendResponse has invalid name and produces invalid XML
|
||||||
|
</li>
|
||||||
|
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-759'>SMACK-759</a>] - PubSubManager.getLeafNode() throws PubSubAssertionError.DiscoInfoNodeAssertionError if node exists but its not a PubSub Node
|
||||||
|
</li>
|
||||||
|
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-764'>SMACK-764</a>] - NPE in hashCode() in Occupant when jid is null
|
||||||
|
</li>
|
||||||
|
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-766'>SMACK-766</a>] - Smack possibly includes 'ask' attribute in roster items when sending requests
|
||||||
|
</li>
|
||||||
|
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-768'>SMACK-768</a>] - Smack throws NoResponse timeout when waiting for IQ although there was a response
|
||||||
|
</li>
|
||||||
|
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-771'>SMACK-771</a>] - XMPPTCPConnection should use KeyManagerFactory.getDefaultAlgorithm() instead of KeyManagerFactory.getInstance("sunX509");
|
||||||
|
</li>
|
||||||
|
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-772'>SMACK-772</a>] - HostAddress must deal with 'fqdn' being null.
|
||||||
|
</li>
|
||||||
|
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-773'>SMACK-773</a>] - Allow roster pushes from our full JID for backwards compatibility
|
||||||
|
</li>
|
||||||
|
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-774'>SMACK-774</a>] - HTTP File Upload's SlotRequest metadata should be attributes not child elements
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2> New Feature
|
||||||
|
</h2>
|
||||||
|
<ul>
|
||||||
|
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-746'>SMACK-746</a>] - Add support for XEP-0380: Explicit Message Encryption
|
||||||
|
</li>
|
||||||
|
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-758'>SMACK-758</a>] - Add support for XEP-0334: Message Processing Hints
|
||||||
|
</li>
|
||||||
|
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-760'>SMACK-760</a>] - Smack does not allow custom extension elements in SM's <failed/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2> Improvement
|
||||||
|
</h2>
|
||||||
|
<ul>
|
||||||
|
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-752'>SMACK-752</a>] - XEP-0357 Push Notification enable IQ uses wrong form type: Should be 'submit' instead of 'form'
|
||||||
|
</li>
|
||||||
|
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-754'>SMACK-754</a>] - Allow MUC room subject changes from the MUCs bare JID
|
||||||
|
</li>
|
||||||
|
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-777'>SMACK-777</a>] - MamManager should use the user's bare JID to check if MAM is supported
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<h2>4.2.0 -- <span style="font-weight: normal;">2017-03-10</span></h2>
|
<h2>4.2.0 -- <span style="font-weight: normal;">2017-03-10</span></h2>
|
||||||
|
|
||||||
<h2> Sub-task
|
<h2> Sub-task
|
||||||
|
|
|
@ -255,7 +255,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
||||||
private final ExecutorService cachedExecutorService = Executors.newCachedThreadPool(
|
private final ExecutorService cachedExecutorService = Executors.newCachedThreadPool(
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
// CHECKSTYLE:OFF
|
// CHECKSTYLE:OFF
|
||||||
new SmackExecutorThreadFactory( // threadFactory
|
new SmackExecutorThreadFactory(
|
||||||
this,
|
this,
|
||||||
"Cached Executor"
|
"Cached Executor"
|
||||||
)
|
)
|
||||||
|
|
|
@ -41,7 +41,7 @@ public interface StanzaListener {
|
||||||
/**
|
/**
|
||||||
* Process the next stanza(/packet) sent to this stanza(/packet) listener.
|
* Process the next stanza(/packet) sent to this stanza(/packet) listener.
|
||||||
* <p>
|
* <p>
|
||||||
* A single thread is responsible for invoking all listeners, so
|
* If this listener is synchronous, then a single thread is responsible for invoking all listeners, so
|
||||||
* it's very important that implementations of this method not block
|
* it's very important that implementations of this method not block
|
||||||
* for any extended period of time.
|
* for any extended period of time.
|
||||||
* </p>
|
* </p>
|
||||||
|
|
|
@ -75,6 +75,22 @@ public class HostAddress {
|
||||||
setException(e);
|
setException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getHost() {
|
||||||
|
if (fqdn != null) {
|
||||||
|
return fqdn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In this case, the HostAddress(int, InetAddress) constructor must been used. We have no FQDN. And
|
||||||
|
// inetAddresses.size() must be exactly one.
|
||||||
|
assert inetAddresses.size() == 1;
|
||||||
|
return inetAddresses.get(0).getHostAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the fully qualified domain name. This may return <code>null</code> in case there host address is only numeric, i.e. an IP address.
|
||||||
|
*
|
||||||
|
* @return the fully qualified domain name or <code>null</code>
|
||||||
|
*/
|
||||||
public String getFQDN() {
|
public String getFQDN() {
|
||||||
return fqdn;
|
return fqdn;
|
||||||
}
|
}
|
||||||
|
@ -109,7 +125,7 @@ public class HostAddress {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return fqdn + ":" + port;
|
return getHost() + ":" + port;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -123,7 +139,7 @@ public class HostAddress {
|
||||||
|
|
||||||
final HostAddress address = (HostAddress) o;
|
final HostAddress address = (HostAddress) o;
|
||||||
|
|
||||||
if (!fqdn.equals(address.fqdn)) {
|
if (!getHost().equals(address.getHost())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return port == address.port;
|
return port == address.port;
|
||||||
|
@ -132,7 +148,7 @@ public class HostAddress {
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = 1;
|
int result = 1;
|
||||||
result = 37 * result + fqdn.hashCode();
|
result = 37 * result + getHost().hashCode();
|
||||||
return result * 37 + port;
|
return result * 37 + port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,9 @@ public class SlotRequest extends IQ {
|
||||||
public static final String ELEMENT = "request";
|
public static final String ELEMENT = "request";
|
||||||
public static final String NAMESPACE = HttpFileUploadManager.NAMESPACE;
|
public static final String NAMESPACE = HttpFileUploadManager.NAMESPACE;
|
||||||
|
|
||||||
private final String filename;
|
protected final String filename;
|
||||||
private final long size;
|
protected final long size;
|
||||||
private final String contentType;
|
protected final String contentType;
|
||||||
|
|
||||||
public SlotRequest(DomainBareJid uploadServiceAddress, String filename, long size) {
|
public SlotRequest(DomainBareJid uploadServiceAddress, String filename, long size) {
|
||||||
this(uploadServiceAddress, filename, size, null);
|
this(uploadServiceAddress, filename, size, null);
|
||||||
|
@ -82,10 +82,10 @@ public class SlotRequest extends IQ {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
xml.rightAngleBracket();
|
xml.attribute("filename", filename);
|
||||||
xml.element("filename", filename);
|
xml.attribute("size", String.valueOf(size));
|
||||||
xml.element("size", String.valueOf(size));
|
xml.optAttribute("content-type", contentType);
|
||||||
xml.optElement("content-type", contentType);
|
xml.setEmptyElement();
|
||||||
return xml;
|
return xml;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,4 +40,13 @@ public class SlotRequest_V0_2 extends SlotRequest {
|
||||||
public SlotRequest_V0_2(DomainBareJid uploadServiceAddress, String filename, long size, String contentType) {
|
public SlotRequest_V0_2(DomainBareJid uploadServiceAddress, String filename, long size, String contentType) {
|
||||||
super(uploadServiceAddress, filename, size, contentType, NAMESPACE);
|
super(uploadServiceAddress, filename, size, contentType, NAMESPACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
|
xml.rightAngleBracket();
|
||||||
|
xml.element("filename", filename);
|
||||||
|
xml.element("size", String.valueOf(size));
|
||||||
|
xml.optElement("content-type", contentType);
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,7 @@ import org.jivesoftware.smackx.rsm.packet.RSMSet;
|
||||||
import org.jivesoftware.smackx.xdata.FormField;
|
import org.jivesoftware.smackx.xdata.FormField;
|
||||||
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
||||||
|
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
import org.jxmpp.jid.EntityBareJid;
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.jxmpp.jid.EntityFullJid;
|
import org.jxmpp.jid.EntityFullJid;
|
||||||
import org.jxmpp.jid.Jid;
|
import org.jxmpp.jid.Jid;
|
||||||
|
@ -103,9 +104,12 @@ public final class MamManager extends Manager {
|
||||||
|
|
||||||
private final Jid archiveAddress;
|
private final Jid archiveAddress;
|
||||||
|
|
||||||
|
private final ServiceDiscoveryManager serviceDiscoveryManager;
|
||||||
|
|
||||||
private MamManager(XMPPConnection connection, Jid archiveAddress) {
|
private MamManager(XMPPConnection connection, Jid archiveAddress) {
|
||||||
super(connection);
|
super(connection);
|
||||||
this.archiveAddress = archiveAddress;
|
this.archiveAddress = archiveAddress;
|
||||||
|
serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -586,6 +590,23 @@ public final class MamManager extends Manager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if MAM is supported for the XMPP connection managed by this MamManager.
|
||||||
|
*
|
||||||
|
* @return true if MAM is supported for the XMPP connection, <code>false</code>otherwhise.
|
||||||
|
*
|
||||||
|
* @throws NoResponseException
|
||||||
|
* @throws XMPPErrorException
|
||||||
|
* @throws NotConnectedException
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @since 4.2.1
|
||||||
|
* @see <a href="https://xmpp.org/extensions/xep-0313.html#support">XEP-0313 § 7. Determining support</a>
|
||||||
|
*/
|
||||||
|
public boolean isSupported() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
BareJid myBareJid = connection().getUser().asBareJid();
|
||||||
|
return serviceDiscoveryManager.supportsFeature(myBareJid, MamElements.NAMESPACE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if Message Archive Management is supported by the server.
|
* Returns true if Message Archive Management is supported by the server.
|
||||||
*
|
*
|
||||||
|
@ -594,7 +615,10 @@ public final class MamManager extends Manager {
|
||||||
* @throws XMPPErrorException
|
* @throws XMPPErrorException
|
||||||
* @throws NoResponseException
|
* @throws NoResponseException
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
|
* @depreacted use {@link #isSupported()} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO Remove in Smack 4.3
|
||||||
public boolean isSupportedByServer()
|
public boolean isSupportedByServer()
|
||||||
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
return ServiceDiscoveryManager.getInstanceFor(connection()).serverSupportsFeature(MamElements.NAMESPACE);
|
return ServiceDiscoveryManager.getInstanceFor(connection()).serverSupportsFeature(MamElements.NAMESPACE);
|
||||||
|
|
|
@ -16,49 +16,52 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.httpfileupload;
|
package org.jivesoftware.smackx.httpfileupload;
|
||||||
|
|
||||||
|
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.httpfileupload.element.SlotRequest;
|
import org.jivesoftware.smackx.httpfileupload.element.SlotRequest;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.jxmpp.jid.JidTestUtil;
|
import org.jxmpp.jid.JidTestUtil;
|
||||||
import org.jxmpp.stringprep.XmppStringprepException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
|
||||||
public class SlotRequestCreateTest {
|
public class SlotRequestCreateTest {
|
||||||
|
|
||||||
String testRequest
|
String testRequest
|
||||||
= "<request xmlns='urn:xmpp:http:upload:0'>"
|
= "<request xmlns='urn:xmpp:http:upload:0'"
|
||||||
+ "<filename>my_juliet.png</filename>"
|
+ " filename='my_juliet.png'"
|
||||||
+ "<size>23456</size>"
|
+ " size='23456'"
|
||||||
+ "<content-type>image/jpeg</content-type>"
|
+ " content-type='image/jpeg'"
|
||||||
+ "</request>";
|
+ "/>";
|
||||||
|
|
||||||
String testRequestWithoutContentType
|
String testRequestWithoutContentType
|
||||||
= "<request xmlns='urn:xmpp:http:upload:0'>"
|
= "<request xmlns='urn:xmpp:http:upload:0'"
|
||||||
+ "<filename>my_romeo.png</filename>"
|
+ " filename='my_romeo.png'"
|
||||||
+ "<size>52523</size>"
|
+ " size='52523'"
|
||||||
+ "</request>";
|
+ "/>";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void checkSlotRequestCreation() throws XmppStringprepException {
|
public void checkSlotRequestCreation() throws SAXException, IOException {
|
||||||
SlotRequest slotRequest = new SlotRequest(JidTestUtil.DOMAIN_BARE_JID_1, "my_juliet.png", 23456, "image/jpeg");
|
SlotRequest slotRequest = new SlotRequest(JidTestUtil.DOMAIN_BARE_JID_1, "my_juliet.png", 23456, "image/jpeg");
|
||||||
|
|
||||||
Assert.assertEquals("my_juliet.png", slotRequest.getFilename());
|
Assert.assertEquals("my_juliet.png", slotRequest.getFilename());
|
||||||
Assert.assertEquals(23456, slotRequest.getSize());
|
Assert.assertEquals(23456, slotRequest.getSize());
|
||||||
Assert.assertEquals("image/jpeg", slotRequest.getContentType());
|
Assert.assertEquals("image/jpeg", slotRequest.getContentType());
|
||||||
|
|
||||||
Assert.assertEquals(testRequest, slotRequest.getChildElementXML().toString());
|
assertXMLEqual(testRequest, slotRequest.getChildElementXML().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void checkSlotRequestCreationWithoutContentType() throws XmppStringprepException {
|
public void checkSlotRequestCreationWithoutContentType() throws SAXException, IOException {
|
||||||
SlotRequest slotRequest = new SlotRequest(JidTestUtil.DOMAIN_BARE_JID_1, "my_romeo.png", 52523);
|
SlotRequest slotRequest = new SlotRequest(JidTestUtil.DOMAIN_BARE_JID_1, "my_romeo.png", 52523);
|
||||||
|
|
||||||
Assert.assertEquals("my_romeo.png", slotRequest.getFilename());
|
Assert.assertEquals("my_romeo.png", slotRequest.getFilename());
|
||||||
Assert.assertEquals(52523, slotRequest.getSize());
|
Assert.assertEquals(52523, slotRequest.getSize());
|
||||||
Assert.assertEquals(null, slotRequest.getContentType());
|
Assert.assertEquals(null, slotRequest.getContentType());
|
||||||
|
|
||||||
Assert.assertEquals(testRequestWithoutContentType, slotRequest.getChildElementXML().toString());
|
assertXMLEqual(testRequestWithoutContentType, slotRequest.getChildElementXML().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
|
|
@ -159,7 +159,7 @@ public final class BoBManager extends Manager {
|
||||||
|
|
||||||
public BoBInfo addBoB(BoBData bobData) {
|
public BoBInfo addBoB(BoBData bobData) {
|
||||||
// We only support SHA-1 for now.
|
// We only support SHA-1 for now.
|
||||||
BoBHash bobHash = new BoBHash("sha1", SHA1.hex(bobData.getContent()));
|
BoBHash bobHash = new BoBHash(SHA1.hex(bobData.getContent()), "sha1");
|
||||||
|
|
||||||
Set<BoBHash> bobHashes = Collections.singleton(bobHash);
|
Set<BoBHash> bobHashes = Collections.singleton(bobHash);
|
||||||
bobHashes = Collections.unmodifiableSet(bobHashes);
|
bobHashes = Collections.unmodifiableSet(bobHashes);
|
||||||
|
|
|
@ -1011,7 +1011,7 @@ public class MultiUserChat {
|
||||||
*
|
*
|
||||||
* @param presenceInterceptor the stanza(/packet) interceptor to remove.
|
* @param presenceInterceptor the stanza(/packet) interceptor to remove.
|
||||||
*/
|
*/
|
||||||
public void removePresenceInterceptor(StanzaListener presenceInterceptor) {
|
public void removePresenceInterceptor(PresenceListener presenceInterceptor) {
|
||||||
presenceInterceptors.remove(presenceInterceptor);
|
presenceInterceptors.remove(presenceInterceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||||
import org.jivesoftware.smackx.pubsub.EventElement;
|
import org.jivesoftware.smackx.pubsub.EventElement;
|
||||||
import org.jivesoftware.smackx.pubsub.Item;
|
import org.jivesoftware.smackx.pubsub.Item;
|
||||||
import org.jivesoftware.smackx.pubsub.LeafNode;
|
import org.jivesoftware.smackx.pubsub.LeafNode;
|
||||||
|
import org.jivesoftware.smackx.pubsub.PubSubException.NotAPubSubNodeException;
|
||||||
import org.jivesoftware.smackx.pubsub.PubSubFeature;
|
import org.jivesoftware.smackx.pubsub.PubSubFeature;
|
||||||
import org.jivesoftware.smackx.pubsub.PubSubManager;
|
import org.jivesoftware.smackx.pubsub.PubSubManager;
|
||||||
import org.jivesoftware.smackx.pubsub.filter.EventExtensionFilter;
|
import org.jivesoftware.smackx.pubsub.filter.EventExtensionFilter;
|
||||||
|
@ -137,9 +138,10 @@ public final class PEPManager extends Manager {
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
* @throws XMPPErrorException
|
* @throws XMPPErrorException
|
||||||
* @throws NoResponseException
|
* @throws NoResponseException
|
||||||
|
* @throws NotAPubSubNodeException
|
||||||
*/
|
*/
|
||||||
public void publish(Item item, String node) throws NotConnectedException, InterruptedException,
|
public void publish(Item item, String node) throws NotConnectedException, InterruptedException,
|
||||||
NoResponseException, XMPPErrorException {
|
NoResponseException, XMPPErrorException, NotAPubSubNodeException {
|
||||||
XMPPConnection connection = connection();
|
XMPPConnection connection = connection();
|
||||||
PubSubManager pubSubManager = PubSubManager.getInstance(connection, connection.getUser().asEntityBareJid());
|
PubSubManager pubSubManager = PubSubManager.getInstance(connection, connection.getUser().asEntityBareJid());
|
||||||
LeafNode pubSubNode = pubSubManager.getNode(node);
|
LeafNode pubSubNode = pubSubManager.getNode(node);
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Copyright 2017 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.pubsub;
|
|
||||||
|
|
||||||
import org.jxmpp.jid.BareJid;
|
|
||||||
|
|
||||||
public abstract class PubSubAssertionError extends AssertionError {
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
protected PubSubAssertionError(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class DiscoInfoNodeAssertionError extends PubSubAssertionError {
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
DiscoInfoNodeAssertionError(BareJid pubSubService, String nodeId) {
|
|
||||||
super("PubSub service '" + pubSubService + "' returned disco info result for node '" + nodeId
|
|
||||||
+ "', but it did not contain an Identity of type 'leaf' or 'collection' (and category 'pubsub'), which is not allowed according to XEP-60 5.3.");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -18,6 +18,8 @@ package org.jivesoftware.smackx.pubsub;
|
||||||
|
|
||||||
import org.jivesoftware.smack.SmackException;
|
import org.jivesoftware.smack.SmackException;
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
||||||
|
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
|
|
||||||
public abstract class PubSubException extends SmackException {
|
public abstract class PubSubException extends SmackException {
|
||||||
|
@ -27,6 +29,16 @@ public abstract class PubSubException extends SmackException {
|
||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final String nodeId;
|
||||||
|
|
||||||
|
protected PubSubException(String nodeId) {
|
||||||
|
this.nodeId = nodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNodeId() {
|
||||||
|
return nodeId;
|
||||||
|
}
|
||||||
|
|
||||||
public static class NotALeafNodeException extends PubSubException {
|
public static class NotALeafNodeException extends PubSubException {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,21 +46,35 @@ public abstract class PubSubException extends SmackException {
|
||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final String nodeId;
|
|
||||||
private final BareJid pubSubService;
|
private final BareJid pubSubService;
|
||||||
|
|
||||||
NotALeafNodeException(String nodeId, BareJid pubSubService) {
|
NotALeafNodeException(String nodeId, BareJid pubSubService) {
|
||||||
this.nodeId = nodeId;
|
super(nodeId);
|
||||||
this.pubSubService = pubSubService;
|
this.pubSubService = pubSubService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getNodeId() {
|
|
||||||
return nodeId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BareJid getPubSubService() {
|
public BareJid getPubSubService() {
|
||||||
return pubSubService;
|
return pubSubService;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class NotAPubSubNodeException extends PubSubException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final DiscoverInfo discoverInfo;
|
||||||
|
|
||||||
|
NotAPubSubNodeException(String nodeId, DiscoverInfo discoverInfo) {
|
||||||
|
super(nodeId);
|
||||||
|
this.discoverInfo = discoverInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiscoverInfo getDiscoverInfo() {
|
||||||
|
return discoverInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||||
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
||||||
import org.jivesoftware.smackx.disco.packet.DiscoverItems;
|
import org.jivesoftware.smackx.disco.packet.DiscoverItems;
|
||||||
import org.jivesoftware.smackx.pubsub.PubSubException.NotALeafNodeException;
|
import org.jivesoftware.smackx.pubsub.PubSubException.NotALeafNodeException;
|
||||||
|
import org.jivesoftware.smackx.pubsub.PubSubException.NotAPubSubNodeException;
|
||||||
import org.jivesoftware.smackx.pubsub.packet.PubSub;
|
import org.jivesoftware.smackx.pubsub.packet.PubSub;
|
||||||
import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
|
import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
|
||||||
import org.jivesoftware.smackx.pubsub.util.NodeUtils;
|
import org.jivesoftware.smackx.pubsub.util.NodeUtils;
|
||||||
|
@ -229,8 +230,9 @@ public final class PubSubManager extends Manager {
|
||||||
* @throws NoResponseException if there was no response from the server.
|
* @throws NoResponseException if there was no response from the server.
|
||||||
* @throws NotConnectedException
|
* @throws NotConnectedException
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
|
* @throws NotAPubSubNodeException
|
||||||
*/
|
*/
|
||||||
public <T extends Node> T getNode(String id) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException
|
public <T extends Node> T getNode(String id) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, NotAPubSubNodeException
|
||||||
{
|
{
|
||||||
Node node = nodeMap.get(id);
|
Node node = nodeMap.get(id);
|
||||||
|
|
||||||
|
@ -249,10 +251,7 @@ public final class PubSubManager extends Manager {
|
||||||
node = new CollectionNode(this, id);
|
node = new CollectionNode(this, id);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// XEP-60 5.3 states that
|
throw new PubSubException.NotAPubSubNodeException(id, infoReply);
|
||||||
// "The 'disco#info' result MUST include an identity with a category of 'pubsub' and a type of either 'leaf' or 'collection'."
|
|
||||||
// If this is not the case, then we are dealing with an PubSub implementation that doesn't follow the specification.
|
|
||||||
throw new PubSubAssertionError.DiscoInfoNodeAssertionError(pubSubService, id);
|
|
||||||
}
|
}
|
||||||
nodeMap.put(id, node);
|
nodeMap.put(id, node);
|
||||||
}
|
}
|
||||||
|
@ -278,6 +277,9 @@ public final class PubSubManager extends Manager {
|
||||||
try {
|
try {
|
||||||
return getNode(id);
|
return getNode(id);
|
||||||
}
|
}
|
||||||
|
catch (NotAPubSubNodeException e) {
|
||||||
|
return createNode(id);
|
||||||
|
}
|
||||||
catch (XMPPErrorException e1) {
|
catch (XMPPErrorException e1) {
|
||||||
if (e1.getXMPPError().getCondition() == Condition.item_not_found) {
|
if (e1.getXMPPError().getCondition() == Condition.item_not_found) {
|
||||||
try {
|
try {
|
||||||
|
@ -286,7 +288,13 @@ public final class PubSubManager extends Manager {
|
||||||
catch (XMPPErrorException e2) {
|
catch (XMPPErrorException e2) {
|
||||||
if (e2.getXMPPError().getCondition() == Condition.conflict) {
|
if (e2.getXMPPError().getCondition() == Condition.conflict) {
|
||||||
// The node was created in the meantime, re-try getNode(). Note that this case should be rare.
|
// The node was created in the meantime, re-try getNode(). Note that this case should be rare.
|
||||||
return getNode(id);
|
try {
|
||||||
|
return getNode(id);
|
||||||
|
}
|
||||||
|
catch (NotAPubSubNodeException e) {
|
||||||
|
// Should not happen
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw e2;
|
throw e2;
|
||||||
}
|
}
|
||||||
|
@ -313,10 +321,11 @@ public final class PubSubManager extends Manager {
|
||||||
* @throws NotConnectedException
|
* @throws NotConnectedException
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
* @throws XMPPErrorException
|
* @throws XMPPErrorException
|
||||||
|
* @throws NotAPubSubNodeException
|
||||||
* @since 4.2.1
|
* @since 4.2.1
|
||||||
*/
|
*/
|
||||||
public LeafNode getLeafNode(String id) throws NotALeafNodeException, NoResponseException, NotConnectedException,
|
public LeafNode getLeafNode(String id) throws NotALeafNodeException, NoResponseException, NotConnectedException,
|
||||||
InterruptedException, XMPPErrorException {
|
InterruptedException, XMPPErrorException, NotAPubSubNodeException {
|
||||||
Node node;
|
Node node;
|
||||||
try {
|
try {
|
||||||
node = getNode(id);
|
node = getNode(id);
|
||||||
|
|
|
@ -1676,8 +1676,8 @@ public final class Roster extends Manager {
|
||||||
final XMPPConnection connection = connection();
|
final XMPPConnection connection = connection();
|
||||||
RosterPacket rosterPacket = (RosterPacket) iqRequest;
|
RosterPacket rosterPacket = (RosterPacket) iqRequest;
|
||||||
|
|
||||||
EntityFullJid localAddress = connection.getUser();
|
EntityFullJid ourFullJid = connection.getUser();
|
||||||
if (localAddress == null) {
|
if (ourFullJid == null) {
|
||||||
LOGGER.warning("Ignoring roster push " + iqRequest + " while " + connection
|
LOGGER.warning("Ignoring roster push " + iqRequest + " while " + connection
|
||||||
+ " has no bound resource. This may be a server bug.");
|
+ " has no bound resource. This may be a server bug.");
|
||||||
return null;
|
return null;
|
||||||
|
@ -1685,12 +1685,23 @@ public final class Roster extends Manager {
|
||||||
|
|
||||||
// Roster push (RFC 6121, 2.1.6)
|
// Roster push (RFC 6121, 2.1.6)
|
||||||
// A roster push with a non-empty from not matching our address MUST be ignored
|
// A roster push with a non-empty from not matching our address MUST be ignored
|
||||||
EntityBareJid jid = localAddress.asEntityBareJid();
|
EntityBareJid ourBareJid = ourFullJid.asEntityBareJid();
|
||||||
Jid from = rosterPacket.getFrom();
|
Jid from = rosterPacket.getFrom();
|
||||||
if (from != null && !from.equals(jid)) {
|
if (from != null) {
|
||||||
LOGGER.warning("Ignoring roster push with a non matching 'from' ourJid='" + jid + "' from='" + from
|
if (from.equals(ourFullJid)) {
|
||||||
+ "'");
|
// Since RFC 6121 roster pushes are no longer allowed to
|
||||||
return IQ.createErrorResponse(iqRequest, Condition.service_unavailable);
|
// origin from the full JID as it was the case with RFC
|
||||||
|
// 3921. Log a warning an continue processing the push.
|
||||||
|
// See also SMACK-773.
|
||||||
|
LOGGER.warning(
|
||||||
|
"Received roster push from full JID. This behavior is since RFC 6121 not longer standard compliant. "
|
||||||
|
+ "Please ask your server vendor to fix this and comply to RFC 6121 § 2.1.6. IQ roster push stanza: "
|
||||||
|
+ iqRequest);
|
||||||
|
} else if (!from.equals(ourBareJid)) {
|
||||||
|
LOGGER.warning("Ignoring roster push with a non matching 'from' ourJid='" + ourBareJid + "' from='"
|
||||||
|
+ from + "'");
|
||||||
|
return IQ.createErrorResponse(iqRequest, Condition.service_unavailable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A roster push must contain exactly one entry
|
// A roster push must contain exactly one entry
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class MamIntegrationTest extends AbstractSmackIntegrationTest {
|
||||||
|
|
||||||
mamManagerConTwo = MamManager.getInstanceFor(conTwo);
|
mamManagerConTwo = MamManager.getInstanceFor(conTwo);
|
||||||
|
|
||||||
if (!mamManagerConTwo.isSupportedByServer()) {
|
if (!mamManagerConTwo.isSupported()) {
|
||||||
throw new TestNotPossibleException("Message Archive Management (XEP-0313) is not supported by the server.");
|
throw new TestNotPossibleException("Message Archive Management (XEP-0313) is not supported by the server.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||||
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
|
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
|
||||||
import org.jivesoftware.smackx.omemo.util.OmemoConstants;
|
import org.jivesoftware.smackx.omemo.util.OmemoConstants;
|
||||||
import org.jivesoftware.smackx.pubsub.PubSubException;
|
import org.jivesoftware.smackx.pubsub.PubSubException;
|
||||||
|
import org.jivesoftware.smackx.pubsub.PubSubException.NotAPubSubNodeException;
|
||||||
|
|
||||||
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
|
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
|
||||||
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
||||||
|
@ -52,9 +53,10 @@ public class OmemoInitializationTest extends AbstractOmemoIntegrationTest {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests, if the initialization is done properly.
|
* Tests, if the initialization is done properly.
|
||||||
|
* @throws NotAPubSubNodeException
|
||||||
*/
|
*/
|
||||||
@SmackIntegrationTest
|
@SmackIntegrationTest
|
||||||
public void initializationTest() throws XMPPException.XMPPErrorException, PubSubException.NotALeafNodeException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, SmackException.NotLoggedInException, CorruptedOmemoKeyException {
|
public void initializationTest() throws XMPPException.XMPPErrorException, PubSubException.NotALeafNodeException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, SmackException.NotLoggedInException, CorruptedOmemoKeyException, NotAPubSubNodeException {
|
||||||
//test keys.
|
//test keys.
|
||||||
setUpOmemoManager(alice);
|
setUpOmemoManager(alice);
|
||||||
assertNotNull("IdentityKey must not be null after initialization.", store.loadOmemoIdentityKeyPair(alice));
|
assertNotNull("IdentityKey must not be null after initialization.", store.loadOmemoIdentityKeyPair(alice));
|
||||||
|
|
|
@ -34,8 +34,8 @@ import org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionExcep
|
||||||
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
|
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
|
||||||
import org.jivesoftware.smackx.omemo.internal.CachedDeviceList;
|
import org.jivesoftware.smackx.omemo.internal.CachedDeviceList;
|
||||||
import org.jivesoftware.smackx.omemo.util.OmemoConstants;
|
import org.jivesoftware.smackx.omemo.util.OmemoConstants;
|
||||||
import org.jivesoftware.smackx.pubsub.PubSubAssertionError;
|
|
||||||
import org.jivesoftware.smackx.pubsub.PubSubException;
|
import org.jivesoftware.smackx.pubsub.PubSubException;
|
||||||
|
import org.jivesoftware.smackx.pubsub.PubSubException.NotAPubSubNodeException;
|
||||||
import org.jivesoftware.smackx.pubsub.PubSubManager;
|
import org.jivesoftware.smackx.pubsub.PubSubManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,26 +70,26 @@ final class OmemoIntegrationTestHelper {
|
||||||
for (int id : deviceList.getAllDevices()) {
|
for (int id : deviceList.getAllDevices()) {
|
||||||
try {
|
try {
|
||||||
pm.getLeafNode(OmemoConstants.PEP_NODE_BUNDLE_FROM_DEVICE_ID(id)).deleteAllItems();
|
pm.getLeafNode(OmemoConstants.PEP_NODE_BUNDLE_FROM_DEVICE_ID(id)).deleteAllItems();
|
||||||
} catch (InterruptedException | SmackException.NoResponseException | SmackException.NotConnectedException | PubSubException.NotALeafNodeException | XMPPException.XMPPErrorException | PubSubAssertionError.DiscoInfoNodeAssertionError e) {
|
} catch (InterruptedException | SmackException.NoResponseException | SmackException.NotConnectedException | PubSubException.NotALeafNodeException | XMPPException.XMPPErrorException | NotAPubSubNodeException e) {
|
||||||
//Silent
|
//Silent
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
pm.deleteNode(OmemoConstants.PEP_NODE_BUNDLE_FROM_DEVICE_ID(id));
|
pm.deleteNode(OmemoConstants.PEP_NODE_BUNDLE_FROM_DEVICE_ID(id));
|
||||||
} catch (SmackException.NoResponseException | InterruptedException | SmackException.NotConnectedException | XMPPException.XMPPErrorException | PubSubAssertionError e) {
|
} catch (SmackException.NoResponseException | InterruptedException | SmackException.NotConnectedException | XMPPException.XMPPErrorException e) {
|
||||||
//Silent
|
//Silent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
pm.getLeafNode(OmemoConstants.PEP_NODE_DEVICE_LIST).deleteAllItems();
|
pm.getLeafNode(OmemoConstants.PEP_NODE_DEVICE_LIST).deleteAllItems();
|
||||||
} catch (InterruptedException | SmackException.NoResponseException | SmackException.NotConnectedException | PubSubException.NotALeafNodeException | XMPPException.XMPPErrorException | PubSubAssertionError.DiscoInfoNodeAssertionError e) {
|
} catch (InterruptedException | SmackException.NoResponseException | SmackException.NotConnectedException | PubSubException.NotALeafNodeException | XMPPException.XMPPErrorException | NotAPubSubNodeException e) {
|
||||||
//Silent
|
//Silent
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
pm.deleteNode(OmemoConstants.PEP_NODE_DEVICE_LIST);
|
pm.deleteNode(OmemoConstants.PEP_NODE_DEVICE_LIST);
|
||||||
} catch (SmackException.NoResponseException | InterruptedException | SmackException.NotConnectedException | XMPPException.XMPPErrorException | PubSubAssertionError e) {
|
} catch (SmackException.NoResponseException | InterruptedException | SmackException.NotConnectedException | XMPPException.XMPPErrorException e) {
|
||||||
//Silent
|
//Silent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ final class OmemoIntegrationTestHelper {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setUpOmemoManager(OmemoManager omemoManager) throws CorruptedOmemoKeyException, InterruptedException, SmackException.NoResponseException, SmackException.NotConnectedException, XMPPException.XMPPErrorException, SmackException.NotLoggedInException, PubSubException.NotALeafNodeException {
|
static void setUpOmemoManager(OmemoManager omemoManager) throws CorruptedOmemoKeyException, InterruptedException, SmackException.NoResponseException, SmackException.NotConnectedException, XMPPException.XMPPErrorException, SmackException.NotLoggedInException, PubSubException.NotALeafNodeException, NotAPubSubNodeException {
|
||||||
omemoManager.initialize();
|
omemoManager.initialize();
|
||||||
OmemoBundleElement bundle = OmemoService.fetchBundle(omemoManager, omemoManager.getOwnDevice());
|
OmemoBundleElement bundle = OmemoService.fetchBundle(omemoManager, omemoManager.getOwnDevice());
|
||||||
assertNotNull("Bundle must not be null.", bundle);
|
assertNotNull("Bundle must not be null.", bundle);
|
||||||
|
|
|
@ -40,6 +40,7 @@ import org.jivesoftware.smackx.omemo.internal.CipherAndAuthTag;
|
||||||
import org.jivesoftware.smackx.omemo.internal.OmemoMessageInformation;
|
import org.jivesoftware.smackx.omemo.internal.OmemoMessageInformation;
|
||||||
import org.jivesoftware.smackx.omemo.listener.OmemoMessageListener;
|
import org.jivesoftware.smackx.omemo.listener.OmemoMessageListener;
|
||||||
import org.jivesoftware.smackx.pubsub.PubSubException;
|
import org.jivesoftware.smackx.pubsub.PubSubException;
|
||||||
|
import org.jivesoftware.smackx.pubsub.PubSubException.NotAPubSubNodeException;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
|
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
|
||||||
|
@ -85,9 +86,15 @@ public class OmemoMessageSendingTest extends AbstractOmemoIntegrationTest {
|
||||||
* @throws UndecidedOmemoIdentityException
|
* @throws UndecidedOmemoIdentityException
|
||||||
* @throws NoSuchAlgorithmException
|
* @throws NoSuchAlgorithmException
|
||||||
* @throws CryptoFailedException
|
* @throws CryptoFailedException
|
||||||
|
* @throws NotAPubSubNodeException
|
||||||
*/
|
*/
|
||||||
@SmackIntegrationTest
|
@SmackIntegrationTest
|
||||||
public void messageSendingTest() throws CorruptedOmemoKeyException, InterruptedException, SmackException.NoResponseException, SmackException.NotConnectedException, XMPPException.XMPPErrorException, SmackException.NotLoggedInException, PubSubException.NotALeafNodeException, CannotEstablishOmemoSessionException, UndecidedOmemoIdentityException, NoSuchAlgorithmException, CryptoFailedException {
|
public void messageSendingTest()
|
||||||
|
throws CorruptedOmemoKeyException, InterruptedException, SmackException.NoResponseException,
|
||||||
|
SmackException.NotConnectedException, XMPPException.XMPPErrorException,
|
||||||
|
SmackException.NotLoggedInException, PubSubException.NotALeafNodeException,
|
||||||
|
CannotEstablishOmemoSessionException, UndecidedOmemoIdentityException, NoSuchAlgorithmException,
|
||||||
|
CryptoFailedException, PubSubException.NotAPubSubNodeException {
|
||||||
final String alicesSecret = "Hey Bob! I love you!";
|
final String alicesSecret = "Hey Bob! I love you!";
|
||||||
final String bobsSecret = "I love you too, Alice."; //aww <3
|
final String bobsSecret = "I love you too, Alice."; //aww <3
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ package org.jivesoftware.smackx.omemo;
|
||||||
import static org.jivesoftware.smackx.omemo.util.OmemoConstants.BODY_OMEMO_HINT;
|
import static org.jivesoftware.smackx.omemo.util.OmemoConstants.BODY_OMEMO_HINT;
|
||||||
import static org.jivesoftware.smackx.omemo.util.OmemoConstants.OMEMO;
|
import static org.jivesoftware.smackx.omemo.util.OmemoConstants.OMEMO;
|
||||||
import static org.jivesoftware.smackx.omemo.util.OmemoConstants.OMEMO_NAMESPACE_V_AXOLOTL;
|
import static org.jivesoftware.smackx.omemo.util.OmemoConstants.OMEMO_NAMESPACE_V_AXOLOTL;
|
||||||
import static org.jivesoftware.smackx.omemo.util.OmemoConstants.PEP_NODE_DEVICE_LIST_NOTIFY;
|
|
||||||
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -32,8 +31,8 @@ import java.util.WeakHashMap;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.AbstractConnectionListener;
|
||||||
import org.jivesoftware.smack.AbstractXMPPConnection;
|
import org.jivesoftware.smack.AbstractXMPPConnection;
|
||||||
import org.jivesoftware.smack.ConnectionListener;
|
|
||||||
import org.jivesoftware.smack.Manager;
|
import org.jivesoftware.smack.Manager;
|
||||||
import org.jivesoftware.smack.SmackException;
|
import org.jivesoftware.smack.SmackException;
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
|
@ -41,6 +40,7 @@ import org.jivesoftware.smack.XMPPException;
|
||||||
import org.jivesoftware.smack.packet.ExtensionElement;
|
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||||
import org.jivesoftware.smack.packet.Message;
|
import org.jivesoftware.smack.packet.Message;
|
||||||
import org.jivesoftware.smack.packet.Stanza;
|
import org.jivesoftware.smack.packet.Stanza;
|
||||||
|
import org.jivesoftware.smack.util.Async;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.carbons.CarbonManager;
|
import org.jivesoftware.smackx.carbons.CarbonManager;
|
||||||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||||
|
@ -78,7 +78,6 @@ import org.jxmpp.jid.BareJid;
|
||||||
import org.jxmpp.jid.DomainBareJid;
|
import org.jxmpp.jid.DomainBareJid;
|
||||||
import org.jxmpp.jid.EntityBareJid;
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.jxmpp.jid.EntityFullJid;
|
import org.jxmpp.jid.EntityFullJid;
|
||||||
import org.jxmpp.jid.FullJid;
|
|
||||||
import org.jxmpp.jid.impl.JidCreate;
|
import org.jxmpp.jid.impl.JidCreate;
|
||||||
import org.jxmpp.stringprep.XmppStringprepException;
|
import org.jxmpp.stringprep.XmppStringprepException;
|
||||||
|
|
||||||
|
@ -110,8 +109,29 @@ public final class OmemoManager extends Manager {
|
||||||
*/
|
*/
|
||||||
private OmemoManager(XMPPConnection connection, int deviceId) {
|
private OmemoManager(XMPPConnection connection, int deviceId) {
|
||||||
super(connection);
|
super(connection);
|
||||||
setConnectionListener();
|
|
||||||
this.deviceId = deviceId;
|
this.deviceId = deviceId;
|
||||||
|
|
||||||
|
connection.addConnectionListener(new AbstractConnectionListener() {
|
||||||
|
@Override
|
||||||
|
public void authenticated(XMPPConnection connection, boolean resumed) {
|
||||||
|
if (resumed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Async.go(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
initialize();
|
||||||
|
} catch (InterruptedException | CorruptedOmemoKeyException | PubSubException.NotALeafNodeException | SmackException.NotLoggedInException | SmackException.NoResponseException | SmackException.NotConnectedException | XMPPException.XMPPErrorException e) {
|
||||||
|
LOGGER.log(Level.SEVERE, "connectionListener.authenticated() failed to initialize OmemoManager: "
|
||||||
|
+ e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
service = OmemoService.getInstance();
|
service = OmemoService.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,13 +183,13 @@ public final class OmemoManager extends Manager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int defaulDeviceId = OmemoService.getInstance().getOmemoStoreBackend().getDefaultDeviceId(user);
|
int defaultDeviceId = OmemoService.getInstance().getOmemoStoreBackend().getDefaultDeviceId(user);
|
||||||
if (defaulDeviceId < 1) {
|
if (defaultDeviceId < 1) {
|
||||||
defaulDeviceId = randomDeviceId();
|
defaultDeviceId = randomDeviceId();
|
||||||
OmemoService.getInstance().getOmemoStoreBackend().setDefaultDeviceId(user, defaulDeviceId);
|
OmemoService.getInstance().getOmemoStoreBackend().setDefaultDeviceId(user, defaultDeviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return getInstanceFor(connection, defaulDeviceId);
|
return getInstanceFor(connection, defaultDeviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -471,24 +491,6 @@ public final class OmemoManager extends Manager {
|
||||||
.getActiveDevices().isEmpty();
|
.getActiveDevices().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true, if the device resource has announced OMEMO support.
|
|
||||||
* Throws an IllegalArgumentException if the provided FullJid does not have a resource part.
|
|
||||||
*
|
|
||||||
* @param fullJid jid of a resource
|
|
||||||
* @return true if resource supports OMEMO
|
|
||||||
* @throws XMPPException.XMPPErrorException if
|
|
||||||
* @throws SmackException.NotConnectedException something
|
|
||||||
* @throws InterruptedException goes
|
|
||||||
* @throws SmackException.NoResponseException wrong
|
|
||||||
*/
|
|
||||||
public boolean resourceSupportsOmemo(FullJid fullJid) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException {
|
|
||||||
if (fullJid.hasNoResource()) {
|
|
||||||
throw new IllegalArgumentException("Jid " + fullJid + " has no resource part.");
|
|
||||||
}
|
|
||||||
return ServiceDiscoveryManager.getInstanceFor(connection()).discoverInfo(fullJid).containsFeature(PEP_NODE_DEVICE_LIST_NOTIFY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true, if the MUC with the EntityBareJid multiUserChat is non-anonymous and members only (prerequisite
|
* Returns true, if the MUC with the EntityBareJid multiUserChat is non-anonymous and members only (prerequisite
|
||||||
* for OMEMO encryption in MUC).
|
* for OMEMO encryption in MUC).
|
||||||
|
@ -641,54 +643,6 @@ public final class OmemoManager extends Manager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setConnectionListener() {
|
|
||||||
connection().addConnectionListener(new ConnectionListener() {
|
|
||||||
@Override
|
|
||||||
public void connected(XMPPConnection connection) {
|
|
||||||
LOGGER.log(Level.INFO, "connected");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void authenticated(XMPPConnection connection, boolean resumed) {
|
|
||||||
LOGGER.log(Level.INFO, "authenticated. Resumed: " + resumed);
|
|
||||||
if (resumed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
initialize();
|
|
||||||
} catch (InterruptedException | CorruptedOmemoKeyException | PubSubException.NotALeafNodeException | SmackException.NotLoggedInException | SmackException.NoResponseException | SmackException.NotConnectedException | XMPPException.XMPPErrorException e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "connectionListener.authenticated() failed to initialize OmemoManager: "
|
|
||||||
+ e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void connectionClosed() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void connectionClosedOnError(Exception e) {
|
|
||||||
connectionClosed();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reconnectionSuccessful() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reconnectingIn(int seconds) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reconnectionFailed(Exception e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int randomDeviceId() {
|
public static int randomDeviceId() {
|
||||||
int i = new Random().nextInt(Integer.MAX_VALUE);
|
int i = new Random().nextInt(Integer.MAX_VALUE);
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,6 @@ import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.crypto.BadPaddingException;
|
import javax.crypto.BadPaddingException;
|
||||||
import javax.crypto.IllegalBlockSizeException;
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
import javax.crypto.NoSuchPaddingException;
|
import javax.crypto.NoSuchPaddingException;
|
||||||
|
@ -51,6 +50,7 @@ import org.jivesoftware.smack.filter.StanzaFilter;
|
||||||
import org.jivesoftware.smack.packet.Message;
|
import org.jivesoftware.smack.packet.Message;
|
||||||
import org.jivesoftware.smack.packet.Stanza;
|
import org.jivesoftware.smack.packet.Stanza;
|
||||||
import org.jivesoftware.smack.packet.XMPPError;
|
import org.jivesoftware.smack.packet.XMPPError;
|
||||||
|
import org.jivesoftware.smack.util.Async;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.carbons.CarbonCopyReceivedListener;
|
import org.jivesoftware.smackx.carbons.CarbonCopyReceivedListener;
|
||||||
import org.jivesoftware.smackx.carbons.CarbonManager;
|
import org.jivesoftware.smackx.carbons.CarbonManager;
|
||||||
|
@ -82,12 +82,13 @@ import org.jivesoftware.smackx.omemo.util.OmemoMessageBuilder;
|
||||||
import org.jivesoftware.smackx.pep.PEPManager;
|
import org.jivesoftware.smackx.pep.PEPManager;
|
||||||
import org.jivesoftware.smackx.pubsub.LeafNode;
|
import org.jivesoftware.smackx.pubsub.LeafNode;
|
||||||
import org.jivesoftware.smackx.pubsub.PayloadItem;
|
import org.jivesoftware.smackx.pubsub.PayloadItem;
|
||||||
import org.jivesoftware.smackx.pubsub.PubSubAssertionError;
|
|
||||||
import org.jivesoftware.smackx.pubsub.PubSubException;
|
import org.jivesoftware.smackx.pubsub.PubSubException;
|
||||||
|
import org.jivesoftware.smackx.pubsub.PubSubException.NotAPubSubNodeException;
|
||||||
import org.jivesoftware.smackx.pubsub.PubSubManager;
|
import org.jivesoftware.smackx.pubsub.PubSubManager;
|
||||||
|
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
|
import org.jxmpp.jid.Jid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class contains OMEMO related logic and registers listeners etc.
|
* This class contains OMEMO related logic and registers listeners etc.
|
||||||
|
@ -427,11 +428,11 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
|
||||||
* @throws XMPPException.XMPPErrorException
|
* @throws XMPPException.XMPPErrorException
|
||||||
* @throws SmackException.NotConnectedException
|
* @throws SmackException.NotConnectedException
|
||||||
* @throws SmackException.NoResponseException
|
* @throws SmackException.NoResponseException
|
||||||
* @throws PubSubAssertionError.DiscoInfoNodeAssertionError ejabberd bug: https://github.com/processone/ejabberd/issues/1717
|
* @throws NotAPubSubNodeException
|
||||||
*/
|
*/
|
||||||
static LeafNode fetchDeviceListNode(OmemoManager omemoManager, BareJid contact)
|
static LeafNode fetchDeviceListNode(OmemoManager omemoManager, BareJid contact)
|
||||||
throws InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException,
|
throws InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException,
|
||||||
SmackException.NotConnectedException, SmackException.NoResponseException, PubSubAssertionError.DiscoInfoNodeAssertionError {
|
SmackException.NotConnectedException, SmackException.NoResponseException, NotAPubSubNodeException {
|
||||||
return PubSubManager.getInstance(omemoManager.getConnection(), contact).getLeafNode(PEP_NODE_DEVICE_LIST);
|
return PubSubManager.getInstance(omemoManager.getConnection(), contact).getLeafNode(PEP_NODE_DEVICE_LIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,9 +447,11 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
|
||||||
* @throws InterruptedException goes
|
* @throws InterruptedException goes
|
||||||
* @throws SmackException.NoResponseException wrong
|
* @throws SmackException.NoResponseException wrong
|
||||||
* @throws PubSubException.NotALeafNodeException when the device lists node is not a LeafNode
|
* @throws PubSubException.NotALeafNodeException when the device lists node is not a LeafNode
|
||||||
* @throws PubSubAssertionError.DiscoInfoNodeAssertionError ejabberd bug: https://github.com/processone/ejabberd/issues/1717
|
* @throws NotAPubSubNodeException
|
||||||
*/
|
*/
|
||||||
static OmemoDeviceListElement fetchDeviceList(OmemoManager omemoManager, BareJid contact) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, PubSubException.NotALeafNodeException, PubSubAssertionError.DiscoInfoNodeAssertionError {
|
static OmemoDeviceListElement fetchDeviceList(OmemoManager omemoManager, BareJid contact)
|
||||||
|
throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException,
|
||||||
|
SmackException.NoResponseException, PubSubException.NotALeafNodeException, NotAPubSubNodeException {
|
||||||
return extractDeviceListFrom(fetchDeviceListNode(omemoManager, contact));
|
return extractDeviceListFrom(fetchDeviceListNode(omemoManager, contact));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,9 +485,9 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
|
||||||
e.getMessage());
|
e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (PubSubAssertionError.DiscoInfoNodeAssertionError bug) {
|
catch (PubSubException.NotAPubSubNodeException e) {
|
||||||
LOGGER.log(Level.WARNING, "Caught a PubSubAssertionError when fetching a deviceList node. " +
|
LOGGER.log(Level.WARNING, "Caught a PubSubAssertionError when fetching a deviceList node. " +
|
||||||
"This probably means that we're dealing with an ejabberd server and the LeafNode does not exist.");
|
"This probably means that we're dealing with an ejabberd server and the LeafNode does not exist.", e);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -506,9 +509,8 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
|
||||||
LOGGER.log(Level.WARNING, "Could not fetch device list of " + contact + ": " + e, e);
|
LOGGER.log(Level.WARNING, "Could not fetch device list of " + contact + ": " + e, e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (PubSubAssertionError.DiscoInfoNodeAssertionError bug) {
|
catch (NotAPubSubNodeException e) {
|
||||||
LOGGER.log(Level.WARNING, "Caught a PubSubAssertionError when fetching a deviceList node. " +
|
LOGGER.log(Level.WARNING, "Could not fetch device list of " + contact ,e);
|
||||||
"This probably means that the LeafNode does not exist.");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -526,9 +528,13 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
|
||||||
* @throws InterruptedException goes
|
* @throws InterruptedException goes
|
||||||
* @throws SmackException.NoResponseException wrong
|
* @throws SmackException.NoResponseException wrong
|
||||||
* @throws PubSubException.NotALeafNodeException when the bundles node is not a LeafNode
|
* @throws PubSubException.NotALeafNodeException when the bundles node is not a LeafNode
|
||||||
|
* @throws NotAPubSubNodeException
|
||||||
*/
|
*/
|
||||||
static OmemoBundleVAxolotlElement fetchBundle(OmemoManager omemoManager, OmemoDevice contact) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, PubSubException.NotALeafNodeException, PubSubAssertionError.DiscoInfoNodeAssertionError {
|
static OmemoBundleVAxolotlElement fetchBundle(OmemoManager omemoManager, OmemoDevice contact)
|
||||||
LeafNode node = PubSubManager.getInstance(omemoManager.getConnection(), contact.getJid()).getLeafNode(PEP_NODE_BUNDLE_FROM_DEVICE_ID(contact.getDeviceId()));
|
throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException,
|
||||||
|
SmackException.NoResponseException, PubSubException.NotALeafNodeException, NotAPubSubNodeException {
|
||||||
|
LeafNode node = PubSubManager.getInstance(omemoManager.getConnection(), contact.getJid()).getLeafNode(
|
||||||
|
PEP_NODE_BUNDLE_FROM_DEVICE_ID(contact.getDeviceId()));
|
||||||
return extractBundleFrom(node);
|
return extractBundleFrom(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -665,7 +671,7 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
|
||||||
OmemoBundleVAxolotlElement bundle;
|
OmemoBundleVAxolotlElement bundle;
|
||||||
try {
|
try {
|
||||||
bundle = fetchBundle(omemoManager, device);
|
bundle = fetchBundle(omemoManager, device);
|
||||||
} catch (SmackException | XMPPException.XMPPErrorException | InterruptedException | PubSubAssertionError e) {
|
} catch (SmackException | XMPPException.XMPPErrorException | InterruptedException e) {
|
||||||
throw new CannotEstablishOmemoSessionException(device, e);
|
throw new CannotEstablishOmemoSessionException(device, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1177,7 +1183,7 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
|
||||||
*/
|
*/
|
||||||
private static OmemoDevice getSender(OmemoManager omemoManager, Stanza stanza) {
|
private static OmemoDevice getSender(OmemoManager omemoManager, Stanza stanza) {
|
||||||
OmemoElement omemoElement = stanza.getExtension(OmemoElement.ENCRYPTED, OMEMO_NAMESPACE_V_AXOLOTL);
|
OmemoElement omemoElement = stanza.getExtension(OmemoElement.ENCRYPTED, OMEMO_NAMESPACE_V_AXOLOTL);
|
||||||
BareJid sender = stanza.getFrom().asBareJid();
|
Jid sender = stanza.getFrom();
|
||||||
if (isMucMessage(omemoManager, stanza)) {
|
if (isMucMessage(omemoManager, stanza)) {
|
||||||
MultiUserChatManager mucm = MultiUserChatManager.getInstanceFor(omemoManager.getConnection());
|
MultiUserChatManager mucm = MultiUserChatManager.getInstanceFor(omemoManager.getConnection());
|
||||||
MultiUserChat muc = mucm.getMultiUserChat(sender.asEntityBareJidIfPossible());
|
MultiUserChat muc = mucm.getMultiUserChat(sender.asEntityBareJidIfPossible());
|
||||||
|
@ -1186,7 +1192,7 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
|
||||||
if (sender == null) {
|
if (sender == null) {
|
||||||
throw new AssertionError("Sender is null.");
|
throw new AssertionError("Sender is null.");
|
||||||
}
|
}
|
||||||
return new OmemoDevice(sender, omemoElement.getHeader().getSid());
|
return new OmemoDevice(sender.asBareJid(), omemoElement.getHeader().getSid());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1309,7 +1315,7 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
|
||||||
@Override
|
@Override
|
||||||
public void onCarbonCopyReceived(CarbonExtension.Direction direction, Message carbonCopy, Message wrappingMessage) {
|
public void onCarbonCopyReceived(CarbonExtension.Direction direction, Message carbonCopy, Message wrappingMessage) {
|
||||||
if (filter.accept(carbonCopy)) {
|
if (filter.accept(carbonCopy)) {
|
||||||
OmemoDevice senderDevice = getSender(omemoManager, carbonCopy);
|
final OmemoDevice senderDevice = getSender(omemoManager, carbonCopy);
|
||||||
Message decrypted;
|
Message decrypted;
|
||||||
MultiUserChatManager mucm = MultiUserChatManager.getInstanceFor(omemoManager.getConnection());
|
MultiUserChatManager mucm = MultiUserChatManager.getInstanceFor(omemoManager.getConnection());
|
||||||
OmemoElement omemoMessage = carbonCopy.getExtension(OmemoElement.ENCRYPTED, OMEMO_NAMESPACE_V_AXOLOTL);
|
OmemoElement omemoMessage = carbonCopy.getExtension(OmemoElement.ENCRYPTED, OMEMO_NAMESPACE_V_AXOLOTL);
|
||||||
|
@ -1365,16 +1371,22 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
|
||||||
LOGGER.log(Level.WARNING, "internal omemoMessageListener failed to decrypt incoming OMEMO carbon copy: "
|
LOGGER.log(Level.WARNING, "internal omemoMessageListener failed to decrypt incoming OMEMO carbon copy: "
|
||||||
+ e.getMessage());
|
+ e.getMessage());
|
||||||
|
|
||||||
} catch (NoRawSessionException e) {
|
} catch (final NoRawSessionException e) {
|
||||||
try {
|
Async.go(new Runnable() {
|
||||||
LOGGER.log(Level.INFO, "Received OMEMO carbon copy message with invalid session from " +
|
@Override
|
||||||
senderDevice + ". Send RatchetUpdateMessage.");
|
public void run() {
|
||||||
service.sendOmemoRatchetUpdateMessage(omemoManager, senderDevice, true);
|
try {
|
||||||
|
LOGGER.log(Level.INFO, "Received OMEMO carbon copy message with invalid session from " +
|
||||||
|
senderDevice + ". Send RatchetUpdateMessage.");
|
||||||
|
service.sendOmemoRatchetUpdateMessage(omemoManager, senderDevice, true);
|
||||||
|
|
||||||
|
} catch (UndecidedOmemoIdentityException | CorruptedOmemoKeyException | CannotEstablishOmemoSessionException | CryptoFailedException e1) {
|
||||||
|
LOGGER.log(Level.WARNING, "internal omemoMessageListener failed to establish a session for incoming OMEMO carbon message: "
|
||||||
|
+ e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
} catch (UndecidedOmemoIdentityException | CorruptedOmemoKeyException | CannotEstablishOmemoSessionException | CryptoFailedException e1) {
|
|
||||||
LOGGER.log(Level.WARNING, "internal omemoMessageListener failed to establish a session for incoming OMEMO carbon message: "
|
|
||||||
+ e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,20 +35,20 @@ public class UndecidedOmemoIdentityException extends Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the HashSet of untrusted devices.
|
* Return the HashSet of undecided devices.
|
||||||
*
|
*
|
||||||
* @return untrusted devices
|
* @return undecided devices
|
||||||
*/
|
*/
|
||||||
public HashSet<OmemoDevice> getUntrustedDevices() {
|
public HashSet<OmemoDevice> getUndecidedDevices() {
|
||||||
return this.devices;
|
return this.devices;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add all untrusted devices of another Exception to this Exceptions HashSet of untrusted devices.
|
* Add all undecided devices of another Exception to this Exceptions HashSet of undecided devices.
|
||||||
*
|
*
|
||||||
* @param other other Exception
|
* @param other other Exception
|
||||||
*/
|
*/
|
||||||
public void join(UndecidedOmemoIdentityException other) {
|
public void join(UndecidedOmemoIdentityException other) {
|
||||||
this.devices.addAll(other.getUntrustedDevices());
|
this.devices.addAll(other.getUndecidedDevices());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,18 +45,18 @@ public class OmemoExceptionsTest {
|
||||||
OmemoDevice mallory = new OmemoDevice(JidCreate.bareFrom("mallory@server.tld"), 9876);
|
OmemoDevice mallory = new OmemoDevice(JidCreate.bareFrom("mallory@server.tld"), 9876);
|
||||||
|
|
||||||
UndecidedOmemoIdentityException u = new UndecidedOmemoIdentityException(alice);
|
UndecidedOmemoIdentityException u = new UndecidedOmemoIdentityException(alice);
|
||||||
assertTrue(u.getUntrustedDevices().contains(alice));
|
assertTrue(u.getUndecidedDevices().contains(alice));
|
||||||
assertTrue(u.getUntrustedDevices().size() == 1);
|
assertTrue(u.getUndecidedDevices().size() == 1);
|
||||||
|
|
||||||
UndecidedOmemoIdentityException v = new UndecidedOmemoIdentityException(bob);
|
UndecidedOmemoIdentityException v = new UndecidedOmemoIdentityException(bob);
|
||||||
v.getUntrustedDevices().add(mallory);
|
v.getUndecidedDevices().add(mallory);
|
||||||
assertTrue(v.getUntrustedDevices().size() == 2);
|
assertTrue(v.getUndecidedDevices().size() == 2);
|
||||||
assertTrue(v.getUntrustedDevices().contains(bob));
|
assertTrue(v.getUndecidedDevices().contains(bob));
|
||||||
assertTrue(v.getUntrustedDevices().contains(mallory));
|
assertTrue(v.getUndecidedDevices().contains(mallory));
|
||||||
|
|
||||||
u.getUntrustedDevices().add(bob);
|
u.getUndecidedDevices().add(bob);
|
||||||
u.join(v);
|
u.join(v);
|
||||||
assertTrue(u.getUntrustedDevices().size() == 3);
|
assertTrue(u.getUndecidedDevices().size() == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -563,7 +563,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
|
||||||
}
|
}
|
||||||
for (HostAddress hostAddress : hostAddresses) {
|
for (HostAddress hostAddress : hostAddresses) {
|
||||||
Iterator<InetAddress> inetAddresses = null;
|
Iterator<InetAddress> inetAddresses = null;
|
||||||
String host = hostAddress.getFQDN();
|
String host = hostAddress.getHost();
|
||||||
int port = hostAddress.getPort();
|
int port = hostAddress.getPort();
|
||||||
if (proxyInfo == null) {
|
if (proxyInfo == null) {
|
||||||
inetAddresses = hostAddress.getInetAddresses().iterator();
|
inetAddresses = hostAddress.getInetAddresses().iterator();
|
||||||
|
@ -737,7 +737,8 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ks != null) {
|
if (ks != null) {
|
||||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
String keyManagerFactoryAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
|
||||||
|
KeyManagerFactory kmf = KeyManagerFactory.getInstance(keyManagerFactoryAlgorithm);
|
||||||
try {
|
try {
|
||||||
if (pcb == null) {
|
if (pcb == null) {
|
||||||
kmf.init(ks, null);
|
kmf.init(ks, null);
|
||||||
|
|
Loading…
Reference in a new issue