diff --git a/README.md b/README.md index 2b8a396..536317c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ -# HTTP Tunnel Client -A lightweight http tunnel client using nodejs. +# CUBETIQ HTTP Tunnel Client +A lightweight http tunnel client using nodejs and socket.io client. + +### Usage +- Generate Client Key +``` +npx @cubetiq/http-tunnel config client new +``` ### Contributors - Original [web-tunnel](https://github.com/web-tunnel/lite-http-tunnel-client) diff --git a/client.js b/client.js index 30d495e..22d0582 100644 --- a/client.js +++ b/client.js @@ -6,7 +6,12 @@ const { io } = require("socket.io-client"); const HttpsProxyAgent = require("https-proxy-agent"); const { program, InvalidArgumentError, Argument } = require("commander"); const { TunnelRequest, TunnelResponse } = require("./lib"); +const { generateUUID, addPrefixOnHttpSchema } = require("./util"); +// constants +const PROFILE_DEFAULT = "default"; + +// create socket instance let socket = null; function keepAlive() { @@ -19,11 +24,24 @@ function keepAlive() { } function initClient(options) { + // Please change this if your domain goes wrong here + // Current style using sub-domain: https://{{clientId}}-tunnel.myhostingdomain.com + // (Original server: https://tunnel.myhostingdomain.com) + const profile = options.profile || PROFILE_DEFAULT; + const clientId = `${options.clientId || generateUUID()}`; + const clientIdSub = `${clientId}-${profile}-`; + const serverUrl = addPrefixOnHttpSchema(options.server, clientIdSub); + const initParams = { - path: "/$web_tunnel", + path: "/$cubetiq_http_tunnel", transports: ["websocket"], auth: { token: options.token, + apiKey: options.apiKey, + clientId: options.clientId, + profile: options.profile, + clientIdSub: clientIdSub, + serverUrl: serverUrl, }, }; @@ -32,20 +50,23 @@ function initClient(options) { initParams.agent = new HttpsProxyAgent(http_proxy); } - socket = io(options.server, initParams); + // Connecting to socket server and agent here... + console.log(`client connecting to server: ${serverUrl}`); + socket = io(serverUrl, initParams); + const clientLogPrefix = `client: ${clientId} on profile: ${profile}`; socket.on("connect", () => { if (socket.connected) { - console.log("client connect to server successfully"); + console.log(`${clientLogPrefix} is connected to server successfully!`); } }); socket.on("connect_error", (e) => { - console.log("connect error", e && e.message); + console.log(`${clientLogPrefix} connect error!`, e && e.message); }); socket.on("disconnect", () => { - console.log("client disconnected"); + console.log(`${clientLogPrefix} disconnected!`); }); socket.on("request", (requestId, request) => { @@ -132,7 +153,7 @@ function initClient(options) { keepAlive(); } -program.name("http-tunnel").description("HTTP tunnel client"); +program.name("http-tunnel").description("CUBETIQ HTTP tunnel client"); program .command("start") @@ -143,7 +164,7 @@ program } return port; }) - .option("-p, --profile ", "setting profile name", "default") + .option("-p, --profile ", "setting profile name", PROFILE_DEFAULT) .option("-h, --host ", "local host value", "localhost") .option("-o, --origin ", "change request origin") .action((port, options) => { @@ -162,32 +183,52 @@ program } if (!config.server) { - console.log("Please set remote tunnel server firstly"); + console.error("Please set remote tunnel server firstly!"); return; } if (!config.token) { - console.log(`Please set jwt token for ${config.server} firstly`); + console.error(`Please set jwt token for ${config.server} firstly!`); + return; + } + + if (!config.clientId) { + console.error(`Please create client for ${config.server} firstly!`); return; } options.port = port; options.token = config.token; options.server = config.server; + options.clientId = config.clientId; + options.apiKey = config.apiKey; initClient(options); }); program .command("config") - .addArgument(new Argument("", "config type").choices(["jwt", "server"])) + .addArgument( + new Argument("", "config type").choices([ + "token", + "server", + "client", + "key", + ]) + ) .argument("", "config value") - .option("-p --profile ", "setting profile name", "default") + .option("-p --profile ", "setting profile name", PROFILE_DEFAULT) .action((type, value, options) => { + if (!type) { + console.error("type config is required!"); + return; + } + const configDir = path.resolve(os.homedir(), ".http-tunnel"); if (!fs.existsSync(configDir)) { fs.mkdirSync(configDir); + console.log(`config file ${configDir} was created!`); } let config = {}; @@ -198,16 +239,24 @@ program config = JSON.parse(fs.readFileSync(configFilePath, "utf8")); } - if (type === "jwt") { + if (type === "token" || type === "jwt") { config.token = value; - } - - if (type === "server") { + } else if (type === "server") { config.server = value; + } else if (type === "clientId" || type === "client") { + if (!value || value === "new") { + config.clientId = generateUUID(); + } else { + config.clientId = value; + } + } else if (type === "apiKey" || type === "key") { + config.apiKey = value; + } else { + config[key] = value; } fs.writeFileSync(configFilePath, JSON.stringify(config, null, 2)); - console.log(`${type} config saved successfully to: ${configFilePath}`); + console.log(`${type} config saved successfully to: ${configFilePath}!`); }); program.parse(); diff --git a/package.json b/package.json index ba93f55..ce9f2b0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@cubetiq/http-tunnel-client", "version": "1.0.0", - "description": "A lightweight http tunnel client", + "description": "A lightweight http tunnel client using nodejs and socket.io client.", "main": "client.js", "bin": { "http-tunnel": "bin/http-tunnel" @@ -14,7 +14,8 @@ "url": "https://git.cubetiqs.com/cubetiq/http-tunnel-client.git" }, "keywords": [ - "http-tunnel-client" + "http-tunnel-client", + "socket.io-client" ], "author": "Sambo Chea ", "license": "ISC", diff --git a/util.js b/util.js new file mode 100644 index 0000000..b4ac6da --- /dev/null +++ b/util.js @@ -0,0 +1,19 @@ +const crypto = require("crypto"); + +const addPrefixOnHttpSchema = (url, prefixDomain) => { + let prefixSubDomain = prefixDomain; + const prefixSchema = url.substring(0, url.indexOf("://") + 3); + const splitDomain = url.substring(url.indexOf("://") + 3); + + // if (!prefixSubDomain.endsWith(".")) { + // prefixSubDomain = `${prefixSubDomain}.`; + // } + + return `${prefixSchema}${prefixSubDomain}${splitDomain}`; +}; + +const generateUUID = () => { + return crypto.randomUUID(); +}; + +module.exports = { addPrefixOnHttpSchema, generateUUID };