mirror of
https://github.com/oxen-io/session-android.git
synced 2025-01-12 11:53:38 +00:00
Update attachment download handling
This commit is contained in:
parent
1a82238a44
commit
c10e96dd91
@ -73,7 +73,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun setUserProfilePictureURL(newValue: String) {
|
override fun setUserProfilePictureURL(newValue: String) {
|
||||||
val ourRecipient = Address.fromSerialized(getUserPublicKey()!!).let {
|
val ourRecipient = fromSerialized(getUserPublicKey()!!).let {
|
||||||
Recipient.from(context, it, false)
|
Recipient.from(context, it, false)
|
||||||
}
|
}
|
||||||
TextSecurePreferences.setProfilePictureURL(context, newValue)
|
TextSecurePreferences.setProfilePictureURL(context, newValue)
|
||||||
@ -103,7 +103,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||||||
|
|
||||||
override fun persist(message: VisibleMessage, quotes: QuoteModel?, linkPreview: List<LinkPreview?>, groupPublicKey: String?, openGroupID: String?, attachments: List<Attachment>): Long? {
|
override fun persist(message: VisibleMessage, quotes: QuoteModel?, linkPreview: List<LinkPreview?>, groupPublicKey: String?, openGroupID: String?, attachments: List<Attachment>): Long? {
|
||||||
var messageID: Long? = null
|
var messageID: Long? = null
|
||||||
val senderAddress = Address.fromSerialized(message.sender!!)
|
val senderAddress = fromSerialized(message.sender!!)
|
||||||
val isUserSender = (message.sender!! == getUserPublicKey())
|
val isUserSender = (message.sender!! == getUserPublicKey())
|
||||||
val group: Optional<SignalServiceGroup> = when {
|
val group: Optional<SignalServiceGroup> = when {
|
||||||
openGroupID != null -> Optional.of(SignalServiceGroup(openGroupID.toByteArray(), SignalServiceGroup.GroupType.PUBLIC_CHAT))
|
openGroupID != null -> Optional.of(SignalServiceGroup(openGroupID.toByteArray(), SignalServiceGroup.GroupType.PUBLIC_CHAT))
|
||||||
@ -117,9 +117,9 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||||||
it.toSignalAttachment()
|
it.toSignalAttachment()
|
||||||
}
|
}
|
||||||
val targetAddress = if (isUserSender && !message.syncTarget.isNullOrEmpty()) {
|
val targetAddress = if (isUserSender && !message.syncTarget.isNullOrEmpty()) {
|
||||||
Address.fromSerialized(message.syncTarget!!)
|
fromSerialized(message.syncTarget!!)
|
||||||
} else if (group.isPresent) {
|
} else if (group.isPresent) {
|
||||||
Address.fromSerialized(GroupUtil.getEncodedId(group.get()))
|
fromSerialized(GroupUtil.getEncodedId(group.get()))
|
||||||
} else {
|
} else {
|
||||||
senderAddress
|
senderAddress
|
||||||
}
|
}
|
||||||
@ -291,6 +291,16 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||||||
return getAllOpenGroups().values.firstOrNull { it.server == server && it.room == room }
|
return getAllOpenGroups().values.firstOrNull { it.server == server && it.room == room }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun updateOpenGroupCapabilities(server: String, capabilities: List<String>) {
|
||||||
|
getAllOpenGroups().values.filter { it.server == server }
|
||||||
|
.map { it.copy(capabilities = it.capabilities) }
|
||||||
|
.forEach(this::updateOpenGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getOpenGroupServer(server: String): List<String> {
|
||||||
|
return getAllOpenGroups().values.firstOrNull { it.server == server }?.capabilities ?: emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
override fun isDuplicateMessage(timestamp: Long): Boolean {
|
override fun isDuplicateMessage(timestamp: Long): Boolean {
|
||||||
return getReceivedMessageTimestamps().contains(timestamp)
|
return getReceivedMessageTimestamps().contains(timestamp)
|
||||||
}
|
}
|
||||||
@ -317,7 +327,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||||||
|
|
||||||
override fun getMessageIdInDatabase(timestamp: Long, author: String): Long? {
|
override fun getMessageIdInDatabase(timestamp: Long, author: String): Long? {
|
||||||
val database = DatabaseComponent.get(context).mmsSmsDatabase()
|
val database = DatabaseComponent.get(context).mmsSmsDatabase()
|
||||||
val address = Address.fromSerialized(author)
|
val address = fromSerialized(author)
|
||||||
return database.getMessageFor(timestamp, address)?.getId()
|
return database.getMessageFor(timestamp, address)?.getId()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,7 +445,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||||||
|
|
||||||
override fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type: SignalServiceGroup.Type, name: String, members: Collection<String>, admins: Collection<String>, sentTimestamp: Long) {
|
override fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type: SignalServiceGroup.Type, name: String, members: Collection<String>, admins: Collection<String>, sentTimestamp: Long) {
|
||||||
val group = SignalServiceGroup(type, GroupUtil.getDecodedGroupIDAsData(groupID), SignalServiceGroup.GroupType.SIGNAL, name, members.toList(), null, admins.toList())
|
val group = SignalServiceGroup(type, GroupUtil.getDecodedGroupIDAsData(groupID), SignalServiceGroup.GroupType.SIGNAL, name, members.toList(), null, admins.toList())
|
||||||
val m = IncomingTextMessage(Address.fromSerialized(senderPublicKey), 1, sentTimestamp, "", Optional.of(group), 0, true)
|
val m = IncomingTextMessage(fromSerialized(senderPublicKey), 1, sentTimestamp, "", Optional.of(group), 0, true)
|
||||||
val updateData = UpdateMessageData.buildGroupUpdate(type, name, members)?.toJSON()
|
val updateData = UpdateMessageData.buildGroupUpdate(type, name, members)?.toJSON()
|
||||||
val infoMessage = IncomingGroupMessage(m, groupID, updateData, true)
|
val infoMessage = IncomingGroupMessage(m, groupID, updateData, true)
|
||||||
val smsDB = DatabaseComponent.get(context).smsDatabase()
|
val smsDB = DatabaseComponent.get(context).smsDatabase()
|
||||||
@ -444,7 +454,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||||||
|
|
||||||
override fun insertOutgoingInfoMessage(context: Context, groupID: String, type: SignalServiceGroup.Type, name: String, members: Collection<String>, admins: Collection<String>, threadID: Long, sentTimestamp: Long) {
|
override fun insertOutgoingInfoMessage(context: Context, groupID: String, type: SignalServiceGroup.Type, name: String, members: Collection<String>, admins: Collection<String>, threadID: Long, sentTimestamp: Long) {
|
||||||
val userPublicKey = getUserPublicKey()
|
val userPublicKey = getUserPublicKey()
|
||||||
val recipient = Recipient.from(context, Address.fromSerialized(groupID), false)
|
val recipient = Recipient.from(context, fromSerialized(groupID), false)
|
||||||
|
|
||||||
val updateData = UpdateMessageData.buildGroupUpdate(type, name, members)?.toJSON() ?: ""
|
val updateData = UpdateMessageData.buildGroupUpdate(type, name, members)?.toJSON() ?: ""
|
||||||
val infoMessage = OutgoingGroupMediaMessage(recipient, updateData, groupID, null, sentTimestamp, 0, true, null, listOf(), listOf())
|
val infoMessage = OutgoingGroupMediaMessage(recipient, updateData, groupID, null, sentTimestamp, 0, true, null, listOf(), listOf())
|
||||||
@ -457,7 +467,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||||||
|
|
||||||
override fun isClosedGroup(publicKey: String): Boolean {
|
override fun isClosedGroup(publicKey: String): Boolean {
|
||||||
val isClosedGroup = DatabaseComponent.get(context).lokiAPIDatabase().isClosedGroup(publicKey)
|
val isClosedGroup = DatabaseComponent.get(context).lokiAPIDatabase().isClosedGroup(publicKey)
|
||||||
val address = Address.fromSerialized(publicKey)
|
val address = fromSerialized(publicKey)
|
||||||
return address.isClosedGroup || isClosedGroup
|
return address.isClosedGroup || isClosedGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,6 +524,10 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||||||
return DatabaseComponent.get(context).lokiThreadDatabase().getAllOpenGroups()
|
return DatabaseComponent.get(context).lokiThreadDatabase().getAllOpenGroups()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun updateOpenGroup(openGroup: OpenGroup) {
|
||||||
|
OpenGroupManager.updateOpenGroup(openGroup, context)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getAllGroups(): List<GroupRecord> {
|
override fun getAllGroups(): List<GroupRecord> {
|
||||||
return DatabaseComponent.get(context).groupDatabase().allGroups
|
return DatabaseComponent.get(context).groupDatabase().allGroups
|
||||||
}
|
}
|
||||||
@ -534,20 +548,20 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||||||
|
|
||||||
override fun getOrCreateThreadIdFor(publicKey: String, groupPublicKey: String?, openGroupID: String?): Long {
|
override fun getOrCreateThreadIdFor(publicKey: String, groupPublicKey: String?, openGroupID: String?): Long {
|
||||||
val database = DatabaseComponent.get(context).threadDatabase()
|
val database = DatabaseComponent.get(context).threadDatabase()
|
||||||
if (!openGroupID.isNullOrEmpty()) {
|
return if (!openGroupID.isNullOrEmpty()) {
|
||||||
val recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedOpenGroupID(openGroupID.toByteArray())), false)
|
val recipient = Recipient.from(context, fromSerialized(GroupUtil.getEncodedOpenGroupID(openGroupID.toByteArray())), false)
|
||||||
return database.getThreadIdIfExistsFor(recipient)
|
database.getThreadIdIfExistsFor(recipient)
|
||||||
} else if (!groupPublicKey.isNullOrEmpty()) {
|
} else if (!groupPublicKey.isNullOrEmpty()) {
|
||||||
val recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.doubleEncodeGroupID(groupPublicKey)), false)
|
val recipient = Recipient.from(context, fromSerialized(GroupUtil.doubleEncodeGroupID(groupPublicKey)), false)
|
||||||
return database.getOrCreateThreadIdFor(recipient)
|
database.getOrCreateThreadIdFor(recipient)
|
||||||
} else {
|
} else {
|
||||||
val recipient = Recipient.from(context, Address.fromSerialized(publicKey), false)
|
val recipient = Recipient.from(context, fromSerialized(publicKey), false)
|
||||||
return database.getOrCreateThreadIdFor(recipient)
|
database.getOrCreateThreadIdFor(recipient)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getThreadId(publicKeyOrOpenGroupID: String): Long? {
|
override fun getThreadId(publicKeyOrOpenGroupID: String): Long? {
|
||||||
val address = Address.fromSerialized(publicKeyOrOpenGroupID)
|
val address = fromSerialized(publicKeyOrOpenGroupID)
|
||||||
return getThreadId(address)
|
return getThreadId(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,7 +609,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||||||
val recipientDatabase = DatabaseComponent.get(context).recipientDatabase()
|
val recipientDatabase = DatabaseComponent.get(context).recipientDatabase()
|
||||||
val threadDatabase = DatabaseComponent.get(context).threadDatabase()
|
val threadDatabase = DatabaseComponent.get(context).threadDatabase()
|
||||||
for (contact in contacts) {
|
for (contact in contacts) {
|
||||||
val address = Address.fromSerialized(contact.publicKey)
|
val address = fromSerialized(contact.publicKey)
|
||||||
val recipient = Recipient.from(context, address, true)
|
val recipient = Recipient.from(context, address, true)
|
||||||
if (!contact.profilePicture.isNullOrEmpty()) {
|
if (!contact.profilePicture.isNullOrEmpty()) {
|
||||||
recipientDatabase.setProfileAvatar(recipient, contact.profilePicture)
|
recipientDatabase.setProfileAvatar(recipient, contact.profilePicture)
|
||||||
@ -725,11 +739,11 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun setLastInboxMessageId(server: String, messageId: Long) {
|
override fun setLastInboxMessageId(server: String, messageId: Long) {
|
||||||
// TODO("Not yet implemented")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun removeLastInboxMessageId(server: String) {
|
override fun removeLastInboxMessageId(server: String) {
|
||||||
// TODO("Not yet implemented")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getLastOutboxMessageId(server: String): Long? {
|
override fun getLastOutboxMessageId(server: String): Long? {
|
||||||
@ -737,11 +751,11 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun setLastOutboxMessageId(server: String, messageId: Long) {
|
override fun setLastOutboxMessageId(server: String, messageId: Long) {
|
||||||
// TODO("Not yet implemented")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun removeLastOutboxMessageId(server: String) {
|
override fun removeLastOutboxMessageId(server: String) {
|
||||||
// TODO("Not yet implemented")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -124,4 +124,11 @@ object OpenGroupManager {
|
|||||||
val publicKey = url.queryParameter("public_key") ?: return
|
val publicKey = url.queryParameter("public_key") ?: return
|
||||||
add(server.toString().removeSuffix("/"), room, publicKey, context)
|
add(server.toString().removeSuffix("/"), room, publicKey, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateOpenGroup(openGroup: OpenGroup, context: Context) {
|
||||||
|
val threadDB = DatabaseComponent.get(context).lokiThreadDatabase()
|
||||||
|
val openGroupID = "${openGroup.server}.${openGroup.room}"
|
||||||
|
val threadID = GroupManager.getOpenGroupThreadID(openGroupID, context)
|
||||||
|
threadDB.setOpenGroupChat(openGroup, threadID)
|
||||||
|
}
|
||||||
}
|
}
|
@ -55,10 +55,13 @@ interface StorageProtocol {
|
|||||||
|
|
||||||
// Open Groups
|
// Open Groups
|
||||||
fun getAllOpenGroups(): Map<Long, OpenGroup>
|
fun getAllOpenGroups(): Map<Long, OpenGroup>
|
||||||
|
fun updateOpenGroup(openGroup: OpenGroup)
|
||||||
fun getOpenGroup(threadId: Long): OpenGroup?
|
fun getOpenGroup(threadId: Long): OpenGroup?
|
||||||
fun addOpenGroup(urlAsString: String)
|
fun addOpenGroup(urlAsString: String)
|
||||||
fun setOpenGroupServerMessageID(messageID: Long, serverID: Long, threadID: Long, isSms: Boolean)
|
fun setOpenGroupServerMessageID(messageID: Long, serverID: Long, threadID: Long, isSms: Boolean)
|
||||||
fun getOpenGroup(room: String, server: String): OpenGroup?
|
fun getOpenGroup(room: String, server: String): OpenGroup?
|
||||||
|
fun updateOpenGroupCapabilities(server: String, capabilities: List<String>)
|
||||||
|
fun getOpenGroupServer(server: String): List<String>
|
||||||
|
|
||||||
// Open Group Public Keys
|
// Open Group Public Keys
|
||||||
fun getOpenGroupPublicKey(server: String): String?
|
fun getOpenGroupPublicKey(server: String): String?
|
||||||
|
@ -87,14 +87,22 @@ object FileServerApi {
|
|||||||
fun upload(file: ByteArray): Promise<Long, Exception> {
|
fun upload(file: ByteArray): Promise<Long, Exception> {
|
||||||
val base64EncodedFile = Base64.encodeBytes(file)
|
val base64EncodedFile = Base64.encodeBytes(file)
|
||||||
val parameters = mapOf( "file" to base64EncodedFile )
|
val parameters = mapOf( "file" to base64EncodedFile )
|
||||||
val request = Request(verb = HTTP.Verb.POST, endpoint = "files", parameters = parameters)
|
val request = Request(
|
||||||
|
verb = HTTP.Verb.POST,
|
||||||
|
endpoint = "file",
|
||||||
|
parameters = parameters,
|
||||||
|
headers = mapOf(
|
||||||
|
"Content-Disposition" to "attachment",
|
||||||
|
"Content-Type" to "application/octet-stream"
|
||||||
|
)
|
||||||
|
)
|
||||||
return send(request).map { json ->
|
return send(request).map { json ->
|
||||||
json["result"] as? Long ?: throw OpenGroupApi.Error.ParsingFailed
|
json["result"] as? Long ?: throw OpenGroupApi.Error.ParsingFailed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun download(file: Long): Promise<ByteArray, Exception> {
|
fun download(file: Long): Promise<ByteArray, Exception> {
|
||||||
val request = Request(verb = HTTP.Verb.GET, endpoint = "files/$file")
|
val request = Request(verb = HTTP.Verb.GET, endpoint = "file/$file")
|
||||||
return send(request).map { json ->
|
return send(request).map { json ->
|
||||||
val base64EncodedFile = json["result"] as? String ?: throw Error.ParsingFailed
|
val base64EncodedFile = json["result"] as? String ?: throw Error.ParsingFailed
|
||||||
Base64.decode(base64EncodedFile) ?: throw Error.ParsingFailed
|
Base64.decode(base64EncodedFile) ?: throw Error.ParsingFailed
|
||||||
|
@ -100,7 +100,7 @@ class AttachmentUploadJob(val attachmentID: Long, val threadID: String, val mess
|
|||||||
val id = upload(data).get()
|
val id = upload(data).get()
|
||||||
val digest = drb.transmittedDigest
|
val digest = drb.transmittedDigest
|
||||||
// Return
|
// Return
|
||||||
return Pair(key, UploadResult(id, "${server}/files/$id", digest))
|
return Pair(key, UploadResult(id, "${server}/file/$id", digest))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSuccess(attachment: SignalServiceAttachmentStream, attachmentKey: ByteArray, uploadResult: UploadResult) {
|
private fun handleSuccess(attachment: SignalServiceAttachmentStream, attachmentKey: ByteArray, uploadResult: UploadResult) {
|
||||||
|
@ -16,8 +16,7 @@ sealed class Endpoint(val value: String) {
|
|||||||
|
|
||||||
// Messages
|
// Messages
|
||||||
|
|
||||||
data class RoomMessage(val roomToken: String) :
|
data class RoomMessage(val roomToken: String) : Endpoint("room/$roomToken/message")
|
||||||
Endpoint("room/$roomToken/message")
|
|
||||||
|
|
||||||
data class RoomMessageIndividual(val roomToken: String, val messageId: Long) :
|
data class RoomMessageIndividual(val roomToken: String, val messageId: Long) :
|
||||||
Endpoint("room/$roomToken/message/$messageId")
|
Endpoint("room/$roomToken/message/$messageId")
|
||||||
@ -42,8 +41,7 @@ sealed class Endpoint(val value: String) {
|
|||||||
data class RoomUnpinMessage(val roomToken: String, val messageId: Long) :
|
data class RoomUnpinMessage(val roomToken: String, val messageId: Long) :
|
||||||
Endpoint("room/$roomToken/unpin/$messageId")
|
Endpoint("room/$roomToken/unpin/$messageId")
|
||||||
|
|
||||||
data class RoomUnpinAll(val roomToken: String) :
|
data class RoomUnpinAll(val roomToken: String) : Endpoint("room/$roomToken/unpin/all")
|
||||||
Endpoint("room/$roomToken/unpin/all")
|
|
||||||
|
|
||||||
// Files
|
// Files
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.type.TypeFactory
|
|||||||
import com.goterl.lazysodium.LazySodiumAndroid
|
import com.goterl.lazysodium.LazySodiumAndroid
|
||||||
import com.goterl.lazysodium.SodiumAndroid
|
import com.goterl.lazysodium.SodiumAndroid
|
||||||
import com.goterl.lazysodium.interfaces.GenericHash
|
import com.goterl.lazysodium.interfaces.GenericHash
|
||||||
|
import com.goterl.lazysodium.interfaces.Sign
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import nl.komponents.kovenant.Promise
|
import nl.komponents.kovenant.Promise
|
||||||
@ -166,8 +167,8 @@ object OpenGroupApi {
|
|||||||
val whisper: Boolean = false,
|
val whisper: Boolean = false,
|
||||||
val whisper_mods: String = "",
|
val whisper_mods: String = "",
|
||||||
val whisper_to: String = "",
|
val whisper_to: String = "",
|
||||||
val data: String = "",
|
val data: String? = null,
|
||||||
val signature: String = ""
|
val signature: String? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
data class MessageDeletion(
|
data class MessageDeletion(
|
||||||
@ -194,8 +195,7 @@ object OpenGroupApi {
|
|||||||
* Always `true` under normal circumstances. You might want to disable
|
* Always `true` under normal circumstances. You might want to disable
|
||||||
* this when running over Lokinet.
|
* this when running over Lokinet.
|
||||||
*/
|
*/
|
||||||
val useOnionRouting: Boolean = true,
|
val useOnionRouting: Boolean = true
|
||||||
val isBlinded: Boolean = true
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun createBody(parameters: Any?): RequestBody? {
|
private fun createBody(parameters: Any?): RequestBody? {
|
||||||
@ -223,6 +223,7 @@ object OpenGroupApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun execute(): Promise<OnionResponse, Exception> {
|
fun execute(): Promise<OnionResponse, Exception> {
|
||||||
|
val serverCapabilities = MessagingModuleConfiguration.shared.storage.getOpenGroupServer(request.server)
|
||||||
val publicKey =
|
val publicKey =
|
||||||
MessagingModuleConfiguration.shared.storage.getOpenGroupPublicKey(request.server)
|
MessagingModuleConfiguration.shared.storage.getOpenGroupPublicKey(request.server)
|
||||||
?: return Promise.ofFail(Error.NoPublicKey)
|
?: return Promise.ofFail(Error.NoPublicKey)
|
||||||
@ -233,32 +234,33 @@ object OpenGroupApi {
|
|||||||
val nonce = sodium.nonce(16)
|
val nonce = sodium.nonce(16)
|
||||||
val timestamp = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())
|
val timestamp = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())
|
||||||
var pubKey = ""
|
var pubKey = ""
|
||||||
var signature = ByteArray(0)
|
var signature = ByteArray(Sign.BYTES)
|
||||||
if (request.isBlinded) {
|
var bodyHash = ByteArray(0)
|
||||||
|
if (request.parameters != null) {
|
||||||
|
val parameterBytes = JsonUtil.toJson(request.parameters).toByteArray()
|
||||||
|
val parameterHash = ByteArray(GenericHash.BYTES_MAX)
|
||||||
|
if (sodium.cryptoGenericHash(
|
||||||
|
parameterHash,
|
||||||
|
parameterHash.size,
|
||||||
|
parameterBytes,
|
||||||
|
parameterBytes.size.toLong()
|
||||||
|
)) {
|
||||||
|
bodyHash = parameterHash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val messageBytes = Hex.fromStringCondensed(publicKey)
|
||||||
|
.plus(nonce)
|
||||||
|
.plus("$timestamp".toByteArray(Charsets.US_ASCII))
|
||||||
|
.plus(request.verb.rawValue.toByteArray())
|
||||||
|
.plus(urlRequest.encodedPath().toByteArray())
|
||||||
|
.plus(bodyHash)
|
||||||
|
if (serverCapabilities.contains("blind")) {
|
||||||
SodiumUtilities.blindedKeyPair(publicKey, ed25519KeyPair)?.let { keyPair ->
|
SodiumUtilities.blindedKeyPair(publicKey, ed25519KeyPair)?.let { keyPair ->
|
||||||
pubKey = SodiumUtilities.SessionId(
|
pubKey = SodiumUtilities.SessionId(
|
||||||
SodiumUtilities.IdPrefix.BLINDED,
|
SodiumUtilities.IdPrefix.BLINDED,
|
||||||
keyPair.publicKey.asBytes
|
keyPair.publicKey.asBytes
|
||||||
).hexString
|
).hexString
|
||||||
var bodyHash = ByteArray(0)
|
|
||||||
if (request.parameters != null) {
|
|
||||||
val parameterBytes = JsonUtil.toJson(request.parameters).toByteArray()
|
|
||||||
val parameterHash = ByteArray(GenericHash.BYTES_MAX)
|
|
||||||
if (sodium.cryptoGenericHash(
|
|
||||||
parameterHash,
|
|
||||||
parameterHash.size,
|
|
||||||
parameterBytes,
|
|
||||||
parameterBytes.size.toLong()
|
|
||||||
)) {
|
|
||||||
bodyHash = parameterHash
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val messageBytes = Hex.fromStringCondensed(publicKey)
|
|
||||||
.plus(nonce)
|
|
||||||
.plus("$timestamp".toByteArray(Charsets.US_ASCII))
|
|
||||||
.plus(request.verb.rawValue.toByteArray())
|
|
||||||
.plus(urlRequest.encodedPath().toByteArray())
|
|
||||||
.plus(bodyHash)
|
|
||||||
signature = SodiumUtilities.sogsSignature(
|
signature = SodiumUtilities.sogsSignature(
|
||||||
messageBytes,
|
messageBytes,
|
||||||
ed25519KeyPair.secretKey.asBytes,
|
ed25519KeyPair.secretKey.asBytes,
|
||||||
@ -271,7 +273,7 @@ object OpenGroupApi {
|
|||||||
SodiumUtilities.IdPrefix.UN_BLINDED,
|
SodiumUtilities.IdPrefix.UN_BLINDED,
|
||||||
ed25519KeyPair.publicKey.asBytes
|
ed25519KeyPair.publicKey.asBytes
|
||||||
).hexString
|
).hexString
|
||||||
signature = ByteArray(0)
|
sodium.cryptoSignDetached(signature, messageBytes, messageBytes.size.toLong(), ed25519KeyPair.secretKey.asBytes)
|
||||||
}
|
}
|
||||||
headers["X-SOGS-Nonce"] = encodeBytes(nonce)
|
headers["X-SOGS-Nonce"] = encodeBytes(nonce)
|
||||||
headers["X-SOGS-Timestamp"] = "$timestamp"
|
headers["X-SOGS-Timestamp"] = "$timestamp"
|
||||||
@ -330,7 +332,12 @@ object OpenGroupApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun download(fileId: Long, room: String, server: String): Promise<ByteArray, Exception> {
|
fun download(fileId: Long, room: String, server: String): Promise<ByteArray, Exception> {
|
||||||
val request = Request(verb = GET, room = room, server = server, endpoint = Endpoint.FileIndividual(fileId))
|
val request = Request(
|
||||||
|
verb = GET,
|
||||||
|
room = room,
|
||||||
|
server = server,
|
||||||
|
endpoint = Endpoint.RoomFileIndividual(room, fileId)
|
||||||
|
)
|
||||||
return send(request).map { it.body ?: throw Error.ParsingFailed }
|
return send(request).map { it.body ?: throw Error.ParsingFailed }
|
||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
@ -415,7 +422,7 @@ object OpenGroupApi {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun deleteMessage(serverID: Long, room: String, server: String): Promise<Unit, Exception> {
|
fun deleteMessage(serverID: Long, room: String, server: String): Promise<Unit, Exception> {
|
||||||
val request =
|
val request =
|
||||||
Request(verb = DELETE, room = room, server = server, endpoint = "messages/$serverID")
|
Request(verb = DELETE, room = room, server = server, endpoint = Endpoint.RoomMessageIndividual(room, serverID))
|
||||||
return send(request).map {
|
return send(request).map {
|
||||||
Log.d("Loki", "Message deletion successful.")
|
Log.d("Loki", "Message deletion successful.")
|
||||||
}
|
}
|
||||||
@ -568,49 +575,51 @@ object OpenGroupApi {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
requests.add(
|
val serverCapabilities = storage.getOpenGroupServer(server)
|
||||||
if (lastInboxMessageId == null) {
|
if (serverCapabilities.contains("blind")) {
|
||||||
BatchRequestInfo(
|
requests.add(
|
||||||
request = BatchRequest(
|
if (lastInboxMessageId == null) {
|
||||||
method = "GET",
|
BatchRequestInfo(
|
||||||
path = "/inbox"
|
request = BatchRequest(
|
||||||
),
|
method = "GET",
|
||||||
endpoint = Endpoint.Inbox,
|
path = "/inbox"
|
||||||
responseType = object : TypeReference<List<DirectMessage>>() {}
|
),
|
||||||
)
|
endpoint = Endpoint.Inbox,
|
||||||
} else {
|
responseType = object : TypeReference<List<DirectMessage>>() {}
|
||||||
BatchRequestInfo(
|
)
|
||||||
request = BatchRequest(
|
} else {
|
||||||
method = "GET",
|
BatchRequestInfo(
|
||||||
path = "/inbox/since/$lastInboxMessageId"
|
request = BatchRequest(
|
||||||
),
|
method = "GET",
|
||||||
endpoint = Endpoint.InboxSince(lastInboxMessageId),
|
path = "/inbox/since/$lastInboxMessageId"
|
||||||
responseType = object : TypeReference<List<DirectMessage>>() {}
|
),
|
||||||
)
|
endpoint = Endpoint.InboxSince(lastInboxMessageId),
|
||||||
}
|
responseType = object : TypeReference<List<DirectMessage>>() {}
|
||||||
)
|
)
|
||||||
requests.add(
|
}
|
||||||
if (lastOutboxMessageId == null) {
|
)
|
||||||
BatchRequestInfo(
|
requests.add(
|
||||||
request = BatchRequest(
|
if (lastOutboxMessageId == null) {
|
||||||
method = "GET",
|
BatchRequestInfo(
|
||||||
path = "/outbox"
|
request = BatchRequest(
|
||||||
),
|
method = "GET",
|
||||||
endpoint = Endpoint.Outbox,
|
path = "/outbox"
|
||||||
responseType = object : TypeReference<List<DirectMessage>>() {}
|
),
|
||||||
)
|
endpoint = Endpoint.Outbox,
|
||||||
} else {
|
responseType = object : TypeReference<List<DirectMessage>>() {}
|
||||||
BatchRequestInfo(
|
)
|
||||||
request = BatchRequest(
|
} else {
|
||||||
method = "GET",
|
BatchRequestInfo(
|
||||||
path = "/outbox/since/$lastOutboxMessageId"
|
request = BatchRequest(
|
||||||
),
|
method = "GET",
|
||||||
endpoint = Endpoint.OutboxSince(lastOutboxMessageId),
|
path = "/outbox/since/$lastOutboxMessageId"
|
||||||
responseType = object : TypeReference<List<DirectMessage>>() {}
|
),
|
||||||
)
|
endpoint = Endpoint.OutboxSince(lastOutboxMessageId),
|
||||||
}
|
responseType = object : TypeReference<List<DirectMessage>>() {}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
return parallelBatch(server, requests)
|
return parallelBatch(server, requests)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -666,7 +675,7 @@ object OpenGroupApi {
|
|||||||
fun getDefaultRoomsIfNeeded(): Promise<List<DefaultGroup>, Exception> {
|
fun getDefaultRoomsIfNeeded(): Promise<List<DefaultGroup>, Exception> {
|
||||||
val storage = MessagingModuleConfiguration.shared.storage
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
storage.setOpenGroupPublicKey(defaultServer, defaultServerPublicKey)
|
storage.setOpenGroupPublicKey(defaultServer, defaultServerPublicKey)
|
||||||
return getAllRooms(defaultServer).map { groups ->
|
return getAllRooms().map { groups ->
|
||||||
val earlyGroups = groups.map { group ->
|
val earlyGroups = groups.map { group ->
|
||||||
DefaultGroup(group.token, group.name, null)
|
DefaultGroup(group.token, group.name, null)
|
||||||
}
|
}
|
||||||
@ -705,11 +714,11 @@ object OpenGroupApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getAllRooms(server: String): Promise<List<RoomInfo>, Exception> {
|
private fun getAllRooms(): Promise<List<RoomInfo>, Exception> {
|
||||||
val request = Request(
|
val request = Request(
|
||||||
verb = GET,
|
verb = GET,
|
||||||
room = null,
|
room = null,
|
||||||
server = server,
|
server = defaultServer,
|
||||||
endpoint = Endpoint.Rooms
|
endpoint = Endpoint.Rooms
|
||||||
)
|
)
|
||||||
return send(request).map { response ->
|
return send(request).map { response ->
|
||||||
|
@ -58,12 +58,17 @@ class OpenGroupPoller(private val server: String, private val executorService: S
|
|||||||
is Endpoint.RoomPollInfo -> {
|
is Endpoint.RoomPollInfo -> {
|
||||||
handleRoomPollInfo(server, response.endpoint.roomToken, response.body as OpenGroupApi.RoomPollInfo)
|
handleRoomPollInfo(server, response.endpoint.roomToken, response.body as OpenGroupApi.RoomPollInfo)
|
||||||
}
|
}
|
||||||
is Endpoint.RoomMessagesRecent -> {
|
is Endpoint.RoomMessagesRecent -> {
|
||||||
handleMessages(server, response.endpoint.roomToken, response.body as List<OpenGroupApi.Message>)
|
handleMessages(server, response.endpoint.roomToken, response.body as List<OpenGroupApi.Message>)
|
||||||
}
|
}
|
||||||
is Endpoint.Inbox, Endpoint.Outbox -> {
|
is Endpoint.RoomMessagesSince -> {
|
||||||
val fromOutbox = response.endpoint.value.startsWith("outbox", ignoreCase = true)
|
handleMessages(server, response.endpoint.roomToken, response.body as List<OpenGroupApi.Message>)
|
||||||
handleDirectMessages(server, fromOutbox, response.body as List<OpenGroupApi.DirectMessage>)
|
}
|
||||||
|
is Endpoint.Inbox, is Endpoint.InboxSince -> {
|
||||||
|
handleDirectMessages(server, false, response.body as List<OpenGroupApi.DirectMessage>)
|
||||||
|
}
|
||||||
|
is Endpoint.Outbox, is Endpoint.OutboxSince -> {
|
||||||
|
handleDirectMessages(server, true, response.body as List<OpenGroupApi.DirectMessage>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (secondToLastJob == null && !isCaughtUp) {
|
if (secondToLastJob == null && !isCaughtUp) {
|
||||||
@ -77,7 +82,7 @@ class OpenGroupPoller(private val server: String, private val executorService: S
|
|||||||
|
|
||||||
private fun handleCapabilities(server: String, capabilities: OpenGroupApi.Capabilities) {
|
private fun handleCapabilities(server: String, capabilities: OpenGroupApi.Capabilities) {
|
||||||
val storage = MessagingModuleConfiguration.shared.storage
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
storage.setOpenGroupSever(server, capabilities.capabilities)
|
storage.updateOpenGroupCapabilities(server, capabilities.capabilities)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleRoomPollInfo(
|
private fun handleRoomPollInfo(
|
||||||
@ -102,7 +107,7 @@ class OpenGroupPoller(private val server: String, private val executorService: S
|
|||||||
capabilities = listOf()
|
capabilities = listOf()
|
||||||
)
|
)
|
||||||
// - Open Group changes
|
// - Open Group changes
|
||||||
storage.setOpenGroup(openGroup)
|
storage.updateOpenGroup(openGroup)
|
||||||
|
|
||||||
// - User Count
|
// - User Count
|
||||||
storage.setUserCount(roomToken, server, pollInfo.active_users)
|
storage.setUserCount(roomToken, server, pollInfo.active_users)
|
||||||
@ -123,16 +128,19 @@ class OpenGroupPoller(private val server: String, private val executorService: S
|
|||||||
messages: List<OpenGroupApi.Message>
|
messages: List<OpenGroupApi.Message>
|
||||||
) {
|
) {
|
||||||
val openGroupId = "$server.$roomToken"
|
val openGroupId = "$server.$roomToken"
|
||||||
val msgs = messages.map {
|
val (deletions, additions) = messages.sortedBy { it.seqno }.partition { it.data.isNullOrBlank() }
|
||||||
|
handleNewMessages(roomToken, openGroupId, additions.map {
|
||||||
OpenGroupMessageV2(
|
OpenGroupMessageV2(
|
||||||
serverID = it.id,
|
serverID = it.id,
|
||||||
sender = it.session_id,
|
sender = it.session_id,
|
||||||
sentTimestamp = it.posted,
|
sentTimestamp = it.posted,
|
||||||
base64EncodedData = it.data,
|
base64EncodedData = it.data!!,
|
||||||
base64EncodedSignature = it.signature
|
base64EncodedSignature = it.signature
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
handleNewMessages(roomToken, openGroupId, msgs)
|
handleDeletedMessages(roomToken, openGroupId, deletions.map {
|
||||||
|
OpenGroupApi.MessageDeletion(it.id, it.seqno)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleDirectMessages(
|
private fun handleDirectMessages(
|
||||||
|
@ -36,7 +36,7 @@ object ProfilePictureUtilities {
|
|||||||
deferred.reject(e)
|
deferred.reject(e)
|
||||||
}
|
}
|
||||||
TextSecurePreferences.setLastProfilePictureUpload(context, Date().time)
|
TextSecurePreferences.setLastProfilePictureUpload(context, Date().time)
|
||||||
val url = "${FileServerApi.server}/files/$id"
|
val url = "${FileServerApi.server}/file/$id"
|
||||||
TextSecurePreferences.setProfilePictureURL(context, url)
|
TextSecurePreferences.setProfilePictureURL(context, url)
|
||||||
deferred.resolve(Unit)
|
deferred.resolve(Unit)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user