lib/ts/server.ts
"use strict";
/**
* Import interfaces
*/
import IWindow from "../../interfaces/IWindow";
/**
* Declare window interface
*/
declare let window: IWindow;
declare let global: any;
declare let require: any;
declare let Buffer: any;
global.Promise = global.Promise || require("promise-polyfill");
global.location = global.location || {};
const ZLIB = require("zlib");
const CRYPTO = require("webcrypto");
const MD5 = require("crypto-js/md5");
const AES = require("crypto-js/aes");
const UTF8 = require("crypto-js/enc-utf8");
const FS = require("fs");
const HTTP = require("http");
HTTP.globalAgent.keepAlive = true;
HTTP.globalAgent.keepAliveMsecs = 5000;
HTTP.globalAgent.maxSockets = Infinity;
HTTP.globalAgent.maxFreeSockets = 1000;
const HTTPS = require("https");
HTTPS.globalAgent.keepAlive = true;
HTTPS.globalAgent.keepAliveMsecs = 5000;
HTTPS.globalAgent.maxSockets = Infinity;
HTTPS.globalAgent.maxFreeSockets = 1000;
const URL = require("url");
const DNS = require("dns");
const PATH = require("path");
const baseHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, OPTIONS, PUT, PATCH, DELETE",
"Access-Control-Allow-Headers": "X-Requested-With, Accept-Encoding, content-type",
"Access-Control-Allow-Credentials": true,
};
import Transport from "./transport";
export default class Server extends Transport {
/**
* Get choice ID
* @param choiceType
* @param choices
*/
public static getChoiceID(choiceType: string, choices: any): string {
const keys = Object.keys(choices[choiceType]);
return keys[keys.length * Math.random() << 0];
}
public listners: any;
public proxyShit: any;
public defaultSettings: any;
private AcceptEncoding: string;
public constructor(settings: any = {}) {
super(settings);
this.Settings = Transport.combineSettings(this.Settings, this.defaultSettings);
this.proxyShit = {};
this.listners = {
download: this.download.bind(this),
};
this.on("debug", (data, params) => {
return new Promise((resolve) => {
resolve(JSON.stringify({data, params}));
});
});
if (!this.Settings.WithoutHttpServer) {
if (
this.Settings.ServerType === "https" &&
this.Settings.HTTPSKeyPath &&
this.Settings.HTTPSCertPath
) {
HTTPS.createServer({
cert: FS.readFileSync(this.Settings.HTTPSCertPath),
key: FS.readFileSync(this.Settings.HTTPSKeyPath),
}, this.listenr.bind(this)).listen(this.Settings.ServerPort);
} else {
HTTP.createServer(this.listenr.bind(this)).listen(this.Settings.ServerPort);
}
}
}
public on(event: string, listner: any) {
this.listners[event] = listner;
}
public listenr(request, response) {
this.AcceptEncoding = request.headers["accept-encoding"] || "";
const headers = Object.assign({}, baseHeaders);
setTimeout(
() => {
this.responceError("0.0.1", request, response, headers);
},
this.Settings.ConnectionTimeout,
);
try {
request.on("error", (_err) => {
this.responceError("0.0.2", request, response, headers, _err);
});
response.on("error", (_err) => {
this.responceError("0.0.3", request, response, headers, _err);
});
if (
request.method === "OPTIONS"
) {
if (request.headers["access-control-request-headers"]) {
if (headers["Access-Control-Allow-Headers"]) {
headers["Access-Control-Allow-Headers"] = headers["Access-Control-Allow-Headers"].split(", ").concat(request.headers["access-control-request-headers"].split(", ")).join(", ");
} else {
headers["Access-Control-Allow-Headers"] = request.headers["access-control-request-headers"];
}
}
if (!response.answered) {
response.answered = true;
response.writeHead(this.Settings.SuccessResponseCode, headers);
response.end();
}
} else {
this.preprocessor(request).then(
(result: any) => {
if (result.indexOf("debug") !== -1) {
const debug = {
headers: request.headers,
rawurl: request.url,
url: URL.parse(request.url, true),
result,
};
if (!response.answered) {
response.answered = true;
response.writeHead(this.Settings.SuccessResponseCode, headers);
response.end(JSON.stringify(debug));
}
} else {
let IP = request.headers["x-real-ip"];
if (!IP) {
const regIP = /([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/i;
const resIP = (regIP).exec(request.connection.remoteAddress);
if (resIP) {
IP = resIP[0];
}
}
if (
!IP ||
IP === "127.0.0.1"
) {
IP = "95.165.148.52";
}
const params = {
Headers: request.headers,
IP,
};
this.processor(result, params, request, headers).then(
(_result: any) => {
headers["Access-Control-Allow-Origin"] = "*";
if (
_result.Params.Host
) {
if (_result.Params.Action === "Respond") {
this.Respond(_result, headers, request, response);
} else if (_result.Params.Action === "Redirect") {
this.Redirect(_result, headers, request, response);
} else if (_result.Params.Action === "Proxy") {
this.Proxy(_result, headers, request, response);
} else {
this.responceError("0.0.4", request, response, headers, new Error("Unsupported action"), {
result,
params,
headers,
});
}
} else {
this.responceError("0.0.5", request, response, headers, new Error("Host does not exist"), {
result,
params,
headers,
});
}
},
).catch(
(e) => {
if (request.url.indexOf(".map") !== -1) {
this.responceError("0.0.6", request, response, headers);
} else {
this.responceError("0.0.7", request, response, headers, e, {
result,
params,
headers,
});
}
},
);
}
},
).catch(
(e) => {
this.responceError("0.0.8", request, response, headers, e);
},
);
}
} catch (e) {
this.responceError("0.0.9", request, response, headers, e);
}
}
public Proxy(result, headers, request, response, depth = 5) {
try {
if (
this.Settings.XAccelRedirect &&
result.Data.link.indexOf(".css") === -1
) {
if (!response.answered) {
response.answered = true;
headers["X-Accel-Redirect"] = this.Settings.XAccelRedirect;
headers["X-Get-Url"] = result.Data.link;
response.writeHead(this.Settings.SuccessResponseCode, headers);
response.end();
}
} else {
let CacheID;
let CachePathBody;
let CachePathHeaders;
if (this.Settings.ProxyCachePath) {
CacheID = MD5(result.Data.link).toString();
CachePathBody = PATH.resolve(this.Settings.ProxyCachePath, CacheID + ".body");
CachePathHeaders = PATH.resolve(this.Settings.ProxyCachePath, CacheID + ".headers");
}
const redirectProxy = () => {
if (
result.Data.link.indexOf(".css") === -1 &&
result.Data.link.indexOf("yandex") === -1
) {
this.proxyShit[result.Data.link] = true;
}
const doRedirect = () => {
if (!response.answered) {
response.answered = true;
headers["Location"] = result.Data.link;
response.writeHead(this.Settings.RedirectResponseCode, headers);
response.end();
}
};
if (this.Settings.ProxyCachePath) {
FS.stat(
CachePathBody,
(err) => {
if (err) {
doRedirect();
} else {
if (!response.answered) {
response.answered = true;
response.writeHead(this.Settings.SuccessResponseCode, headers);
FS.readFile(CachePathHeaders, "utf-8", (e, _headers) => {
try {
if (e) {
doRedirect();
} else {
response.writeHead(this.Settings.SuccessResponseCode, JSON.parse(_headers));
FS.createReadStream(CachePathBody).pipe(response);
}
} catch (_e) {
doRedirect();
}
});
}
}
},
);
} else {
doRedirect();
}
};
try {
const doProxy = () => {
if (this.proxyShit[result.Data.link]) {
redirectProxy();
} else {
const url = URL.parse(result.Data.link);
url.port = url.port || url.protocol === "https:" ? 443 : 80;
request.headers.host = url.host;
if (result.Data.link.indexOf(".css") !== -1) {
request.headers["accept-encoding"] = "";
request.headers["cache-control"] = "no-cache";
request.headers["pragma"] = "no-cache";
delete request.headers["if-modified-since"];
delete request.headers["if-none-match"];
}
const options: any = {
headers: request.headers,
hostname: url.host,
method: "GET",
path: url.path,
port: url.port,
};
if (!this.Settings.StrictSSL) {
options.rejectUnauthorized = false;
options.strictSSL = false;
options.secureProtocol = "TLSv1_method";
}
DNS.lookup(
options.hostname,
(err) => {
if (err) {
redirectProxy();
this.ErrorHandler(err, "0.1.1", options);
} else {
let proxyConnectionTimeout;
const req = (options.port === 443 ? HTTPS : HTTP).request(options, (res) => {
clearTimeout(proxyConnectionTimeout);
res.on("error", (_err) => {
redirectProxy();
this.ErrorHandler(_err, "0.1.2", options);
});
if (res.statusCode === 200) {
if (
this.Settings.MaxProxySize &&
res.headers["content-length"] &&
parseInt(res.headers["content-length"], 10) > this.Settings.MaxProxySize &&
result.Data.link.indexOf(".css") === -1 &&
result.Data.link.indexOf("yandex") === -1
) {
req.abort();
redirectProxy();
this.ErrorHandler(new Error("Too big file"), "0.1.3", options);
} else {
if (!response.answered) {
if (res.headers["content-type"].indexOf("text/css") !== -1) {
const buffer = [];
res.on("data", (chunk) => {
buffer.push(chunk);
});
res.on("end", () => {
if (!response.answered) {
response.answered = true;
const _headers = res.headers;
for (const prop in headers) {
if (headers.hasOwnProperty(prop)) {
delete _headers[prop.toLowerCase()];
_headers[prop] = headers[prop];
}
}
const newCss = this.replaceRelativePathInCss(result.Data.link, Buffer.concat(buffer).toString("utf-8"));
_headers["content-length"] = newCss.length;
_headers["cache-control"] = "no-cache";
delete _headers["etag"];
delete _headers["expires"];
delete _headers["last-modified"];
delete _headers["content-length"];
this.prepareRespond(newCss, _headers).then((_result: any) => {
if (this.Settings.ProxyCachePath) {
FS.writeFile(CachePathBody, _result.data);
FS.writeFile(CachePathHeaders, JSON.stringify(_result.headers));
}
response.writeHead(this.Settings.SuccessResponseCode, _result.headers);
response.end(_result.data);
}).catch(() => {
if (this.Settings.ProxyCachePath) {
FS.writeFile(CachePathBody, newCss);
FS.writeFile(CachePathHeaders, JSON.stringify(_headers));
}
response.writeHead(this.Settings.SuccessResponseCode, _headers);
response.end(newCss);
});
}
});
} else {
const _headers = res.headers;
for (const prop in headers) {
if (headers.hasOwnProperty(prop)) {
delete _headers[prop.toLowerCase()];
_headers[prop] = headers[prop];
}
}
delete _headers["content-length"];
response.answered = true;
response.writeHead(this.Settings.SuccessResponseCode, _headers);
if (this.Settings.ProxyCachePath) {
res.pipe(FS.createWriteStream(CachePathBody));
FS.writeFile(CachePathHeaders, JSON.stringify(_headers));
}
res.pipe(response);
}
}
}
} else if (
(
res.statusCode === 301 ||
res.statusCode === 302
) &&
res.headers.location &&
depth > 0
) {
result.Data.link = res.headers.location;
this.Proxy(result, headers, request, response, --depth);
} else {
req.abort();
redirectProxy();
this.ErrorHandler(new Error("Non 200 status code"), "0.1.4", {
status: res.statusCode,
headers: res.headers,
options,
});
}
});
proxyConnectionTimeout = setTimeout(
() => {
req.abort();
redirectProxy();
this.ErrorHandler(new Error("Proxy request timeout"), "0.1.5", options);
},
this.Settings.ProxyTimeout,
);
req.on("error", (_err) => {
req.abort();
redirectProxy();
this.ErrorHandler(_err, "0.1.6", options);
});
req.end();
}
},
);
}
};
if (this.Settings.ProxyCachePath) {
FS.stat(
CachePathBody,
(err, stat) => {
if (err) {
doProxy();
} else {
if ((new Date()) - this.Settings.ProxyCacheTimeout < stat.birthtime * 1) {
if (!response.answered) {
response.answered = true;
FS.readFile(CachePathHeaders, "utf-8", (e, _headers) => {
try {
if (e) {
redirectProxy();
this.ErrorHandler(e, "0.1.7", result);
} else {
response.writeHead(this.Settings.SuccessResponseCode, JSON.parse(_headers));
FS.createReadStream(CachePathBody).pipe(response);
}
} catch (_e) {
redirectProxy();
this.ErrorHandler(_e, "0.1.7", result);
}
});
}
} else {
doProxy();
}
}
},
);
} else {
doProxy();
}
} catch (e) {
redirectProxy();
this.ErrorHandler(e, "0.1.8", result);
}
}
} catch (e) {
this.responceError("0.1.9", request, response, headers, e, {
result,
});
}
}
public Redirect(result, headers, request, response) {
try {
headers["Location"] = result.Data.link;
if (!response.answered) {
response.answered = true;
response.writeHead(this.Settings.RedirectResponseCode, headers);
response.end();
}
} catch (e) {
this.responceError("0.2.1", request, response, headers, e, {
result,
});
}
}
public Respond(result, headers, request, response) {
try {
headers["Cache-Control"] = "no-cache";
let resp = "";
switch (result.Params.Transport) {
case "style":
resp = `.${result.Params.Callback} {content:"${result.Data}";}`;
headers["Content-Type"] = "text/css; charset=utf-8";
break;
case "styleextend":
const baseStylesExtend = [
"width:{d}px;",
"height:{d}px;",
"top:{d}px;",
"left:{d}px;",
"bottom:{d}px;",
"right:{d}px;",
];
const l2 = Math.floor(result.Params.Callback.length / 2);
const translation = Transport.stringChunks(result.Params.Callback, Math.ceil(result.Params.Callback.length / l2), l2).reduce((s, v, i) => {
if (i === 0) {
s["="] = v;
} else if (i === 1) {
s["+"] = v;
}
return s;
}, {});
const length = this.Settings.Transports.styleextend.Params.PartLength;
Transport.stringChunks(result.Data, Math.ceil(result.Data.length / length), length).forEach((data) => {
data = data.replace(/(=|\+)/igm, (v) => translation[v]);
resp += ` .${data} {`;
baseStylesExtend.forEach((v: any) => {
if (Math.random() > 0.5) {
resp += v.replace("{d}", Math.round(Math.random() * length).toString());
}
}, "");
resp += `}`;
});
headers["Content-Type"] = "text/css; charset=utf-8";
break;
case "styleadvanced":
const toD = (s) => s.charCodeAt();
const toH = (s) => {
s = toD(s).toString(16);
return s.length === 1 ? "0" + s : s;
};
const calc = (s) => {
return s.match(/\{[d-h]\}/g).length / (s.replace(/\{d\}/ig, 999).replace(/\{h\}/ig, "FF")).length;
};
const baseStylesAdvanced = [
"width:{d}px;",
"height:{d}px;",
"top:{d}px;",
"left:{d}px;",
"bottom:{d}px;",
"right:{d}px;",
"padding:{d}px {d}px {d}px {d}px;",
"margin:{d}px {d}px {d}px {d}px;",
"color:#{h}{h}{h};",
"background:#{h}{h}{h};",
].sort((a, b) => calc(b) - calc(a));
let styles = [];
result.Data = result.Data.split("");
const l = result.Data.length;
for (let i = 0; i < l;) {
if (styles.length === 0) {
styles = baseStylesAdvanced.join(",").split(",");
resp += `.${result.Params.Callback}_${Server.getRandomWord()}{`;
}
const style = styles.shift();
if (i + style.match(/\{(d|h)\}/g).length <= l) {
resp += style.replace(/\{(d|h)\}/g, (v) => (v === "{d}" ? toD(result.Data[i++]) : toH(result.Data[i++])));
}
if (styles.length === 0) {
resp += `}`;
}
}
headers["Content-Type"] = "text/css; charset=utf-8";
break;
case "script":
resp = 'window["' + result.Params.Callback + '"]("' + result.Data + '")';
headers["Content-Type"] = "text/javascript; charset=utf-8";
break;
case "iframe":
resp = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>${result.Params.Callback}</title>
</head>
<body>
<script type="text/javascript">
var timer = setInterval(
function(){
try{
if(parent &&parent.postMessage){
parent.postMessage("${result.Data}","${headers["Access-Control-Allow-Origin"]}");
clearTimeout(timer);
}
}catch(e){}
},
100
);
</script>
</body>
</html>`;
headers["Content-Type"] = "text/html; charset=utf-8";
break;
case "xhr":
case "fetch":
resp = result.Data;
headers["Content-Type"] = "text/plain; charset=utf-8";
break;
default:
this.responceError("0.3.1", request, response, headers, new Error("Unsupported transport"));
}
if (resp) {
this.prepareRespond(resp, headers).then((_result: any) => {
if (!response.answered) {
response.answered = true;
response.writeHead(this.Settings.SuccessResponseCode, _result.headers);
response.end(_result.data);
}
}).catch(() => {
if (!response.answered) {
response.answered = true;
response.writeHead(this.Settings.SuccessResponseCode, headers);
response.end(resp);
}
});
} else {
this.responceError("0.3.3", request, response, headers);
}
} catch (e) {
this.responceError("0.3.4", request, response, headers, e, {
result,
});
}
}
public responceError(id, request, response, headers, e?, ...data) {
this.ErrorHandler(e, id, data);
if (request.headers["x-real-404"]) {
const url = URL.parse(request.headers["x-real-404"]);
request.headers.host = url.host;
const options: any = {
headers: request.headers,
hostname: url.host,
method: "GET",
path: url.path,
port: "80",
};
if (!this.Settings.StrictSSL) {
options.rejectUnauthorized = false;
options.strictSSL = false;
options.secureProtocol = "TLSv1_method";
}
HTTP.request(options, (res) => {
if (!response.answered) {
response.answered = true;
response.writeHead(this.Settings.SuccessResponseCode, headers);
res.pipe(response);
}
}).end();
} else {
if (!response.answered) {
response.answered = true;
response.writeHead(this.Settings.ErrorResponseCode, headers);
response.end();
}
}
}
public processor(data, params, request, headers) {
return new Promise((resolve, reject) => {
this.decode(data, this.Settings.Password).then(
(_data: any) => {
if (
_data &&
_data.data &&
_data.data.Action
) {
if (_data.data.Transport) {
params.Transport = _data.data.Transport;
delete _data.data.Transport;
}
if (_data.data.Callback) {
params.Callback = _data.data.Callback;
delete _data.data.Callback;
}
if (_data.data.Action) {
params.Action = _data.data.Action;
delete _data.data.Action;
}
if (_data.data.Url) {
params.Url = _data.data.Url;
delete _data.data.Url;
}
if (_data.data.Refferer) {
params.Refferer = _data.data.Refferer;
delete _data.data.Refferer;
}
if (_data.data.Protocol) {
params.Protocol = _data.data.Protocol;
delete _data.data.Protocol;
}
params.Protocol = params.Protocol || "http:";
params.Hosts = [];
if (_data.data.Host) {
params.Hosts.push(params.Host);
delete _data.data.Host;
}
params.Hosts.push(this.getHostFromHeaderXRealHost(request, params));
params.Hosts.push(this.getHostFromHeaderOrigin(request, params));
params.Hosts.push(this.getHostFromParamsReferer(request, params));
params.Hosts.push(this.getHostFromHeaderReferer(request, params));
params.Hosts.push(this.getHostFromHeaderHost(request, params));
params.Hosts = params.Hosts.filter((value) => {
return !!value;
});
if (params.Hosts.length > 0) {
params.Host = params.Hosts[0];
}
if (params.Action === "Respond") {
if (
this.listners[_data.event] &&
this.Settings.Transports[params.Transport]
) {
new Promise(
(_resolve) => {
_resolve(this.listners[_data.event](_data.data, params, request));
},
).then(
(result) => {
this.encode(result, this.Settings.Password).then(
(__data) => {
resolve({
Data: __data,
Params: params,
});
},
).catch(reject);
},
).catch(reject);
} else {
reject(new Error("Transport undefined or unsupported or listener unexist"));
}
} else if (params.Action === "Redirect") {
if (
this.listners["redirect"]
) {
new Promise(
(_resolve) => {
_resolve(this.listners["redirect"](_data, params));
},
).then(
() => {
resolve({
Data: _data,
Params: params,
});
},
).catch(reject);
} else {
resolve({
Data: _data,
Params: params,
});
}
} else if (params.Action === "Proxy") {
if (
this.listners["proxy"]
) {
new Promise(
(_resolve) => {
_resolve(this.listners["proxy"](_data, params));
},
).then(
() => {
resolve({
Data: _data,
Params: params,
});
},
).catch(reject);
} else {
resolve({
Data: _data,
Params: params,
});
}
} else {
reject(new Error("Action unsupported"));
}
} else {
reject(new Error("Invalid data"));
}
},
).catch(reject);
});
}
public preprocessor(request) {
return new Promise((resolve, reject) => {
const data = [];
/**
* Get data from url
*/
const params = URL.parse(request.url, true);
/**
* Get data from path
*/
const path = PATH.parse(params.pathname);
if (
params.pathname.lastIndexOf("/") === params.pathname.length - 1
) {
path.dir = path.dir + "/" + path.name + "/";
path.name = "";
}
/**
* Get data from path
*/
path.dir.split("/").forEach((item) => {
if (
!this.Settings.IgnoredRequestPaths[item]
) {
data.push(decodeURIComponent(item));
}
});
/**
* Get data from name
*/
if (
!this.Settings.IgnoredNames[path.name]
) {
data.push(decodeURIComponent(path.name));
}
/**
* Get data from params
*/
data.concat(Object.keys(params.query).forEach((key) => {
if (
!this.Settings.IgnoredQueryParams[key]
) {
data.push(params.query[key]);
}
}));
/**
* Get data from headers
*/
Object.keys(request.headers).filter((key) => {
return (
!this.Settings.IgnoredRequestHeaders[key] &&
key.indexOf("-") === -1
);
}).sort().forEach((key) => {
data.push(decodeURIComponent(request.headers[key]));
});
/**
* Get data from body
*/
const buffer = [];
request.on("data", (chunk) => {
buffer.push(chunk);
});
request.on("end", () => {
data.push(Buffer.concat(buffer).toString("utf-8"));
resolve(data.join(""));
});
request.on("error", (err) => {
reject(err);
});
});
}
public download(data, headers, request, depth = 3) {
return new Promise((resolve, reject) => {
const url = URL.parse(data.link);
url.port = url.port || url.protocol === "https:" ? 443 : 80;
request.headers.host = url.host;
request.headers["accept-encoding"] = "";
const options: any = {
headers: request.headers,
hostname: url.host,
method: "GET",
path: url.path,
port: url.port,
};
if (!this.Settings.StrictSSL) {
options.rejectUnauthorized = false;
options.strictSSL = false;
options.secureProtocol = "TLSv1_method";
}
DNS.lookup(
options.hostname,
(err) => {
if (err) {
reject(err);
} else {
const req = (options.port === 443 ? HTTPS : HTTP).request(options, (res) => {
res.on("error", (_err) => {
reject(_err);
});
if (res.statusCode === 200) {
const buffer = [];
res.on("data", (chunk) => {
buffer.push(chunk);
});
res.on("end", () => {
resolve(Buffer.concat(buffer).toString("utf-8"));
});
} else if (
res.statusCode === 301 &&
res.headers.location &&
depth > 0
) {
data.link = res.headers.location;
this.download(data, headers, request, --depth).then(resolve).catch(reject);
} else {
req.abort();
reject(new Error("Non 200 status code"));
}
});
req.on("error", (_err) => {
req.abort();
reject(_err);
});
req.end();
}
},
);
});
}
/**
* Decode data asynchronously
* @param data
* @param password
*/
public decode(data: any, password: string) {
return new Promise((resolve, reject) => {
const _data = this.decodeSync(data, password);
if (_data) {
resolve(_data);
} else {
reject(new Error("Decode failed"));
}
});
}
/**
* Encode data object asynchronously
* @param data
* @param password
*/
public encode(data: any, password: string) {
return new Promise((resolve, reject) => {
const _data = this.encodeSync(data, password);
if (_data) {
resolve(_data);
} else {
reject(new Error("Encode failed"));
}
});
}
/**
* Decode data synchronously
* @param data
* @param password
*/
public decodeSync(data: any, password: string) {
try {
let dec = decodeURIComponent(global.escape(Buffer.from(data, "base64").toString("utf8"))).split("@");
dec.shift();
dec = JSON.parse(dec.join("@"));
this.cryptoModule = "base64salt";
return dec;
} catch (e) {
// TODO: add logger
}
try {
const dec = JSON.parse(decodeURIComponent(global.escape(Buffer.from(data, "base64").toString("utf8"))));
this.cryptoModule = "base64+";
return dec;
} catch (e) {
// TODO: add logger
}
try {
const dec = JSON.parse(Buffer.from(data, "base64").toString("utf8"));
this.cryptoModule = "base64";
return dec;
} catch (e) {
// TODO: add logger
}
try {
const decipher = CRYPTO.createDecipher("aes-256-ctr", password);
let dec = decipher.update(data, "hex", "utf8");
dec += decipher.final("utf8");
dec = JSON.parse(dec);
this.cryptoModule = "webcrypto";
return dec;
} catch (e) {
// TODO: add logger
}
try {
const dec = JSON.parse(AES.decrypt(data, password).toString(UTF8)) || false;
this.cryptoModule = "cryptojs";
return dec;
} catch (e) {
/**
* TODO: add logger
*/
}
return false;
}
/**
* Encode data object synchronously
* @param data
* @param password
*/
public encodeSync(data: any, password: string) {
if (
this.cryptoModule === "" ||
this.cryptoModule === "base64salt"
) {
try {
return Buffer.from(global.unescape(encodeURIComponent((Math.random() * 1e8).toString(36) + "@" + JSON.stringify(data)))).toString("base64");
} catch (e) {
// TODO: add logger
}
}
if (
this.cryptoModule === "" ||
this.cryptoModule === "base64+"
) {
try {
return Buffer.from(global.unescape(encodeURIComponent(JSON.stringify(data)))).toString("base64");
} catch (e) {
// TODO: add logger
}
}
if (
this.cryptoModule === "" ||
this.cryptoModule === "base64"
) {
try {
return Buffer.from(JSON.stringify(data)).toString("base64");
} catch (e) {
// TODO: add logger
}
}
if (
this.cryptoModule === "" ||
this.cryptoModule === "webcrypto"
) {
try {
const cipher = CRYPTO.createCipher("aes-256-ctr", password);
let crypted = cipher.update(JSON.stringify(data), "utf8", "hex");
crypted += cipher.final("hex");
return crypted;
} catch (e) {
// TODO: add logger
}
}
if (
this.cryptoModule === "" ||
this.cryptoModule === "cryptojs"
) {
try {
data = AES.encrypt(JSON.stringify(data), password).toString();
return data;
} catch (e) {
// TODO: add logger
}
}
return null;
}
public getHostFromHeaderXRealHost(request, params) {
if (request.headers["x-real-host"]) {
let origin;
if (request.headers["x-real-host"].indexOf("http") === -1) {
origin = URL.parse(params.Protocol + "//" + request.headers["x-real-host"]);
} else {
origin = URL.parse(request.headers["x-real-host"]);
}
if (
origin &&
origin.hostname
) {
return origin.hostname;
}
}
}
public getHostFromHeaderOrigin(request, params) {
if (request.headers.origin) {
let origin;
if (request.headers.origin.indexOf("http") === -1) {
origin = URL.parse(params.Protocol + "//" + request.headers.origin);
} else {
origin = URL.parse(request.headers.origin);
}
if (
origin &&
origin.hostname
) {
return origin.hostname;
}
}
}
public getHostFromHeaderReferer(request, params) {
if (request.headers.referer) {
let origin;
if (request.headers.referer.indexOf("http") === -1) {
origin = URL.parse(params.Protocol + "//" + request.headers.referer);
} else {
origin = URL.parse(request.headers.referer);
}
if (
origin &&
origin.hostname
) {
return origin.hostname;
}
}
}
public getHostFromParamsReferer(request, params) {
if (params.Refferer) {
let origin;
if (params.Refferer.indexOf("http") === -1) {
origin = URL.parse(params.Protocol + "//" + params.Refferer);
} else {
origin = URL.parse(params.Refferer);
}
if (
origin &&
origin.hostname
) {
return origin.hostname;
}
}
}
public getHostFromHeaderHost(request, params) {
if (request.headers.host) {
let origin;
if (request.headers.host.indexOf("http") === -1) {
origin = URL.parse(params.Protocol + "//" + request.headers.host);
} else {
origin = URL.parse(request.headers.host);
}
if (
origin &&
origin.hostname
) {
return origin.hostname;
}
}
}
public ErrorHandler(e, id, data) {
if (
e &&
typeof this.Settings.ErrorHandler === "function"
) {
this.Settings.ErrorHandler(e, id, data);
}
}
private replaceRelativePathInCss(base, css) {
let regexp = /url\((['"]?)(?!(data|http))([^'")]+)(['"]?)\)/igm;
(css.match(regexp) || []).map((url) => {
url = regexp.exec(url) || regexp.exec(url);
css = css.replace(url[0], `url("${URL.resolve(base, url[3])}")`);
});
return css;
}
private prepareRespond(data, headers) {
return new Promise((resolve) => {
if (this.Settings.GZIP) {
if (this.AcceptEncoding.indexOf("gzip") !== -1) {
ZLIB.gzip(data, (error, result) => {
if (!error) {
data = result;
headers["Content-Encoding"] = "gzip";
}
resolve({data, headers});
});
} else if (this.AcceptEncoding.indexOf("deflate") !== -1) {
ZLIB.deflate(data, (error, result) => {
if (!error) {
data = result;
headers["Content-Encoding"] = "deflate";
}
resolve({data, headers});
});
} else {
resolve({data, headers});
}
} else {
resolve({data, headers});
}
});
}
}