react-native-security-suite 0.6.7 → 0.7.0

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.
Files changed (123) hide show
  1. package/android/build.gradle +0 -15
  2. package/android/src/main/AndroidManifest.xml +3 -48
  3. package/package.json +1 -1
  4. package/android/src/main/java/com/securitysuite/NetworkLogger.java +0 -25
  5. package/android/src/main/java/com/securitysuite/api/BodyDecoder.kt +0 -35
  6. package/android/src/main/java/com/securitysuite/api/Chucker.kt +0 -108
  7. package/android/src/main/java/com/securitysuite/api/ChuckerCollector.kt +0 -129
  8. package/android/src/main/java/com/securitysuite/api/ChuckerInterceptor.kt +0 -280
  9. package/android/src/main/java/com/securitysuite/api/ExportFormat.kt +0 -12
  10. package/android/src/main/java/com/securitysuite/api/RetentionManager.kt +0 -109
  11. package/android/src/main/java/com/securitysuite/internal/data/entity/HttpHeader.kt +0 -8
  12. package/android/src/main/java/com/securitysuite/internal/data/entity/HttpTransaction.kt +0 -344
  13. package/android/src/main/java/com/securitysuite/internal/data/entity/HttpTransactionTuple.kt +0 -62
  14. package/android/src/main/java/com/securitysuite/internal/data/har/Har.kt +0 -13
  15. package/android/src/main/java/com/securitysuite/internal/data/har/Log.kt +0 -24
  16. package/android/src/main/java/com/securitysuite/internal/data/har/log/Browser.kt +0 -11
  17. package/android/src/main/java/com/securitysuite/internal/data/har/log/Creator.kt +0 -11
  18. package/android/src/main/java/com/securitysuite/internal/data/har/log/Entry.kt +0 -49
  19. package/android/src/main/java/com/securitysuite/internal/data/har/log/Page.kt +0 -14
  20. package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/Cache.kt +0 -12
  21. package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/Header.kt +0 -17
  22. package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/Request.kt +0 -35
  23. package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/Response.kt +0 -33
  24. package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/Timings.kt +0 -25
  25. package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/cache/SecondaryRequest.kt +0 -13
  26. package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/request/PostData.kt +0 -20
  27. package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/request/QueryString.kt +0 -23
  28. package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/request/postdata/Params.kt +0 -13
  29. package/android/src/main/java/com/securitysuite/internal/data/har/log/entry/response/Content.kt +0 -30
  30. package/android/src/main/java/com/securitysuite/internal/data/har/log/page/PageTimings.kt +0 -11
  31. package/android/src/main/java/com/securitysuite/internal/data/model/DialogData.kt +0 -8
  32. package/android/src/main/java/com/securitysuite/internal/data/repository/HttpTransactionDatabaseRepository.kt +0 -60
  33. package/android/src/main/java/com/securitysuite/internal/data/repository/HttpTransactionRepository.kt +0 -33
  34. package/android/src/main/java/com/securitysuite/internal/data/repository/RepositoryProvider.kt +0 -38
  35. package/android/src/main/java/com/securitysuite/internal/data/room/ChuckerDatabase.kt +0 -22
  36. package/android/src/main/java/com/securitysuite/internal/data/room/HttpTransactionDao.kt +0 -53
  37. package/android/src/main/java/com/securitysuite/internal/support/BitmapUtils.kt +0 -45
  38. package/android/src/main/java/com/securitysuite/internal/support/CacheDirectoryProvider.kt +0 -11
  39. package/android/src/main/java/com/securitysuite/internal/support/ChessboardDrawable.kt +0 -76
  40. package/android/src/main/java/com/securitysuite/internal/support/ChuckerFileProvider.kt +0 -9
  41. package/android/src/main/java/com/securitysuite/internal/support/ClearDatabaseJobIntentServiceReceiver.kt +0 -14
  42. package/android/src/main/java/com/securitysuite/internal/support/ClearDatabaseService.kt +0 -32
  43. package/android/src/main/java/com/securitysuite/internal/support/ContextExt.kt +0 -22
  44. package/android/src/main/java/com/securitysuite/internal/support/DepletingSource.kt +0 -37
  45. package/android/src/main/java/com/securitysuite/internal/support/FileFactory.kt +0 -30
  46. package/android/src/main/java/com/securitysuite/internal/support/FileSaver.kt +0 -41
  47. package/android/src/main/java/com/securitysuite/internal/support/FormatUtils.kt +0 -117
  48. package/android/src/main/java/com/securitysuite/internal/support/FormattedUrl.kt +0 -76
  49. package/android/src/main/java/com/securitysuite/internal/support/HarUtils.kt +0 -28
  50. package/android/src/main/java/com/securitysuite/internal/support/HttpUrlUtils.kt +0 -11
  51. package/android/src/main/java/com/securitysuite/internal/support/JsonConverter.kt +0 -19
  52. package/android/src/main/java/com/securitysuite/internal/support/LimitingSource.kt +0 -22
  53. package/android/src/main/java/com/securitysuite/internal/support/LiveDataUtils.kt +0 -68
  54. package/android/src/main/java/com/securitysuite/internal/support/Logger.kt +0 -43
  55. package/android/src/main/java/com/securitysuite/internal/support/NotificationHelper.kt +0 -149
  56. package/android/src/main/java/com/securitysuite/internal/support/OkHttpUtils.kt +0 -86
  57. package/android/src/main/java/com/securitysuite/internal/support/OkioUtils.kt +0 -34
  58. package/android/src/main/java/com/securitysuite/internal/support/PlainTextDecoder.kt +0 -30
  59. package/android/src/main/java/com/securitysuite/internal/support/ReportingSink.kt +0 -114
  60. package/android/src/main/java/com/securitysuite/internal/support/RequestProcessor.kt +0 -102
  61. package/android/src/main/java/com/securitysuite/internal/support/ResponseProcessor.kt +0 -170
  62. package/android/src/main/java/com/securitysuite/internal/support/SearchHighlightUtil.kt +0 -80
  63. package/android/src/main/java/com/securitysuite/internal/support/Sharable.kt +0 -86
  64. package/android/src/main/java/com/securitysuite/internal/support/SpanTextUtil.kt +0 -202
  65. package/android/src/main/java/com/securitysuite/internal/support/TeeSource.kt +0 -68
  66. package/android/src/main/java/com/securitysuite/internal/support/TransactionCurlCommandSharable.kt +0 -46
  67. package/android/src/main/java/com/securitysuite/internal/support/TransactionDetailsHarSharable.kt +0 -11
  68. package/android/src/main/java/com/securitysuite/internal/support/TransactionDetailsSharable.kt +0 -73
  69. package/android/src/main/java/com/securitysuite/internal/support/TransactionDiffCallback.kt +0 -26
  70. package/android/src/main/java/com/securitysuite/internal/support/TransactionListDetailsSharable.kt +0 -23
  71. package/android/src/main/java/com/securitysuite/internal/ui/BaseChuckerActivity.kt +0 -35
  72. package/android/src/main/java/com/securitysuite/internal/ui/MainActivity.kt +0 -375
  73. package/android/src/main/java/com/securitysuite/internal/ui/MainViewModel.kt +0 -47
  74. package/android/src/main/java/com/securitysuite/internal/ui/transaction/PayloadType.kt +0 -6
  75. package/android/src/main/java/com/securitysuite/internal/ui/transaction/ProtocolResources.kt +0 -14
  76. package/android/src/main/java/com/securitysuite/internal/ui/transaction/TransactionActivity.kt +0 -186
  77. package/android/src/main/java/com/securitysuite/internal/ui/transaction/TransactionAdapter.kt +0 -139
  78. package/android/src/main/java/com/securitysuite/internal/ui/transaction/TransactionOverviewFragment.kt +0 -100
  79. package/android/src/main/java/com/securitysuite/internal/ui/transaction/TransactionPagerAdapter.kt +0 -29
  80. package/android/src/main/java/com/securitysuite/internal/ui/transaction/TransactionPayloadAdapter.kt +0 -269
  81. package/android/src/main/java/com/securitysuite/internal/ui/transaction/TransactionPayloadFragment.kt +0 -529
  82. package/android/src/main/java/com/securitysuite/internal/ui/transaction/TransactionViewModel.kt +0 -69
  83. package/android/src/main/res/A.java +0 -12
  84. package/android/src/main/res/color/chucker_fab_background_colour.xml +0 -5
  85. package/android/src/main/res/drawable/chucker_empty_payload.xml +0 -10
  86. package/android/src/main/res/drawable/chucker_ic_arrow_down.xml +0 -10
  87. package/android/src/main/res/drawable/chucker_ic_copy.xml +0 -12
  88. package/android/src/main/res/drawable/chucker_ic_decoded_url_white.xml +0 -10
  89. package/android/src/main/res/drawable/chucker_ic_delete_white.xml +0 -9
  90. package/android/src/main/res/drawable/chucker_ic_encoded_url_white.xml +0 -11
  91. package/android/src/main/res/drawable/chucker_ic_graphql.xml +0 -27
  92. package/android/src/main/res/drawable/chucker_ic_http.xml +0 -10
  93. package/android/src/main/res/drawable/chucker_ic_https.xml +0 -9
  94. package/android/src/main/res/drawable/chucker_ic_launcher_foreground.xml +0 -14
  95. package/android/src/main/res/drawable/chucker_ic_save_white.xml +0 -9
  96. package/android/src/main/res/drawable/chucker_ic_search_white.xml +0 -9
  97. package/android/src/main/res/drawable/chucker_ic_share_white.xml +0 -9
  98. package/android/src/main/res/drawable/chucker_ic_transaction_notification.xml +0 -9
  99. package/android/src/main/res/layout/activity_main.xml +0 -83
  100. package/android/src/main/res/layout/activity_transaction.xml +0 -48
  101. package/android/src/main/res/layout/fragment_transaction_overview.xml +0 -365
  102. package/android/src/main/res/layout/fragment_transaction_payload.xml +0 -132
  103. package/android/src/main/res/layout/list_item_transaction.xml +0 -122
  104. package/android/src/main/res/layout/transaction_item_body_line.xml +0 -13
  105. package/android/src/main/res/layout/transaction_item_copy.xml +0 -19
  106. package/android/src/main/res/layout/transaction_item_headers.xml +0 -12
  107. package/android/src/main/res/layout/transaction_item_image.xml +0 -16
  108. package/android/src/main/res/menu/chucker_transaction.xml +0 -46
  109. package/android/src/main/res/menu/chucker_transactions_list.xml +0 -41
  110. package/android/src/main/res/mipmap-anydpi-v26/chucker_ic_launcher.xml +0 -5
  111. package/android/src/main/res/mipmap-hdpi/chucker_ic_launcher.png +0 -0
  112. package/android/src/main/res/mipmap-xhdpi/chucker_ic_launcher.png +0 -0
  113. package/android/src/main/res/mipmap-xxhdpi/chucker_ic_launcher.png +0 -0
  114. package/android/src/main/res/mipmap-xxxhdpi/chucker_ic_launcher.png +0 -0
  115. package/android/src/main/res/values/chucker_ic_launcher_background.xml +0 -4
  116. package/android/src/main/res/values/colors.xml +0 -38
  117. package/android/src/main/res/values/dimens.xml +0 -10
  118. package/android/src/main/res/values/public.xml +0 -5
  119. package/android/src/main/res/values/strings.xml +0 -77
  120. package/android/src/main/res/values/styles.xml +0 -44
  121. package/android/src/main/res/values-es/strings.xml +0 -75
  122. package/android/src/main/res/values-night/colors.xml +0 -32
  123. package/android/src/main/res/xml/chucker_provider_paths.xml +0 -4
@@ -1,529 +0,0 @@
1
- @file:Suppress("TooManyFunctions")
2
-
3
- package com.securitysuite.internal.ui.transaction
4
-
5
- import android.annotation.SuppressLint
6
- import android.app.Activity
7
- import android.content.ClipData
8
- import android.content.ClipboardManager
9
- import android.content.Context
10
- import android.graphics.Color
11
- import android.os.Bundle
12
- import android.text.SpannableStringBuilder
13
- import android.view.LayoutInflater
14
- import android.view.Menu
15
- import android.view.MenuInflater
16
- import android.view.View
17
- import android.view.ViewGroup
18
- import android.view.inputmethod.InputMethodManager
19
- import android.widget.Toast
20
- import androidx.activity.result.contract.ActivityResultContracts
21
- import androidx.appcompat.widget.SearchView
22
- import androidx.core.content.ContextCompat
23
- import androidx.core.text.HtmlCompat
24
- import androidx.core.text.bold
25
- import androidx.core.view.isVisible
26
- import androidx.fragment.app.Fragment
27
- import androidx.fragment.app.activityViewModels
28
- import androidx.lifecycle.Observer
29
- import androidx.lifecycle.lifecycleScope
30
- import androidx.lifecycle.withResumed
31
- import com.securitysuite.R
32
- import com.securitysuite.databinding.FragmentTransactionPayloadBinding
33
- import com.securitysuite.internal.data.entity.HttpTransaction
34
- import com.securitysuite.internal.support.FileSaver
35
- import com.securitysuite.internal.support.Logger
36
- import com.securitysuite.internal.support.calculateLuminance
37
- import com.securitysuite.internal.support.combineLatest
38
- import kotlinx.coroutines.Dispatchers
39
- import kotlinx.coroutines.delay
40
- import kotlinx.coroutines.launch
41
- import kotlinx.coroutines.withContext
42
- import okio.Source
43
- import okio.source
44
- import java.io.IOException
45
- import kotlin.math.abs
46
-
47
- internal class TransactionPayloadFragment :
48
- Fragment(), SearchView.OnQueryTextListener {
49
- private val viewModel: TransactionViewModel by activityViewModels { TransactionViewModelFactory() }
50
-
51
- private val payloadType: PayloadType by lazy(LazyThreadSafetyMode.NONE) {
52
- arguments?.getSerializable(ARG_TYPE) as PayloadType
53
- }
54
-
55
- private val saveToFile =
56
- registerForActivityResult(ActivityResultContracts.CreateDocument()) { uri ->
57
- val transaction = viewModel.transaction.value
58
- val applicationContext = requireContext().applicationContext
59
- if (uri != null && transaction != null) {
60
- lifecycleScope.launch {
61
- val source =
62
- runCatching {
63
- prepareDataToSave(payloadType, transaction)
64
- }.getOrElse {
65
- Logger.error("Failed to save transaction to a file", it)
66
- return@launch
67
- }
68
- val result = FileSaver.saveFile(source, uri, applicationContext.contentResolver)
69
- val toastMessageId =
70
- if (result) {
71
- R.string.chucker_file_saved
72
- } else {
73
- R.string.chucker_file_not_saved
74
- }
75
- Toast.makeText(applicationContext, toastMessageId, Toast.LENGTH_SHORT).show()
76
- }
77
- } else {
78
- Toast.makeText(
79
- applicationContext,
80
- R.string.chucker_save_failed_to_open_document,
81
- Toast.LENGTH_SHORT,
82
- ).show()
83
- }
84
- }
85
-
86
- private lateinit var payloadBinding: FragmentTransactionPayloadBinding
87
- private val payloadAdapter = TransactionBodyAdapter(::copyResponse)
88
-
89
- private var backgroundSpanColor: Int = Color.YELLOW
90
- private var foregroundSpanColor: Int = Color.RED
91
- private var backgroundSpanColorSearchItem: Int = Color.GREEN
92
-
93
- private val scrollableIndices = arrayListOf<TransactionBodyAdapter.SearchItemBodyLine>()
94
- private var currentSearchScrollIndex = -1
95
- private var currentSearchQuery: String = ""
96
-
97
- override fun onCreate(savedInstanceState: Bundle?) {
98
- super.onCreate(savedInstanceState)
99
- setHasOptionsMenu(true)
100
- }
101
-
102
- override fun onCreateView(
103
- inflater: LayoutInflater,
104
- container: ViewGroup?,
105
- savedInstanceState: Bundle?,
106
- ): View {
107
- payloadBinding =
108
- FragmentTransactionPayloadBinding.inflate(
109
- inflater,
110
- container,
111
- false,
112
- )
113
- return payloadBinding.root
114
- }
115
-
116
- override fun onViewCreated(
117
- view: View,
118
- savedInstanceState: Bundle?,
119
- ) {
120
- super.onViewCreated(view, savedInstanceState)
121
-
122
- payloadBinding.payloadRecyclerView.apply {
123
- setHasFixedSize(true)
124
- adapter = payloadAdapter
125
- }
126
-
127
- viewModel.transaction.combineLatest(viewModel.formatRequestBody).observe(
128
- viewLifecycleOwner,
129
- Observer { (transaction, formatRequestBody) ->
130
- if (transaction == null) return@Observer
131
- lifecycleScope.launch {
132
- payloadBinding.loadingProgress.visibility = View.VISIBLE
133
-
134
- val result = processPayload(payloadType, transaction, formatRequestBody)
135
- if (result.isEmpty()) {
136
- showEmptyState()
137
- } else {
138
- payloadAdapter.setItems(result)
139
- showPayloadState()
140
- }
141
- // Invalidating menu, because we need to hide menu items for empty payloads
142
- requireActivity().invalidateOptionsMenu()
143
-
144
- payloadBinding.loadingProgress.visibility = View.GONE
145
- }
146
- },
147
- )
148
- payloadBinding.searchNavButton.setOnClickListener {
149
- onSearchScrollerButtonClick(true)
150
- }
151
- payloadBinding.searchNavButtonUp.setOnClickListener {
152
- onSearchScrollerButtonClick(false)
153
- }
154
- }
155
-
156
- private fun copyResponse() {
157
- val transaction = viewModel.transaction.value
158
-
159
- when (payloadType.name) {
160
- PayloadType.REQUEST.name -> {
161
- transaction?.requestBody?.let { request ->
162
- copyToClipboard(
163
- request,
164
- getString(R.string.chucker_request),
165
- getString(R.string.chucker_request_copied),
166
- )
167
- }
168
- }
169
-
170
- PayloadType.RESPONSE.name -> {
171
- transaction?.responseBody?.let { response ->
172
- copyToClipboard(
173
- response,
174
- getString(R.string.chucker_response),
175
- getString(R.string.chucker_response_copied),
176
- )
177
- }
178
- }
179
- }
180
- }
181
-
182
- private fun copyToClipboard(
183
- payload: String,
184
- payloadType: String,
185
- toastSuccessMessage: String,
186
- ) {
187
- val clipboard = activity?.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
188
- val clip = ClipData.newPlainText(payloadType, payload)
189
- clipboard.setPrimaryClip(clip)
190
-
191
- Toast.makeText(activity, toastSuccessMessage, Toast.LENGTH_LONG)
192
- .show()
193
- }
194
-
195
- private fun onSearchScrollerButtonClick(goNext: Boolean) {
196
- // hide the keyboard if visible
197
- val inputMethodManager = activity?.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
198
- if (inputMethodManager.isAcceptingText) {
199
- activity?.currentFocus?.clearFocus()
200
- inputMethodManager.hideSoftInputFromWindow(view?.windowToken, 0)
201
- }
202
-
203
- if (scrollableIndices.isNotEmpty()) {
204
- val scrollToIndex =
205
- if (goNext) {
206
- ((currentSearchScrollIndex + 1) % scrollableIndices.size)
207
- } else {
208
- (abs(currentSearchScrollIndex - 1 + scrollableIndices.size) % scrollableIndices.size)
209
- }
210
-
211
- scrollToSearchedItemPosition(scrollToIndex)
212
- }
213
- }
214
-
215
- private fun showEmptyState() {
216
- payloadBinding.apply {
217
- emptyPayloadTextView.text =
218
- if (payloadType == PayloadType.RESPONSE) {
219
- getString(R.string.chucker_response_is_empty)
220
- } else {
221
- getString(R.string.chucker_request_is_empty)
222
- }
223
- emptyStateGroup.visibility = View.VISIBLE
224
- payloadRecyclerView.visibility = View.GONE
225
- }
226
- }
227
-
228
- private fun showPayloadState() {
229
- payloadBinding.apply {
230
- emptyStateGroup.visibility = View.GONE
231
- payloadRecyclerView.visibility = View.VISIBLE
232
- }
233
- }
234
-
235
- @SuppressLint("NewApi")
236
- override fun onCreateOptionsMenu(
237
- menu: Menu,
238
- inflater: MenuInflater,
239
- ) {
240
- val transaction = viewModel.transaction.value
241
-
242
- if (shouldShowSearchIcon(transaction)) {
243
- val searchMenuItem = menu.findItem(R.id.search)
244
- searchMenuItem.isVisible = true
245
- val searchView = searchMenuItem.actionView as SearchView
246
- searchView.setOnQueryTextListener(this)
247
- searchView.setIconifiedByDefault(true)
248
- }
249
-
250
- if (shouldShowSaveIcon(transaction)) {
251
- menu.findItem(R.id.save_body).apply {
252
- isVisible = true
253
- setOnMenuItemClickListener {
254
- createFileToSaveBody()
255
- true
256
- }
257
- }
258
- }
259
-
260
- if (payloadType == PayloadType.REQUEST) {
261
- viewModel.doesRequestBodyRequireEncoding.observe(
262
- viewLifecycleOwner,
263
- { menu.findItem(R.id.encode_url).isVisible = it },
264
- )
265
- } else {
266
- menu.findItem(R.id.encode_url).isVisible = false
267
- }
268
-
269
- super.onCreateOptionsMenu(menu, inflater)
270
- }
271
-
272
- private fun shouldShowSaveIcon(transaction: HttpTransaction?) =
273
- when {
274
- (payloadType == PayloadType.REQUEST) -> (0L != (transaction?.requestPayloadSize))
275
- (payloadType == PayloadType.RESPONSE) -> (0L != (transaction?.responsePayloadSize))
276
- else -> true
277
- }
278
-
279
- private fun shouldShowSearchIcon(transaction: HttpTransaction?) =
280
- when (payloadType) {
281
- PayloadType.REQUEST -> {
282
- (false == transaction?.isRequestBodyEncoded) && (0L != (transaction.requestPayloadSize))
283
- }
284
-
285
- PayloadType.RESPONSE -> {
286
- (false == transaction?.isResponseBodyEncoded) && (0L != (transaction.responsePayloadSize))
287
- }
288
- }
289
-
290
- override fun onAttach(context: Context) {
291
- super.onAttach(context)
292
- backgroundSpanColor = ContextCompat.getColor(context, R.color.chucker_background_span_color)
293
- foregroundSpanColor = ContextCompat.getColor(context, R.color.chucker_foreground_span_color)
294
- }
295
-
296
- private fun createFileToSaveBody() {
297
- val transaction = viewModel.transaction.value
298
- if (transaction != null && isBodyEmpty(payloadType, transaction)) {
299
- Toast.makeText(
300
- activity,
301
- R.string.chucker_file_not_saved_body_is_empty,
302
- Toast.LENGTH_SHORT,
303
- ).show()
304
- } else {
305
- saveToFile.launch("$DEFAULT_FILE_PREFIX${System.currentTimeMillis()}")
306
- }
307
- }
308
-
309
- override fun onQueryTextSubmit(query: String): Boolean = false
310
-
311
- override fun onQueryTextChange(newText: String): Boolean {
312
- scrollableIndices.clear()
313
- currentSearchQuery = newText
314
- currentSearchScrollIndex = -1
315
-
316
- if (newText.isNotBlank() && newText.length > NUMBER_OF_IGNORED_SYMBOLS) {
317
- val listOfSearchQuery =
318
- payloadAdapter.highlightQueryWithColors(
319
- newText,
320
- backgroundSpanColor,
321
- foregroundSpanColor,
322
- )
323
- if (listOfSearchQuery.isNotEmpty()) {
324
- scrollableIndices.addAll(listOfSearchQuery)
325
- } else {
326
- payloadAdapter.resetHighlight()
327
- makeToolbarSearchSummaryVisible(false)
328
- }
329
- } else {
330
- payloadAdapter.resetHighlight()
331
- makeToolbarSearchSummaryVisible(false)
332
- }
333
-
334
- lifecycleScope.launch {
335
- delay(DELAY_FOR_SEARCH_SCROLL)
336
- lifecycle.withResumed {
337
- if (scrollableIndices.isNotEmpty()) {
338
- scrollToSearchedItemPosition(0)
339
- } else {
340
- currentSearchScrollIndex = -1
341
- }
342
- }
343
- }
344
- return true
345
- }
346
-
347
- private fun makeToolbarSearchSummaryVisible(visible: Boolean = true) {
348
- payloadBinding.rootSearchSummary.isVisible = visible
349
- }
350
-
351
- private fun updateToolbarText(
352
- searchResultsCount: Int,
353
- currentIndex: Int = 1,
354
- ) {
355
- payloadBinding.searchSummary.text =
356
- SpannableStringBuilder().apply {
357
- bold {
358
- append("$currentIndex / $searchResultsCount")
359
- }
360
- }
361
- }
362
-
363
- private fun scrollToSearchedItemPosition(positionOfScrollableIndices: Int) {
364
- // reset the last searched item highlight if done
365
- scrollableIndices.getOrNull(currentSearchScrollIndex)?.let {
366
- payloadAdapter.highlightItemWithColorOnPosition(
367
- it.indexBodyLine,
368
- it.indexStartOfQuerySubString,
369
- currentSearchQuery,
370
- backgroundSpanColor,
371
- foregroundSpanColor,
372
- )
373
- }
374
- currentSearchScrollIndex = positionOfScrollableIndices
375
- val scrollTo = scrollableIndices.getOrNull(positionOfScrollableIndices)
376
- if (scrollTo != null) {
377
- // highlight the next navigated item and update toolbar summary text
378
- payloadAdapter.highlightItemWithColorOnPosition(
379
- scrollTo.indexBodyLine,
380
- scrollTo.indexStartOfQuerySubString,
381
- currentSearchQuery,
382
- backgroundSpanColorSearchItem,
383
- foregroundSpanColor,
384
- )
385
- updateToolbarText(scrollableIndices.size, positionOfScrollableIndices + 1)
386
- makeToolbarSearchSummaryVisible()
387
-
388
- payloadBinding.payloadRecyclerView.smoothScrollToPosition(scrollTo.indexBodyLine)
389
- currentSearchScrollIndex = positionOfScrollableIndices
390
- }
391
- }
392
-
393
- @Suppress("LongMethod")
394
- private suspend fun processPayload(
395
- type: PayloadType,
396
- transaction: HttpTransaction,
397
- formatRequestBody: Boolean,
398
- ): MutableList<TransactionPayloadItem> {
399
- return withContext(Dispatchers.Default) {
400
- val result = mutableListOf<TransactionPayloadItem>()
401
-
402
- val headersString: String
403
- val isBodyEncoded: Boolean
404
- val bodyString: CharSequence
405
-
406
- if (type == PayloadType.REQUEST) {
407
- headersString = transaction.getRequestHeadersString(true)
408
- isBodyEncoded = transaction.isRequestBodyEncoded
409
- bodyString =
410
- if (formatRequestBody) {
411
- transaction.getSpannedRequestBody(context)
412
- } else {
413
- transaction.requestBody ?: ""
414
- }
415
- } else {
416
- headersString = transaction.getResponseHeadersString(true)
417
- isBodyEncoded = transaction.isResponseBodyEncoded
418
- bodyString = transaction.getSpannedResponseBody(context)
419
- }
420
- if (headersString.isNotBlank()) {
421
- result.add(
422
- TransactionPayloadItem.HeaderItem(
423
- HtmlCompat.fromHtml(
424
- headersString,
425
- HtmlCompat.FROM_HTML_MODE_LEGACY,
426
- ),
427
- ),
428
- )
429
- }
430
-
431
- // The body could either be an image, plain text, decoded binary or not decoded binary.
432
- val responseBitmap = transaction.responseImageBitmap
433
-
434
- if (type == PayloadType.RESPONSE && responseBitmap != null) {
435
- val bitmapLuminance = responseBitmap.calculateLuminance()
436
- result.add(TransactionPayloadItem.ImageItem(responseBitmap, bitmapLuminance))
437
- return@withContext result
438
- }
439
-
440
- when {
441
- isBodyEncoded -> {
442
- val text = requireContext().getString(R.string.chucker_body_omitted)
443
- result.add(TransactionPayloadItem.BodyLineItem(SpannableStringBuilder.valueOf(text)))
444
- }
445
-
446
- bodyString.isBlank() -> {
447
- val text = requireContext().getString(R.string.chucker_body_empty)
448
- result.add(TransactionPayloadItem.BodyLineItem(SpannableStringBuilder.valueOf(text)))
449
- }
450
-
451
- else -> {
452
- // adding copy item
453
- result.add(TransactionPayloadItem.CopyItem(getString(R.string.chucker_copy_response)))
454
-
455
- bodyString.lines().forEach {
456
- result.add(
457
- TransactionPayloadItem.BodyLineItem(
458
- if (it is SpannableStringBuilder) {
459
- it
460
- } else {
461
- SpannableStringBuilder.valueOf(it)
462
- },
463
- ),
464
- )
465
- }
466
- }
467
- }
468
- return@withContext result
469
- }
470
- }
471
-
472
- private fun prepareDataToSave(
473
- type: PayloadType,
474
- transaction: HttpTransaction,
475
- ): Source =
476
- when (type) {
477
- PayloadType.REQUEST -> {
478
- transaction.requestBody?.byteInputStream()?.source()
479
- ?: throw IOException(TRANSACTION_EXCEPTION)
480
- }
481
-
482
- PayloadType.RESPONSE -> {
483
- transaction.responseBody?.byteInputStream()?.source()
484
- ?: throw IOException(TRANSACTION_EXCEPTION)
485
- }
486
- }
487
-
488
- private fun isBodyEmpty(
489
- type: PayloadType,
490
- transaction: HttpTransaction,
491
- ): Boolean =
492
- when {
493
- type == PayloadType.REQUEST && transaction.requestBody == null -> true
494
- type == PayloadType.RESPONSE && transaction.responseBody == null -> true
495
- else -> false
496
- }
497
-
498
- companion object {
499
- private const val ARG_TYPE = "type"
500
- private const val TRANSACTION_EXCEPTION = "Transaction not ready"
501
- private const val DELAY_FOR_SEARCH_SCROLL: Long = 600L
502
-
503
- private const val NUMBER_OF_IGNORED_SYMBOLS = 1
504
-
505
- const val DEFAULT_FILE_PREFIX = "chucker-export-"
506
-
507
- fun newInstance(type: PayloadType): TransactionPayloadFragment =
508
- TransactionPayloadFragment().apply {
509
- arguments =
510
- Bundle().apply {
511
- putSerializable(ARG_TYPE, type)
512
- }
513
- }
514
- }
515
-
516
- private fun CharSequence.lines(): List<CharSequence> {
517
- val linesList = this.lineSequence().toList()
518
- val result = mutableListOf<CharSequence>()
519
- var lineIndex = 0
520
- for (index in linesList.indices) {
521
- result.add(subSequence(lineIndex, lineIndex + linesList[index].length))
522
- lineIndex += linesList[index].length + 1
523
- }
524
- if (result.isEmpty()) {
525
- result.add(subSequence(0, length))
526
- }
527
- return result
528
- }
529
- }
@@ -1,69 +0,0 @@
1
- package com.securitysuite.internal.ui.transaction
2
-
3
- import androidx.lifecycle.LiveData
4
- import androidx.lifecycle.MutableLiveData
5
- import androidx.lifecycle.ViewModel
6
- import androidx.lifecycle.ViewModelProvider
7
- import androidx.lifecycle.map
8
- import com.securitysuite.internal.data.entity.HttpTransaction
9
- import com.securitysuite.internal.data.repository.RepositoryProvider
10
- import com.securitysuite.internal.support.combineLatest
11
-
12
- internal class TransactionViewModel(transactionId: Long) : ViewModel() {
13
- private val mutableEncodeUrl = MutableLiveData<Boolean>(false)
14
-
15
- val encodeUrl: LiveData<Boolean> = mutableEncodeUrl
16
-
17
- val transactionTitle: LiveData<String> =
18
- RepositoryProvider.transaction()
19
- .getTransaction(transactionId)
20
- .combineLatest(encodeUrl) { transaction, encodeUrl ->
21
- if (transaction != null) {
22
- "${transaction.method} ${transaction.getFormattedPath(encode = encodeUrl)}"
23
- } else {
24
- ""
25
- }
26
- }
27
-
28
- val doesUrlRequireEncoding: LiveData<Boolean> =
29
- RepositoryProvider.transaction()
30
- .getTransaction(transactionId)
31
- .map { transaction ->
32
- if (transaction == null) {
33
- false
34
- } else {
35
- transaction.getFormattedPath(encode = true) != transaction.getFormattedPath(encode = false)
36
- }
37
- }
38
-
39
- val doesRequestBodyRequireEncoding: LiveData<Boolean> =
40
- RepositoryProvider.transaction()
41
- .getTransaction(transactionId)
42
- .map { transaction ->
43
- transaction?.requestContentType?.contains("x-www-form-urlencoded", ignoreCase = true) ?: false
44
- }
45
-
46
- val transaction: LiveData<HttpTransaction?> = RepositoryProvider.transaction().getTransaction(transactionId)
47
-
48
- val formatRequestBody: LiveData<Boolean> =
49
- doesRequestBodyRequireEncoding
50
- .combineLatest(encodeUrl) { requiresEncoding, encodeUrl ->
51
- !(requiresEncoding && encodeUrl)
52
- }
53
-
54
- fun switchUrlEncoding() = encodeUrl(!encodeUrl.value!!)
55
-
56
- fun encodeUrl(encode: Boolean) {
57
- mutableEncodeUrl.value = encode
58
- }
59
- }
60
-
61
- internal class TransactionViewModelFactory(
62
- private val transactionId: Long = 0L,
63
- ) : ViewModelProvider.NewInstanceFactory() {
64
- override fun <T : ViewModel> create(modelClass: Class<T>): T {
65
- require(modelClass == TransactionViewModel::class.java) { "Cannot create $modelClass" }
66
- @Suppress("UNCHECKED_CAST")
67
- return TransactionViewModel(transactionId) as T
68
- }
69
- }
@@ -1,12 +0,0 @@
1
- mipmap-xxhdpi
2
- color
3
- drawable
4
- layout
5
- menu
6
- mipmap-anydpi-v26
7
- mipmap-hdpi
8
- mipmap-xhdpi
9
- mipmap-xxxhdpi
10
- values-es
11
- values-night
12
- xml
@@ -1,5 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
3
- <item android:color="@android:color/darker_gray" android:state_enabled="false" />
4
- <item android:color="@color/chucker_color_primary" />
5
- </selector>
@@ -1,10 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <vector xmlns:android="http://schemas.android.com/apk/res/android"
3
- android:width="24dp"
4
- android:height="24dp"
5
- android:viewportWidth="24"
6
- android:viewportHeight="24">
7
- <path
8
- android:fillColor="#fff"
9
- android:pathData="M2,10.96C1.5,10.68 1.35,10.07 1.63,9.59L3.13,7C3.24,6.8 3.41,6.66 3.6,6.58L11.43,2.18C11.59,2.06 11.79,2 12,2C12.21,2 12.41,2.06 12.57,2.18L20.47,6.62C20.66,6.72 20.82,6.88 20.91,7.08L22.36,9.6C22.64,10.08 22.47,10.69 22,10.96L21,11.54V16.5C21,16.88 20.79,17.21 20.47,17.38L12.57,21.82C12.41,21.94 12.21,22 12,22C11.79,22 11.59,21.94 11.43,21.82L3.53,17.38C3.21,17.21 3,16.88 3,16.5V10.96C2.7,11.13 2.32,11.14 2,10.96M12,4.15V4.15L12,10.85V10.85L17.96,7.5L12,4.15M5,15.91L11,19.29V12.58L5,9.21V15.91M19,15.91V12.69L14,15.59C13.67,15.77 13.3,15.76 13,15.6V19.29L19,15.91M13.85,13.36L20.13,9.73L19.55,8.72L13.27,12.35L13.85,13.36Z" />
10
- </vector>
@@ -1,10 +0,0 @@
1
- <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
- android:width="24dp"
3
- android:height="24dp"
4
- android:tint="#FFFFFF"
5
- android:viewportWidth="24"
6
- android:viewportHeight="24">
7
- <path
8
- android:fillColor="@color/chucker_color_on_primary"
9
- android:pathData="M7.41,8.59L12,13.17l4.59,-4.58L18,10l-6,6 -6,-6 1.41,-1.41z" />
10
- </vector>
@@ -1,12 +0,0 @@
1
- <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
- android:width="24dp"
3
- android:height="24dp"
4
- android:autoMirrored="true"
5
- android:viewportWidth="24"
6
- android:viewportHeight="24">
7
-
8
- <path
9
- android:fillColor="@color/chucker_copy_icon_color"
10
- android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z" />
11
-
12
- </vector>
@@ -1,10 +0,0 @@
1
- <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
- android:width="24dp"
3
- android:height="24dp"
4
- android:tint="#FFFFFF"
5
- android:viewportWidth="24.0"
6
- android:viewportHeight="24.0">
7
- <path
8
- android:fillColor="#FF000000"
9
- android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z" />
10
- </vector>
@@ -1,9 +0,0 @@
1
- <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
- android:width="24dp"
3
- android:height="24dp"
4
- android:viewportWidth="24.0"
5
- android:viewportHeight="24.0">
6
- <path
7
- android:fillColor="#FFFFFFFF"
8
- android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
9
- </vector>
@@ -1,11 +0,0 @@
1
- <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
- android:width="24dp"
3
- android:height="24dp"
4
- android:tint="#FFFFFF"
5
- android:viewportWidth="24.0"
6
- android:viewportHeight="24.0">
7
- <path
8
- android:fillColor="#FF000000"
9
- android:pathData="M11.83 9L15 12.16V12a3 3 0 0 0-3-3h-0.17m-4.3 0.8l1.55 1.55c-0.05 0.21-0.08 0.42-0.08 0.65a3 3 0 0 0 3 3c0.22 0 0.44-0.03 0.65-0.08l1.55 1.55c-0.67 0.33-1.41 0.53-2.2 0.53a5 5 0 0 1-5-5c0-0.79 0.2-1.53 0.53-2.2M2 4.27l2.28 2.28l0.45 0.45C3.08 8.3 1.78 10 1 12c1.73 4.39 6 7.5 11 7.5c1.55 0 3.03-0.3 4.38-0.84l0.43 0.42L19.73 22L21 20.73L3.27 3M12 7a5 5 0 0 1 5 5c0 0.64-0.13 1.26-0.36 1.82l2.93 2.93c1.5-1.25 2.7-2.89 3.43-4.75c-1.73-4.39-6-7.5-11-7.5c-1.4 0-2.74 0.25-4 0.7l2.17 2.15C10.74 7.13 11.35 7 12 7z" />
10
- </vector>
11
-