UNPKG

@microsoft/dev-tunnels-ssh-tcp

Version:

SSH TCP extensions library for Dev Tunnels

112 lines 5.31 kB
"use strict"; // // Copyright (c) Microsoft Corporation. All rights reserved. // Object.defineProperty(exports, "__esModule", { value: true }); exports.SshServer = void 0; const vscode_jsonrpc_1 = require("vscode-jsonrpc"); const dev_tunnels_ssh_1 = require("@microsoft/dev-tunnels-ssh"); const tcpListenerFactory_1 = require("./tcpListenerFactory"); /** * Enables accepting SSH sessions on a TCP socket. * * It's possible to create an `SshServerSession` over any `Stream` instance; * this class is merely a convenient helper that manages creating sessions * over Node.js TCP `Socket`s from incoming connections. */ class SshServer { constructor(config) { this.config = config; this.sessions = []; /** * Gets or sets a function that handles trace messages associated with the server sessions. * * By default, no messages are traced. To enable tracing, set this property to a function * that routes the message to console.log, a file, or anywhere else. * * @param level The level of message being traced: error, warning, info, or verbose. * @param eventId An integer that identifies the type of event. Normally this is one of * the values from `SshTraceEventIds`, but extensions may define additional event IDs. * @param msg A description of the event (non-localized). * @param err Optional `Error` object associated with the event, often included with * warning or error events. While the `Error.message` property is typically included as * (part of) the `msg` parameter, the error object may contain additional useful context * such as the stack trace. */ this.trace = (level, eventId, msg, err) => { }; this.errorEmitter = new vscode_jsonrpc_1.Emitter(); this.onError = this.errorEmitter.event; this.sessionOpenedEmitter = new vscode_jsonrpc_1.Emitter(); this.onSessionOpened = this.sessionOpenedEmitter.event; this.credentials = { publicKeys: [] }; /** * Gets or sets a factory for creating TCP listeners. * * Applications may override this factory to provide custom logic for selecting * local port numbers to listen on for port-forwarding. */ this.tcpListenerFactory = new tcpListenerFactory_1.DefaultTcpListenerFactory(); if (!config) throw new TypeError('SshSessionConfiguration is required.'); if (config.protocolExtensions.includes(dev_tunnels_ssh_1.SshProtocolExtensionNames.sessionReconnect)) { this.reconnectableSessions = []; } } async acceptSessions(localPort, localAddress) { if (!localAddress) { localAddress = '0.0.0.0'; } const portPrefix = localAddress === '0.0.0.0' ? 'port ' : localAddress + ':'; try { this.tcpListener = await this.tcpListenerFactory.createTcpListener(undefined, // remotePort localAddress, localPort, false); } catch (e) { if (!(e instanceof Error)) throw e; this.trace(dev_tunnels_ssh_1.TraceLevel.Error, dev_tunnels_ssh_1.SshTraceEventIds.serverListenFailed, `SshServer failed to listen on ${portPrefix}${localPort}: ${e.message}`, e); throw e; } this.tcpListener.addListener('connection', this.acceptSession.bind(this)); this.trace(dev_tunnels_ssh_1.TraceLevel.Info, dev_tunnels_ssh_1.SshTraceEventIds.serverListening, `SshServer listening on ${portPrefix}${localPort}.`); } async acceptConnection(socket) { socket.setNoDelay(true); return new dev_tunnels_ssh_1.NodeStream(socket); } async acceptSession(socket) { this.trace(dev_tunnels_ssh_1.TraceLevel.Info, dev_tunnels_ssh_1.SshTraceEventIds.serverClientConnected, 'SshServer client connected.'); const stream = await this.acceptConnection(socket); const session = new dev_tunnels_ssh_1.SshServerSession(this.config, this.reconnectableSessions); session.trace = this.trace; session.credentials = this.credentials; this.sessions.push(session); session.onClosed((e) => { const sessionIndex = this.sessions.indexOf(session); if (sessionIndex >= 0) { this.sessions.splice(sessionIndex, 1); } }); this.sessionOpenedEmitter.fire(session); try { await session.connect(stream); } catch (e) { if (!(e instanceof Error)) throw e; if (e instanceof dev_tunnels_ssh_1.SshConnectionError) { await session.close(e.reason || dev_tunnels_ssh_1.SshDisconnectReason.connectionLost, e.message, e); } else { await session.close(dev_tunnels_ssh_1.SshDisconnectReason.protocolError, e.message, e); } this.errorEmitter.fire(e); } } dispose() { var _a; (_a = this.tcpListener) === null || _a === void 0 ? void 0 : _a.close(); } } exports.SshServer = SshServer; //# sourceMappingURL=sshServer.js.map