fix(sdk-webview): reject file picker result when MIME type doesn't match accepted types
Some devices show .doc files in the picker even when only .docx was requested (accept=".docx"). Passing the .doc URI to the WebView renderer could cause a native crash. Now we check the actual MIME type of the selected file against the accepted list and cancel the upload if it does not match, preventing the renderer from receiving an unexpected file type. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
父节点
a481da7bad
当前提交
265994042e
@ -360,6 +360,7 @@ fun XWebViewView(
|
||||
// <input type="file" capture> camera capture
|
||||
val pendingFileCallback = remember { mutableStateOf<ValueCallback<Array<Uri>>?>(null) }
|
||||
val pendingCameraUri = remember { mutableStateOf<Uri?>(null) }
|
||||
val pendingAcceptMimes = remember { mutableStateOf<Array<String>?>(null) }
|
||||
|
||||
val takePictureLauncher = rememberLauncherForActivityResult(
|
||||
ActivityResultContracts.TakePicture()
|
||||
@ -374,7 +375,28 @@ fun XWebViewView(
|
||||
val pickContentLauncher = rememberLauncherForActivityResult(GetContentWithMimeTypes()) { uri ->
|
||||
val cb = pendingFileCallback.value
|
||||
pendingFileCallback.value = null
|
||||
cb?.onReceiveValue(if (uri != null) arrayOf(uri) else null)
|
||||
if (uri == null) {
|
||||
cb?.onReceiveValue(null)
|
||||
return@rememberLauncherForActivityResult
|
||||
}
|
||||
// Validate that the selected file's actual MIME type is within the accepted list.
|
||||
// Some devices show extra file types in the picker (e.g. .doc when only .docx was
|
||||
// requested). Passing an unsupported type to the WebView renderer can cause a native
|
||||
// crash. We accept the file only when its MIME type matches, or fall back to passing
|
||||
// it through when we can't determine the type (to avoid blocking legitimate uploads).
|
||||
val acceptedMimes = pendingAcceptMimes.value
|
||||
val actualMime = uri.let { context.contentResolver.getType(it) }
|
||||
val allowed = acceptedMimes.isNullOrEmpty() ||
|
||||
acceptedMimes.any { accepted ->
|
||||
accepted == "*/*" ||
|
||||
(actualMime != null && (actualMime == accepted || actualMime.startsWith(accepted.substringBefore("*"))))
|
||||
}
|
||||
if (!allowed) {
|
||||
android.util.Log.w("XWV", "Rejected file: actualMime=$actualMime not in accepted=$acceptedMimes")
|
||||
cb?.onReceiveValue(null)
|
||||
} else {
|
||||
cb?.onReceiveValue(arrayOf(uri))
|
||||
}
|
||||
}
|
||||
|
||||
val shouldLaunchCamera = remember { mutableStateOf(false) }
|
||||
@ -605,6 +627,7 @@ fun XWebViewView(
|
||||
pendingFileCallback.value = filePathCallback
|
||||
|
||||
val acceptMimes = resolvePickerMimeTypes(fileChooserParams.acceptTypes)
|
||||
pendingAcceptMimes.value = acceptMimes
|
||||
val isCameraCapture = fileChooserParams.isCaptureEnabled &&
|
||||
fileChooserParams.acceptTypes.any { it.contains("image") }
|
||||
val isImageOnly = acceptMimes.all { it.startsWith("image/") || it == "image/*" }
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户