mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-12 11:07:42 +00:00
Merge branch 'dev' of https://github.com/oxen-io/session-android into client-side-nickname
This commit is contained in:
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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?
|
||||
|
@@ -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 {
|
||||
|
@@ -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 {
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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? {
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -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.")
|
||||
|
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -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.")
|
||||
}
|
||||
|
@@ -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 ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user