diff --git a/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt b/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt index e26736de7e..3f38e4ef15 100755 --- a/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt +++ b/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt @@ -69,6 +69,9 @@ class BugReportActivity : VectorBaseActivity() { bug_report_button_include_crash_logs.isChecked = false bug_report_button_include_crash_logs.isVisible = false + bug_report_button_include_key_share_history.isChecked = false + bug_report_button_include_key_share_history.isVisible = false + // Keep the screenshot } else { supportActionBar?.setTitle(R.string.title_activity_bug_report) @@ -121,6 +124,7 @@ class BugReportActivity : VectorBaseActivity() { forSuggestion, bug_report_button_include_logs.isChecked, bug_report_button_include_crash_logs.isChecked, + bug_report_button_include_key_share_history.isChecked, bug_report_button_include_screenshot.isChecked, bug_report_edit_text.text.toString(), object : BugReporter.IMXBugReportListener { diff --git a/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt b/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt index e7382a17e9..95fe16ea51 100755 --- a/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt +++ b/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt @@ -33,6 +33,7 @@ import im.vector.app.core.extensions.getAllChildFragments import im.vector.app.core.extensions.toOnOff import im.vector.app.features.settings.VectorLocale import im.vector.app.features.settings.VectorPreferences +import im.vector.app.features.settings.devtools.GossipingEventsSerializer import im.vector.app.features.settings.locale.SystemLocaleProvider import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.version.VersionProvider @@ -74,6 +75,7 @@ class BugReporter @Inject constructor( private const val LOG_CAT_FILENAME = "logcat.log" private const val LOG_CAT_SCREENSHOT_FILENAME = "screenshot.png" private const val CRASH_FILENAME = "crash.log" + private const val KEY_REQUESTS_FILENAME = "keyRequests.log" private const val BUFFER_SIZE = 1024 * 1024 * 50 } @@ -143,6 +145,7 @@ class BugReporter @Inject constructor( * @param forSuggestion true to send a suggestion * @param withDevicesLogs true to include the device log * @param withCrashLogs true to include the crash logs + * @param withKeyRequestHistory true to include the crash logs * @param withScreenshot true to include the screenshot * @param theBugDescription the bug description * @param listener the listener @@ -152,6 +155,7 @@ class BugReporter @Inject constructor( forSuggestion: Boolean, withDevicesLogs: Boolean, withCrashLogs: Boolean, + withKeyRequestHistory: Boolean, withScreenshot: Boolean, theBugDescription: String, listener: IMXBugReportListener?) { @@ -207,6 +211,22 @@ class BugReporter @Inject constructor( } } + activeSessionHolder.getSafeActiveSession() + ?.takeIf { !mIsCancelled && withKeyRequestHistory } + ?.cryptoService() + ?.getGossipingEvents() + ?.let { GossipingEventsSerializer().serialize(it) } + ?.toByteArray() + ?.let { rawByteArray -> + File(context.cacheDir.absolutePath, KEY_REQUESTS_FILENAME) + .also { + it.outputStream() + .use { os -> os.write(rawByteArray) } + } + } + ?.let { compressFile(it) } + ?.let { gzippedFiles.add(it) } + var deviceId = "undefined" var userId = "undefined" var olmVersion = "undefined" diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsSerializer.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsSerializer.kt new file mode 100644 index 0000000000..d18a6c2ba8 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsSerializer.kt @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * 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 im.vector.app.features.settings.devtools + +import im.vector.app.core.resources.DateProvider +import me.gujun.android.span.span +import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.events.model.EventType +import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.internal.crypto.model.event.OlmEventContent +import org.matrix.android.sdk.internal.crypto.model.event.SecretSendEventContent +import org.matrix.android.sdk.internal.crypto.model.rest.ForwardedRoomKeyContent +import org.matrix.android.sdk.internal.crypto.model.rest.GossipingToDeviceObject +import org.matrix.android.sdk.internal.crypto.model.rest.RoomKeyShareRequest +import org.matrix.android.sdk.internal.crypto.model.rest.SecretShareRequest +import org.threeten.bp.format.DateTimeFormatter + +class GossipingEventsSerializer { + private val full24DateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS") + + fun serialize(eventList: List): String { + return buildString { + eventList.forEach { + val clearType = it.getClearType() + append("[${getFormattedDate(it.ageLocalTs)}] $clearType from:${it.senderId} - ") + when (clearType) { + EventType.ROOM_KEY_REQUEST -> { + val content = it.getClearContent().toModel() + append("reqId:${content?.requestId} action:${content?.action} ") + if (content?.action == GossipingToDeviceObject.ACTION_SHARE_REQUEST) { + append("sessionId: ${content.body?.sessionId} ") + } + append("requestedBy: ${content?.requestingDeviceId}") + } + EventType.FORWARDED_ROOM_KEY -> { + val encryptedContent = it.content.toModel() + val content = it.getClearContent().toModel() + + append("sessionId:${content?.sessionId} From Device (sender key):${encryptedContent?.senderKey}") + span("\nFrom Device (sender key):") { + textStyle = "bold" + } + } + EventType.ROOM_KEY -> { + val content = it.getClearContent() + append("sessionId:${content?.get("session_id")} roomId:${content?.get("room_id")} dest:${content?.get("_dest") ?: "me"}") + } + EventType.SEND_SECRET -> { + val content = it.getClearContent().toModel() + append("requestId:${content?.requestId} From Device:${it.mxDecryptionResult?.payload?.get("sender_device")}") + } + EventType.REQUEST_SECRET -> { + val content = it.getClearContent().toModel() + append("reqId:${content?.requestId} action:${content?.action} ") + if (content?.action == GossipingToDeviceObject.ACTION_SHARE_REQUEST) { + append("secretName:${content.secretName} ") + } + append("requestedBy:${content?.requestingDeviceId}") + } + EventType.ENCRYPTED -> { + append("Failed to Decrypt") + } + else -> { + append("??") + } + } + append("\n") + } + } + } + + private fun getFormattedDate(ageLocalTs: Long?): String { + return ageLocalTs + ?.let { DateProvider.toLocalDateTime(it) } + ?.let { full24DateFormatter.format(it) } + ?: "?" + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestViewModel.kt index 4385cb2c09..d49d3dc0b6 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestViewModel.kt @@ -70,10 +70,6 @@ class KeyRequestViewModel @AssistedInject constructor( fun create(initialState: KeyRequestViewState): KeyRequestViewModel } - private val full24DateFormatter by lazy { - DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS") - } - companion object : MvRxViewModelFactory { @JvmStatic @@ -98,54 +94,7 @@ class KeyRequestViewModel @AssistedInject constructor( // this can take long val eventList = session.cryptoService().getGossipingEvents() // clean it a bit to - val raw = buildString { - eventList.forEach { - val clearType = it.getClearType() - append("[${getFormattedDate(it.ageLocalTs)}] $clearType from:${it.senderId} - ") - when (clearType) { - EventType.ROOM_KEY_REQUEST -> { - val content = it.getClearContent().toModel() - append("reqId:${content?.requestId} action:${content?.action} ") - if (content?.action == GossipingToDeviceObject.ACTION_SHARE_REQUEST) { - append("sessionId: ${content.body?.sessionId} ") - } - append("requestedBy: ${content?.requestingDeviceId}") - } - EventType.FORWARDED_ROOM_KEY -> { - val encryptedContent = it.content.toModel() - val content = it.getClearContent().toModel() - - append("sessionId:${content?.sessionId} From Device (sender key):${encryptedContent?.senderKey}") - span("\nFrom Device (sender key):") { - textStyle = "bold" - } - } - EventType.ROOM_KEY -> { - val content = it.getClearContent() - append("sessionId:${content?.get("session_id")} roomId:${content?.get("room_id")} dest:${content?.get("_dest") ?: "me"}") - } - EventType.SEND_SECRET -> { - val content = it.getClearContent().toModel() - append("requestId:${content?.requestId} From Device:${it.mxDecryptionResult?.payload?.get("sender_device")}") - } - EventType.REQUEST_SECRET -> { - val content = it.getClearContent().toModel() - append("reqId:${content?.requestId} action:${content?.action} ") - if (content?.action == GossipingToDeviceObject.ACTION_SHARE_REQUEST) { - append("secretName:${content.secretName} ") - } - append("requestedBy:${content?.requestingDeviceId}") - } - EventType.ENCRYPTED -> { - append("Failed to Decrypt") - } - else -> { - append("??") - } - } - append("\n") - } - } + val raw = GossipingEventsSerializer().serialize(eventList) setState { copy(exporting = Success(Unit)) } @@ -157,11 +106,4 @@ class KeyRequestViewModel @AssistedInject constructor( } } } - - private fun getFormattedDate(ageLocalTs: Long?): String { - return ageLocalTs - ?.let { DateProvider.toLocalDateTime(it) } - ?.let { full24DateFormatter.format(it) } - ?: "?" - } } diff --git a/vector/src/main/res/layout/activity_bug_report.xml b/vector/src/main/res/layout/activity_bug_report.xml index 3bfb1f5429..34169f44f8 100644 --- a/vector/src/main/res/layout/activity_bug_report.xml +++ b/vector/src/main/res/layout/activity_bug_report.xml @@ -125,6 +125,15 @@ android:checked="true" android:text="@string/send_bug_report_include_crash_logs" /> + + Send logs Send crash logs + Send key share requests history Send screenshot Report bug Please describe the bug. What did you do? What did you expect to happen? What actually happened?