前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >谷歌来了也不好使!谁说Chrome插件v3中不能使用eval?

谷歌来了也不好使!谁说Chrome插件v3中不能使用eval?

作者头像
源心锁
发布2022-09-21 14:47:26
1.5K0
发布2022-09-21 14:47:26
举报
文章被收录于专栏:前端魔法指南前端魔法指南

1 前言

大家好,我是心锁,一枚23届准毕业生。

近期在做一个Chrome浏览器截图插件,功能是从浏览器截图并发送图片到企微,便于在远程办公环境下快速从浏览器发送图片进行showCase(目前未真正使用上,原因是截图时html2canvas有错位)

image-20220904221932400
image-20220904221932400

在开发浏览器插件时,有时候会遇到并不需要全屏截图的情况。比如,截图的时候忽略侧边栏只截图右侧的内容区。

所以在这个简单的需求下,我尝试通过允许用户自定义hook来实现

2 解决方案

我们要完成hook,本质上就是两种方法。

一种是动态代码注入(文件注入),一种是eval执行字符串

2.1 已知限制

开始之前,我们首先先获取一些(踩坑后明白的)已知限制

  • Chrome v3版本全面禁止eval, new Function,不管在background,inject还是popup中都无法通过任何手段开启
  • Chrome v3版本全面禁止通过script标签加载外部源文件
  • Chrome目前上的的插件仅支持v3,v2已经禁上架

那么在此基础上,我们能评估出哪些方案呢?

2.2 方案评估

2.3.1 unsafe-wasm-eval【❌】

经过chrome文档的查阅,发现在v3版本中允许对wasm文件做动态导入的操作

87923D69A780C4012B16BDA5F4718552
87923D69A780C4012B16BDA5F4718552

...

但是,WebAssembly的难度一下子击中我的心巴

...

不必多说,且往下看

2.3.2 动态注入chrome.tabs.executeScript【❌】

在查阅API文档时发现,chrome支持程序注入,可以胜任动态注入脚本

代码语言:javascript
复制
chrome.action.onClicked.addListener((tab) => {
  chrome.scripting.executeScript({
    target: { tabId: tab.id },
    files: ['content-script.js']
  });
});

那么我们现在需要考虑的就是能否生成文件并注入。

这就需要两个条件:

  • 可以生成文件,即File对象存在
  • 可以将文件转换成地址用于注入

对于前者是没有问题的

image-20220905162024976
image-20220905162024976

但是很遗憾,对于将文件转换成地址用于注入常用的APIURL.createObjectURL是不支持的

image-20220905162507492
image-20220905162507492

2.3.3 在inject里做URL注入呢?【❌】

结合2.3.2,我们可以获得文件内容~

既然background不支持获得URL,那么我们在inject中跑行不行呢?

确实,我们可以拿到URL

image-20220905195246504
image-20220905195246504

传递URL到background之后再插入到content中

image-20220905195309513
image-20220905195309513

很遗憾还是不行,会直接找不到文件

image-20220905195514963
image-20220905195514963

而另一个方案是在content中注入script,这是实践内容,答案是不行。

image-20220905195102797
image-20220905195102797

2.3.4 JS解释器【🔮】

否决了三个方案,最后回到了通过eval的方式解决问题的方法。

上文说过,Chrome全面禁止了eval,但是这并非绝对的。

0E9417AA32C9237EE375B432C56D18F4
0E9417AA32C9237EE375B432C56D18F4

我们知道,JS作为一款解释性语言,是无法从根源上切断JS的运行的。

Chrome固然禁止了我们使用系统携带的eval解释器,但是并不妨碍我们引入自己的解释器。

48C0DB306922DBD18A546DAD5C9A5920
48C0DB306922DBD18A546DAD5C9A5920

一番搜索,找到了曾经超diao的eval5

根据eval5的README,我们完全可以在浏览器沙盒环境中使用eval5

image-20220905204017010
image-20220905204017010

所以,最终方案选择eval5

3 让eval5支持ES6+

上边的截图也看到了,eval5目前只支持ES5,同时从作者的回复来看,并没有计划支持ES6

image-20220905204345349
image-20220905204345349

但是如果只是这样多没意思,不会有人还在使用ES5开发吧~

383C8600B9482E7EF711D15F6D955F07
383C8600B9482E7EF711D15F6D955F07

所以我们尝试让eval5支持ES6+

3.1 solution

244392FC225E2177F8435874B3A49BE3
244392FC225E2177F8435874B3A49BE3

ES5和ES6有哪些区别?

其实我们平时使用的箭头函数、const、let全都是ES6+的内容,习惯了现代JavaScript再去支持ES5编程会感觉非常别扭。

而这也造就了,如果我们要支持ES6,去动手修改eval5的解释器工作量会很大。

27C9BA14FEC45B6C24BF60C8F18C84B6
27C9BA14FEC45B6C24BF60C8F18C84B6

所以转变思路,我们把ES6+代码转换成ES5

3.2 用babel将ES6+字符串转ES5字符串

那自然就引出了老朋友babel,我们来到babel官网

8E0B48BD4AA1E478A961D2C5EC0ECDDB
8E0B48BD4AA1E478A961D2C5EC0ECDDB

我们直接揭露谜底,我们本次需要用到的是@babel/standalone集成包

image-20220905210916144
image-20220905210916144

所以现在,我们可以通过简单的两行代码将ES6+的代码字符串转为ES5字符串

代码语言:javascript
复制
var input = 'const getMessage = () => "Hello World";';
var output = Babel.transform(input, { presets: ["env"] }).code;

在这个基础上,我们尝试一下将Babel与eval5搭配使用。

代码语言:javascript
复制
const { Interpreter } = eval5;

Interpreter.global = window;
const interpreter = new Interpreter();

const baseCode="const getMessage=()=>'Hello World';console.log(getMessage());"
const newCode=Babel.transform(baseCode, { presets: ["env"] }).code
console.log('newCode',newCode)
interpreter.evaluate(newCode);
image-20220905211313755
image-20220905211313755

很显然,一切OK~

1020055674B596C2B83948ADE0679D33
1020055674B596C2B83948ADE0679D33

现在我们可以愉快地在Chrome v3中使用ES6甚至TS语法了

4 总结

0E9417AA32C9237EE375B432C56D18F4
0E9417AA32C9237EE375B432C56D18F4

文章结尾,是我把相关的内容抽离成了一个只有18行代码的github仓库,对于懒人朋友们,只需要将打包产物umd.min.js在content_scripts中配置好进行注入,即可在Chrome v3插件中使用eval。

image-20220905211658495
image-20220905211658495

除此之外,我们对于使用Babel将ES6+转换成ES5+代码的方案还是要给出一些已知的问题:

  • eval5不支持ProxyReflect这些无法被babel兼容的ES6代码,所以我们无法使用这两个特性
  • 众说周知,babel转换是一个废时的操作,大量应用可能引起性能瓶颈
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-09-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 前言
  • 2 解决方案
    • 2.1 已知限制
      • 2.2 方案评估
        • 2.3.1 unsafe-wasm-eval【❌】
        • 2.3.2 动态注入chrome.tabs.executeScript【❌】
        • 2.3.3 在inject里做URL注入呢?【❌】
        • 2.3.4 JS解释器【🔮】
    • 3 让eval5支持ES6+
      • 3.1 solution
        • 3.2 用babel将ES6+字符串转ES5字符串
        • 4 总结
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档