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:
committed by
jonnyandrew
parent
83296727a2
commit
51e952cc9e
@@ -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.
|
||||
*/
|
||||
|
@@ -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()
|
||||
}
|
@@ -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()
|
||||
|
@@ -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,
|
||||
|
@@ -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 {
|
||||
|
@@ -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
|
||||
}
|
@@ -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()
|
||||
}
|
||||
}
|
@@ -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)
|
||||
}
|
||||
}
|
@@ -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>
|
||||
|
@@ -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()
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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()
|
||||
}
|
||||
|
@@ -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,
|
||||
)
|
||||
}
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user