=Start=
缘由:
学习了解一下Electron是什么,能做什么,代码该怎么写,方便以后参考。
正文:
参考解答:
1、Electron是什么?
Electron是由Github开发,用HTML,CSS和JavaScript来构建跨平台桌面应用程序的一个开源库。Electron通过将Chromium和Node.js合并到同一个运行时环境中,并将其打包为Mac,Windows和Linux系统下的应用来实现这一目的。
2、Electron能做什么?
Electron 可以让你使用纯 JavaScript 调用丰富的原生(操作系统) APIs 来创造桌面应用。你可以把它看作一个 Node. js 的变体,它专注于桌面应用而不是 Web 服务器端。
这不意味着 Electron 是某个图形用户界面(GUI)库的 JavaScript 版本。 相反,Electron 使用 web 页面作为它的 GUI,所以你能把它看作成一个被 JavaScript 控制的,精简版的 Chromium 浏览器。
3、Electron应用的开发
①开发环境准备
# 下面这行的命令会打印出Node.js的版本信息
node -v
# 下面这行的命令会打印出npm的版本信息
npm -v
# 全局安装 electron 然后查看其版本
npm install electron@latest -g
electron --version
②代码目录结构
从开发的角度来看, Electron application 本质上是一个 Node. js 应用程序。 与 Node.js 模块相同,应用的入口是 package.json
文件。一个最基本的 Electron 应用一般来说会有如下的目录结构:
your-app/
├── package.json
├── main.js
└── index.html
③Demo应用开发
为你的新Electron应用创建一个新的空文件夹。 打开你的命令行工具,然后在该文件夹下运行npm init
命令:
npm init
该 npm init 命令会帮助你创建一个基本的 package.json
文件。其中的 main
字段所表示的脚本为应用的启动脚本,它将会在主进程中执行。 如下片段是一个 package.json
的示例:
{
"name": "your-app",
"version": "0.1.0",
"main": "main.js"
}
下面是一个简单的main.js
文件,它将在应用程序准备就绪后打开一个窗口,同时打开开发者工具,并添加上处理窗口关闭事件、在macOS用户点击dock上图标时重建窗口的逻辑:
const { app, BrowserWindow } = require('electron')
// 保持对window对象的全局引用,如果不这么做的话,当JavaScript对象被
// 垃圾回收的时候,window对象将会自动的关闭
let win
function createWindow () {
// 创建浏览器窗口。
win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// 加载index.html文件
win.loadFile('index.html')
// 打开开发者工具
win.webContents.openDevTools()
// 当 window 被关闭,这个事件会被触发。
win.on('closed', () => {
// 取消引用 window 对象,如果你的应用支持多窗口的话,
// 通常会把多个 window 对象存放在一个数组里面,
// 与此同时,你应该删除相应的元素。
win = null
})
}
// Electron 会在初始化后并准备
// 创建浏览器窗口时,调用这个函数。
// 部分 API 在 ready 事件触发后才能使用。
app.on('ready', createWindow)
// 当全部窗口关闭时退出。
app.on('window-all-closed', () => {
// 在 macOS 上,除非用户用 Cmd + Q 确定地退出,
// 否则绝大部分应用及其菜单栏会保持激活。
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
// 在macOS上,当单击dock图标并且没有其他窗口打开时,
// 通常在应用程序中重新创建一个窗口。
if (win === null) {
createWindow()
}
})
// 在这个文件中,你可以续写应用剩下主进程代码。
// 也可以拆分成几个文件,然后用 require 导入。
然后,创建你想展示的 index.html
:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
</body>
</html>
在创建并初始化完成 main.js
、 index.html
和package.json
之后,您就可以在当前工程的根目录执行 npm start
命令来启动刚刚编写好的Electron程序了。
一些简单的知识点和注意事项:
主进程&渲染进程
- 在 Electron 里,运行
package.json
里main
脚本的进程被称为主进程。 - 由于 Electron 使用 Chromium 来展示页面,所以 Chromium 的多进程结构也被充分利用。每个 Electron 的页面都在运行着自己的进程,这样的进程我们称之为渲染进程。在一般浏览器中,网页通常会在沙盒环境下运行,并且不允许访问原生资源。然而,Electron 用户拥有在网页中调用 io.js 的 APIs 的能力,可以与底层操作系统直接交互。
主进程和渲染进程的区别
主进程使用 BrowserWindow 实例创建网页。每个 BrowserWindow 实例都在自己的渲染进程里运行着一个网页。当一个 BrowserWindow 实例被销毁后,相应的渲染进程也会被终止。
主进程管理所有页面和与之对应的渲染进程。每个渲染进程都是相互独立的,并且只关心他们自己的网页。
由于在网页里管理原生 GUI 资源是非常危险而且容易造成资源泄露,所以在网页面调用 GUI 相关的 APIs 是不被允许的。如果你想在网页里使用 GUI 操作,其对应的渲染进程必须与主进程进行通讯,请求主进程进行相关的 GUI 操作。
在 Electron,我们提供用于在主进程与渲染进程之间通讯的 ipc 模块。并且也有一个远程进程调用风格的通讯模块 remote。
低版本Electron
不支持loadFile
在1.x
和2.x
的electron
中,如果要使用loadFile
函数,就会报错unknown function
。所以如果想用这个函数的话,需要更新到 3.x 及以后版本的 Electron 。
参考链接:
- Electron macOS 开发环境配置
https://nodejs.org/en/download/ - 打造你的第一个 Electron 应用
https://electronjs.org/docs/tutorial/first-app - Electron入门教程
- electron 3.x 系统新增加的页面加载函数 loadFile
- Electron 中文文档
=END=
《“Electron 快速入门”》 有 10 条评论
用Nodejs开发桌面应用。NW.js 和 Electron 各有什么优缺点,你选择哪个?
https://www.zhihu.com/question/38854224
`
我们最近有个项目需要使用Node桌面版技术,正如大多数人一样,我的初次选型是NW,那么出乎意料,大坑来了!!!
倘若你的桌面版应用没有跟底层(C++模块)挂钩,也就是没有使用到消息推送、版本升级、打印功能之类的东西,但是bug还是挺多的。并且一旦使用到这些功能,你就彻底调到坑里了,nw有个致命的缺陷在于所有的非javascript编写的模块都需要重新用nw-gyp重新编译一下,这个编译的过程会出现各种各样的问题。而Electron几乎可以使用所有的node模块,只需要node-gyp编译的即可。主要深坑就在这!!!还有,NW不像Electron自带版本升级。
nw唯一的好处是啥?兼容window XP呗。
`
http://tangiblejs.com/posts/nw-js-electron-compared
https://github.com/nwjs/nw.js/
https://github.com/electron/electron
维护一个大型开源项目是怎样的体验?
https://www.zhihu.com/question/36292298/answer/102418523
怎么去阅读Chromium的源码?
https://www.zhihu.com/question/306408034/answer/565791530
`
从初学者角度的话,如果是刚开始研究chromium,建议找个老版本chromium来看。新版太大太复杂了。我建议从github搜下 chromium.bb 这个项目,是个chromium49的删减版。之所以推荐这个,有几个原因:
0,工程环境比原版chromium好搭多了,不用翻墙,不用改一些系统设置。90%的初学者我估计卡在搭chromium环境这了,尤其是国内。。
1,代码量相对较小,所以直接可以生成vs工程后配合vax的代码着色和智能跳转阅读。有VAX辅助,对于查找函数具体位置有很大帮助。
2,同样由于代码量小,你可以用vs直接编译跑起来。阅读chromium代码你一定要调试,否则很难理清某个流程。
搭好环境后,建议你疯狂搜下网上讲解chromium架构的文章预热一下。否则你会不知所云。先把chromium的进程架构了解下,大概每个进程是做什么的,然后开始研究content层,这是chromium最主要的层,负责连接所有其他组件。
其他具体架构细节以后想到再写……
`
Chromium
https://www.zhihu.com/topic/19557071/top-answers
Chromium source code and modifications
https://github.com/bloomberg/chromium.bb
http://bloomberg.github.io/chromium.bb/
`
This repository contains the version of Chromium used by Bloomberg, along with all the modifications made by Bloomberg in order to use it in our environment.
`
Chromium 编译增加 音频/视频 支持(chromium add wav support compile options)
https://stackoverflow.com/questions/50971187/can-i-build-chromium-with-ffmpeg-to-support-all-video-formats
https://www.chromium.org/developers/how-tos/get-the-code
https://chromium.googlesource.com/chromium/src/+/master/docs/windows_build_instructions.md
https://chromium.googlesource.com/chromium/src/+/master/docs/mac_build_instructions.md
https://www.chromium.org/audio-video
https://superuser.com/questions/1111994/how-to-compile-chromium-with-mp3-aac-and-h264-support
https://github.com/henrypp/chromium
`
enable_ac3_eac3_audio_demuxing = true
enable_mse_mpeg2ts_stream_parser = true
proprietary_codecs = true
`
History of Node.js on a Timeline
https://blog.risingstack.com/history-of-node-js/
你需要了解的Node.js 发展史
https://www.jianshu.com/p/4e45641123dc
https://zh.wikipedia.org/wiki/Node.js
向Typora学习electron安全攻防
https://mp.weixin.qq.com/s/Ggx34AqhzsbBLkecv5RNJw
`
越来越多的应用开始使用 electron 来构建跨平台桌面应用。从实现方式上来说,其本质还是基于chrome内核的html、js、css构成的应用,基于浏览器,代码必定会暴露在用户侧,任何加密手段只是增加破解门槛跟时间成本而已。
# 认识electron项目文件目录特征
electron打包的项目,最常见的就是 asar 格式的私有编码文件,里面包含文件名、大小、内容偏移量等数据,按文件头部的 json内容 解析即可提取出所有文件。
# electron asar解包
目前来说,官方的版本并没有提供保护源码的方法。在github开源的找到个大神提供的解决方案(https://github.com/toyobayashi/electron-asar-encrypt-demo) ,该方案可以把启动文件编译为node二进制文件,作为启动入口,来保护薄弱的js代码。在项目启动时,将加密后的代码进行解密,交回electron流程进行执行,从而避免上述步骤直接解包拿到源代码的可能。
经过分析对比,typora用的恰好是这个demo提供的思路。
找到上述步骤解压成功的 package.json 文件,main属性就是 electron 项目启动的主入口。把 main.node 拖到ida中, 分析执行流程。
结合 electron-asar-encrypt-demo 跟 IDA伪代码, 可以定位到两个关键函数 napi_create_string_utf8 跟 napi_call_function。
# 万能js提取方案
已知经过编译后的node文件, 在执行前,都会调用 napi_create_string_utf8 创建js字符串,所以在调用该函数的时候,基于electron没有自带加密的特性,想要运行js流程,必定会传递明文,所以在加载流程上截断,就可以导出解密后的数据。
解包项目中的所有 asar文件,就能拿到所有的源代码,并且把解压的文件夹,改成对应的 asar 文件名即可正常运行项目,无需重打包即可调试。
# 无限试用思路
删除注册表键,让程序认为是第一次安装。
# 去除授权功能实现单机版本思路
将所有的网络验证给他删掉/注释掉, 也可以直接把 “是否授权” 的变量,改成true即可。
# 注册机思路
由于该示例使用了rsa解密,所以要基于官方版本编写注册机就不太行了。一定要出注册机的话,需要先替换截图部分的rsa公钥即可。
# 自建授权网关实现注册机思路
自建网关的话,可以把应用自带的域名,替换成自己的,然后按接口需要的返回值,给他返回响应的数据格式即可。这个实例仅需要修改两处即可。
# 重打包发版思路
把解压的文件夹打包回 asar格式的文件即可, 这个网上一大把资料。
# 对于electron加密方式的思考
相对于原生开发来说,js安全做客户端毕竟薄弱,UI交互是没问题的,关键代码可以放到dll、so层去做,但是也没办法避免从js层面去剥离dll层函数的调用。所以目前来说并没有很好的解决方案,本文只是起到抛砖引玉的作用。期待electron有更好、更安全的解决方案。
`
又是 Electron!Element 桌面版被发现远程代码执行
https://mp.weixin.qq.com/s/bcgtMXmx_yRvSR2olvOKhA
`
Remote Code Execution on Element Desktop Application using Node Integration in Sub Frames Bypass – CVE-2022-23597
Element 是一款基于 Matrix 协议的即时通讯软件,支持多个桌面和移动平台,允许端到端加密、拉群、语音视频通话和自建服务器等功能。
Element 的桌面端主要还是用 Electron。一个有趣的现象是,只要一款 App 而且足够流行,而且选择使用 Electron,那么一定会被人搞出 XSS 甚至 RCE 漏洞来。
2018 年 5 月,Signal 桌面端很短的时间内连续发现两个 XSS
2020 年 8 月,另一款以安全为卖点的跨平台即时通信软件 Wire 桌面端被发现没有对打开文件的参数做检查,可以远程运行可执行文件。
2020 年 10 月,知名的即时聊天和社群工具 Discord 被发现 XSS 和远程代码执行。
2021 年 7 月,还是 Discord。
Electron 大大方便了桌面应用的开发,可是两大黑点广受诟病——大多数 Electron 应用都没几个功能,却要带上一整个 Chrome 引擎来浪费存储空间和性能;而用 js 做桌面应用极大降低了漏洞利用成本,经常栽在 XSS 之类问题上。
哪怕是公认性能架构好性能高,同时还是 Electron 亲兄弟的 VSCode,也时不时出过安全问题。怎么说呢?虽然因噎废食不好,可是 Electron 的生态确实该领几张反思券。其他的应用,能用网页版尽量用网页版吧……
`
TAURI
https://tauri.app/
`
Build an optimized, secure, and frontend-independent application for multi-platform deployment.
Electron 的替代品,用来制作跨平台的桌面应用,使用 Rust 语言开发。它采用各平台自带的 WebView,缺点是支持的 Web API 会比较少,优点是打包产物体积小。
`
文件桥
https://github.com/ppz-pro/file-bridge
`
网页里的文件服务器
一个简单的 JS 脚本,用来架设静态文件服务器。A 电脑在网页上打开一个本地文件目录,B 电脑就能下载里面的文件,两者不必在同一局域网。
# 需要
* 一个公网可访问的服务器
* Node.js
* https
git clone https://github.com/ppz-pro/file-bridge.git
cd file-bridge
node file_bridge.js
# 原理
两个“客户端”之间没法直接“传递数据”,因为没有公网地址,于是就需要一个“桥”,连接两个“客户端”。提供文件供人下载的,我在这里叫它“提供端”,另一个叫“下载端”。
1. “桥”为每一个“提供端”生成一个 id(以下称为“提供端 id”)
2. “提供端”使用 File System API 读取用户指定的目录,把目录结构发给“桥”
3. “下载端”根据“提供端 id”从“桥”那里获取目录结构
4. “下载端”要下载文件时,向“桥”发送“下载请求”并指定“提供端 id”及文件路径,桥会把这个请求存起来
5. 用户在“提供端”指定“允许下载的目录”后,“提供端”程序就开始每隔 1 秒向“桥”发请求:问一问“有没有谁想下载我的文件”
6. 上两个步骤,一个想下载别人的文件,一个想让人下载,一拍即合,而传文件只需一行代码 http.IncomingMessage.pipe(http.ServerResponse)
其实第 5 步的“每隔 1 秒”很膈应,但原生 Node.js 对 Websocket 支持度比较低,而专门封装一个 Websocket 可能需要几十甚至上百行代码,于是作罢。反正,,,,这只是个有趣的项目,我是说,,,一开始就没以实用为目的。当然,适当地改造一下,也可以很实用,但谁能拒绝“仅使用原生模块”的诱惑呢。
这个项目更加深我那个刻板印象:编程的难点不在于“让人使用”,而是“不让人使用”,比如“非法用户”和“未付费用户”。其实“未付费用户”就是“非法用户
`