implemented support for for jingle encrypted transports (XEP-0396)
This commit is contained in:
parent
ff4d127b6f
commit
7ec1b443ab
|
@ -101,8 +101,8 @@ public final class Config {
|
||||||
|
|
||||||
|
|
||||||
public static final boolean DISABLE_PROXY_LOOKUP = false; //useful to debug ibb
|
public static final boolean DISABLE_PROXY_LOOKUP = false; //useful to debug ibb
|
||||||
public static final boolean USE_DIRECT_JINGLE_CANDIDATES = false;
|
public static final boolean USE_DIRECT_JINGLE_CANDIDATES = true;
|
||||||
public static final boolean DISABLE_HTTP_UPLOAD = false;
|
public static final boolean DISABLE_HTTP_UPLOAD = true;
|
||||||
public static final boolean EXTENDED_SM_LOGGING = false; // log stanza counts
|
public static final boolean EXTENDED_SM_LOGGING = false; // log stanza counts
|
||||||
public static final boolean BACKGROUND_STANZA_LOGGING = false; //log all stanzas that were received while the app is in background
|
public static final boolean BACKGROUND_STANZA_LOGGING = false; //log all stanzas that were received while the app is in background
|
||||||
public static final boolean RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE = true; //setting to true might increase power consumption
|
public static final boolean RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE = true; //setting to true might increase power consumption
|
||||||
|
|
|
@ -29,6 +29,8 @@ public abstract class AbstractGenerator {
|
||||||
Content.Version.FT_5.getNamespace(),
|
Content.Version.FT_5.getNamespace(),
|
||||||
Namespace.JINGLE_TRANSPORTS_S5B,
|
Namespace.JINGLE_TRANSPORTS_S5B,
|
||||||
Namespace.JINGLE_TRANSPORTS_IBB,
|
Namespace.JINGLE_TRANSPORTS_IBB,
|
||||||
|
Namespace.JINGLE_ENCRYPTED_TRANSPORT,
|
||||||
|
Namespace.JINGLE_ENCRYPTED_TRANSPORT_OMEMO,
|
||||||
"http://jabber.org/protocol/muc",
|
"http://jabber.org/protocol/muc",
|
||||||
"jabber:x:conference",
|
"jabber:x:conference",
|
||||||
Namespace.OOB,
|
Namespace.OOB,
|
||||||
|
|
|
@ -30,4 +30,6 @@ public final class Namespace {
|
||||||
public static final String PING = "urn:xmpp:ping";
|
public static final String PING = "urn:xmpp:ping";
|
||||||
public static final String PUSH = "urn:xmpp:push:0";
|
public static final String PUSH = "urn:xmpp:push:0";
|
||||||
public static final String COMMANDS = "http://jabber.org/protocol/commands";
|
public static final String COMMANDS = "http://jabber.org/protocol/commands";
|
||||||
|
public static final String JINGLE_ENCRYPTED_TRANSPORT = "urn:xmpp:jingle:jet:0";
|
||||||
|
public static final String JINGLE_ENCRYPTED_TRANSPORT_OMEMO = "urn:xmpp:jingle:jet-omemo:0";
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,8 @@ import rocks.xmpp.addr.Jid;
|
||||||
|
|
||||||
public class JingleConnection implements Transferable {
|
public class JingleConnection implements Transferable {
|
||||||
|
|
||||||
|
private static final String JET_OMEMO_CIPHER = "urn:xmpp:ciphers:aes-128-gcm-nopadding";
|
||||||
|
|
||||||
private static final int JINGLE_STATUS_INITIATED = 0;
|
private static final int JINGLE_STATUS_INITIATED = 0;
|
||||||
private static final int JINGLE_STATUS_ACCEPTED = 1;
|
private static final int JINGLE_STATUS_ACCEPTED = 1;
|
||||||
private static final int JINGLE_STATUS_FINISHED = 4;
|
private static final int JINGLE_STATUS_FINISHED = 4;
|
||||||
|
@ -72,6 +74,7 @@ public class JingleConnection implements Transferable {
|
||||||
private String contentName;
|
private String contentName;
|
||||||
private String contentCreator;
|
private String contentCreator;
|
||||||
private Transport initialTransport;
|
private Transport initialTransport;
|
||||||
|
private boolean remoteSupportsOmemoJet;
|
||||||
|
|
||||||
private int mProgress = 0;
|
private int mProgress = 0;
|
||||||
|
|
||||||
|
@ -295,8 +298,10 @@ public class JingleConnection implements Transferable {
|
||||||
this.contentName = this.mJingleConnectionManager.nextRandomId();
|
this.contentName = this.mJingleConnectionManager.nextRandomId();
|
||||||
this.message = message;
|
this.message = message;
|
||||||
this.account = message.getConversation().getAccount();
|
this.account = message.getConversation().getAccount();
|
||||||
upgradeNamespace();
|
final List<String> remoteFeatures = getRemoteFeatures();
|
||||||
this.initialTransport = getRemoteFeatures().contains(Namespace.JINGLE_TRANSPORTS_S5B) ? Transport.SOCKS : Transport.IBB;
|
upgradeNamespace(remoteFeatures);
|
||||||
|
this.initialTransport = remoteFeatures.contains(Namespace.JINGLE_TRANSPORTS_S5B) ? Transport.SOCKS : Transport.IBB;
|
||||||
|
this.remoteSupportsOmemoJet = remoteFeatures.contains(Namespace.JINGLE_ENCRYPTED_TRANSPORT_OMEMO);
|
||||||
this.message.setTransferable(this);
|
this.message.setTransferable(this);
|
||||||
this.mStatus = Transferable.STATUS_UPLOADING;
|
this.mStatus = Transferable.STATUS_UPLOADING;
|
||||||
this.initiator = this.account.getJid();
|
this.initiator = this.account.getJid();
|
||||||
|
@ -356,11 +361,10 @@ public class JingleConnection implements Transferable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void upgradeNamespace() {
|
private void upgradeNamespace(List<String> remoteFeatures) {
|
||||||
List<String> features = getRemoteFeatures();
|
if (remoteFeatures.contains(Content.Version.FT_5.getNamespace())) {
|
||||||
if (features.contains(Content.Version.FT_5.getNamespace())) {
|
|
||||||
this.ftVersion = Content.Version.FT_5;
|
this.ftVersion = Content.Version.FT_5;
|
||||||
} else if (features.contains(Content.Version.FT_4.getNamespace())) {
|
} else if (remoteFeatures.contains(Content.Version.FT_4.getNamespace())) {
|
||||||
this.ftVersion = Content.Version.FT_4;
|
this.ftVersion = Content.Version.FT_4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -430,6 +434,13 @@ public class JingleConnection implements Transferable {
|
||||||
|
|
||||||
if (fileOffer != null) {
|
if (fileOffer != null) {
|
||||||
Element encrypted = fileOffer.findChild("encrypted", AxolotlService.PEP_PREFIX);
|
Element encrypted = fileOffer.findChild("encrypted", AxolotlService.PEP_PREFIX);
|
||||||
|
if (encrypted == null) {
|
||||||
|
final Element security = content.findChild("security", Namespace.JINGLE_ENCRYPTED_TRANSPORT);
|
||||||
|
if (security != null && AxolotlService.PEP_PREFIX.equals(security.getAttribute("type"))) {
|
||||||
|
Log.d(Config.LOGTAG, account.getJid().asBareJid()+": received jingle file offer with JET");
|
||||||
|
encrypted = security.findChild("encrypted", AxolotlService.PEP_PREFIX);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (encrypted != null) {
|
if (encrypted != null) {
|
||||||
this.mXmppAxolotlMessage = XmppAxolotlMessage.fromElement(encrypted, packet.getFrom().asBareJid());
|
this.mXmppAxolotlMessage = XmppAxolotlMessage.fromElement(encrypted, packet.getFrom().asBareJid());
|
||||||
}
|
}
|
||||||
|
@ -520,7 +531,18 @@ public class JingleConnection implements Transferable {
|
||||||
this.file.setKey(mXmppAxolotlMessage.getInnerKey());
|
this.file.setKey(mXmppAxolotlMessage.getInnerKey());
|
||||||
this.file.setIv(mXmppAxolotlMessage.getIV());
|
this.file.setIv(mXmppAxolotlMessage.getIV());
|
||||||
this.file.setExpectedSize(file.getSize() + 16);
|
this.file.setExpectedSize(file.getSize() + 16);
|
||||||
content.setFileOffer(this.file, false, this.ftVersion).addChild(mXmppAxolotlMessage.toElement());
|
final Element file = content.setFileOffer(this.file, false, this.ftVersion);
|
||||||
|
if (remoteSupportsOmemoJet) {
|
||||||
|
Log.d(Config.LOGTAG, account.getJid().asBareJid()+": remote announced support for JET");
|
||||||
|
final Element security = new Element("security", Namespace.JINGLE_ENCRYPTED_TRANSPORT);
|
||||||
|
security.setAttribute("name", this.contentName);
|
||||||
|
security.setAttribute("cipher", JET_OMEMO_CIPHER);
|
||||||
|
security.setAttribute("type", AxolotlService.PEP_PREFIX);
|
||||||
|
security.addChild(mXmppAxolotlMessage.toElement());
|
||||||
|
content.addChild(security);
|
||||||
|
} else {
|
||||||
|
file.addChild(mXmppAxolotlMessage.toElement());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.file.setExpectedSize(file.getSize());
|
this.file.setExpectedSize(file.getSize());
|
||||||
content.setFileOffer(this.file, false, this.ftVersion);
|
content.setFileOffer(this.file, false, this.ftVersion);
|
||||||
|
@ -754,6 +776,8 @@ public class JingleConnection implements Transferable {
|
||||||
this.sendFallbackToIbb();
|
this.sendFallbackToIbb();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
final JingleCandidate candidate = connection.getCandidate();
|
||||||
|
Log.d(Config.LOGTAG, account.getJid().asBareJid()+": elected candidate "+candidate.getHost()+":"+candidate.getPort());
|
||||||
this.mJingleStatus = JINGLE_STATUS_TRANSMITTING;
|
this.mJingleStatus = JINGLE_STATUS_TRANSMITTING;
|
||||||
if (connection.needsActivation()) {
|
if (connection.needsActivation()) {
|
||||||
if (connection.getCandidate().isOurs()) {
|
if (connection.getCandidate().isOurs()) {
|
||||||
|
|
|
@ -16,6 +16,7 @@ import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
import eu.siacs.conversations.Config;
|
import eu.siacs.conversations.Config;
|
||||||
|
import eu.siacs.conversations.entities.Account;
|
||||||
import eu.siacs.conversations.entities.DownloadableFile;
|
import eu.siacs.conversations.entities.DownloadableFile;
|
||||||
import eu.siacs.conversations.persistance.FileBackend;
|
import eu.siacs.conversations.persistance.FileBackend;
|
||||||
import eu.siacs.conversations.services.AbstractConnectionManager;
|
import eu.siacs.conversations.services.AbstractConnectionManager;
|
||||||
|
@ -134,11 +135,14 @@ public class JingleSocks5Transport extends JingleTransport {
|
||||||
outputStream.write(response.array());
|
outputStream.write(response.array());
|
||||||
outputStream.flush();
|
outputStream.flush();
|
||||||
if (success) {
|
if (success) {
|
||||||
|
Log.d(Config.LOGTAG,connection.getAccount().getJid().asBareJid()+": successfully processed connection to candidate "+candidate.getHost()+":"+candidate.getPort());
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
this.inputStream = inputStream;
|
this.inputStream = inputStream;
|
||||||
this.outputStream = outputStream;
|
this.outputStream = outputStream;
|
||||||
this.isEstablished = true;
|
this.isEstablished = true;
|
||||||
FileBackend.close(serverSocket);
|
FileBackend.close(serverSocket);
|
||||||
|
} else {
|
||||||
|
this.socket.close();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
socket.close();
|
socket.close();
|
||||||
|
@ -174,6 +178,7 @@ public class JingleSocks5Transport extends JingleTransport {
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
InputStream fileInputStream = null;
|
InputStream fileInputStream = null;
|
||||||
final PowerManager.WakeLock wakeLock = connection.getConnectionManager().createWakeLock("jingle_send_" + connection.getSessionId());
|
final PowerManager.WakeLock wakeLock = connection.getConnectionManager().createWakeLock("jingle_send_" + connection.getSessionId());
|
||||||
|
long transmitted = 0;
|
||||||
try {
|
try {
|
||||||
wakeLock.acquire();
|
wakeLock.acquire();
|
||||||
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
||||||
|
@ -186,7 +191,6 @@ public class JingleSocks5Transport extends JingleTransport {
|
||||||
}
|
}
|
||||||
final InputStream innerInputStream = AbstractConnectionManager.upgrade(file, fileInputStream);
|
final InputStream innerInputStream = AbstractConnectionManager.upgrade(file, fileInputStream);
|
||||||
long size = file.getExpectedSize();
|
long size = file.getExpectedSize();
|
||||||
long transmitted = 0;
|
|
||||||
int count;
|
int count;
|
||||||
byte[] buffer = new byte[8192];
|
byte[] buffer = new byte[8192];
|
||||||
while ((count = innerInputStream.read(buffer)) > 0) {
|
while ((count = innerInputStream.read(buffer)) > 0) {
|
||||||
|
@ -201,7 +205,8 @@ public class JingleSocks5Transport extends JingleTransport {
|
||||||
callback.onFileTransmitted(file);
|
callback.onFileTransmitted(file);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": " + e.getMessage());
|
final Account account = connection.getAccount();
|
||||||
|
Log.d(Config.LOGTAG, account.getJid().asBareJid()+": failed sending file after "+transmitted+"/"+file.getExpectedSize()+" ("+ socket.getInetAddress()+":"+socket.getPort()+")", e);
|
||||||
callback.onFileTransferAborted();
|
callback.onFileTransferAborted();
|
||||||
} finally {
|
} finally {
|
||||||
FileBackend.close(fileInputStream);
|
FileBackend.close(fileInputStream);
|
||||||
|
|
|
@ -873,4 +873,5 @@
|
||||||
<string name="not_a_backup_file">A kiválasztott fájl nem a Conversations biztonsági mentése</string>
|
<string name="not_a_backup_file">A kiválasztott fájl nem a Conversations biztonsági mentése</string>
|
||||||
<string name="account_already_setup">Ez a fiók már be lett állítva</string>
|
<string name="account_already_setup">Ez a fiók már be lett állítva</string>
|
||||||
<string name="please_enter_password">Kérem, adja meg a fiókhoz tartozó jelszót</string>
|
<string name="please_enter_password">Kérem, adja meg a fiókhoz tartozó jelszót</string>
|
||||||
|
<string name="unable_to_perform_this_action">Nem sikerült ezt a cselekvést elvégezni</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue