296 lines
9.1 KiB
JavaScript
296 lines
9.1 KiB
JavaScript
/**
|
||
* 中国蚁剑::核心模块::基础函数库
|
||
* 开写:2016/04/12
|
||
* 更新:-
|
||
* 作者:蚁逅 <https://github.com/antoor>
|
||
*/
|
||
'use strict';
|
||
|
||
const iconv = require('iconv-lite');
|
||
|
||
class Base {
|
||
|
||
/**
|
||
* 初始化
|
||
* @param {Object} opts 配置对象
|
||
* @return {Object} this
|
||
*/
|
||
constructor(opts) {
|
||
// 默认配置
|
||
opts['encode'] = opts['encode'] || 'utf8';
|
||
opts['encoder'] = opts['encoder'] || 'default';
|
||
this.__opts__ = opts;
|
||
|
||
this['__encoder__'] = {
|
||
/**
|
||
* 默认编码器
|
||
* @param {String} pwd 连接密码
|
||
* @param {Object} data 请求数据
|
||
* @return {Object} 生成数据
|
||
*/
|
||
default(pwd, data) {
|
||
data[pwd] = data['_'];
|
||
delete data['_'];
|
||
return data;
|
||
},
|
||
/**
|
||
* 随机编码器
|
||
* @param {String} pwd 连接密码
|
||
* @param {Object} data 请求数据
|
||
* @return {Object} 生成数据
|
||
*/
|
||
random(pwd, data) {
|
||
let _encoders = [];
|
||
for (let _ in this) {
|
||
if (_ === 'random') { continue }
|
||
_encoders.push(_);
|
||
}
|
||
let _index = parseInt(Math.random() * _encoders.length);
|
||
return this[
|
||
_encoders[_index]
|
||
](pwd, data);
|
||
}
|
||
}
|
||
// 解析自定义编码器
|
||
this.user_encoders.map((_)=>{
|
||
this.parseEncoder(`${_}`);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 返回参数列表
|
||
* @return {array} [arg1, arg2, arg3..]
|
||
*/
|
||
argv() {
|
||
// 生成一个随机的变量名
|
||
let random = () => `0x${(Math.random() + Math.random()).toString(16).substr(2)}`;
|
||
// 返回六个随机变量名数组
|
||
return [
|
||
random(), random(), random(),
|
||
random(), random(), random()
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 字符串格式化处理
|
||
* 使用方法:const format = new format()
|
||
* @param {String} encode [字符串编码,默认utf8]
|
||
* @return {Object} [返回字符串处理函数对象]
|
||
*/
|
||
format(encode) {
|
||
return {
|
||
/**
|
||
* base64编码
|
||
* @param {String} str 字符串
|
||
* @return {String} 编码后的字符串
|
||
*/
|
||
base64(str) {
|
||
return new Buffer(
|
||
iconv.encode(new Buffer(str), encode)
|
||
).toString('base64');
|
||
},
|
||
/**
|
||
* 字符串转16进制(不进行编码转换
|
||
* @param {String} str 转换的字符串
|
||
* @return {Buffer} 转换完成的buffer
|
||
*/
|
||
buffer(str) {
|
||
return new Buffer(str).toString('hex').toUpperCase();
|
||
},
|
||
/**
|
||
* 字符串转16进制(进行编码转换
|
||
* @param {String} str 转换的字符串
|
||
* @return {Buffer} 转换完成的buffer
|
||
*/
|
||
hex(str) {
|
||
return new Buffer(
|
||
iconv.encode(new Buffer(str), encode)
|
||
).toString('hex').toUpperCase();
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 解析脚本模板
|
||
* @param {String} tpl 模板文件
|
||
* @return {Object} 解析完毕的模板对象(参数`_`为主代码入口
|
||
*/
|
||
parseTemplate(tpl) {
|
||
// 把模板路径的`/`转换为`_`
|
||
let templateName = (tpl.split('template/')[1]).replace(/\//g, '_');
|
||
this[templateName] = {};
|
||
// 加载模板
|
||
let _argv = this.argv();
|
||
let templateObj = require(`${tpl}`)(
|
||
_argv[0], _argv[1], _argv[2],
|
||
_argv[3], _argv[4], _argv[5]
|
||
);
|
||
// let formatter = new this.format(this.__opts__['encode']);
|
||
let formatter = Base.prototype.format(this.__opts__['encode']);
|
||
// 解析模板
|
||
for (let funcName in templateObj) {
|
||
this[templateName][funcName] = (
|
||
(args) => {
|
||
if (typeof(args) === 'object') {
|
||
// 如果脚本函数需要参数,则进行解析
|
||
return (argv) => {
|
||
let data = {};
|
||
// 克隆源数据到返回数据中
|
||
for (let _ in args) {
|
||
data[_] = args[_];
|
||
}
|
||
// 循环替换脚本中的标签
|
||
for (let arg in args) {
|
||
(args[arg].match(/#{([\w\:]+)}/g) || []).map(
|
||
// example: #{hex::str} = hex(str), #{arg1} = arg1
|
||
(tag) => {
|
||
let tagStr = tag.substr(2, tag.length - 3);
|
||
let tagArr = tagStr.split('::');
|
||
let func, retStr;
|
||
if (
|
||
(tagArr.length > 0) &&
|
||
(func = formatter[tagArr[0]])
|
||
) {
|
||
// 如果包含有分割标签且该格式化函数存在,则调用该函数进行处理
|
||
retStr = func( argv[tagArr[1] || ''] );
|
||
} else {
|
||
// 否则替换直接返回字符串
|
||
retStr = argv[tagStr] || '';
|
||
}
|
||
// 组合最终生成模板代码
|
||
data[arg] = args[arg].replace(tag, retStr);
|
||
}
|
||
)
|
||
}
|
||
// 发送HTTP请求
|
||
return data;
|
||
}
|
||
} else {
|
||
// 否则直接返回
|
||
return () => ({ _: args });
|
||
}
|
||
}
|
||
)(templateObj[funcName]);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 解析编码器
|
||
* ? 编码器其实模板返回的脚本对象进行编码处理,主要就是把脚本模板中的`_`主变量改为用户传递的密码
|
||
* @param {String} enc 编码器文件
|
||
* @return {Object} 编码器处理函数对象
|
||
*/
|
||
parseEncoder(enc) {
|
||
// 加载编码器
|
||
// QAQ!我也不知道为什么,如果直接require变量名,babel编译就会warning,so我只好加个`咯~
|
||
this['__encoder__'][enc.split('encoder/')[1]] = require(`${enc}`);
|
||
}
|
||
|
||
/**
|
||
* 编码处理并返回操作
|
||
* @param {String} tag_s 前截断符
|
||
* @param {String} tag_e 后截断符
|
||
* @param {Object} data 源POST数据
|
||
* @return {Object} 最终生成数据// 将返回三个参数对象:tag_s,tag_e,data
|
||
*/
|
||
encodeComplete(tag_s, tag_e, data) {
|
||
// 编码器处理
|
||
let finalData = this.__encoder__[this.__opts__['encoder']](
|
||
this.__opts__['pwd'],
|
||
data
|
||
);
|
||
return {
|
||
'tag_s': tag_s,
|
||
'tag_e': tag_e,
|
||
'data': finalData
|
||
};
|
||
}
|
||
|
||
/**
|
||
* HTTP请求函数
|
||
* ? 用法:core.request(core.base.info()).then((ret) => {}).catch((e) => {})..
|
||
* @param {Object} code 请求源数据
|
||
* @param {Function} chunkCallBack 二进制流回调函数,可选
|
||
* @return {Promise} Promise操作对象
|
||
*/
|
||
request(code, chunkCallBack) {
|
||
const opt = this.complete(code);
|
||
return new Promise((res, rej) => {
|
||
// 随机ID(用于监听数据来源)
|
||
const hash = (String(+new Date) + String(Math.random())).substr(10, 10).replace('.', '_');
|
||
// 监听数据返回
|
||
antSword['ipcRenderer']
|
||
// 请求完毕返回数据{text,buff}
|
||
.once(`request-${hash}`, (event, ret) => {
|
||
return res({
|
||
'text': ret['text'],
|
||
'buff': ret['buff']
|
||
});
|
||
})
|
||
// HTTP请求返回字节流
|
||
.on(`request-chunk-${hash}`, (event, ret) => {
|
||
return chunkCallBack ? chunkCallBack(ret) : null;
|
||
})
|
||
// 数据请求错误
|
||
.once(`request-error-${hash}`, (event, ret) => {
|
||
return rej(ret);
|
||
})
|
||
// 发送请求数据
|
||
.send('request', {
|
||
url: this.__opts__['url'],
|
||
hash: hash,
|
||
data: opt['data'],
|
||
tag_s: opt['tag_s'],
|
||
tag_e: opt['tag_e'],
|
||
encode: this.__opts__['encode'],
|
||
ignoreHTTPS: (this.__opts__['otherConf'] || {})['ignore-https'] === 1,
|
||
timeout: parseInt((this.__opts__['otherConf'] || {})['request-timeout']),
|
||
headers: (this.__opts__['httpConf'] || {})['headers'] || {},
|
||
body: (this.__opts__['httpConf'] || {})['body'] || {}
|
||
});
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 文件下载专用函数(因有些文件过大,导致Electron出错
|
||
* @param {String} savePath 保存文件路径
|
||
* @param {Object} postCode 提交数据
|
||
* @param {Function} progressCallback 进度回调
|
||
* @return {Promise} Promise操作对象
|
||
*/
|
||
download(savePath, postCode, progressCallback) {
|
||
const opt = this.complete(postCode);
|
||
return new Promise((ret, rej) => {
|
||
// 随机ID(用于监听数据来源)
|
||
const hash = (String(+new Date) + String(Math.random())).substr(10, 10).replace('.', '_');
|
||
// 监听数据返回
|
||
antSword['ipcRenderer']
|
||
// 请求完毕返回数据(size)
|
||
.once(`download-${hash}`, (event, size) => {
|
||
return ret(size);
|
||
})
|
||
// HTTP请求返回字节流大小
|
||
.on(`download-progress-${hash}`, (event, size) => {
|
||
return progressCallback ? progressCallback(size) : null;
|
||
})
|
||
// 数据请求错误
|
||
.once(`download-error-${hash}`, (event, ret) => {
|
||
throw new Error(ret);
|
||
})
|
||
// 发送请求数据
|
||
.send('download', {
|
||
url: this.__opts__['url'],
|
||
hash: hash,
|
||
path: savePath,
|
||
data: opt['data'],
|
||
tag_s: opt['tag_s'],
|
||
tag_e: opt['tag_e'],
|
||
encode: this.__opts__['encode']
|
||
});
|
||
})
|
||
}
|
||
}
|
||
|
||
// export default Base;
|
||
module.exports = Base;
|