get rid of legacy Jid wrapper around jxmpp

This commit is contained in:
Daniel Gultsch 2023-02-16 10:33:18 +01:00
parent 6845380be5
commit 3c42066a7c
No known key found for this signature in database
GPG key ID: F43D18AD2A0982C2
74 changed files with 372 additions and 319 deletions

View file

@ -5,7 +5,6 @@ import androidx.room.Room;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.IDs; import im.conversations.android.IDs;
import im.conversations.android.database.ConversationsDatabase; import im.conversations.android.database.ConversationsDatabase;
import im.conversations.android.database.entity.AccountEntity; import im.conversations.android.database.entity.AccountEntity;
@ -28,12 +27,16 @@ import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.jid.parts.Resourcepart;
import org.jxmpp.stringprep.XmppStringprepException;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class TransformationTest { public class TransformationTest {
private static final Jid ACCOUNT = Jid.of("user@example.com"); private static final BareJid ACCOUNT = JidCreate.bareFromOrThrowUnchecked("user@example.com");
private static final Jid REMOTE = Jid.of("juliet@example.com"); private static final BareJid REMOTE = JidCreate.bareFromOrThrowUnchecked("juliet@example.com");
private static final String GREETING = "Hi Juliet. How are you?"; private static final String GREETING = "Hi Juliet. How are you?";
@ -55,11 +58,11 @@ public class TransformationTest {
} }
@Test @Test
public void reactionBeforeOriginal() { public void reactionBeforeOriginal() throws XmppStringprepException {
final var reactionMessage = new Message(); final var reactionMessage = new Message();
reactionMessage.setId("2"); reactionMessage.setId("2");
reactionMessage.setTo(ACCOUNT); reactionMessage.setTo(ACCOUNT);
reactionMessage.setFrom(REMOTE.withResource("junit")); reactionMessage.setFrom(JidCreate.fullFrom(REMOTE, Resourcepart.from("junit")));
final var reactions = reactionMessage.addExtension(new Reactions()); final var reactions = reactionMessage.addExtension(new Reactions());
reactions.setId("1"); reactions.setId("1");
final var reaction = reactions.addExtension(new Reaction()); final var reaction = reactions.addExtension(new Reaction());
@ -69,7 +72,7 @@ public class TransformationTest {
final var originalMessage = new Message(); final var originalMessage = new Message();
originalMessage.setId("1"); originalMessage.setId("1");
originalMessage.setTo(REMOTE); originalMessage.setTo(REMOTE);
originalMessage.setFrom(ACCOUNT.withResource("junit")); originalMessage.setFrom(JidCreate.fullFrom(ACCOUNT, Resourcepart.from(("junit"))));
final var body = originalMessage.addExtension(new Body()); final var body = originalMessage.addExtension(new Body());
body.setContent(GREETING); body.setContent(GREETING);
this.transformer.transform( this.transformer.transform(
@ -86,28 +89,28 @@ public class TransformationTest {
} }
@Test @Test
public void multipleReactions() { public void multipleReactions() throws XmppStringprepException {
final var group = Jid.ofEscaped("a@group.example.com"); final var group = JidCreate.bareFrom("a@group.example.com");
final var message = new Message(Message.Type.GROUPCHAT); final var message = new Message(Message.Type.GROUPCHAT);
message.addExtension(new Body("Please give me a thumbs up")); message.addExtension(new Body("Please give me a thumbs up"));
message.setFrom(group.withResource("user-a")); message.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-a")));
this.transformer.transform( this.transformer.transform(
Transformation.of(message, Instant.now(), REMOTE, "stanza-a", "id-user-a")); Transformation.of(message, Instant.now(), REMOTE, "stanza-a", "id-user-a"));
final var reactionA = new Message(Message.Type.GROUPCHAT); final var reactionA = new Message(Message.Type.GROUPCHAT);
reactionA.setFrom(group.withResource("user-b")); reactionA.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-b")));
reactionA.addExtension(Reactions.to("stanza-a")).addExtension(new Reaction("Y")); reactionA.addExtension(Reactions.to("stanza-a")).addExtension(new Reaction("Y"));
this.transformer.transform( this.transformer.transform(
Transformation.of(reactionA, Instant.now(), REMOTE, "stanza-b", "id-user-b")); Transformation.of(reactionA, Instant.now(), REMOTE, "stanza-b", "id-user-b"));
final var reactionB = new Message(Message.Type.GROUPCHAT); final var reactionB = new Message(Message.Type.GROUPCHAT);
reactionB.setFrom(group.withResource("user-c")); reactionB.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-c")));
reactionB.addExtension(Reactions.to("stanza-a")).addExtension(new Reaction("Y")); reactionB.addExtension(Reactions.to("stanza-a")).addExtension(new Reaction("Y"));
this.transformer.transform( this.transformer.transform(
Transformation.of(reactionB, Instant.now(), REMOTE, "stanza-c", "id-user-c")); Transformation.of(reactionB, Instant.now(), REMOTE, "stanza-c", "id-user-c"));
final var reactionC = new Message(Message.Type.GROUPCHAT); final var reactionC = new Message(Message.Type.GROUPCHAT);
reactionC.setFrom(group.withResource("user-d")); reactionC.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-d")));
final var reactions = reactionC.addExtension(Reactions.to("stanza-a")); final var reactions = reactionC.addExtension(Reactions.to("stanza-a"));
reactions.addExtension(new Reaction("Y")); reactions.addExtension(new Reaction("Y"));
reactions.addExtension(new Reaction("Z")); reactions.addExtension(new Reaction("Z"));
@ -128,12 +131,12 @@ public class TransformationTest {
} }
@Test @Test
public void correctionBeforeOriginal() { public void correctionBeforeOriginal() throws XmppStringprepException {
final var messageCorrection = new Message(); final var messageCorrection = new Message();
messageCorrection.setId("2"); messageCorrection.setId("2");
messageCorrection.setTo(ACCOUNT); messageCorrection.setTo(ACCOUNT);
messageCorrection.setFrom(REMOTE.withResource("junit")); messageCorrection.setFrom(JidCreate.fullFrom(REMOTE, Resourcepart.from("junit")));
messageCorrection.addExtension(new Body()).setContent("Hi example!"); messageCorrection.addExtension(new Body()).setContent("Hi example!");
messageCorrection.addExtension(new Replace()).setId("1"); messageCorrection.addExtension(new Replace()).setId("1");
@ -146,7 +149,7 @@ public class TransformationTest {
final var messageWithTypo = new Message(); final var messageWithTypo = new Message();
messageWithTypo.setId("1"); messageWithTypo.setId("1");
messageWithTypo.setTo(ACCOUNT); messageWithTypo.setTo(ACCOUNT);
messageWithTypo.setFrom(REMOTE.withResource("junit")); messageWithTypo.setFrom(JidCreate.fullFrom(REMOTE, Resourcepart.from("junit")));
messageWithTypo.addExtension(new Body()).setContent("Hii example!"); messageWithTypo.addExtension(new Body()).setContent("Hii example!");
this.transformer.transform( this.transformer.transform(
@ -163,12 +166,12 @@ public class TransformationTest {
} }
@Test @Test
public void correctionAfterOriginal() { public void correctionAfterOriginal() throws XmppStringprepException {
final var messageWithTypo = new Message(); final var messageWithTypo = new Message();
messageWithTypo.setId("1"); messageWithTypo.setId("1");
messageWithTypo.setTo(ACCOUNT); messageWithTypo.setTo(ACCOUNT);
messageWithTypo.setFrom(REMOTE.withResource("junit")); messageWithTypo.setFrom(JidCreate.fullFrom(REMOTE, Resourcepart.from("junit")));
messageWithTypo.addExtension(new Body()).setContent("Hii example!"); messageWithTypo.addExtension(new Body()).setContent("Hii example!");
this.transformer.transform( this.transformer.transform(
@ -179,7 +182,7 @@ public class TransformationTest {
final var messageCorrection = new Message(); final var messageCorrection = new Message();
messageCorrection.setId("2"); messageCorrection.setId("2");
messageCorrection.setTo(ACCOUNT); messageCorrection.setTo(ACCOUNT);
messageCorrection.setFrom(REMOTE.withResource("junit")); messageCorrection.setFrom(JidCreate.fullFrom(REMOTE, Resourcepart.from("junit")));
messageCorrection.addExtension(new Body()).setContent("Hi example!"); messageCorrection.addExtension(new Body()).setContent("Hi example!");
messageCorrection.addExtension(new Replace()).setId("1"); messageCorrection.addExtension(new Replace()).setId("1");
@ -197,22 +200,22 @@ public class TransformationTest {
} }
@Test @Test
public void replacingReactions() { public void replacingReactions() throws XmppStringprepException {
final var group = Jid.ofEscaped("a@group.example.com"); final var group = JidCreate.bareFrom("a@group.example.com");
final var message = new Message(Message.Type.GROUPCHAT); final var message = new Message(Message.Type.GROUPCHAT);
message.addExtension(new Body("Please give me a thumbs up")); message.addExtension(new Body("Please give me a thumbs up"));
message.setFrom(group.withResource("user-a")); message.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-a")));
this.transformer.transform( this.transformer.transform(
Transformation.of(message, Instant.now(), REMOTE, "stanza-a", "id-user-a")); Transformation.of(message, Instant.now(), REMOTE, "stanza-a", "id-user-a"));
final var reactionA = new Message(Message.Type.GROUPCHAT); final var reactionA = new Message(Message.Type.GROUPCHAT);
reactionA.setFrom(group.withResource("user-b")); reactionA.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-b")));
reactionA.addExtension(Reactions.to("stanza-a")).addExtension(new Reaction("N")); reactionA.addExtension(Reactions.to("stanza-a")).addExtension(new Reaction("N"));
this.transformer.transform( this.transformer.transform(
Transformation.of(reactionA, Instant.now(), REMOTE, "stanza-b", "id-user-b")); Transformation.of(reactionA, Instant.now(), REMOTE, "stanza-b", "id-user-b"));
final var reactionB = new Message(Message.Type.GROUPCHAT); final var reactionB = new Message(Message.Type.GROUPCHAT);
reactionB.setFrom(group.withResource("user-b")); reactionB.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-b")));
reactionB.addExtension(Reactions.to("stanza-a")).addExtension(new Reaction("Y")); reactionB.addExtension(Reactions.to("stanza-a")).addExtension(new Reaction("Y"));
this.transformer.transform( this.transformer.transform(
Transformation.of(reactionB, Instant.now(), REMOTE, "stanza-c", "id-user-b")); Transformation.of(reactionB, Instant.now(), REMOTE, "stanza-c", "id-user-b"));
@ -224,8 +227,9 @@ public class TransformationTest {
} }
@Test @Test
public void twoCorrectionsOneReactionBeforeOriginalInGroupChat() { public void twoCorrectionsOneReactionBeforeOriginalInGroupChat()
final var group = Jid.ofEscaped("a@group.example.com"); throws XmppStringprepException {
final var group = JidCreate.bareFrom("a@group.example.com");
final var ogStanzaId = "og-stanza-id"; final var ogStanzaId = "og-stanza-id";
final var ogMessageId = "og-message-id"; final var ogMessageId = "og-message-id";
@ -234,7 +238,7 @@ public class TransformationTest {
// m1.setId(ogMessageId); // m1.setId(ogMessageId);
m1.addExtension(new Body("Please give me an thumbs up")); m1.addExtension(new Body("Please give me an thumbs up"));
m1.addExtension(new Replace()).setId(ogMessageId); m1.addExtension(new Replace()).setId(ogMessageId);
m1.setFrom(group.withResource("user-a")); m1.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-a")));
this.transformer.transform( this.transformer.transform(
Transformation.of( Transformation.of(
m1, m1,
@ -248,7 +252,7 @@ public class TransformationTest {
// m2.setId(ogMessageId); // m2.setId(ogMessageId);
m2.addExtension(new Body("Please give me a thumbs up")); m2.addExtension(new Body("Please give me a thumbs up"));
m2.addExtension(new Replace()).setId(ogMessageId); m2.addExtension(new Replace()).setId(ogMessageId);
m2.setFrom(group.withResource("user-a")); m2.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-a")));
this.transformer.transform( this.transformer.transform(
Transformation.of( Transformation.of(
m2, m2,
@ -259,7 +263,7 @@ public class TransformationTest {
// a reaction // a reaction
final var reactionB = new Message(Message.Type.GROUPCHAT); final var reactionB = new Message(Message.Type.GROUPCHAT);
reactionB.setFrom(group.withResource("user-b")); reactionB.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-b")));
reactionB.addExtension(Reactions.to(ogStanzaId)).addExtension(new Reaction("Y")); reactionB.addExtension(Reactions.to(ogStanzaId)).addExtension(new Reaction("Y"));
this.transformer.transform( this.transformer.transform(
Transformation.of( Transformation.of(
@ -269,7 +273,7 @@ public class TransformationTest {
final var m4 = new Message(Message.Type.GROUPCHAT); final var m4 = new Message(Message.Type.GROUPCHAT);
m4.setId(ogMessageId); m4.setId(ogMessageId);
m4.addExtension(new Body("Please give me thumbs up")); m4.addExtension(new Body("Please give me thumbs up"));
m4.setFrom(group.withResource("user-a")); m4.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-a")));
this.transformer.transform( this.transformer.transform(
Transformation.of(m4, Instant.ofEpochMilli(1000), REMOTE, ogStanzaId, "id-user-a")); Transformation.of(m4, Instant.ofEpochMilli(1000), REMOTE, ogStanzaId, "id-user-a"));
@ -283,14 +287,15 @@ public class TransformationTest {
} }
@Test @Test
public void twoReactionsOneCorrectionBeforeOriginalInGroupChat() { public void twoReactionsOneCorrectionBeforeOriginalInGroupChat()
final var group = Jid.ofEscaped("a@group.example.com"); throws XmppStringprepException {
final var group = JidCreate.bareFrom("a@group.example.com");
final var ogStanzaId = "og-stanza-id"; final var ogStanzaId = "og-stanza-id";
final var ogMessageId = "og-message-id"; final var ogMessageId = "og-message-id";
// first reaction // first reaction
final var reactionA = new Message(Message.Type.GROUPCHAT); final var reactionA = new Message(Message.Type.GROUPCHAT);
reactionA.setFrom(group.withResource("user-b")); reactionA.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-b")));
reactionA.addExtension(Reactions.to(ogStanzaId)).addExtension(new Reaction("Y")); reactionA.addExtension(Reactions.to(ogStanzaId)).addExtension(new Reaction("Y"));
this.transformer.transform( this.transformer.transform(
Transformation.of( Transformation.of(
@ -298,7 +303,7 @@ public class TransformationTest {
// second reaction // second reaction
final var reactionB = new Message(Message.Type.GROUPCHAT); final var reactionB = new Message(Message.Type.GROUPCHAT);
reactionB.setFrom(group.withResource("user-c")); reactionB.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-c")));
reactionB.addExtension(Reactions.to(ogStanzaId)).addExtension(new Reaction("Y")); reactionB.addExtension(Reactions.to(ogStanzaId)).addExtension(new Reaction("Y"));
this.transformer.transform( this.transformer.transform(
Transformation.of( Transformation.of(
@ -308,7 +313,7 @@ public class TransformationTest {
final var m1 = new Message(Message.Type.GROUPCHAT); final var m1 = new Message(Message.Type.GROUPCHAT);
m1.addExtension(new Body("Please give me a thumbs up")); m1.addExtension(new Body("Please give me a thumbs up"));
m1.addExtension(new Replace()).setId(ogMessageId); m1.addExtension(new Replace()).setId(ogMessageId);
m1.setFrom(group.withResource("user-a")); m1.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-a")));
this.transformer.transform( this.transformer.transform(
Transformation.of( Transformation.of(
m1, m1,
@ -321,7 +326,7 @@ public class TransformationTest {
final var m4 = new Message(Message.Type.GROUPCHAT); final var m4 = new Message(Message.Type.GROUPCHAT);
m4.setId(ogMessageId); m4.setId(ogMessageId);
m4.addExtension(new Body("Please give me thumbs up (Typo)")); m4.addExtension(new Body("Please give me thumbs up (Typo)"));
m4.setFrom(group.withResource("user-a")); m4.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-a")));
this.transformer.transform( this.transformer.transform(
Transformation.of(m4, Instant.ofEpochMilli(1000), REMOTE, ogStanzaId, "id-user-a")); Transformation.of(m4, Instant.ofEpochMilli(1000), REMOTE, ogStanzaId, "id-user-a"));
@ -337,8 +342,8 @@ public class TransformationTest {
} }
@Test @Test
public void twoReactionsInGroupChat() { public void twoReactionsInGroupChat() throws XmppStringprepException {
final var group = Jid.ofEscaped("a@group.example.com"); final var group = JidCreate.bareFrom("a@group.example.com");
final var ogStanzaId = "og-stanza-id"; final var ogStanzaId = "og-stanza-id";
final var ogMessageId = "og-message-id"; final var ogMessageId = "og-message-id";
@ -346,13 +351,13 @@ public class TransformationTest {
final var m4 = new Message(Message.Type.GROUPCHAT); final var m4 = new Message(Message.Type.GROUPCHAT);
m4.setId(ogMessageId); m4.setId(ogMessageId);
m4.addExtension(new Body("Please give me a thumbs up")); m4.addExtension(new Body("Please give me a thumbs up"));
m4.setFrom(group.withResource("user-a")); m4.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-a")));
this.transformer.transform( this.transformer.transform(
Transformation.of(m4, Instant.ofEpochMilli(1000), REMOTE, ogStanzaId, "id-user-a")); Transformation.of(m4, Instant.ofEpochMilli(1000), REMOTE, ogStanzaId, "id-user-a"));
// first reaction // first reaction
final var reactionA = new Message(Message.Type.GROUPCHAT); final var reactionA = new Message(Message.Type.GROUPCHAT);
reactionA.setFrom(group.withResource("user-b")); reactionA.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-b")));
reactionA.addExtension(Reactions.to(ogStanzaId)).addExtension(new Reaction("Y")); reactionA.addExtension(Reactions.to(ogStanzaId)).addExtension(new Reaction("Y"));
this.transformer.transform( this.transformer.transform(
Transformation.of( Transformation.of(
@ -360,7 +365,7 @@ public class TransformationTest {
// second reaction // second reaction
final var reactionB = new Message(Message.Type.GROUPCHAT); final var reactionB = new Message(Message.Type.GROUPCHAT);
reactionB.setFrom(group.withResource("user-c")); reactionB.setFrom(JidCreate.fullFrom(group, Resourcepart.from("user-c")));
reactionB.addExtension(Reactions.to(ogStanzaId)).addExtension(new Reaction("Y")); reactionB.addExtension(Reactions.to(ogStanzaId)).addExtension(new Reaction("Y"));
this.transformer.transform( this.transformer.transform(
Transformation.of( Transformation.of(
@ -378,11 +383,11 @@ public class TransformationTest {
} }
@Test @Test
public void inReplyTo() { public void inReplyTo() throws XmppStringprepException {
final var m1 = new Message(); final var m1 = new Message();
m1.setId("1"); m1.setId("1");
m1.setTo(ACCOUNT); m1.setTo(ACCOUNT);
m1.setFrom(REMOTE.withResource("junit")); m1.setFrom(JidCreate.fullFrom(REMOTE, Resourcepart.from("junit")));
m1.addExtension(new Body("Hi. How are you?")); m1.addExtension(new Body("Hi. How are you?"));
this.transformer.transform(Transformation.of(m1, Instant.now(), REMOTE, "stanza-a", null)); this.transformer.transform(Transformation.of(m1, Instant.now(), REMOTE, "stanza-a", null));
@ -411,18 +416,18 @@ public class TransformationTest {
} }
@Test @Test
public void messageWithReceipt() { public void messageWithReceipt() throws XmppStringprepException {
final var m1 = new Message(); final var m1 = new Message();
m1.setId("1"); m1.setId("1");
m1.setTo(REMOTE); m1.setTo(REMOTE);
m1.setFrom(ACCOUNT.withResource("junit")); m1.setFrom(JidCreate.fullFrom(ACCOUNT, Resourcepart.from("junit")));
m1.addExtension(new Body("Hi. How are you?")); m1.addExtension(new Body("Hi. How are you?"));
this.transformer.transform(Transformation.of(m1, Instant.now(), REMOTE, null, null)); this.transformer.transform(Transformation.of(m1, Instant.now(), REMOTE, null, null));
final var m2 = new Message(); final var m2 = new Message();
m2.setTo(ACCOUNT.withResource("junit")); m2.setTo(JidCreate.fullFrom(ACCOUNT, Resourcepart.from("junit")));
m2.setFrom(REMOTE.withResource("junit")); m2.setFrom(JidCreate.fullFrom(REMOTE, Resourcepart.from("junit")));
m2.addExtension(new Received()).setId("1"); m2.addExtension(new Received()).setId("1");
this.transformer.transform(Transformation.of(m2, Instant.now(), REMOTE, null, null)); this.transformer.transform(Transformation.of(m2, Instant.now(), REMOTE, null, null));
@ -434,10 +439,10 @@ public class TransformationTest {
} }
@Test @Test
public void messageAndRetraction() { public void messageAndRetraction() throws XmppStringprepException {
final var m1 = new Message(); final var m1 = new Message();
m1.setTo(ACCOUNT); m1.setTo(ACCOUNT);
m1.setFrom(REMOTE.withResource("junit")); m1.setFrom(JidCreate.fullFrom(REMOTE, Resourcepart.from("junit")));
m1.setId("m1"); m1.setId("m1");
m1.addExtension(new Body("It is raining outside")); m1.addExtension(new Body("It is raining outside"));
@ -445,7 +450,7 @@ public class TransformationTest {
final var m2 = new Message(); final var m2 = new Message();
m2.setTo(ACCOUNT); m2.setTo(ACCOUNT);
m2.setFrom(REMOTE.withResource("junit")); m2.setFrom(JidCreate.fullFrom(REMOTE, Resourcepart.from("junit")));
m2.addExtension(new Retract()).setId("m1"); m2.addExtension(new Retract()).setId("m1");
this.transformer.transform(Transformation.of(m2, Instant.now(), REMOTE, null, null)); this.transformer.transform(Transformation.of(m2, Instant.now(), REMOTE, null, null));

View file

@ -10,6 +10,12 @@ public class IDs {
private static final long UUID_VERSION_MASK = 4 << 12; private static final long UUID_VERSION_MASK = 4 << 12;
public static String huge() {
final var random = new byte[96];
Conversations.SECURE_RANDOM.nextBytes(random);
return BaseEncoding.base64Url().encode(random);
}
public static String medium() { public static String medium() {
final var random = new byte[9]; final var random = new byte[9];
Conversations.SECURE_RANDOM.nextBytes(random); Conversations.SECURE_RANDOM.nextBytes(random);

View file

@ -1,9 +1,13 @@
package im.conversations.android.database; package im.conversations.android.database;
import androidx.room.TypeConverter; import androidx.room.TypeConverter;
import eu.siacs.conversations.xmpp.Jid; import com.google.common.base.Strings;
import java.io.IOException; import java.io.IOException;
import java.time.Instant; import java.time.Instant;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.jid.parts.Resourcepart;
import org.whispersystems.libsignal.IdentityKey; import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.IdentityKeyPair; import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.InvalidKeyException; import org.whispersystems.libsignal.InvalidKeyException;
@ -26,13 +30,35 @@ public final class Converters {
} }
@TypeConverter @TypeConverter
public static Jid toJid(final String input) { public static BareJid toBareJid(final String input) {
return input == null ? null : Jid.ofEscaped(input); return input == null ? null : JidCreate.bareFromOrThrowUnchecked(input);
}
@TypeConverter
public static String fromBareJid(final BareJid jid) {
return jid == null ? null : jid.toString();
} }
@TypeConverter @TypeConverter
public static String fromJid(final Jid jid) { public static String fromJid(final Jid jid) {
return jid == null ? null : jid.toEscapedString(); return jid == null ? null : jid.toString();
}
@TypeConverter
public static Jid toJid(final String input) {
return input == null ? null : JidCreate.fromOrThrowUnchecked(input);
}
@TypeConverter
public static Resourcepart toResourcePart(final String input) {
return Strings.isNullOrEmpty(input)
? Resourcepart.EMPTY
: Resourcepart.fromOrThrowUnchecked(input);
}
@TypeConverter
public static String fromResourcePart(final Resourcepart resourcepart) {
return resourcepart == null ? null : resourcepart.toString();
} }
@TypeConverter @TypeConverter

View file

@ -159,14 +159,14 @@ public class CredentialStore {
private Credential getOrEmpty(final Account account) { private Credential getOrEmpty(final Account account) {
final Map<String, Credential> store = loadOrEmpty(); final Map<String, Credential> store = loadOrEmpty();
final Credential credential = store.get(account.address.toEscapedString()); final Credential credential = store.get(account.address.toString());
return credential == null ? Credential.empty() : credential; return credential == null ? Credential.empty() : credential;
} }
private void set(@NonNull final Account account, @NonNull final Credential credential) private void set(@NonNull final Account account, @NonNull final Credential credential)
throws GeneralSecurityException, IOException { throws GeneralSecurityException, IOException {
final HashMap<String, Credential> credentialStore = new HashMap<>(loadOrEmpty()); final HashMap<String, Credential> credentialStore = new HashMap<>(loadOrEmpty());
credentialStore.put(account.address.toEscapedString(), credential); credentialStore.put(account.address.toString(), credential);
store(credentialStore); store(credentialStore);
} }

View file

@ -5,11 +5,11 @@ import androidx.room.Insert;
import androidx.room.OnConflictStrategy; import androidx.room.OnConflictStrategy;
import androidx.room.Query; import androidx.room.Query;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.entity.AccountEntity; import im.conversations.android.database.entity.AccountEntity;
import im.conversations.android.database.model.Account; import im.conversations.android.database.model.Account;
import im.conversations.android.database.model.Connection; import im.conversations.android.database.model.Connection;
import java.util.List; import java.util.List;
import org.jxmpp.jid.BareJid;
@Dao @Dao
public interface AccountDao { public interface AccountDao {
@ -21,7 +21,7 @@ public interface AccountDao {
ListenableFuture<List<Account>> getEnabledAccounts(); ListenableFuture<List<Account>> getEnabledAccounts();
@Query("SELECT id,address,randomSeed FROM account WHERE address=:address AND enabled=1") @Query("SELECT id,address,randomSeed FROM account WHERE address=:address AND enabled=1")
ListenableFuture<Account> getEnabledAccount(Jid address); ListenableFuture<Account> getEnabledAccount(BareJid address);
@Query("SELECT id,address,randomSeed FROM account WHERE id=:id AND enabled=1") @Query("SELECT id,address,randomSeed FROM account WHERE id=:id AND enabled=1")
ListenableFuture<Account> getEnabledAccount(long id); ListenableFuture<Account> getEnabledAccount(long id);

View file

@ -4,12 +4,12 @@ import androidx.room.Dao;
import androidx.room.Insert; import androidx.room.Insert;
import androidx.room.OnConflictStrategy; import androidx.room.OnConflictStrategy;
import com.google.common.collect.Collections2; import com.google.common.collect.Collections2;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.entity.AvatarAdditionalEntity; import im.conversations.android.database.entity.AvatarAdditionalEntity;
import im.conversations.android.database.entity.AvatarEntity; import im.conversations.android.database.entity.AvatarEntity;
import im.conversations.android.database.model.Account; import im.conversations.android.database.model.Account;
import im.conversations.android.xmpp.model.avatar.Info; import im.conversations.android.xmpp.model.avatar.Info;
import java.util.Collection; import java.util.Collection;
import org.jxmpp.jid.BareJid;
@Dao @Dao
public abstract class AvatarDao { public abstract class AvatarDao {
@ -22,7 +22,7 @@ public abstract class AvatarDao {
public void set( public void set(
final Account account, final Account account,
final Jid address, final BareJid address,
final Info thumbnail, final Info thumbnail,
final Collection<Info> additional) { final Collection<Info> additional) {
final long id = insert(AvatarEntity.of(account, address, thumbnail)); final long id = insert(AvatarEntity.of(account, address, thumbnail));

View file

@ -6,7 +6,6 @@ import androidx.room.OnConflictStrategy;
import androidx.room.Query; import androidx.room.Query;
import androidx.room.Transaction; import androidx.room.Transaction;
import com.google.common.collect.Collections2; import com.google.common.collect.Collections2;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.entity.AxolotlDeviceListEntity; import im.conversations.android.database.entity.AxolotlDeviceListEntity;
import im.conversations.android.database.entity.AxolotlDeviceListItemEntity; import im.conversations.android.database.entity.AxolotlDeviceListItemEntity;
import im.conversations.android.database.entity.AxolotlIdentityEntity; import im.conversations.android.database.entity.AxolotlIdentityEntity;
@ -19,6 +18,7 @@ import im.conversations.android.xmpp.model.error.Condition;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.jxmpp.jid.BareJid;
import org.whispersystems.libsignal.IdentityKey; import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.IdentityKeyPair; import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.ecc.Curve; import org.whispersystems.libsignal.ecc.Curve;
@ -36,7 +36,7 @@ public abstract class AxolotlDao {
protected abstract void insert(Collection<AxolotlDeviceListItemEntity> entities); protected abstract void insert(Collection<AxolotlDeviceListItemEntity> entities);
@Transaction @Transaction
public void setDeviceList(Account account, Jid from, Set<Integer> deviceIds) { public void setDeviceList(Account account, BareJid from, Set<Integer> deviceIds) {
final var listId = insert(AxolotlDeviceListEntity.of(account.id, from)); final var listId = insert(AxolotlDeviceListEntity.of(account.id, from));
insert( insert(
Collections2.transform( Collections2.transform(
@ -47,15 +47,17 @@ public abstract class AxolotlDao {
"SELECT EXISTS(SELECT deviceId FROM axolotl_device_list JOIN axolotl_device_list_item" "SELECT EXISTS(SELECT deviceId FROM axolotl_device_list JOIN axolotl_device_list_item"
+ " ON axolotl_device_list.id=axolotl_device_list_item.deviceListId WHERE" + " ON axolotl_device_list.id=axolotl_device_list_item.deviceListId WHERE"
+ " accountId=:account AND address=:address AND deviceId=:deviceId)") + " accountId=:account AND address=:address AND deviceId=:deviceId)")
public abstract boolean hasDeviceId(final long account, final Jid address, final int deviceId); public abstract boolean hasDeviceId(
final long account, final BareJid address, final int deviceId);
@Transaction @Transaction
public void setDeviceListError(final Account account, final Jid address, Condition condition) { public void setDeviceListError(
final Account account, final BareJid address, Condition condition) {
insert(AxolotlDeviceListEntity.of(account.id, address, condition.getName())); insert(AxolotlDeviceListEntity.of(account.id, address, condition.getName()));
} }
@Transaction @Transaction
public void setDeviceListParsingError(final Account account, final Jid address) { public void setDeviceListParsingError(final Account account, final BareJid address) {
insert(AxolotlDeviceListEntity.ofParsingIssue(account.id, address)); insert(AxolotlDeviceListEntity.ofParsingIssue(account.id, address));
} }
@ -96,7 +98,7 @@ public abstract class AxolotlDao {
@Transaction @Transaction
public boolean setIdentity( public boolean setIdentity(
Account account, Jid address, int deviceId, IdentityKey identityKey) { Account account, BareJid address, int deviceId, IdentityKey identityKey) {
final var existing = getIdentityKey(account.id, address, deviceId); final var existing = getIdentityKey(account.id, address, deviceId);
if (existing == null || !existing.equals(identityKey)) { if (existing == null || !existing.equals(identityKey)) {
insert(AxolotlIdentityEntity.of(account, address, deviceId, identityKey)); insert(AxolotlIdentityEntity.of(account, address, deviceId, identityKey));
@ -112,7 +114,7 @@ public abstract class AxolotlDao {
@Query( @Query(
"SELECT identityKey FROM AXOLOTL_IDENTITY WHERE accountId=:account AND" "SELECT identityKey FROM AXOLOTL_IDENTITY WHERE accountId=:account AND"
+ " address=:address AND deviceId=:deviceId") + " address=:address AND deviceId=:deviceId")
protected abstract IdentityKey getIdentityKey(long account, Jid address, int deviceId); protected abstract IdentityKey getIdentityKey(long account, BareJid address, int deviceId);
@Query( @Query(
"SELECT preKeyRecord FROM axolotl_pre_key WHERE accountId=:account AND" "SELECT preKeyRecord FROM axolotl_pre_key WHERE accountId=:account AND"
@ -165,24 +167,25 @@ public abstract class AxolotlDao {
@Query( @Query(
"SELECT sessionRecord FROM axolotl_session WHERE accountId=:account AND" "SELECT sessionRecord FROM axolotl_session WHERE accountId=:account AND"
+ " address=:address AND deviceId=:deviceId") + " address=:address AND deviceId=:deviceId")
public abstract SessionRecord getSessionRecord(long account, Jid address, int deviceId); public abstract SessionRecord getSessionRecord(long account, BareJid address, int deviceId);
@Query("SELECT deviceId FROM axolotl_session WHERE accountId=:account AND address=:address") @Query("SELECT deviceId FROM axolotl_session WHERE accountId=:account AND address=:address")
public abstract List<Integer> getSessionDeviceIds(long account, String address); public abstract List<Integer> getSessionDeviceIds(long account, String address);
public void setSessionRecord(Account account, Jid address, int deviceId, SessionRecord record) { public void setSessionRecord(
Account account, BareJid address, int deviceId, SessionRecord record) {
insert(AxolotlSessionEntity.of(account, address, deviceId, record)); insert(AxolotlSessionEntity.of(account, address, deviceId, record));
} }
@Query( @Query(
"SELECT EXISTS(SELECT id FROM axolotl_session WHERE accountId=:account AND" "SELECT EXISTS(SELECT id FROM axolotl_session WHERE accountId=:account AND"
+ " address=:address AND deviceId=:deviceId)") + " address=:address AND deviceId=:deviceId)")
public abstract boolean hasSession(long account, Jid address, int deviceId); public abstract boolean hasSession(long account, BareJid address, int deviceId);
@Query( @Query(
"DELETE FROM axolotl_session WHERE accountId=:account AND address=:address AND" "DELETE FROM axolotl_session WHERE accountId=:account AND address=:address AND"
+ " deviceId=:deviceId") + " deviceId=:deviceId")
public abstract void deleteSession(long account, Jid address, int deviceId); public abstract void deleteSession(long account, BareJid address, int deviceId);
@Query("DELETE FROM axolotl_session WHERE accountId=:account AND address=:address") @Query("DELETE FROM axolotl_session WHERE accountId=:account AND address=:address")
public abstract void deleteSessions(long account, String address); public abstract void deleteSessions(long account, String address);

View file

@ -6,11 +6,11 @@ import androidx.room.OnConflictStrategy;
import androidx.room.Query; import androidx.room.Query;
import androidx.room.Transaction; import androidx.room.Transaction;
import com.google.common.collect.Collections2; import com.google.common.collect.Collections2;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.entity.BlockedItemEntity; import im.conversations.android.database.entity.BlockedItemEntity;
import im.conversations.android.database.model.Account; import im.conversations.android.database.model.Account;
import im.conversations.android.xmpp.model.blocking.Item; import im.conversations.android.xmpp.model.blocking.Item;
import java.util.Collection; import java.util.Collection;
import org.jxmpp.jid.Jid;
@Dao @Dao
public abstract class BlockingDao { public abstract class BlockingDao {

View file

@ -5,13 +5,14 @@ import androidx.room.Insert;
import androidx.room.Query; import androidx.room.Query;
import androidx.room.Transaction; import androidx.room.Transaction;
import com.google.common.collect.Collections2; import com.google.common.collect.Collections2;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.entity.BookmarkEntity; import im.conversations.android.database.entity.BookmarkEntity;
import im.conversations.android.database.model.Account; import im.conversations.android.database.model.Account;
import im.conversations.android.xmpp.model.bookmark.Conference; import im.conversations.android.xmpp.model.bookmark.Conference;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.impl.JidCreate;
@Dao @Dao
public abstract class BookmarkDao { public abstract class BookmarkDao {
@ -28,7 +29,7 @@ public abstract class BookmarkDao {
@Transaction @Transaction
public void updateItems(final Account account, Map<String, Conference> items) { public void updateItems(final Account account, Map<String, Conference> items) {
final Collection<Jid> addresses = final Collection<Jid> addresses =
Collections2.transform(items.keySet(), BookmarkEntity::jidOrNull); Collections2.transform(items.keySet(), JidCreate::fromOrNull);
delete(account.id, addresses); delete(account.id, addresses);
final var entities = final var entities =
Collections2.transform( Collections2.transform(

View file

@ -4,13 +4,13 @@ import androidx.room.Dao;
import androidx.room.Insert; import androidx.room.Insert;
import androidx.room.Query; import androidx.room.Query;
import androidx.room.Transaction; import androidx.room.Transaction;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.entity.ChatEntity; import im.conversations.android.database.entity.ChatEntity;
import im.conversations.android.database.model.Account; import im.conversations.android.database.model.Account;
import im.conversations.android.database.model.ChatIdentifier; import im.conversations.android.database.model.ChatIdentifier;
import im.conversations.android.database.model.ChatType; import im.conversations.android.database.model.ChatType;
import im.conversations.android.xmpp.model.stanza.Message; import im.conversations.android.xmpp.model.stanza.Message;
import java.util.Arrays; import java.util.Arrays;
import org.jxmpp.jid.Jid;
@Dao @Dao
public abstract class ChatDao { public abstract class ChatDao {
@ -38,7 +38,7 @@ public abstract class ChatDao {
// TODO do not create entity for 'error' // TODO do not create entity for 'error'
final var entity = new ChatEntity(); final var entity = new ChatEntity();
entity.accountId = account.id; entity.accountId = account.id;
entity.address = address.toEscapedString(); entity.address = address.toString();
entity.type = chatType; entity.type = chatType;
entity.archived = true; entity.archived = true;
final long id = insert(entity); final long id = insert(entity);

View file

@ -8,7 +8,6 @@ import androidx.room.Query;
import androidx.room.Transaction; import androidx.room.Transaction;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.collect.Collections2; import com.google.common.collect.Collections2;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.entity.DiscoEntity; import im.conversations.android.database.entity.DiscoEntity;
import im.conversations.android.database.entity.DiscoExtensionEntity; import im.conversations.android.database.entity.DiscoExtensionEntity;
import im.conversations.android.database.entity.DiscoExtensionFieldEntity; import im.conversations.android.database.entity.DiscoExtensionFieldEntity;
@ -27,6 +26,8 @@ import im.conversations.android.xmpp.model.disco.info.Identity;
import im.conversations.android.xmpp.model.disco.info.InfoQuery; import im.conversations.android.xmpp.model.disco.info.InfoQuery;
import im.conversations.android.xmpp.model.disco.items.Item; import im.conversations.android.xmpp.model.disco.items.Item;
import java.util.Collection; import java.util.Collection;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.parts.Resourcepart;
@Dao @Dao
public abstract class DiscoDao { public abstract class DiscoDao {
@ -56,7 +57,7 @@ public abstract class DiscoDao {
"UPDATE presence SET discoId=:discoId WHERE accountId=:account AND address=:address" "UPDATE presence SET discoId=:discoId WHERE accountId=:account AND address=:address"
+ " AND resource=:resource") + " AND resource=:resource")
protected abstract void updateDiscoIdInPresence( protected abstract void updateDiscoIdInPresence(
long account, Jid address, String resource, long discoId); long account, Jid address, Resourcepart resource, long discoId);
@Query( @Query(
"UPDATE disco_item SET discoId=:discoId WHERE accountId=:account AND address=:address" "UPDATE disco_item SET discoId=:discoId WHERE accountId=:account AND address=:address"
@ -131,7 +132,7 @@ public abstract class DiscoDao {
updateDiscoIdInPresence( updateDiscoIdInPresence(
account, account,
entity.address.asBareJid(), entity.address.asBareJid(),
Strings.nullToEmpty(entity.address.getResource()), entity.address.getResourceOrEmpty(),
discoId); discoId);
} }
} }

View file

@ -9,7 +9,6 @@ import androidx.room.Update;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.Collections2; import com.google.common.collect.Collections2;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.entity.MessageContentEntity; import im.conversations.android.database.entity.MessageContentEntity;
import im.conversations.android.database.entity.MessageEntity; import im.conversations.android.database.entity.MessageEntity;
import im.conversations.android.database.entity.MessageReactionEntity; import im.conversations.android.database.entity.MessageReactionEntity;
@ -27,6 +26,9 @@ import im.conversations.android.xmpp.model.reactions.Reactions;
import im.conversations.android.xmpp.model.stanza.Message; import im.conversations.android.xmpp.model.stanza.Message;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.parts.Resourcepart;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -38,14 +40,17 @@ public abstract class MessageDao {
@Query( @Query(
"UPDATE message SET acknowledged=1 WHERE messageId=:messageId AND toBare=:toBare AND" "UPDATE message SET acknowledged=1 WHERE messageId=:messageId AND toBare=:toBare AND"
+ " toResource=NULL AND chatId IN (SELECT id FROM chat WHERE accountId=:account)") + " toResource=NULL AND chatId IN (SELECT id FROM chat WHERE accountId=:account)")
abstract int acknowledge(long account, String messageId, final String toBare); abstract int acknowledge(long account, String messageId, final BareJid toBare);
@Query( @Query(
"UPDATE message SET acknowledged=1 WHERE messageId=:messageId AND toBare=:toBare AND" "UPDATE message SET acknowledged=1 WHERE messageId=:messageId AND toBare=:toBare AND"
+ " toResource=:toResource AND chatId IN (SELECT id FROM chat WHERE" + " toResource=:toResource AND chatId IN (SELECT id FROM chat WHERE"
+ " accountId=:account)") + " accountId=:account)")
abstract int acknowledge( abstract int acknowledge(
long account, final String messageId, final String toBare, final String toResource); long account,
final String messageId,
final BareJid toBare,
final Resourcepart toResource);
public boolean acknowledge( public boolean acknowledge(
final Account account, @NonNull final String messageId, @NonNull final Jid to) { final Account account, @NonNull final String messageId, @NonNull final Jid to) {
@ -54,12 +59,10 @@ public abstract class MessageDao {
public boolean acknowledge( public boolean acknowledge(
final long account, @NonNull final String messageId, @NonNull final Jid to) { final long account, @NonNull final String messageId, @NonNull final Jid to) {
if (to.isBareJid()) { if (to.hasResource()) {
return acknowledge(account, messageId, to.toEscapedString()) > 0; return acknowledge(account, messageId, to.asBareJid(), to.getResourceOrThrow()) > 0;
} else { } else {
return acknowledge( return acknowledge(account, messageId, to.asBareJid()) > 0;
account, messageId, to.asBareJid().toEscapedString(), to.getResource())
> 0;
} }
} }
@ -192,7 +195,7 @@ public abstract class MessageDao {
+ " stanzaId=:stanzaId AND (stanzaIdVerified=1 OR latestVersion IS NULL)) OR" + " stanzaId=:stanzaId AND (stanzaIdVerified=1 OR latestVersion IS NULL)) OR"
+ " (stanzaId IS NULL AND messageId=:messageId AND latestVersion IS NULL))") + " (stanzaId IS NULL AND messageId=:messageId AND latestVersion IS NULL))")
abstract MessageIdentifier get( abstract MessageIdentifier get(
long chatId, Jid fromBare, String occupantId, String stanzaId, String messageId); long chatId, BareJid fromBare, String occupantId, String stanzaId, String messageId);
public MessageIdentifier getOrCreateVersion( public MessageIdentifier getOrCreateVersion(
ChatIdentifier chat, ChatIdentifier chat,
@ -257,13 +260,13 @@ public abstract class MessageDao {
+ " chatId=:chatId AND (fromBare=:fromBare OR fromBare IS NULL) AND" + " chatId=:chatId AND (fromBare=:fromBare OR fromBare IS NULL) AND"
+ " (occupantId=:occupantId OR occupantId IS NULL) AND messageId=:messageId") + " (occupantId=:occupantId OR occupantId IS NULL) AND messageId=:messageId")
abstract MessageIdentifier getByOccupantIdAndMessageId( abstract MessageIdentifier getByOccupantIdAndMessageId(
long chatId, Jid fromBare, String occupantId, String messageId); long chatId, BareJid fromBare, String occupantId, String messageId);
@Query( @Query(
"SELECT id,stanzaId,messageId,fromBare,latestVersion as version FROM message WHERE" "SELECT id,stanzaId,messageId,fromBare,latestVersion as version FROM message WHERE"
+ " chatId=:chatId AND (fromBare=:fromBare OR fromBare IS NULL) AND" + " chatId=:chatId AND (fromBare=:fromBare OR fromBare IS NULL) AND"
+ " messageId=:messageId") + " messageId=:messageId")
abstract MessageIdentifier getByMessageId(long chatId, Jid fromBare, String messageId); abstract MessageIdentifier getByMessageId(long chatId, BareJid fromBare, String messageId);
@Query( @Query(
"SELECT id FROM message_version WHERE messageEntityId=:messageEntityId ORDER BY (CASE" "SELECT id FROM message_version WHERE messageEntityId=:messageEntityId ORDER BY (CASE"
@ -393,7 +396,7 @@ public abstract class MessageDao {
@Query( @Query(
"DELETE FROM message_reaction WHERE messageEntityId=:messageEntityId AND" "DELETE FROM message_reaction WHERE messageEntityId=:messageEntityId AND"
+ " reactionBy=:fromBare") + " reactionBy=:fromBare")
protected abstract void deleteReactionsByFromBare(long messageEntityId, Jid fromBare); protected abstract void deleteReactionsByFromBare(long messageEntityId, BareJid fromBare);
@Transaction @Transaction
@Query( @Query(
@ -436,7 +439,7 @@ public abstract class MessageDao {
@Query( @Query(
"SELECT id FROM message WHERE chatId=:chatId AND fromBare=:fromBare AND" "SELECT id FROM message WHERE chatId=:chatId AND fromBare=:fromBare AND"
+ " messageId=:messageId") + " messageId=:messageId")
protected abstract Long getMessageByMessageId(long chatId, Jid fromBare, String messageId); protected abstract Long getMessageByMessageId(long chatId, BareJid fromBare, String messageId);
@Query("SELECT id FROM message WHERE chatId=:chatId AND stanzaId=:stanzaId") @Query("SELECT id FROM message WHERE chatId=:chatId AND stanzaId=:stanzaId")
protected abstract Long getMessageByStanzaId(long chatId, String stanzaId); protected abstract Long getMessageByStanzaId(long chatId, String stanzaId);

View file

@ -3,9 +3,9 @@ package im.conversations.android.database.dao;
import androidx.room.Dao; import androidx.room.Dao;
import androidx.room.Insert; import androidx.room.Insert;
import androidx.room.OnConflictStrategy; import androidx.room.OnConflictStrategy;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.entity.NickEntity; import im.conversations.android.database.entity.NickEntity;
import im.conversations.android.database.model.Account; import im.conversations.android.database.model.Account;
import org.jxmpp.jid.Jid;
@Dao @Dao
public abstract class NickDao { public abstract class NickDao {

View file

@ -6,12 +6,13 @@ import androidx.room.Dao;
import androidx.room.Insert; import androidx.room.Insert;
import androidx.room.OnConflictStrategy; import androidx.room.OnConflictStrategy;
import androidx.room.Query; import androidx.room.Query;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.entity.PresenceEntity; import im.conversations.android.database.entity.PresenceEntity;
import im.conversations.android.database.model.Account; import im.conversations.android.database.model.Account;
import im.conversations.android.database.model.PresenceShow; import im.conversations.android.database.model.PresenceShow;
import im.conversations.android.database.model.PresenceType; import im.conversations.android.database.model.PresenceType;
import java.util.Arrays; import java.util.Arrays;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.parts.Resourcepart;
@Dao @Dao
public abstract class PresenceDao { public abstract class PresenceDao {
@ -20,29 +21,29 @@ public abstract class PresenceDao {
public abstract void deletePresences(long account); public abstract void deletePresences(long account);
@Query("DELETE FROM presence WHERE accountId=:account AND address=:address") @Query("DELETE FROM presence WHERE accountId=:account AND address=:address")
abstract void deletePresences(long account, Jid address); abstract void deletePresences(long account, BareJid address);
@Query( @Query(
"DELETE FROM presence WHERE accountId=:account AND address=:address AND" "DELETE FROM presence WHERE accountId=:account AND address=:address AND"
+ " resource=:resource") + " resource=:resource")
abstract void deletePresence(long account, Jid address, String resource); abstract void deletePresence(long account, BareJid address, Resourcepart resource);
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
abstract void insert(PresenceEntity entity); abstract void insert(PresenceEntity entity);
public void set( public void set(
@NonNull final Account account, @NonNull final Account account,
@NonNull final Jid address, @NonNull final BareJid address,
@Nullable final String resource, @NonNull final Resourcepart resource,
@Nullable final PresenceType type, @Nullable final PresenceType type,
@Nullable final PresenceShow show, @Nullable final PresenceShow show,
@Nullable final String status) { @Nullable final String status) {
if (resource == null if (resource.equals(Resourcepart.EMPTY)
&& Arrays.asList(PresenceType.ERROR, PresenceType.UNAVAILABLE).contains(type)) { && Arrays.asList(PresenceType.ERROR, PresenceType.UNAVAILABLE).contains(type)) {
deletePresences(account.id, address); deletePresences(account.id, address);
} }
if (type == PresenceType.UNAVAILABLE) { if (type == PresenceType.UNAVAILABLE) {
if (resource != null) { if (!resource.equals(Resourcepart.EMPTY)) {
deletePresence(account.id, address, resource); deletePresence(account.id, address, resource);
} }
// unavailable presence only delete previous nothing left to do // unavailable presence only delete previous nothing left to do

View file

@ -7,12 +7,12 @@ import androidx.room.Insert;
import androidx.room.Query; import androidx.room.Query;
import androidx.room.Transaction; import androidx.room.Transaction;
import com.google.common.collect.Collections2; import com.google.common.collect.Collections2;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.entity.RosterItemEntity; import im.conversations.android.database.entity.RosterItemEntity;
import im.conversations.android.database.entity.RosterItemGroupEntity; import im.conversations.android.database.entity.RosterItemGroupEntity;
import im.conversations.android.database.model.Account; import im.conversations.android.database.model.Account;
import im.conversations.android.xmpp.model.roster.Item; import im.conversations.android.xmpp.model.roster.Item;
import java.util.Collection; import java.util.Collection;
import org.jxmpp.jid.Jid;
@Dao @Dao
public abstract class RosterDao { public abstract class RosterDao {

View file

@ -5,9 +5,10 @@ import androidx.room.Embedded;
import androidx.room.Entity; import androidx.room.Entity;
import androidx.room.Index; import androidx.room.Index;
import androidx.room.PrimaryKey; import androidx.room.PrimaryKey;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.model.Connection; import im.conversations.android.database.model.Connection;
import im.conversations.android.database.model.Proxy; import im.conversations.android.database.model.Proxy;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.parts.Resourcepart;
@Entity( @Entity(
tableName = "account", tableName = "account",
@ -21,8 +22,8 @@ public class AccountEntity {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
public Long id; public Long id;
@NonNull public Jid address; @NonNull public BareJid address;
public String resource; public Resourcepart resource;
public byte[] randomSeed; public byte[] randomSeed;
public boolean enabled; public boolean enabled;

View file

@ -6,10 +6,10 @@ import androidx.room.Entity;
import androidx.room.ForeignKey; import androidx.room.ForeignKey;
import androidx.room.Index; import androidx.room.Index;
import androidx.room.PrimaryKey; import androidx.room.PrimaryKey;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.model.Account; import im.conversations.android.database.model.Account;
import im.conversations.android.database.model.AvatarThumbnail; import im.conversations.android.database.model.AvatarThumbnail;
import im.conversations.android.xmpp.model.avatar.Info; import im.conversations.android.xmpp.model.avatar.Info;
import org.jxmpp.jid.BareJid;
@Entity( @Entity(
tableName = "avatar", tableName = "avatar",
@ -31,13 +31,13 @@ public class AvatarEntity {
@NonNull public Long accountId; @NonNull public Long accountId;
@NonNull public Jid address; @NonNull public BareJid address;
@Embedded(prefix = "thumb_") @Embedded(prefix = "thumb_")
@NonNull @NonNull
public AvatarThumbnail thumbnail; public AvatarThumbnail thumbnail;
public static AvatarEntity of(final Account account, final Jid address, final Info info) { public static AvatarEntity of(final Account account, final BareJid address, final Info info) {
final var entity = new AvatarEntity(); final var entity = new AvatarEntity();
entity.accountId = account.id; entity.accountId = account.id;
entity.address = address; entity.address = address;

View file

@ -5,8 +5,8 @@ import androidx.room.Entity;
import androidx.room.ForeignKey; import androidx.room.ForeignKey;
import androidx.room.Index; import androidx.room.Index;
import androidx.room.PrimaryKey; import androidx.room.PrimaryKey;
import eu.siacs.conversations.xmpp.Jid;
import java.time.Instant; import java.time.Instant;
import org.jxmpp.jid.BareJid;
@Entity( @Entity(
tableName = "axolotl_device_list", tableName = "axolotl_device_list",
@ -28,7 +28,7 @@ public class AxolotlDeviceListEntity {
@NonNull public Long accountId; @NonNull public Long accountId;
@NonNull public Jid address; @NonNull public BareJid address;
@NonNull public Instant receivedAt; @NonNull public Instant receivedAt;
@ -36,7 +36,7 @@ public class AxolotlDeviceListEntity {
public boolean isParsingIssue; public boolean isParsingIssue;
public static AxolotlDeviceListEntity of(long accountId, final Jid address) { public static AxolotlDeviceListEntity of(long accountId, final BareJid address) {
final var entity = new AxolotlDeviceListEntity(); final var entity = new AxolotlDeviceListEntity();
entity.accountId = accountId; entity.accountId = accountId;
entity.address = address; entity.address = address;
@ -46,7 +46,7 @@ public class AxolotlDeviceListEntity {
} }
public static AxolotlDeviceListEntity of( public static AxolotlDeviceListEntity of(
final long accountId, final Jid address, final String errorCondition) { final long accountId, final BareJid address, final String errorCondition) {
final var entity = new AxolotlDeviceListEntity(); final var entity = new AxolotlDeviceListEntity();
entity.accountId = accountId; entity.accountId = accountId;
entity.address = address; entity.address = address;
@ -55,7 +55,7 @@ public class AxolotlDeviceListEntity {
return entity; return entity;
} }
public static AxolotlDeviceListEntity ofParsingIssue(final long account, Jid address) { public static AxolotlDeviceListEntity ofParsingIssue(final long account, BareJid address) {
final var entity = new AxolotlDeviceListEntity(); final var entity = new AxolotlDeviceListEntity();
entity.accountId = account; entity.accountId = account;
entity.address = address; entity.address = address;

View file

@ -5,8 +5,8 @@ import androidx.room.Entity;
import androidx.room.ForeignKey; import androidx.room.ForeignKey;
import androidx.room.Index; import androidx.room.Index;
import androidx.room.PrimaryKey; import androidx.room.PrimaryKey;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.model.Account; import im.conversations.android.database.model.Account;
import org.jxmpp.jid.BareJid;
import org.whispersystems.libsignal.IdentityKey; import org.whispersystems.libsignal.IdentityKey;
@Entity( @Entity(
@ -29,14 +29,14 @@ public class AxolotlIdentityEntity {
@NonNull public Long accountId; @NonNull public Long accountId;
@NonNull public Jid address; @NonNull public BareJid address;
@NonNull public Integer deviceId; @NonNull public Integer deviceId;
@NonNull public IdentityKey identityKey; @NonNull public IdentityKey identityKey;
public static AxolotlIdentityEntity of( public static AxolotlIdentityEntity of(
Account account, Jid address, int deviceId, IdentityKey identityKey) { Account account, BareJid address, int deviceId, IdentityKey identityKey) {
final var entity = new AxolotlIdentityEntity(); final var entity = new AxolotlIdentityEntity();
entity.accountId = account.id; entity.accountId = account.id;
entity.address = address; entity.address = address;

View file

@ -5,8 +5,8 @@ import androidx.room.Entity;
import androidx.room.ForeignKey; import androidx.room.ForeignKey;
import androidx.room.Index; import androidx.room.Index;
import androidx.room.PrimaryKey; import androidx.room.PrimaryKey;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.model.Account; import im.conversations.android.database.model.Account;
import org.jxmpp.jid.BareJid;
import org.whispersystems.libsignal.state.SessionRecord; import org.whispersystems.libsignal.state.SessionRecord;
@Entity( @Entity(
@ -29,14 +29,14 @@ public class AxolotlSessionEntity {
@NonNull public Long accountId; @NonNull public Long accountId;
@NonNull public Jid address; @NonNull public BareJid address;
@NonNull public Integer deviceId; @NonNull public Integer deviceId;
@NonNull public SessionRecord sessionRecord; @NonNull public SessionRecord sessionRecord;
public static AxolotlSessionEntity of( public static AxolotlSessionEntity of(
Account account, Jid address, int deviceId, SessionRecord record) { Account account, BareJid address, int deviceId, SessionRecord record) {
final var entity = new AxolotlSessionEntity(); final var entity = new AxolotlSessionEntity();
entity.accountId = account.id; entity.accountId = account.id;
entity.address = address; entity.address = address;

View file

@ -5,7 +5,7 @@ import androidx.room.Entity;
import androidx.room.ForeignKey; import androidx.room.ForeignKey;
import androidx.room.Index; import androidx.room.Index;
import androidx.room.PrimaryKey; import androidx.room.PrimaryKey;
import eu.siacs.conversations.xmpp.Jid; import org.jxmpp.jid.Jid;
@Entity( @Entity(
tableName = "blocked", tableName = "blocked",

View file

@ -5,9 +5,10 @@ import androidx.room.Entity;
import androidx.room.ForeignKey; import androidx.room.ForeignKey;
import androidx.room.Index; import androidx.room.Index;
import androidx.room.PrimaryKey; import androidx.room.PrimaryKey;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xmpp.model.bookmark.Conference; import im.conversations.android.xmpp.model.bookmark.Conference;
import java.util.Map; import java.util.Map;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.impl.JidCreate;
@Entity( @Entity(
tableName = "bookmark", tableName = "bookmark",
@ -41,7 +42,7 @@ public class BookmarkEntity {
public static BookmarkEntity of( public static BookmarkEntity of(
final long accountId, final Map.Entry<String, Conference> entry) { final long accountId, final Map.Entry<String, Conference> entry) {
final var address = jidOrNull(entry.getKey()); final var address = JidCreate.fromOrNull(entry.getKey());
final var conference = entry.getValue(); final var conference = entry.getValue();
if (address == null) { if (address == null) {
return null; return null;
@ -53,12 +54,4 @@ public class BookmarkEntity {
entity.name = conference.getConferenceName(); entity.name = conference.getConferenceName();
return entity; return entity;
} }
public static Jid jidOrNull(final String address) {
try {
return address == null ? null : Jid.ofEscaped(address);
} catch (final IllegalArgumentException e) {
return null;
}
}
} }

View file

@ -6,8 +6,8 @@ import androidx.room.ForeignKey;
import androidx.room.Index; import androidx.room.Index;
import androidx.room.PrimaryKey; import androidx.room.PrimaryKey;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xmpp.model.disco.items.Item; import im.conversations.android.xmpp.model.disco.items.Item;
import org.jxmpp.jid.Jid;
@Entity( @Entity(
tableName = "disco_item", tableName = "disco_item",
@ -57,7 +57,7 @@ public class DiscoItemEntity {
entity.accountId = accountId; entity.accountId = accountId;
entity.address = item.getJid(); entity.address = item.getJid();
entity.node = Strings.nullToEmpty(item.getNode()); entity.node = Strings.nullToEmpty(item.getNode());
entity.parentAddress = parent.toEscapedString(); entity.parentAddress = parent.toString();
entity.parentNode = Strings.nullToEmpty(parentNode); entity.parentNode = Strings.nullToEmpty(parentNode);
return entity; return entity;
} }

View file

@ -6,10 +6,11 @@ import androidx.room.Entity;
import androidx.room.ForeignKey; import androidx.room.ForeignKey;
import androidx.room.Index; import androidx.room.Index;
import androidx.room.PrimaryKey; import androidx.room.PrimaryKey;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.transformer.Transformation; import im.conversations.android.transformer.Transformation;
import java.time.Instant; import java.time.Instant;
import java.util.Objects; import java.util.Objects;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.parts.Resourcepart;
@Entity( @Entity(
tableName = "message", tableName = "message",
@ -47,10 +48,10 @@ public class MessageEntity {
public boolean outgoing; public boolean outgoing;
public Jid toBare; public BareJid toBare;
public String toResource; public Resourcepart toResource;
public Jid fromBare; public BareJid fromBare;
public String fromResource; public Resourcepart fromResource;
public String occupantId; public String occupantId;

View file

@ -5,9 +5,10 @@ import androidx.room.Entity;
import androidx.room.ForeignKey; import androidx.room.ForeignKey;
import androidx.room.Index; import androidx.room.Index;
import androidx.room.PrimaryKey; import androidx.room.PrimaryKey;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.transformer.Transformation; import im.conversations.android.transformer.Transformation;
import java.time.Instant; import java.time.Instant;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.parts.Resourcepart;
@Entity( @Entity(
tableName = "message_reaction", tableName = "message_reaction",
@ -27,8 +28,8 @@ public class MessageReactionEntity {
public String stanzaId; public String stanzaId;
public String messageId; public String messageId;
public Jid reactionBy; public BareJid reactionBy;
public String reactionByResource; public Resourcepart reactionByResource;
public String occupantId; public String occupantId;
public Instant receivedAt; public Instant receivedAt;

View file

@ -6,9 +6,10 @@ import androidx.room.Entity;
import androidx.room.ForeignKey; import androidx.room.ForeignKey;
import androidx.room.Index; import androidx.room.Index;
import androidx.room.PrimaryKey; import androidx.room.PrimaryKey;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.model.MessageState; import im.conversations.android.database.model.MessageState;
import im.conversations.android.database.model.StateType; import im.conversations.android.database.model.StateType;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.parts.Resourcepart;
@Entity( @Entity(
tableName = "message_state", tableName = "message_state",
@ -26,9 +27,9 @@ public class MessageStateEntity {
@NonNull public Long messageVersionId; @NonNull public Long messageVersionId;
@NonNull public Jid fromBare; @NonNull public BareJid fromBare;
@Nullable public String fromResource; @Nullable public Resourcepart fromResource;
@NonNull public StateType type; @NonNull public StateType type;

View file

@ -6,11 +6,12 @@ import androidx.room.ForeignKey;
import androidx.room.Index; import androidx.room.Index;
import androidx.room.PrimaryKey; import androidx.room.PrimaryKey;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.model.Modification; import im.conversations.android.database.model.Modification;
import im.conversations.android.transformer.Transformation; import im.conversations.android.transformer.Transformation;
import im.conversations.android.xmpp.model.stanza.Message; import im.conversations.android.xmpp.model.stanza.Message;
import java.time.Instant; import java.time.Instant;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.parts.Resourcepart;
@Entity( @Entity(
tableName = "message_version", tableName = "message_version",
@ -31,8 +32,8 @@ public class MessageVersionEntity {
public String messageId; public String messageId;
public String stanzaId; public String stanzaId;
public Modification modification; public Modification modification;
public Jid modifiedBy; public BareJid modifiedBy;
public String modifiedByResource; public Resourcepart modifiedByResource;
public String occupantId; public String occupantId;
public Instant receivedAt; public Instant receivedAt;

View file

@ -5,7 +5,7 @@ import androidx.room.Entity;
import androidx.room.ForeignKey; import androidx.room.ForeignKey;
import androidx.room.Index; import androidx.room.Index;
import androidx.room.PrimaryKey; import androidx.room.PrimaryKey;
import eu.siacs.conversations.xmpp.Jid; import org.jxmpp.jid.Jid;
@Entity( @Entity(
tableName = "nick", tableName = "nick",

View file

@ -6,11 +6,12 @@ import androidx.room.Entity;
import androidx.room.ForeignKey; import androidx.room.ForeignKey;
import androidx.room.Index; import androidx.room.Index;
import androidx.room.PrimaryKey; import androidx.room.PrimaryKey;
import com.google.common.base.Strings;
import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.model.PresenceShow; import im.conversations.android.database.model.PresenceShow;
import im.conversations.android.database.model.PresenceType; import im.conversations.android.database.model.PresenceType;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.parts.Resourcepart;
@Entity( @Entity(
tableName = "presence", tableName = "presence",
@ -39,9 +40,9 @@ public class PresenceEntity {
@NonNull public Long accountId; @NonNull public Long accountId;
@NonNull public Jid address; @NonNull public BareJid address;
@NonNull public String resource; @NonNull public Resourcepart resource;
@Nullable public PresenceType type; @Nullable public PresenceType type;
@ -66,15 +67,15 @@ public class PresenceEntity {
public static PresenceEntity of( public static PresenceEntity of(
long account, long account,
Jid address, @NonNull BareJid address,
@Nullable String resource, @NonNull Resourcepart resource,
PresenceType type, PresenceType type,
PresenceShow show, PresenceShow show,
String status) { String status) {
final var entity = new PresenceEntity(); final var entity = new PresenceEntity();
entity.accountId = account; entity.accountId = account;
entity.address = address; entity.address = address;
entity.resource = Strings.nullToEmpty(resource); entity.resource = resource;
entity.type = type; entity.type = type;
entity.show = show; entity.show = show;
entity.status = status; entity.status = status;

View file

@ -5,8 +5,8 @@ import androidx.room.Entity;
import androidx.room.ForeignKey; import androidx.room.ForeignKey;
import androidx.room.Index; import androidx.room.Index;
import androidx.room.PrimaryKey; import androidx.room.PrimaryKey;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xmpp.model.roster.Item; import im.conversations.android.xmpp.model.roster.Item;
import org.jxmpp.jid.Jid;
@Entity( @Entity(
tableName = "roster", tableName = "roster",

View file

@ -6,20 +6,19 @@ import com.google.common.base.Preconditions;
import com.google.common.hash.Hashing; import com.google.common.hash.Hashing;
import com.google.common.io.ByteSource; import com.google.common.io.ByteSource;
import com.google.common.primitives.Ints; import com.google.common.primitives.Ints;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.IDs; import im.conversations.android.IDs;
import java.io.IOException; import java.io.IOException;
import java.util.UUID; import java.util.UUID;
import org.jxmpp.jid.BareJid;
public class Account { public class Account {
public final long id; public final long id;
@NonNull public final Jid address; @NonNull public final BareJid address;
@NonNull public final byte[] randomSeed; @NonNull public final byte[] randomSeed;
public Account(final long id, @NonNull final Jid address, @NonNull byte[] randomSeed) { public Account(final long id, @NonNull final BareJid address, @NonNull byte[] randomSeed) {
Preconditions.checkNotNull(address, "Account can not be instantiated without an address"); Preconditions.checkNotNull(address, "Account can not be instantiated without an address");
Preconditions.checkArgument(address.isBareJid(), "Account address must be bare");
Preconditions.checkArgument( Preconditions.checkArgument(
randomSeed.length == 32, "RandomSeed must have exactly 32 bytes"); randomSeed.length == 32, "RandomSeed must have exactly 32 bytes");
this.id = id; this.id = id;
@ -43,7 +42,7 @@ public class Account {
} }
public boolean isOnion() { public boolean isOnion() {
final String domain = address.getDomain().toEscapedString(); final String domain = address.getDomain().toString();
return domain.endsWith(".onion"); return domain.endsWith(".onion");
} }

View file

@ -1,6 +1,6 @@
package im.conversations.android.database.model; package im.conversations.android.database.model;
import eu.siacs.conversations.xmpp.Jid; import org.jxmpp.jid.Jid;
public class ChatIdentifier { public class ChatIdentifier {

View file

@ -1,10 +1,10 @@
package im.conversations.android.database.model; package im.conversations.android.database.model;
import androidx.room.Relation; import androidx.room.Relation;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.entity.MessageContentEntity; import im.conversations.android.database.entity.MessageContentEntity;
import java.time.Instant; import java.time.Instant;
import java.util.List; import java.util.List;
import org.jxmpp.jid.Jid;
public class MessageEmbedded { public class MessageEmbedded {

View file

@ -1,17 +1,17 @@
package im.conversations.android.database.model; package im.conversations.android.database.model;
import eu.siacs.conversations.xmpp.Jid; import org.jxmpp.jid.BareJid;
public class MessageIdentifier { public class MessageIdentifier {
public final long id; public final long id;
public final String stanzaId; public final String stanzaId;
public final String messageId; public final String messageId;
public final Jid fromBare; public final BareJid fromBare;
public final Long version; public final Long version;
public MessageIdentifier( public MessageIdentifier(
long id, String stanzaId, String messageId, Jid fromBare, Long version) { long id, String stanzaId, String messageId, BareJid fromBare, Long version) {
this.id = id; this.id = id;
this.stanzaId = stanzaId; this.stanzaId = stanzaId;
this.messageId = messageId; this.messageId = messageId;

View file

@ -1,6 +1,6 @@
package im.conversations.android.database.model; package im.conversations.android.database.model;
import eu.siacs.conversations.xmpp.Jid; import org.jxmpp.jid.Jid;
public class MessageReaction { public class MessageReaction {

View file

@ -1,18 +1,19 @@
package im.conversations.android.database.model; package im.conversations.android.database.model;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.transformer.Transformation; import im.conversations.android.transformer.Transformation;
import im.conversations.android.xmpp.model.error.Condition; import im.conversations.android.xmpp.model.error.Condition;
import im.conversations.android.xmpp.model.error.Error; import im.conversations.android.xmpp.model.error.Error;
import im.conversations.android.xmpp.model.error.Text; import im.conversations.android.xmpp.model.error.Text;
import im.conversations.android.xmpp.model.stanza.Message; import im.conversations.android.xmpp.model.stanza.Message;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.parts.Resourcepart;
public class MessageState { public class MessageState {
public final Jid fromBare; public final BareJid fromBare;
public final String fromResource; public final Resourcepart fromResource;
public final StateType type; public final StateType type;
@ -21,8 +22,8 @@ public class MessageState {
public final String errorText; public final String errorText;
public MessageState( public MessageState(
Jid fromBare, BareJid fromBare,
String fromResource, Resourcepart fromResource,
StateType type, StateType type,
String errorCondition, String errorCondition,
String errorText) { String errorText) {

View file

@ -4,7 +4,6 @@ import androidx.room.Relation;
import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Multimaps; import com.google.common.collect.Multimaps;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.entity.MessageContentEntity; import im.conversations.android.database.entity.MessageContentEntity;
import im.conversations.android.database.entity.MessageEntity; import im.conversations.android.database.entity.MessageEntity;
import im.conversations.android.database.entity.MessageReactionEntity; import im.conversations.android.database.entity.MessageReactionEntity;
@ -14,6 +13,7 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.jxmpp.jid.Jid;
public class MessageWithContentReactions { public class MessageWithContentReactions {

View file

@ -6,7 +6,6 @@ import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.IDs; import im.conversations.android.IDs;
import im.conversations.android.database.CredentialStore; import im.conversations.android.database.CredentialStore;
import im.conversations.android.database.entity.AccountEntity; import im.conversations.android.database.entity.AccountEntity;
@ -14,6 +13,7 @@ import im.conversations.android.database.model.Account;
import im.conversations.android.xmpp.ConnectionPool; import im.conversations.android.xmpp.ConnectionPool;
import im.conversations.android.xmpp.XmppConnection; import im.conversations.android.xmpp.XmppConnection;
import im.conversations.android.xmpp.manager.RegistrationManager; import im.conversations.android.xmpp.manager.RegistrationManager;
import org.jxmpp.jid.BareJid;
public class AccountRepository extends AbstractRepository { public class AccountRepository extends AbstractRepository {
@ -22,9 +22,7 @@ public class AccountRepository extends AbstractRepository {
} }
private Account createAccount( private Account createAccount(
@NonNull final Jid address, final String password, final boolean loginAndBind) { @NonNull final BareJid address, final String password, final boolean loginAndBind) {
Preconditions.checkArgument(
address.isBareJid(), "Account should be specified without resource");
Preconditions.checkArgument(password != null, "Missing password"); Preconditions.checkArgument(password != null, "Missing password");
final byte[] randomSeed = IDs.seed(); final byte[] randomSeed = IDs.seed();
final var entity = new AccountEntity(); final var entity = new AccountEntity();
@ -44,12 +42,12 @@ public class AccountRepository extends AbstractRepository {
} }
public ListenableFuture<Account> createAccountAsync( public ListenableFuture<Account> createAccountAsync(
final @NonNull Jid address, final String password, final boolean loginAndBind) { final @NonNull BareJid address, final String password, final boolean loginAndBind) {
return Futures.submit(() -> createAccount(address, password, loginAndBind), IO_EXECUTOR); return Futures.submit(() -> createAccount(address, password, loginAndBind), IO_EXECUTOR);
} }
public ListenableFuture<Account> createAccountAsync( public ListenableFuture<Account> createAccountAsync(
final @NonNull Jid address, final String password) { final @NonNull BareJid address, final String password) {
return createAccountAsync(address, password, true); return createAccountAsync(address, password, true);
} }

View file

@ -4,7 +4,6 @@ import androidx.annotation.NonNull;
import com.google.common.collect.Collections2; import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xmpp.model.DeliveryReceipt; import im.conversations.android.xmpp.model.DeliveryReceipt;
import im.conversations.android.xmpp.model.DeliveryReceiptRequest; import im.conversations.android.xmpp.model.DeliveryReceiptRequest;
import im.conversations.android.xmpp.model.Extension; import im.conversations.android.xmpp.model.Extension;
@ -25,6 +24,9 @@ import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.parts.Resourcepart;
public class Transformation { public class Transformation {
@ -83,20 +85,20 @@ public class Transformation {
return this.extensions.size() > 0; return this.extensions.size() > 0;
} }
public Jid fromBare() { public BareJid fromBare() {
return from == null ? null : from.asBareJid(); return from == null ? null : from.asBareJid();
} }
public String fromResource() { public Resourcepart fromResource() {
return from == null ? null : from.getResource(); return from == null ? null : from.getResourceOrNull();
} }
public Jid toBare() { public BareJid toBare() {
return to == null ? null : to.asBareJid(); return to == null ? null : to.asBareJid();
} }
public String toResource() { public Resourcepart toResource() {
return to == null ? null : to.getResource(); return to == null ? null : to.getResourceOrNull();
} }
public Instant sentAt() { public Instant sentAt() {

View file

@ -1,13 +1,13 @@
package im.conversations.android.transformer; package im.conversations.android.transformer;
import android.content.Context; import android.content.Context;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xml.Namespace; import im.conversations.android.xml.Namespace;
import im.conversations.android.xmpp.XmppConnection; import im.conversations.android.xmpp.XmppConnection;
import im.conversations.android.xmpp.manager.DiscoManager; import im.conversations.android.xmpp.manager.DiscoManager;
import im.conversations.android.xmpp.model.occupant.OccupantId; import im.conversations.android.xmpp.model.occupant.OccupantId;
import im.conversations.android.xmpp.model.stanza.Message; import im.conversations.android.xmpp.model.stanza.Message;
import java.time.Instant; import java.time.Instant;
import org.jxmpp.jid.Jid;
public class TransformationFactory extends XmppConnection.Delegate { public class TransformationFactory extends XmppConnection.Delegate {

View file

@ -4,7 +4,6 @@ import com.google.common.base.Preconditions;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import eu.siacs.conversations.xmpp.InvalidJid;
import im.conversations.android.database.ConversationsDatabase; import im.conversations.android.database.ConversationsDatabase;
import im.conversations.android.database.model.Account; import im.conversations.android.database.model.Account;
import im.conversations.android.database.model.ChatIdentifier; import im.conversations.android.database.model.ChatIdentifier;
@ -132,7 +131,7 @@ public class Transformer {
final var reply = transformation.getExtension(Reply.class); final var reply = transformation.getExtension(Reply.class);
if (Objects.nonNull(reply) if (Objects.nonNull(reply)
&& Objects.nonNull(reply.getId()) && Objects.nonNull(reply.getId())
&& InvalidJid.isValid(reply.getTo())) { && Objects.nonNull(reply.getTo())) {
database.messageDao() database.messageDao()
.setInReplyTo( .setInReplyTo(
chat, messageIdentifier, messageType, reply.getTo(), reply.getId()); chat, messageIdentifier, messageType, reply.getTo(), reply.getId());

View file

@ -1,7 +1,6 @@
package im.conversations.android.xml; package im.conversations.android.xml;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.base.Strings; import com.google.common.base.Strings;
@ -9,15 +8,14 @@ import com.google.common.collect.Collections2;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.primitives.Ints; import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs; import com.google.common.primitives.Longs;
import eu.siacs.conversations.xmpp.InvalidJid;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xmpp.ExtensionFactory; import im.conversations.android.xmpp.ExtensionFactory;
import im.conversations.android.xmpp.model.Extension; import im.conversations.android.xmpp.model.Extension;
import im.conversations.android.xmpp.model.stanza.Message;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.List; import java.util.List;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.impl.JidCreate;
public class Element { public class Element {
private final String name; private final String name;
@ -154,7 +152,7 @@ public class Element {
} }
public Element setAttribute(final String name, final Jid value) { public Element setAttribute(final String name, final Jid value) {
return this.setAttribute(name, value == null ? null : value.toEscapedString()); return this.setAttribute(name, value == null ? null : value.toString());
} }
public void removeAttribute(final String name) { public void removeAttribute(final String name) {
@ -187,16 +185,12 @@ public class Element {
return Optional.fromNullable(Ints.tryParse(value)); return Optional.fromNullable(Ints.tryParse(value));
} }
public Jid getAttributeAsJid(String name) { public Jid getAttributeAsJid(final String name) {
final String jid = this.getAttribute(name); final String jid = this.getAttribute(name);
if (Strings.isNullOrEmpty(jid)) { if (Strings.isNullOrEmpty(jid)) {
return null; return null;
} }
try { return JidCreate.fromOrThrowUnchecked(jid);
return Jid.ofEscaped(jid);
} catch (final IllegalArgumentException e) {
return InvalidJid.of(jid, this instanceof Message);
}
} }
public Hashtable<String, String> getAttributes() { public Hashtable<String, String> getAttributes() {

View file

@ -1,10 +1,10 @@
package im.conversations.android.xml; package im.conversations.android.xml;
import eu.siacs.conversations.xmpp.Jid;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jxmpp.jid.Jid;
public class Tag { public class Tag {
public static final int NO = -1; public static final int NO = -1;
@ -52,7 +52,7 @@ public class Tag {
public Tag setAttribute(final String attrName, final Jid attrValue) { public Tag setAttribute(final String attrName, final Jid attrValue) {
if (attrValue != null) { if (attrValue != null) {
this.attributes.put(attrName, attrValue.toEscapedString()); this.attributes.put(attrName, attrValue.toString());
} }
return this; return this;
} }

View file

@ -12,9 +12,7 @@ import com.google.common.primitives.Ints;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import eu.siacs.conversations.Config; import eu.siacs.conversations.Config;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.PhoneHelper; import eu.siacs.conversations.utils.PhoneHelper;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.Conversations; import im.conversations.android.Conversations;
import im.conversations.android.database.ConversationsDatabase; import im.conversations.android.database.ConversationsDatabase;
import im.conversations.android.database.model.Account; import im.conversations.android.database.model.Account;
@ -26,6 +24,8 @@ import java.util.concurrent.Executor;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.Jid;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -66,7 +66,7 @@ public class ConnectionPool {
return setupXmppConnection(context, account); return setupXmppConnection(context, account);
} }
public synchronized ListenableFuture<XmppConnection> get(final Jid address) { public synchronized ListenableFuture<XmppConnection> get(final BareJid address) {
final var configured = final var configured =
Iterables.tryFind(this.connections, c -> address.equals(c.getAccount().address)); Iterables.tryFind(this.connections, c -> address.equals(c.getAccount().address));
if (configured.isPresent()) { if (configured.isPresent()) {
@ -78,8 +78,7 @@ public class ConnectionPool {
if (account == null) { if (account == null) {
throw new IllegalStateException( throw new IllegalStateException(
String.format( String.format(
"No enabled account with address %s", "No enabled account with address %s", address.toString()));
address.toEscapedString()));
} }
return reconfigure(account); return reconfigure(account);
}, },
@ -231,9 +230,8 @@ public class ConnectionPool {
final String androidId = PhoneHelper.getAndroidId(context); final String androidId = PhoneHelper.getAndroidId(context);
for (final XmppConnection xmppConnection : this.connections) { for (final XmppConnection xmppConnection : this.connections) {
final Account account = xmppConnection.getAccount(); final Account account = xmppConnection.getAccount();
final boolean pushWasMeantForThisAccount = // TODO fix me if we bring back FCM push support
CryptoHelper.getFingerprint(account.address, androidId) final boolean pushWasMeantForThisAccount = false;
.equals(pushedAccountHash);
if (processAccountState(xmppConnection, pushWasMeantForThisAccount, pingCandidates)) { if (processAccountState(xmppConnection, pushWasMeantForThisAccount, pingCandidates)) {
pingNow++; pingNow++;
} }

View file

@ -1,6 +1,6 @@
package im.conversations.android.xmpp; package im.conversations.android.xmpp;
import eu.siacs.conversations.xmpp.Jid; import org.jxmpp.jid.Jid;
public abstract class Entity { public abstract class Entity {

View file

@ -30,9 +30,6 @@ import eu.siacs.conversations.utils.PhoneHelper;
import eu.siacs.conversations.utils.Resolver; import eu.siacs.conversations.utils.Resolver;
import eu.siacs.conversations.utils.SSLSockets; import eu.siacs.conversations.utils.SSLSockets;
import eu.siacs.conversations.utils.SocksSocketFactory; import eu.siacs.conversations.utils.SocksSocketFactory;
import eu.siacs.conversations.xml.LocalizedContent;
import eu.siacs.conversations.xmpp.InvalidJid;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.bind.Bind2; import eu.siacs.conversations.xmpp.bind.Bind2;
import im.conversations.android.Conversations; import im.conversations.android.Conversations;
import im.conversations.android.IDs; import im.conversations.android.IDs;
@ -91,6 +88,7 @@ import java.util.Collections;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
@ -107,6 +105,9 @@ import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509KeyManager; import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager; import javax.net.ssl.X509TrustManager;
import okhttp3.HttpUrl; import okhttp3.HttpUrl;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
@ -293,7 +294,7 @@ public class XmppConnection implements Runnable {
final int port; final int port;
final boolean directTls; final boolean directTls;
if (connection == null || account.isOnion()) { if (connection == null || account.isOnion()) {
destination = account.address.getDomain().toEscapedString(); destination = account.address.getDomain().toString();
port = 5222; port = 5222;
directTls = false; directTls = false;
} else { } else {
@ -328,7 +329,7 @@ public class XmppConnection implements Runnable {
throw new IOException("Could not start stream", e); throw new IOException("Could not start stream", e);
} }
} else { } else {
final String domain = account.address.getDomain().toEscapedString(); final String domain = account.address.getDomain().toString();
final List<Resolver.Result> results; final List<Resolver.Result> results;
if (connection != null) { if (connection != null) {
results = Resolver.fromHardCoded(connection.hostname, connection.port); results = Resolver.fromHardCoded(connection.hostname, connection.port);
@ -497,7 +498,7 @@ public class XmppConnection implements Runnable {
final boolean quickStart; final boolean quickStart;
if (socket instanceof SSLSocket) { if (socket instanceof SSLSocket) {
final SSLSocket sslSocket = (SSLSocket) socket; final SSLSocket sslSocket = (SSLSocket) socket;
SSLSockets.log(account.address, sslSocket); logTlsCipher(sslSocket);
quickStart = establishStream(SSLSockets.version(sslSocket)); quickStart = establishStream(SSLSockets.version(sslSocket));
} else { } else {
quickStart = establishStream(SSLSockets.Version.NONE); quickStart = establishStream(SSLSockets.Version.NONE);
@ -524,7 +525,7 @@ public class XmppConnection implements Runnable {
} else { } else {
keyManager = new KeyManager[] {new MyKeyManager(context, credential)}; keyManager = new KeyManager[] {new MyKeyManager(context, credential)};
} }
final String domain = account.address.getDomain().toEscapedString(); final String domain = account.address.getDomain().toString();
// TODO we used to use two different trust managers; interactive and non interactive (to // TODO we used to use two different trust managers; interactive and non interactive (to
// trigger SSL cert prompts) // trigger SSL cert prompts)
// we need a better solution for this using live data or similar // we need a better solution for this using live data or similar
@ -719,8 +720,8 @@ public class XmppConnection implements Runnable {
authorizationJid = authorizationJid =
Strings.isNullOrEmpty(authorizationIdentifier) Strings.isNullOrEmpty(authorizationIdentifier)
? null ? null
: Jid.ofEscaped(authorizationIdentifier); : JidCreate.from(authorizationIdentifier);
} catch (final IllegalArgumentException e) { } catch (final XmppStringprepException e) {
Log.d( Log.d(
Config.LOGTAG, Config.LOGTAG,
account.address account.address
@ -993,7 +994,9 @@ public class XmppConnection implements Runnable {
private void changeStatusToOnline() { private void changeStatusToOnline() {
Log.d( Log.d(
Config.LOGTAG, Config.LOGTAG,
account.address + ": online with resource " + connectionAddress.getResource()); account.address
+ ": online with resource "
+ connectionAddress.getResourceOrNull());
changeStatus(ConnectionState.ONLINE); changeStatus(ConnectionState.ONLINE);
} }
@ -1058,7 +1061,7 @@ public class XmppConnection implements Runnable {
final S stanza = tagReader.readElement(currentTag, clazz); final S stanza = tagReader.readElement(currentTag, clazz);
if (stanzasReceived == Integer.MAX_VALUE) { if (stanzasReceived == Integer.MAX_VALUE) {
resetStreamId(); resetStreamId();
throw new IOException("time to restart the session. cant handle >2 billion pcks"); throw new IOException("time to restart the session. cant handle >2 billion stanzas");
} }
if (inSmacksSession) { if (inSmacksSession) {
++stanzasReceived; ++stanzasReceived;
@ -1071,25 +1074,12 @@ public class XmppConnection implements Runnable {
+ "). Not in smacks session."); + "). Not in smacks session.");
} }
lastPacketReceived = SystemClock.elapsedRealtime(); lastPacketReceived = SystemClock.elapsedRealtime();
if (InvalidJid.invalid(stanza.getTo()) || InvalidJid.invalid(stanza.getFrom())) { // TODO validate to and from
Log.e(
Config.LOGTAG,
"encountered invalid stanza from "
+ stanza.getFrom()
+ " to "
+ stanza.getTo());
}
return stanza; return stanza;
} }
private void processIq(final Tag currentTag) throws IOException { private void processIq(final Tag currentTag) throws IOException {
final Iq packet = processStanza(currentTag, Iq.class); final Iq packet = processStanza(currentTag, Iq.class);
if (InvalidJid.invalid(packet.getTo()) || InvalidJid.invalid(packet.getFrom())) {
Log.e(
Config.LOGTAG,
"encountered invalid IQ from " + packet.getFrom() + " to " + packet.getTo());
return;
}
final Consumer<Iq> callback; final Consumer<Iq> callback;
synchronized (this.packetCallbacks) { synchronized (this.packetCallbacks) {
final Pair<Iq, Consumer<Iq>> packetCallbackDuple = packetCallbacks.get(packet.getId()); final Pair<Iq, Consumer<Iq>> packetCallbackDuple = packetCallbacks.get(packet.getId());
@ -1130,29 +1120,11 @@ public class XmppConnection implements Runnable {
private void processMessage(final Tag currentTag) throws IOException { private void processMessage(final Tag currentTag) throws IOException {
final var message = processStanza(currentTag, Message.class); final var message = processStanza(currentTag, Message.class);
if (InvalidJid.invalid(message.getTo()) || InvalidJid.invalid(message.getFrom())) {
Log.e(
Config.LOGTAG,
"encountered invalid Message from "
+ message.getFrom()
+ " to "
+ message.getTo());
return;
}
this.messagePacketConsumer.accept(message); this.messagePacketConsumer.accept(message);
} }
private void processPresence(final Tag currentTag) throws IOException { private void processPresence(final Tag currentTag) throws IOException {
final var presence = processStanza(currentTag, Presence.class); final var presence = processStanza(currentTag, Presence.class);
if (InvalidJid.invalid(presence.getTo()) || InvalidJid.invalid(presence.getFrom())) {
Log.e(
Config.LOGTAG,
"encountered invalid Presence from "
+ presence.getFrom()
+ " to "
+ presence.getTo());
return;
}
this.presencePacketConsumer.accept(presence); this.presencePacketConsumer.accept(presence);
} }
@ -1181,7 +1153,7 @@ public class XmppConnection implements Runnable {
this.encryptionEnabled = true; this.encryptionEnabled = true;
final Tag tag = tagReader.readTag(); final Tag tag = tagReader.readTag();
if (tag != null && tag.isStart("stream", Namespace.STREAMS)) { if (tag != null && tag.isStart("stream", Namespace.STREAMS)) {
SSLSockets.log(account.address, sslSocket); logTlsCipher(sslSocket);
processStream(); processStream();
} else { } else {
throw new StateChangingException(ConnectionState.STREAM_OPENING_ERROR); throw new StateChangingException(ConnectionState.STREAM_OPENING_ERROR);
@ -1189,6 +1161,14 @@ public class XmppConnection implements Runnable {
sslSocket.close(); sslSocket.close();
} }
private void logTlsCipher(final SSLSocket sslSocket) {
final var session = sslSocket.getSession();
LOGGER.info(
"TLS session protocol {} cipher {}",
session.getProtocol(),
session.getCipherSuite());
}
private SSLSocket upgradeSocketToTls(final Socket socket) throws IOException { private SSLSocket upgradeSocketToTls(final Socket socket) throws IOException {
final SSLSocketFactory sslSocketFactory; final SSLSocketFactory sslSocketFactory;
try { try {
@ -1202,13 +1182,12 @@ public class XmppConnection implements Runnable {
sslSocketFactory.createSocket( sslSocketFactory.createSocket(
socket, address.getHostAddress(), socket.getPort(), true); socket, address.getHostAddress(), socket.getPort(), true);
SSLSockets.setSecurity(sslSocket); SSLSockets.setSecurity(sslSocket);
SSLSockets.setHostname( SSLSockets.setHostname(sslSocket, IDN.toASCII(account.address.getDomain().toString()));
sslSocket, IDN.toASCII(account.address.getDomain().toEscapedString()));
SSLSockets.setApplicationProtocol(sslSocket, "xmpp-client"); SSLSockets.setApplicationProtocol(sslSocket, "xmpp-client");
final XmppDomainVerifier xmppDomainVerifier = new XmppDomainVerifier(); final XmppDomainVerifier xmppDomainVerifier = new XmppDomainVerifier();
try { try {
if (!xmppDomainVerifier.verify( if (!xmppDomainVerifier.verify(
account.address.getDomain().toEscapedString(), account.address.getDomain().toString(),
this.verifiedHostname, this.verifiedHostname,
sslSocket.getSession())) { sslSocket.getSession())) {
Log.d( Log.d(
@ -1536,8 +1515,8 @@ public class XmppConnection implements Runnable {
} }
final Jid assignedJid; final Jid assignedJid;
try { try {
assignedJid = Jid.ofEscaped(jid); assignedJid = JidCreate.from(jid);
} catch (final IllegalArgumentException e) { } catch (final XmppStringprepException e) {
Log.d( Log.d(
Config.LOGTAG, Config.LOGTAG,
account.address account.address
@ -1675,7 +1654,7 @@ public class XmppConnection implements Runnable {
final var discoManager = getManager(DiscoManager.class); final var discoManager = getManager(DiscoManager.class);
final var nodeHash = this.streamFeatures.getCapabilities(); final var nodeHash = this.streamFeatures.getCapabilities();
final var domainDiscoItem = Entity.discoItem(account.address.getDomain()); final var domainDiscoItem = Entity.discoItem(account.address.asDomainBareJid());
if (nodeHash != null) { if (nodeHash != null) {
discoFutures.add( discoFutures.add(
discoManager.infoOrCache(domainDiscoItem, nodeHash.node, nodeHash.hash)); discoManager.infoOrCache(domainDiscoItem, nodeHash.node, nodeHash.hash));
@ -1819,12 +1798,13 @@ public class XmppConnection implements Runnable {
private void sendStartStream(final boolean from, final boolean flush) throws IOException { private void sendStartStream(final boolean from, final boolean flush) throws IOException {
final Tag stream = Tag.start("stream:stream"); final Tag stream = Tag.start("stream:stream");
stream.setAttribute("to", account.address.getDomain()); stream.setAttribute("to", account.address.asDomainBareJid());
if (from) { if (from) {
stream.setAttribute("from", account.address); stream.setAttribute("from", account.address);
} }
stream.setAttribute("version", "1.0"); stream.setAttribute("version", "1.0");
stream.setAttribute("xml:lang", LocalizedContent.STREAM_LANGUAGE); // TODO use 'en' when privacy mode is enabled
stream.setAttribute("xml:lang", Locale.getDefault().getLanguage());
stream.setAttribute("xmlns", "jabber:client"); stream.setAttribute("xmlns", "jabber:client");
stream.setAttribute("xmlns:stream", Namespace.STREAMS); stream.setAttribute("xmlns:stream", Namespace.STREAMS);
tagWriter.writeTag(stream, flush); tagWriter.writeTag(stream, flush);

View file

@ -1,20 +1,18 @@
package im.conversations.android.xmpp.axolotl; package im.conversations.android.xmpp.axolotl;
import com.google.common.base.Preconditions; import org.jxmpp.jid.BareJid;
import eu.siacs.conversations.xmpp.Jid;
import org.whispersystems.libsignal.SignalProtocolAddress; import org.whispersystems.libsignal.SignalProtocolAddress;
public class AxolotlAddress extends SignalProtocolAddress { public class AxolotlAddress extends SignalProtocolAddress {
private final Jid jid; private final BareJid jid;
public AxolotlAddress(final Jid jid, int deviceId) { public AxolotlAddress(final BareJid jid, int deviceId) {
super(jid.toEscapedString(), deviceId); super(jid.toString(), deviceId);
Preconditions.checkArgument(jid.isBareJid(), "AxolotlAddresses must use bare JIDs");
this.jid = jid; this.jid = jid;
} }
public Jid getJid() { public BareJid getJid() {
return this.jid; return this.jid;
} }

View file

@ -9,7 +9,6 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.SettableFuture;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xmpp.XmppConnection; import im.conversations.android.xmpp.XmppConnection;
import im.conversations.android.xmpp.model.avatar.Data; import im.conversations.android.xmpp.model.avatar.Data;
import im.conversations.android.xmpp.model.avatar.Info; import im.conversations.android.xmpp.model.avatar.Info;
@ -21,6 +20,8 @@ import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.Jid;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -34,7 +35,7 @@ public class AvatarManager extends AbstractManager {
super(context, connection); super(context, connection);
} }
public void handleItems(final Jid from, final Items items) { public void handleItems(final BareJid from, final Items items) {
final var itemsMap = items.getItemMap(Metadata.class); final var itemsMap = items.getItemMap(Metadata.class);
final var firstEntry = Iterables.getFirst(itemsMap.entrySet(), null); final var firstEntry = Iterables.getFirst(itemsMap.entrySet(), null);
if (firstEntry == null) { if (firstEntry == null) {
@ -142,7 +143,7 @@ public class AvatarManager extends AbstractManager {
new File( new File(
accountCacheDirectory, accountCacheDirectory,
Hashing.sha256() Hashing.sha256()
.hashString(address.toEscapedString(), StandardCharsets.UTF_8) .hashString(address.toString(), StandardCharsets.UTF_8)
.toString()); .toString());
if (userCacheDirectory.mkdirs()) { if (userCacheDirectory.mkdirs()) {
LOGGER.debug("Created directory {}", userCacheDirectory.getAbsolutePath()); LOGGER.debug("Created directory {}", userCacheDirectory.getAbsolutePath());

View file

@ -7,7 +7,6 @@ import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.AxolotlDatabaseStore; import im.conversations.android.database.AxolotlDatabaseStore;
import im.conversations.android.xml.Namespace; import im.conversations.android.xml.Namespace;
import im.conversations.android.xmpp.IqErrorException; import im.conversations.android.xmpp.IqErrorException;
@ -22,6 +21,8 @@ import java.util.Collections;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.Jid;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.libsignal.IdentityKey; import org.whispersystems.libsignal.IdentityKey;
@ -47,7 +48,7 @@ public class AxolotlManager extends AbstractManager {
this.signalProtocolStore = new AxolotlDatabaseStore(context, connection.getAccount()); this.signalProtocolStore = new AxolotlDatabaseStore(context, connection.getAccount());
} }
public void handleItems(final Jid from, final Items items) { public void handleItems(final BareJid from, final Items items) {
final var deviceList = items.getFirstItem(DeviceList.class); final var deviceList = items.getFirstItem(DeviceList.class);
if (from == null || deviceList == null) { if (from == null || deviceList == null) {
return; return;
@ -57,7 +58,7 @@ public class AxolotlManager extends AbstractManager {
getDatabase().axolotlDao().setDeviceList(getAccount(), from, deviceIds); getDatabase().axolotlDao().setDeviceList(getAccount(), from, deviceIds);
} }
public ListenableFuture<Set<Integer>> fetchDeviceIds(final Jid address) { public ListenableFuture<Set<Integer>> fetchDeviceIds(final BareJid address) {
final var deviceIdsFuture = final var deviceIdsFuture =
Futures.transform( Futures.transform(
getManager(PubSubManager.class) getManager(PubSubManager.class)

View file

@ -7,8 +7,6 @@ import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.database.entity.BookmarkEntity;
import im.conversations.android.xml.Namespace; import im.conversations.android.xml.Namespace;
import im.conversations.android.xmpp.NodeConfiguration; import im.conversations.android.xmpp.NodeConfiguration;
import im.conversations.android.xmpp.XmppConnection; import im.conversations.android.xmpp.XmppConnection;
@ -18,6 +16,8 @@ import im.conversations.android.xmpp.model.pubsub.event.Retract;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.impl.JidCreate;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -53,7 +53,7 @@ public class BookmarkManager extends AbstractManager {
private void deleteItems(Collection<Retract> retractions) { private void deleteItems(Collection<Retract> retractions) {
final Collection<Jid> addresses = final Collection<Jid> addresses =
Collections2.transform(retractions, r -> BookmarkEntity.jidOrNull(r.getId())); Collections2.transform(retractions, r -> JidCreate.fromOrNull(r.getId()));
getDatabase() getDatabase()
.bookmarkDao() .bookmarkDao()
.delete(getAccount().id, Collections2.filter(addresses, Objects::nonNull)); .delete(getAccount().id, Collections2.filter(addresses, Objects::nonNull));
@ -75,7 +75,7 @@ public class BookmarkManager extends AbstractManager {
} }
public ListenableFuture<Void> publishBookmark(final Jid address) { public ListenableFuture<Void> publishBookmark(final Jid address) {
final var itemId = address.toEscapedString(); final var itemId = address.toString();
final var conference = new Conference(); final var conference = new Conference();
return Futures.transform( return Futures.transform(
getManager(PepManager.class) getManager(PepManager.class)
@ -85,7 +85,7 @@ public class BookmarkManager extends AbstractManager {
} }
public ListenableFuture<Void> retractBookmark(final Jid address) { public ListenableFuture<Void> retractBookmark(final Jid address) {
final var itemId = address.toEscapedString(); final var itemId = address.toString();
return Futures.transform( return Futures.transform(
getManager(PepManager.class).retract(itemId, Namespace.BOOKMARKS2), getManager(PepManager.class).retract(itemId, Namespace.BOOKMARKS2),
result -> null, result -> null,

View file

@ -1,9 +1,9 @@
package im.conversations.android.xmpp.manager; package im.conversations.android.xmpp.manager;
import android.content.Context; import android.content.Context;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xmpp.XmppConnection; import im.conversations.android.xmpp.XmppConnection;
import im.conversations.android.xmpp.model.state.ChatStateNotification; import im.conversations.android.xmpp.model.state.ChatStateNotification;
import org.jxmpp.jid.Jid;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View file

@ -13,7 +13,6 @@ import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import eu.siacs.conversations.BuildConfig; import eu.siacs.conversations.BuildConfig;
import eu.siacs.conversations.R; import eu.siacs.conversations.R;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xml.Namespace; import im.conversations.android.xml.Namespace;
import im.conversations.android.xmpp.Entity; import im.conversations.android.xmpp.Entity;
import im.conversations.android.xmpp.EntityCapabilities; import im.conversations.android.xmpp.EntityCapabilities;
@ -32,6 +31,7 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import org.jxmpp.jid.Jid;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -249,7 +249,7 @@ public class DiscoManager extends AbstractManager {
} }
public boolean hasServerFeature(final String feature) { public boolean hasServerFeature(final String feature) {
return hasFeature(getAccount().address.getDomain(), feature); return hasFeature(getAccount().address.asDomainBareJid(), feature);
} }
public ServiceDescription getServiceDescription() { public ServiceDescription getServiceDescription() {

View file

@ -2,10 +2,10 @@ package im.conversations.android.xmpp.manager;
import android.content.Context; import android.content.Context;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xmpp.XmppConnection; import im.conversations.android.xmpp.XmppConnection;
import im.conversations.android.xmpp.model.nick.Nick; import im.conversations.android.xmpp.model.nick.Nick;
import im.conversations.android.xmpp.model.pubsub.Items; import im.conversations.android.xmpp.model.pubsub.Items;
import org.jxmpp.jid.BareJid;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -17,7 +17,7 @@ public class NickManager extends AbstractManager {
super(context, connection); super(context, connection);
} }
public void handleItems(final Jid from, Items items) { public void handleItems(final BareJid from, Items items) {
final var item = items.getFirstItem(Nick.class); final var item = items.getFirstItem(Nick.class);
final var nick = item == null ? null : item.getContent(); final var nick = item == null ? null : item.getContent();
if (from == null || Strings.isNullOrEmpty(nick)) { if (from == null || Strings.isNullOrEmpty(nick)) {

View file

@ -2,12 +2,12 @@ package im.conversations.android.xmpp.manager;
import android.content.Context; import android.content.Context;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xmpp.NodeConfiguration; import im.conversations.android.xmpp.NodeConfiguration;
import im.conversations.android.xmpp.XmppConnection; import im.conversations.android.xmpp.XmppConnection;
import im.conversations.android.xmpp.model.Extension; import im.conversations.android.xmpp.model.Extension;
import im.conversations.android.xmpp.model.stanza.Iq; import im.conversations.android.xmpp.model.stanza.Iq;
import java.util.Map; import java.util.Map;
import org.jxmpp.jid.Jid;
public class PepManager extends AbstractManager { public class PepManager extends AbstractManager {

View file

@ -6,7 +6,6 @@ import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xml.Namespace; import im.conversations.android.xml.Namespace;
import im.conversations.android.xmpp.ExtensionFactory; import im.conversations.android.xmpp.ExtensionFactory;
import im.conversations.android.xmpp.IqErrorException; import im.conversations.android.xmpp.IqErrorException;
@ -29,6 +28,7 @@ import im.conversations.android.xmpp.model.pubsub.owner.PubSubOwner;
import im.conversations.android.xmpp.model.stanza.Iq; import im.conversations.android.xmpp.model.stanza.Iq;
import im.conversations.android.xmpp.model.stanza.Message; import im.conversations.android.xmpp.model.stanza.Message;
import java.util.Map; import java.util.Map;
import org.jxmpp.jid.Jid;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -147,6 +147,7 @@ public class PubSubManager extends AbstractManager {
private void handleItems(final Message message) { private void handleItems(final Message message) {
final var from = message.getFrom(); final var from = message.getFrom();
final var bareFrom = from == null ? null : from.asBareJid();
final var event = message.getExtension(Event.class); final var event = message.getExtension(Event.class);
final Items items = event.getItems(); final Items items = event.getItems();
final var node = items.getNode(); final var node = items.getNode();
@ -155,15 +156,15 @@ public class PubSubManager extends AbstractManager {
return; return;
} }
if (Namespace.AVATAR_METADATA.equals(node)) { if (Namespace.AVATAR_METADATA.equals(node)) {
getManager(AvatarManager.class).handleItems(from, items); getManager(AvatarManager.class).handleItems(bareFrom, items);
return; return;
} }
if (Namespace.NICK.equals(node)) { if (Namespace.NICK.equals(node)) {
getManager(NickManager.class).handleItems(from, items); getManager(NickManager.class).handleItems(bareFrom, items);
return; return;
} }
if (Namespace.AXOLOTL_DEVICE_LIST.equals(node)) { if (Namespace.AXOLOTL_DEVICE_LIST.equals(node)) {
getManager(AxolotlManager.class).handleItems(from, items); getManager(AxolotlManager.class).handleItems(bareFrom, items);
} }
} }

View file

@ -2,7 +2,6 @@ package im.conversations.android.xmpp.manager;
import android.content.Context; import android.content.Context;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xmpp.XmppConnection; import im.conversations.android.xmpp.XmppConnection;
import im.conversations.android.xmpp.model.DeliveryReceiptRequest; import im.conversations.android.xmpp.model.DeliveryReceiptRequest;
import im.conversations.android.xmpp.model.markers.Markable; import im.conversations.android.xmpp.model.markers.Markable;
@ -10,6 +9,7 @@ import im.conversations.android.xmpp.model.receipts.Received;
import im.conversations.android.xmpp.model.receipts.Request; import im.conversations.android.xmpp.model.receipts.Request;
import im.conversations.android.xmpp.model.stanza.Message; import im.conversations.android.xmpp.model.stanza.Message;
import java.util.Collection; import java.util.Collection;
import org.jxmpp.jid.Jid;
public class ReceiptManager extends AbstractManager { public class ReceiptManager extends AbstractManager {

View file

@ -34,9 +34,9 @@ public class RegistrationManager extends AbstractManager {
public ListenableFuture<Void> setPassword(final String password) { public ListenableFuture<Void> setPassword(final String password) {
final var account = getAccount(); final var account = getAccount();
final var iq = new Iq(Iq.Type.SET); final var iq = new Iq(Iq.Type.SET);
iq.setTo(account.address.getDomain()); iq.setTo(account.address.asDomainBareJid());
final var register = iq.addExtension(new Register()); final var register = iq.addExtension(new Register());
register.addUsername(account.address.getEscapedLocal()); register.addUsername(account.address.getLocalpartOrThrow());
register.addPassword(password); register.addPassword(password);
return Futures.transform( return Futures.transform(
connection.sendIqPacket(iq), r -> null, MoreExecutors.directExecutor()); connection.sendIqPacket(iq), r -> null, MoreExecutors.directExecutor());
@ -44,7 +44,7 @@ public class RegistrationManager extends AbstractManager {
public ListenableFuture<Void> unregister() { public ListenableFuture<Void> unregister() {
final var iq = new Iq(Iq.Type.SET); final var iq = new Iq(Iq.Type.SET);
iq.setTo(getAccount().address.getDomain()); iq.setTo(getAccount().address.asDomainBareJid());
final var register = iq.addExtension(new Register()); final var register = iq.addExtension(new Register());
register.addExtension(new Remove()); register.addExtension(new Remove());
return Futures.transform( return Futures.transform(
@ -53,7 +53,7 @@ public class RegistrationManager extends AbstractManager {
public ListenableFuture<Registration> getRegistration() { public ListenableFuture<Registration> getRegistration() {
final var iq = new Iq(Iq.Type.GET); final var iq = new Iq(Iq.Type.GET);
iq.setTo(getAccount().address.getDomain()); iq.setTo(getAccount().address.asDomainBareJid());
iq.addExtension(new Register()); iq.addExtension(new Register());
return Futures.transform( return Futures.transform(
connection.sendIqPacketUnbound(iq), connection.sendIqPacketUnbound(iq),
@ -98,7 +98,7 @@ public class RegistrationManager extends AbstractManager {
public ListenableFuture<Void> sendPreAuthentication(final String token) { public ListenableFuture<Void> sendPreAuthentication(final String token) {
final var iq = new Iq(Iq.Type.GET); final var iq = new Iq(Iq.Type.GET);
iq.setTo(getAccount().address.getDomain()); iq.setTo(getAccount().address.asDomainBareJid());
final var preAuthentication = iq.addExtension(new PreAuth()); final var preAuthentication = iq.addExtension(new PreAuth());
preAuthentication.setToken(token); preAuthentication.setToken(token);
return Futures.transform( return Futures.transform(

View file

@ -1,11 +1,11 @@
package im.conversations.android.xmpp.manager; package im.conversations.android.xmpp.manager;
import android.content.Context; import android.content.Context;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xml.Namespace; import im.conversations.android.xml.Namespace;
import im.conversations.android.xmpp.XmppConnection; import im.conversations.android.xmpp.XmppConnection;
import im.conversations.android.xmpp.model.stanza.Message; import im.conversations.android.xmpp.model.stanza.Message;
import im.conversations.android.xmpp.model.unique.StanzaId; import im.conversations.android.xmpp.model.unique.StanzaId;
import org.jxmpp.jid.Jid;
public class StanzaIdManager extends AbstractManager { public class StanzaIdManager extends AbstractManager {

View file

@ -1,8 +1,8 @@
package im.conversations.android.xmpp.model.blocking; package im.conversations.android.xmpp.model.blocking;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.annotation.XmlElement; import im.conversations.android.annotation.XmlElement;
import im.conversations.android.xmpp.model.Extension; import im.conversations.android.xmpp.model.Extension;
import org.jxmpp.jid.Jid;
@XmlElement @XmlElement
public class Item extends Extension { public class Item extends Extension {

View file

@ -1,9 +1,9 @@
package im.conversations.android.xmpp.model.disco.items; package im.conversations.android.xmpp.model.disco.items;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.annotation.XmlElement; import im.conversations.android.annotation.XmlElement;
import im.conversations.android.xmpp.model.Extension; import im.conversations.android.xmpp.model.Extension;
import org.jxmpp.jid.Jid;
@XmlElement @XmlElement
public class Item extends Extension { public class Item extends Extension {

View file

@ -2,6 +2,7 @@ package im.conversations.android.xmpp.model.register;
import im.conversations.android.annotation.XmlElement; import im.conversations.android.annotation.XmlElement;
import im.conversations.android.xmpp.model.Extension; import im.conversations.android.xmpp.model.Extension;
import org.jxmpp.jid.parts.Localpart;
@XmlElement(name = "query") @XmlElement(name = "query")
public class Register extends Extension { public class Register extends Extension {
@ -10,8 +11,8 @@ public class Register extends Extension {
super(Register.class); super(Register.class);
} }
public void addUsername(final String username) { public void addUsername(final Localpart username) {
this.addExtension(new Username()).setContent(username); this.addExtension(new Username()).setContent(username.toString());
} }
public void addPassword(final String password) { public void addPassword(final String password) {

View file

@ -1,9 +1,9 @@
package im.conversations.android.xmpp.model.reply; package im.conversations.android.xmpp.model.reply;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.annotation.XmlElement; import im.conversations.android.annotation.XmlElement;
import im.conversations.android.xml.Namespace; import im.conversations.android.xml.Namespace;
import im.conversations.android.xmpp.model.Extension; import im.conversations.android.xmpp.model.Extension;
import org.jxmpp.jid.Jid;
@XmlElement(namespace = Namespace.REPLY) @XmlElement(namespace = Namespace.REPLY)
public class Reply extends Extension { public class Reply extends Extension {

View file

@ -1,7 +1,6 @@
package im.conversations.android.xmpp.model.roster; package im.conversations.android.xmpp.model.roster;
import com.google.common.collect.Collections2; import com.google.common.collect.Collections2;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.annotation.XmlElement; import im.conversations.android.annotation.XmlElement;
import im.conversations.android.xml.Element; import im.conversations.android.xml.Element;
import im.conversations.android.xmpp.model.Extension; import im.conversations.android.xmpp.model.Extension;
@ -10,6 +9,7 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import org.jxmpp.jid.Jid;
@XmlElement @XmlElement
public class Item extends Extension { public class Item extends Extension {

View file

@ -1,9 +1,9 @@
package im.conversations.android.xmpp.model.stanza; package im.conversations.android.xmpp.model.stanza;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xmpp.model.Extension; import im.conversations.android.xmpp.model.Extension;
import im.conversations.android.xmpp.model.StreamElement; import im.conversations.android.xmpp.model.StreamElement;
import im.conversations.android.xmpp.model.error.Error; import im.conversations.android.xmpp.model.error.Error;
import org.jxmpp.jid.Jid;
public abstract class Stanza extends StreamElement { public abstract class Stanza extends StreamElement {

View file

@ -1,8 +1,8 @@
package im.conversations.android.xmpp.model.unique; package im.conversations.android.xmpp.model.unique;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.annotation.XmlElement; import im.conversations.android.annotation.XmlElement;
import im.conversations.android.xmpp.model.Extension; import im.conversations.android.xmpp.model.Extension;
import org.jxmpp.jid.Jid;
@XmlElement @XmlElement
public class StanzaId extends Extension { public class StanzaId extends Extension {

View file

@ -1,7 +1,6 @@
package im.conversations.android.xmpp.processor; package im.conversations.android.xmpp.processor;
import android.content.Context; import android.content.Context;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xml.Namespace; import im.conversations.android.xml.Namespace;
import im.conversations.android.xmpp.Entity; import im.conversations.android.xmpp.Entity;
import im.conversations.android.xmpp.XmppConnection; import im.conversations.android.xmpp.XmppConnection;
@ -12,6 +11,7 @@ import im.conversations.android.xmpp.manager.DiscoManager;
import im.conversations.android.xmpp.manager.PresenceManager; import im.conversations.android.xmpp.manager.PresenceManager;
import im.conversations.android.xmpp.manager.RosterManager; import im.conversations.android.xmpp.manager.RosterManager;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.jxmpp.jid.Jid;
public class BindProcessor extends XmppConnection.Delegate implements Consumer<Jid> { public class BindProcessor extends XmppConnection.Delegate implements Consumer<Jid> {
@ -35,7 +35,8 @@ public class BindProcessor extends XmppConnection.Delegate implements Consumer<J
} }
if (discoManager.hasServerFeature(Namespace.COMMANDS)) { if (discoManager.hasServerFeature(Namespace.COMMANDS)) {
discoManager.items(Entity.discoItem(account.address.getDomain()), Namespace.COMMANDS); discoManager.items(
Entity.discoItem(account.address.asDomainBareJid()), Namespace.COMMANDS);
} }
getManager(BookmarkManager.class).fetch(); getManager(BookmarkManager.class).fetch();

View file

@ -1,9 +1,9 @@
package im.conversations.android.xmpp.processor; package im.conversations.android.xmpp.processor;
import android.content.Context; import android.content.Context;
import eu.siacs.conversations.xmpp.Jid;
import im.conversations.android.xmpp.XmppConnection; import im.conversations.android.xmpp.XmppConnection;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import org.jxmpp.jid.Jid;
public class MessageAcknowledgeProcessor extends XmppConnection.Delegate public class MessageAcknowledgeProcessor extends XmppConnection.Delegate
implements BiFunction<Jid, String, Boolean> { implements BiFunction<Jid, String, Boolean> {

View file

@ -19,7 +19,7 @@ public class PresenceProcessor extends XmppConnection.Delegate implements Consum
public void accept(final Presence presencePacket) { public void accept(final Presence presencePacket) {
final var from = presencePacket.getFrom(); final var from = presencePacket.getFrom();
final var address = from == null ? null : from.asBareJid(); final var address = from == null ? null : from.asBareJid();
final var resource = from == null ? null : from.getResource(); final var resource = from == null ? null : from.getResourceOrEmpty();
final var typeAttribute = presencePacket.getAttribute("type"); final var typeAttribute = presencePacket.getAttribute("type");
final PresenceType type; final PresenceType type;
try { try {

View file

@ -51,7 +51,7 @@ public class DigestMd5 extends SaslMechanism {
final String digestUri = "xmpp/" + account.address.getDomain(); final String digestUri = "xmpp/" + account.address.getDomain();
final String nonceCount = "00000001"; final String nonceCount = "00000001";
final String x = final String x =
account.address.getEscapedLocal() account.address.getLocalpartOrNull().toString()
+ ":" + ":"
+ account.address.getDomain() + account.address.getDomain()
+ ":" + ":"
@ -60,7 +60,7 @@ public class DigestMd5 extends SaslMechanism {
final byte[] y = md.digest(x.getBytes(Charset.defaultCharset())); final byte[] y = md.digest(x.getBytes(Charset.defaultCharset()));
final String cNonce = CryptoHelper.random(100); final String cNonce = CryptoHelper.random(100);
final byte[] a1 = final byte[] a1 =
CryptoHelper.concatenateByteArrays( concatenate(
y, y,
(":" + nonce + ":" + cNonce) (":" + nonce + ":" + cNonce)
.getBytes(Charset.defaultCharset())); .getBytes(Charset.defaultCharset()));
@ -76,7 +76,7 @@ public class DigestMd5 extends SaslMechanism {
md.digest(kd.getBytes(Charset.defaultCharset()))); md.digest(kd.getBytes(Charset.defaultCharset())));
final String saslString = final String saslString =
"username=\"" "username=\""
+ account.address.getEscapedLocal() + account.address.getLocalpartOrThrow().toString()
+ "\",realm=\"" + "\",realm=\""
+ account.address.getDomain() + account.address.getDomain()
+ "\",nonce=\"" + "\",nonce=\""

View file

@ -25,6 +25,6 @@ public class External extends SaslMechanism {
@Override @Override
public String getClientFirstMessage(final SSLSocket sslSocket) { public String getClientFirstMessage(final SSLSocket sslSocket) {
return Base64.encodeToString(account.address.toEscapedString().getBytes(), Base64.NO_WRAP); return Base64.encodeToString(account.address.toString().getBytes(), Base64.NO_WRAP);
} }
} }

View file

@ -49,9 +49,10 @@ public abstract class HashedToken extends SaslMechanism implements ChannelBindin
final byte[] cbData = getChannelBindingData(sslSocket); final byte[] cbData = getChannelBindingData(sslSocket);
final byte[] initiatorHashedToken = final byte[] initiatorHashedToken =
hashing.hashBytes(Bytes.concat(INITIATOR, cbData)).asBytes(); hashing.hashBytes(Bytes.concat(INITIATOR, cbData)).asBytes();
final String username = account.address.getLocalpartOrThrow().toString();
final byte[] firstMessage = final byte[] firstMessage =
Bytes.concat( Bytes.concat(
account.address.getEscapedLocal().getBytes(StandardCharsets.UTF_8), username.getBytes(StandardCharsets.UTF_8),
new byte[] {0x00}, new byte[] {0x00},
initiatorHashedToken); initiatorHashedToken);
return Base64.encodeToString(firstMessage, Base64.NO_WRAP); return Base64.encodeToString(firstMessage, Base64.NO_WRAP);

View file

@ -33,6 +33,7 @@ public class Plain extends SaslMechanism {
@Override @Override
public String getClientFirstMessage(final SSLSocket sslSocket) { public String getClientFirstMessage(final SSLSocket sslSocket) {
return getMessage( return getMessage(
account.address.getEscapedLocal(), Strings.nullToEmpty(credential.password)); account.address.getLocalpartOrThrow().toString(),
Strings.nullToEmpty(credential.password));
} }
} }

View file

@ -233,4 +233,11 @@ public abstract class SaslMechanism {
public static boolean pin(final SaslMechanism saslMechanism) { public static boolean pin(final SaslMechanism saslMechanism) {
return !hashedToken(saslMechanism); return !hashedToken(saslMechanism);
} }
protected static byte[] concatenate(byte[] a, byte[] b) {
byte[] result = new byte[a.length + b.length];
System.arraycopy(a, 0, result, 0, a.length);
System.arraycopy(b, 0, result, a.length, b.length);
return result;
}
} }

View file

@ -7,11 +7,12 @@ import com.google.common.base.Strings;
import com.google.common.cache.Cache; import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.google.common.hash.HashFunction; import com.google.common.hash.HashFunction;
import eu.siacs.conversations.utils.CryptoHelper; import im.conversations.android.IDs;
import im.conversations.android.database.model.Account; import im.conversations.android.database.model.Account;
import im.conversations.android.database.model.Credential; import im.conversations.android.database.model.Credential;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.text.Normalizer;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocket;
@ -36,6 +37,8 @@ abstract class ScramMechanism extends SaslMechanism {
} }
}; };
private static final byte[] ONE = new byte[] {0, 0, 0, 1};
private static final byte[] CLIENT_KEY_BYTES = "Client Key".getBytes(); private static final byte[] CLIENT_KEY_BYTES = "Client Key".getBytes();
private static final byte[] SERVER_KEY_BYTES = "Server Key".getBytes(); private static final byte[] SERVER_KEY_BYTES = "Server Key".getBytes();
private static final Cache<CacheKey, KeyPair> CACHE = private static final Cache<CacheKey, KeyPair> CACHE =
@ -67,7 +70,7 @@ abstract class ScramMechanism extends SaslMechanism {
.convert(channelBinding.toString())); .convert(channelBinding.toString()));
} }
// This nonce should be different for each authentication attempt. // This nonce should be different for each authentication attempt.
this.clientNonce = CryptoHelper.random(100); this.clientNonce = IDs.huge();
clientFirstMessageBare = ""; clientFirstMessageBare = "";
} }
@ -107,7 +110,7 @@ abstract class ScramMechanism extends SaslMechanism {
*/ */
private byte[] hi(final byte[] key, final byte[] salt, final int iterations) private byte[] hi(final byte[] key, final byte[] salt, final int iterations)
throws InvalidKeyException { throws InvalidKeyException {
byte[] u = hmac(key, CryptoHelper.concatenateByteArrays(salt, CryptoHelper.ONE)); byte[] u = hmac(key, concatenate(salt, ONE));
byte[] out = u.clone(); byte[] out = u.clone();
for (int i = 1; i < iterations; i++) { for (int i = 1; i < iterations; i++) {
u = hmac(key, u); u = hmac(key, u);
@ -123,8 +126,7 @@ abstract class ScramMechanism extends SaslMechanism {
if (clientFirstMessageBare.isEmpty() && state == State.INITIAL) { if (clientFirstMessageBare.isEmpty() && state == State.INITIAL) {
clientFirstMessageBare = clientFirstMessageBare =
"n=" "n="
+ CryptoHelper.saslEscape( + escape(prep(account.address.getLocalpartOrThrow().toString()))
CryptoHelper.saslPrep(account.address.getEscapedLocal()))
+ ",r=" + ",r="
+ this.clientNonce; + this.clientNonce;
state = State.AUTH_TEXT_SENT; state = State.AUTH_TEXT_SENT;
@ -216,7 +218,7 @@ abstract class ScramMechanism extends SaslMechanism {
try { try {
keys = keys =
getKeyPair( getKeyPair(
CryptoHelper.saslPrep(Strings.nullToEmpty(credential.password)), prep(Strings.nullToEmpty(credential.password)),
salt, salt,
iterationCount); iterationCount);
} catch (ExecutionException e) { } catch (ExecutionException e) {
@ -269,6 +271,29 @@ abstract class ScramMechanism extends SaslMechanism {
} }
} }
public static String escape(final String s) {
final StringBuilder sb = new StringBuilder((int) (s.length() * 1.1));
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case ',':
sb.append("=2C");
break;
case '=':
sb.append("=3D");
break;
default:
sb.append(c);
break;
}
}
return sb.toString();
}
public static String prep(final String s) {
return Normalizer.normalize(s, Normalizer.Form.NFKC);
}
protected byte[] getChannelBindingData(final SSLSocket sslSocket) protected byte[] getChannelBindingData(final SSLSocket sslSocket)
throws AuthenticationException { throws AuthenticationException {
if (this.channelBinding == ChannelBinding.NONE) { if (this.channelBinding == ChannelBinding.NONE) {