Merge branch 'dev' of https://github.com/oxen-io/session-android into client-side-nickname

This commit is contained in:
Ryan ZHAO
2021-05-13 14:25:19 +10:00
28 changed files with 143 additions and 84 deletions

View File

@@ -5,6 +5,7 @@ import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.file_server.FileServerAPI
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentState
import org.session.libsession.messaging.utilities.Data
import org.session.libsession.messaging.utilities.DotNetAPI
import org.session.libsession.utilities.DownloadUtilities
import org.session.libsignal.service.api.crypto.AttachmentCipherInputStream

View File

@@ -8,6 +8,7 @@ import org.session.libsession.messaging.file_server.FileServerAPI
import org.session.libsession.messaging.messages.Message
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.messaging.utilities.Data
import org.session.libsession.messaging.utilities.DotNetAPI
import org.session.libsignal.service.api.crypto.AttachmentCipherOutputStream
import org.session.libsignal.service.api.messages.SignalServiceAttachmentStream

View File

@@ -1,5 +1,7 @@
package org.session.libsession.messaging.jobs
import org.session.libsession.messaging.utilities.Data
interface Job {
var delegate: JobDelegate?
var id: String?

View File

@@ -4,6 +4,7 @@ import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.deferred
import org.session.libsession.messaging.sending_receiving.MessageReceiver
import org.session.libsession.messaging.sending_receiving.handle
import org.session.libsession.messaging.utilities.Data
import org.session.libsignal.utilities.logging.Log
class MessageReceiveJob(val data: ByteArray, val isBackgroundPoll: Boolean, val openGroupMessageServerID: Long? = null, val openGroupID: String? = null) : Job {

View File

@@ -9,6 +9,7 @@ import org.session.libsession.messaging.messages.Destination
import org.session.libsession.messaging.messages.Message
import org.session.libsession.messaging.messages.visible.VisibleMessage
import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.messaging.utilities.Data
import org.session.libsignal.utilities.logging.Log
class MessageSendJob(val message: Message, val destination: Destination) : Job {

View File

@@ -9,6 +9,7 @@ import okhttp3.Request
import okhttp3.RequestBody
import org.session.libsession.messaging.sending_receiving.notifications.PushNotificationAPI
import org.session.libsession.messaging.utilities.Data
import org.session.libsession.snode.SnodeMessage
import org.session.libsession.snode.OnionRequestAPI

View File

@@ -1,5 +1,7 @@
package org.session.libsession.messaging.jobs
import org.session.libsession.messaging.utilities.Data
class SessionJobInstantiator(private val jobFactories: Map<String, Job.Factory<out Job>>) {
fun instantiate(jobFactoryKey: String, data: Data): Job? {

View File

@@ -1,4 +1,4 @@
package org.session.libsession.messaging.jobs;
package org.session.libsession.messaging.utilities;
import android.os.Parcelable;
@@ -12,11 +12,7 @@ import org.session.libsession.utilities.ParcelableUtil;
import java.util.HashMap;
import java.util.Map;
// Introduce a dedicated Map<String, byte[]> field specifically for parcelable needs.
public class Data {
public static final Data EMPTY = new Data.Builder().build();
@JsonProperty private final Map<String, String> strings;
@JsonProperty private final Map<String, String[]> stringArrays;
@JsonProperty private final Map<String, Integer> integers;
@@ -31,20 +27,23 @@ public class Data {
@JsonProperty private final Map<String, boolean[]> booleanArrays;
@JsonProperty private final Map<String, byte[]> byteArrays;
public Data(@JsonProperty("strings") @NonNull Map<String, String> strings,
@JsonProperty("stringArrays") @NonNull Map<String, String[]> stringArrays,
@JsonProperty("integers") @NonNull Map<String, Integer> integers,
@JsonProperty("integerArrays") @NonNull Map<String, int[]> integerArrays,
@JsonProperty("longs") @NonNull Map<String, Long> longs,
@JsonProperty("longArrays") @NonNull Map<String, long[]> longArrays,
@JsonProperty("floats") @NonNull Map<String, Float> floats,
@JsonProperty("floatArrays") @NonNull Map<String, float[]> floatArrays,
@JsonProperty("doubles") @NonNull Map<String, Double> doubles,
@JsonProperty("doubleArrays") @NonNull Map<String, double[]> doubleArrays,
@JsonProperty("booleans") @NonNull Map<String, Boolean> booleans,
@JsonProperty("booleanArrays") @NonNull Map<String, boolean[]> booleanArrays,
@JsonProperty("byteArrays") @NonNull Map<String, byte[]> byteArrays)
{
public static final Data EMPTY = new Data.Builder().build();
public Data(
@JsonProperty("strings") @NonNull Map<String, String> strings,
@JsonProperty("stringArrays") @NonNull Map<String, String[]> stringArrays,
@JsonProperty("integers") @NonNull Map<String, Integer> integers,
@JsonProperty("integerArrays") @NonNull Map<String, int[]> integerArrays,
@JsonProperty("longs") @NonNull Map<String, Long> longs,
@JsonProperty("longArrays") @NonNull Map<String, long[]> longArrays,
@JsonProperty("floats") @NonNull Map<String, Float> floats,
@JsonProperty("floatArrays") @NonNull Map<String, float[]> floatArrays,
@JsonProperty("doubles") @NonNull Map<String, Double> doubles,
@JsonProperty("doubleArrays") @NonNull Map<String, double[]> doubleArrays,
@JsonProperty("booleans") @NonNull Map<String, Boolean> booleans,
@JsonProperty("booleanArrays") @NonNull Map<String, boolean[]> booleanArrays,
@JsonProperty("byteArrays") @NonNull Map<String, byte[]> byteArrays
) {
this.strings = strings;
this.stringArrays = stringArrays;
this.integers = integers;
@@ -75,6 +74,7 @@ public class Data {
}
public boolean hasStringArray(@NonNull String key) {
return stringArrays.containsKey(key);
}
@@ -100,6 +100,7 @@ public class Data {
}
public boolean hasIntegerArray(@NonNull String key) {
return integerArrays.containsKey(key);
}
@@ -110,6 +111,7 @@ public class Data {
}
public boolean hasLong(@NonNull String key) {
return longs.containsKey(key);
}
@@ -125,6 +127,7 @@ public class Data {
}
public boolean hasLongArray(@NonNull String key) {
return longArrays.containsKey(key);
}
@@ -135,6 +138,7 @@ public class Data {
}
public boolean hasFloat(@NonNull String key) {
return floats.containsKey(key);
}
@@ -150,6 +154,7 @@ public class Data {
}
public boolean hasFloatArray(@NonNull String key) {
return floatArrays.containsKey(key);
}
@@ -160,6 +165,7 @@ public class Data {
}
public boolean hasDouble(@NonNull String key) {
return doubles.containsKey(key);
}
@@ -175,6 +181,7 @@ public class Data {
}
public boolean hasDoubleArray(@NonNull String key) {
return floatArrays.containsKey(key);
}
@@ -185,6 +192,7 @@ public class Data {
}
public boolean hasBoolean(@NonNull String key) {
return booleans.containsKey(key);
}
@@ -200,6 +208,7 @@ public class Data {
}
public boolean hasBooleanArray(@NonNull String key) {
return booleanArrays.containsKey(key);
}
@@ -209,6 +218,8 @@ public class Data {
return booleanArrays.get(key);
}
public boolean hasByteArray(@NonNull String key) {
return byteArrays.containsKey(key);
}
@@ -218,6 +229,8 @@ public class Data {
return byteArrays.get(key);
}
public boolean hasParcelable(@NonNull String key) {
return byteArrays.containsKey(key);
}
@@ -228,6 +241,8 @@ public class Data {
return ParcelableUtil.unmarshall(bytes, creator);
}
private void throwIfAbsent(@NonNull Map map, @NonNull String key) {
if (!map.containsKey(key)) {
throw new IllegalStateException("Tried to retrieve a value with key '" + key + "', but it wasn't present.");
@@ -236,7 +251,6 @@ public class Data {
public static class Builder {
private final Map<String, String> strings = new HashMap<>();
private final Map<String, String[]> stringArrays = new HashMap<>();
private final Map<String, Integer> integers = new HashMap<>();
@@ -323,19 +337,21 @@ public class Data {
}
public Data build() {
return new Data(strings,
stringArrays,
integers,
integerArrays,
longs,
longArrays,
floats,
floatArrays,
doubles,
doubleArrays,
booleans,
booleanArrays,
byteArrays);
return new Data(
strings,
stringArrays,
integers,
integerArrays,
longs,
longArrays,
floats,
floatArrays,
doubles,
doubleArrays,
booleans,
booleanArrays,
byteArrays
);
}
}
@@ -343,5 +359,4 @@ public class Data {
@NonNull String serialize(@NonNull Data data);
@NonNull Data deserialize(@NonNull String serialized);
}
}
}

View File

@@ -53,11 +53,11 @@ object OnionRequestAPI {
/**
* The number of times a path can fail before it's replaced.
*/
private const val pathFailureThreshold = 1
private const val pathFailureThreshold = 3
/**
* The number of times a snode can fail before it's replaced.
*/
private const val snodeFailureThreshold = 1
private const val snodeFailureThreshold = 3
/**
* The number of guard snodes required to maintain `targetPathCount` paths.
*/
@@ -93,7 +93,7 @@ object OnionRequestAPI {
ThreadUtils.queue { // No need to block the shared context for this
val url = "${snode.address}:${snode.port}/get_stats/v1"
try {
val json = HTTP.execute(HTTP.Verb.GET, url)
val json = HTTP.execute(HTTP.Verb.GET, url, 3)
val version = json["version"] as? String
if (version == null) { deferred.reject(Exception("Missing snode version.")); return@queue }
if (version >= "2.0.7") {
@@ -463,7 +463,6 @@ object OnionRequestAPI {
"method" to request.method(),
"headers" to headers
)
url.isHttps
val destination = Destination.Server(host, target, x25519PublicKey, url.scheme(), url.port())
return sendOnionRequest(destination, payload, isJSONRequired).recover { exception ->
Log.d("Loki", "Couldn't reach server: $urlAsString due to error: $exception.")

View File

@@ -71,11 +71,11 @@ object OnionRequestEncryption {
}
is OnionRequestAPI.Destination.Server -> {
payload = mutableMapOf(
"host" to rhs.host,
"target" to rhs.target,
"method" to "POST",
"protocol" to rhs.scheme,
"port" to rhs.port
"host" to rhs.host,
"target" to rhs.target,
"method" to "POST",
"protocol" to rhs.scheme,
"port" to rhs.port
)
}
}

View File

@@ -34,7 +34,7 @@ object SnodeAPI {
// Settings
private val maxRetryCount = 6
private val minimumSnodePoolCount = 12
private val minimumSwarmSnodeCount = 2
private val minimumSwarmSnodeCount = 3
// Use port 4433 if the API level can handle the network security configuration and enforce pinned certificates
private val seedNodePort = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) 443 else 4433
private val seedNodePool by lazy {
@@ -44,7 +44,7 @@ object SnodeAPI {
setOf( "https://storage.seed1.loki.network:$seedNodePort ", "https://storage.seed3.loki.network:$seedNodePort ", "https://public.loki.foundation:$seedNodePort" )
}
}
private val snodeFailureThreshold = 4
private val snodeFailureThreshold = 3
private val targetSwarmSnodeCount = 2
private val useOnionRequests = true
@@ -252,19 +252,20 @@ object SnodeAPI {
private fun removeDuplicates(publicKey: String, rawMessages: List<*>): List<*> {
val receivedMessageHashValues = database.getReceivedMessageHashValues(publicKey)?.toMutableSet() ?: mutableSetOf()
return rawMessages.filter { rawMessage ->
val result = rawMessages.filter { rawMessage ->
val rawMessageAsJSON = rawMessage as? Map<*, *>
val hashValue = rawMessageAsJSON?.get("hash") as? String
if (hashValue != null) {
val isDuplicate = receivedMessageHashValues.contains(hashValue)
receivedMessageHashValues.add(hashValue)
database.setReceivedMessageHashValues(publicKey, receivedMessageHashValues)
!isDuplicate
} else {
Log.d("Loki", "Missing hash value for message: ${rawMessage?.prettifiedDescription()}.")
false
}
}
database.setReceivedMessageHashValues(publicKey, receivedMessageHashValues)
return result
}
private fun parseEnvelopes(rawMessages: List<*>): List<SignalServiceProtos.Envelope> {
@@ -305,7 +306,7 @@ object SnodeAPI {
}
}
when (statusCode) {
400, 500, 503 -> { // Usually indicates that the snode isn't up to date
400, 500, 502, 503 -> { // Usually indicates that the snode isn't up to date
handleBadSnode()
}
406 -> {
@@ -316,8 +317,20 @@ object SnodeAPI {
421 -> {
// The snode isn't associated with the given public key anymore
if (publicKey != null) {
Log.d("Loki", "Invalidating swarm for: $publicKey.")
dropSnodeFromSwarmIfNeeded(snode, publicKey)
fun invalidateSwarm() {
Log.d("Loki", "Invalidating swarm for: $publicKey.")
dropSnodeFromSwarmIfNeeded(snode, publicKey)
}
if (json != null) {
val snodes = parseSnodes(json)
if (snodes.isNotEmpty()) {
database.setSwarm(publicKey, snodes.toSet())
} else {
invalidateSwarm()
}
} else {
invalidateSwarm()
}
} else {
Log.d("Loki", "Got a 421 without an associated public key.")
}

View File

@@ -3,23 +3,33 @@ package org.session.libsession.snode
import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded
data class SnodeMessage(
// The hex encoded public key of the recipient.
/**
* The hex encoded public key of the recipient.
*/
val recipient: String,
// The content of the message.
/**
* The content of the message.
*/
val data: String,
// The time to live for the message in milliseconds.
/**
* The time to live for the message in milliseconds.
*/
val ttl: Long,
// When the proof of work was calculated.
/**
* When the proof of work was calculated.
*
* **Note:** Expressed as milliseconds since 00:00:00 UTC on 1 January 1970.
*/
val timestamp: Long
) {
internal fun toJSON(): Map<String, String> {
return mapOf(
"pubKey" to if (SnodeAPI.useTestnet) recipient.removing05PrefixIfNeeded() else recipient,
"data" to data,
"ttl" to ttl.toString(),
"timestamp" to timestamp.toString(),
"nonce" to ""
"data" to data,
"ttl" to ttl.toString(),
"timestamp" to timestamp.toString(),
"nonce" to ""
)
}
}