Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions apps/cli/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import prompts from "prompts";
import { encodeMessage, decodeMessage } from "./protocol";
import { TunnelDataMessage, TunnelResponseMessage } from "./types";
import http from "http";
import https from "https";

export class OutRayClient {
private ws: WebSocket | null = null;
Expand All @@ -12,6 +13,7 @@ export class OutRayClient {
private apiKey?: string;
private subdomain?: string;
private customDomain?: string;
private localProtocol: "http" | "https";
private requestedSubdomain?: string;
private reconnectTimeout: NodeJS.Timeout | null = null;
private pingInterval: NodeJS.Timeout | null = null;
Expand All @@ -23,7 +25,8 @@ export class OutRayClient {
private reconnectAttempts = 0;
private lastPongReceived = Date.now();
private noLog: boolean;
private readonly PING_INTERVAL_MS = 25000; // 25 seconds
private verifySsl: boolean;
private readonly PING_INTERVAL_MS = 25000;
private readonly PONG_TIMEOUT_MS = 10000; // 10 seconds to wait for pong

constructor(
Expand All @@ -33,6 +36,8 @@ export class OutRayClient {
subdomain?: string,
customDomain?: string,
noLog: boolean = false,
localProtocol: "http" | "https" = "http",
verifySsl: boolean = false,
) {
this.localPort = localPort;
this.serverUrl = serverUrl;
Expand All @@ -41,6 +46,8 @@ export class OutRayClient {
this.customDomain = customDomain;
this.requestedSubdomain = subdomain;
this.noLog = noLog;
this.localProtocol = localProtocol;
this.verifySsl = verifySsl;
}

public start(): void {
Expand Down Expand Up @@ -183,15 +190,17 @@ export class OutRayClient {

private handleTunnelData(message: TunnelDataMessage): void {
const startTime = Date.now();
const reqOptions = {
const reqOptions: http.RequestOptions | https.RequestOptions = {
hostname: "localhost",
port: this.localPort,
path: message.path,
method: message.method,
headers: message.headers,
...(this.localProtocol === "https" && { rejectUnauthorized: this.verifySsl }),
};

const req = http.request(reqOptions, (res) => {
const requestFn = this.localProtocol === "https" ? https.request : http.request;
const req = requestFn(reqOptions, (res) => {
const chunks: Buffer[] = [];

res.on("data", (chunk) => {
Expand Down
21 changes: 20 additions & 1 deletion apps/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ function printHelp() {
console.log(chalk.cyan(" outray validate-config Validate config.toml file"));
console.log(chalk.cyan(" outray <port> Start HTTP tunnel"));
console.log(chalk.cyan(" outray http <port> Start HTTP tunnel"));
console.log(chalk.cyan(" outray https <port> Start HTTPS tunnel (local server uses HTTPS)"));
console.log(chalk.cyan(" outray tcp <port> Start TCP tunnel"));
console.log(chalk.cyan(" outray udp <port> Start UDP tunnel"));
console.log(chalk.cyan(" outray switch [org] Switch organization"));
Expand All @@ -381,6 +382,9 @@ function printHelp() {
chalk.cyan(" --remote-port <port> Remote port (TCP/UDP only)"),
);
console.log(chalk.cyan(" --key <token> Override auth token"));
console.log(
chalk.cyan(" --verify-ssl Verify SSL certs (HTTPS only, default: off)"),
);
console.log(
chalk.cyan(" --no-logs Disable tunnel request logs"),
);
Expand Down Expand Up @@ -523,7 +527,7 @@ async function main() {
// Parse tunnel command
let localPort: number;
let remainingArgs: string[];
let tunnelProtocol: "http" | "tcp" | "udp" = "http";
let tunnelProtocol: "http" | "https" | "tcp" | "udp" = "http";

if (command === "http") {
const portArg = args[1];
Expand All @@ -545,6 +549,16 @@ async function main() {
localPort = parseInt(portArg, 10);
remainingArgs = args.slice(2);
tunnelProtocol = "tcp";
} else if (command === "https") {
const portArg = args[1];
if (!portArg) {
console.log(chalk.red("❌ Please specify a port"));
console.log(chalk.cyan("Usage: outray https <port>"));
process.exit(1);
}
localPort = parseInt(portArg, 10);
remainingArgs = args.slice(2);
tunnelProtocol = "https";
} else if (command === "udp") {
const portArg = args[1];
if (!portArg) {
Expand Down Expand Up @@ -630,6 +644,8 @@ async function main() {
// Handle --no-logs flag to disable tunnel request logs
const noLogs = remainingArgs.includes("--no-logs");

const verifySsl = remainingArgs.includes("--verify-ssl");

// Load and validate config
let config = configManager.load();

Expand Down Expand Up @@ -717,13 +733,16 @@ async function main() {
noLogs,
);
} else {
const localProtocol = tunnelProtocol === "https" ? "https" : "http";
client = new OutRayClient(
localPort!,
serverUrl,
apiKey,
subdomain,
customDomain,
noLogs,
localProtocol,
verifySsl,
);
}

Expand Down
Loading