"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.NewChannel = exports.Channel = exports.SSHAgentStream = exports.SFTP = exports.isPageantRunning = exports.SFTPFile = exports.OPEN_WRITE = exports.OPEN_TRUNCATE = exports.OPEN_READ = exports.OPEN_CREATE = exports.OPEN_APPEND = exports.getSupportedKeyTypes = exports.getSupportedCompressionAlgorithms = exports.getSupportedMACs = exports.getSupportedKexAlgorithms = exports.getSupportedCiphers = exports.NewSshChannel = exports.SshChannel = exports.SshTransport = exports.SshPublicKey = exports.KeyboardInteractiveAuthenticationPrompt = exports.AuthenticatedSSHClient = exports.SSHClient = exports.KeyPair = void 0;
const rxjs_1 = require("rxjs");
const helpers_1 = require("./helpers");
const sftp_1 = require("./sftp");
const channel_1 = require("./channel");
Object.defineProperty(exports, "Channel", { enumerable: true, get: function () { return channel_1.Channel; } });
Object.defineProperty(exports, "NewChannel", { enumerable: true, get: function () { return channel_1.NewChannel; } });
const events_1 = require("./events");
const native_1 = __importDefault(require("./native"));
const agent_1 = require("./agent");
class KeyPair {
    constructor(inner) {
        this.inner = inner;
    }
    get algorithm() {
        return this.inner.publicKey().algorithm();
    }
    static parse(data, passphrase) {
        return __awaiter(this, void 0, void 0, function* () {
            return new KeyPair(yield native_1.default.parseKey(data, passphrase));
        });
    }
}
exports.KeyPair = KeyPair;
class SSHClient extends helpers_1.Destructible {
    constructor(client, events) {
        super();
        this.client = client;
        this.events = events;
        this.disconnect$ = this.events.disconnect$.asObservable();
        this.banner$ = this.events.banner$.asObservable();
    }
    static connect(transport, serverKeyCallback, config) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a, _b, _c, _d, _e, _f;
            const eventInterface = new events_1.ClientEventInterface();
            const russhClient = yield native_1.default.connect(transport, (_a = config === null || config === void 0 ? void 0 : config.preferred) === null || _a === void 0 ? void 0 : _a.ciphers, (_b = config === null || config === void 0 ? void 0 : config.preferred) === null || _b === void 0 ? void 0 : _b.kex, (_c = config === null || config === void 0 ? void 0 : config.preferred) === null || _c === void 0 ? void 0 : _c.key, (_d = config === null || config === void 0 ? void 0 : config.preferred) === null || _d === void 0 ? void 0 : _d.mac, (_e = config === null || config === void 0 ? void 0 : config.preferred) === null || _e === void 0 ? void 0 : _e.compression, config === null || config === void 0 ? void 0 : config.connectionTimeoutSeconds, config === null || config === void 0 ? void 0 : config.keepaliveIntervalSeconds, (_f = config === null || config === void 0 ? void 0 : config.keepaliveCountMax) !== null && _f !== void 0 ? _f : 3, (_, k) => serverKeyCallback(k), eventInterface.dataCallback, eventInterface.extendedDataCallback, eventInterface.eofCallback, eventInterface.closeCallback, eventInterface.disconnectCallback, eventInterface.x11ChannelOpenCallback, eventInterface.tcpChannelOpenCallback, eventInterface.agentChannelOpenCallback, eventInterface.bannerCallback);
            eventInterface.disconnect$.subscribe(() => {
                setTimeout(() => eventInterface.complete());
            });
            return new SSHClient(russhClient, eventInterface);
        });
    }
    destruct() {
        super.destruct();
    }
    authenticateNone(username) {
        return __awaiter(this, void 0, void 0, function* () {
            this.assertNotDestructed();
            const result = yield this.client.authenticateNone(username);
            if (result.success) {
                return this.intoAuthenticated();
            }
            return result;
        });
    }
    authenticateWithPassword(username, password) {
        return __awaiter(this, void 0, void 0, function* () {
            this.assertNotDestructed();
            const result = yield this.client.authenticatePassword(username, password);
            if (result.success) {
                return this.intoAuthenticated();
            }
            return result;
        });
    }
    _hashAlg(hashAlgorithm) {
        return hashAlgorithm ? {
            sha1: 0 /* HashAlgorithm.Sha1 */,
            sha256: 1 /* HashAlgorithm.Sha256 */,
            sha512: 2 /* HashAlgorithm.Sha512 */,
        }[hashAlgorithm] : null;
    }
    authenticateWithKeyPair(username, keyPair, hashAlgorithm) {
        return __awaiter(this, void 0, void 0, function* () {
            this.assertNotDestructed();
            const result = yield this.client.authenticatePublickey(username, keyPair['inner'], this._hashAlg(hashAlgorithm));
            if (result.success) {
                return this.intoAuthenticated();
            }
            return result;
        });
    }
    startKeyboardInteractiveAuthentication(username) {
        return __awaiter(this, void 0, void 0, function* () {
            this.assertNotDestructed();
            return yield this.client.startKeyboardInteractiveAuthentication(username);
        });
    }
    continueKeyboardInteractiveAuthentication(responses) {
        return __awaiter(this, void 0, void 0, function* () {
            this.assertNotDestructed();
            const result = yield this.client.respondToKeyboardInteractiveAuthentication(responses);
            if (result.state === 'success') {
                return this.intoAuthenticated();
            }
            return result;
        });
    }
    authenticateWithAgent(username, connection) {
        return __awaiter(this, void 0, void 0, function* () {
            this.assertNotDestructed();
            const result = yield this.client.authenticateAgent(username, (0, agent_1.makeRusshAgentConnection)(connection));
            if (result.success) {
                return this.intoAuthenticated();
            }
            return result;
        });
    }
    disconnect() {
        return __awaiter(this, void 0, void 0, function* () {
            this.destruct();
            yield this.client.disconnect();
        });
    }
    intoAuthenticated() {
        this.destruct();
        return new AuthenticatedSSHClient(this.client, this.events);
    }
}
exports.SSHClient = SSHClient;
class AuthenticatedSSHClient extends helpers_1.Destructible {
    constructor(client, events) {
        super();
        this.client = client;
        this.events = events;
        this.disconnect$ = this.events.disconnect$;
        this.x11ChannelOpen$ = this.events.x11ChannelOpen$.pipe((0, rxjs_1.map)(([ch, address, port]) => ({
            channel: new channel_1.NewChannel(ch),
            clientAddress: address,
            clientPort: port,
        })));
        this.tcpChannelOpen$ = this.events.tcpChannelOpen$.pipe((0, rxjs_1.map)(([ch, targetAddress, targetPort, clientAddress, clientPort,]) => ({
            channel: new channel_1.NewChannel(ch),
            targetAddress,
            targetPort,
            clientAddress,
            clientPort,
        })));
        this.agentChannelOpen$ = this.events.agentChannelOpen$.pipe((0, rxjs_1.map)(([ch]) => new channel_1.NewChannel(ch)));
    }
    openSessionChannel() {
        return __awaiter(this, void 0, void 0, function* () {
            return yield new channel_1.NewChannel(yield this.client.channelOpenSession());
        });
    }
    openTCPForwardChannel(options) {
        return __awaiter(this, void 0, void 0, function* () {
            return new channel_1.NewChannel(yield this.client.channelOpenDirectTcpip(options.addressToConnectTo, options.portToConnectTo, options.originatorAddress, options.originatorPort));
        });
    }
    forwardTCPPort(addressToBind, portToBind) {
        return __awaiter(this, void 0, void 0, function* () {
            return yield this.client.tcpipForward(addressToBind, portToBind);
        });
    }
    stopForwardingTCPPort(addressToBind, portToBind) {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.client.cancelTcpipForward(addressToBind, portToBind);
        });
    }
    disconnect() {
        return __awaiter(this, void 0, void 0, function* () {
            this.destruct();
            yield this.client.disconnect();
        });
    }
    activateChannel(ch) {
        return __awaiter(this, void 0, void 0, function* () {
            let channel = yield ch.take().activate();
            return this.wrapChannel(channel);
        });
    }
    activateSFTP(ch) {
        return __awaiter(this, void 0, void 0, function* () {
            let channel = yield ch.take().activateSftp();
            return new sftp_1.SFTP(channel, this.events);
        });
    }
    wrapChannel(channel) {
        return __awaiter(this, void 0, void 0, function* () {
            let id = yield channel.id();
            return new channel_1.Channel(id, channel, this.events);
        });
    }
}
exports.AuthenticatedSSHClient = AuthenticatedSSHClient;
var native_2 = require("./native");
Object.defineProperty(exports, "KeyboardInteractiveAuthenticationPrompt", { enumerable: true, get: function () { return native_2.KeyboardInteractiveAuthenticationPrompt; } });
Object.defineProperty(exports, "SshPublicKey", { enumerable: true, get: function () { return native_2.SshPublicKey; } });
Object.defineProperty(exports, "SshTransport", { enumerable: true, get: function () { return native_2.SshTransport; } });
Object.defineProperty(exports, "SshChannel", { enumerable: true, get: function () { return native_2.SshChannel; } });
Object.defineProperty(exports, "NewSshChannel", { enumerable: true, get: function () { return native_2.NewSshChannel; } });
Object.defineProperty(exports, "getSupportedCiphers", { enumerable: true, get: function () { return native_2.supportedCiphers; } });
Object.defineProperty(exports, "getSupportedKexAlgorithms", { enumerable: true, get: function () { return native_2.supportedKexAlgorithms; } });
Object.defineProperty(exports, "getSupportedMACs", { enumerable: true, get: function () { return native_2.supportedMacs; } });
Object.defineProperty(exports, "getSupportedCompressionAlgorithms", { enumerable: true, get: function () { return native_2.supportedCompressionAlgorithms; } });
Object.defineProperty(exports, "getSupportedKeyTypes", { enumerable: true, get: function () { return native_2.supportedKeyTypes; } });
Object.defineProperty(exports, "OPEN_APPEND", { enumerable: true, get: function () { return native_2.OPEN_APPEND; } });
Object.defineProperty(exports, "OPEN_CREATE", { enumerable: true, get: function () { return native_2.OPEN_CREATE; } });
Object.defineProperty(exports, "OPEN_READ", { enumerable: true, get: function () { return native_2.OPEN_READ; } });
Object.defineProperty(exports, "OPEN_TRUNCATE", { enumerable: true, get: function () { return native_2.OPEN_TRUNCATE; } });
Object.defineProperty(exports, "OPEN_WRITE", { enumerable: true, get: function () { return native_2.OPEN_WRITE; } });
Object.defineProperty(exports, "SFTPFile", { enumerable: true, get: function () { return native_2.SftpFile; } });
Object.defineProperty(exports, "isPageantRunning", { enumerable: true, get: function () { return native_2.isPageantRunning; } });
var sftp_2 = require("./sftp");
Object.defineProperty(exports, "SFTP", { enumerable: true, get: function () { return sftp_2.SFTP; } });
var agent_2 = require("./agent");
Object.defineProperty(exports, "SSHAgentStream", { enumerable: true, get: function () { return agent_2.SSHAgentStream; } });
