1
0
mirror of https://github.com/vector-im/riotX-android synced 2025-10-05 15:52:47 +02:00

Add remote wipe

This commit is contained in:
Jonny Andrew
2023-02-15 17:51:16 +00:00
committed by jonnyandrew
parent 83296727a2
commit 51e952cc9e
14 changed files with 236 additions and 49 deletions

View File

@@ -26,6 +26,7 @@ import org.matrix.android.sdk.api.federation.FederationService
import org.matrix.android.sdk.api.session.account.AccountService
import org.matrix.android.sdk.api.session.accountdata.SessionAccountDataService
import org.matrix.android.sdk.api.session.call.CallSignalingService
import org.matrix.android.sdk.api.session.cleardata.ClearDataService
import org.matrix.android.sdk.api.session.content.ContentUploadStateTracker
import org.matrix.android.sdk.api.session.content.ContentUrlResolver
import org.matrix.android.sdk.api.session.contentscanner.ContentScannerService
@@ -162,6 +163,11 @@ interface Session {
*/
fun signOutService(): SignOutService
/**
* Returns the ClearDataService associated with the session.
*/
fun clearDataService(): ClearDataService
/**
* Returns the PushRuleService associated with the session.
*/

View File

@@ -0,0 +1,25 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api.session.cleardata
interface ClearDataService {
/**
* Clear all data except for basic session data such as credentials
*/
suspend fun clearData()
}

View File

@@ -34,6 +34,7 @@ import org.matrix.android.sdk.api.session.account.AccountService
import org.matrix.android.sdk.api.session.accountdata.SessionAccountDataService
import org.matrix.android.sdk.api.session.cache.CacheService
import org.matrix.android.sdk.api.session.call.CallSignalingService
import org.matrix.android.sdk.api.session.cleardata.ClearDataService
import org.matrix.android.sdk.api.session.content.ContentUploadStateTracker
import org.matrix.android.sdk.api.session.content.ContentUrlResolver
import org.matrix.android.sdk.api.session.contentscanner.ContentScannerService
@@ -99,6 +100,7 @@ internal class DefaultSession @Inject constructor(
private val federationService: Lazy<FederationService>,
private val cacheService: Lazy<CacheService>,
private val signOutService: Lazy<SignOutService>,
private val clearDataService: Lazy<ClearDataService>,
private val pushRuleService: Lazy<PushRuleService>,
private val pushersService: Lazy<PushersService>,
private val termsService: Lazy<TermsService>,
@@ -207,6 +209,7 @@ internal class DefaultSession @Inject constructor(
override fun roomDirectoryService(): RoomDirectoryService = roomDirectoryService.get()
override fun userService(): UserService = userService.get()
override fun signOutService(): SignOutService = signOutService.get()
override fun clearDataService(): ClearDataService = clearDataService.get()
override fun pushRuleService(): PushRuleService = pushRuleService.get()
override fun pushersService(): PushersService = pushersService.get()
override fun eventService(): EventService = eventService.get()

View File

@@ -31,6 +31,7 @@ import org.matrix.android.sdk.internal.network.RequestModule
import org.matrix.android.sdk.internal.session.account.AccountModule
import org.matrix.android.sdk.internal.session.cache.CacheModule
import org.matrix.android.sdk.internal.session.call.CallModule
import org.matrix.android.sdk.internal.session.cleardata.ClearDataModule
import org.matrix.android.sdk.internal.session.content.ContentModule
import org.matrix.android.sdk.internal.session.content.UploadContentWorker
import org.matrix.android.sdk.internal.session.contentscanner.ContentScannerModule
@@ -73,6 +74,7 @@ import org.matrix.android.sdk.internal.util.system.SystemModule
SyncModule::class,
HomeServerCapabilitiesModule::class,
SignOutModule::class,
ClearDataModule::class,
UserModule::class,
FilterModule::class,
ContentModule::class,

View File

@@ -89,6 +89,16 @@ internal class CleanupSession @Inject constructor(
sessionCache.deleteRecursively()
}
suspend fun clearSessionData() {
Timber.d("Clear data: clear session data...")
clearSessionDataTask.execute(Unit)
waitRealmRelease()
Timber.d("Clear data: clear session cache")
sessionCache.deleteRecursively()
}
private suspend fun waitRealmRelease() {
var timeToWaitMillis = MAX_TIME_TO_WAIT_MILLIS
do {

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.cleardata
import dagger.Binds
import dagger.Module
import org.matrix.android.sdk.api.session.cleardata.ClearDataService
@Module
internal abstract class ClearDataModule {
@Binds
abstract fun bindClearDataTask(task: DefaultClearDataTask): ClearDataTask
@Binds
abstract fun bindClearDataService(service: DefaultClearDataService): ClearDataService
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.cleardata
import org.matrix.android.sdk.internal.session.cleanup.CleanupSession
import org.matrix.android.sdk.internal.task.Task
import javax.inject.Inject
internal interface ClearDataTask : Task<ClearDataTask.Params, Unit> {
object Params
}
internal class DefaultClearDataTask @Inject constructor(
private val cleanupSession: CleanupSession
) : ClearDataTask {
override suspend fun execute(params: ClearDataTask.Params) {
cleanupSession.stopActiveTasks()
cleanupSession.clearSessionData()
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.cleardata
import org.matrix.android.sdk.api.session.cleardata.ClearDataService
import javax.inject.Inject
internal class DefaultClearDataService @Inject constructor(
private val clearDataTask: ClearDataTask,
) : ClearDataService {
override suspend fun clearData() {
return clearDataTask.execute(ClearDataTask.Params)
}
}

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application>
<activity android:name="im.vector.app.features.debug.TestLinkifyActivity" />
@@ -16,6 +17,17 @@
android:name="com.facebook.flipper.android.diagnostics.FlipperDiagnosticActivity"
android:exported="true" />
<receiver
android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver"
android:exported="true"
android:permission="@null"
tools:replace="android:permission">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
</application>
</manifest>

View File

@@ -51,6 +51,7 @@ class PushParser @Inject constructor() {
eventId = message["event_id"],
roomId = message["room_id"],
unread = message["unread"]?.let { tryOrNull { Integer.parseInt(it) } },
remoteWipeNonce = message["io.element.remote_wipe_nonce"]
)
return pushDataFcm.toPushData()
}

View File

@@ -49,15 +49,15 @@ import javax.inject.Inject
private val loggerTag = LoggerTag("Push", LoggerTag.SYNC)
class VectorPushHandler @Inject constructor(
private val notificationDrawerManager: NotificationDrawerManager,
private val notifiableEventResolver: NotifiableEventResolver,
private val activeSessionHolder: ActiveSessionHolder,
private val vectorPreferences: VectorPreferences,
private val vectorDataStore: VectorDataStore,
private val wifiDetector: WifiDetector,
private val actionIds: NotificationActionIds,
private val context: Context,
private val buildMeta: BuildMeta
private val notificationDrawerManager: NotificationDrawerManager,
private val notifiableEventResolver: NotifiableEventResolver,
private val activeSessionHolder: ActiveSessionHolder,
private val vectorPreferences: VectorPreferences,
private val vectorDataStore: VectorDataStore,
private val wifiDetector: WifiDetector,
private val actionIds: NotificationActionIds,
private val context: Context,
private val buildMeta: BuildMeta
) {
private val coroutineScope = CoroutineScope(SupervisorJob())
@@ -83,24 +83,30 @@ class VectorPushHandler @Inject constructor(
vectorDataStore.incrementPushCounter()
}
// Diagnostic Push
if (pushData.eventId == PushersManager.TEST_EVENT_ID) {
val intent = Intent(actionIds.push)
LocalBroadcastManager.getInstance(context).sendBroadcast(intent)
return
}
if (!vectorPreferences.areNotificationEnabledForDevice()) {
Timber.tag(loggerTag.value).i("Notification are disabled for this device")
return
}
mUIHandler.post {
if (ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
// we are in foreground, let the sync do the things?
Timber.tag(loggerTag.value).d("PUSH received in a foreground state, ignore")
} else {
when (pushData) {
PushData.Diagnostic -> {
val intent = Intent(actionIds.push)
LocalBroadcastManager.getInstance(context).sendBroadcast(intent)
return
}
is PushData.RemoteWipe -> {
coroutineScope.launch(Dispatchers.IO) { handleInternal(pushData) }
return
}
is PushData.Event -> {
if (!vectorPreferences.areNotificationEnabledForDevice()) {
Timber.tag(loggerTag.value).i("Notification are disabled for this device")
return
}
mUIHandler.post {
if (ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
// we are in foreground, let the sync do the things?
Timber.tag(loggerTag.value).d("PUSH received in a foreground state, ignore")
} else {
coroutineScope.launch(Dispatchers.IO) { handleInternal(pushData) }
}
}
}
}
}
@@ -122,8 +128,11 @@ class VectorPushHandler @Inject constructor(
if (session == null) {
Timber.tag(loggerTag.value).w("## Can't sync from push, no current session")
} else {
if (isEventAlreadyKnown(pushData)) {
return
}
when (pushData) {
PushData.Diagnostic -> {}
is PushData.Event -> if (isEventAlreadyKnown(pushData)) {
Timber.tag(loggerTag.value).d("Ignoring push, event already known")
} else {
// Try to get the Event content faster
@@ -133,13 +142,19 @@ class VectorPushHandler @Inject constructor(
Timber.tag(loggerTag.value).d("Requesting background sync")
session.syncService().requireBackgroundSync()
}
is PushData.RemoteWipe -> {
Timber.tag(loggerTag.value).d("## Remote wipe: received")
Timber.tag(loggerTag.value).d("## Remote wipe: clearing data")
session.clearDataService().clearData()
}
}
} catch (e: Exception) {
Timber.tag(loggerTag.value).e(e, "## handleInternal() failed")
}
}
private suspend fun getEventFastLane(session: Session, pushData: PushData) {
private suspend fun getEventFastLane(session: Session, pushData: PushData.Event) {
pushData.roomId ?: return
pushData.eventId ?: return
@@ -169,7 +184,7 @@ class VectorPushHandler @Inject constructor(
// check if the event was not yet received
// a previous catchup might have already retrieved the notified event
private fun isEventAlreadyKnown(pushData: PushData): Boolean {
private fun isEventAlreadyKnown(pushData: PushData.Event): Boolean {
if (pushData.eventId != null && pushData.roomId != null) {
try {
val session = activeSessionHolder.getSafeActiveSession() ?: return false

View File

@@ -16,15 +16,23 @@
package im.vector.app.core.pushers.model
/**
* Represent parsed data that the app has received from a Push content.
*
* @property eventId The Event ID. If not null, it will not be empty, and will have a valid format.
* @property roomId The Room ID. If not null, it will not be empty, and will have a valid format.
* @property unread Number of unread message.
*/
data class PushData(
val eventId: String?,
val roomId: String?,
val unread: Int?,
)
sealed class PushData {
/**
* Represent parsed data that the app has received from a Push content.
*
* @property eventId The Event ID. If not null, it will not be empty, and will have a valid format.
* @property roomId The Room ID. If not null, it will not be empty, and will have a valid format.
* @property unread Number of unread message.
*/
data class Event(
val eventId: String?,
val roomId: String?,
val unread: Int?,
) : PushData()
data class RemoteWipe(
val nonce: String
) : PushData()
object Diagnostic : PushData()
}

View File

@@ -16,6 +16,7 @@
package im.vector.app.core.pushers.model
import im.vector.app.core.pushers.PushersManager
import org.matrix.android.sdk.api.MatrixPatterns
/**
@@ -34,10 +35,18 @@ data class PushDataFcm(
val eventId: String?,
val roomId: String?,
var unread: Int?,
val remoteWipeNonce: String?,
)
fun PushDataFcm.toPushData() = PushData(
eventId = eventId?.takeIf { MatrixPatterns.isEventId(it) },
roomId = roomId?.takeIf { MatrixPatterns.isRoomId(it) },
unread = unread
)
fun PushDataFcm.toPushData(): PushData =
if (eventId == PushersManager.TEST_EVENT_ID) {
PushData.Diagnostic
} else if (remoteWipeNonce != null) {
PushData.RemoteWipe(nonce = remoteWipeNonce)
} else {
PushData.Event(
eventId = eventId?.takeIf { MatrixPatterns.isEventId(it) },
roomId = roomId?.takeIf { MatrixPatterns.isRoomId(it) },
unread = unread,
)
}

View File

@@ -53,7 +53,8 @@ data class PushDataUnifiedPushCounts(
@Json(name = "unread") val unread: Int?
)
fun PushDataUnifiedPush.toPushData() = PushData(
// TODO
fun PushDataUnifiedPush.toPushData() = PushData.Event(
eventId = notification?.eventId?.takeIf { MatrixPatterns.isEventId(it) },
roomId = notification?.roomId?.takeIf { MatrixPatterns.isRoomId(it) },
unread = notification?.counts?.unread