UNPKG

balena-cli

Version:

The official balena Command Line Interface

91 lines 3.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.tunnelConnectionToDevice = void 0; const tls = require("tls"); const typed_error_1 = require("typed-error"); const errors_1 = require("../errors"); const PROXY_CONNECT_TIMEOUT_MS = 10000; class TunnelServerNotTrustedError extends errors_1.ExpectedError { } class UnableToConnectError extends typed_error_1.TypedError { constructor(statusCode, status) { super(`Unable to connect: ${statusCode} ${status}`); this.status = status; this.statusCode = statusCode; } } class RemoteSocketNotListening extends typed_error_1.TypedError { constructor(port) { super(`Device is not listening on port ${port}`); } } const tunnelConnectionToDevice = (uuid, port, sdk) => { return Promise.all([ sdk.settings.get('tunnelUrl'), sdk.auth.whoami(), sdk.auth.getToken(), ]).then(([tunnelUrl, whoami, token]) => { const auth = { user: (whoami === null || whoami === void 0 ? void 0 : whoami.actorType) === 'user' ? whoami.username : 'root', password: token, }; return (client) => openPortThroughProxy(tunnelUrl, 443, auth, uuid, port) .then((remote) => { client.pipe(remote); remote.pipe(client); remote.on('error', (err) => { console.error('Remote: ' + err); client.end(); }); client.on('error', (err) => { console.error('Client: ' + err); remote.end(); }); remote.on('close', () => { client.end(); }); client.on('close', () => { remote.end(); }); }) .catch((e) => { client.end(); throw e; }); }); }; exports.tunnelConnectionToDevice = tunnelConnectionToDevice; const openPortThroughProxy = (proxyServer, proxyPort, proxyAuth, deviceUuid, devicePort) => { const httpHeaders = [`CONNECT ${deviceUuid}.balena:${devicePort} HTTP/1.0`]; if (proxyAuth !== null) { const credentials = Buffer.from(`${proxyAuth.user}:${proxyAuth.password}`).toString('base64'); httpHeaders.push(`Proxy-Authorization: Basic ${credentials}`); } return new Promise((resolve, reject) => { const proxyTunnel = tls.connect(proxyPort, proxyServer, { servername: proxyServer }, () => { if (!proxyTunnel.authorized) { console.error('Unable to authorize the tunnel server'); reject(new TunnelServerNotTrustedError(proxyTunnel.authorizationError)); return; } proxyTunnel.once('data', (data) => { const [httpStatus] = data.toString('utf8').split('\r\n'); const [, httpStatusCode, ...httpMessage] = httpStatus.split(' '); if (parseInt(httpStatusCode, 10) === 200) { proxyTunnel.setTimeout(0); resolve(proxyTunnel); } else { reject(new UnableToConnectError(httpStatusCode, httpMessage.join(' '))); } }); proxyTunnel.on('timeout', () => { reject(new RemoteSocketNotListening(devicePort)); }); proxyTunnel.setTimeout(PROXY_CONNECT_TIMEOUT_MS); proxyTunnel.write(httpHeaders.join('\r\n').concat('\r\n\r\n')); }); proxyTunnel.on('error', reject); }); }; //# sourceMappingURL=tunnel.js.map