File chooser dialog can only be shown with a user activation
lostvita opened this issue · 2 comments
日前,做需求过程碰到了这么一个问题:File chooser dialog can only be shown with a user activation,从描述看是在没有用户激活页面的情况下尝试去调起文件选择器,被浏览器拒绝了。
需求背景:页面加载时,通过代码触发file input
的click
事件,达到调起文件选择器的目的。大致如下:
const autoClick = () => {
const input = document.createElement('input')
input.type = 'file'
input.accept = '.gif,.jpg,.jpeg,.png,.bmp'
input.onchange = (e) => {
console.log('>>', e.target.files)
}
input.click()
}
setTimeout(autoClick, 0)
猜想这是浏览器考虑安全因素做的限制,确实也是。试想一下用户打开一个未知网页,不断调起文件选择器(或者新建窗口操作),用户的设备将直接被卡死。
但还是想探究验证一下浏览器内核是如何做限制的。chromium源码位置
void FileInputType::HandleDOMActivateEvent(Event& event) {
// ...
if (!LocalFrame::HasTransientUserActivation(document.GetFrame())) {
String message =
"File chooser dialog can only be shown with a user activation.";
document.AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
mojom::ConsoleMessageSource::kJavaScript,
mojom::ConsoleMessageLevel::kWarning, message));
return;
}
// ...
}
可以看出,浏览器在响应dom事件时会先判断是否有短暂的
用户激活行为。但,短暂
是多久?
bool HasTransientUserActivation() const {
return user_activation_state_.IsActive();
}
浏览器用user_activation_state_
维护了用户激活的状态,其中IsActive
最终是通过IsActiveInternal
实现的,里面维护了一个transient_state_expiry_time_
变量,这就是浏览器用来标识短暂的
用户激活的变量。
bool UserActivationState::IsActiveInternal() const {
return base::TimeTicks::Now() <= transient_state_expiry_time_;
}
void UserActivationState::ActivateTransientState() {
transient_state_expiry_time_ = base::TimeTicks::Now() + kActivationLifespan;
}
constexpr base::TimeDelta kActivationLifespan = base::Seconds(5);
浏览器每收到用户的交互行为时(单纯地移动鼠标可不算,浏览器应该维护了一套属于用户激活行为的事件白名单)ActivateTransientState
,这里会更新激活态的过期时间,在kActivationLifespan
时间后就会过期,也就是5s。
搞清楚了原理,我们用demo来验证一下!
const autoClick = () => {
console.log('>> autoClick')
const input = document.createElement('input')
input.type = 'file'
input.accept = '.gif,.jpg,.jpeg,.png,.bmp'
input.onchange = (e) => {
console.log('>>', e.target)
}
input.click()
}
// 脚本加载时,3s后自动触发`input click`
setTimeout(autoClick, 3000)
总结一下:在用户激活页面(点击,选中等)的5s内,自动执行的脚本有响应,否则浏览器无响应。
Is there any way to bypass user activation verification?
Is there any way to bypass user activation verification?