mirror of
https://github.com/oxen-io/session-android.git
synced 2025-12-14 07:42:30 +00:00
Merge branch 'dev' into just-prefs
This commit is contained in:
@@ -2,7 +2,7 @@ package org.session.libsession.messaging
|
||||
|
||||
data class BlindedIdMapping(
|
||||
val blindedId: String,
|
||||
val sessionId: String?,
|
||||
val accountId: String?,
|
||||
val serverUrl: String,
|
||||
val serverId: String
|
||||
)
|
||||
@@ -3,8 +3,11 @@ package org.session.libsession.messaging.file_server
|
||||
import nl.komponents.kovenant.Promise
|
||||
import nl.komponents.kovenant.functional.map
|
||||
import okhttp3.Headers
|
||||
import okhttp3.Headers.Companion.toHeaders
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.RequestBody
|
||||
import org.session.libsession.snode.OnionRequestAPI
|
||||
import org.session.libsignal.utilities.HTTP
|
||||
@@ -37,18 +40,18 @@ object FileServerApi {
|
||||
)
|
||||
|
||||
private fun createBody(body: ByteArray?, parameters: Any?): RequestBody? {
|
||||
if (body != null) return RequestBody.create(MediaType.get("application/octet-stream"), body)
|
||||
if (body != null) return RequestBody.create("application/octet-stream".toMediaType(), body)
|
||||
if (parameters == null) return null
|
||||
val parametersAsJSON = JsonUtil.toJson(parameters)
|
||||
return RequestBody.create(MediaType.get("application/json"), parametersAsJSON)
|
||||
return RequestBody.create("application/json".toMediaType(), parametersAsJSON)
|
||||
}
|
||||
|
||||
private fun send(request: Request): Promise<ByteArray, Exception> {
|
||||
val url = HttpUrl.parse(server) ?: return Promise.ofFail(Error.InvalidURL)
|
||||
val url = server.toHttpUrlOrNull() ?: return Promise.ofFail(Error.InvalidURL)
|
||||
val urlBuilder = HttpUrl.Builder()
|
||||
.scheme(url.scheme())
|
||||
.host(url.host())
|
||||
.port(url.port())
|
||||
.scheme(url.scheme)
|
||||
.host(url.host)
|
||||
.port(url.port)
|
||||
.addPathSegments(request.endpoint)
|
||||
if (request.verb == HTTP.Verb.GET) {
|
||||
for ((key, value) in request.queryParameters) {
|
||||
@@ -57,7 +60,7 @@ object FileServerApi {
|
||||
}
|
||||
val requestBuilder = okhttp3.Request.Builder()
|
||||
.url(urlBuilder.build())
|
||||
.headers(Headers.of(request.headers))
|
||||
.headers(request.headers.toHeaders())
|
||||
when (request.verb) {
|
||||
HTTP.Verb.GET -> requestBuilder.get()
|
||||
HTTP.Verb.PUT -> requestBuilder.put(createBody(request.body, request.parameters)!!)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.session.libsession.messaging.jobs
|
||||
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import org.session.libsession.database.MessageDataProvider
|
||||
import org.session.libsession.database.StorageProtocol
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
@@ -141,8 +142,8 @@ class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long)
|
||||
DownloadUtilities.downloadFile(tempFile, attachment.url)
|
||||
} else {
|
||||
Log.d("AttachmentDownloadJob", "downloading open group attachment")
|
||||
val url = HttpUrl.parse(attachment.url)!!
|
||||
val fileID = url.pathSegments().last()
|
||||
val url = attachment.url.toHttpUrlOrNull()!!
|
||||
val fileID = url.pathSegments.last()
|
||||
OpenGroupApi.download(fileID, openGroup.room, openGroup.server).get().let {
|
||||
tempFile.writeBytes(it)
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ class AttachmentUploadJob(val attachmentID: Long, val threadID: String, val mess
|
||||
val kryo = Kryo()
|
||||
kryo.isRegistrationRequired = false
|
||||
val serializedMessage = ByteArray(4096)
|
||||
val output = Output(serializedMessage, Job.MAX_BUFFER_SIZE)
|
||||
val output = Output(serializedMessage, Job.MAX_BUFFER_SIZE_BYTES)
|
||||
kryo.writeClassAndObject(output, message)
|
||||
output.close()
|
||||
return Data.Builder()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.session.libsession.messaging.jobs
|
||||
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.open_groups.OpenGroup
|
||||
import org.session.libsession.messaging.utilities.Data
|
||||
@@ -21,9 +22,9 @@ class BackgroundGroupAddJob(val joinUrl: String): Job {
|
||||
override val maxFailureCount: Int = 1
|
||||
|
||||
val openGroupId: String? get() {
|
||||
val url = HttpUrl.parse(joinUrl) ?: return null
|
||||
val url = joinUrl.toHttpUrlOrNull() ?: return null
|
||||
val server = OpenGroup.getServer(joinUrl)?.toString()?.removeSuffix("/") ?: return null
|
||||
val room = url.pathSegments().firstOrNull() ?: return null
|
||||
val room = url.pathSegments.firstOrNull() ?: return null
|
||||
return "$server.$room"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.session.libsession.messaging.jobs
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import network.loki.messenger.libsession_util.ConfigBase.Companion.protoKindFor
|
||||
import nl.komponents.kovenant.functional.bind
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
@@ -10,7 +11,6 @@ import org.session.libsession.messaging.utilities.Data
|
||||
import org.session.libsession.snode.RawResponse
|
||||
import org.session.libsession.snode.SnodeAPI
|
||||
import org.session.libsignal.utilities.Log
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
// only contact (self) and closed group destinations will be supported
|
||||
data class ConfigurationSyncJob(val destination: Destination): Job {
|
||||
@@ -180,7 +180,6 @@ data class ConfigurationSyncJob(val destination: Destination): Job {
|
||||
// type mappings
|
||||
const val CONTACT_TYPE = 1
|
||||
const val GROUP_TYPE = 2
|
||||
|
||||
}
|
||||
|
||||
class Factory: Job.Factory<ConfigurationSyncJob> {
|
||||
|
||||
@@ -14,7 +14,7 @@ interface Job {
|
||||
// Keys used for database storage
|
||||
private val ID_KEY = "id"
|
||||
private val FAILURE_COUNT_KEY = "failure_count"
|
||||
internal const val MAX_BUFFER_SIZE = 1_000_000 // bytes
|
||||
internal const val MAX_BUFFER_SIZE_BYTES = 1_000_000 // ~1MB
|
||||
}
|
||||
|
||||
suspend fun execute(dispatcherName: String)
|
||||
|
||||
@@ -4,7 +4,7 @@ import com.esotericsoftware.kryo.Kryo
|
||||
import com.esotericsoftware.kryo.io.Input
|
||||
import com.esotericsoftware.kryo.io.Output
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.jobs.Job.Companion.MAX_BUFFER_SIZE
|
||||
import org.session.libsession.messaging.jobs.Job.Companion.MAX_BUFFER_SIZE_BYTES
|
||||
import org.session.libsession.messaging.messages.Destination
|
||||
import org.session.libsession.messaging.messages.Message
|
||||
import org.session.libsession.messaging.messages.visible.VisibleMessage
|
||||
@@ -118,12 +118,12 @@ class MessageSendJob(val message: Message, val destination: Destination) : Job {
|
||||
val kryo = Kryo()
|
||||
kryo.isRegistrationRequired = false
|
||||
// Message
|
||||
val messageOutput = Output(ByteArray(4096), MAX_BUFFER_SIZE)
|
||||
val messageOutput = Output(ByteArray(4096), MAX_BUFFER_SIZE_BYTES)
|
||||
kryo.writeClassAndObject(messageOutput, message)
|
||||
messageOutput.close()
|
||||
val serializedMessage = messageOutput.toBytes()
|
||||
// Destination
|
||||
val destinationOutput = Output(ByteArray(4096), MAX_BUFFER_SIZE)
|
||||
val destinationOutput = Output(ByteArray(4096), MAX_BUFFER_SIZE_BYTES)
|
||||
kryo.writeClassAndObject(destinationOutput, destination)
|
||||
destinationOutput.close()
|
||||
val serializedDestination = destinationOutput.toBytes()
|
||||
|
||||
@@ -3,10 +3,10 @@ package org.session.libsession.messaging.jobs
|
||||
import com.esotericsoftware.kryo.Kryo
|
||||
import com.esotericsoftware.kryo.io.Input
|
||||
import com.esotericsoftware.kryo.io.Output
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody
|
||||
import org.session.libsession.messaging.jobs.Job.Companion.MAX_BUFFER_SIZE
|
||||
import org.session.libsession.messaging.jobs.Job.Companion.MAX_BUFFER_SIZE_BYTES
|
||||
import org.session.libsession.messaging.sending_receiving.notifications.Server
|
||||
import org.session.libsession.messaging.utilities.Data
|
||||
import org.session.libsession.snode.OnionRequestAPI
|
||||
@@ -33,7 +33,7 @@ class NotifyPNServerJob(val message: SnodeMessage) : Job {
|
||||
val server = Server.LEGACY
|
||||
val parameters = mapOf( "data" to message.data, "send_to" to message.recipient )
|
||||
val url = "${server.url}/notify"
|
||||
val body = RequestBody.create(MediaType.get("application/json"), JsonUtil.toJson(parameters))
|
||||
val body = RequestBody.create("application/json".toMediaType(), JsonUtil.toJson(parameters))
|
||||
val request = Request.Builder().url(url).post(body).build()
|
||||
retryIfNeeded(4) {
|
||||
OnionRequestAPI.sendOnionRequest(
|
||||
@@ -67,7 +67,7 @@ class NotifyPNServerJob(val message: SnodeMessage) : Job {
|
||||
val kryo = Kryo()
|
||||
kryo.isRegistrationRequired = false
|
||||
val serializedMessage = ByteArray(4096)
|
||||
val output = Output(serializedMessage, MAX_BUFFER_SIZE)
|
||||
val output = Output(serializedMessage, MAX_BUFFER_SIZE_BYTES)
|
||||
kryo.writeObject(output, message)
|
||||
output.close()
|
||||
return Data.Builder()
|
||||
|
||||
@@ -37,7 +37,7 @@ class RetrieveProfileAvatarJob(private val profileAvatar: String?, val recipient
|
||||
}
|
||||
|
||||
override suspend fun execute(dispatcherName: String) {
|
||||
val delegate = delegate ?: return
|
||||
val delegate = delegate ?: return Log.w(TAG, "RetrieveProfileAvatarJob has no delegate method to work with!")
|
||||
if (profileAvatar in errorUrls) return delegate.handleJobFailed(this, dispatcherName, Exception("Profile URL 404'd this app instance"))
|
||||
val context = MessagingModuleConfiguration.shared.context
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
|
||||
@@ -30,8 +30,8 @@ sealed class Endpoint(val value: String) {
|
||||
data class RoomMessagesSince(val roomToken: String, val seqNo: Long) :
|
||||
Endpoint("room/$roomToken/messages/since/$seqNo")
|
||||
|
||||
data class RoomDeleteMessages(val roomToken: String, val sessionId: String) :
|
||||
Endpoint("room/$roomToken/all/$sessionId")
|
||||
data class RoomDeleteMessages(val roomToken: String, val accountId: String) :
|
||||
Endpoint("room/$roomToken/all/$accountId")
|
||||
|
||||
data class Reactors(val roomToken: String, val messageId: Long, val emoji: String):
|
||||
Endpoint("room/$roomToken/reactors/$messageId/$emoji")
|
||||
@@ -67,15 +67,15 @@ sealed class Endpoint(val value: String) {
|
||||
|
||||
object Inbox : Endpoint("inbox")
|
||||
data class InboxSince(val id: Long) : Endpoint("inbox/since/$id")
|
||||
data class InboxFor(val sessionId: String) : Endpoint("inbox/$sessionId")
|
||||
data class InboxFor(val accountId: String) : Endpoint("inbox/$accountId")
|
||||
|
||||
object Outbox : Endpoint("outbox")
|
||||
data class OutboxSince(val id: Long) : Endpoint("outbox/since/$id")
|
||||
|
||||
// Users
|
||||
|
||||
data class UserBan(val sessionId: String) : Endpoint("user/$sessionId/ban")
|
||||
data class UserUnban(val sessionId: String) : Endpoint("user/$sessionId/unban")
|
||||
data class UserModerator(val sessionId: String) : Endpoint("user/$sessionId/moderator")
|
||||
data class UserBan(val accountId: String) : Endpoint("user/$accountId/ban")
|
||||
data class UserUnban(val accountId: String) : Endpoint("user/$accountId/unban")
|
||||
data class UserModerator(val accountId: String) : Endpoint("user/$accountId/moderator")
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.session.libsession.messaging.open_groups
|
||||
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import org.session.libsignal.utilities.JsonUtil
|
||||
import org.session.libsignal.utilities.Log
|
||||
import java.util.Locale
|
||||
@@ -47,11 +48,11 @@ data class OpenGroup(
|
||||
}
|
||||
|
||||
fun getServer(urlAsString: String): HttpUrl? {
|
||||
val url = HttpUrl.parse(urlAsString) ?: return null
|
||||
val builder = HttpUrl.Builder().scheme(url.scheme()).host(url.host())
|
||||
if (url.port() != 80 || url.port() != 443) {
|
||||
val url = urlAsString.toHttpUrlOrNull() ?: return null
|
||||
val builder = HttpUrl.Builder().scheme(url.scheme).host(url.host)
|
||||
if (url.port != 80 || url.port != 443) {
|
||||
// Non-standard port; add to server
|
||||
builder.port(url.port())
|
||||
builder.port(url.port)
|
||||
}
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
@@ -6,16 +6,14 @@ import com.fasterxml.jackson.core.type.TypeReference
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming
|
||||
import com.fasterxml.jackson.databind.type.TypeFactory
|
||||
import com.goterl.lazysodium.LazySodiumAndroid
|
||||
import com.goterl.lazysodium.SodiumAndroid
|
||||
import com.goterl.lazysodium.interfaces.GenericHash
|
||||
import com.goterl.lazysodium.interfaces.Sign
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import nl.komponents.kovenant.Promise
|
||||
import nl.komponents.kovenant.functional.map
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.Headers.Companion.toHeaders
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.RequestBody
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupPoller.Companion.maxInactivityPeriod
|
||||
@@ -282,10 +280,10 @@ object OpenGroupApi {
|
||||
)
|
||||
|
||||
private fun createBody(body: ByteArray?, parameters: Any?): RequestBody? {
|
||||
if (body != null) return RequestBody.create(MediaType.get("application/octet-stream"), body)
|
||||
if (body != null) return RequestBody.create("application/octet-stream".toMediaType(), body)
|
||||
if (parameters == null) return null
|
||||
val parametersAsJSON = JsonUtil.toJson(parameters)
|
||||
return RequestBody.create(MediaType.get("application/json"), parametersAsJSON)
|
||||
return RequestBody.create("application/json".toMediaType(), parametersAsJSON)
|
||||
}
|
||||
|
||||
private fun getResponseBody(request: Request): Promise<ByteArray, Exception> {
|
||||
@@ -301,7 +299,7 @@ object OpenGroupApi {
|
||||
}
|
||||
|
||||
private fun send(request: Request): Promise<OnionResponse, Exception> {
|
||||
HttpUrl.parse(request.server) ?: return Promise.ofFail(Error.InvalidURL)
|
||||
request.server.toHttpUrlOrNull() ?: return Promise.ofFail(Error.InvalidURL)
|
||||
val urlBuilder = StringBuilder("${request.server}/${request.endpoint.value}")
|
||||
if (request.verb == GET && request.queryParameters.isNotEmpty()) {
|
||||
urlBuilder.append("?")
|
||||
@@ -387,7 +385,7 @@ object OpenGroupApi {
|
||||
|
||||
val requestBuilder = okhttp3.Request.Builder()
|
||||
.url(urlRequest)
|
||||
.headers(Headers.of(headers))
|
||||
.headers(headers.toHeaders())
|
||||
when (request.verb) {
|
||||
GET -> requestBuilder.get()
|
||||
PUT -> requestBuilder.put(createBody(request.body, request.parameters)!!)
|
||||
|
||||
@@ -36,7 +36,7 @@ data class OpenGroupMessage(
|
||||
val base64EncodedData = json["data"] as? String ?: return null
|
||||
val sentTimestamp = json["posted"] as? Double ?: return null
|
||||
val serverID = json["id"] as? Int
|
||||
val sender = json["account_id"] as? String
|
||||
val sender = json["session_id"] as? String
|
||||
val base64EncodedSignature = json["signature"] as? String
|
||||
return OpenGroupMessage(
|
||||
serverID = serverID?.toLong(),
|
||||
|
||||
@@ -72,4 +72,4 @@ class SessionServiceAttachmentStream(val inputStream: InputStream?, contentType:
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@ import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class SubscriptionRequest(
|
||||
/** the 33-byte account being subscribed to; typically a session ID */
|
||||
/** the 33-byte account being subscribed to; typically an account ID */
|
||||
val pubkey: String,
|
||||
/** when the pubkey starts with 05 (i.e. a session ID) this is the ed25519 32-byte pubkey associated with the session ID */
|
||||
/** when the pubkey starts with 05 (i.e. an account ID) this is the ed25519 32-byte pubkey associated with the account ID */
|
||||
val session_ed25519: String?,
|
||||
/** 32-byte swarm authentication subkey; omitted (or null) when not using subkey auth (new closed groups) */
|
||||
val subkey_tag: String? = null,
|
||||
@@ -38,9 +38,9 @@ data class SubscriptionRequest(
|
||||
|
||||
@Serializable
|
||||
data class UnsubscriptionRequest(
|
||||
/** the 33-byte account being subscribed to; typically a session ID */
|
||||
/** the 33-byte account being subscribed to; typically a account ID */
|
||||
val pubkey: String,
|
||||
/** when the pubkey starts with 05 (i.e. a session ID) this is the ed25519 32-byte pubkey associated with the session ID */
|
||||
/** when the pubkey starts with 05 (i.e. an account ID) this is the ed25519 32-byte pubkey associated with the account ID */
|
||||
val session_ed25519: String?,
|
||||
/** 32-byte swarm authentication subkey; omitted (or null) when not using subkey auth (new closed groups) */
|
||||
val subkey_tag: String? = null,
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.session.libsession.messaging.sending_receiving.notifications
|
||||
import android.annotation.SuppressLint
|
||||
import nl.komponents.kovenant.Promise
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
@@ -59,7 +60,7 @@ object PushRegistryV1 {
|
||||
|
||||
val url = "${server.url}/register_legacy_groups_only"
|
||||
val body = RequestBody.create(
|
||||
MediaType.get("application/json"),
|
||||
"application/json".toMediaType(),
|
||||
JsonUtil.toJson(parameters)
|
||||
)
|
||||
val request = Request.Builder().url(url).post(body).build()
|
||||
@@ -84,7 +85,7 @@ object PushRegistryV1 {
|
||||
return retryIfNeeded(maxRetryCount) {
|
||||
val parameters = mapOf("token" to token)
|
||||
val url = "${server.url}/unregister"
|
||||
val body = RequestBody.create(MediaType.get("application/json"), JsonUtil.toJson(parameters))
|
||||
val body = RequestBody.create("application/json".toMediaType(), JsonUtil.toJson(parameters))
|
||||
val request = Request.Builder().url(url).post(body).build()
|
||||
|
||||
sendOnionRequest(request) success {
|
||||
@@ -121,7 +122,7 @@ object PushRegistryV1 {
|
||||
): Promise<*, Exception> {
|
||||
val parameters = mapOf("closedGroupPublicKey" to closedGroupPublicKey, "pubKey" to publicKey)
|
||||
val url = "${server.url}/$operation"
|
||||
val body = RequestBody.create(MediaType.get("application/json"), JsonUtil.toJson(parameters))
|
||||
val body = RequestBody.create("application/json".toMediaType(), JsonUtil.toJson(parameters))
|
||||
val request = Request.Builder().url(url).post(body).build()
|
||||
|
||||
return retryIfNeeded(maxRetryCount) {
|
||||
|
||||
@@ -272,7 +272,7 @@ class OpenGroupPoller(private val server: String, private val executorService: S
|
||||
serverPublicKey,
|
||||
true
|
||||
)
|
||||
val syncTarget = mapping.sessionId ?: it.recipient
|
||||
val syncTarget = mapping.accountId ?: it.recipient
|
||||
if (message is VisibleMessage) {
|
||||
message.syncTarget = syncTarget
|
||||
} else if (message is ExpirationTimerUpdate) {
|
||||
|
||||
@@ -159,22 +159,22 @@ object SodiumUtilities {
|
||||
} else null
|
||||
}
|
||||
|
||||
/* This method should be used to check if a users standard sessionId matches a blinded one */
|
||||
fun sessionId(
|
||||
/* This method should be used to check if a users standard accountId matches a blinded one */
|
||||
fun accountId(
|
||||
standardAccountId: String,
|
||||
blindedAccountId: String,
|
||||
serverPublicKey: String
|
||||
): Boolean {
|
||||
// Only support generating blinded keys for standard session ids
|
||||
val sessionId = AccountId(standardAccountId)
|
||||
if (sessionId.prefix != IdPrefix.STANDARD) return false
|
||||
// Only support generating blinded keys for standard account ids
|
||||
val accountId = AccountId(standardAccountId)
|
||||
if (accountId.prefix != IdPrefix.STANDARD) return false
|
||||
val blindedId = AccountId(blindedAccountId)
|
||||
if (blindedId.prefix != IdPrefix.BLINDED) return false
|
||||
val k = generateBlindingFactor(serverPublicKey) ?: return false
|
||||
|
||||
// From the session id (ignoring 05 prefix) we have two possible ed25519 pubkeys;
|
||||
// From the account id (ignoring 05 prefix) we have two possible ed25519 pubkeys;
|
||||
// the first is the positive (which is what Signal's XEd25519 conversion always uses)
|
||||
val xEd25519Key = curve.convertToEd25519PublicKey(Key.fromHexString(sessionId.publicKey).asBytes)
|
||||
val xEd25519Key = curve.convertToEd25519PublicKey(Key.fromHexString(accountId.publicKey).asBytes)
|
||||
|
||||
// Blind the positive public key
|
||||
val pk1 = combineKeys(k, xEd25519Key) ?: return false
|
||||
|
||||
@@ -467,9 +467,9 @@ object OnionRequestAPI {
|
||||
x25519PublicKey: String,
|
||||
version: Version = Version.V4
|
||||
): Promise<OnionResponse, Exception> {
|
||||
val url = request.url()
|
||||
val url = request.url
|
||||
val payload = generatePayload(request, server, version)
|
||||
val destination = Destination.Server(url.host(), version.value, x25519PublicKey, url.scheme(), url.port())
|
||||
val destination = Destination.Server(url.host, version.value, x25519PublicKey, url.scheme, url.port)
|
||||
return sendOnionRequest(destination, payload, version).recover { exception ->
|
||||
Log.d("Loki", "Couldn't reach server: $url due to error: $exception.")
|
||||
throw exception
|
||||
@@ -478,7 +478,7 @@ object OnionRequestAPI {
|
||||
|
||||
private fun generatePayload(request: Request, server: String, version: Version): ByteArray {
|
||||
val headers = request.getHeadersForOnionRequest().toMutableMap()
|
||||
val url = request.url()
|
||||
val url = request.url
|
||||
val urlAsString = url.toString()
|
||||
val body = request.getBodyForOnionRequest() ?: "null"
|
||||
val endpoint = when {
|
||||
@@ -486,19 +486,19 @@ object OnionRequestAPI {
|
||||
else -> ""
|
||||
}
|
||||
return if (version == Version.V4) {
|
||||
if (request.body() != null &&
|
||||
if (request.body != null &&
|
||||
headers.keys.find { it.equals("Content-Type", true) } == null) {
|
||||
headers["Content-Type"] = "application/json"
|
||||
}
|
||||
val requestPayload = mapOf(
|
||||
"endpoint" to endpoint,
|
||||
"method" to request.method(),
|
||||
"method" to request.method,
|
||||
"headers" to headers
|
||||
)
|
||||
val requestData = JsonUtil.toJson(requestPayload).toByteArray()
|
||||
val prefixData = "l${requestData.size}:".toByteArray(Charsets.US_ASCII)
|
||||
val suffixData = "e".toByteArray(Charsets.US_ASCII)
|
||||
if (request.body() != null) {
|
||||
if (request.body != null) {
|
||||
val bodyData = if (body is ByteArray) body else body.toString().toByteArray()
|
||||
val bodyLengthData = "${bodyData.size}:".toByteArray(Charsets.US_ASCII)
|
||||
prefixData + requestData + bodyLengthData + bodyData + suffixData
|
||||
@@ -509,7 +509,7 @@ object OnionRequestAPI {
|
||||
val payload = mapOf(
|
||||
"body" to body,
|
||||
"endpoint" to endpoint.removePrefix("/"),
|
||||
"method" to request.method(),
|
||||
"method" to request.method,
|
||||
"headers" to headers
|
||||
)
|
||||
JsonUtil.toJson(payload).toByteArray()
|
||||
|
||||
@@ -9,13 +9,13 @@ import java.util.Locale
|
||||
|
||||
internal fun Request.getHeadersForOnionRequest(): Map<String, Any> {
|
||||
val result = mutableMapOf<String, Any>()
|
||||
val contentType = body()?.contentType()
|
||||
val contentType = body?.contentType()
|
||||
if (contentType != null) {
|
||||
result["content-type"] = contentType.toString()
|
||||
}
|
||||
val headers = headers()
|
||||
val headers = headers
|
||||
for (name in headers.names()) {
|
||||
val value = headers.get(name)
|
||||
val value = headers[name]
|
||||
if (value != null) {
|
||||
if (value.toLowerCase(Locale.US) == "true" || value.toLowerCase(Locale.US) == "false") {
|
||||
result[name] = value.toBoolean()
|
||||
@@ -33,7 +33,7 @@ internal fun Request.getBodyForOnionRequest(): Any? {
|
||||
try {
|
||||
val copyOfThis = newBuilder().build()
|
||||
val buffer = Buffer()
|
||||
val body = copyOfThis.body() ?: return null
|
||||
val body = copyOfThis.body ?: return null
|
||||
body.writeTo(buffer)
|
||||
val bodyAsData = buffer.readByteArray()
|
||||
if (body is MultipartBody) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.session.libsession.utilities
|
||||
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import org.session.libsession.messaging.file_server.FileServerApi
|
||||
import org.session.libsignal.utilities.HTTP
|
||||
import org.session.libsignal.utilities.Log
|
||||
@@ -36,8 +37,8 @@ object DownloadUtilities {
|
||||
*/
|
||||
@JvmStatic
|
||||
fun downloadFile(outputStream: OutputStream, urlAsString: String) {
|
||||
val url = HttpUrl.parse(urlAsString)!!
|
||||
val fileID = url.pathSegments().last()
|
||||
val url = urlAsString.toHttpUrlOrNull()!!
|
||||
val fileID = url.pathSegments.last()
|
||||
try {
|
||||
FileServerApi.download(fileID).get().let {
|
||||
outputStream.write(it)
|
||||
|
||||
@@ -17,9 +17,9 @@ object GroupUtil {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getEncodedOpenGroupInboxID(openGroup: OpenGroup, sessionId: AccountId): Address {
|
||||
fun getEncodedOpenGroupInboxID(openGroup: OpenGroup, accountId: AccountId): Address {
|
||||
val openGroupInboxId =
|
||||
"${openGroup.server}!${openGroup.publicKey}!${sessionId.hexString}".toByteArray()
|
||||
"${openGroup.server}!${openGroup.publicKey}!${accountId.hexString}".toByteArray()
|
||||
return getEncodedOpenGroupInboxID(openGroupInboxId)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.session.libsession.utilities
|
||||
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import org.session.libsession.messaging.open_groups.migrateLegacyServerUrl
|
||||
|
||||
object OpenGroupUrlParser {
|
||||
@@ -19,14 +20,14 @@ object OpenGroupUrlParser {
|
||||
// URL has to start with 'http://'
|
||||
val urlWithPrefix = if (!string.startsWith("http")) "http://$string" else string
|
||||
// If the URL is malformed, throw an exception
|
||||
val url = HttpUrl.parse(urlWithPrefix) ?: throw Error.MalformedURL
|
||||
val url = urlWithPrefix.toHttpUrlOrNull() ?: throw Error.MalformedURL
|
||||
// Parse components
|
||||
val server = HttpUrl.Builder().scheme(url.scheme()).host(url.host()).port(url.port()).build().toString().removeSuffix(suffix).migrateLegacyServerUrl()
|
||||
val room = url.pathSegments().firstOrNull { !it.isNullOrEmpty() } ?: throw Error.NoRoom
|
||||
val server = HttpUrl.Builder().scheme(url.scheme).host(url.host).port(url.port).build().toString().removeSuffix(suffix).migrateLegacyServerUrl()
|
||||
val room = url.pathSegments.firstOrNull { !it.isNullOrEmpty() } ?: throw Error.NoRoom
|
||||
val publicKey = url.queryParameter(queryPrefix) ?: throw Error.NoPublicKey
|
||||
if (publicKey.length != 64) throw Error.InvalidPublicKey
|
||||
// Return
|
||||
return V2OpenGroupInfo(server,room,publicKey)
|
||||
return V2OpenGroupInfo(server, room, publicKey)
|
||||
}
|
||||
|
||||
fun trimQueryParameter(string: String): String {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.session.libsession.utilities
|
||||
|
||||
// String substitution keys for use with the Phrase library.
|
||||
// Note: The substitution will be to {app_name} etc. in the strings - but do NOT include the curly braces in these keys!
|
||||
object StringSubstitutionConstants {
|
||||
const val APP_NAME_KEY = "app_name"
|
||||
const val COMMUNITY_NAME_KEY = "community_name"
|
||||
const val CONVERSATION_COUNT_KEY = "conversation_count"
|
||||
const val CONVERSATION_NAME_KEY = "conversation_name"
|
||||
const val COUNT_KEY = "count"
|
||||
const val DATE_TIME_KEY = "date_time"
|
||||
const val DISAPPEARING_MESSAGES_TYPE_KEY = "disappearing_messages_type"
|
||||
const val DOWNLOAD_URL_KEY = "download_url" // Used to invite people to download Session
|
||||
const val EMOJI_KEY = "emoji"
|
||||
const val FILE_TYPE_KEY = "file_type"
|
||||
const val GROUP_NAME_KEY = "group_name"
|
||||
const val MEMBERS_KEY = "members"
|
||||
const val MESSAGE_COUNT_KEY = "message_count"
|
||||
const val NAME_KEY = "name"
|
||||
const val OTHER_NAME_KEY = "other_name"
|
||||
const val QUERY_KEY = "query"
|
||||
const val SECONDS_KEY = "seconds"
|
||||
const val TOTAL_COUNT_KEY = "total_count"
|
||||
const val TIME_KEY = "time"
|
||||
const val TIME_LARGE_KEY = "time_large"
|
||||
const val TIME_SMALL_KEY = "time_small"
|
||||
const val URL_KEY = "url"
|
||||
const val VERSION_KEY = "version"
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import java.util.concurrent.atomic.AtomicReference
|
||||
* Not really a 'debouncer' but named to be similar to the current Debouncer
|
||||
* designed to queue tasks on a window (if not already queued) like a timer
|
||||
*/
|
||||
class WindowDebouncer(private val window: Long, private val timer: Timer) {
|
||||
class WindowDebouncer(private val timeWindowMilliseconds: Long, private val timer: Timer) {
|
||||
|
||||
private val atomicRef: AtomicReference<Runnable?> = AtomicReference(null)
|
||||
private val hasStarted = AtomicBoolean(false)
|
||||
@@ -23,7 +23,7 @@ class WindowDebouncer(private val window: Long, private val timer: Timer) {
|
||||
|
||||
fun publish(runnable: Runnable) {
|
||||
if (hasStarted.compareAndSet(false, true)) {
|
||||
timer.scheduleAtFixedRate(recursiveRunnable, 0, window)
|
||||
timer.scheduleAtFixedRate(recursiveRunnable, 0, timeWindowMilliseconds)
|
||||
}
|
||||
atomicRef.compareAndSet(null, runnable)
|
||||
}
|
||||
|
||||
@@ -333,11 +333,11 @@ public class Recipient implements RecipientModifiedListener {
|
||||
} else if (isOpenGroupInboxRecipient()){
|
||||
String inboxID = GroupUtil.getDecodedOpenGroupInboxAccountId(accountID);
|
||||
Contact contact = storage.getContactWithAccountID(inboxID);
|
||||
if (contact == null) { return accountID; }
|
||||
if (contact == null) return accountID;
|
||||
return contact.displayName(Contact.ContactContext.REGULAR);
|
||||
} else {
|
||||
Contact contact = storage.getContactWithAccountID(accountID);
|
||||
if (contact == null) { return null; }
|
||||
if (contact == null) return null;
|
||||
return contact.displayName(Contact.ContactContext.REGULAR);
|
||||
}
|
||||
}
|
||||
@@ -513,11 +513,11 @@ public class Recipient implements RecipientModifiedListener {
|
||||
public synchronized String toShortString() {
|
||||
String name = getName();
|
||||
if (name != null) return name;
|
||||
String sessionId = address.serialize();
|
||||
if (sessionId.length() < 4) return sessionId; // so substrings don't throw out of bounds exceptions
|
||||
String accountId = address.serialize();
|
||||
if (accountId.length() < 4) return accountId; // so substrings don't throw out of bounds exceptions
|
||||
int takeAmount = 4;
|
||||
String start = sessionId.substring(0, takeAmount);
|
||||
String end = sessionId.substring(sessionId.length()-takeAmount);
|
||||
String start = accountId.substring(0, takeAmount);
|
||||
String end = accountId.substring(accountId.length()-takeAmount);
|
||||
return start+"..."+end;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
|
||||
<attr name="emoji_tab_strip_background" format="color" />
|
||||
<attr name="emoji_tab_indicator" format="color" />
|
||||
<attr name="emoji_tab_underline" format="color" />
|
||||
<attr name="emoji_tab_seperator" format="color" />
|
||||
<attr name="emoji_drawer_background" format="color" />
|
||||
<attr name="emoji_text_color" format="color" />
|
||||
|
||||
@@ -93,7 +91,6 @@
|
||||
|
||||
<attr name="dialog_info_icon" format="reference" />
|
||||
<attr name="dialog_alert_icon" format="reference" />
|
||||
<attr name="dialog_background_color" format="reference|color" />
|
||||
|
||||
<attr name="conversation_icon_attach_audio" format="reference"/>
|
||||
<attr name="conversation_icon_attach_video" format="reference" />
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
<color name="gray27">#ffbbbbbb</color>
|
||||
<color name="gray50">#ff808080</color>
|
||||
<color name="gray65">#ff595959</color>
|
||||
<color name="gray70">#ff4d4d4d</color>
|
||||
<color name="gray78">#ff383838</color>
|
||||
|
||||
<color name="transparent_black_30">#30000000</color>
|
||||
|
||||
@@ -80,4 +80,10 @@
|
||||
<string name="clearDevice">Clear Device</string>
|
||||
<string name="clearDeviceOnly">Clear device only</string>
|
||||
<string name="clearDeviceAndNetwork">Clear device and network</string>
|
||||
|
||||
<string name="profileDisplayPictureRemoveError">Failed to remove display picture.</string>
|
||||
<string name="profileErrorUpdate">Failed to update profile.</string>
|
||||
|
||||
<!-- Added for SS-40 -->
|
||||
<string name="attachmentsNotification">{emoji} Attachment</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user