Add http tunnel client implements
This commit is contained in:
parent
c68968022e
commit
1c5468bbe8
132
.gitignore
vendored
132
.gitignore
vendored
@ -1,132 +1,2 @@
|
||||
# ---> Node
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
npm-debug.log
|
@ -1,2 +1,6 @@
|
||||
# http-tunnel-client
|
||||
# HTTP Tunnel Client
|
||||
A lightweight http tunnel client using nodejs.
|
||||
|
||||
### Contributors
|
||||
- Original [web-tunnel](https://github.com/web-tunnel/lite-http-tunnel-client)
|
||||
- Sambo Chea <sombochea@cubetiqs.com>
|
3
bin/http-tunnel
Normal file
3
bin/http-tunnel
Normal file
@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
require('../client');
|
179
client.js
Normal file
179
client.js
Normal file
@ -0,0 +1,179 @@
|
||||
const os = require("os");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const http = require("http");
|
||||
const { io } = require("socket.io-client");
|
||||
const HttpsProxyAgent = require("https-proxy-agent");
|
||||
const { program, InvalidArgumentError, Argument } = require("commander");
|
||||
const { TunnelRequest, TunnelResponse } = require("./lib");
|
||||
|
||||
let socket = null;
|
||||
|
||||
function keepAlive() {
|
||||
setTimeout(() => {
|
||||
if (socket && socket.connected) {
|
||||
socket.send("ping");
|
||||
}
|
||||
keepAlive();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function initClient(options) {
|
||||
const initParams = {
|
||||
path: "/$web_tunnel",
|
||||
transports: ["websocket"],
|
||||
auth: {
|
||||
token: options.token,
|
||||
},
|
||||
};
|
||||
const http_proxy = process.env.https_proxy || process.env.http_proxy;
|
||||
if (http_proxy) {
|
||||
initParams.agent = new HttpsProxyAgent(http_proxy);
|
||||
}
|
||||
socket = io(options.server, initParams);
|
||||
|
||||
socket.on("connect", () => {
|
||||
if (socket.connected) {
|
||||
console.log("client connect to server successfully");
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("connect_error", (e) => {
|
||||
console.log("connect error", e && e.message);
|
||||
});
|
||||
|
||||
socket.on("disconnect", () => {
|
||||
console.log("client disconnected");
|
||||
});
|
||||
|
||||
socket.on("request", (requestId, request) => {
|
||||
const isWebSocket = request.headers.upgrade === "websocket";
|
||||
console.log(`${isWebSocket ? "WS" : request.method}: `, request.path);
|
||||
request.port = options.port;
|
||||
request.hostname = options.host;
|
||||
if (options.origin) {
|
||||
request.headers.host = options.origin;
|
||||
}
|
||||
const tunnelRequest = new TunnelRequest({
|
||||
requestId,
|
||||
socket: socket,
|
||||
});
|
||||
const localReq = http.request(request);
|
||||
tunnelRequest.pipe(localReq);
|
||||
const onTunnelRequestError = (e) => {
|
||||
tunnelRequest.off("end", onTunnelRequestEnd);
|
||||
localReq.destroy(e);
|
||||
};
|
||||
const onTunnelRequestEnd = () => {
|
||||
tunnelRequest.off("error", onTunnelRequestError);
|
||||
};
|
||||
tunnelRequest.once("error", onTunnelRequestError);
|
||||
tunnelRequest.once("end", onTunnelRequestEnd);
|
||||
const onLocalResponse = (localRes) => {
|
||||
localReq.off("error", onLocalError);
|
||||
if (isWebSocket && localRes.upgrade) {
|
||||
return;
|
||||
}
|
||||
const tunnelResponse = new TunnelResponse({
|
||||
responseId: requestId,
|
||||
socket: socket,
|
||||
});
|
||||
tunnelResponse.writeHead(
|
||||
localRes.statusCode,
|
||||
localRes.statusMessage,
|
||||
localRes.headers,
|
||||
localRes.httpVersion
|
||||
);
|
||||
localRes.pipe(tunnelResponse);
|
||||
};
|
||||
const onLocalError = (error) => {
|
||||
console.log(error);
|
||||
localReq.off("response", onLocalResponse);
|
||||
socket.emit("request-error", requestId, error && error.message);
|
||||
tunnelRequest.destroy(error);
|
||||
};
|
||||
const onUpgrade = (localRes, localSocket, localHead) => {
|
||||
// localSocket.once('error', onTunnelRequestError);
|
||||
if (localHead && localHead.length) localSocket.unshift(localHead);
|
||||
const tunnelResponse = new TunnelResponse({
|
||||
responseId: requestId,
|
||||
socket: socket,
|
||||
duplex: true,
|
||||
});
|
||||
tunnelResponse.writeHead(null, null, localRes.headers);
|
||||
localSocket.pipe(tunnelResponse).pipe(localSocket);
|
||||
};
|
||||
localReq.once("error", onLocalError);
|
||||
localReq.once("response", onLocalResponse);
|
||||
|
||||
if (isWebSocket) {
|
||||
localReq.on("upgrade", onUpgrade);
|
||||
}
|
||||
});
|
||||
keepAlive();
|
||||
}
|
||||
|
||||
program.name("http-tunnel").description("HTTP tunnel client");
|
||||
|
||||
program
|
||||
.command("start")
|
||||
.argument("<port>", "local server port number", (value) => {
|
||||
const port = parseInt(value, 10);
|
||||
if (isNaN(port)) {
|
||||
throw new InvalidArgumentError("Not a number.");
|
||||
}
|
||||
return port;
|
||||
})
|
||||
.option("-p, --profile <string>", "setting profile name", "config")
|
||||
.option("-h, --host <string>", "local host value", "localhost")
|
||||
.option("-o, --origin <string>", "change request origin")
|
||||
.action((port, options) => {
|
||||
const configDir = path.resolve(os.homedir(), ".http-tunnel");
|
||||
if (!fs.existsSync(configDir)) {
|
||||
fs.mkdirSync(configDir);
|
||||
}
|
||||
let config = {};
|
||||
const configFilePath = path.resolve(configDir, `${options.profile}.json`);
|
||||
if (fs.existsSync(configFilePath)) {
|
||||
config = JSON.parse(fs.readFileSync(configFilePath, "utf8"));
|
||||
}
|
||||
if (!config.server) {
|
||||
console.log("Please set remote tunnel server firstly");
|
||||
return;
|
||||
}
|
||||
if (!config.token) {
|
||||
console.log(`Please set jwt token for ${config.server} firstly`);
|
||||
return;
|
||||
}
|
||||
options.port = port;
|
||||
options.token = config.token;
|
||||
options.server = config.server;
|
||||
initClient(options);
|
||||
});
|
||||
|
||||
program
|
||||
.command("config")
|
||||
.addArgument(new Argument("<type>", "config type").choices(["jwt", "server"]))
|
||||
.argument("<value>", "config value")
|
||||
.option("-p --profile <string>", "setting profile name", "config")
|
||||
.action((type, value, options) => {
|
||||
const configDir = path.resolve(os.homedir(), ".http-tunnel");
|
||||
if (!fs.existsSync(configDir)) {
|
||||
fs.mkdirSync(configDir);
|
||||
}
|
||||
let config = {};
|
||||
const configFilePath = path.resolve(configDir, `${options.profile}.json`);
|
||||
if (fs.existsSync(configFilePath)) {
|
||||
config = JSON.parse(fs.readFileSync(configFilePath, "utf8"));
|
||||
}
|
||||
if (type === "jwt") {
|
||||
config.token = value;
|
||||
}
|
||||
if (type === "server") {
|
||||
config.server = value;
|
||||
}
|
||||
fs.writeFileSync(configFilePath, JSON.stringify(config, null, 2));
|
||||
console.log(`${type} config saved successfully`);
|
||||
});
|
||||
|
||||
program.parse();
|
146
lib.js
Normal file
146
lib.js
Normal file
@ -0,0 +1,146 @@
|
||||
const stream = require("stream");
|
||||
|
||||
class TunnelRequest extends stream.Readable {
|
||||
constructor({ socket, requestId }) {
|
||||
super();
|
||||
this._socket = socket;
|
||||
this._requestId = requestId;
|
||||
const onRequestPipe = (requestId, data) => {
|
||||
if (this._requestId === requestId) {
|
||||
this.push(data);
|
||||
}
|
||||
};
|
||||
const onRequestPipes = (requestId, data) => {
|
||||
if (this._requestId === requestId) {
|
||||
data.forEach((chunk) => {
|
||||
this.push(chunk);
|
||||
});
|
||||
}
|
||||
};
|
||||
const onRequestPipeError = (requestId, error) => {
|
||||
if (this._requestId === requestId) {
|
||||
this._socket.off("request-pipe", onRequestPipe);
|
||||
this._socket.off("request-pipes", onRequestPipes);
|
||||
this._socket.off("request-pipe-error", onRequestPipeError);
|
||||
this._socket.off("request-pipe-end", onRequestPipeEnd);
|
||||
this.destroy(new Error(error));
|
||||
}
|
||||
};
|
||||
const onRequestPipeEnd = (requestId, data) => {
|
||||
if (this._requestId === requestId) {
|
||||
this._socket.off("request-pipe", onRequestPipe);
|
||||
this._socket.off("request-pipes", onRequestPipes);
|
||||
this._socket.off("request-pipe-error", onRequestPipeError);
|
||||
this._socket.off("request-pipe-end", onRequestPipeEnd);
|
||||
if (data) {
|
||||
this.push(data);
|
||||
}
|
||||
this.push(null);
|
||||
}
|
||||
};
|
||||
this._socket.on("request-pipe", onRequestPipe);
|
||||
this._socket.on("request-pipes", onRequestPipes);
|
||||
this._socket.on("request-pipe-error", onRequestPipeError);
|
||||
this._socket.on("request-pipe-end", onRequestPipeEnd);
|
||||
}
|
||||
|
||||
_read() {}
|
||||
}
|
||||
|
||||
class TunnelResponse extends stream.Duplex {
|
||||
constructor({ socket, responseId, duplex }) {
|
||||
super();
|
||||
this._socket = socket;
|
||||
this._responseId = responseId;
|
||||
if (duplex) {
|
||||
// for websocket request: bidirection
|
||||
const onResponsePipe = (responseId, data) => {
|
||||
if (this._responseId === responseId) {
|
||||
this.push(data);
|
||||
}
|
||||
};
|
||||
const onResponsePipes = (responseId, data) => {
|
||||
if (this._responseId === responseId) {
|
||||
data.forEach((chunk) => {
|
||||
this.push(chunk);
|
||||
});
|
||||
}
|
||||
};
|
||||
const onResponsePipeError = (responseId, error) => {
|
||||
if (this._responseId === responseId) {
|
||||
this._socket.off("response-pipe", onResponsePipe);
|
||||
this._socket.off("response-pipes", onResponsePipes);
|
||||
this._socket.off("response-pipe-error", onResponsePipeError);
|
||||
this._socket.off("response-pipe-end", onResponsePipeEnd);
|
||||
this.destroy(new Error(error));
|
||||
}
|
||||
};
|
||||
const onResponsePipeEnd = (responseId, data) => {
|
||||
if (this._responseId === responseId) {
|
||||
this._socket.off("response-pipe", onResponsePipe);
|
||||
this._socket.off("response-pipes", onResponsePipes);
|
||||
this._socket.off("response-pipe-error", onResponsePipeError);
|
||||
this._socket.off("response-pipe-end", onResponsePipeEnd);
|
||||
if (data) {
|
||||
this.push(data);
|
||||
}
|
||||
this.push(null);
|
||||
}
|
||||
};
|
||||
this._socket.on("response-pipe", onResponsePipe);
|
||||
this._socket.on("response-pipes", onResponsePipes);
|
||||
this._socket.on("response-pipe-error", onResponsePipeError);
|
||||
this._socket.on("response-pipe-end", onResponsePipeEnd);
|
||||
}
|
||||
}
|
||||
|
||||
_write(chunk, encoding, callback) {
|
||||
this._socket.emit("response-pipe", this._responseId, chunk);
|
||||
this._socket.io.engine.once("drain", () => {
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
_writev(chunks, callback) {
|
||||
this._socket.emit("response-pipes", this._responseId, chunks);
|
||||
this._socket.io.engine.once("drain", () => {
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
_final(callback) {
|
||||
this._socket.emit("response-pipe-end", this._responseId);
|
||||
this._socket.io.engine.once("drain", () => {
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
_destroy(e, callback) {
|
||||
if (e) {
|
||||
this._socket.emit(
|
||||
"response-pipe-error",
|
||||
this._responseId,
|
||||
e && e.message
|
||||
);
|
||||
this._socket.io.engine.once("drain", () => {
|
||||
callback();
|
||||
});
|
||||
return;
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
writeHead(statusCode, statusMessage, headers, httpVersion) {
|
||||
this._socket.emit("response", this._responseId, {
|
||||
statusCode,
|
||||
statusMessage,
|
||||
headers,
|
||||
httpVersion,
|
||||
});
|
||||
}
|
||||
|
||||
_read(size) {}
|
||||
}
|
||||
|
||||
exports.TunnelRequest = TunnelRequest;
|
||||
exports.TunnelResponse = TunnelResponse;
|
239
package-lock.json
generated
Normal file
239
package-lock.json
generated
Normal file
@ -0,0 +1,239 @@
|
||||
{
|
||||
"name": "@cubetiq/http-tunnel-client",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@cubetiq/http-tunnel-client",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"commander": "^9.3.0",
|
||||
"https-proxy-agent": "^5.0.1",
|
||||
"socket.io-client": "^4.5.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@socket.io/component-emitter": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
||||
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
||||
"dependencies": {
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "9.3.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz",
|
||||
"integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==",
|
||||
"engines": {
|
||||
"node": "^12.20.0 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-client": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.2.2.tgz",
|
||||
"integrity": "sha512-8ZQmx0LQGRTYkHuogVZuGSpDqYZtCM/nv8zQ68VZ+JkOpazJ7ICdsSpaO6iXwvaU30oFg5QJOJWj8zWqhbKjkQ==",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.0.3",
|
||||
"ws": "~8.2.3",
|
||||
"xmlhttprequest-ssl": "~2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-parser": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz",
|
||||
"integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
||||
"dependencies": {
|
||||
"agent-base": "6",
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/socket.io-client": {
|
||||
"version": "4.5.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.1.tgz",
|
||||
"integrity": "sha512-e6nLVgiRYatS+AHXnOnGi4ocOpubvOUCGhyWw8v+/FxW8saHkinG6Dfhi9TU0Kt/8mwJIAASxvw6eujQmjdZVA==",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io-client": "~6.2.1",
|
||||
"socket.io-parser": "~4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-parser": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.0.tgz",
|
||||
"integrity": "sha512-tLfmEwcEwnlQTxFB7jibL/q2+q8dlVQzj4JdRLJ/W/G1+Fu9VSxCx1Lo+n1HvXxKnM//dUuD0xgiA7tQf57Vng==",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.2.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
|
||||
"integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": "^5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xmlhttprequest-ssl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
|
||||
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
||||
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
|
||||
},
|
||||
"agent-base": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
||||
"requires": {
|
||||
"debug": "4"
|
||||
}
|
||||
},
|
||||
"commander": {
|
||||
"version": "9.3.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz",
|
||||
"integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"engine.io-client": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.2.2.tgz",
|
||||
"integrity": "sha512-8ZQmx0LQGRTYkHuogVZuGSpDqYZtCM/nv8zQ68VZ+JkOpazJ7ICdsSpaO6iXwvaU30oFg5QJOJWj8zWqhbKjkQ==",
|
||||
"requires": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.0.3",
|
||||
"ws": "~8.2.3",
|
||||
"xmlhttprequest-ssl": "~2.0.0"
|
||||
}
|
||||
},
|
||||
"engine.io-parser": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz",
|
||||
"integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg=="
|
||||
},
|
||||
"https-proxy-agent": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
||||
"requires": {
|
||||
"agent-base": "6",
|
||||
"debug": "4"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"socket.io-client": {
|
||||
"version": "4.5.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.1.tgz",
|
||||
"integrity": "sha512-e6nLVgiRYatS+AHXnOnGi4ocOpubvOUCGhyWw8v+/FxW8saHkinG6Dfhi9TU0Kt/8mwJIAASxvw6eujQmjdZVA==",
|
||||
"requires": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io-client": "~6.2.1",
|
||||
"socket.io-parser": "~4.2.0"
|
||||
}
|
||||
},
|
||||
"socket.io-parser": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.0.tgz",
|
||||
"integrity": "sha512-tLfmEwcEwnlQTxFB7jibL/q2+q8dlVQzj4JdRLJ/W/G1+Fu9VSxCx1Lo+n1HvXxKnM//dUuD0xgiA7tQf57Vng==",
|
||||
"requires": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1"
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "8.2.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
|
||||
"integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
|
||||
"requires": {}
|
||||
},
|
||||
"xmlhttprequest-ssl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
|
||||
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A=="
|
||||
}
|
||||
}
|
||||
}
|
26
package.json
Normal file
26
package.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "@cubetiq/http-tunnel-client",
|
||||
"version": "1.0.0",
|
||||
"description": "A lightweight http tunnel client",
|
||||
"main": "client.js",
|
||||
"bin": {
|
||||
"http-tunnel": "bin/http-tunnel"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node client.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.cubetiqs.com/cubetiq/http-tunnel-client.git"
|
||||
},
|
||||
"keywords": [
|
||||
"http-tunnel-client"
|
||||
],
|
||||
"author": "Sambo Chea <sombochea@cubetiqs.com>",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"commander": "^9.3.0",
|
||||
"https-proxy-agent": "^5.0.1",
|
||||
"socket.io-client": "^4.5.1"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user