homogenize ID generation
This commit is contained in:
parent
7ee3e07946
commit
2c32f9738c
|
@ -2,9 +2,12 @@ package im.conversations.android;
|
|||
|
||||
import android.app.Application;
|
||||
import im.conversations.android.xmpp.ConnectionPool;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class Conversations extends Application {
|
||||
|
||||
public static final SecureRandom SECURE_RANDOM = new SecureRandom();
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
|
68
src/main/java/im/conversations/android/IDs.java
Normal file
68
src/main/java/im/conversations/android/IDs.java
Normal file
|
@ -0,0 +1,68 @@
|
|||
package im.conversations.android;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import com.google.common.io.ByteSource;
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
||||
public class IDs {
|
||||
|
||||
private static final long UUID_VERSION_MASK = 4 << 12;
|
||||
|
||||
public static String medium() {
|
||||
final var random = new byte[9];
|
||||
Conversations.SECURE_RANDOM.nextBytes(random);
|
||||
return BaseEncoding.base64Url().encode(random);
|
||||
}
|
||||
|
||||
public static String tiny() {
|
||||
final var random = new byte[3];
|
||||
Conversations.SECURE_RANDOM.nextBytes(random);
|
||||
return BaseEncoding.base64Url().encode(random);
|
||||
}
|
||||
|
||||
public static String tiny(final byte[] seed) {
|
||||
return BaseEncoding.base64Url().encode(slice(seed));
|
||||
}
|
||||
|
||||
private static byte[] slice(final byte[] input) {
|
||||
if (input == null || input.length < 3) {
|
||||
return new byte[3];
|
||||
}
|
||||
try {
|
||||
return ByteSource.wrap(input).slice(0, 3).read();
|
||||
} catch (final IOException e) {
|
||||
return new byte[3];
|
||||
}
|
||||
}
|
||||
|
||||
public static UUID uuid(final byte[] bytes) {
|
||||
Preconditions.checkArgument(bytes != null && bytes.length == 32);
|
||||
|
||||
long msb = 0;
|
||||
long lsb = 0;
|
||||
|
||||
msb |= (bytes[0x0] & 0xffL) << 56;
|
||||
msb |= (bytes[0x1] & 0xffL) << 48;
|
||||
msb |= (bytes[0x2] & 0xffL) << 40;
|
||||
msb |= (bytes[0x3] & 0xffL) << 32;
|
||||
msb |= (bytes[0x4] & 0xffL) << 24;
|
||||
msb |= (bytes[0x5] & 0xffL) << 16;
|
||||
msb |= (bytes[0x6] & 0xffL) << 8;
|
||||
msb |= (bytes[0x7] & 0xffL);
|
||||
|
||||
lsb |= (bytes[0x8] & 0xffL) << 56;
|
||||
lsb |= (bytes[0x9] & 0xffL) << 48;
|
||||
lsb |= (bytes[0xa] & 0xffL) << 40;
|
||||
lsb |= (bytes[0xb] & 0xffL) << 32;
|
||||
lsb |= (bytes[0xc] & 0xffL) << 24;
|
||||
lsb |= (bytes[0xd] & 0xffL) << 16;
|
||||
lsb |= (bytes[0xe] & 0xffL) << 8;
|
||||
lsb |= (bytes[0xf] & 0xffL);
|
||||
|
||||
msb = (msb & 0xffffffffffff0fffL) | UUID_VERSION_MASK; // set version
|
||||
lsb = (lsb & 0x3fffffffffffffffL) | 0x8000000000000000L; // set variant
|
||||
return new UUID(msb, lsb);
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package im.conversations.android;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.util.UUID;
|
||||
|
||||
public class Uuids {
|
||||
|
||||
private static final long VERSION_MASK = 4 << 12;
|
||||
|
||||
public static UUID getUuid(final byte[] bytes) {
|
||||
Preconditions.checkArgument(bytes != null && bytes.length == 32);
|
||||
|
||||
long msb = 0;
|
||||
long lsb = 0;
|
||||
|
||||
msb |= (bytes[0x0] & 0xffL) << 56;
|
||||
msb |= (bytes[0x1] & 0xffL) << 48;
|
||||
msb |= (bytes[0x2] & 0xffL) << 40;
|
||||
msb |= (bytes[0x3] & 0xffL) << 32;
|
||||
msb |= (bytes[0x4] & 0xffL) << 24;
|
||||
msb |= (bytes[0x5] & 0xffL) << 16;
|
||||
msb |= (bytes[0x6] & 0xffL) << 8;
|
||||
msb |= (bytes[0x7] & 0xffL);
|
||||
|
||||
lsb |= (bytes[0x8] & 0xffL) << 56;
|
||||
lsb |= (bytes[0x9] & 0xffL) << 48;
|
||||
lsb |= (bytes[0xa] & 0xffL) << 40;
|
||||
lsb |= (bytes[0xb] & 0xffL) << 32;
|
||||
lsb |= (bytes[0xc] & 0xffL) << 24;
|
||||
lsb |= (bytes[0xd] & 0xffL) << 16;
|
||||
lsb |= (bytes[0xe] & 0xffL) << 8;
|
||||
lsb |= (bytes[0xf] & 0xffL);
|
||||
|
||||
msb = (msb & 0xffffffffffff0fffL) | VERSION_MASK; // set version
|
||||
lsb = (lsb & 0x3fffffffffffffffL) | 0x8000000000000000L; // set variant
|
||||
return new UUID(msb, lsb);
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ import com.google.common.base.Preconditions;
|
|||
import com.google.common.hash.Hashing;
|
||||
import com.google.common.io.ByteSource;
|
||||
import eu.siacs.conversations.xmpp.Jid;
|
||||
import im.conversations.android.Uuids;
|
||||
import im.conversations.android.IDs;
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -48,7 +48,7 @@ public class Account {
|
|||
|
||||
public UUID getPublicDeviceId() {
|
||||
try {
|
||||
return Uuids.getUuid(
|
||||
return IDs.uuid(
|
||||
ByteSource.wrap(randomSeed).slice(0, 16).hash(Hashing.sha256()).asBytes());
|
||||
} catch (final IOException e) {
|
||||
return UUID.randomUUID();
|
||||
|
|
|
@ -16,7 +16,6 @@ import androidx.annotation.NonNull;
|
|||
import androidx.annotation.Nullable;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.io.ByteSource;
|
||||
import eu.siacs.conversations.Config;
|
||||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.crypto.XmppDomainVerifier;
|
||||
|
@ -27,7 +26,6 @@ import eu.siacs.conversations.persistance.FileBackend;
|
|||
import eu.siacs.conversations.services.MemorizingTrustManager;
|
||||
import eu.siacs.conversations.services.MessageArchiveService;
|
||||
import eu.siacs.conversations.services.NotificationService;
|
||||
import eu.siacs.conversations.utils.CryptoHelper;
|
||||
import eu.siacs.conversations.utils.Patterns;
|
||||
import eu.siacs.conversations.utils.PhoneHelper;
|
||||
import eu.siacs.conversations.utils.Resolver;
|
||||
|
@ -56,6 +54,7 @@ import eu.siacs.conversations.xmpp.stanzas.streammgmt.AckPacket;
|
|||
import eu.siacs.conversations.xmpp.stanzas.streammgmt.EnablePacket;
|
||||
import eu.siacs.conversations.xmpp.stanzas.streammgmt.RequestPacket;
|
||||
import eu.siacs.conversations.xmpp.stanzas.streammgmt.ResumePacket;
|
||||
import im.conversations.android.IDs;
|
||||
import im.conversations.android.database.ConversationsDatabase;
|
||||
import im.conversations.android.database.CredentialStore;
|
||||
import im.conversations.android.database.model.Account;
|
||||
|
@ -1713,6 +1712,7 @@ public class XmppConnection implements Runnable {
|
|||
|
||||
private void sendBindRequest() {
|
||||
clearIqCallbacks();
|
||||
// TODO if we never store a 'broken' resource we don’t need to fix it
|
||||
final String recentResource =
|
||||
fixResource(
|
||||
ConversationsDatabase.getInstance(context)
|
||||
|
@ -1722,7 +1722,7 @@ public class XmppConnection implements Runnable {
|
|||
if (recentResource != null) {
|
||||
resource = recentResource;
|
||||
} else {
|
||||
resource = this.createNewResource(account.randomSeed);
|
||||
resource = this.createNewResource(IDs.tiny(account.randomSeed));
|
||||
}
|
||||
final IqPacket iq = new IqPacket(IqPacket.TYPE.SET);
|
||||
iq.addChild("bind", Namespace.BIND).addChild("resource").setContent(resource);
|
||||
|
@ -1783,8 +1783,7 @@ public class XmppConnection implements Runnable {
|
|||
if (packet.getType() == IqPacket.TYPE.ERROR
|
||||
&& error != null
|
||||
&& error.hasChild("conflict")) {
|
||||
final String alternativeResource =
|
||||
createNewResource(SECURE_RANDOM.generateSeed(3));
|
||||
final String alternativeResource = createNewResource(IDs.tiny());
|
||||
ConversationsDatabase.getInstance(context)
|
||||
.accountDao()
|
||||
.setResource(account.id, alternativeResource);
|
||||
|
@ -2132,7 +2131,7 @@ public class XmppConnection implements Runnable {
|
|||
return;
|
||||
}
|
||||
if (streamError.hasChild("conflict")) {
|
||||
final String alternativeResource = createNewResource(SECURE_RANDOM.generateSeed(3));
|
||||
final String alternativeResource = createNewResource(IDs.tiny());
|
||||
ConversationsDatabase.getInstance(context)
|
||||
.accountDao()
|
||||
.setResource(account.id, alternativeResource);
|
||||
|
@ -2224,31 +2223,8 @@ public class XmppConnection implements Runnable {
|
|||
tagWriter.writeTag(stream, flush);
|
||||
}
|
||||
|
||||
private String createNewResource(final byte[] random) {
|
||||
return String.format(
|
||||
"%s.%s",
|
||||
context.getString(R.string.app_name),
|
||||
Base64.encodeToString(
|
||||
slice(random), Base64.NO_PADDING | Base64.NO_WRAP | Base64.URL_SAFE));
|
||||
}
|
||||
|
||||
private static byte[] slice(final byte[] input) {
|
||||
if (input == null || input.length < 3) {
|
||||
return new byte[3];
|
||||
}
|
||||
try {
|
||||
return ByteSource.wrap(input).slice(0, 3).read();
|
||||
} catch (final IOException e) {
|
||||
return new byte[3];
|
||||
}
|
||||
}
|
||||
|
||||
private String nextRandomId() {
|
||||
return nextRandomId(false);
|
||||
}
|
||||
|
||||
private String nextRandomId(final boolean s) {
|
||||
return CryptoHelper.random(s ? 3 : 9);
|
||||
private String createNewResource(final String postfixId) {
|
||||
return String.format("%s.%s", context.getString(R.string.app_name), postfixId);
|
||||
}
|
||||
|
||||
public String sendIqPacket(final IqPacket packet, final Consumer<IqPacket> callback) {
|
||||
|
@ -2258,8 +2234,8 @@ public class XmppConnection implements Runnable {
|
|||
|
||||
public synchronized String sendUnmodifiedIqPacket(
|
||||
final IqPacket packet, final Consumer<IqPacket> callback, boolean force) {
|
||||
if (packet.getId() == null) {
|
||||
packet.setAttribute("id", nextRandomId());
|
||||
if (Strings.isNullOrEmpty(packet.getId())) {
|
||||
packet.setAttribute("id", IDs.medium());
|
||||
}
|
||||
if (callback != null) {
|
||||
synchronized (this.packetCallbacks) {
|
||||
|
|
Loading…
Reference in a new issue