mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +00:00
Tweaked some open group handling and a couple of onboarding issues
Updated the OpenGroup adding and polling logic to reduce duplicate API calls Updated the BackgroundGroupAddJob to start a GroupAvatarDownloadJob instead of running the download itself (to appear to run faster) Defaulted OpenGroups to use blinded auth when no server capabilities are present Fixed an issue where the background poller could be started even though the onboarding hadn't been completed Fixed an issue where the database could get into an invalid state if the app was restarted during onboarding
This commit is contained in:
parent
d0a4bac83e
commit
5afd647686
@ -245,6 +245,12 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
|
|||||||
Log.i(TAG, "App is now visible.");
|
Log.i(TAG, "App is now visible.");
|
||||||
KeyCachingService.onAppForegrounded(this);
|
KeyCachingService.onAppForegrounded(this);
|
||||||
|
|
||||||
|
// If the user account hasn't been created or onboarding wasn't finished then don't start
|
||||||
|
// the pollers
|
||||||
|
if (TextSecurePreferences.getLocalNumber(this) == null || !TextSecurePreferences.hasSeenWelcomeScreen(this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ThreadUtils.queue(()->{
|
ThreadUtils.queue(()->{
|
||||||
if (poller != null) {
|
if (poller != null) {
|
||||||
poller.setCaughtUp(false);
|
poller.setCaughtUp(false);
|
||||||
|
@ -300,6 +300,11 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
|
|||||||
val lastHash = database.insertOrUpdate(lastMessageHashValueTable2, row, query, arrayOf( snode.toString(), publicKey, namespace.toString() ))
|
val lastHash = database.insertOrUpdate(lastMessageHashValueTable2, row, query, arrayOf( snode.toString(), publicKey, namespace.toString() ))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun clearAllLastMessageHashes() {
|
||||||
|
val database = databaseHelper.writableDatabase
|
||||||
|
database.delete(lastMessageHashValueTable2, null, null)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getReceivedMessageHashValues(publicKey: String, namespace: Int): Set<String>? {
|
override fun getReceivedMessageHashValues(publicKey: String, namespace: Int): Set<String>? {
|
||||||
val database = databaseHelper.readableDatabase
|
val database = databaseHelper.readableDatabase
|
||||||
val query = "${Companion.publicKey} = ? AND ${Companion.receivedMessageHashNamespace} = ?"
|
val query = "${Companion.publicKey} = ? AND ${Companion.receivedMessageHashNamespace} = ?"
|
||||||
@ -321,6 +326,11 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
|
|||||||
database.insertOrUpdate(receivedMessageHashValuesTable, row, query, arrayOf( publicKey, namespace.toString() ))
|
database.insertOrUpdate(receivedMessageHashValuesTable, row, query, arrayOf( publicKey, namespace.toString() ))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun clearReceivedMessageHashValues() {
|
||||||
|
val database = databaseHelper.writableDatabase
|
||||||
|
database.delete(receivedMessageHashValuesTable, null, null)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getAuthToken(server: String): String? {
|
override fun getAuthToken(server: String): String? {
|
||||||
val database = databaseHelper.readableDatabase
|
val database = databaseHelper.readableDatabase
|
||||||
return database.get(openGroupAuthTokenTable, "${Companion.server} = ?", wrap(server)) { cursor ->
|
return database.get(openGroupAuthTokenTable, "${Companion.server} = ?", wrap(server)) { cursor ->
|
||||||
|
@ -58,14 +58,14 @@ object OpenGroupManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
fun add(server: String, room: String, publicKey: String, context: Context) {
|
fun add(server: String, room: String, publicKey: String, context: Context): OpenGroupApi.RoomInfo? {
|
||||||
val openGroupID = "$server.$room"
|
val openGroupID = "$server.$room"
|
||||||
var threadID = GroupManager.getOpenGroupThreadID(openGroupID, context)
|
var threadID = GroupManager.getOpenGroupThreadID(openGroupID, context)
|
||||||
val storage = MessagingModuleConfiguration.shared.storage
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
val threadDB = DatabaseComponent.get(context).lokiThreadDatabase()
|
val threadDB = DatabaseComponent.get(context).lokiThreadDatabase()
|
||||||
// Check it it's added already
|
// Check it it's added already
|
||||||
val existingOpenGroup = threadDB.getOpenGroupChat(threadID)
|
val existingOpenGroup = threadDB.getOpenGroupChat(threadID)
|
||||||
if (existingOpenGroup != null) { return }
|
if (existingOpenGroup != null) { return null }
|
||||||
// Clear any existing data if needed
|
// Clear any existing data if needed
|
||||||
storage.removeLastDeletionServerID(room, server)
|
storage.removeLastDeletionServerID(room, server)
|
||||||
storage.removeLastMessageServerID(room, server)
|
storage.removeLastMessageServerID(room, server)
|
||||||
@ -73,18 +73,17 @@ object OpenGroupManager {
|
|||||||
storage.removeLastOutboxMessageId(server)
|
storage.removeLastOutboxMessageId(server)
|
||||||
// Store the public key
|
// Store the public key
|
||||||
storage.setOpenGroupPublicKey(server, publicKey)
|
storage.setOpenGroupPublicKey(server, publicKey)
|
||||||
// Get capabilities
|
// Get capabilities & room info
|
||||||
val capabilities = OpenGroupApi.getCapabilities(server).get()
|
val (capabilities, info) = OpenGroupApi.getCapabilitiesAndRoomInfo(room, server).get()
|
||||||
storage.setServerCapabilities(server, capabilities.capabilities)
|
storage.setServerCapabilities(server, capabilities.capabilities)
|
||||||
// Get room info
|
|
||||||
val info = OpenGroupApi.getRoomInfo(room, server).get()
|
|
||||||
storage.setUserCount(room, server, info.activeUsers)
|
storage.setUserCount(room, server, info.activeUsers)
|
||||||
// Create the group locally if not available already
|
// Create the group locally if not available already
|
||||||
if (threadID < 0) {
|
if (threadID < 0) {
|
||||||
threadID = GroupManager.createOpenGroup(openGroupID, context, null, info.name).threadId
|
threadID = GroupManager.createOpenGroup(openGroupID, context, null, info.name).threadId
|
||||||
}
|
}
|
||||||
val openGroup = OpenGroup(server, room, info.name, info.infoUpdates, publicKey)
|
val openGroup = OpenGroup(server, room, publicKey, info.name, info.imageId, info.infoUpdates)
|
||||||
threadDB.setOpenGroupChat(openGroup, threadID)
|
threadDB.setOpenGroupChat(openGroup, threadID)
|
||||||
|
return info
|
||||||
}
|
}
|
||||||
|
|
||||||
fun restartPollerForServer(server: String) {
|
fun restartPollerForServer(server: String) {
|
||||||
@ -130,12 +129,13 @@ object OpenGroupManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addOpenGroup(urlAsString: String, context: Context) {
|
fun addOpenGroup(urlAsString: String, context: Context): OpenGroupApi.RoomInfo? {
|
||||||
val url = HttpUrl.parse(urlAsString) ?: return
|
val url = HttpUrl.parse(urlAsString) ?: return null
|
||||||
val server = OpenGroup.getServer(urlAsString)
|
val server = OpenGroup.getServer(urlAsString)
|
||||||
val room = url.pathSegments().firstOrNull() ?: return
|
val room = url.pathSegments().firstOrNull() ?: return null
|
||||||
val publicKey = url.queryParameter("public_key") ?: return
|
val publicKey = url.queryParameter("public_key") ?: return null
|
||||||
add(server.toString().removeSuffix("/"), room, publicKey, context) // assume migrated from calling function
|
|
||||||
|
return add(server.toString().removeSuffix("/"), room, publicKey, context) // assume migrated from calling function
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateOpenGroup(openGroup: OpenGroup, context: Context) {
|
fun updateOpenGroup(openGroup: OpenGroup, context: Context) {
|
||||||
|
@ -44,7 +44,7 @@ class BackgroundPollWorker(val context: Context, params: WorkerParameters) : Wor
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
if (TextSecurePreferences.getLocalNumber(context) == null) {
|
if (TextSecurePreferences.getLocalNumber(context) == null || !TextSecurePreferences.hasSeenWelcomeScreen(context)) {
|
||||||
Log.v(TAG, "User not registered yet.")
|
Log.v(TAG, "User not registered yet.")
|
||||||
return Result.failure()
|
return Result.failure()
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,10 @@ import kotlinx.coroutines.launch
|
|||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import network.loki.messenger.databinding.ActivityLinkDeviceBinding
|
import network.loki.messenger.databinding.ActivityLinkDeviceBinding
|
||||||
import network.loki.messenger.databinding.FragmentRecoveryPhraseBinding
|
import network.loki.messenger.databinding.FragmentRecoveryPhraseBinding
|
||||||
|
import org.session.libsession.snode.SnodeModule
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
import org.session.libsignal.crypto.MnemonicCodec
|
import org.session.libsignal.crypto.MnemonicCodec
|
||||||
|
import org.session.libsignal.database.LokiAPIDatabaseProtocol
|
||||||
import org.session.libsignal.utilities.Hex
|
import org.session.libsignal.utilities.Hex
|
||||||
import org.session.libsignal.utilities.KeyHelper
|
import org.session.libsignal.utilities.KeyHelper
|
||||||
import org.session.libsignal.utilities.Log
|
import org.session.libsignal.utilities.Log
|
||||||
@ -39,6 +41,8 @@ import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo
|
|||||||
|
|
||||||
class LinkDeviceActivity : BaseActionBarActivity(), ScanQRCodeWrapperFragmentDelegate {
|
class LinkDeviceActivity : BaseActionBarActivity(), ScanQRCodeWrapperFragmentDelegate {
|
||||||
private lateinit var binding: ActivityLinkDeviceBinding
|
private lateinit var binding: ActivityLinkDeviceBinding
|
||||||
|
internal val database: LokiAPIDatabaseProtocol
|
||||||
|
get() = SnodeModule.shared.storage
|
||||||
private val adapter = LinkDeviceActivityAdapter(this)
|
private val adapter = LinkDeviceActivityAdapter(this)
|
||||||
private var restoreJob: Job? = null
|
private var restoreJob: Job? = null
|
||||||
|
|
||||||
@ -99,6 +103,11 @@ class LinkDeviceActivity : BaseActionBarActivity(), ScanQRCodeWrapperFragmentDel
|
|||||||
if (restoreJob?.isActive == true) return
|
if (restoreJob?.isActive == true) return
|
||||||
|
|
||||||
restoreJob = lifecycleScope.launch {
|
restoreJob = lifecycleScope.launch {
|
||||||
|
// This is here to resolve a case where the app restarts before a user completes onboarding
|
||||||
|
// which can result in an invalid database state
|
||||||
|
database.clearAllLastMessageHashes()
|
||||||
|
database.clearReceivedMessageHashValues()
|
||||||
|
|
||||||
// RestoreActivity handles seed this way
|
// RestoreActivity handles seed this way
|
||||||
val keyPairGenerationResult = KeyPairUtilities.generate(seed)
|
val keyPairGenerationResult = KeyPairUtilities.generate(seed)
|
||||||
val x25519KeyPair = keyPairGenerationResult.x25519KeyPair
|
val x25519KeyPair = keyPairGenerationResult.x25519KeyPair
|
||||||
|
@ -13,8 +13,10 @@ import android.view.View
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import network.loki.messenger.databinding.ActivityRecoveryPhraseRestoreBinding
|
import network.loki.messenger.databinding.ActivityRecoveryPhraseRestoreBinding
|
||||||
|
import org.session.libsession.snode.SnodeModule
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
import org.session.libsignal.crypto.MnemonicCodec
|
import org.session.libsignal.crypto.MnemonicCodec
|
||||||
|
import org.session.libsignal.database.LokiAPIDatabaseProtocol
|
||||||
import org.session.libsignal.utilities.Hex
|
import org.session.libsignal.utilities.Hex
|
||||||
import org.session.libsignal.utilities.KeyHelper
|
import org.session.libsignal.utilities.KeyHelper
|
||||||
import org.session.libsignal.utilities.hexEncodedPublicKey
|
import org.session.libsignal.utilities.hexEncodedPublicKey
|
||||||
@ -26,6 +28,8 @@ import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo
|
|||||||
|
|
||||||
class RecoveryPhraseRestoreActivity : BaseActionBarActivity() {
|
class RecoveryPhraseRestoreActivity : BaseActionBarActivity() {
|
||||||
private lateinit var binding: ActivityRecoveryPhraseRestoreBinding
|
private lateinit var binding: ActivityRecoveryPhraseRestoreBinding
|
||||||
|
internal val database: LokiAPIDatabaseProtocol
|
||||||
|
get() = SnodeModule.shared.storage
|
||||||
// region Lifecycle
|
// region Lifecycle
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -64,6 +68,11 @@ class RecoveryPhraseRestoreActivity : BaseActionBarActivity() {
|
|||||||
private fun restore() {
|
private fun restore() {
|
||||||
val mnemonic = binding.mnemonicEditText.text.toString()
|
val mnemonic = binding.mnemonicEditText.text.toString()
|
||||||
try {
|
try {
|
||||||
|
// This is here to resolve a case where the app restarts before a user completes onboarding
|
||||||
|
// which can result in an invalid database state
|
||||||
|
database.clearAllLastMessageHashes()
|
||||||
|
database.clearReceivedMessageHashValues()
|
||||||
|
|
||||||
val loadFileContents: (String) -> String = { fileName ->
|
val loadFileContents: (String) -> String = { fileName ->
|
||||||
MnemonicUtilities.loadFileContents(this, fileName)
|
MnemonicUtilities.loadFileContents(this, fileName)
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,10 @@ import android.widget.Toast
|
|||||||
import com.goterl.lazysodium.utils.KeyPair
|
import com.goterl.lazysodium.utils.KeyPair
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import network.loki.messenger.databinding.ActivityRegisterBinding
|
import network.loki.messenger.databinding.ActivityRegisterBinding
|
||||||
|
import org.session.libsession.snode.SnodeModule
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
import org.session.libsignal.crypto.ecc.ECKeyPair
|
import org.session.libsignal.crypto.ecc.ECKeyPair
|
||||||
|
import org.session.libsignal.database.LokiAPIDatabaseProtocol
|
||||||
import org.session.libsignal.utilities.KeyHelper
|
import org.session.libsignal.utilities.KeyHelper
|
||||||
import org.session.libsignal.utilities.hexEncodedPublicKey
|
import org.session.libsignal.utilities.hexEncodedPublicKey
|
||||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||||
@ -29,6 +31,8 @@ import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo
|
|||||||
|
|
||||||
class RegisterActivity : BaseActionBarActivity() {
|
class RegisterActivity : BaseActionBarActivity() {
|
||||||
private lateinit var binding: ActivityRegisterBinding
|
private lateinit var binding: ActivityRegisterBinding
|
||||||
|
internal val database: LokiAPIDatabaseProtocol
|
||||||
|
get() = SnodeModule.shared.storage
|
||||||
private var seed: ByteArray? = null
|
private var seed: ByteArray? = null
|
||||||
private var ed25519KeyPair: KeyPair? = null
|
private var ed25519KeyPair: KeyPair? = null
|
||||||
private var x25519KeyPair: ECKeyPair? = null
|
private var x25519KeyPair: ECKeyPair? = null
|
||||||
@ -109,6 +113,11 @@ class RegisterActivity : BaseActionBarActivity() {
|
|||||||
|
|
||||||
// region Interaction
|
// region Interaction
|
||||||
private fun register() {
|
private fun register() {
|
||||||
|
// This is here to resolve a case where the app restarts before a user completes onboarding
|
||||||
|
// which can result in an invalid database state
|
||||||
|
database.clearAllLastMessageHashes()
|
||||||
|
database.clearReceivedMessageHashValues()
|
||||||
|
|
||||||
KeyPairUtilities.store(this, seed!!, ed25519KeyPair!!, x25519KeyPair!!)
|
KeyPairUtilities.store(this, seed!!, ed25519KeyPair!!, x25519KeyPair!!)
|
||||||
val userHexEncodedPublicKey = x25519KeyPair!!.hexEncodedPublicKey
|
val userHexEncodedPublicKey = x25519KeyPair!!.hexEncodedPublicKey
|
||||||
val registrationID = KeyHelper.generateRegistrationId(false)
|
val registrationID = KeyHelper.generateRegistrationId(false)
|
||||||
|
@ -41,15 +41,10 @@ class BackgroundGroupAddJob(val joinUrl: String): Job {
|
|||||||
}
|
}
|
||||||
// get image
|
// get image
|
||||||
storage.setOpenGroupPublicKey(openGroup.server, openGroup.serverPublicKey)
|
storage.setOpenGroupPublicKey(openGroup.server, openGroup.serverPublicKey)
|
||||||
val (capabilities, info) = OpenGroupApi.getCapabilitiesAndRoomInfo(openGroup.room, openGroup.server, false).get()
|
val info = storage.addOpenGroup(openGroup.joinUrl())
|
||||||
storage.setServerCapabilities(openGroup.server, capabilities.capabilities)
|
val imageId = info?.imageId
|
||||||
val imageId = info.imageId
|
|
||||||
storage.addOpenGroup(openGroup.joinUrl())
|
|
||||||
if (imageId != null) {
|
if (imageId != null) {
|
||||||
val bytes = OpenGroupApi.downloadOpenGroupProfilePicture(openGroup.server, openGroup.room, imageId).get()
|
JobQueue.shared.add(GroupAvatarDownloadJob(openGroup.room, openGroup.server))
|
||||||
val groupId = GroupUtil.getEncodedOpenGroupID("${openGroup.server}.${openGroup.room}".toByteArray())
|
|
||||||
storage.updateProfilePicture(groupId, bytes)
|
|
||||||
storage.updateTimestampUpdated(groupId, System.currentTimeMillis())
|
|
||||||
}
|
}
|
||||||
Log.d(KEY, "onOpenGroupAdded(${openGroup.server})")
|
Log.d(KEY, "onOpenGroupAdded(${openGroup.server})")
|
||||||
storage.onOpenGroupAdded(openGroup.server)
|
storage.onOpenGroupAdded(openGroup.server)
|
||||||
|
@ -14,10 +14,9 @@ class GroupAvatarDownloadJob(val room: String, val server: String) : Job {
|
|||||||
|
|
||||||
override fun execute() {
|
override fun execute() {
|
||||||
val storage = MessagingModuleConfiguration.shared.storage
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
|
val imageId = storage.getOpenGroup(room, server)?.imageId ?: return
|
||||||
try {
|
try {
|
||||||
val info = OpenGroupApi.getRoomInfo(room, server).get()
|
val bytes = OpenGroupApi.downloadOpenGroupProfilePicture(server, room, imageId).get()
|
||||||
val imageId = info.imageId ?: return
|
|
||||||
val bytes = OpenGroupApi.downloadOpenGroupProfilePicture(server, info.token, imageId).get()
|
|
||||||
val groupId = GroupUtil.getEncodedOpenGroupID("$server.$room".toByteArray())
|
val groupId = GroupUtil.getEncodedOpenGroupID("$server.$room".toByteArray())
|
||||||
storage.updateProfilePicture(groupId, bytes)
|
storage.updateProfilePicture(groupId, bytes)
|
||||||
storage.updateTimestampUpdated(groupId, System.currentTimeMillis())
|
storage.updateTimestampUpdated(groupId, System.currentTimeMillis())
|
||||||
|
@ -11,15 +11,17 @@ data class OpenGroup(
|
|||||||
val id: String,
|
val id: String,
|
||||||
val name: String,
|
val name: String,
|
||||||
val publicKey: String,
|
val publicKey: String,
|
||||||
|
val imageId: String?,
|
||||||
val infoUpdates: Int,
|
val infoUpdates: Int,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
constructor(server: String, room: String, name: String, infoUpdates: Int, publicKey: String) : this(
|
constructor(server: String, room: String, publicKey: String, name: String, imageId: String?, infoUpdates: Int) : this(
|
||||||
server = server,
|
server = server,
|
||||||
room = room,
|
room = room,
|
||||||
id = "$server.$room",
|
id = "$server.$room",
|
||||||
name = name,
|
name = name,
|
||||||
publicKey = publicKey,
|
publicKey = publicKey,
|
||||||
|
imageId = imageId,
|
||||||
infoUpdates = infoUpdates,
|
infoUpdates = infoUpdates,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -31,11 +33,12 @@ data class OpenGroup(
|
|||||||
if (!json.has("room")) return null
|
if (!json.has("room")) return null
|
||||||
val room = json.get("room").asText().toLowerCase(Locale.US)
|
val room = json.get("room").asText().toLowerCase(Locale.US)
|
||||||
val server = json.get("server").asText().toLowerCase(Locale.US)
|
val server = json.get("server").asText().toLowerCase(Locale.US)
|
||||||
val displayName = json.get("displayName").asText()
|
|
||||||
val publicKey = json.get("publicKey").asText()
|
val publicKey = json.get("publicKey").asText()
|
||||||
|
val displayName = json.get("displayName").asText()
|
||||||
|
val imageId = json.get("imageId")?.asText()
|
||||||
val infoUpdates = json.get("infoUpdates")?.asText()?.toIntOrNull() ?: 0
|
val infoUpdates = json.get("infoUpdates")?.asText()?.toIntOrNull() ?: 0
|
||||||
val capabilities = json.get("capabilities")?.asText()?.split(",") ?: emptyList()
|
val capabilities = json.get("capabilities")?.asText()?.split(",") ?: emptyList()
|
||||||
OpenGroup(server, room, displayName, infoUpdates, publicKey)
|
OpenGroup(server, room, displayName, publicKey, imageId, infoUpdates)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.w("Loki", "Couldn't parse open group from JSON: $jsonAsString.", e);
|
Log.w("Loki", "Couldn't parse open group from JSON: $jsonAsString.", e);
|
||||||
null
|
null
|
||||||
@ -53,11 +56,12 @@ data class OpenGroup(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toJson(): Map<String,String> = mapOf(
|
fun toJson(): Map<String,String?> = mapOf(
|
||||||
"room" to room,
|
"room" to room,
|
||||||
"server" to server,
|
"server" to server,
|
||||||
"displayName" to name,
|
|
||||||
"publicKey" to publicKey,
|
"publicKey" to publicKey,
|
||||||
|
"displayName" to name,
|
||||||
|
"imageId" to imageId,
|
||||||
"infoUpdates" to infoUpdates.toString(),
|
"infoUpdates" to infoUpdates.toString(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ object OpenGroupApi {
|
|||||||
val created: Long = 0,
|
val created: Long = 0,
|
||||||
val activeUsers: Int = 0,
|
val activeUsers: Int = 0,
|
||||||
val activeUsersCutoff: Int = 0,
|
val activeUsersCutoff: Int = 0,
|
||||||
val imageId: Long? = null,
|
val imageId: String? = null,
|
||||||
val pinnedMessages: List<PinnedMessage> = emptyList(),
|
val pinnedMessages: List<PinnedMessage> = emptyList(),
|
||||||
val admin: Boolean = false,
|
val admin: Boolean = false,
|
||||||
val globalAdmin: Boolean = false,
|
val globalAdmin: Boolean = false,
|
||||||
@ -337,7 +337,7 @@ object OpenGroupApi {
|
|||||||
.plus(request.verb.rawValue.toByteArray())
|
.plus(request.verb.rawValue.toByteArray())
|
||||||
.plus("/${request.endpoint.value}".toByteArray())
|
.plus("/${request.endpoint.value}".toByteArray())
|
||||||
.plus(bodyHash)
|
.plus(bodyHash)
|
||||||
if (serverCapabilities.contains(Capability.BLIND.name.lowercase())) {
|
if (serverCapabilities.isEmpty() || serverCapabilities.contains(Capability.BLIND.name.lowercase())) {
|
||||||
SodiumUtilities.blindedKeyPair(publicKey, ed25519KeyPair)?.let { keyPair ->
|
SodiumUtilities.blindedKeyPair(publicKey, ed25519KeyPair)?.let { keyPair ->
|
||||||
pubKey = SessionId(
|
pubKey = SessionId(
|
||||||
IdPrefix.BLINDED,
|
IdPrefix.BLINDED,
|
||||||
@ -395,13 +395,13 @@ object OpenGroupApi {
|
|||||||
fun downloadOpenGroupProfilePicture(
|
fun downloadOpenGroupProfilePicture(
|
||||||
server: String,
|
server: String,
|
||||||
roomID: String,
|
roomID: String,
|
||||||
imageId: Long
|
imageId: String
|
||||||
): Promise<ByteArray, Exception> {
|
): Promise<ByteArray, Exception> {
|
||||||
val request = Request(
|
val request = Request(
|
||||||
verb = GET,
|
verb = GET,
|
||||||
room = roomID,
|
room = roomID,
|
||||||
server = server,
|
server = server,
|
||||||
endpoint = Endpoint.RoomFileIndividual(roomID, imageId.toString())
|
endpoint = Endpoint.RoomFileIndividual(roomID, imageId)
|
||||||
)
|
)
|
||||||
return getResponseBody(request)
|
return getResponseBody(request)
|
||||||
}
|
}
|
||||||
@ -794,16 +794,14 @@ object OpenGroupApi {
|
|||||||
|
|
||||||
private fun sequentialBatch(
|
private fun sequentialBatch(
|
||||||
server: String,
|
server: String,
|
||||||
requests: MutableList<BatchRequestInfo<*>>,
|
requests: MutableList<BatchRequestInfo<*>>
|
||||||
authRequired: Boolean = true
|
|
||||||
): Promise<List<BatchResponse<*>>, Exception> {
|
): Promise<List<BatchResponse<*>>, Exception> {
|
||||||
val request = Request(
|
val request = Request(
|
||||||
verb = POST,
|
verb = POST,
|
||||||
room = null,
|
room = null,
|
||||||
server = server,
|
server = server,
|
||||||
endpoint = Endpoint.Sequence,
|
endpoint = Endpoint.Sequence,
|
||||||
parameters = requests.map { it.request },
|
parameters = requests.map { it.request }
|
||||||
isAuthRequired = authRequired
|
|
||||||
)
|
)
|
||||||
return getBatchResponseJson(request, requests)
|
return getBatchResponseJson(request, requests)
|
||||||
}
|
}
|
||||||
@ -912,8 +910,7 @@ object OpenGroupApi {
|
|||||||
|
|
||||||
fun getCapabilitiesAndRoomInfo(
|
fun getCapabilitiesAndRoomInfo(
|
||||||
room: String,
|
room: String,
|
||||||
server: String,
|
server: String
|
||||||
authRequired: Boolean = true
|
|
||||||
): Promise<Pair<Capabilities, RoomInfo>, Exception> {
|
): Promise<Pair<Capabilities, RoomInfo>, Exception> {
|
||||||
val requests = mutableListOf<BatchRequestInfo<*>>(
|
val requests = mutableListOf<BatchRequestInfo<*>>(
|
||||||
BatchRequestInfo(
|
BatchRequestInfo(
|
||||||
@ -933,7 +930,7 @@ object OpenGroupApi {
|
|||||||
responseType = object : TypeReference<RoomInfo>(){}
|
responseType = object : TypeReference<RoomInfo>(){}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return sequentialBatch(server, requests, authRequired).map {
|
return sequentialBatch(server, requests).map {
|
||||||
val capabilities = it.firstOrNull()?.body as? Capabilities ?: throw Error.ParsingFailed
|
val capabilities = it.firstOrNull()?.body as? Capabilities ?: throw Error.ParsingFailed
|
||||||
val roomInfo = it.lastOrNull()?.body as? RoomInfo ?: throw Error.ParsingFailed
|
val roomInfo = it.lastOrNull()?.body as? RoomInfo ?: throw Error.ParsingFailed
|
||||||
capabilities to roomInfo
|
capabilities to roomInfo
|
||||||
|
@ -59,7 +59,7 @@ class OpenGroupPoller(private val server: String, private val executorService: S
|
|||||||
fun poll(isPostCapabilitiesRetry: Boolean = false): Promise<Unit, Exception> {
|
fun poll(isPostCapabilitiesRetry: Boolean = false): Promise<Unit, Exception> {
|
||||||
val storage = MessagingModuleConfiguration.shared.storage
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
val rooms = storage.getAllOpenGroups().values.filter { it.server == server }.map { it.room }
|
val rooms = storage.getAllOpenGroups().values.filter { it.server == server }.map { it.room }
|
||||||
rooms.forEach { downloadGroupAvatarIfNeeded(it) }
|
|
||||||
return OpenGroupApi.poll(rooms, server).successBackground { responses ->
|
return OpenGroupApi.poll(rooms, server).successBackground { responses ->
|
||||||
responses.filterNot { it.body == null }.forEach { response ->
|
responses.filterNot { it.body == null }.forEach { response ->
|
||||||
when (response.endpoint) {
|
when (response.endpoint) {
|
||||||
@ -123,9 +123,10 @@ class OpenGroupPoller(private val server: String, private val executorService: S
|
|||||||
val openGroup = OpenGroup(
|
val openGroup = OpenGroup(
|
||||||
server = server,
|
server = server,
|
||||||
room = pollInfo.token,
|
room = pollInfo.token,
|
||||||
name = pollInfo.details?.name ?: "",
|
name = if (pollInfo.details != null) { pollInfo.details.name } else { existingOpenGroup.name },
|
||||||
infoUpdates = pollInfo.details?.infoUpdates ?: 0,
|
infoUpdates = if (pollInfo.details != null) { pollInfo.details.infoUpdates } else { existingOpenGroup.infoUpdates },
|
||||||
publicKey = publicKey,
|
publicKey = publicKey,
|
||||||
|
imageId = if (pollInfo.details != null) { pollInfo.details.imageId } else { existingOpenGroup.imageId }
|
||||||
)
|
)
|
||||||
// - Open Group changes
|
// - Open Group changes
|
||||||
storage.updateOpenGroup(openGroup)
|
storage.updateOpenGroup(openGroup)
|
||||||
@ -155,6 +156,11 @@ class OpenGroupPoller(private val server: String, private val executorService: S
|
|||||||
GroupMember(groupId, it, GroupMemberRole.HIDDEN_ADMIN)
|
GroupMember(groupId, it, GroupMemberRole.HIDDEN_ADMIN)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start downloading the room image (if we don't have one or it's been updated)
|
||||||
|
if (pollInfo.details?.imageId != null && pollInfo.details.imageId != existingOpenGroup.imageId) {
|
||||||
|
JobQueue.shared.add(GroupAvatarDownloadJob(roomToken, server))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleMessages(
|
private fun handleMessages(
|
||||||
@ -284,16 +290,4 @@ class OpenGroupPoller(private val server: String, private val executorService: S
|
|||||||
JobQueue.shared.add(deleteJob)
|
JobQueue.shared.add(deleteJob)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun downloadGroupAvatarIfNeeded(room: String) {
|
|
||||||
val storage = MessagingModuleConfiguration.shared.storage
|
|
||||||
if (storage.getGroupAvatarDownloadJob(server, room) != null) return
|
|
||||||
val groupId = GroupUtil.getEncodedOpenGroupID("$server.$room".toByteArray())
|
|
||||||
storage.getGroup(groupId)?.let {
|
|
||||||
if (System.currentTimeMillis() > it.updatedTimestamp + TimeUnit.DAYS.toMillis(7)) {
|
|
||||||
JobQueue.shared.add(GroupAvatarDownloadJob(room, server))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -16,8 +16,10 @@ interface LokiAPIDatabaseProtocol {
|
|||||||
fun setSwarm(publicKey: String, newValue: Set<Snode>)
|
fun setSwarm(publicKey: String, newValue: Set<Snode>)
|
||||||
fun getLastMessageHashValue(snode: Snode, publicKey: String, namespace: Int): String?
|
fun getLastMessageHashValue(snode: Snode, publicKey: String, namespace: Int): String?
|
||||||
fun setLastMessageHashValue(snode: Snode, publicKey: String, newValue: String, namespace: Int)
|
fun setLastMessageHashValue(snode: Snode, publicKey: String, newValue: String, namespace: Int)
|
||||||
|
fun clearAllLastMessageHashes()
|
||||||
fun getReceivedMessageHashValues(publicKey: String, namespace: Int): Set<String>?
|
fun getReceivedMessageHashValues(publicKey: String, namespace: Int): Set<String>?
|
||||||
fun setReceivedMessageHashValues(publicKey: String, newValue: Set<String>, namespace: Int)
|
fun setReceivedMessageHashValues(publicKey: String, newValue: Set<String>, namespace: Int)
|
||||||
|
fun clearReceivedMessageHashValues()
|
||||||
fun getAuthToken(server: String): String?
|
fun getAuthToken(server: String): String?
|
||||||
fun setAuthToken(server: String, newValue: String?)
|
fun setAuthToken(server: String, newValue: String?)
|
||||||
fun setUserCount(room: String, server: String, newValue: Int)
|
fun setUserCount(room: String, server: String, newValue: Int)
|
||||||
|
Loading…
Reference in New Issue
Block a user