Closed fuxin052 closed 2 years ago
我采用@require方式引而不是用包方式引入, 是因为这个代码被编译过后效果好像发生了变化, 其中的原因我也没搞明白, 所以用@require让它不被编译
~不好意思刚刚在打游戏没注意邮件通知~
@require
如果是 iife ,会在那个作用域 出现一个变量,如果是 umd ,会在那个作用域的 window 添加一个 属性
因为 dev 模式的 你的代码 运行的 window 是 被注入网页的 window ,不是 monkey 插件的 window
如果你引入的包是 umd 格式的,假设你的 cdn 导出的叫 Vue,可以通过以下方式获取
import{monkeyWindow}from'$'
const Vue = monkeyWindow.Vue
如果是 iife 格式,你需要在刚刚的cdn后面加入额外 @require
一个cdn,它的内容是这样
try{
this.Vue = this.Vue ?? Vue
}catch{}
try{
window.Vue = window.Vue ?? Vue
}catch{}
或者使用 //@grant none
或者 //@unwrap
这样就只有一个 window ,限制是你不能使用 GM_api
我采用@require方式引而不是用包方式引入, 是因为这个代码被编译过后效果好像发生了变化, 其中的原因我也没搞明白, 所以用@require让它不被编译
@fuxin052 你要 @require
的 cdn url 是什么呢?这个包是什么?
我做的是115提取下载链接 参照这个chrome扩展的代码
包是https://github.com/acgotaku/115/blob/master/src/vendor/jsencrypt.js 加解密代码是https://github.com/acgotaku/115/blob/master/src/js/lib/secret.js
我尝试过
使用npm的jsencrypt@3,当时没注意版本, 加密的的数据服务器不能解密,
使用npm的jsencrypt@2.3.0, 结果忘记了, 反正不行
我又试了下, 是执行报错, 里面有一行 报错信息如下
https://github.com/travist/jsencrypt/blob/v2.3.0/bin/jsencrypt.js#L2021
Uncaught ReferenceError: KJUR is not defined
at jsencrypt.js:2021:42
at node_modules/jsencrypt/bin/jsencrypt.js (jsencrypt.js:4342:1)
at __require (chunk-RSJERJUL.js?v=71cb38fe:3:50)
at dep:jsencrypt:1:16
把jsencrypt.js文件下载到项目目录 通过import引入,
此时jsencrypt.js引入时会报错SyntaxError: The requested module '/src/libs/jsencrypt.js?t=1660359267496' does not provide an export named 'default' (at secret.ts:2:8)
, 按下面修改后可引入 但是 加密成功, 但是服务器返回的加密数据我不能解密
// 注释下面
// (function (global, factory) {
// if (typeof exports === 'object' && typeof module !== 'undefined') {
// module.exports = factory;
// } else if (typeof define === 'function' && define.amd) {
// define(factory);
// } else {
// global.JSEncrypt = factory;
// }
// }(this, JSEncryptExports.JSEncrypt));
// 改成这个
export default JSEncryptExports.JSEncrypt;
把jsencrypt.js用@require引入, secret.js改造下也用@require引入, 其中的md5也是用cdn, 结果是dev模式方法找不到, build模式加密解密都能成功
使用monkeyWindow拿到jsencrypt后成功
1和2产生的原因完全搞不清楚, 所以我想如果能解决3的问题, 应该也解决了
刚刚试了下monkeyWindow可以, 感谢
就是有一点 调用的时候类型报错
只能用(monkeyWindow as any).JSEncrypt()
来处理
类型错误也可以通过以下方式解决
首先 pnpm add jsencrypt@version
以便在代码里使用类型,version
是你 @require
加载的版本,最新包就用 latest
。
我看你评论里说使用的 https://unpkg.com/browse/jsencrypt@2.3.0/ 这个版本很旧是没有类型提示的,只有 3.x.x
才有,如果想使用正确的类型提示,确保你手动 @require
的是 3.x.x
或者自己手动声明
然后可通过以下方式使用
方式1,使用 Reflect.get
或者 //@ts-ignore
// main.ts
import{monkeyWindow}from'$'
import type JSEncryptT from 'jsencrypt';
const JSEncrypt = Reflect.get(monkeyWindow, 'JSEncrypt') as typeof JSEncryptT
const obj = new JSEncrypt()
// main.ts
import{monkeyWindow}from'$'
import type JSEncryptT from 'jsencrypt';
//@ts-ignore
const JSEncrypt = monkeyWindow.JSEncrypt as typeof JSEncryptT
const obj = new JSEncrypt()
方式2,扩展类型声明,修改 vite-env.d.ts
// file->vite-env.d.ts
/// <reference types="vite/client" />
/**
* alias of vite-plugin-monkey/dist/client
*/
declare module '$' {
export * from 'vite-plugin-monkey/dist/client';
// ------new-start-----
import type { MonkeyWindow } from 'vite-plugin-monkey/dist/client';
import type JSEncryptT from 'jsencrypt';
export const monkeyWindow: MonkeyWindow & {
JSEncrypt: typeof JSEncryptT;
};
//---------new-----end-------
}
然后正常使用
// main.ts
import{monkeyWindow}from'$'
const JSEncrypt = monkeyWindow.JSEncrypt
const obj = new JSEncrypt()
推荐使用 方式2,一次声明,到处使用
另外方式1需要注意必须使用 import type
否则 vite build
的时候可能把 jsencrypt
打包进去
对于 https://github.com/lisonge/vite-plugin-monkey/issues/12#issuecomment-1213622455 的两个错误
错误1:Uncaught ReferenceError: KJUR is not defined
,你的代码 dev 模式下是 esm ,esm 是 严格模式,不允许使用未声明的变量
而 115/**/jsencrypt.js 不报这个错是因为 它用 var 声明了 KJUR
解决方式也很简单
['KJUR'].forEach((s) => {
Reflect.set(window, s, void 0);
});
// 必须在导入 `jsencrypt` 之前运行
import JSEncrypt from 'jsencrypt';
错误2我不太明白意思,能给出具体的加密数据展示吗?
我创了一个仓库来展示这个错误: https://github.com/fuxin052/monkey-test secretRequire方法是使用@require的解密库 secretLib是将解密库放到本地通过import引入
测试结果如下
// 1. 只执行require的解密方法
var r = secretRequire.decode(str, key);
console.log('r: ', r);
// var l = secretLib.decode(str, key);
// console.log('l: ', l);
// r: {"2406025156334976380":{"file_name":"323.txt","file_size":"3","pick_code":"argtzklaodttphfjt","url":{"url":"https:\/\/cdnfhnfile.115.com\/5fab54fa697fc76ecd15c6532b6d52d7a189c905\/323.txt?t=1660404201&u=364042722&s=3250586&d=vip-666703667-argtzklaodttphfjt-1&c=0&f=1&k=610d9fa42bfa26b67aa79a3a5bcdad6f&us=32505856&uc=10&v=1","client":3,"desc":null,"isp":null,"oss_id":"fhnfile\/5fab54fa697fc76ecd15c6532b6d52d7a189c905","ooid":"\/c101\/0\/3B20hkVMCVqrHgBXvXcNNnjdHH8kgD_v4ZuaPt-A"}}}
// 2. 只执行使用import引入的解密方法
// var r = secretRequire.decode(str, key);
// console.log('r: ', r);
var l = secretLib.decode(str, key);
console.log('l: ', l);
// l: G«ïØG{
// 乱码代表解密失败
// 3. 以上两种同时执行
var r = secretRequire.decode(str, key);
console.log('r: ', r);
var l = secretLib.decode(str, key);
console.log('l: ', l);
// r: {"2406025156334976380":{"file_name":"323.txt","file_size":"3","pick_code":"argtzklaodttphfjt","url":{"url":"https:\/\/cdnfhnfile.115.com\/5fab54fa697fc76ecd15c6532b6d52d7a189c905\/323.txt?t=1660404201&u=364042722&s=3250586&d=vip-666703667-argtzklaodttphfjt-1&c=0&f=1&k=610d9fa42bfa26b67aa79a3a5bcdad6f&us=32505856&uc=10&v=1","client":3,"desc":null,"isp":null,"oss_id":"fhnfile\/5fab54fa697fc76ecd15c6532b6d52d7a189c905","ooid":"\/c101\/0\/3B20hkVMCVqrHgBXvXcNNnjdHH8kgD_v4ZuaPt-A"}}}
// l: {"2406025156334976380":{"file_name":"323.txt","file_size":"3","pick_code":"argtzklaodttphfjt","url":{"url":"https:\/\/cdnfhnfile.115.com\/5fab54fa697fc76ecd15c6532b6d52d7a189c905\/323.txt?t=1660404201&u=364042722&s=3250586&d=vip-666703667-argtzklaodttphfjt-1&c=0&f=1&k=610d9fa42bfa26b67aa79a3a5bcdad6f&us=32505856&uc=10&v=1","client":3,"desc":null,"isp":null,"oss_id":"fhnfile\/5fab54fa697fc76ecd15c6532b6d52d7a189c905","ooid":"\/c101\/0\/3B20hkVMCVqrHgBXvXcNNnjdHH8kgD_v4ZuaPt-A"}}}
结果有点出乎意料, 第3个居然都解密成功了, 让人摸不着头脑
对于第二种情况
// 2. 只执行使用import引入的解密方法
// var r = secretRequire.decode(str, key);
// console.log('r: ', r);
var l = secretLib.decode(str, key);
console.log('l: ', l);
// l: G�«ïØ�G�{
// 乱码代表解密失败
也就是报错直接返回 false
代码运行到这里根据 esm 严格模式
会直接报错 Uncaught ReferenceError: v is not defined
然后上面的函数就直接返回 false
解码函数接收到的就是 falsefalsefalsefalsefalsefalse...
, 最终造成乱码
对于第三种同时执行的情况
// 3. 以上两种同时执行
var r = secretRequire.decode(str, key);
console.log('r: ', r);
var l = secretLib.decode(str, key);
console.log('l: ', l);
由于 @require
的代码运行在 非严格模式
下,并且你的代码顺序是先执行 secretRequire
,当执行到
https://github.com/fuxin052/monkey-test/blob/eb980f23f64486402fca1c520046f019cafc8616/src/libs/jsencrypt.js#L1744
非严格模式下,相当于 window.v = xxx
不会报错,直接给 window 添加一个 v 属性,最终也就输出了正确的结果
接下来执行 secretLib.decode
,当执行到它的相同位置的代码时,由于此时 window.v
是有值的,所以虽然代码在严格模式下,
但是并不会报 v is not defined
的错,代码正常执行,也输出了正确的结果
可以用 eslint 检查潜在的错误
非常感谢解答了超出范围的问题
1.x和2.00都有这个情况, 导致开发模式不顺利