diff --git a/CHANGELOG.md b/CHANGELOG.md index fa5c9038..6aa62d99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,32 @@ > 有空会补补BUG、添添新功能。 > 同时也欢迎大家的参与!感谢各位朋友的支持! .TAT. +## 2018/12/25 `(v2.0.3)` + +### 模块增强 + +#### Shell 管理 + + * 添加 Shell 时 URL 默认前缀 `http://` + * 添加 Shell 时根据文件后缀选择 Shell 类型并赋予默认编码(asp 默认 GBK, 其它默认 UTF8) #109 + * 其它配置新增 `Multipart 发包` 功能 + +#### 后端模块 + + * 数据存储新增插件配置存储管理功能 (`shell-addPluginDataConf`, `shell-editPluginDataConf`, `shell-delPluginDataConf`, `shell-getPluginDataConf`) + * 后台发包方式支持 `Multipart`, 可在「编辑Shell配置」-「其它配置」里选择是否开启此功能,默认关闭。(thx @phith0n) + +### Bug Fix + + * 修复数据库编码无法保存的 Bug (#110 thx @Twi1ight) + * 修复 PHP Mysql(i) 数据管理模版代码中编码设置部分的错误 (#110 thx @Twi1ight) + +### Other + + * 自动检查更新每24小时触发一次(GitHub 访问频率限制) + * 插件市场默认窗口大小调整 + * Loading 界面增加了圣诞节彩蛋, 偶尔跟风过个节 🎄 Merry Christmas 🎄 + ## 2018/12/05 `(v2.0.2)` ### 模块增强 diff --git a/modules/database.js b/modules/database.js index 792261eb..84d526af 100644 --- a/modules/database.js +++ b/modules/database.js @@ -41,7 +41,11 @@ class Database { .on('shell-delDataConf', this.delDataConf.bind(this)) .on('shell-getDataConf', this.getDataConf.bind(this)) .on('shell-renameCategory', this.renameShellCategory.bind(this)) - .on('shell-updateHttpConf', this.updateHttpConf.bind(this)); + .on('shell-updateHttpConf', this.updateHttpConf.bind(this)) + .on('shell-addPluginDataConf', this.addPluginDataConf.bind(this)) + .on('shell-editPluginDataConf', this.editPluginDataConf.bind(this)) + .on('shell-delPluginDataConf', this.delPluginDataConf.bind(this)) + .on('shell-getPluginDataConf', this.getPluginDataConf.bind(this)); } /** @@ -389,6 +393,120 @@ class Database { event.returnValue = err || confs[opts['id']]; }); } + + /** + * 添加插件数据配置 + * @param {Object} event ipcMain对象 + * @param {string} plugin 插件注册的名称 + * @param {Object} opts 配置(_id,data + */ + addPluginDataConf(event, plugin, opts) { + logger.info('addPluginDataConf', plugin, opts); + // 1. 获取原配置列表 + this.cursor.findOne({ + _id: opts['_id'] + }, (err, ret) => { + ret['plugins'] = ret['plugins'] || {}; + let confs = ret['plugins'][plugin] || {}; + // 随机Id(顺序增长 + const random_id = parseInt(+new Date + Math.random() * 1000).toString(16); + // 添加到配置 + confs[random_id] = opts['data']; + let setdata = { + utime: +new Date, + } + setdata[`plugins.${plugin}`] = confs; + + // 更新 + this.cursor.update({ + _id: opts['_id'] + }, { + $set: setdata + }, (_err, _ret) => { + event.returnValue = random_id; + }); + }); + } + /** + * 修改插件数据配置 + * @param {Object} event ipcMain对象 + * @param {string} plugin 插件注册的名称 + * @param {Object} opts 配置(_id,id,data + */ + editPluginDataConf(event, plugin, opts) { + logger.info('editPluginDataConf', plugin, opts); + // 1. 获取原配置列表 + this.cursor.findOne({ + _id: opts['_id'] + }, (err, ret) => { + ret['plugins'] = ret['plugins'] || {}; + let confs = ret['plugins'][plugin] || {}; + // 添加到配置 + confs[opts['id']] = opts['data']; + let setdata = { + utime: +new Date, + } + setdata[`plugins.${plugin}`] = confs; + // 更新数据库 + this.cursor.update({ + _id: opts['_id'] + }, { + $set: setdata + }, (_err, _ret) => { + event.returnValue = opts['id']; + }); + }); + } + + /** + * 删除插件数据配置 + * @param {Object} event ipcMain对象 + * @param {string} plugin 插件注册的名称 + * @param {Object} opts 配置(_id,id + * @return {[type]} [description] + */ + delPluginDataConf(event, plugin, opts) { + logger.info('delPluginDataConf', plugin, opts); + // 1. 获取原配置 + this.cursor.findOne({ + _id: opts['_id'] + }, (err, ret) => { + ret['plugins'] = ret['plugins'] || {}; + let confs = ret['plugins'][plugin] || {}; + // 2. 删除配置 + delete confs[opts['id']]; + let setdata = { + utime: +new Date, + } + setdata[`plugins.${plugin}`] = confs; + // 3. 更新数据库 + this.cursor.update({ + _id: opts['_id'] + }, { + $set: setdata + }, (_err, _ret) => { + event.returnValue = _err || _ret; + }); + }) + } + + /** + * 获取单个插件数据配置 + * @param {Object} event ipcMain对象 + * @param {string} plugin 插件注册的名称 + * @param {Object} opts 配置(_id,id + * @return {[type]} [description] + */ + getPluginDataConf(event, plugin, opts) { + logger.info('getPluginDatConf', plugin, opts); + this.cursor.findOne({ + _id: opts['_id'] + }, (err, ret) => { + ret['plugins'] = ret['plugins'] || {}; + const confs = ret['plugins'][plugin] || {}; + event.returnValue = err || confs[opts['id']]; + }); + } } module.exports = Database; diff --git a/modules/request.js b/modules/request.js index 0599717a..747a3e4a 100644 --- a/modules/request.js +++ b/modules/request.js @@ -99,7 +99,7 @@ class Request { if(opts['url'].match(CONF.urlblacklist)) { return event.sender.send('request-error-' + opts['hash'], "Blacklist URL"); } - const _request = superagent.post(opts['url']); + let _request = superagent.post(opts['url']); // 设置headers _request.set('User-Agent', USER_AGENT); // 自定义headers @@ -108,6 +108,13 @@ class Request { } // 自定义body const _postData = Object.assign({}, opts.body, opts.data); + // 通过替换函数方式来实现发包方式切换, 后续可改成别的 + const old_send = _request.send; + if(opts['useMultipart'] == 1) { + _request.send = _request.field; + }else{ + _request.send = old_send; + } _request .proxy(APROXY_CONF['uri']) .type('form') @@ -158,7 +165,7 @@ class Request { let indexEnd = -1; let tempData = []; - const _request = superagent.post(opts['url']); + let _request = superagent.post(opts['url']); // 设置headers _request.set('User-Agent', USER_AGENT); // 自定义headers @@ -167,6 +174,13 @@ class Request { } // 自定义body const _postData = Object.assign({}, opts.body, opts.data); + // 通过替换函数方式来实现发包方式切换, 后续可改成别的 + const old_send = _request.send; + if(opts['useMultipart'] == 1) { + _request.send = _request.field; + }else{ + _request.send = old_send; + } _request .proxy(APROXY_CONF['uri']) .type('form') diff --git a/package-lock.json b/package-lock.json index 82010ee8..a2bbb965 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "antsword", - "version": "2.0.0", + "version": "2.0.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 5833f492..7ee9e403 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "antsword", - "version": "2.0.2", + "version": "2.0.3", "description": "中国蚁剑是一款跨平台的开源网站管理工具", "main": "app.js", "dependencies": { diff --git a/source/app.entry.js b/source/app.entry.js index 20f8701c..82bc4349 100644 --- a/source/app.entry.js +++ b/source/app.entry.js @@ -385,8 +385,12 @@ antSword.reloadPlug(); antSword['menubar'].reg('check-update', ()=>{ antSword.ipcRenderer.send('check-update'); }); -// 检查更新 -setTimeout( - antSword.ipcRenderer.send.bind(antSword.ipcRenderer, 'check-update'), - 1000 * 60 -); + +if(new Date() - new Date(antSword['storage']('lastautocheck', false, "0")) >= 86400000) { + // 检查更新 + antSword['storage']('lastautocheck', new Date().getTime()); + setTimeout( + antSword.ipcRenderer.send.bind(antSword.ipcRenderer, 'check-update'), + 1000 * 60 + ); +} \ No newline at end of file diff --git a/source/core/base.js b/source/core/base.js index c20b7fb7..f071d92b 100644 --- a/source/core/base.js +++ b/source/core/base.js @@ -244,6 +244,7 @@ class Base { tag_e: opt['tag_e'], encode: this.__opts__['encode'], ignoreHTTPS: (this.__opts__['otherConf'] || {})['ignore-https'] === 1, + useMultipart: (this.__opts__['otherConf'] || {})['use-multipart'] === 1, timeout: parseInt((this.__opts__['otherConf'] || {})['request-timeout']), headers: (this.__opts__['httpConf'] || {})['headers'] || {}, body: (this.__opts__['httpConf'] || {})['body'] || {} @@ -285,6 +286,8 @@ class Base { data: opt['data'], tag_s: opt['tag_s'], tag_e: opt['tag_e'], + ignoreHTTPS: (this.__opts__['otherConf'] || {})['ignore-https'] === 1, + useMultipart: (this.__opts__['otherConf'] || {})['use-multipart'] === 1, encode: this.__opts__['encode'] }); }) diff --git a/source/core/php/template/database/mysql.js b/source/core/php/template/database/mysql.js index 2c2ae73f..5dfd98b6 100644 --- a/source/core/php/template/database/mysql.js +++ b/source/core/php/template/database/mysql.js @@ -34,7 +34,7 @@ module.exports = (arg1, arg2, arg3, arg4, arg5, arg6) => ({ // 执行SQL语句 query: { _: - `$m=get_magic_quotes_gpc();$hst=$m?stripslashes($_POST["${arg1}"]):$_POST["${arg1}"];$usr=$m?stripslashes($_POST["${arg2}"]):$_POST["${arg2}"];$pwd=$m?stripslashes($_POST["${arg3}"]):$_POST["${arg3}"];$dbn=$m?stripslashes($_POST["${arg4}"]):$_POST["${arg4}"];$sql=base64_decode($_POST["${arg5}"]);$T=@mysql_connect($hst,$usr,$pwd);@mysql_query("SET NAMES ${arg6}");@mysql_select_db($dbn, $T);$q=@mysql_query($sql);if(is_bool($q)){echo("Status\t|\t\r\n".($q?"VHJ1ZQ==":"RmFsc2U=")."\t|\t\r\n");}else{$i=0;while($col=@mysql_fetch_field($q)){echo($col->name."\t|\t");$i++;}echo("\r\n");while($rs=@mysql_fetch_row($q)){for($c=0;$c<$i;$c++){echo(base64_encode(trim($rs[$c])));echo("\t|\t");}echo("\r\n");}}@mysql_close($T);`, + `$m=get_magic_quotes_gpc();$hst=$m?stripslashes($_POST["${arg1}"]):$_POST["${arg1}"];$usr=$m?stripslashes($_POST["${arg2}"]):$_POST["${arg2}"];$pwd=$m?stripslashes($_POST["${arg3}"]):$_POST["${arg3}"];$dbn=$m?stripslashes($_POST["${arg4}"]):$_POST["${arg4}"];$sql=base64_decode($_POST["${arg5}"]);$T=@mysql_connect($hst,$usr,$pwd);@mysql_query("SET NAMES $_POST[${arg6}]");@mysql_select_db($dbn, $T);$q=@mysql_query($sql);if(is_bool($q)){echo("Status\t|\t\r\n".($q?"VHJ1ZQ==":"RmFsc2U=")."\t|\t\r\n");}else{$i=0;while($col=@mysql_fetch_field($q)){echo($col->name."\t|\t");$i++;}echo("\r\n");while($rs=@mysql_fetch_row($q)){for($c=0;$c<$i;$c++){echo(base64_encode(trim($rs[$c])));echo("\t|\t");}echo("\r\n");}}@mysql_close($T);`, [arg1]: '#{host}', [arg2]: '#{user}', [arg3]: '#{passwd}', diff --git a/source/core/php/template/database/mysqli.js b/source/core/php/template/database/mysqli.js index afe21e8f..0d80d15f 100644 --- a/source/core/php/template/database/mysqli.js +++ b/source/core/php/template/database/mysqli.js @@ -34,7 +34,7 @@ module.exports = (arg1, arg2, arg3, arg4, arg5, arg6) => ({ // 执行SQL语句 query: { _: - `$m=get_magic_quotes_gpc();$hst=$m?stripslashes($_POST["${arg1}"]):$_POST["${arg1}"];$usr=$m?stripslashes($_POST["${arg2}"]):$_POST["${arg2}"];$pwd=$m?stripslashes($_POST["${arg3}"]):$_POST["${arg3}"];$dbn=$m?stripslashes($_POST["${arg4}"]):$_POST["${arg4}"];$sql=base64_decode($_POST["${arg5}"]);$T=@mysqli_connect($hst,$usr,$pwd);@mysqli_query($T,"SET NAMES ${arg6}");@mysqli_select_db($T,$dbn);$q=@mysqli_query($T,$sql);if(is_bool($q)){echo("Status\t|\t\r\n".($q?"VHJ1ZQ==":"RmFsc2U=")."\t|\t\r\n");}{$i=0;while($col=@mysqli_fetch_field($q)){echo($col->name."\t|\t");$i++;}echo("\r\n");while($rs=@mysqli_fetch_row($q)){for($c=0;$c<$i;$c++){echo(base64_encode(trim($rs[$c])));echo("\t|\t");}echo("\r\n");}}@mysqli_close($T);`, + `$m=get_magic_quotes_gpc();$hst=$m?stripslashes($_POST["${arg1}"]):$_POST["${arg1}"];$usr=$m?stripslashes($_POST["${arg2}"]):$_POST["${arg2}"];$pwd=$m?stripslashes($_POST["${arg3}"]):$_POST["${arg3}"];$dbn=$m?stripslashes($_POST["${arg4}"]):$_POST["${arg4}"];$sql=base64_decode($_POST["${arg5}"]);$T=@mysqli_connect($hst,$usr,$pwd);@mysqli_query($T,"SET NAMES $_POST[${arg6}]");@mysqli_select_db($T,$dbn);$q=@mysqli_query($T,$sql);if(is_bool($q)){echo("Status\t|\t\r\n".($q?"VHJ1ZQ==":"RmFsc2U=")."\t|\t\r\n");}{$i=0;while($col=@mysqli_fetch_field($q)){echo($col->name."\t|\t");$i++;}echo("\r\n");while($rs=@mysqli_fetch_row($q)){for($c=0;$c<$i;$c++){echo(base64_encode(trim($rs[$c])));echo("\t|\t");}echo("\r\n");}}@mysqli_close($T);`, [arg1]: '#{host}', [arg2]: '#{user}', [arg3]: '#{passwd}', diff --git a/source/language/en.js b/source/language/en.js index 296c034a..ea271a46 100644 --- a/source/language/en.js +++ b/source/language/en.js @@ -168,6 +168,7 @@ module.exports = { }, otherConf: { nohttps: 'Ignore HTTPS certificate', + usemultipart: 'Use Multipart send payload', terminalCache: "Use the terminal's cache", filemanagerCache: "Use the filemanager's cache", uploadFragment: "Upload File Fragmentation Size", diff --git a/source/language/zh.js b/source/language/zh.js index 75ab5ec5..33e3d898 100644 --- a/source/language/zh.js +++ b/source/language/zh.js @@ -169,6 +169,7 @@ module.exports = { }, otherConf: { nohttps: '忽略HTTPS证书', + usemultipart: '使用 Multipart 发包', terminalCache: '虚拟终端使用缓存', filemanagerCache: '文件管理使用缓存', uploadFragment: '上传文件分片大小', diff --git a/source/load.entry.js b/source/load.entry.js index 86c4730b..d183a90c 100644 --- a/source/load.entry.js +++ b/source/load.entry.js @@ -85,6 +85,17 @@ window.addEventListener('load', () => { }); } + /** + * 加载界面 UI 修改 + */ + function loadingUI() { + let now = new Date(); + /** 加载圣诞节 loading 效果 */ + if(now.getMonth()+1 == 12) { + document.getElementById('loading').classList.add('loading_christmas'); + } + } + loadingUI(); // 开始加载css loadCSS('ant-static://libs/bmenu/bmenu.css') .then(() => loadCSS('ant-static://libs/toastr/toastr.min.css')) diff --git a/source/modules/database/php/index.js b/source/modules/database/php/index.js index 80206db1..3b958e62 100644 --- a/source/modules/database/php/index.js +++ b/source/modules/database/php/index.js @@ -485,26 +485,35 @@ class PHP { ], true); form.attachEvent('onChange', (_, id) => { - if (_ !== 'type') { return }; - switch(id) { - case 'mysql': - case 'mysqli': - form.setFormData({ - user: conf['user'], - passwd: conf['passwd'] - }); - break; - case 'mssql': - form.setFormData({ - user: conf['user'], - passwd: conf['passwd'] - }); - break; - default: - form.setFormData({ - user: conf['user'], - passwd: conf['passwd'] - }); + if (_ == 'type') { + switch(id) { + case 'mysql': + case 'mysqli': + form.setFormData({ + encode: conf['encode'], + user: conf['user'], + passwd: conf['passwd'] + }); + break; + case 'mssql': + form.setFormData({ + encode: conf['encode'], + user: conf['user'], + passwd: conf['passwd'] + }); + break; + default: + form.setFormData({ + encode: conf['encode'], + user: conf['user'], + passwd: conf['passwd'] + }); + } + }; + if(_ == 'encode') { + form.setFormData({ + encode: id, + }); } }); diff --git a/source/modules/plugin/index.js b/source/modules/plugin/index.js index 0cac096c..9bead452 100644 --- a/source/modules/plugin/index.js +++ b/source/modules/plugin/index.js @@ -29,9 +29,9 @@ class Plugin { return this.win.focus(); } let win = new antSword['remote'].BrowserWindow({ - width: 930, + width: 950, height: 666, - minWidth: 888, + minWidth: 650, minHeight: 555, show: false, title: 'AntSword.Store' diff --git a/source/modules/shellmanager/list/form.js b/source/modules/shellmanager/list/form.js index 56198e13..c172ca88 100644 --- a/source/modules/shellmanager/list/form.js +++ b/source/modules/shellmanager/list/form.js @@ -140,7 +140,7 @@ class Form { */ _createBaseForm(arg) { const opt = Object.assign({}, { - url: '', + url: 'http://', pwd: '', note: '', type: 'php', @@ -168,6 +168,47 @@ class Form { } ] } ], true); + + form.attachEvent('onChange', (_, id) => { + // 根据后缀自动修改 shell 类型 + if(_ == "url") { + let file_match = { + "php": /.+\.ph(p[345]?|s|t|tml)/, + "aspx": /.+\.as(px|mx)/, + "asp": /.+\.(as(p|a|hx)|c(dx|er))/, + "custom": /.+\.((jsp[x]?)|cgi)/, + } + let typecombo = form.getCombo('type'); + if(file_match.php.test(id) == true) { + typecombo.selectOption(typecombo.getOption('php').index); + }else if(file_match.aspx.test(id) == true){ + typecombo.selectOption(typecombo.getOption('aspx').index); + }else if(file_match.asp.test(id) == true){ + typecombo.selectOption(typecombo.getOption('asp').index); + }else if(file_match.custom.test(id) == true){ + typecombo.selectOption(typecombo.getOption('custom').index); + } + } + + // 默认编码设置 + if(_ == "type") { + let encodecombo = form.getCombo('encode'); + switch(id) { + case 'php': + encodecombo.selectOption(encodecombo.getOption('UTF8').index); + break; + case 'asp': + encodecombo.selectOption(encodecombo.getOption('GBK').index); + break; + case 'aspx': + encodecombo.selectOption(encodecombo.getOption('UTF8').index); + break; + case 'custom': + encodecombo.selectOption(encodecombo.getOption('UTF8').index); + break; + } + } + }); return form; } @@ -276,6 +317,7 @@ class Form { _createOtherForm(arg) { const opt = Object.assign({}, { 'ignore-https': 0, + 'use-multipart': 0, 'terminal-cache': 0, 'filemanager-cache': 1, 'upload-fragment': '500', @@ -289,6 +331,9 @@ class Form { { type: "checkbox", name: 'ignore-https', label: LANG['list']['otherConf']['nohttps'], checked: opt['ignore-https'] === 1 + }, { + type: "checkbox", name: 'use-multipart', label: LANG['list']['otherConf']['usemultipart'], + checked: opt['use-multipart'] === 1 }, { type: "checkbox", name: 'terminal-cache', label: LANG['list']['otherConf']['terminalCache'], checked: opt['terminal-cache'] === 1 diff --git a/static/css/index.css b/static/css/index.css index 26bdbe76..cc8e8430 100644 --- a/static/css/index.css +++ b/static/css/index.css @@ -11,11 +11,18 @@ html, body, #container, #loading { position: fixed; background-color: #FFF; text-align: center; - background-image: url(ant-static://imgs/load.png); background-repeat: no-repeat; background-position: 50% 50%; } +.loading_default { + background-image: url(ant-static://imgs/load.png); +} + +.loading_christmas { + background-image: url(ant-static://imgs/load-christmas.png); +} + /*sidebar.bubble*/ .dhxsidebar_bubble { width: auto !important; diff --git a/static/imgs/load-christmas.png b/static/imgs/load-christmas.png new file mode 100644 index 00000000..a113298e Binary files /dev/null and b/static/imgs/load-christmas.png differ diff --git a/views/index.html b/views/index.html index d38eb06e..b029e671 100644 --- a/views/index.html +++ b/views/index.html @@ -7,6 +7,6 @@
- +