mirror of
https://github.com/avwo/whistle.git
synced 2026-10-18 14:41:12 +08:00
1137 lines
35 KiB
JavaScript
1137 lines
35 KiB
JavaScript
var path = require('path');
|
|
var fs = require('fs');
|
|
var net = require('net');
|
|
var dns = require('dns');
|
|
var qs = require('querystring');
|
|
var LRU = require('lru-cache');
|
|
var HttpAgent = require('http').Agent;
|
|
var HttpsAgent = require('https').Agent;
|
|
var parseUrl = require('./util/parse-url-safe');
|
|
var fse = require('fs-extra2');
|
|
var extend = require('extend');
|
|
var tunnel = require('hagent').agent;
|
|
var socks = require('sockx');
|
|
var json5 = require('json5');
|
|
var pkgConf = require('../package.json');
|
|
var config = extend(exports, pkgConf);
|
|
var common = require('./util/common');
|
|
|
|
var customUIHost;
|
|
var customHostPluginMap = {};
|
|
var customPluginNameHost = {};
|
|
var WHISTLE_PLUGIN_RE = /^(?:whistle\.)?([a-z\d_\-]+)$/;
|
|
var CMD_RE = /^[\w]{1,12}(?:\s+-g)?$/;
|
|
var httpsAgents = new LRU({ max: 360 });
|
|
var socksAgents = new LRU({ max: 100 });
|
|
var version = process.version.substring(1).split('.');
|
|
var hasIPv6First = (version[0] === 22 && version[1] >= 1) || version[0] > 22;
|
|
var hasDnsOrder = typeof dns.setDefaultResultOrder === 'function';
|
|
var uid = Date.now().toString(16) + (process.pid * 10000 + Math.floor(Math.random() * 10000)).toString(16);
|
|
var IPV4_RE = /^([\d.]+)(:\d{1,5})?$/;
|
|
var IPV6_RE = /^\[([\w:]+)\](:\d{1,5})?$/;
|
|
var DATA_KEY_RE = /^(clientip|clientid|tunneldata)([=.])([\w.-]+)$/i;
|
|
var DNS_ORDERS = ['ipv4First', 'ipv4first', 'ipv6first', 'ipv6First', 'verbatim'];
|
|
var LOCAL_UI_HOST_LIST = [
|
|
'local.whistlejs.com',
|
|
'local.wproxy.org',
|
|
'rootca.pro'
|
|
];
|
|
var variableProperties = [
|
|
'encrypted',
|
|
'sockets',
|
|
'dataDirname',
|
|
'storage',
|
|
'baseDir',
|
|
'noGlobalPlugins',
|
|
'pluginsDataMap',
|
|
'globalData',
|
|
'username',
|
|
'password',
|
|
'debugMode',
|
|
'localUIHost',
|
|
'extra',
|
|
'rules',
|
|
'values',
|
|
'dnsCache',
|
|
'allowDisableShadowRules',
|
|
'disableInstaller'
|
|
];
|
|
if (hasDnsOrder) {
|
|
config.verbatim = hasIPv6First ? 2 : 1;
|
|
}
|
|
|
|
config.appName = common.upperFirst(config.name);
|
|
config.uid = uid;
|
|
config.rejectUnauthorized = false;
|
|
config.ASSESTS_PATH = path.join(__dirname, '../assets');
|
|
config.WHISTLE_POLICY_HEADER = 'x-whistle-policy';
|
|
config.CLIENT_IP_HEADER = common.CLIENT_IP_HEADER;
|
|
config.HTTPS_FIELD = common.HTTPS_FIELD;
|
|
config.CLIENT_INFO_HEADER = 'x-whistle-client-info-' + uid;
|
|
config.SHOW_LOGIN_BOX = 'x-whistle-show-login-box-' + uid;
|
|
config.WEBUI_PATH = '/.whistle-path.5b6af7b9884e1165/';
|
|
config.PREVIEW_PATH_RE = /\?\?\?WHISTLE_PREVIEW_CHARSET=([A-Z\d_-]+)\?\?\?$/;
|
|
config.PLUGIN_HOOK_NAME_HEADER = 'x-whistle-plugin-hook-name_';
|
|
config.CLIENT_ID_HEADER = common.CLIENT_ID_HEADER;
|
|
config.CLIENT_PORT_HEADER = common.CLIENT_PORT_HEADER;
|
|
config.ALPN_PROTOCOL_HEADER = common.ALPN_PROTOCOL_HEADER;
|
|
config.DISABLE_RULES_HEADER = 'x-whistle-proxy-rules-' + uid;
|
|
config.PROXY_ID_HEADER = 'x-whistle-proxy-id-' + uid;
|
|
config.WEBUI_HEAD = 'x-forwarded-from-whistle-' + uid;
|
|
config.RES_RULES_HEAD = 'x-whistle-res-rules-' + uid;
|
|
config.COMPOSER_CLIENT_ID_HEADER = 'x-whistle-client-id-' + uid;
|
|
config.FROM_COM_HEADER = 'x-whistle-composer-' + uid;
|
|
config.TEST_HEADER = 'x-whistle-test-' + uid;
|
|
config.PLUGIN_HOOKS = {
|
|
SNI: 'sni-' + uid,
|
|
AUTH: 'auth-' + uid,
|
|
HTTP: 'http-' + uid,
|
|
UI: 'ui-' + uid,
|
|
TUNNEL: 'tunnel-' + uid,
|
|
TUNNEL_RULES: 'tunnel-rules-' + uid,
|
|
REQ_STATS: 'req-stats-' + uid,
|
|
RES_STATS: 'res-stats-' + uid,
|
|
REQ_RULES: 'req-rules-' + uid,
|
|
RES_RULES: 'res-rules-' + uid,
|
|
REQ_READ: 'req-read-' + uid,
|
|
REQ_WRITE: 'req-write-' + uid,
|
|
RES_READ: 'res-read-' + uid,
|
|
RES_WRITE: 'res-write-' + uid,
|
|
WS_REQ_READ: 'ws-req-read-' + uid,
|
|
WS_REQ_WRITE: 'ws-req-write-' + uid,
|
|
WS_RES_READ: 'ws-res-read-' + uid,
|
|
WS_RES_WRITE: 'ws-res-write-' + uid,
|
|
TUNNEL_REQ_READ: 'tunnel-req-read-' + uid,
|
|
TUNNEL_REQ_WRITE: 'tunnel-req-write-' + uid,
|
|
TUNNEL_RES_READ: 'tunnel-res-read-' + uid,
|
|
TUNNEL_RES_WRITE: 'tunnel-res-write-' + uid
|
|
};
|
|
|
|
var KEEP_ALIVE_MSECS = 10000;
|
|
var CONN_TIMEOUT = common.CONN_TIMEOUT;
|
|
var DNS_ORDERS_OPTS = ['', 'ipv4first', 'ipv4first', hasIPv6First ? 'ipv6first' : '', '', 'verbatim'];
|
|
var DOMAIN_STAR_RE = /([*~]+)(\\.)?/g;
|
|
|
|
config.CONN_TIMEOUT = CONN_TIMEOUT;
|
|
|
|
var getWhistlePath = common.getWhistlePath;
|
|
var getHostPort = common.getHostPort;
|
|
var WHISTLE_PATH = getWhistlePath();
|
|
|
|
var ALL_WHISTLES_PATH = path.join(WHISTLE_PATH, 'all_whistles');
|
|
|
|
config.WHISTLE_PATH = WHISTLE_PATH;
|
|
|
|
function domainToRegExp(_, star, dot) {
|
|
var len = star.length;
|
|
var result = len > 1 ? '([^/?]*)' : '([^/?.]*)';
|
|
if (dot) {
|
|
result += '\\.';
|
|
if (len > 2) {
|
|
result = '(?:' + result + ')?';
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function getDataDir(dirname) {
|
|
var dir = path.join(WHISTLE_PATH, dirname || '.' + config.name);
|
|
fse.ensureDirSync(dir);
|
|
return dir;
|
|
}
|
|
|
|
config.baseDir = getDataDir();
|
|
config.CUSTOM_PLUGIN_PATH = path.join(WHISTLE_PATH, 'custom_plugins');
|
|
config.CUSTOM_CERTS_DIR = path.resolve(WHISTLE_PATH, 'custom_certs');
|
|
config.SAVED_SESSIONS_PATH = path.resolve(WHISTLE_PATH, 'saved_sessions');
|
|
config.DEV_PLUGINS_PATH = path.resolve(WHISTLE_PATH, 'dev_plugins');
|
|
config.rulesDir = path.join(config.baseDir, 'rules');
|
|
config.valuesDir = path.join(config.baseDir, 'values');
|
|
config.propertiesDir = path.join(config.baseDir, 'properties');
|
|
|
|
try {
|
|
fse.ensureDirSync(common.TEMP_FILES_PATH);
|
|
var blankFile = path.join(common.TEMP_FILES_PATH, 'blank');
|
|
if (!fs.existsSync(blankFile)) {
|
|
fs.writeFileSync(blankFile, '');
|
|
}
|
|
} catch (e) {}
|
|
try {
|
|
fse.ensureDirSync(config.CUSTOM_CERTS_DIR);
|
|
} catch (e) {}
|
|
try {
|
|
fse.ensureDirSync(config.SAVED_SESSIONS_PATH);
|
|
} catch (e) {}
|
|
|
|
exports.getWhistlePath = getWhistlePath;
|
|
exports.getDataDir = getDataDir;
|
|
|
|
function getHttpsAgent(options, reqOpts) {
|
|
var key = getCacheKey(options);
|
|
var agent = httpsAgents.get(key);
|
|
if (reqOpts) {
|
|
var headers = options.headers || {};
|
|
var proxyHeaders = {};
|
|
Object.keys(headers).forEach(function (key) {
|
|
var rawKey = key.split('-').map(common.upperFirst).join('-');
|
|
proxyHeaders[rawKey] = headers[key];
|
|
});
|
|
reqOpts._tunnelProxyHeaders = proxyHeaders;
|
|
}
|
|
if (!agent) {
|
|
options.proxyAuth = options.auth;
|
|
options.rejectUnauthorized = config.rejectUnauthorized;
|
|
options.proxy = {
|
|
host: options.proxyHost,
|
|
port: options.proxyPort,
|
|
enableIntercept: options.enableIntercept,
|
|
keepStreamResume: options.keepStreamResume,
|
|
proxyTunnelPath: options.proxyTunnelPath
|
|
};
|
|
var agentName = options.isHttps ? 'httpsOverHttp' : 'httpOverHttp';
|
|
if (options.proxyServername) {
|
|
options.proxy.servername = options.proxyServername;
|
|
agentName += 's';
|
|
}
|
|
agent = new tunnel[agentName](options);
|
|
httpsAgents.set(key, agent);
|
|
agent.on('free', preventThrowOutError);
|
|
}
|
|
return agent;
|
|
}
|
|
|
|
exports.getHttpsAgent = getHttpsAgent;
|
|
|
|
function getCacheKey(options, isSocks) {
|
|
var auth = options.auth || options.proxyAuth;
|
|
if (!auth) {
|
|
var headers = options.headers || '';
|
|
auth = headers['proxy-authorization'] || '';
|
|
}
|
|
var ip = (!isSocks && options.clientIp) || '';
|
|
return [
|
|
options.proxyServername ? 'https-proxy' : '',
|
|
options.isHttps ? 'https' : 'http',
|
|
options.proxyHost,
|
|
options.proxyPort,
|
|
auth,
|
|
ip,
|
|
options.proxyTunnelPath || '',
|
|
(options.isHttps && options.cacheKey) || ''
|
|
].join(':');
|
|
}
|
|
|
|
function getAuths(_url) {
|
|
var options = typeof _url == 'string' ? parseUrl(_url) : _url;
|
|
if (!options || !options.auth) {
|
|
return [socks.auth.None()];
|
|
}
|
|
|
|
var auths = [];
|
|
options.auth.split('|').forEach(function (auth) {
|
|
auth = auth.trim();
|
|
if (auth) {
|
|
var index = auth.indexOf(':');
|
|
auths.push({
|
|
username: index == -1 ? auth : auth.substring(0, index),
|
|
password: index == -1 ? '' : auth.substring(index + 1)
|
|
});
|
|
}
|
|
});
|
|
|
|
return auths.length
|
|
? auths.map(function (auth) {
|
|
return socks.auth.UserPassword(auth.username, auth.password);
|
|
})
|
|
: [socks.auth.None()];
|
|
}
|
|
|
|
exports.getAuths = getAuths;
|
|
|
|
function getDnsOrder(order) {
|
|
return order == 1 ? 2 : order;
|
|
}
|
|
|
|
function setDefaultResultOrder(order) {
|
|
if (!hasDnsOrder) {
|
|
return;
|
|
}
|
|
if (DNS_ORDERS_OPTS.indexOf(order) === -1) {
|
|
order = DNS_ORDERS_OPTS[order] || DNS_ORDERS_OPTS[1];
|
|
}
|
|
config.ipv4First = false;
|
|
config.ipv6First = false;
|
|
if (order[3] === '6') {
|
|
config.ipv6First = true;
|
|
} else if (order[3] === '4') {
|
|
config.ipv4First = true;
|
|
}
|
|
try {
|
|
if (!dns.getDefaultResultOrder || dns.getDefaultResultOrder() !== order) {
|
|
dns.setDefaultResultOrder(order);
|
|
}
|
|
config.dnsOrder = getDnsOrder(DNS_ORDERS_OPTS.indexOf(order));
|
|
return true;
|
|
} catch (e) {}
|
|
}
|
|
|
|
exports.setDefaultResultOrder = setDefaultResultOrder;
|
|
|
|
exports.setAuth = function (auth) {
|
|
if (auth) {
|
|
config.username = getString(auth.username);
|
|
var password = (config.password = getString(auth.password));
|
|
config.passwordHash = password && common.createHash(password);
|
|
setGuestAuth(auth);
|
|
}
|
|
return config;
|
|
};
|
|
|
|
exports.getPluginData = function (name) {
|
|
var pluginsDataMap = name && config.pluginsDataMap;
|
|
if (!pluginsDataMap) {
|
|
return;
|
|
}
|
|
name = name.substring(name.lastIndexOf('.') + 1);
|
|
return pluginsDataMap[name];
|
|
};
|
|
|
|
exports.setGuestAuth = function (auth) {
|
|
auth && setGuestAuth(auth);
|
|
};
|
|
|
|
function parseHost(host) {
|
|
if (Array.isArray(host)) {
|
|
return host.filter(function (h) {
|
|
return h && typeof h === 'string';
|
|
});
|
|
}
|
|
host = typeof host === 'string' ? host.trim() : '';
|
|
return host && host.split('|').map(getHostname);
|
|
}
|
|
|
|
exports.setUIHost = function (host) {
|
|
customUIHost = parseHost(host);
|
|
};
|
|
|
|
exports.setPluginUIHost = function (pluginName, host) {
|
|
if (!pluginName || !WHISTLE_PLUGIN_RE.test(pluginName)) {
|
|
return;
|
|
}
|
|
pluginName = RegExp.$1;
|
|
host = parseHost(host);
|
|
if (host) {
|
|
customPluginNameHost[pluginName] = host;
|
|
host.forEach(function (h) {
|
|
delete customHostPluginMap[h];
|
|
});
|
|
} else {
|
|
delete customPluginNameHost[pluginName];
|
|
}
|
|
customHostPluginMap = {};
|
|
Object.keys(customPluginNameHost).forEach(function (name) {
|
|
var list = customPluginNameHost[name];
|
|
list &&
|
|
list.forEach(function (h) {
|
|
customHostPluginMap[h] = name;
|
|
});
|
|
});
|
|
};
|
|
|
|
exports.connect = function (options, cb) {
|
|
return common.connectInner(options, cb, config);
|
|
};
|
|
|
|
function preventThrowOutError(socket) {
|
|
if (socket.listeners('error').indexOf(freeSocketErrorListener) === -1) {
|
|
socket.once('error', freeSocketErrorListener);
|
|
}
|
|
}
|
|
|
|
function freeSocketErrorListener() {
|
|
var socket = this;
|
|
socket.destroy();
|
|
socket.emit('agentRemove');
|
|
socket.removeListener('error', freeSocketErrorListener);
|
|
}
|
|
|
|
function resolvePath(file) {
|
|
if (!file || !(file = file.trim())) {
|
|
return file;
|
|
}
|
|
|
|
return /^[\w-]+$/.test(file) ? file : path.resolve(file);
|
|
}
|
|
|
|
function getHostname(_url) {
|
|
if (typeof _url != 'string') {
|
|
return '';
|
|
}
|
|
if (_url.indexOf('/') != -1) {
|
|
return parseUrl(_url).hostname;
|
|
}
|
|
var index = _url.indexOf(':');
|
|
return index == -1 ? _url : _url.substring(0, index);
|
|
}
|
|
|
|
function getPaths(paths, isCustom) {
|
|
if (typeof paths === 'string') {
|
|
paths = paths.trim().split(/\s*[|,;]\s*/);
|
|
} else if (!Array.isArray(paths)) {
|
|
return;
|
|
}
|
|
var result = [];
|
|
paths.forEach(function (path) {
|
|
if (isCustom && ['self', 'buildin', 'buildIn', 'build-in'].indexOf(path) !== -1) {
|
|
result.push(config.CUSTOM_PLUGIN_PATH);
|
|
} else if (path && typeof path === 'string') {
|
|
result.push(path);
|
|
}
|
|
});
|
|
return result.length ? result : null;
|
|
}
|
|
|
|
function getSecureFilter(newConf) {
|
|
var secureFilter = newConf.secureFilter;
|
|
if (typeof secureFilter === 'function') {
|
|
return secureFilter;
|
|
}
|
|
if (!secureFilter || typeof secureFilter !== 'string') {
|
|
return;
|
|
}
|
|
try {
|
|
return require(secureFilter);
|
|
} catch (e) {}
|
|
}
|
|
|
|
function getString(str) {
|
|
return str && typeof str === 'string' ? str : '';
|
|
}
|
|
|
|
function readFileText(filepath) {
|
|
var text = common.readFileTextSync(filepath);
|
|
return text && text.trim();
|
|
}
|
|
|
|
function readFileBuffer(filepath, required) {
|
|
return common.readFileBufferSync(filepath, required === false);
|
|
}
|
|
|
|
function isPort(port) {
|
|
return /^\d+$/.test(port) && port <= 65535 && port > 0;
|
|
}
|
|
|
|
function setGuestAuth(auth) {
|
|
if (auth.guestName === '-' && !auth.guestPassword) {
|
|
config.guest = {};
|
|
} else if (auth.guestName && auth.guestPassword) {
|
|
config.guest = {
|
|
username: auth.guestName,
|
|
password: auth.guestPassword
|
|
};
|
|
} else if ('guest' in auth) {
|
|
config.guest = auth.guest;
|
|
}
|
|
}
|
|
|
|
function parseString(str) {
|
|
str = str && typeof str === 'string' && str.trim();
|
|
if (!str) {
|
|
return '';
|
|
}
|
|
str = readFileText(str) || str;
|
|
if (!/\s/.test(str) && str.indexOf('%') !== -1) {
|
|
try {
|
|
str = decodeURIComponent(str);
|
|
} catch (e) {}
|
|
}
|
|
if (/^\{[\s\S]+\}$/.test(str) || /^\[[\s\S]+\]$/.test(str)) {
|
|
try {
|
|
return json5.parse(str);
|
|
} catch (e) {}
|
|
}
|
|
return str;
|
|
}
|
|
|
|
function getPluginList(list) {
|
|
if (typeof list == 'string') {
|
|
list = list.trim().split(/\s*[,|]\s*/);
|
|
}
|
|
var result;
|
|
if (Array.isArray(list)) {
|
|
list.forEach(function (name) {
|
|
if (WHISTLE_PLUGIN_RE.test(name)) {
|
|
result = result || [];
|
|
result.push(RegExp.$1);
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function readUIExt(uiExt) {
|
|
if (!uiExt) {
|
|
return;
|
|
}
|
|
var htmlPrepend = uiExt.htmlPrepend && readFileBuffer(uiExt.htmlPrepend, uiExt.required);
|
|
var htmlAppend = uiExt.htmlAppend && readFileBuffer(uiExt.htmlAppend, uiExt.required);
|
|
var jsPrepend = uiExt.jsPrepend && readFileBuffer(uiExt.jsPrepend, uiExt.required);
|
|
var jsAppend = uiExt.jsAppend && readFileBuffer(uiExt.jsAppend, uiExt.required);
|
|
if (htmlPrepend ||htmlAppend || jsPrepend || jsAppend) {
|
|
if (htmlPrepend) {
|
|
htmlPrepend = Buffer.concat([Buffer.from('<!DOCTYPE html>\n'), htmlPrepend]);
|
|
}
|
|
return {
|
|
htmlPrepend: htmlPrepend,
|
|
htmlAppend: htmlAppend,
|
|
jsPrepend: jsPrepend,
|
|
jsAppend: jsAppend
|
|
};
|
|
}
|
|
}
|
|
|
|
exports.extend = function (newConf) {
|
|
config.pluginHostMap = {};
|
|
config.uiport = config.port;
|
|
config.ipv6Only = false;
|
|
var rcConf = common.readWhistleRc(newConf);
|
|
newConf = extend({}, rcConf, newConf);
|
|
if (rcConf) {
|
|
if (rcConf.clearPreOptions) {
|
|
newConf.clearPreOptions = true;
|
|
}
|
|
if (rcConf.noGlobalPlugins) {
|
|
newConf.noGlobalPlugins = true;
|
|
}
|
|
}
|
|
if (process.env.WHISTLE_MODE) {
|
|
newConf.mode = process.env.WHISTLE_MODE + '|' + (newConf.mode || '');
|
|
}
|
|
var useAgent;
|
|
var newAgentConf;
|
|
|
|
if (newConf.specialPath && typeof newConf.specialPath === 'string') {
|
|
config.SPEC_PATH = newConf.specialPath;
|
|
}
|
|
if (newConf.whistleName && common.isWhistleName(newConf.whistleName)) {
|
|
config.whistleName = newConf.whistleName;
|
|
}
|
|
config.uiExt = readUIExt(newConf.uiExt);
|
|
config.specialAuth = newConf.specialAuth;
|
|
config.uiMiddleware = newConf.uiMiddlewares || newConf.uiMiddleware;
|
|
newAgentConf = newConf.agentConfig;
|
|
if (newConf.cmdName && CMD_RE.test(newConf.cmdName)) {
|
|
config.cmdName = newConf.cmdName;
|
|
}
|
|
if (newConf.account && typeof newConf.account === 'string') {
|
|
config.account = newConf.account;
|
|
}
|
|
config.allowPluginList = getPluginList(newConf.allowPluginList);
|
|
config.blockPluginList = getPluginList(newConf.blockPluginList);
|
|
|
|
if (newConf.webUIPath && /^[\w.-]+$/.test(newConf.webUIPath)) {
|
|
config.WEBUI_PATH = '/.' + newConf.webUIPath + config.WEBUI_PATH.substring(1);
|
|
}
|
|
if (newConf.cluster) {
|
|
config.headless = true;
|
|
config.workerIndex = process.env.workerIndex;
|
|
if (typeof newConf.mode !== 'string') {
|
|
newConf.mode = '';
|
|
}
|
|
}
|
|
var dnsServer = newConf.dnsServer;
|
|
var resolve6;
|
|
var dnsOptional;
|
|
if (common.isString(dnsServer)) {
|
|
dnsServer = dnsServer.trim();
|
|
if (common.isUrl(dnsServer)) {
|
|
config.dnsOverHttps = dnsServer;
|
|
} else {
|
|
dnsServer = dnsServer.split(/[|,&]/);
|
|
}
|
|
}
|
|
|
|
var allowOrigin = newConf.allowOrigin;
|
|
if (common.isString(allowOrigin)) {
|
|
allowOrigin = allowOrigin.trim().toLowerCase().split(/\s*[|,&]\s*/);
|
|
if (allowOrigin.indexOf('*') === -1) {
|
|
allowOrigin = allowOrigin.map(function(h) {
|
|
if (h.indexOf('*') === -1) {
|
|
return h;
|
|
}
|
|
h = common.escapeRegExp(h);
|
|
h = h.replace(DOMAIN_STAR_RE, domainToRegExp);
|
|
try {
|
|
return new RegExp('^' + h + '$');
|
|
} catch (e) {}
|
|
}).filter(function(h) {
|
|
return h;
|
|
});
|
|
if (allowOrigin.length) {
|
|
config.allowOrigin = allowOrigin;
|
|
}
|
|
} else {
|
|
config.allowAllOrigin = true;
|
|
}
|
|
}
|
|
|
|
if (dns.getServers && Array.isArray(dnsServer)) {
|
|
var newServers = [];
|
|
dnsServer.forEach(function (ip) {
|
|
ip = typeof ip === 'string' && ip.trim();
|
|
if (/^ipv6$/i.test(ip)) {
|
|
resolve6 = true;
|
|
} else if (ip === 'optional' || ip === 'default' || ip === 'fallback') {
|
|
dnsOptional = true;
|
|
} else if (net.isIP(ip)) {
|
|
newServers.push(ip);
|
|
} else if (IPV4_RE.test(ip) || IPV6_RE.test(ip)) {
|
|
var dnsIp = RegExp.$1;
|
|
var dnsPort = RegExp.$2;
|
|
if (net.isIP(dnsIp) && (!dnsPort || isPort(dnsPort.substring(1)))) {
|
|
newServers.push(ip);
|
|
}
|
|
}
|
|
});
|
|
if (newServers.length) {
|
|
dns.setServers(newServers);
|
|
config.resolve6 = resolve6;
|
|
config.dnsOptional = dnsOptional;
|
|
config.dnsServer = newServers.join();
|
|
}
|
|
}
|
|
|
|
if (newConf.inspect || newConf.inspectBrk) {
|
|
config.inspectMode = true;
|
|
process.env.PFORK_MODE = 'inline';
|
|
}
|
|
variableProperties.forEach(function (name) {
|
|
config[name] = newConf[name] || pkgConf[name];
|
|
});
|
|
var shadowRules = parseString(newConf.shadowRules);
|
|
var resolveShadowValues = function (obj) {
|
|
if (
|
|
(!obj.rules || typeof obj.rules === 'string') &&
|
|
obj.values &&
|
|
typeof obj.values !== 'string'
|
|
) {
|
|
config.shadowRules = obj.rules || obj.rules.trim();
|
|
if (Object.keys(obj.values).length) {
|
|
config.shadowValues = obj.values;
|
|
}
|
|
} else {
|
|
config.rules = extend({}, newConf.rules, obj);
|
|
}
|
|
};
|
|
if (typeof shadowRules === 'string') {
|
|
config.shadowRules = shadowRules.trim();
|
|
} else if (Array.isArray(shadowRules)) {
|
|
if (typeof shadowRules[0] === 'string') {
|
|
config.shadowRules = shadowRules[0].trim();
|
|
if (shadowRules[1]) {
|
|
config.rules = extend({}, newConf.rules, shadowRules[1]);
|
|
}
|
|
if (shadowRules[2]) {
|
|
config.values = extend({}, newConf.values, shadowRules[2]);
|
|
}
|
|
} else if (shadowRules[0]) {
|
|
resolveShadowValues(shadowRules[0]);
|
|
if (shadowRules[1]) {
|
|
config.values = extend({}, newConf.values, shadowRules[1]);
|
|
}
|
|
} else if (shadowRules[1]) {
|
|
config.values = extend({}, newConf.values, shadowRules[1]);
|
|
}
|
|
} else if (shadowRules) {
|
|
resolveShadowValues(shadowRules);
|
|
}
|
|
var extra = newConf.extra;
|
|
if (common.isString(extra)) {
|
|
extra = /^\s*\{[\w\W]*\}\s*$/.test(extra) ? extra : readFileText(extra);
|
|
try {
|
|
extra = extra && JSON.parse(extra);
|
|
if (extra && typeof extra === 'object') {
|
|
config.pluginsDataMap = extend({}, config.pluginsDataMap, extra);
|
|
}
|
|
} catch (e) {}
|
|
extra = null;
|
|
}
|
|
var customHandler = newConf.customHandler || newConf.customHandle;
|
|
if (typeof customHandler === 'function') {
|
|
config.customHandler = customHandler;
|
|
}
|
|
if (isPort(newConf.realPort) && config.realPort != config.port) {
|
|
config.realPort = newConf.realPort;
|
|
}
|
|
var realHost = newConf.realHost;
|
|
if (typeof realHost === 'string' && (!realHost || /^[\w.-]+$/.test(newConf.realHost))) {
|
|
config.realHost = newConf.realHost;
|
|
}
|
|
|
|
var socksPort = getHostPort(newConf.socksPort);
|
|
if (socksPort) {
|
|
config.socksPort = socksPort.port;
|
|
config.socksHost = socksPort.host;
|
|
}
|
|
var httpPort = getHostPort(newConf.httpPort);
|
|
if (httpPort) {
|
|
config.httpPort = httpPort.port;
|
|
config.httpHost = httpPort.host;
|
|
}
|
|
var httpsPort = getHostPort(newConf.httpsPort);
|
|
if (httpsPort) {
|
|
config.httpsPort = httpsPort.port;
|
|
config.httpsHost = httpsPort.host;
|
|
}
|
|
|
|
if (common.isString(newConf.host)) {
|
|
config.defaultHost = newConf.host;
|
|
}
|
|
|
|
if (typeof newConf.authKey === 'string') {
|
|
config.authKey = newConf.authKey;
|
|
}
|
|
if (typeof newConf.guestAuthKey === 'string') {
|
|
config.guestAuthKey = newConf.guestAuthKey;
|
|
}
|
|
if (newConf.reqCacheSize > 0) {
|
|
config.reqCacheSize = newConf.reqCacheSize;
|
|
}
|
|
if (newConf.frameCacheSize > 0) {
|
|
config.frameCacheSize = newConf.frameCacheSize;
|
|
}
|
|
config.allowMultipleChoice = newConf.allowMultipleChoice;
|
|
if (common.isString(newConf.mode)) {
|
|
var mode = newConf.mode.trim().split(/\s*[|,&]\s*/);
|
|
var useResolve;
|
|
var dnsFallback;
|
|
if (mode.indexOf('admin') !== -1) {
|
|
var admin = 'proxyServer|master|x-forwarded-proto';
|
|
admin = config.debugMode ? admin : `${admin}|strict|rules|disableUpdateTips|proxifier|notAllowedDisablePlugins`;
|
|
mode = admin.split('|').concat(mode);
|
|
}
|
|
if (mode.indexOf('multiple') !== -1) {
|
|
mode = 'multiEnv|disableUpdateTips|keepXFF|x-forwarded-proto'.split('|').concat(mode);
|
|
}
|
|
mode.forEach(function (m) {
|
|
m = m.trim();
|
|
if (
|
|
/^(pureProxy|debug|ipv6Only|master|client|diagnose|disableAuthUI|captureData|headless|strict|proxyServer|encrypted|noGzip|disableUpdateTips|proxifier2?)$/.test(m)
|
|
) {
|
|
config[m] = true;
|
|
} else if(m === 'ipv6only') {
|
|
config.ipv6Only = true;
|
|
} else if (m === 'keepProxyUI') {
|
|
config.keepProxyUI = true;
|
|
} else if (m === 'agent') {
|
|
useAgent = true;
|
|
} else if (m === 'disableUIAuth') {
|
|
config.disableAuthUI = true;
|
|
} else if (m === 'showPluginReq') {
|
|
config.showPluginReq = config.debugMode;
|
|
} else if (m === 'disableCustomCerts') {
|
|
config.disableCustomCerts = true;
|
|
} else if (m === 'nohost' || m === 'multienv' || m === 'multiEnv') {
|
|
config[m] = true;
|
|
config.multiEnv = true;
|
|
} else if (DNS_ORDERS.indexOf(m) !== -1) {
|
|
setDefaultResultOrder(m.toLowerCase());
|
|
} else if (m === 'proxyOnly') {
|
|
config.pureProxy = true;
|
|
} else if (m === 'useMultipleRules' || m === 'enableMultipleRules' || m === 'allowMultipleChoice') {
|
|
config.allowMultipleChoice = true;
|
|
} else if (m === 'disableMultipleRules') {
|
|
config.allowMultipleChoice = false;
|
|
} else if (
|
|
m === 'notAllowDisableRules' ||
|
|
m === 'notAllowedDisableRules'
|
|
) {
|
|
config.notAllowedDisableRules = true;
|
|
} else if (m === 'disableBackOption' || m === 'disabledBackOption') {
|
|
config.disabledBackOption = true;
|
|
} else if (
|
|
m === 'disableMultipleOption' ||
|
|
m === 'disabledMultipleOption'
|
|
) {
|
|
config.disabledMultipleOption = true;
|
|
} else if (
|
|
m === 'disableRulesOptions' ||
|
|
m === 'disabledRulesOptions'
|
|
) {
|
|
config.disabledRulesOptions = true;
|
|
config.disabledBackOption = true;
|
|
config.disabledMultipleOption = true;
|
|
config.notAllowedDisableRules = true;
|
|
} else if (
|
|
m === 'notAllowDisablePlugins' ||
|
|
m === 'notAllowedDisablePlugins'
|
|
) {
|
|
config.notAllowedDisablePlugins = true;
|
|
} else if (
|
|
m === 'notAllowEnableHTTPS' ||
|
|
m === 'notAllowedEnableHTTPS'
|
|
) {
|
|
config.notAllowedEnableHTTPS = true;
|
|
} else if (m === 'socks') {
|
|
config.socksMode = true;
|
|
} else if (m === 'network') {
|
|
config.networkMode = true;
|
|
config.captureData = true;
|
|
} else if (m === 'shadowRules') {
|
|
config.shadowRulesMode = true;
|
|
} else if (m === 'shadowRulesOnly') {
|
|
config.shadowRulesMode = true;
|
|
config.disableWebUI = true;
|
|
} else if (m === 'plugins') {
|
|
config.pluginsMode = true;
|
|
} else if (m === 'pluginsOnly') {
|
|
config.pluginsOnlyMode = true;
|
|
} else if (m === 'rules') {
|
|
config.rulesMode = true;
|
|
} else if (m === 'rulesOnly') {
|
|
config.rulesOnlyMode = true;
|
|
} else if (m === 'httpProxy') {
|
|
config.pureProxy = true;
|
|
} else if (
|
|
m === 'keepXFF' ||
|
|
m === common.CLIENT_IP_HEADER ||
|
|
m === 'forwardedFor'
|
|
) {
|
|
config.keepXFF = true;
|
|
} else if (m === 'x-forwarded-host') {
|
|
config.enableFwdHost = true;
|
|
} else if (m === 'x-forwarded-proto') {
|
|
config.enableFwdProto = true;
|
|
} else if (m === 'INADDR_ANY') {
|
|
config.INADDR_ANY = true;
|
|
} else if (m === 'buildIn' || m === 'build-in') {
|
|
process.env.PFORK_EXEC_PATH = process.execPath;
|
|
} else if (m === 'safe' || m === 'rejectUnauthorized') {
|
|
config.rejectUnauthorized = true;
|
|
} else if (m === 'enableRequestHeaderRules') {
|
|
config.enableRequestHeaderRules = true;
|
|
} else if (m === 'persistentCapture') {
|
|
config.isEnableCapture = true;
|
|
config.persistentCapture = true;
|
|
} else if (['capture', 'intercept', 'enable-capture', 'enableHttps', 'enableHTTPS', 'enableCapture'].indexOf(m) !== -1) {
|
|
config.isEnableCapture = true;
|
|
} else if (['disable-capture', 'disableCapture'].indexOf(m) !== -1) {
|
|
config.isEnableCapture = false;
|
|
} else if (['http2', 'enable-http2', 'enableHttp2', 'enable-h2', 'enableH2'].indexOf(m) !== -1) {
|
|
config.isEnableHttp2 = true;
|
|
} else if (
|
|
['disable-http2', 'disableHttp2', 'disable-h2', 'disableH2'].indexOf(m) !== -1
|
|
) {
|
|
config.isEnableHttp2 = false;
|
|
} else if (m === 'hideLeftBar' || m === 'hideLeftMenu') {
|
|
config.hideLeftMenu = true;
|
|
} else if (DATA_KEY_RE.test(m)) {
|
|
var type = RegExp.$1;
|
|
var override = RegExp.$2 === '=';
|
|
var key = RegExp.$3.toLowerCase();
|
|
switch (type) {
|
|
case 'clientip':
|
|
config.overCipKey = override;
|
|
config.cipKey = key;
|
|
break;
|
|
case 'clientid':
|
|
config.overCidKey = override;
|
|
config.cidKey = key;
|
|
break;
|
|
default:
|
|
config.overTdKey = override;
|
|
config.tdKey = key;
|
|
break;
|
|
}
|
|
} else if (['dnsResolve', 'dnsResolve4', 'dnsResolve6'].indexOf(m) !== -1) {
|
|
useResolve = true;
|
|
config[m] = true;
|
|
} else if (m === 'dnsFallback') {
|
|
dnsFallback = true;
|
|
}
|
|
});
|
|
|
|
if (useResolve && dnsFallback) {
|
|
config.dnsFallback = true;
|
|
}
|
|
if (config.headless) {
|
|
if (!config.pluginsMode) {
|
|
config.noGlobalPlugins = true;
|
|
}
|
|
config.pluginsOnlyMode = true;
|
|
config.disableWebUI = true;
|
|
delete config.rulesOnlyMode;
|
|
} else if (config.shadowRulesMode) {
|
|
config.networkMode = true;
|
|
delete config.rulesOnlyMode;
|
|
delete config.pluginsOnlyMode;
|
|
}
|
|
if (config.rulesOnlyMode) {
|
|
delete config.pluginsOnlyMode;
|
|
delete config.networkMode;
|
|
delete config.pluginsMode;
|
|
config.rulesMode = true;
|
|
} else if (config.pluginsOnlyMode) {
|
|
delete config.networkMode;
|
|
config.rulesMode = true;
|
|
config.pluginsMode = true;
|
|
} else if (config.networkMode) {
|
|
delete config.rulesMode;
|
|
delete config.pluginsMode;
|
|
} else if (config.rulesMode) {
|
|
delete config.pluginsMode;
|
|
delete config.networkMode;
|
|
}
|
|
}
|
|
if (/^\d+$/.test(newConf.timeout)) {
|
|
config.timeout = +newConf.timeout;
|
|
}
|
|
|
|
setGuestAuth(newConf);
|
|
config.disableAllRules = newConf.disableAllRules;
|
|
config.disableAllPlugins = newConf.disableAllPlugins;
|
|
if (newConf.replaceExistRule === false) {
|
|
config.replaceExistRule = false;
|
|
} else {
|
|
config.replaceExistRule = newConf.replaceRules;
|
|
}
|
|
if (newConf.replaceExistValue === false) {
|
|
config.replaceExistValue = false;
|
|
} else {
|
|
config.replaceExistValue = newConf.replaceValues;
|
|
}
|
|
if (common.isString(newConf.certDir)) {
|
|
config.certDir = path.resolve(newConf.certDir);
|
|
}
|
|
var mw = newConf.middlewares || newConf.middleware;
|
|
if (typeof mw == 'string') {
|
|
config.middlewares = mw.trim().split(/\s*,\s*/);
|
|
}
|
|
var secureFilter = getSecureFilter(newConf);
|
|
if (typeof secureFilter === 'function') {
|
|
config.secureFilter = secureFilter;
|
|
}
|
|
if (typeof newConf.installPlugins === 'function') {
|
|
config.installPlugins = newConf.installPlugins;
|
|
config.hasInstaller = true;
|
|
}
|
|
if (typeof newConf.handleWebReq === 'function') {
|
|
config.handleWebReq = newConf.handleWebReq;
|
|
}
|
|
if (typeof newConf.handleUpdate === 'function') {
|
|
config.handleUpdate = newConf.handleUpdate;
|
|
config.hasUpdater = true;
|
|
}
|
|
config.notUninstallPluginPaths = getPaths(newConf.notUninstallPluginPath || newConf.notUninstallPluginPaths);
|
|
config.pluginPaths = getPaths(newConf.pluginPaths || newConf.pluginsPath || newConf.pluginPath);
|
|
config.prePluginsPath = config.projectPluginPaths = getPaths(newConf.projectPluginPaths || newConf.projectPluginsPath || newConf.projectPluginPath);
|
|
config.accountPluginsPath = getPaths(newConf.accountPluginPaths || newConf.accountPluginsPath || newConf.accountPluginPath);
|
|
config.customPluginPaths = getPaths(newConf.customPluginPaths || newConf.customPluginsPath || newConf.customPluginPath, true);
|
|
config.addon = getPaths(newConf.addonsPath || newConf.addonPath || newConf.addon);
|
|
if (config.accountPluginsPath) {
|
|
config.customPluginPaths = config.accountPluginsPath.concat(config.customPluginPaths || []);
|
|
}
|
|
if (config.customPluginPaths) {
|
|
config.prePluginsPath = (config.prePluginsPath || []).concat(config.customPluginPaths);
|
|
}
|
|
|
|
var pluginHost = newConf.pluginHost;
|
|
if (typeof pluginHost === 'string' && (pluginHost = pluginHost.trim())) {
|
|
pluginHost = qs.parse(pluginHost);
|
|
Object.keys(pluginHost).forEach(function (name) {
|
|
var host = pluginHost[name];
|
|
if (typeof host === 'string' && (host = host.trim())) {
|
|
host = host.toLowerCase().split(/\s*[|,&]\s*/);
|
|
host.forEach(function (h) {
|
|
config.pluginHostMap[h] = name;
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
var port = getHostPort(newConf.port);
|
|
if (port) {
|
|
config.host = port.host;
|
|
config.uiport = config.port = port.port;
|
|
}
|
|
if (config.disableWebUI) {
|
|
config.notAllowedDisablePlugins = true;
|
|
} else {
|
|
var uiPort = getHostPort(newConf.uiport);
|
|
if (uiPort) {
|
|
var curHost = config.host || config.defaultHost;
|
|
if (curHost && uiPort.host && curHost !== uiPort.host) {
|
|
config.customUIPort = true;
|
|
} else {
|
|
config.customUIPort = uiPort.port != config.port;
|
|
}
|
|
config.uiport = uiPort.port;
|
|
config.uihost = uiPort.host;
|
|
}
|
|
}
|
|
|
|
|
|
if (!config.rulesMode) {
|
|
config.captureData = true;
|
|
}
|
|
|
|
if (!config.authKey) {
|
|
config.authKey = 'auto_' + (Date.now() + Math.random().toFixed(6));
|
|
}
|
|
config.middlewares = Array.isArray(config.middlewares)
|
|
? config.middlewares.map(resolvePath)
|
|
: [];
|
|
var uiHostList = (config.uiHostList = []);
|
|
if (typeof config.localUIHost === 'string') {
|
|
var localHostList = config.localUIHost.toLowerCase().split(/\s*[|,&]\s*/);
|
|
localHostList.forEach(function (hostname) {
|
|
hostname = getHostname(hostname);
|
|
if (hostname && LOCAL_UI_HOST_LIST.indexOf(hostname) == -1) {
|
|
uiHostList.push(hostname);
|
|
}
|
|
});
|
|
LOCAL_UI_HOST_LIST.push.apply(LOCAL_UI_HOST_LIST, uiHostList);
|
|
// 兼容老版本
|
|
config.customLocalUIHost = uiHostList[0];
|
|
}
|
|
|
|
config.setLocalUIHost = function (hostname) {
|
|
config.customLocalUIHost = getHostname(hostname);
|
|
};
|
|
|
|
config.localUIHost = 'local.whistlejs.com';
|
|
|
|
var isWebUIHost = function (host) {
|
|
if (
|
|
host === 'local.wproxy.org' ||
|
|
uiHostList.indexOf(host) !== -1 ||
|
|
(customUIHost && customUIHost.indexOf(host) !== -1)
|
|
) {
|
|
return true;
|
|
}
|
|
if (config.pureProxy) {
|
|
return false;
|
|
}
|
|
return LOCAL_UI_HOST_LIST.indexOf(host) !== -1;
|
|
};
|
|
var isLocalUIUrl = function (url) {
|
|
var host = getHostname(url);
|
|
return (
|
|
isWebUIHost(host) ||
|
|
!!config.pluginHostMap[host] ||
|
|
!!customHostPluginMap[host]
|
|
);
|
|
};
|
|
config.isLocalUIUrl = isLocalUIUrl;
|
|
exports.isWebUIHost = isWebUIHost;
|
|
exports.getPluginNameByHost = function (host) {
|
|
host = getHostname(host);
|
|
if (isWebUIHost(host)) {
|
|
return;
|
|
}
|
|
return config.pluginHostMap[host] || customHostPluginMap[host];
|
|
};
|
|
|
|
config.sockets = Math.max(parseInt(config.sockets, 10) || 0, 1);
|
|
if (config.strict) {
|
|
config.sockets = Math.max(config.sockets, 360);
|
|
}
|
|
var agentConfig = newAgentConf || {
|
|
maxSockets: config.sockets,
|
|
keepAlive: true,
|
|
keepAliveMsecs: KEEP_ALIVE_MSECS,
|
|
maxFreeSockets: 0
|
|
};
|
|
// node 11及以上版本缓存连接有问题,默认禁掉
|
|
var disableAgent = !newAgentConf && !useAgent;
|
|
config.httpAgent = disableAgent ? false : new HttpAgent(agentConfig);
|
|
config.httpsAgent = disableAgent ? false : new HttpsAgent(agentConfig);
|
|
config.getSocksAgent = function (options) {
|
|
var key = getCacheKey(options, true);
|
|
var agent = socksAgents.get(key);
|
|
if (agent) {
|
|
return agent;
|
|
}
|
|
extend(options, agentConfig);
|
|
options.proxyPort = parseInt(options.proxyPort, 10) || 1080;
|
|
options.rejectUnauthorized = config.rejectUnauthorized;
|
|
options.localDNS = false;
|
|
options.auths = getAuths(options);
|
|
agent = options.isHttps
|
|
? new socks.HttpsAgent(options)
|
|
: new socks.HttpAgent(options);
|
|
socksAgents.set(key, agent);
|
|
agent.on('free', preventThrowOutError);
|
|
return agent;
|
|
};
|
|
var baseDir = config.baseDir
|
|
? path.resolve(common.getHomePath(config.baseDir), config.dataDirname)
|
|
: (config.whistleName ? path.join(ALL_WHISTLES_PATH, config.whistleName) : getDataDir(config.dataDirname));
|
|
var customDirs = path.join(baseDir, 'custom_dirs');
|
|
config.baseDir = baseDir;
|
|
config.storage = config.storage && encodeURIComponent(config.storage);
|
|
if (config.storage) {
|
|
baseDir = path.join(customDirs, config.storage);
|
|
}
|
|
if (config.whistleName) {
|
|
config.CUSTOM_PLUGIN_PATH = path.join(baseDir, 'custom_plugins');
|
|
config.CUSTOM_CERTS_DIR = path.resolve(baseDir, 'custom_certs');
|
|
config.SAVED_SESSIONS_PATH = path.resolve(baseDir, 'saved_sessions');
|
|
fse.ensureDirSync(config.CUSTOM_PLUGIN_PATH);
|
|
fse.ensureDirSync(config.CUSTOM_CERTS_DIR);
|
|
fse.ensureDirSync(config.SAVED_SESSIONS_PATH);
|
|
}
|
|
fse.ensureDirSync(baseDir);
|
|
config.baseDirHash = common.createHash(baseDir);
|
|
if (config.password) {
|
|
config.passwordHash = common.createHash(config.password);
|
|
}
|
|
config.rulesDir = path.join(baseDir, 'rules');
|
|
config.valuesDir = path.join(baseDir, 'values');
|
|
config.propertiesDir = path.join(baseDir, 'properties');
|
|
if (config.storage && newConf.copy) {
|
|
var copyDir =
|
|
typeof newConf.copy == 'string' && encodeURIComponent(newConf.copy);
|
|
if (copyDir !== config.storage) {
|
|
var dataDir = copyDir ? path.join(customDirs, copyDir) : config.baseDir;
|
|
var rulesDir = path.join(dataDir, 'rules');
|
|
var valuesDir = path.join(dataDir, 'values');
|
|
var propsDir = path.join(dataDir, 'properties');
|
|
fse.ensureDirSync(rulesDir);
|
|
fse.ensureDirSync(valuesDir);
|
|
fse.ensureDirSync(propsDir);
|
|
fse.copySync(rulesDir, config.rulesDir);
|
|
fse.copySync(valuesDir, config.valuesDir);
|
|
fse.copySync(propsDir, config.propertiesDir);
|
|
}
|
|
}
|
|
var clientIdFile = path.join(config.baseDir, '.clientid');
|
|
var clientId = readFileText(clientIdFile);
|
|
if (!clientId) {
|
|
clientId = [
|
|
Date.now(),
|
|
Math.random(),
|
|
Math.random(),
|
|
Math.random(),
|
|
Math.random(),
|
|
Math.random()
|
|
].join();
|
|
fs.writeFileSync(clientIdFile, clientId);
|
|
}
|
|
if (config.whistleName) {
|
|
clientId += '/' + config.whistleName;
|
|
}
|
|
config.clientId = clientId;
|
|
config.clientIdNo = common.getStatSync(clientIdFile).ino + '';
|
|
config.setModified = function (clientId, isRules) {
|
|
if (isRules) {
|
|
config.mrulesClientId = clientId || '';
|
|
config.mrulesTime = Date.now();
|
|
} else {
|
|
config.mvaluesClientId = clientId || '';
|
|
config.mvaluesTime = Date.now();
|
|
}
|
|
};
|
|
return config;
|
|
};
|