whistle
Version:
HTTP, HTTPS, Websocket debugging proxy
428 lines (377 loc) • 10.3 kB
JavaScript
var net = require('net');
var http = require('http');
var rules = require('./index');
var util = require('../util');
var config = require('../config');
var Storage = require('./storage');
var rulesStorage = new Storage(config.rulesDir);
var valuesStorage = new Storage(config.valuesDir);
var propertiesStorage = new Storage(config.propertiesDir);
var system = require('./system');
var filter;
function setFilter(text) {
if (!text || typeof text != 'string') {
text = '';
}
text = text.substring(0, 128);
propertiesStorage.setProperty('filterText', text);
filter = util.toRegExp(text) || text;
}
exports.setFilter = setFilter;
setFilter(propertiesStorage.getProperty('filterText'));
exports.filterUrl = function filterUrl(url) {
if (!url) {
return false;
}
if (!filter) {
return true;
}
if (filter.test) {
return filter.test(url);
}
return url.indexOf(filter) != -1;
};
process.nextTick(function() {
parseRules();
});
/**
* rules
*/
function parseHosts(text) {
if (typeof text != 'string'
|| !(text = text.trim())) {
return '';
}
var result = [];
text.split(/\n|\r\n|\r/g)
.forEach(function(line) {
line = line.replace(/#.*$/, '').trim();
if (!line) {
return;
}
line = line.split(/\s+/);
var pattern = line[0];
if (net.isIP(pattern)) {
line.slice(1).forEach(function(matcher) {
!/\//.test(matcher) && result.push(pattern + ' ' + matcher);
});
} else if (!/\//.test(pattern) && line[1] && net.isIP(line[1])) {
result.push(line[1] + ' ' + pattern);
}
});
return result.join('\r\n');
}
function parseRules(defaultRules) {
if (propertiesStorage.getProperty('disabledAllRules')) {
return rules.parse();
}
var value = [];
var hosts = propertiesStorage.getProperty('syncWithSysHosts') ? [] : null;
getAllRulesFile().forEach(function(file) {
if (file.selected) {
value.push(file.data);
if (hosts) {
var sysHosts = parseHosts(file.data);
if (sysHosts) {
hosts.push('#\r\n# ' + file.name + '\r\n#' + '\r\n' + sysHosts);
}
}
}
});
if (typeof defaultRules == 'string') {
setDefaultRules(defaultRules);
value.push(defaultRules);
rulesStorage.setProperty('disabledDefalutRules', false);
} else if (!defaultRulesIsDisabled()) {
defaultRules = getDefaultRules();
value.push(defaultRules);
}
if (hosts && defaultRules) {
var sysHosts = parseHosts(defaultRules);
if (sysHosts) {
hosts.push('#\r\n# Default\r\n#' + '\r\n' + sysHosts);
}
}
rules.parse(value.join('\r\n'));
if (hosts) {
hosts = hosts.join('\r\n\r\n');
system.setHosts(hosts, util.noop);
}
}
exports.parseRules = parseRules;
function setDefaultRules(data) {
data = typeof data != 'string' ? '' : data;
rulesStorage.setProperty('defalutRules', data);
parseRules();
}
function getDefaultRules() {
return rulesStorage.getProperty('defalutRules');
}
function disableDefaultRules() {
rulesStorage.setProperty('disabledDefalutRules', true);
parseRules();
}
function enableDefaultRules() {
rulesStorage.setProperty('disabledDefalutRules', false);
parseRules();
}
function defaultRulesIsDisabled() {
return rulesStorage.getProperty('disabledDefalutRules');
}
function selectRulesFile(file) {
if (!rulesStorage.existsFile(file)) {
return;
}
var selectedList = allowMultipleChoice() ? getSelectedRulesList() : [];
if (selectedList.indexOf(file) == -1) {
selectedList.push(file);
rulesStorage.setProperty('selectedList', selectedList);
}
parseRules();
return selectedList;
}
function unselectRulesFile(file) {
var selectedList;
if (allowMultipleChoice()) {
selectedList = getSelectedRulesList();
var index = selectedList.indexOf(file);
if (index != -1) {
selectedList.splice(index, 1);
rulesStorage.setProperty('selectedList', selectedList);
}
} else {
selectedList = [];
rulesStorage.setProperty('selectedList', selectedList);
}
parseRules();
return selectedList;
}
function allowMultipleChoice() {
return propertiesStorage.getProperty('allowMultipleChoice');
}
function clearSelection() {
rulesStorage.setProperty('selectedList', []);
parseRules();
}
function getSelectedRulesList() {
var selectedList = rulesStorage.getProperty('selectedList');
if (!selectedList) {
selectedList = [];
rulesStorage.setProperty('selectedList', selectedList);
}
return selectedList;
}
function removeRulesFile(file) {
unselectRulesFile(file);
rulesStorage.removeFile(file);
}
function renameRulesFile(file, newFile) {
if (!rulesStorage.renameFile(file, newFile)) {
return;
}
var selectedList = getSelectedRulesList();
var index = selectedList.indexOf(file);
if (index != -1) {
selectedList[index] = newFile;
rulesStorage.setProperty('selectedList', selectedList);
}
}
function addRulesFile(file, data) {
rulesStorage.writeFile(file, data);
}
function getAllRulesFile() {
var list = rulesStorage.getFileList();
var selectedList = getSelectedRulesList();
list.forEach(function(file) {
file.selected = selectedList.indexOf(file.name) != -1;
});
return list;
}
function resetRulesIfSwap(next, prev) {
if (!next || !prev) {
return;
}
var selectedList = getSelectedRulesList();
if (selectedList.indexOf(next) == -1 || selectedList.indexOf(prev) == -1) {
return;
}
parseRules();
}
exports.rules = {
get: function(key) {
var list = rulesStorage.getFileList();
var file = util.findArray(list, function(file) {
if (file.name === key) {
return true;
}
});
return file && file.data;
},
getSysHosts: system.getHosts,
setSysHosts: system.setHosts,
remove: removeRulesFile,
add: addRulesFile,
rename: renameRulesFile,
select: selectRulesFile,
unselect: unselectRulesFile,
list: getAllRulesFile,
getDefault: getDefaultRules,
setDefault: setDefaultRules,
enableDefault: enableDefaultRules,
disableDefault: disableDefaultRules,
defaultRulesIsDisabled: defaultRulesIsDisabled,
parseRules: parseRules,
clearSelection:clearSelection,
getSelectedList: getSelectedRulesList,
moveUp: function(file) {
resetRulesIfSwap(file, rulesStorage.moveUp(file));
},
moveDown: function(file) {
resetRulesIfSwap(file, rulesStorage.moveDown(file));
}
};
/**
* values
*/
function addValuesFile(file, data) {
valuesStorage.writeFile(file, data);
}
exports.values = {
add: addValuesFile,
get: function(file) {
return valuesStorage.readFile(file);
},
remove: function remove(file) {
valuesStorage.removeFile(file);
},
rename: function(file, newFile) {
valuesStorage.renameFile(file, newFile);
},
list: function list() {
var selectedFile = valuesStorage.getProperty('selectedFile');
var list = valuesStorage.getFileList();
if (selectedFile) {
list.forEach(function(file) {
file.selected = file.name == selectedFile;
});
}
return list;
},
select: function(file) {
typeof file == 'string' && valuesStorage.setProperty('selectedFile', file);
},
unselect: function() {
valuesStorage.removeProperty('selectedFile');
},
moveUp: function(file) {
valuesStorage.moveUp(file);
},
moveDown: function(file) {
valuesStorage.moveDown(file);
}
};
setTimeout(function getWhistleVersion() {
http.get(config.registry, function(res) {
res.setEncoding('utf8');
var body = '';
res.on('data', function(data) {
body += data;
});
res.on('error', util.noop);
res.on('end', function() {
var ver = util.parseJSON(body);
ver = ver && ver['dist-tags'];
if (ver = ver && ver['latest']) {
propertiesStorage.setProperty('latestVersion', ver);
}
});
setTimeout(getWhistleVersion, 1000 * 60 * 60 * 12);
}).on('error', util.noop);
}, 1000); //等待package的信息配置更新完成
/**
* properties
*/
exports.properties = {
set: function(name, value) {
typeof name == 'string' ? propertiesStorage.setProperty(name, value) :
propertiesStorage.setProperties(name);
},
remove: function(name) {
propertiesStorage.removeProperty(name);
},
get: function(name) {
return propertiesStorage.getProperty(name);
}
};
function getRules(rules) {
if (Array.isArray(rules)) {
return rules.join('\n');
}
if (typeof rules === 'string') {
return rules;
}
}
exports.addRules = function(rules, replace) {
if (rules == null) {
return;
}
replace = replace !== false;
if (Array.isArray(rules) || typeof rules == 'string') {
if (replace !== false || !getDefaultRules()) {
setDefaultRules(getRules(rules));
}
} else {
Object.keys(rules).forEach(function(name) {
var item = name ? rules[name] : null;
if (Array.isArray(item) || typeof item === 'string') {
item = { rules: item };
}
if (item) {
item.rules = getRules(item.rules);
if (typeof item.replace !== 'boolean') {
item.replace = replace;
}
if (name === 'Default') {
if (typeof item.rules === 'string'
&& (item.replace !== false || !getDefaultRules())) {
setDefaultRules(item.rules);
}
if (item.enable) {
enableDefaultRules();
} else if (item.enable === false) {
disableDefaultRules();
}
} else {
if (typeof item.rules === 'string'
&& (item.replace !== false || !rulesStorage.existsFile(name))) {
addRulesFile(name, item.rules);
}
if (item.enable) {
selectRulesFile(name);
} else if (item.enable === false) {
unselectRulesFile(name);
}
}
}
});
}
};
exports.addValues = function(values, replace) {
if (values == null) {
return;
}
replace = replace !== false;
Object.keys(values).forEach(function(name) {
if (/\s/.test(name) || (!replace && valuesStorage.existsFile(name))) {
return;
}
var value = name ? values[name] : null;
if (value == null) {
return;
}
if (typeof value !== 'string') {
value = JSON.stringify(value, null, ' ');
}
addValuesFile(name, value);
});
};