tampermonkey 如何自动填充密码 并通过前端的表单检查

2020-08-27 00:11:26 +08:00
 cy97cool

需求:类似 LastPass 这种可以自动填充用户名密码,点击提交

难点:很多现代化的页面前端做了表单校验,直接赋值 input 的 value 不能通过表单校验

关键在于没能触发人家框架的 event listener

查资料咯,发现了这个解答 https://stackoverflow.com/a/35807417 就是触发 input 、keyup 、change 事件,但实际测试仍然不行,甚至我把在开发人员工具能看到的 event listner 全触发了一边都没用 sad

function fireChangeEvents(element){
    var changeEvent = null;
    for(var i of ["keypress","focus", "input", "keydown", "keyup", "change", "blur", "click", "invalid", "mouseover", "popstate", "reset", "scroll", "selectionchange", "submit", "transitionend"]){
        changeEvent = document.createEvent ("HTMLEvents");
        changeEvent.initEvent (i, true, true);
        element.dispatchEvent (changeEvent);
    }
}
fireChangeEvents(document.querySelectorAll("input")[0])

然后接着找,发现一个能模拟用户交互的 npm 包: https://github.com/testing-library/user-event

然后折腾了一下 browserify 打包成浏览器可以用的 js 文件,实际测试可行:

userEvent.type(document.querySelectorAll("input")[0], USERNAME);
userEvent.type(document.querySelectorAll("input")[1], PASSWORD);

问题是解决了,但觉得为了一个触发 event 引入一个 500KB 的 js 文件有点蠢( uglify 之后也有 300KB ),问问大佬们有没有更好的方案,不需要引入这么重的 js 库的

2962 次点击
所在节点    JavaScript
11 条回复
iNaru
2020-08-27 00:57:39 +08:00
input.dispatchEvent(new Event('input', { bubbles: true }));
cy97cool
2020-08-27 07:31:55 +08:00
@iNaru 没有用呢 仍然要求“请输入用户名!”
initEvent 的第二个参数就是 bubbles
cy97cool
2020-08-27 07:38:14 +08:00
https://ant.design/components/form-cn/
找到一个可以用来验证的例子,这个页面中的 嵌套结构与校验信息 部分,Username 右边有个 Need Help?的链接

对这个 input 右键 检查元素,在 Console 里输入 $0.value="1" , 然后点击这个表单的 Submit,会报错“Username is required”。

问题就是:在 Console 里输入啥神奇的代码,能成功通过这个表单的检查
CoolSpring
2020-08-27 09:53:31 +08:00
如果是 React,似乎可以用这个: https://stackoverflow.com/questions/23892547/what-is-the-best-way-to-trigger-onchange-event-in-react-js

var input = document.getElementById("complex-form_username");

var nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
nativeInputValueSetter.call(input, 'react 16 value');

var ev2 = new Event('input', { bubbles: true});
input.dispatchEvent(ev2);
cy97cool
2020-08-27 10:07:57 +08:00
@CoolSpring 感谢 确实有用
Damon3621
2020-10-20 14:06:05 +08:00
Hi 兄弟 请问你如何获取页面中的 input 框呢?我最近也在写自动填充插件,遇到问题了。 比如腾讯视频 他的 Input 框放在 iframe 框架里,调用的话不是会跨域吗
cy97cool
2020-10-21 10:21:20 +08:00
@Damon3621 如果这个 iframe 是有 url 的,你可以对这个 iframe 的 url 启用脚本
Damon3621
2020-10-21 14:11:29 +08:00
@cy97cool 大佬,可以说的具体点嘛 我现在能获取这个 iframe 的 url 但不能操作里面的 dom 怎么对这个 url 启用脚本呢
cy97cool
2020-10-30 20:00:38 +08:00
@Damon3621 不要局限你的思维啊 你以为只能在外层的网页匹配脚本运行嘛?
举个例子 如果我写一个脚本 匹配所有网站 那你打开当前这个窗口的时候会显示几次呢?
// @match https://*/*
console.log("script started")

你的脚本可以去匹配 iframe 的 url 而不是匹配地址栏的 url
Damon3621
2020-11-03 14:18:36 +08:00
@cy97cool 非常感谢 确实有用
Jonatvtwoex
2020-11-23 17:48:45 +08:00
原因是校验逻辑依赖 input 事件, 而 inputEle.value = xxx 并不会触发 input 事件

const inputEle = document.querySelector(`input[name=${key}]`)
inputEle.value = fields[key]
// 关键代码: input 元素在事后触发一下 input 事件
inputEle.dispatchEvent(new Event('input'));

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/701749

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX