balena-cli
Version:
The official balena Command Line Interface
91 lines • 3.6 kB
JavaScript
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
;