blinksocks/src/core/config.js

227 lines
6.0 KiB
JavaScript
Raw Normal View History

import dns from 'dns';
2016-12-09 14:54:58 +00:00
import fs from 'fs';
import os from 'os';
import net from 'net';
import {isValidPort} from '../utils';
2017-08-14 09:39:37 +00:00
import {BLINKSOCKS_DIR, LOG_DIR, DEFAULT_LOG_LEVEL} from './constants';
import {DNS_DEFAULT_EXPIRE} from './dns-cache';
2016-12-09 14:54:58 +00:00
/**
* make directory if not exist
* @param dir
*/
function mkdir(dir) {
try {
fs.lstatSync(dir);
} catch (err) {
if (err.code === 'ENOENT') {
fs.mkdirSync(dir);
}
}
}
// create ~/.blinksocks directory
mkdir(BLINKSOCKS_DIR);
// create ~/.blinksocks/logs directory
mkdir(LOG_DIR);
2016-12-09 14:54:58 +00:00
export class Config {
static validate(json) {
2016-12-09 14:54:58 +00:00
if (typeof json !== 'object' || Array.isArray(json)) {
throw Error('Invalid configuration file');
}
// host
2016-12-09 14:54:58 +00:00
if (typeof json.host !== 'string' || json.host === '') {
throw Error('\'host\' must be provided and is not empty');
}
// port
if (!isValidPort(json.port)) {
throw Error('\'port\' is invalid');
2016-12-09 14:54:58 +00:00
}
// servers
if (typeof json.servers !== 'undefined') {
if (!Array.isArray(json.servers)) {
2017-03-24 09:09:37 +00:00
throw Error('\'servers\' must be provided as an array');
2016-12-09 14:54:58 +00:00
}
2017-04-16 09:38:57 +00:00
const servers = json.servers.filter((server) => server.enabled === true);
if (servers.length < 1) {
throw Error('\'servers\' must have at least one enabled item');
2016-12-09 14:54:58 +00:00
}
servers.forEach(this.validateServer);
} else {
this.validateServer(json);
}
if (typeof json.dns !== 'undefined') {
if (!Array.isArray(json.dns)) {
throw Error('\'dns\' must be an array');
}
for (const ip of json.dns) {
if (!net.isIP(ip)) {
throw Error(`"${ip}" is not an ip address`);
}
}
}
// redirect
2017-03-29 08:30:10 +00:00
if (typeof json.redirect === 'string' && json.redirect !== '') {
const address = json.redirect.split(':');
if (address.length !== 2 || !isValidPort(+address[1])) {
throw Error('\'redirect\' is an invalid address');
}
}
// timeout
if (typeof json.timeout !== 'number') {
throw Error('\'timeout\' must be a number');
}
if (json.timeout < 1) {
throw Error('\'timeout\' must be greater than 0');
}
if (json.timeout < 60) {
console.warn(`==> [config] 'timeout' is too short, is ${json.timeout}s expected?`);
}
// workers
if (typeof json.workers !== 'undefined') {
if (typeof json.workers !== 'number') {
throw Error('\'workers\' must be a number');
}
if (json.workers < 0) {
throw Error('\'workers\' must be an integer');
}
if (json.workers > os.cpus().length) {
console.warn(`==> [config] 'workers' is greater than the number of cpus, is ${json.workers} workers expected?`);
}
}
// dns_expire
if (typeof json.dns_expire !== 'undefined') {
if (typeof json.dns_expire !== 'number') {
throw Error('\'dns_expire\' must be a number');
}
if (json.dns_expire < 0) {
throw Error('\'dns_expire\' must be greater or equal to 0');
}
if (json.dns_expire > 24 * 60 * 60) {
console.warn(`==> [config] 'dns_expire' is too long, is ${json.dns_expire}s expected?`);
}
}
2016-12-09 14:54:58 +00:00
}
static validateServer(server) {
2017-04-20 09:20:42 +00:00
// transport
if (typeof server.transport !== 'string') {
throw Error('\'server.transport\' must be a string');
}
if (!['tcp', 'udp'].includes(server.transport.toLowerCase())) {
throw Error('\'server.transport\' must be one of "tcp" or "udp"');
}
// host
if (typeof server.host !== 'string' || server.host === '') {
throw Error('\'server.host\' must be provided and is not empty');
}
// port
if (!isValidPort(server.port)) {
2017-04-20 09:20:42 +00:00
throw Error('\'server.port\' is invalid');
}
// key
if (typeof server.key !== 'string') {
2017-04-20 09:20:42 +00:00
throw Error('\'server.key\' must be a string');
}
if (server.key === '') {
2017-04-20 09:20:42 +00:00
throw Error('\'server.key\' cannot be empty');
}
// presets
if (!Array.isArray(server.presets)) {
2017-04-20 09:20:42 +00:00
throw Error('\'server.presets\' must be an array');
}
if (server.presets.length < 1) {
2017-04-20 09:20:42 +00:00
throw Error('\'server.presets\' must contain at least one preset');
}
// presets[].parameters
for (const preset of server.presets) {
const {name, params} = preset;
if (typeof name === 'undefined') {
2017-04-20 09:20:42 +00:00
throw Error('\'server.presets[].name\' must be a string');
}
if (name === '') {
2017-04-20 09:20:42 +00:00
throw Error('\'server.presets[].name\' cannot be empty');
}
if (typeof params !== 'undefined') {
if (typeof params !== 'object' || params === null) {
throw Error('\'server.presets[].params\' must be an object and not null');
}
}
// 1. check for the existence of the preset
const ps = require(`../presets/${preset.name}`).default;
2017-08-10 14:07:15 +00:00
// 2. check parameters
delete new ps(params || {});
}
}
static init(json) {
this.validate(json);
global.__LOCAL_HOST__ = json.host;
global.__LOCAL_PORT__ = json.port;
if (typeof json.servers !== 'undefined') {
global.__SERVERS__ = json.servers.filter((server) => server.enabled);
global.__IS_CLIENT__ = true;
} else {
global.__IS_CLIENT__ = false;
this.initServer(json);
}
global.__IS_SERVER__ = !global.__IS_CLIENT__;
global.__REDIRECT__ = json.redirect;
global.__TIMEOUT__ = json.timeout * 1e3;
2017-08-14 09:39:37 +00:00
global.__WORKERS__ = (json.workers !== undefined) ? json.workers : 0;
2017-06-10 08:23:03 +00:00
global.__LOG_LEVEL__ = json.log_level || DEFAULT_LOG_LEVEL;
global.__DNS_EXPIRE__ = (json.dns_expire !== undefined) ? json.dns_expire * 1e3 : DNS_DEFAULT_EXPIRE;
global.__ALL_CONFIG__ = json;
if (typeof json.dns !== 'undefined' && json.dns.length > 0) {
global.__DNS__ = json.dns;
dns.setServers(json.dns);
}
}
static initServer(server) {
this.validateServer(server);
global.__TRANSPORT__ = server.transport;
global.__SERVER_HOST__ = server.host;
global.__SERVER_PORT__ = server.port;
global.__KEY__ = server.key;
global.__PRESETS__ = server.presets;
2016-12-09 14:54:58 +00:00
}
}