Skip to content

Commit caf48a7

Browse files
authored
Merge pull request #52 from MetaMask/feature/prevent_tapjacking_on_android
feat: For Downloading dialog on Android add 500ms delay for the Positive button to become enabled to prevent accidental downloads
2 parents e525bcd + acb6d49 commit caf48a7

File tree

3 files changed

+66
-29
lines changed

3 files changed

+66
-29
lines changed

android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package com.reactnativecommunity.webview
22

3-
import android.app.AlertDialog
43
import android.app.DownloadManager
5-
import android.content.DialogInterface
64
import android.content.pm.ActivityInfo
75
import android.graphics.Bitmap
86
import android.graphics.Color
@@ -27,6 +25,7 @@ import com.facebook.react.common.build.ReactBuildConfig
2725
import com.facebook.react.uimanager.ThemedReactContext
2826
import com.reactnativecommunity.webview.extension.file.Base64FileDownloader
2927
import com.reactnativecommunity.webview.extension.file.BlobFileDownloader
28+
import com.reactnativecommunity.webview.extension.file.TapjackingPreventionAlertDialog
3029
import com.reactnativecommunity.webview.extension.file.addBlobFileDownloaderJavascriptInterface
3130
import org.json.JSONException
3231
import org.json.JSONObject
@@ -146,10 +145,12 @@ class RNCWebViewManagerImpl(private val newArch: Boolean = false) {
146145
if (Bidi(fileName, Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT).isMixed) {
147146
Toast.makeText(webView.context, "Invalid filename or type", Toast.LENGTH_LONG).show()
148147
} else {
149-
val builder = AlertDialog.Builder(webView.context)
150-
builder.setMessage("Do you want to download \n$fileName?")
151-
builder.setCancelable(false)
152-
builder.setPositiveButton("Download") { _, _ ->
148+
TapjackingPreventionAlertDialog(
149+
context = webView.context,
150+
message = "Do you want to download \n$fileName?",
151+
positiveButtonText = "Download",
152+
negativeButtonText = "Cancel",
153+
onPositiveButtonClick = {
153154
//Attempt to add cookie, if it exists
154155
var urlObj: URL? = null
155156
try {
@@ -178,10 +179,7 @@ class RNCWebViewManagerImpl(private val newArch: Boolean = false) {
178179
getDownloadingMessageOrDefault()
179180
)
180181
}
181-
}
182-
builder.setNegativeButton("Cancel") { _: DialogInterface?, _: Int -> }
183-
val alertDialog = builder.create()
184-
alertDialog.show()
182+
}).show()
185183
}
186184
})
187185
return RNCWebViewWrapper(context, webView)

android/src/main/java/com/reactnativecommunity/webview/extension/file/Base64FileDownloader.kt

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package com.reactnativecommunity.webview.extension.file
22

33
import android.Manifest
4-
import android.app.AlertDialog
54
import android.content.ContentValues
65
import android.content.Context
7-
import android.content.DialogInterface
86
import android.content.Intent
97
import android.content.pm.PackageManager
108
import android.os.Build
@@ -59,23 +57,13 @@ internal object Base64FileDownloader {
5957
}
6058

6159
private fun showAlertDialog(context: Context, extension: String, onPositiveButtonClick: () -> Unit) {
62-
AlertDialog.Builder(context)
63-
.apply {
64-
setMessage("Do you want to download \nFile.${extension}?")
65-
setCancelable(false)
66-
setPositiveButton("Download", object : DialogInterface.OnClickListener {
67-
override fun onClick(p0: DialogInterface?, p1: Int) {
68-
onPositiveButtonClick()
69-
}
70-
})
71-
setNegativeButton("Cancel", object : DialogInterface.OnClickListener {
72-
override fun onClick(p0: DialogInterface?, p1: Int) {
73-
// Do nothing
74-
}
75-
})
76-
}
77-
.create()
78-
.show()
60+
TapjackingPreventionAlertDialog(
61+
context = context,
62+
message = "Do you want to download \nFile.${extension}?",
63+
positiveButtonText = "Download",
64+
negativeButtonText = "Cancel",
65+
onPositiveButtonClick = onPositiveButtonClick,
66+
).show()
7967
}
8068

8169

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.reactnativecommunity.webview.extension.file
2+
3+
import android.app.AlertDialog
4+
import android.content.Context
5+
6+
/**
7+
* For the first 500ms disabled Positive button to prevent accidental taps
8+
*/
9+
class TapjackingPreventionAlertDialog(
10+
context: Context,
11+
private val message: String,
12+
private val positiveButtonText: String,
13+
private val negativeButtonText: String,
14+
private val onPositiveButtonClick: () -> Unit,
15+
) {
16+
private val dialog: AlertDialog = AlertDialog.Builder(context)
17+
.setCancelable(false)
18+
.setMessage(message)
19+
.setPositiveButton(positiveButtonText, null)
20+
.setNegativeButton(negativeButtonText, null)
21+
.create()
22+
23+
fun show() {
24+
dialog.setOnShowListener {
25+
val positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
26+
val negativeButton = dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
27+
28+
// Disable Positive button to prevent accidental tap
29+
positiveButton.isEnabled = false
30+
31+
positiveButton.postDelayed({
32+
positiveButton.isEnabled = true
33+
}, PREVENT_ACCIDENTAL_TAP_WAITING_TIME_MS)
34+
35+
positiveButton.setOnClickListener {
36+
onPositiveButtonClick.invoke()
37+
dialog.dismiss()
38+
}
39+
40+
negativeButton.setOnClickListener {
41+
dialog.dismiss()
42+
}
43+
}
44+
45+
dialog.show()
46+
}
47+
48+
companion object {
49+
const val PREVENT_ACCIDENTAL_TAP_WAITING_TIME_MS = 500L
50+
}
51+
}

0 commit comments

Comments
 (0)