Commit 426f564a authored by Medicean's avatar Medicean

v2.0::enhancement encoder manager

* new user encoder
* edit encoder
* rename, change type
* delete encoder

enhancement #94
parent aa3d7702
......@@ -465,11 +465,39 @@ module.exports = {
},
encoders:{
title: 'Encoder Manager',
form:{
shelltype: 'Shell Type',
encoderslist: 'Encoder Lists'
toolbar: {
new: "New",
edit: "Edit",
delete: "Delete",
help: "Help",
save: "Save",
},
grid: {
ename: "Name",
etype: "Type"
},
edit_win_title: "Edit Encoder",
delete_title: "Delete Encoder",
message: {
ename_duplicate: "The encoder name cannot be duplicated",
rename_success: "Rename success",
etype_error: "Encoder type error",
retype_success: "Modify type success",
create_success: "Create encoder success",
edit_not_select: "Please select the row you want to edit first",
edit_only_single: "You can only edit one",
edit_null_value: "Encoder content can not be empty",
edit_save_success: "Save success",
delete_not_select: "Please select the row you want to delete first",
delete_success: "Delete success",
ename_invalid: "Name can only contain numbers, letters, and underlines",
},
prompt: {
create_encoder: "Create Encoder",
},
success: 'Loaded Encoder Successfully'
confirm: {
delete: (num) => antSword.noxss(`Are you sure to delete ${typeof(num) === 'number' ? num + ' encoders' : num}?`),
}
},
aproxy: {
title: 'Proxy setting',
......
......@@ -466,11 +466,39 @@ module.exports = {
},
encoders:{
title: '编码管理',
form:{
shelltype: '脚本类型',
encoderslist: '编码器列表'
toolbar: {
new: "新建",
edit: "编辑",
delete: "删除",
help: "帮助",
save: "保存",
},
grid: {
ename: "名称",
etype: "类型"
},
edit_win_title: "编辑编码器",
delete_title: "删除编码器",
message: {
ename_duplicate: "编码器名称不能重复",
rename_success: "重命名成功",
etype_error: "编码器类型错误",
retype_success: "类型修改成功",
create_success: "新增编码器成功",
edit_not_select: "请先选中要编辑的行",
edit_only_single: "只能编辑一个",
edit_null_value: "编码器内容不能为空",
edit_save_success: "保存成功",
delete_not_select: "请先选中要删除的行",
delete_success: "删除成功",
ename_invalid: "名称只能包含数字、字母、下划线",
},
prompt: {
create_encoder: "创建编码器",
},
success: '编码器加载成功'
confirm: {
delete: (num) => antSword.noxss(`你确定要删除 ${typeof(num) === 'number' ? num + ' 个编码器' : num+" "}吗?`),
}
},
aproxy: {
title: '代理设置',
......
/**
* 中国蚁剑::编码器管理
* 创建:2017-05-30
* 更新:2017-05-30
* 更新:2018-08-19
* 作者:Virink <virink@outlook.com>
*
* 瞎折腾好了。。。
* 编辑保存什么的功能我就不弄了
* 累觉不爱。。。。。。。。
* 作者:Medici.Yan <Medici.Yan@gmail.com>
*/
const LANG = antSword['language']['settings']['encoders'];
const LANG_T = antSword['language']['toastr'];
const fs = require('fs');
const path = require('path');
const WIN = require("../../ui/window");
class Encoders {
constructor(sidebar) {
var _me = this;
this.encoders = {asp:[],aspx:[],php:[],custom:[]};
this.getEncoders();
var that = this;
this.encoders = antSword["encoders"];
sidebar.addItem({
id: 'encoders',
text: `<i class="fa fa-file-code-o"></i> ${LANG['title']}`
});
this.cell = sidebar.cells('encoders');
// 并没有什么卵用的工具栏
const toolbar = this.cell.attachToolbar();
that.cell = sidebar.cells('encoders');
const toolbar = that.cell.attachToolbar();
toolbar.loadStruct([
{ type: 'button', text: `${LANG['title']}`, icon: 'eye'}
{ type: 'buttonSelect', text: LANG['toolbar']['new'], icon: 'plus-circle', id: 'new', openAll: true,
options: [
{ id: 'new_asp', icon: 'file-code-o', type: 'button', text: "ASP" },
{ id: 'new_aspx', icon: 'file-code-o', type: 'button', text: "ASPX"},
{ id: 'new_php', icon: 'file-code-o', type: 'button', text: "PHP"},
{ type: 'separator' },
{ id: 'new_custom', icon: 'file-code-o', type: 'button', text: "Custom"}
]},
{ type: 'separator' },
{ type: 'button', text: LANG['toolbar']['edit'], icon: 'fa fa-edit', id: 'edit' },
{ type: 'button', text: LANG['toolbar']['delete'], icon: 'fa fa-trash-o', id: 'delete' },
]);
let layout = this.cell.attachLayout('2E');
this.a = layout.cells('a');
this.b = layout.cells('b');
this.a.hideHeader();
this.b.hideHeader();
this.a.setHeight(80);
toolbar.attachEvent("onClick", (id)=>{
switch(id) {
case "new_asp":
that.createEncoder("asp");
break;
case "new_aspx":
that.createEncoder("aspx");
break;
case "new_php":
that.createEncoder("php");
break;
case "new_custom":
that.createEncoder("custom");
break;
case "edit":
that.editEncoder();
break;
case "delete":
that.deleteEncoder();
break;
}
});
this._createFrom({});
let grid = that.cell.attachGrid();
grid.setHeader(`
&nbsp;,
${LANG['grid']['ename']},
${LANG['grid']['etype']}
`);
grid.setColTypes("ro,edtxt,coro");
grid.setColSorting('str,str,str');
grid.setInitWidths("40,*,150");
grid.setColAlign("center,left,center");
grid.enableMultiselect(true);
var combobox = grid.getCombo(2);
combobox.put("asp","ASP");
combobox.put("aspx","ASPX");
combobox.put("php","PHP");
combobox.put("custom","CUSTOM");
grid.attachEvent("onEditCell", function(stage,rId,cInd,nValue,oValue){
// 2 编辑完成
if(stage === 2) {
nValue = nValue.toLocaleLowerCase();
oValue = oValue.toLocaleLowerCase();
if(nValue === oValue){return;}
var oename = grid.getRowAttribute(rId, "ename");
var oepath = grid.getRowAttribute(rId, "epath");
var oetype = grid.getRowAttribute(rId, "etype");
oepath = oepath+".js";
switch(cInd){
case 1:
// name
if(!nValue.match(/^[a-zA-Z0-9_]+$/)){
toastr.error(LANG["message"]["ename_invalid"],LANG_T['error']);
return
}
if(that._checkname(nValue, oetype)){
toastr.error(LANG['message']['ename_duplicate'], LANG_T['error']);
return;
}
fs.renameSync(oepath, path.join(process.env.AS_WORKDIR, `antData/encoders/${oetype}/encoder/${nValue}.js`));
toastr.success(LANG['message']["rename_success"],LANG_T["success"]);
break
case 2:
// type
if(nValue != "asp" && nValue != "aspx" && nValue != "php" && nValue != "custom") {
toastr.error(LANG['message']["etype_error"], LANG_T['error']);
return
}
if(that._checkname(oename, nValue)){
toastr.error(LANG['message']['ename_duplicate'], LANG_T['error']);
return;
}
fs.renameSync(oepath, path.join(process.env.AS_WORKDIR, `antData/encoders/${nValue}/encoder/${oename}.js`));
toastr.success(LANG['message']["retype_success"],LANG_T["success"]);
break
}
that.syncencoders();
}
});
grid.init();
that.grid = grid;
this.editor = this.b.attachEditor([{
name: 'editor', type: 'editor',
inputLeft:0, inputTop:0, inputHeight:this.b.getHeight(),inputWidth:this.b.getWidth(),
position:'absolute'
}]);
that.parseData();
}
// 创建新的编码器
createEncoder(t) {
let self = this;
layer.prompt({
value: `myencoder`,
title: `<i class="fa fa-file-code-o"></i> ${LANG["prompt"]["create_encoder"]}`
},(value, i, e) => {
value = value.toLocaleLowerCase();
if(!value.match(/^[a-zA-Z0-9_]+$/)){
toastr.error(LANG["message"]["ename_invalid"],LANG_T['error']);
return
}
if(self._checkname(value, t)){
toastr.error(LANG["message"]["ename_duplicate"] ,LANG_T['error']);
layer.close(i);
return
}
let savePath= path.join(process.env.AS_WORKDIR,`antData/encoders/${t}/encoder/${value}.js`);
_createFrom(arg){
var _me = this;
const opt = Object.assign({}, {
type: 'asp',
encoder: []
}, arg);
const form = this.a.attachForm([
{ type: 'block', list: [
{
type: 'combo', label: `${LANG['form']['shelltype']}`, width: 100,
name: 'encodertype', readonly: true, options: this._parseEncodes(opt.type)
}
]}
], true);
form.enableLiveValidation(true);
form.attachEvent("onChange", function(name, value){
if (name == "encoder" && value != 'virink') {
let _ = form.getFormData();
_me._readEncoderSource(_.encodertype, value);
fs.writeFileSync(savePath, self.default_template);
var ids = self.grid.getAllRowIds();
let _id = 1;
if(ids.length > 0){
_id = parseInt(ids[ids.length-1]);
}
_id ++;
self.grid.addRow(_id, `${_id},${antSword.noxss(value)},${t}`);
toastr.success(LANG["message"]["create_success"], LANG_T["success"]);
self.cell.progressOff();
layer.close(i);
self.syncencoders();
});
return form;
}
_readEncoderSource(_path,name){
let codes = fs.readFileSync(path.join(__dirname,`../../core/${_path}/encoder/${name}.js`));
if(codes){
let c = [];
codes.toString().split("\n").map((_)=>{
c.push(`<div>${_}</div>`);
});
this.editor.setContent(c.toString().replace(/,/ig,""));
// 编辑选中的编码器代码
editEncoder() {
let self = this;
// 获取选中ID列表
let ids = self.grid.getSelectedId();
if(!ids){
toastr.warning(LANG["message"]["edit_not_select"], LANG_T["warning"]);
return
}
let _ids = ids.split(",");
if (_ids.length !== 1) {
toastr.warning(LANG["message"]["edit_only_single"], LANG_T["warning"]);
return
}
let _id = _ids[0];
const ename = self.grid.getRowAttribute(_id, 'ename');
const epath = self.grid.getRowAttribute(_id, 'epath');
let buff = fs.readFileSync(epath+".js");
let opt = {
title: `${LANG["edit_win_title"]}: ${ename}`,
width: 800,
height: 600,
};
let _win = new WIN(opt);
_win.win.centerOnScreen();
_win.win.button('minmax').show();
_win.win.button('minmax').enable();
// _win.win.maximize();
let toolbar = _win.win.attachToolbar();
toolbar.loadStruct([
{ id: 'save', type: 'button', icon: 'save', text: LANG["toolbar"]['save'] },
{ type: 'separator' },
]);
toolbar.attachEvent('onClick', (id) => {
if (id === 'save') {
// 保存代码
let saveData = editor.session.getValue();
if(!saveData){
toastr.warning(LANG["message"]["edit_null_value"],LANG_T["warning"]);
return
}
fs.writeFileSync(epath+".js", saveData);
toastr.success(LANG["message"]["edit_save_success"], LANG_T["success"]);
}
});
// 创建编辑器
let editor = ace.edit(_win.win.cell.lastChild);
editor.$blockScrolling = Infinity;
editor.setTheme('ace/theme/tomorrow');
editor.session.setMode(`ace/mode/javascript`);
editor.session.setUseWrapMode(true);
editor.session.setWrapLimitRange(null, null);
editor.setOptions({
fontSize: '14px',
enableBasicAutocompletion: true,
enableSnippets: true,
enableLiveAutocompletion: true
});
// 编辑器快捷键
editor.commands.addCommand({
name: 'save',
bindKey: {
win: 'Ctrl-S',
mac: 'Command-S'
},
exec: () => {
toolbar.callEvent('onClick', ['save']);
}
});
editor.session.setValue(buff.toString());
// 定时刷新
const inter = setInterval(editor.resize.bind(editor), 200);
_win.win.attachEvent('onClose', () => {
self.syncencoders();
clearInterval(inter);
return true;
});
}
_parseEncodes(_st){
let ret = [];
for (let t in this.encoders){
let es = this.encoders[t];
ret.push({
text: t.toUpperCase(),
selected: t === _st,
value: t,
list: ((t)=>{
let s = [{ text: 'Welcome', value: 'virink'}];
es.map((e)=>{
s.push({ text: e, value: e});
});
let _ = [{
type: 'combo', label: `${LANG['form']['encoderslist']}`, width: 200,
name: 'encoder', readonly: true, options: s
}];
return _;
})(t)
});
deleteEncoder() {
let self = this;
// 获取选中ID列表
let ids = self.grid.getSelectedId();
if(!ids){
toastr.warning(LANG["message"]["delete_not_select"], LANG_T["warning"]);
return
}
return ret;
let _ids = ids.split(",");
layer.confirm(`${LANG['confirm']['delete'](_ids.length==1?self.grid.getRowAttribute(_ids[0],"ename"): _ids.length)}`,
{
icon: 2,
shift: 6,
title: `<i class="fa fa-trash"></i> ${LANG["delete_title"]}`,
},(_)=>{
layer.close(_);
_ids.map((_id)=>{
var ename = self.grid.getRowAttribute(_id, 'ename');
var epath = self.grid.getRowAttribute(_id, 'epath');
fs.unlink(epath+".js");
});
toastr.success(LANG["message"]["delete_success"], LANG_T["success"]);
self.syncencoders();
});
}
get default_template() {
return `/**
* php::base64编码器
* Create at: ${new Date().format("yyyy/MM/dd hh:mm:ss")}
*/
\'use strict\';
/*
* @param {String} pwd 连接密码
* @param {Array} data 编码器处理前的 payload 数组
* @return {Array} data 编码器处理后的 payload 数组
*/
module.exports = (pwd, data) => {
// ########## 请在下方编写你自己的代码 ###################
// 以下代码为 PHP Base64 样例
// 生成一个随机变量名
let randomID = \`_0x\${Math.random().toString(16).substr(2)}\`;
// 原有的 payload 在 data['_']中
// 取出来之后,转为 base64 编码并放入 randomID key 下
data[randomID] = new Buffer(data['_']).toString('base64');
// shell 在接收到 payload 后,先处理 pwd 参数下的内容,
data[pwd] = \`eval(base64_decode($_POST[\${randomID}]));\`;
// ########## 请在上方编写你自己的代码 ###################
// 删除 _ 原有的payload
delete data['_'];
// 返回编码器处理后的 payload 数组
return data;
}`;
}
// 检查 name 是否重复
_checkname(name,t) {
let tstr = ',' + antSword['encoders'][t].join(',')+',';
return tstr.indexOf(","+name+",")!=-1;
}
// 解析数据
parseData() {
let data = [];
let self = this;
let _id = 1;
getEncoders(){
var _me = this;
['asp','aspx','php','custom'].map((t)=>{
let me = fs.readdirSync(path.join(__dirname,`../../core/${t}/encoder`));
me.map((_) => {
if (_ != '.DS_Store')
_me.encoders[t].push(_.replace(/\.js/ig, ''));
Object.keys(self.encoders).map((t) => {
self.encoders[t].map( _ => {
data.push({
id: _id,
ename: _,
epath: path.join(process.env.AS_WORKDIR, `antData/encoders/${t}/encoder/${_}`),
etype: t,
data: [
`<i class="fa fa-file-code-o"></i>`,
antSword.noxss(_),
t
]
});
_id++;
});
localStorage.setItem(`encoders_${t}`,_me.encoders[t]);
});
toastr.success(`${LANG['success']}`, LANG_T['success']);
self.grid.clearAll();
self.grid.parse({
'rows': data
}, 'json');
}
// 同步到全局编码器
syncencoders() {
antSword['encoders'] = (function(){
var encoders = {asp:[],aspx:[],php:[],custom:[]};
var encoders_path = {asp:[],aspx:[],php:[],custom:[]};
let userencoder_path = path.join(process.env.AS_WORKDIR,'antData/encoders');
// 初始化
!fs.existsSync(userencoder_path) ? fs.mkdirSync(userencoder_path) : null;
['asp','aspx','php','custom'].map((t)=>{
!fs.existsSync(path.join(userencoder_path, `${t}`))? fs.mkdirSync(path.join(userencoder_path, `${t}`)):null;
let t_path = path.join(userencoder_path, `${t}/encoder/`);
!fs.existsSync(t_path) ? fs.mkdirSync(t_path) : null;
let es = fs.readdirSync(t_path);
if(es){
es.map((_)=>{
if(!_.endsWith(".js")){
return
}
encoders[t].push(_.slice(0,-3));
encoders_path[t].push(path.join(t_path, _.slice(0,-3)));
});
}
antSword["core"][t].prototype.user_encoders = encoders_path[t];
});
return encoders;
})();
this.encoders=antSword["encoders"];
this.parseData();
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment