react-native-security-suite 0.6.6 → 0.6.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +1 -0
- package/android/src/main/AndroidManifest.xml +3 -48
- package/android/src/main/java/com/securitysuite/Sslpinning.java +2 -1
- package/package.json +1 -1
- package/android/src/main/java/com/securitysuite/NetworkLogger.java +0 -25
- package/android/src/main/java/com/securitysuite/api/BodyDecoder.kt +0 -35
- package/android/src/main/java/com/securitysuite/api/Chucker.kt +0 -108
- package/android/src/main/java/com/securitysuite/api/ChuckerCollector.kt +0 -129
- package/android/src/main/java/com/securitysuite/api/ChuckerInterceptor.kt +0 -280
- package/android/src/main/java/com/securitysuite/api/ExportFormat.kt +0 -12
- package/android/src/main/java/com/securitysuite/api/RetentionManager.kt +0 -109
- package/android/src/main/java/com/securitysuite/internal/data/entity/HttpHeader.kt +0 -8
- package/android/src/main/java/com/securitysuite/internal/data/entity/HttpTransaction.kt +0 -344
- package/android/src/main/java/com/securitysuite/internal/data/entity/HttpTransactionTuple.kt +0 -62
- package/android/src/main/java/com/securitysuite/internal/data/har/Har.kt +0 -13
- package/android/src/main/java/com/securitysuite/internal/data/har/Log.kt +0 -24
- package/android/src/main/java/com/securitysuite/internal/data/har/log/Browser.kt +0 -11
- package/android/src/main/java/com/securitysuite/internal/data/har/log/Creator.kt +0 -11
- package/android/src/main/java/com/securitysuite/internal/data/har/log/Entry.kt +0 -49
- package/android/src/main/java/com/securitysuite/internal/data/har/log/Page.kt +0 -14
- package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/Cache.kt +0 -12
- package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/Header.kt +0 -17
- package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/Request.kt +0 -35
- package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/Response.kt +0 -33
- package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/Timings.kt +0 -25
- package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/cache/SecondaryRequest.kt +0 -13
- package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/request/PostData.kt +0 -20
- package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/request/QueryString.kt +0 -23
- package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/request/postdata/Params.kt +0 -13
- package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/response/Content.kt +0 -30
- package/android/src/main/java/com/securitysuite/internal/data/har/log/page/PageTimings.kt +0 -11
- package/android/src/main/java/com/securitysuite/internal/data/model/DialogData.kt +0 -8
- package/android/src/main/java/com/securitysuite/internal/data/repository/HttpTransactionDatabaseRepository.kt +0 -60
- package/android/src/main/java/com/securitysuite/internal/data/repository/HttpTransactionRepository.kt +0 -33
- package/android/src/main/java/com/securitysuite/internal/data/repository/RepositoryProvider.kt +0 -38
- package/android/src/main/java/com/securitysuite/internal/data/room/ChuckerDatabase.kt +0 -22
- package/android/src/main/java/com/securitysuite/internal/data/room/HttpTransactionDao.kt +0 -53
- package/android/src/main/java/com/securitysuite/internal/support/BitmapUtils.kt +0 -45
- package/android/src/main/java/com/securitysuite/internal/support/CacheDirectoryProvider.kt +0 -11
- package/android/src/main/java/com/securitysuite/internal/support/ChessboardDrawable.kt +0 -76
- package/android/src/main/java/com/securitysuite/internal/support/ChuckerFileProvider.kt +0 -9
- package/android/src/main/java/com/securitysuite/internal/support/ClearDatabaseJobIntentServiceReceiver.kt +0 -14
- package/android/src/main/java/com/securitysuite/internal/support/ClearDatabaseService.kt +0 -32
- package/android/src/main/java/com/securitysuite/internal/support/ContextExt.kt +0 -22
- package/android/src/main/java/com/securitysuite/internal/support/DepletingSource.kt +0 -37
- package/android/src/main/java/com/securitysuite/internal/support/FileFactory.kt +0 -30
- package/android/src/main/java/com/securitysuite/internal/support/FileSaver.kt +0 -41
- package/android/src/main/java/com/securitysuite/internal/support/FormatUtils.kt +0 -117
- package/android/src/main/java/com/securitysuite/internal/support/FormattedUrl.kt +0 -76
- package/android/src/main/java/com/securitysuite/internal/support/HarUtils.kt +0 -28
- package/android/src/main/java/com/securitysuite/internal/support/HttpUrlUtils.kt +0 -11
- package/android/src/main/java/com/securitysuite/internal/support/JsonConverter.kt +0 -19
- package/android/src/main/java/com/securitysuite/internal/support/LimitingSource.kt +0 -22
- package/android/src/main/java/com/securitysuite/internal/support/LiveDataUtils.kt +0 -68
- package/android/src/main/java/com/securitysuite/internal/support/Logger.kt +0 -43
- package/android/src/main/java/com/securitysuite/internal/support/NotificationHelper.kt +0 -149
- package/android/src/main/java/com/securitysuite/internal/support/OkHttpUtils.kt +0 -86
- package/android/src/main/java/com/securitysuite/internal/support/OkioUtils.kt +0 -34
- package/android/src/main/java/com/securitysuite/internal/support/PlainTextDecoder.kt +0 -30
- package/android/src/main/java/com/securitysuite/internal/support/ReportingSink.kt +0 -114
- package/android/src/main/java/com/securitysuite/internal/support/RequestProcessor.kt +0 -102
- package/android/src/main/java/com/securitysuite/internal/support/ResponseProcessor.kt +0 -170
- package/android/src/main/java/com/securitysuite/internal/support/SearchHighlightUtil.kt +0 -80
- package/android/src/main/java/com/securitysuite/internal/support/Sharable.kt +0 -86
- package/android/src/main/java/com/securitysuite/internal/support/SpanTextUtil.kt +0 -202
- package/android/src/main/java/com/securitysuite/internal/support/TeeSource.kt +0 -68
- package/android/src/main/java/com/securitysuite/internal/support/TransactionCurlCommandSharable.kt +0 -46
- package/android/src/main/java/com/securitysuite/internal/support/TransactionDetailsHarSharable.kt +0 -11
- package/android/src/main/java/com/securitysuite/internal/support/TransactionDetailsSharable.kt +0 -73
- package/android/src/main/java/com/securitysuite/internal/support/TransactionDiffCallback.kt +0 -26
- package/android/src/main/java/com/securitysuite/internal/support/TransactionListDetailsSharable.kt +0 -23
- package/android/src/main/java/com/securitysuite/internal/ui/BaseChuckerActivity.kt +0 -35
- package/android/src/main/java/com/securitysuite/internal/ui/MainActivity.kt +0 -375
- package/android/src/main/java/com/securitysuite/internal/ui/MainViewModel.kt +0 -47
- package/android/src/main/java/com/securitysuite/internal/ui/transaction/PayloadType.kt +0 -6
- package/android/src/main/java/com/securitysuite/internal/ui/transaction/ProtocolResources.kt +0 -14
- package/android/src/main/java/com/securitysuite/internal/ui/transaction/TransactionActivity.kt +0 -186
- package/android/src/main/java/com/securitysuite/internal/ui/transaction/TransactionAdapter.kt +0 -139
- package/android/src/main/java/com/securitysuite/internal/ui/transaction/TransactionOverviewFragment.kt +0 -100
- package/android/src/main/java/com/securitysuite/internal/ui/transaction/TransactionPagerAdapter.kt +0 -29
- package/android/src/main/java/com/securitysuite/internal/ui/transaction/TransactionPayloadAdapter.kt +0 -269
- package/android/src/main/java/com/securitysuite/internal/ui/transaction/TransactionPayloadFragment.kt +0 -529
- package/android/src/main/java/com/securitysuite/internal/ui/transaction/TransactionViewModel.kt +0 -69
- package/android/src/main/res/A.java +0 -12
- package/android/src/main/res/color/chucker_fab_background_colour.xml +0 -5
- package/android/src/main/res/drawable/chucker_empty_payload.xml +0 -10
- package/android/src/main/res/drawable/chucker_ic_arrow_down.xml +0 -10
- package/android/src/main/res/drawable/chucker_ic_copy.xml +0 -12
- package/android/src/main/res/drawable/chucker_ic_decoded_url_white.xml +0 -10
- package/android/src/main/res/drawable/chucker_ic_delete_white.xml +0 -9
- package/android/src/main/res/drawable/chucker_ic_encoded_url_white.xml +0 -11
- package/android/src/main/res/drawable/chucker_ic_graphql.xml +0 -27
- package/android/src/main/res/drawable/chucker_ic_http.xml +0 -10
- package/android/src/main/res/drawable/chucker_ic_https.xml +0 -9
- package/android/src/main/res/drawable/chucker_ic_launcher_foreground.xml +0 -14
- package/android/src/main/res/drawable/chucker_ic_save_white.xml +0 -9
- package/android/src/main/res/drawable/chucker_ic_search_white.xml +0 -9
- package/android/src/main/res/drawable/chucker_ic_share_white.xml +0 -9
- package/android/src/main/res/drawable/chucker_ic_transaction_notification.xml +0 -9
- package/android/src/main/res/layout/activity_main.xml +0 -83
- package/android/src/main/res/layout/activity_transaction.xml +0 -48
- package/android/src/main/res/layout/fragment_transaction_overview.xml +0 -365
- package/android/src/main/res/layout/fragment_transaction_payload.xml +0 -132
- package/android/src/main/res/layout/list_item_transaction.xml +0 -122
- package/android/src/main/res/layout/transaction_item_body_line.xml +0 -13
- package/android/src/main/res/layout/transaction_item_copy.xml +0 -19
- package/android/src/main/res/layout/transaction_item_headers.xml +0 -12
- package/android/src/main/res/layout/transaction_item_image.xml +0 -16
- package/android/src/main/res/menu/chucker_transaction.xml +0 -46
- package/android/src/main/res/menu/chucker_transactions_list.xml +0 -41
- package/android/src/main/res/mipmap-anydpi-v26/chucker_ic_launcher.xml +0 -5
- package/android/src/main/res/mipmap-hdpi/chucker_ic_launcher.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/chucker_ic_launcher.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/chucker_ic_launcher.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/chucker_ic_launcher.png +0 -0
- package/android/src/main/res/values/chucker_ic_launcher_background.xml +0 -4
- package/android/src/main/res/values/colors.xml +0 -38
- package/android/src/main/res/values/dimens.xml +0 -10
- package/android/src/main/res/values/public.xml +0 -5
- package/android/src/main/res/values/strings.xml +0 -77
- package/android/src/main/res/values/styles.xml +0 -44
- package/android/src/main/res/values-es/strings.xml +0 -75
- package/android/src/main/res/values-night/colors.xml +0 -32
- package/android/src/main/res/xml/chucker_provider_paths.xml +0 -4
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
package com.securitysuite.internal.support
|
|
2
|
-
|
|
3
|
-
import android.content.Context
|
|
4
|
-
import com.securitysuite.internal.data.model.DialogData
|
|
5
|
-
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
6
|
-
|
|
7
|
-
internal fun Context.showDialog(
|
|
8
|
-
dialogData: DialogData,
|
|
9
|
-
onPositiveClick: (() -> Unit)?,
|
|
10
|
-
onNegativeClick: (() -> Unit)?,
|
|
11
|
-
) {
|
|
12
|
-
MaterialAlertDialogBuilder(this)
|
|
13
|
-
.setTitle(dialogData.title)
|
|
14
|
-
.setMessage(dialogData.message)
|
|
15
|
-
.setPositiveButton(dialogData.positiveButtonText) { _, _ ->
|
|
16
|
-
onPositiveClick?.invoke()
|
|
17
|
-
}
|
|
18
|
-
.setNegativeButton(dialogData.negativeButtonText) { _, _ ->
|
|
19
|
-
onNegativeClick?.invoke()
|
|
20
|
-
}
|
|
21
|
-
.show()
|
|
22
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
package com.securitysuite.internal.support
|
|
2
|
-
|
|
3
|
-
import okio.Buffer
|
|
4
|
-
import okio.ForwardingSource
|
|
5
|
-
import okio.Source
|
|
6
|
-
import okio.blackholeSink
|
|
7
|
-
import okio.buffer
|
|
8
|
-
import java.io.IOException
|
|
9
|
-
|
|
10
|
-
internal class DepletingSource(delegate: Source) : ForwardingSource(delegate) {
|
|
11
|
-
private var shouldDeplete = true
|
|
12
|
-
|
|
13
|
-
override fun read(
|
|
14
|
-
sink: Buffer,
|
|
15
|
-
byteCount: Long,
|
|
16
|
-
) = try {
|
|
17
|
-
val bytesRead = super.read(sink, byteCount)
|
|
18
|
-
if (bytesRead == -1L) shouldDeplete = false
|
|
19
|
-
bytesRead
|
|
20
|
-
} catch (e: IOException) {
|
|
21
|
-
shouldDeplete = false
|
|
22
|
-
throw e
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
override fun close() {
|
|
26
|
-
if (shouldDeplete) {
|
|
27
|
-
try {
|
|
28
|
-
delegate.buffer().readAll(blackholeSink())
|
|
29
|
-
} catch (e: IOException) {
|
|
30
|
-
Logger.error("An error occurred while depleting the source", e)
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
shouldDeplete = false
|
|
34
|
-
|
|
35
|
-
super.close()
|
|
36
|
-
}
|
|
37
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
package com.securitysuite.internal.support
|
|
2
|
-
|
|
3
|
-
import java.io.File
|
|
4
|
-
import java.io.IOException
|
|
5
|
-
import java.util.concurrent.atomic.AtomicLong
|
|
6
|
-
|
|
7
|
-
internal object FileFactory {
|
|
8
|
-
private val uniqueIdGenerator = AtomicLong()
|
|
9
|
-
|
|
10
|
-
fun create(directory: File) = create(directory, fileName = "chucker-${uniqueIdGenerator.getAndIncrement()}")
|
|
11
|
-
|
|
12
|
-
fun create(
|
|
13
|
-
directory: File,
|
|
14
|
-
fileName: String,
|
|
15
|
-
): File? =
|
|
16
|
-
try {
|
|
17
|
-
File(directory, fileName).apply {
|
|
18
|
-
if (exists() && !delete()) {
|
|
19
|
-
throw IOException("Failed to delete file $this")
|
|
20
|
-
}
|
|
21
|
-
parentFile?.mkdirs()
|
|
22
|
-
if (!createNewFile()) {
|
|
23
|
-
throw IOException("File $this already exists")
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
} catch (e: IOException) {
|
|
27
|
-
Logger.error("An error occurred while creating a file", e)
|
|
28
|
-
null
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
package com.securitysuite.internal.support
|
|
2
|
-
|
|
3
|
-
import android.content.ContentResolver
|
|
4
|
-
import android.net.Uri
|
|
5
|
-
import kotlinx.coroutines.Dispatchers
|
|
6
|
-
import kotlinx.coroutines.withContext
|
|
7
|
-
import okio.Source
|
|
8
|
-
import okio.buffer
|
|
9
|
-
import okio.sink
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Utility class to save a file from a [Source] to a [Uri].
|
|
13
|
-
*/
|
|
14
|
-
public object FileSaver {
|
|
15
|
-
/**
|
|
16
|
-
* Saves the data from the [source] to the file at the [uri] using the [contentResolver].
|
|
17
|
-
*
|
|
18
|
-
* @param source The source of the data to save.
|
|
19
|
-
* @param uri The URI of the file to save the data to.
|
|
20
|
-
* @param contentResolver The content resolver to use to save the data.
|
|
21
|
-
* @return `true` if the data was saved successfully, `false` otherwise.
|
|
22
|
-
*/
|
|
23
|
-
public suspend fun saveFile(
|
|
24
|
-
source: Source,
|
|
25
|
-
uri: Uri,
|
|
26
|
-
contentResolver: ContentResolver,
|
|
27
|
-
): Boolean =
|
|
28
|
-
withContext(Dispatchers.IO) {
|
|
29
|
-
runCatching {
|
|
30
|
-
contentResolver.openOutputStream(uri)?.use { outputStream ->
|
|
31
|
-
outputStream.sink().buffer().use { sink ->
|
|
32
|
-
sink.writeAll(source)
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}.onFailure {
|
|
36
|
-
Logger.error("Failed to save data to a file", it)
|
|
37
|
-
return@withContext false
|
|
38
|
-
}
|
|
39
|
-
return@withContext true
|
|
40
|
-
}
|
|
41
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
package com.securitysuite.internal.support
|
|
2
|
-
|
|
3
|
-
import com.securitysuite.internal.data.entity.HttpHeader
|
|
4
|
-
import com.google.gson.JsonParseException
|
|
5
|
-
import com.google.gson.JsonParser
|
|
6
|
-
import org.w3c.dom.Document
|
|
7
|
-
import org.xml.sax.InputSource
|
|
8
|
-
import org.xml.sax.SAXParseException
|
|
9
|
-
import java.io.ByteArrayInputStream
|
|
10
|
-
import java.io.IOException
|
|
11
|
-
import java.io.StringWriter
|
|
12
|
-
import java.io.UnsupportedEncodingException
|
|
13
|
-
import java.net.URLDecoder
|
|
14
|
-
import java.nio.charset.Charset
|
|
15
|
-
import java.util.Locale
|
|
16
|
-
import javax.xml.XMLConstants
|
|
17
|
-
import javax.xml.parsers.DocumentBuilder
|
|
18
|
-
import javax.xml.parsers.DocumentBuilderFactory
|
|
19
|
-
import javax.xml.transform.OutputKeys
|
|
20
|
-
import javax.xml.transform.TransformerException
|
|
21
|
-
import javax.xml.transform.TransformerFactory
|
|
22
|
-
import javax.xml.transform.dom.DOMSource
|
|
23
|
-
import javax.xml.transform.stream.StreamResult
|
|
24
|
-
import kotlin.math.ln
|
|
25
|
-
import kotlin.math.pow
|
|
26
|
-
|
|
27
|
-
internal object FormatUtils {
|
|
28
|
-
private const val SI_MULTIPLE = 1000
|
|
29
|
-
private const val BASE_TWO_MULTIPLE = 1024
|
|
30
|
-
|
|
31
|
-
fun formatHeaders(
|
|
32
|
-
httpHeaders: List<HttpHeader>?,
|
|
33
|
-
withMarkup: Boolean,
|
|
34
|
-
): String {
|
|
35
|
-
return httpHeaders?.joinToString(separator = "") { header ->
|
|
36
|
-
if (withMarkup) {
|
|
37
|
-
"<b> ${header.name}: </b>${header.value} <br />"
|
|
38
|
-
} else {
|
|
39
|
-
"${header.name}: ${header.value}\n"
|
|
40
|
-
}
|
|
41
|
-
} ?: ""
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
fun formatByteCount(
|
|
45
|
-
bytes: Long,
|
|
46
|
-
si: Boolean,
|
|
47
|
-
): String {
|
|
48
|
-
val unit = if (si) SI_MULTIPLE else BASE_TWO_MULTIPLE
|
|
49
|
-
|
|
50
|
-
if (bytes < unit) {
|
|
51
|
-
return "$bytes B"
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
val exp = (ln(bytes.toDouble()) / ln(unit.toDouble())).toInt()
|
|
55
|
-
val pre = (if (si) "kMGTPE" else "KMGTPE")[exp - 1] + if (si) "" else "i"
|
|
56
|
-
|
|
57
|
-
return String.format(Locale.US, "%.1f %sB", bytes / unit.toDouble().pow(exp.toDouble()), pre)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
fun formatJson(json: String): String {
|
|
61
|
-
return try {
|
|
62
|
-
val je = JsonParser.parseString(json)
|
|
63
|
-
JsonConverter.instance.toJson(je)
|
|
64
|
-
} catch (e: JsonParseException) {
|
|
65
|
-
json
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
fun formatXml(xml: String): String {
|
|
70
|
-
return try {
|
|
71
|
-
val documentFactory: DocumentBuilderFactory = DocumentBuilderFactory.newInstance()
|
|
72
|
-
// This flag is required for security reasons
|
|
73
|
-
documentFactory.isExpandEntityReferences = false
|
|
74
|
-
|
|
75
|
-
val documentBuilder: DocumentBuilder = documentFactory.newDocumentBuilder()
|
|
76
|
-
val inputSource = InputSource(ByteArrayInputStream(xml.toByteArray(Charset.defaultCharset())))
|
|
77
|
-
val document: Document = documentBuilder.parse(inputSource)
|
|
78
|
-
|
|
79
|
-
val domSource = DOMSource(document)
|
|
80
|
-
val writer = StringWriter()
|
|
81
|
-
val result = StreamResult(writer)
|
|
82
|
-
|
|
83
|
-
TransformerFactory.newInstance().apply {
|
|
84
|
-
setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true)
|
|
85
|
-
}.newTransformer().apply {
|
|
86
|
-
setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2")
|
|
87
|
-
setOutputProperty(OutputKeys.INDENT, "yes")
|
|
88
|
-
transform(domSource, result)
|
|
89
|
-
}
|
|
90
|
-
writer.toString()
|
|
91
|
-
} catch (ignore: SAXParseException) {
|
|
92
|
-
xml
|
|
93
|
-
} catch (ignore: IOException) {
|
|
94
|
-
xml
|
|
95
|
-
} catch (ignore: TransformerException) {
|
|
96
|
-
xml
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
fun formatUrlEncodedForm(form: String): String {
|
|
101
|
-
return try {
|
|
102
|
-
if (form.isBlank()) {
|
|
103
|
-
return form
|
|
104
|
-
}
|
|
105
|
-
form.split("&").joinToString(separator = "\n") { entry ->
|
|
106
|
-
val keyValue = entry.split("=")
|
|
107
|
-
val key = keyValue[0]
|
|
108
|
-
val value = if (keyValue.size > 1) URLDecoder.decode(keyValue[1], "UTF-8") else ""
|
|
109
|
-
"$key: $value"
|
|
110
|
-
}
|
|
111
|
-
} catch (ignore: IllegalArgumentException) {
|
|
112
|
-
form
|
|
113
|
-
} catch (ignore: UnsupportedEncodingException) {
|
|
114
|
-
form
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
package com.securitysuite.internal.support
|
|
2
|
-
|
|
3
|
-
import okhttp3.HttpUrl
|
|
4
|
-
|
|
5
|
-
internal class FormattedUrl private constructor(
|
|
6
|
-
val scheme: String,
|
|
7
|
-
val host: String,
|
|
8
|
-
val port: Int,
|
|
9
|
-
val path: String,
|
|
10
|
-
val query: String,
|
|
11
|
-
) {
|
|
12
|
-
val pathWithQuery: String
|
|
13
|
-
get() =
|
|
14
|
-
if (query.isBlank()) {
|
|
15
|
-
path
|
|
16
|
-
} else {
|
|
17
|
-
"$path?$query"
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
val url: String
|
|
21
|
-
get() {
|
|
22
|
-
return if (shouldShowPort()) {
|
|
23
|
-
"$scheme://$host:$port$pathWithQuery"
|
|
24
|
-
} else {
|
|
25
|
-
"$scheme://$host$pathWithQuery"
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
private fun shouldShowPort(): Boolean {
|
|
30
|
-
if (scheme == "https" && port == HTTPS_PORT) {
|
|
31
|
-
return false
|
|
32
|
-
}
|
|
33
|
-
if (scheme == "http" && port == HTTP_PORT) {
|
|
34
|
-
return false
|
|
35
|
-
}
|
|
36
|
-
return true
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
companion object {
|
|
40
|
-
private const val HTTPS_PORT = 443
|
|
41
|
-
private const val HTTP_PORT = 80
|
|
42
|
-
|
|
43
|
-
fun fromHttpUrl(
|
|
44
|
-
httpUrl: HttpUrl,
|
|
45
|
-
encoded: Boolean,
|
|
46
|
-
): FormattedUrl {
|
|
47
|
-
return if (encoded) {
|
|
48
|
-
encodedUrl(httpUrl)
|
|
49
|
-
} else {
|
|
50
|
-
decodedUrl(httpUrl)
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
private fun encodedUrl(httpUrl: HttpUrl): FormattedUrl {
|
|
55
|
-
val path = httpUrl.encodedPathSegments.joinToString("/")
|
|
56
|
-
return FormattedUrl(
|
|
57
|
-
httpUrl.scheme,
|
|
58
|
-
httpUrl.host,
|
|
59
|
-
httpUrl.port,
|
|
60
|
-
if (path.isNotBlank()) "/$path" else "",
|
|
61
|
-
httpUrl.encodedQuery.orEmpty(),
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
private fun decodedUrl(httpUrl: HttpUrl): FormattedUrl {
|
|
66
|
-
val path = httpUrl.pathSegments.joinToString("/")
|
|
67
|
-
return FormattedUrl(
|
|
68
|
-
httpUrl.scheme,
|
|
69
|
-
httpUrl.host,
|
|
70
|
-
httpUrl.port,
|
|
71
|
-
if (path.isNotBlank()) "/$path" else "",
|
|
72
|
-
httpUrl.query.orEmpty(),
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
package com.securitysuite.internal.support
|
|
2
|
-
|
|
3
|
-
import com.securitysuite.internal.data.entity.HttpTransaction
|
|
4
|
-
import com.securitysuite.internal.data.har.Har
|
|
5
|
-
import com.securitysuite.internal.data.har.log.Creator
|
|
6
|
-
import kotlinx.coroutines.Dispatchers
|
|
7
|
-
import kotlinx.coroutines.withContext
|
|
8
|
-
|
|
9
|
-
// http://www.softwareishard.com/blog/har-12-spec/
|
|
10
|
-
// https://github.com/ahmadnassri/har-spec/blob/master/versions/1.2.md
|
|
11
|
-
internal object HarUtils {
|
|
12
|
-
suspend fun harStringFromTransactions(
|
|
13
|
-
transactions: List<HttpTransaction>,
|
|
14
|
-
name: String,
|
|
15
|
-
version: String,
|
|
16
|
-
): String =
|
|
17
|
-
withContext(Dispatchers.Default) {
|
|
18
|
-
JsonConverter.nonNullSerializerInstance
|
|
19
|
-
.toJson(fromHttpTransactions(transactions, Creator(name, version)))
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
internal fun fromHttpTransactions(
|
|
23
|
-
transactions: List<HttpTransaction>,
|
|
24
|
-
creator: Creator,
|
|
25
|
-
): Har {
|
|
26
|
-
return Har(transactions, creator)
|
|
27
|
-
}
|
|
28
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
package com.securitysuite.internal.support
|
|
2
|
-
|
|
3
|
-
import okhttp3.HttpUrl
|
|
4
|
-
|
|
5
|
-
private const val PATH_SEGMENTS_DELIMITER = "/"
|
|
6
|
-
|
|
7
|
-
public fun HttpUrl.Builder.addNonBlankPathSegments(candidatePath: String): HttpUrl.Builder =
|
|
8
|
-
apply {
|
|
9
|
-
candidatePath.split(PATH_SEGMENTS_DELIMITER).filter { it.isNotBlank() }
|
|
10
|
-
.forEach { item -> addPathSegment(item) }
|
|
11
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
package com.securitysuite.internal.support
|
|
2
|
-
|
|
3
|
-
import com.google.gson.Gson
|
|
4
|
-
import com.google.gson.GsonBuilder
|
|
5
|
-
|
|
6
|
-
internal object JsonConverter {
|
|
7
|
-
val nonNullSerializerInstance: Gson by lazy {
|
|
8
|
-
GsonBuilder()
|
|
9
|
-
.disableHtmlEscaping()
|
|
10
|
-
.setPrettyPrinting()
|
|
11
|
-
.create()
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
val instance: Gson by lazy {
|
|
15
|
-
nonNullSerializerInstance.newBuilder()
|
|
16
|
-
.serializeNulls()
|
|
17
|
-
.create()
|
|
18
|
-
}
|
|
19
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
package com.securitysuite.internal.support
|
|
2
|
-
|
|
3
|
-
import okio.Buffer
|
|
4
|
-
import okio.ForwardingSource
|
|
5
|
-
import okio.Source
|
|
6
|
-
|
|
7
|
-
internal class LimitingSource(
|
|
8
|
-
delegate: Source,
|
|
9
|
-
private val bytesCountThreshold: Long,
|
|
10
|
-
) : ForwardingSource(delegate) {
|
|
11
|
-
private var bytesRead = 0L
|
|
12
|
-
val isThresholdReached get() = bytesRead >= bytesCountThreshold
|
|
13
|
-
|
|
14
|
-
override fun read(
|
|
15
|
-
sink: Buffer,
|
|
16
|
-
byteCount: Long,
|
|
17
|
-
) = if (!isThresholdReached) {
|
|
18
|
-
super.read(sink, byteCount).also { bytesRead += it }
|
|
19
|
-
} else {
|
|
20
|
-
-1L
|
|
21
|
-
}
|
|
22
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
package com.securitysuite.internal.support
|
|
2
|
-
|
|
3
|
-
import android.annotation.SuppressLint
|
|
4
|
-
import androidx.arch.core.executor.ArchTaskExecutor
|
|
5
|
-
import androidx.lifecycle.LiveData
|
|
6
|
-
import androidx.lifecycle.MediatorLiveData
|
|
7
|
-
import java.util.concurrent.Executor
|
|
8
|
-
|
|
9
|
-
internal fun <T1, T2, R> LiveData<T1>.combineLatest(
|
|
10
|
-
other: LiveData<T2>,
|
|
11
|
-
func: (T1, T2) -> R,
|
|
12
|
-
): LiveData<R> {
|
|
13
|
-
return MediatorLiveData<R>().apply {
|
|
14
|
-
var lastA: T1? = null
|
|
15
|
-
var lastB: T2? = null
|
|
16
|
-
|
|
17
|
-
addSource(this@combineLatest) {
|
|
18
|
-
lastA = it
|
|
19
|
-
val observedB = lastB
|
|
20
|
-
if (it == null && value != null) {
|
|
21
|
-
value = null
|
|
22
|
-
} else if (it != null && observedB != null) {
|
|
23
|
-
value = func(it, observedB)
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
addSource(other) {
|
|
28
|
-
lastB = it
|
|
29
|
-
val observedA = lastA
|
|
30
|
-
if (it == null && value != null) {
|
|
31
|
-
value = null
|
|
32
|
-
} else if (observedA != null && it != null) {
|
|
33
|
-
value = func(observedA, it)
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
internal fun <T1, T2> LiveData<T1>.combineLatest(other: LiveData<T2>): LiveData<Pair<T1, T2>> {
|
|
40
|
-
return combineLatest(other) { a, b -> a to b }
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Unlike built-in extension operation is performed on a provided thread pool.
|
|
44
|
-
// This is needed in our case since we compare requests and responses which can be big
|
|
45
|
-
// and result in frame drops.
|
|
46
|
-
internal fun <T> LiveData<T>.distinctUntilChanged(
|
|
47
|
-
executor: Executor = ioExecutor(),
|
|
48
|
-
areEqual: (old: T, new: T) -> Boolean = { old, new -> old == new },
|
|
49
|
-
): LiveData<T> {
|
|
50
|
-
val distinctMediator = MediatorLiveData<T>()
|
|
51
|
-
var old = uninitializedToken
|
|
52
|
-
distinctMediator.addSource(this) { new ->
|
|
53
|
-
executor.execute {
|
|
54
|
-
@Suppress("UNCHECKED_CAST")
|
|
55
|
-
if (old === uninitializedToken || !areEqual(old as T, new)) {
|
|
56
|
-
old = new
|
|
57
|
-
distinctMediator.postValue(new)
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return distinctMediator
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
private val uninitializedToken: Any? = Any()
|
|
65
|
-
|
|
66
|
-
// It is lesser evil than providing a custom executor.
|
|
67
|
-
@SuppressLint("RestrictedApi")
|
|
68
|
-
private fun ioExecutor() = ArchTaskExecutor.getIOThreadExecutor()
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
package com.securitysuite.internal.support
|
|
2
|
-
|
|
3
|
-
import com.securitysuite.api.Chucker
|
|
4
|
-
|
|
5
|
-
internal interface Logger {
|
|
6
|
-
fun info(
|
|
7
|
-
message: String,
|
|
8
|
-
throwable: Throwable? = null,
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
fun warn(
|
|
12
|
-
message: String,
|
|
13
|
-
throwable: Throwable? = null,
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
fun error(
|
|
17
|
-
message: String,
|
|
18
|
-
throwable: Throwable? = null,
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
companion object : Logger {
|
|
22
|
-
override fun info(
|
|
23
|
-
message: String,
|
|
24
|
-
throwable: Throwable?,
|
|
25
|
-
) {
|
|
26
|
-
Chucker.logger.info(message, throwable)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
override fun warn(
|
|
30
|
-
message: String,
|
|
31
|
-
throwable: Throwable?,
|
|
32
|
-
) {
|
|
33
|
-
Chucker.logger.warn(message, throwable)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
override fun error(
|
|
37
|
-
message: String,
|
|
38
|
-
throwable: Throwable?,
|
|
39
|
-
) {
|
|
40
|
-
Chucker.logger.error(message, throwable)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
package com.securitysuite.internal.support
|
|
2
|
-
|
|
3
|
-
import android.app.NotificationChannel
|
|
4
|
-
import android.app.NotificationManager
|
|
5
|
-
import android.app.PendingIntent
|
|
6
|
-
import android.content.Context
|
|
7
|
-
import android.content.Intent
|
|
8
|
-
import android.os.Build
|
|
9
|
-
import android.util.LongSparseArray
|
|
10
|
-
import androidx.core.app.NotificationCompat
|
|
11
|
-
import androidx.core.content.ContextCompat
|
|
12
|
-
import com.securitysuite.R
|
|
13
|
-
import com.securitysuite.api.Chucker
|
|
14
|
-
import com.securitysuite.internal.data.entity.HttpTransaction
|
|
15
|
-
import com.securitysuite.internal.ui.BaseChuckerActivity
|
|
16
|
-
import java.util.HashSet
|
|
17
|
-
|
|
18
|
-
internal class NotificationHelper(val context: Context) {
|
|
19
|
-
companion object {
|
|
20
|
-
private const val TRANSACTIONS_CHANNEL_ID = "chucker_transactions"
|
|
21
|
-
|
|
22
|
-
private const val TRANSACTION_NOTIFICATION_ID = 1138
|
|
23
|
-
|
|
24
|
-
private const val BUFFER_SIZE = 10
|
|
25
|
-
private const val INTENT_REQUEST_CODE = 11
|
|
26
|
-
private val transactionBuffer = LongSparseArray<HttpTransaction>()
|
|
27
|
-
private val transactionIdsSet = HashSet<Long>()
|
|
28
|
-
|
|
29
|
-
fun clearBuffer() {
|
|
30
|
-
synchronized(transactionBuffer) {
|
|
31
|
-
transactionBuffer.clear()
|
|
32
|
-
transactionIdsSet.clear()
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
private val notificationManager: NotificationManager =
|
|
38
|
-
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
39
|
-
|
|
40
|
-
private val transactionsScreenIntent by lazy {
|
|
41
|
-
PendingIntent.getActivity(
|
|
42
|
-
context,
|
|
43
|
-
TRANSACTION_NOTIFICATION_ID,
|
|
44
|
-
Chucker.getLaunchIntent(context),
|
|
45
|
-
PendingIntent.FLAG_UPDATE_CURRENT or immutableFlag(),
|
|
46
|
-
)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
init {
|
|
50
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
51
|
-
val transactionsChannel =
|
|
52
|
-
NotificationChannel(
|
|
53
|
-
TRANSACTIONS_CHANNEL_ID,
|
|
54
|
-
context.getString(R.string.chucker_network_notification_category),
|
|
55
|
-
NotificationManager.IMPORTANCE_LOW,
|
|
56
|
-
)
|
|
57
|
-
notificationManager.createNotificationChannels(listOf(transactionsChannel))
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
private fun addToBuffer(transaction: HttpTransaction) {
|
|
62
|
-
if (transaction.id == 0L) {
|
|
63
|
-
// Don't store Transactions with an invalid ID (0).
|
|
64
|
-
// Transaction with an Invalid ID will be shown twice in the notification
|
|
65
|
-
// with both the invalid and the valid ID and we want to avoid this.
|
|
66
|
-
return
|
|
67
|
-
}
|
|
68
|
-
synchronized(transactionBuffer) {
|
|
69
|
-
transactionIdsSet.add(transaction.id)
|
|
70
|
-
transactionBuffer.put(transaction.id, transaction)
|
|
71
|
-
if (transactionBuffer.size() > BUFFER_SIZE) {
|
|
72
|
-
transactionBuffer.removeAt(0)
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
private fun canShowNotifications(): Boolean {
|
|
78
|
-
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
79
|
-
notificationManager.areNotificationsEnabled()
|
|
80
|
-
} else {
|
|
81
|
-
true
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
fun show(transaction: HttpTransaction) {
|
|
86
|
-
addToBuffer(transaction)
|
|
87
|
-
if (!BaseChuckerActivity.isInForeground && canShowNotifications()) {
|
|
88
|
-
val builder =
|
|
89
|
-
NotificationCompat.Builder(context, TRANSACTIONS_CHANNEL_ID)
|
|
90
|
-
.setContentIntent(transactionsScreenIntent)
|
|
91
|
-
.setLocalOnly(true)
|
|
92
|
-
.setSmallIcon(R.drawable.chucker_ic_transaction_notification)
|
|
93
|
-
.setColor(ContextCompat.getColor(context, R.color.chucker_color_primary))
|
|
94
|
-
.setContentTitle(context.getString(R.string.chucker_http_notification_title))
|
|
95
|
-
.setAutoCancel(true)
|
|
96
|
-
.addAction(createClearAction())
|
|
97
|
-
val inboxStyle = NotificationCompat.InboxStyle()
|
|
98
|
-
synchronized(transactionBuffer) {
|
|
99
|
-
var count = 0
|
|
100
|
-
for (i in transactionBuffer.size() - 1 downTo 0) {
|
|
101
|
-
val bufferedTransaction = transactionBuffer.valueAt(i)
|
|
102
|
-
if ((bufferedTransaction != null) && count < BUFFER_SIZE) {
|
|
103
|
-
if (count == 0) {
|
|
104
|
-
builder.setContentText(bufferedTransaction.notificationText)
|
|
105
|
-
}
|
|
106
|
-
inboxStyle.addLine(bufferedTransaction.notificationText)
|
|
107
|
-
}
|
|
108
|
-
count++
|
|
109
|
-
}
|
|
110
|
-
builder.setStyle(inboxStyle)
|
|
111
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
112
|
-
builder.setSubText(transactionIdsSet.size.toString())
|
|
113
|
-
} else {
|
|
114
|
-
builder.setNumber(transactionIdsSet.size)
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
notificationManager.notify(TRANSACTION_NOTIFICATION_ID, builder.build())
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
private fun createClearAction(): NotificationCompat.Action {
|
|
122
|
-
val clearTitle = context.getString(R.string.chucker_clear)
|
|
123
|
-
val clearTransactionsBroadcastIntent =
|
|
124
|
-
Intent(context, ClearDatabaseJobIntentServiceReceiver::class.java)
|
|
125
|
-
val pendingBroadcastIntent =
|
|
126
|
-
PendingIntent.getBroadcast(
|
|
127
|
-
context,
|
|
128
|
-
INTENT_REQUEST_CODE,
|
|
129
|
-
clearTransactionsBroadcastIntent,
|
|
130
|
-
PendingIntent.FLAG_ONE_SHOT or immutableFlag(),
|
|
131
|
-
)
|
|
132
|
-
return NotificationCompat.Action(
|
|
133
|
-
R.drawable.chucker_ic_delete_white,
|
|
134
|
-
clearTitle,
|
|
135
|
-
pendingBroadcastIntent,
|
|
136
|
-
)
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
fun dismissNotifications() {
|
|
140
|
-
notificationManager.cancel(TRANSACTION_NOTIFICATION_ID)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
private fun immutableFlag() =
|
|
144
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
145
|
-
PendingIntent.FLAG_IMMUTABLE
|
|
146
|
-
} else {
|
|
147
|
-
0
|
|
148
|
-
}
|
|
149
|
-
}
|