mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-30 13:35:18 +00:00
Merge remote-tracking branch 'upstream/dev' into notification_control
This commit is contained in:
commit
285d5a6c22
@ -143,8 +143,8 @@ dependencies {
|
|||||||
testImplementation 'org.robolectric:shadows-multidex:4.2'
|
testImplementation 'org.robolectric:shadows-multidex:4.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
def canonicalVersionCode = 206
|
def canonicalVersionCode = 207
|
||||||
def canonicalVersionName = "1.11.5"
|
def canonicalVersionName = "1.11.6"
|
||||||
|
|
||||||
def postFixSize = 10
|
def postFixSize = 10
|
||||||
def abiPostFix = ['armeabi-v7a' : 1,
|
def abiPostFix = ['armeabi-v7a' : 1,
|
||||||
|
@ -281,6 +281,15 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateSentTimestamp(long messageId, long newTimestamp, long threadId) {
|
||||||
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
|
db.execSQL("UPDATE " + TABLE_NAME + " SET " + DATE_SENT + " = ? " +
|
||||||
|
"WHERE " + ID + " = ?",
|
||||||
|
new String[] {newTimestamp + "", messageId + ""});
|
||||||
|
notifyConversationListeners(threadId);
|
||||||
|
notifyConversationListListeners();
|
||||||
|
}
|
||||||
|
|
||||||
public long getThreadIdForMessage(long id) {
|
public long getThreadIdForMessage(long id) {
|
||||||
String sql = "SELECT " + THREAD_ID + " FROM " + TABLE_NAME + " WHERE " + ID + " = ?";
|
String sql = "SELECT " + THREAD_ID + " FROM " + TABLE_NAME + " WHERE " + ID + " = ?";
|
||||||
String[] sqlArgs = new String[] {id+""};
|
String[] sqlArgs = new String[] {id+""};
|
||||||
|
@ -20,8 +20,6 @@ package org.thoughtcrime.securesms.database;
|
|||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
@ -320,6 +318,15 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateSentTimestamp(long messageId, long newTimestamp, long threadId) {
|
||||||
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
|
db.execSQL("UPDATE " + TABLE_NAME + " SET " + DATE_SENT + " = ? " +
|
||||||
|
"WHERE " + ID + " = ?",
|
||||||
|
new String[] {newTimestamp + "", messageId + ""});
|
||||||
|
notifyConversationListeners(threadId);
|
||||||
|
notifyConversationListListeners();
|
||||||
|
}
|
||||||
|
|
||||||
public Pair<Long, Long> updateBundleMessageBody(long messageId, String body) {
|
public Pair<Long, Long> updateBundleMessageBody(long messageId, String body) {
|
||||||
long type = Types.BASE_INBOX_TYPE | Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT;
|
long type = Types.BASE_INBOX_TYPE | Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT;
|
||||||
return updateMessageBodyAndType(messageId, body, Types.TOTAL_MASK, type);
|
return updateMessageBodyAndType(messageId, body, Types.TOTAL_MASK, type);
|
||||||
|
@ -27,12 +27,11 @@ import org.session.libsignal.messages.SignalServiceGroup
|
|||||||
import org.session.libsignal.utilities.KeyHelper
|
import org.session.libsignal.utilities.KeyHelper
|
||||||
import org.session.libsignal.utilities.guava.Optional
|
import org.session.libsignal.utilities.guava.Optional
|
||||||
import org.thoughtcrime.securesms.ApplicationContext
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
|
|
||||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
||||||
import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob
|
|
||||||
import org.thoughtcrime.securesms.groups.OpenGroupManager
|
import org.thoughtcrime.securesms.groups.OpenGroupManager
|
||||||
import org.thoughtcrime.securesms.util.SessionMetaProtocol
|
import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob
|
||||||
import org.thoughtcrime.securesms.mms.PartAuthority
|
import org.thoughtcrime.securesms.mms.PartAuthority
|
||||||
|
import org.thoughtcrime.securesms.util.SessionMetaProtocol
|
||||||
|
|
||||||
class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), StorageProtocol {
|
class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), StorageProtocol {
|
||||||
|
|
||||||
@ -284,6 +283,21 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||||||
return database.getMessageFor(timestamp, address)?.getId()
|
return database.getMessageFor(timestamp, address)?.getId()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun updateSentTimestamp(
|
||||||
|
messageID: Long,
|
||||||
|
isMms: Boolean,
|
||||||
|
openGroupSentTimestamp: Long,
|
||||||
|
threadId: Long
|
||||||
|
) {
|
||||||
|
if (isMms) {
|
||||||
|
val mmsDb = DatabaseFactory.getMmsDatabase(context)
|
||||||
|
mmsDb.updateSentTimestamp(messageID, openGroupSentTimestamp, threadId)
|
||||||
|
} else {
|
||||||
|
val smsDb = DatabaseFactory.getSmsDatabase(context)
|
||||||
|
smsDb.updateSentTimestamp(messageID, openGroupSentTimestamp, threadId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun markAsSent(timestamp: Long, author: String) {
|
override fun markAsSent(timestamp: Long, author: String) {
|
||||||
val database = DatabaseFactory.getMmsSmsDatabase(context)
|
val database = DatabaseFactory.getMmsSmsDatabase(context)
|
||||||
val messageRecord = database.getMessageFor(timestamp, author) ?: return
|
val messageRecord = database.getMessageFor(timestamp, author) ?: return
|
||||||
|
@ -88,6 +88,7 @@ interface StorageProtocol {
|
|||||||
fun persistAttachments(messageID: Long, attachments: List<Attachment>): List<Long>
|
fun persistAttachments(messageID: Long, attachments: List<Attachment>): List<Long>
|
||||||
fun getAttachmentsForMessage(messageID: Long): List<DatabaseAttachment>
|
fun getAttachmentsForMessage(messageID: Long): List<DatabaseAttachment>
|
||||||
fun getMessageIdInDatabase(timestamp: Long, author: String): Long? // TODO: This is a weird name
|
fun getMessageIdInDatabase(timestamp: Long, author: String): Long? // TODO: This is a weird name
|
||||||
|
fun updateSentTimestamp(messageID: Long, isMms: Boolean, openGroupSentTimestamp: Long, threadId: Long)
|
||||||
fun markAsSending(timestamp: Long, author: String)
|
fun markAsSending(timestamp: Long, author: String)
|
||||||
fun markAsSent(timestamp: Long, author: String)
|
fun markAsSent(timestamp: Long, author: String)
|
||||||
fun markUnidentified(timestamp: Long, author: String)
|
fun markUnidentified(timestamp: Long, author: String)
|
||||||
|
@ -95,7 +95,7 @@ object OpenGroupAPIV2 {
|
|||||||
return RequestBody.create(MediaType.get("application/json"), parametersAsJSON)
|
return RequestBody.create(MediaType.get("application/json"), parametersAsJSON)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun send(request: Request, isJsonRequired: Boolean = true): Promise<Map<*, *>, Exception> {
|
private fun send(request: Request): Promise<Map<*, *>, Exception> {
|
||||||
val url = HttpUrl.parse(request.server) ?: return Promise.ofFail(Error.InvalidURL)
|
val url = HttpUrl.parse(request.server) ?: return Promise.ofFail(Error.InvalidURL)
|
||||||
val urlBuilder = HttpUrl.Builder()
|
val urlBuilder = HttpUrl.Builder()
|
||||||
.scheme(url.scheme())
|
.scheme(url.scheme())
|
||||||
@ -127,7 +127,7 @@ object OpenGroupAPIV2 {
|
|||||||
if (request.useOnionRouting) {
|
if (request.useOnionRouting) {
|
||||||
val publicKey = MessagingModuleConfiguration.shared.storage.getOpenGroupPublicKey(request.server)
|
val publicKey = MessagingModuleConfiguration.shared.storage.getOpenGroupPublicKey(request.server)
|
||||||
?: return Promise.ofFail(Error.NoPublicKey)
|
?: return Promise.ofFail(Error.NoPublicKey)
|
||||||
return OnionRequestAPI.sendOnionRequest(requestBuilder.build(), request.server, publicKey, isJSONRequired = isJsonRequired).fail { e ->
|
return OnionRequestAPI.sendOnionRequest(requestBuilder.build(), request.server, publicKey).fail { e ->
|
||||||
// A 401 means that we didn't provide a (valid) auth token for a route that required one. We use this as an
|
// A 401 means that we didn't provide a (valid) auth token for a route that required one. We use this as an
|
||||||
// indication that the token we're using has expired. Note that a 403 has a different meaning; it means that
|
// indication that the token we're using has expired. Note that a 403 has a different meaning; it means that
|
||||||
// we provided a valid token but it doesn't have a high enough permission level for the route in question.
|
// we provided a valid token but it doesn't have a high enough permission level for the route in question.
|
||||||
|
@ -13,20 +13,19 @@ import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
|||||||
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
||||||
import org.session.libsession.messaging.messages.visible.*
|
import org.session.libsession.messaging.messages.visible.*
|
||||||
import org.session.libsession.messaging.open_groups.*
|
import org.session.libsession.messaging.open_groups.*
|
||||||
import org.session.libsession.utilities.Address
|
|
||||||
import org.session.libsession.messaging.utilities.MessageWrapper
|
import org.session.libsession.messaging.utilities.MessageWrapper
|
||||||
import org.session.libsession.snode.RawResponsePromise
|
import org.session.libsession.snode.RawResponsePromise
|
||||||
import org.session.libsession.snode.SnodeAPI
|
import org.session.libsession.snode.SnodeAPI
|
||||||
import org.session.libsession.snode.SnodeModule
|
|
||||||
import org.session.libsession.snode.SnodeMessage
|
import org.session.libsession.snode.SnodeMessage
|
||||||
|
import org.session.libsession.snode.SnodeModule
|
||||||
|
import org.session.libsession.utilities.Address
|
||||||
import org.session.libsession.utilities.GroupUtil
|
import org.session.libsession.utilities.GroupUtil
|
||||||
import org.session.libsession.utilities.SSKEnvironment
|
import org.session.libsession.utilities.SSKEnvironment
|
||||||
import org.session.libsignal.crypto.PushTransportDetails
|
import org.session.libsignal.crypto.PushTransportDetails
|
||||||
import org.session.libsignal.protos.SignalServiceProtos
|
import org.session.libsignal.protos.SignalServiceProtos
|
||||||
import org.session.libsignal.utilities.hexEncodedPublicKey
|
|
||||||
import org.session.libsignal.utilities.Base64
|
import org.session.libsignal.utilities.Base64
|
||||||
import org.session.libsignal.utilities.Log
|
import org.session.libsignal.utilities.Log
|
||||||
import java.lang.IllegalStateException
|
import org.session.libsignal.utilities.hexEncodedPublicKey
|
||||||
import org.session.libsession.messaging.sending_receiving.attachments.Attachment as SignalAttachment
|
import org.session.libsession.messaging.sending_receiving.attachments.Attachment as SignalAttachment
|
||||||
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview as SignalLinkPreview
|
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview as SignalLinkPreview
|
||||||
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel as SignalQuote
|
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel as SignalQuote
|
||||||
@ -146,7 +145,8 @@ object MessageSender {
|
|||||||
}
|
}
|
||||||
val base64EncodedData = Base64.encodeBytes(wrappedMessage)
|
val base64EncodedData = Base64.encodeBytes(wrappedMessage)
|
||||||
// Send the result
|
// Send the result
|
||||||
val snodeMessage = SnodeMessage(message.recipient!!, base64EncodedData, message.ttl, message.sentTimestamp!!)
|
val timestamp = message.sentTimestamp!! + SnodeAPI.clockOffset
|
||||||
|
val snodeMessage = SnodeMessage(message.recipient!!, base64EncodedData, message.ttl, timestamp)
|
||||||
if (destination is Destination.Contact && message is VisibleMessage && !isSelfSend) {
|
if (destination is Destination.Contact && message is VisibleMessage && !isSelfSend) {
|
||||||
SnodeModule.shared.broadcaster.broadcast("sendingMessage", message.sentTimestamp!!)
|
SnodeModule.shared.broadcaster.broadcast("sendingMessage", message.sentTimestamp!!)
|
||||||
}
|
}
|
||||||
@ -234,7 +234,7 @@ object MessageSender {
|
|||||||
)
|
)
|
||||||
OpenGroupAPIV2.send(openGroupMessage,room,server).success {
|
OpenGroupAPIV2.send(openGroupMessage,room,server).success {
|
||||||
message.openGroupServerMessageID = it.serverID
|
message.openGroupServerMessageID = it.serverID
|
||||||
handleSuccessfulMessageSend(message, destination)
|
handleSuccessfulMessageSend(message, destination, openGroupSentTimestamp = it.sentTimestamp)
|
||||||
deferred.resolve(Unit)
|
deferred.resolve(Unit)
|
||||||
}.fail {
|
}.fail {
|
||||||
handleFailure(it)
|
handleFailure(it)
|
||||||
@ -248,12 +248,17 @@ object MessageSender {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Result Handling
|
// Result Handling
|
||||||
fun handleSuccessfulMessageSend(message: Message, destination: Destination, isSyncMessage: Boolean = false) {
|
fun handleSuccessfulMessageSend(message: Message, destination: Destination, isSyncMessage: Boolean = false, openGroupSentTimestamp: Long = -1) {
|
||||||
val storage = MessagingModuleConfiguration.shared.storage
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
val userPublicKey = storage.getUserPublicKey()!!
|
val userPublicKey = storage.getUserPublicKey()!!
|
||||||
val messageID = storage.getMessageIdInDatabase(message.sentTimestamp!!, message.sender?:userPublicKey) ?: return
|
val messageID = storage.getMessageIdInDatabase(message.sentTimestamp!!, message.sender?:userPublicKey) ?: return
|
||||||
// Ignore future self-sends
|
// Ignore future self-sends
|
||||||
storage.addReceivedMessageTimestamp(message.sentTimestamp!!)
|
storage.addReceivedMessageTimestamp(message.sentTimestamp!!)
|
||||||
|
if (openGroupSentTimestamp != -1L && message is VisibleMessage) {
|
||||||
|
storage.addReceivedMessageTimestamp(openGroupSentTimestamp)
|
||||||
|
storage.updateSentTimestamp(messageID, message.isMediaMessage(), openGroupSentTimestamp, message.threadID!!)
|
||||||
|
message.sentTimestamp = openGroupSentTimestamp
|
||||||
|
}
|
||||||
// Track the open group server message ID
|
// Track the open group server message ID
|
||||||
if (message.openGroupServerMessageID != null && destination is Destination.OpenGroupV2) {
|
if (message.openGroupServerMessageID != null && destination is Destination.OpenGroupV2) {
|
||||||
val encoded = GroupUtil.getEncodedOpenGroupID("${destination.server}.${destination.room}".toByteArray())
|
val encoded = GroupUtil.getEncodedOpenGroupID("${destination.server}.${destination.room}".toByteArray())
|
||||||
|
@ -20,6 +20,8 @@ import org.session.libsignal.crypto.getRandomElementOrNull
|
|||||||
import org.session.libsignal.utilities.Broadcaster
|
import org.session.libsignal.utilities.Broadcaster
|
||||||
import org.session.libsignal.utilities.HTTP
|
import org.session.libsignal.utilities.HTTP
|
||||||
import org.session.libsignal.database.LokiAPIDatabaseProtocol
|
import org.session.libsignal.database.LokiAPIDatabaseProtocol
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
private typealias Path = List<Snode>
|
private typealias Path = List<Snode>
|
||||||
|
|
||||||
@ -306,7 +308,7 @@ object OnionRequestAPI {
|
|||||||
/**
|
/**
|
||||||
* Sends an onion request to `destination`. Builds new paths as needed.
|
* Sends an onion request to `destination`. Builds new paths as needed.
|
||||||
*/
|
*/
|
||||||
private fun sendOnionRequest(destination: Destination, payload: Map<*, *>, isJSONRequired: Boolean = true): Promise<Map<*, *>, Exception> {
|
private fun sendOnionRequest(destination: Destination, payload: Map<*, *>): Promise<Map<*, *>, Exception> {
|
||||||
val deferred = deferred<Map<*, *>, Exception>()
|
val deferred = deferred<Map<*, *>, Exception>()
|
||||||
lateinit var guardSnode: Snode
|
lateinit var guardSnode: Snode
|
||||||
buildOnionForDestination(payload, destination).success { result ->
|
buildOnionForDestination(payload, destination).success { result ->
|
||||||
@ -347,11 +349,12 @@ object OnionRequestAPI {
|
|||||||
body = json["body"] as Map<*, *>
|
body = json["body"] as Map<*, *>
|
||||||
} else {
|
} else {
|
||||||
val bodyAsString = json["body"] as String
|
val bodyAsString = json["body"] as String
|
||||||
if (!isJSONRequired) {
|
|
||||||
body = mapOf( "result" to bodyAsString )
|
|
||||||
} else {
|
|
||||||
body = JsonUtil.fromJson(bodyAsString, Map::class.java)
|
body = JsonUtil.fromJson(bodyAsString, Map::class.java)
|
||||||
}
|
}
|
||||||
|
if (body["t"] != null) {
|
||||||
|
val timestamp = body["t"] as Long
|
||||||
|
val offset = timestamp - Date().time
|
||||||
|
SnodeAPI.clockOffset = offset
|
||||||
}
|
}
|
||||||
if (statusCode != 200) {
|
if (statusCode != 200) {
|
||||||
val exception = HTTPRequestFailedAtDestinationException(statusCode, body, destination.description)
|
val exception = HTTPRequestFailedAtDestinationException(statusCode, body, destination.description)
|
||||||
@ -455,7 +458,7 @@ object OnionRequestAPI {
|
|||||||
*
|
*
|
||||||
* `publicKey` is the hex encoded public key of the user the call is associated with. This is needed for swarm cache maintenance.
|
* `publicKey` is the hex encoded public key of the user the call is associated with. This is needed for swarm cache maintenance.
|
||||||
*/
|
*/
|
||||||
fun sendOnionRequest(request: Request, server: String, x25519PublicKey: String, target: String = "/loki/v3/lsrpc", isJSONRequired: Boolean = true): Promise<Map<*, *>, Exception> {
|
fun sendOnionRequest(request: Request, server: String, x25519PublicKey: String, target: String = "/loki/v3/lsrpc"): Promise<Map<*, *>, Exception> {
|
||||||
val headers = request.getHeadersForOnionRequest()
|
val headers = request.getHeadersForOnionRequest()
|
||||||
val url = request.url()
|
val url = request.url()
|
||||||
val urlAsString = url.toString()
|
val urlAsString = url.toString()
|
||||||
@ -472,7 +475,7 @@ object OnionRequestAPI {
|
|||||||
"headers" to headers
|
"headers" to headers
|
||||||
)
|
)
|
||||||
val destination = Destination.Server(host, target, x25519PublicKey, url.scheme(), url.port())
|
val destination = Destination.Server(host, target, x25519PublicKey, url.scheme(), url.port())
|
||||||
return sendOnionRequest(destination, payload, isJSONRequired).recover { exception ->
|
return sendOnionRequest(destination, payload).recover { exception ->
|
||||||
Log.d("Loki", "Couldn't reach server: $urlAsString due to error: $exception.")
|
Log.d("Loki", "Couldn't reach server: $urlAsString due to error: $exception.")
|
||||||
throw exception
|
throw exception
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,6 @@ import kotlin.Pair
|
|||||||
|
|
||||||
object SnodeAPI {
|
object SnodeAPI {
|
||||||
private val sodium by lazy { LazySodiumAndroid(SodiumAndroid()) }
|
private val sodium by lazy { LazySodiumAndroid(SodiumAndroid()) }
|
||||||
|
|
||||||
private val database: LokiAPIDatabaseProtocol
|
private val database: LokiAPIDatabaseProtocol
|
||||||
get() = SnodeModule.shared.storage
|
get() = SnodeModule.shared.storage
|
||||||
private val broadcaster: Broadcaster
|
private val broadcaster: Broadcaster
|
||||||
@ -38,6 +37,11 @@ object SnodeAPI {
|
|||||||
internal var snodePool: Set<Snode>
|
internal var snodePool: Set<Snode>
|
||||||
get() = database.getSnodePool()
|
get() = database.getSnodePool()
|
||||||
set(newValue) { database.setSnodePool(newValue) }
|
set(newValue) { database.setSnodePool(newValue) }
|
||||||
|
/**
|
||||||
|
* The offset between the user's clock and the Service Node's clock. Used in cases where the
|
||||||
|
* user's clock is incorrect.
|
||||||
|
*/
|
||||||
|
internal var clockOffset = 0L
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
private val maxRetryCount = 6
|
private val maxRetryCount = 6
|
||||||
|
Loading…
Reference in New Issue
Block a user