From 6dee4fbc930422f6d7f78ffe3a79baa0de173eda Mon Sep 17 00:00:00 2001
From: Abdelilah El Aissaoui <aeab13@gmail.com>
Date: Wed, 20 Sep 2023 10:26:02 +0200
Subject: [PATCH] Added basic ssh auth in rust without error handling

---
 build.gradle.kts                              |   2 +-
 rs/Cargo.toml                                 |   1 +
 rs/build.rs                                   |   2 +-
 rs/src/gitnuro.udl                            |  46 +++++++
 rs/src/lib.rs                                 | 129 +++++++++++++++++-
 rs/src/repository_watcher.udl                 |  20 ---
 .../gitnuro/credentials/GProcessLibSsh.kt     |  13 +-
 .../gitnuro/credentials/GRemoteSession.kt     |  69 ++++------
 .../gitnuro/ssh/libssh/LibSshChannel.kt       |  19 ++-
 .../gitnuro/ssh/libssh/LibSshOptions.kt       |  50 -------
 .../gitnuro/ssh/libssh/LibSshSession.kt       |  62 ---------
 .../gitnuro/ssh/libssh/LibSshWrapper.kt       |  44 ------
 .../streams/LibSshChannelInputErrStream.kt    |  15 +-
 .../streams/LibSshChannelInputStream.kt       |  20 ++-
 .../streams/LibSshChannelOutputStream.kt      |  14 +-
 15 files changed, 239 insertions(+), 267 deletions(-)
 create mode 100644 rs/src/gitnuro.udl
 delete mode 100644 rs/src/repository_watcher.udl
 delete mode 100644 src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/LibSshOptions.kt
 delete mode 100644 src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/LibSshSession.kt
 delete mode 100644 src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/LibSshWrapper.kt

diff --git a/build.gradle.kts b/build.gradle.kts
index 43c6c67..a3b4f91 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -205,7 +205,7 @@ fun generateKotlinFromUdl() {
         workingDir = File(project.projectDir, "rs")
         commandLine = listOf(
             "cargo", "run", "--features=uniffi/cli",
-            "--bin", "uniffi-bindgen", "generate", "src/repository_watcher.udl",
+            "--bin", "uniffi-bindgen", "generate", "src/gitnuro.udl",
             "--language", "kotlin",
             "--out-dir", rustGeneratedSource
         )
diff --git a/rs/Cargo.toml b/rs/Cargo.toml
index b72fb94..4f12390 100644
--- a/rs/Cargo.toml
+++ b/rs/Cargo.toml
@@ -13,6 +13,7 @@ name = "gitnuro_rs"
 uniffi = { version = "0.24.1" }
 notify = "6.0.1"
 thiserror = "1.0.43"
+libssh-rs = "0.2.1"
 
 [build-dependencies]
 uniffi = { version = "0.24.1", features = [ "build" ] }
diff --git a/rs/build.rs b/rs/build.rs
index b76debf..f5c593b 100644
--- a/rs/build.rs
+++ b/rs/build.rs
@@ -1,3 +1,3 @@
 fn main() {
-    uniffi::generate_scaffolding("src/repository_watcher.udl").unwrap();
+    uniffi::generate_scaffolding("src/gitnuro.udl").unwrap();
 }
diff --git a/rs/src/gitnuro.udl b/rs/src/gitnuro.udl
new file mode 100644
index 0000000..3f29928
--- /dev/null
+++ b/rs/src/gitnuro.udl
@@ -0,0 +1,46 @@
+namespace gitnuro {
+    [Throws=WatcherInitError]
+    void watch_directory(string path, WatchDirectoryNotifier checker);
+};
+
+callback interface WatchDirectoryNotifier {
+    boolean should_keep_looping();
+
+    void detected_change(sequence<string> paths);
+};
+
+[Error]
+interface WatcherInitError {
+    Generic(string error);
+    Io(string error);
+    PathNotFound();
+    WatchNotFound();
+    InvalidConfig();
+    MaxFilesWatch();
+};
+
+
+interface Session {
+    constructor();
+    void setup(string host, string? user, i32 port);
+    void public_key_auth();
+    void password_auth(string password);
+    void disconnect();
+};
+
+interface Channel {
+    constructor(Session session);
+    void open_session();
+    boolean is_open();
+    void close();
+    void request_exec(string command);
+    boolean poll_has_bytes(boolean is_stderr);
+    ReadResult read(boolean is_stderr, u64 len);
+    void write_byte(i32 byte);
+    void write_bytes(bytes data);
+};
+
+dictionary ReadResult {
+    u64 read_count;
+    bytes data;
+};
\ No newline at end of file
diff --git a/rs/src/lib.rs b/rs/src/lib.rs
index 1a7e182..9a93859 100644
--- a/rs/src/lib.rs
+++ b/rs/src/lib.rs
@@ -1,13 +1,18 @@
 extern crate notify;
 
 use std::fmt::Debug;
+use std::io::{Write};
 use std::path::Path;
 use std::sync::mpsc::{channel, RecvTimeoutError};
+use std::sync::{Arc, RwLock};
 use std::time::Duration;
 
+use libssh_rs::{PollStatus, SshOption};
 use notify::{Config, Error, ErrorKind, Event, RecommendedWatcher, RecursiveMode, Watcher};
 
-uniffi::include_scaffolding!("repository_watcher");
+uniffi::include_scaffolding!("gitnuro");
+
+const ACCEPTED_SSH_TYPES: &str = "ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,rsa-sha2-512,rsa-sha2-256,ssh-dss";
 
 fn watch_directory(
     path: String,
@@ -114,3 +119,125 @@ impl WatcherInitErrorConverter for ErrorKind {
         }
     }
 }
+
+struct Session {
+    pub session: RwLock<libssh_rs::Session>,
+}
+
+impl Session {
+    fn new() -> Self {
+        let session = libssh_rs::Session::new().unwrap();
+
+        Session {
+            session: RwLock::new(session)
+        }
+    }
+
+    fn setup(&self, host: String, user: Option<String>, port: i32) {
+        let session = self.session.write().unwrap();
+        session.set_option(SshOption::Hostname(host)).unwrap();
+
+        if let Some(user) = user {
+            session.set_option(SshOption::User(Some(user))).unwrap();
+        }
+
+        if let Ok(port) = port.try_into() {
+            session.set_option(SshOption::Port(port)).unwrap();
+        }
+
+        session.set_option(SshOption::PublicKeyAcceptedTypes(ACCEPTED_SSH_TYPES.to_string())).unwrap();
+        session.options_parse_config(None).unwrap();
+        session.connect().unwrap();
+    }
+
+    fn public_key_auth(&self) {
+        let session = self.session.write().unwrap();
+        session.userauth_public_key_auto(None, Some("")).unwrap();
+    }
+
+    fn password_auth(&self, password: String) {
+        let session = self.session.write().unwrap();
+        session.userauth_password(None, Some(&password)).unwrap();
+    }
+
+    fn disconnect(&self) {
+        let session = self.session.write().unwrap();
+        session.disconnect()
+    }
+}
+
+
+struct Channel {
+    channel: RwLock<libssh_rs::Channel>,
+}
+
+unsafe impl Send for Channel {}
+unsafe impl Sync for Channel {}
+
+impl Channel {
+    fn new(session: Arc<Session>) -> Self {
+        let session = session.session.write().unwrap();
+        let channel = session.new_channel().unwrap();
+
+        Channel {
+            channel: RwLock::new(channel)
+        }
+    }
+    fn open_session(&self) {
+        let channel = self.channel.write().unwrap();
+        channel.open_session().unwrap();
+    }
+    fn is_open(&self) -> bool {
+        let channel = self.channel.write().unwrap();
+        channel.is_open()
+    }
+
+    fn close(&self) {
+        let channel = self.channel.write().unwrap();
+        channel.close().unwrap();
+    }
+
+    fn request_exec(&self, command: String) {
+        let channel = self.channel.write().unwrap();
+        channel.request_exec(&command).unwrap();
+    }
+
+    fn poll_has_bytes(&self, is_stderr: bool) -> bool {
+        let channel = self.channel.write().unwrap();
+        let poll_timeout = channel.poll_timeout(is_stderr, None).unwrap();
+
+        match poll_timeout {
+            PollStatus::AvailableBytes(count) => count > 0,
+            PollStatus::EndOfFile => false
+        }
+    }
+
+    fn read(&self, is_stderr: bool, len: u64) ->  ReadResult {
+        let ulen = len as usize;
+
+        let channel = self.channel.write().unwrap();
+
+        let mut buffer = vec![0; ulen];
+        let read = channel.read_timeout(&mut buffer, is_stderr, None).unwrap();
+
+        ReadResult {
+            read_count: read as u64,
+            data: buffer,
+        }
+    }
+
+    fn write_byte(&self, byte: i32) {
+        let channel = self.channel.write().unwrap();
+        channel.stdin().write_all(&byte.to_ne_bytes()).unwrap();
+    }
+
+    fn write_bytes(&self, data: Vec<u8>) {
+        let channel = self.channel.write().unwrap();
+        channel.stdin().write_all(&data).unwrap();
+    }
+}
+
+pub struct ReadResult {
+    read_count: u64,
+    data: Vec<u8>,
+}
\ No newline at end of file
diff --git a/rs/src/repository_watcher.udl b/rs/src/repository_watcher.udl
deleted file mode 100644
index 163bab0..0000000
--- a/rs/src/repository_watcher.udl
+++ /dev/null
@@ -1,20 +0,0 @@
-namespace gitnuro {
-    [Throws=WatcherInitError]
-    void watch_directory(string path, WatchDirectoryNotifier checker);
-};
-
-callback interface WatchDirectoryNotifier {
-    boolean should_keep_looping();
-
-    void detected_change(sequence<string> paths);
-};
-
-[Error]
-interface WatcherInitError {
-    Generic(string error);
-    Io(string error);
-    PathNotFound();
-    WatchNotFound();
-    InvalidConfig();
-    MaxFilesWatch();
-};
diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/credentials/GProcessLibSsh.kt b/src/main/kotlin/com/jetpackduba/gitnuro/credentials/GProcessLibSsh.kt
index ecc681b..80dba1c 100644
--- a/src/main/kotlin/com/jetpackduba/gitnuro/credentials/GProcessLibSsh.kt
+++ b/src/main/kotlin/com/jetpackduba/gitnuro/credentials/GProcessLibSsh.kt
@@ -1,13 +1,14 @@
 package com.jetpackduba.gitnuro.credentials
 
 import com.jetpackduba.gitnuro.ssh.libssh.LibSshChannel
-import com.jetpackduba.gitnuro.ssh.libssh.LibSshSession
+import uniffi.gitnuro.Channel
+import uniffi.gitnuro.Session
 import java.io.InputStream
 import java.io.OutputStream
 
 class GProcessLibSsh : Process() {
     private lateinit var channel: LibSshChannel
-    private lateinit var session: LibSshSession
+    private lateinit var session: Session
 
     private val outputStream by lazy {
         channel.outputStream
@@ -42,7 +43,9 @@ class GProcessLibSsh : Process() {
         check(!isRunning())
         println("exitValue called")
 
-        return channel.close()
+        channel.close()
+
+        return 0
     }
 
     override fun destroy() {
@@ -57,8 +60,8 @@ class GProcessLibSsh : Process() {
         return channel.isOpen()
     }
 
-    fun setup(session: LibSshSession, commandName: String) {
-        val channel = session.createChannel()
+    fun setup(session: Session, commandName: String) {
+        val channel = LibSshChannel(session)
 
         channel.openSession()
         channel.requestExec(commandName)
diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/credentials/GRemoteSession.kt b/src/main/kotlin/com/jetpackduba/gitnuro/credentials/GRemoteSession.kt
index 4d77843..292fc9b 100644
--- a/src/main/kotlin/com/jetpackduba/gitnuro/credentials/GRemoteSession.kt
+++ b/src/main/kotlin/com/jetpackduba/gitnuro/credentials/GRemoteSession.kt
@@ -1,21 +1,17 @@
 package com.jetpackduba.gitnuro.credentials
 
-import com.jetpackduba.gitnuro.ssh.libssh.LibSshOptions
-import com.jetpackduba.gitnuro.ssh.libssh.LibSshSession
-import kotlinx.coroutines.CancellationException
 import org.eclipse.jgit.transport.RemoteSession
 import org.eclipse.jgit.transport.URIish
+import uniffi.gitnuro.Session
 import javax.inject.Inject
-import javax.inject.Provider
 
 
 private const val DEFAULT_SSH_PORT = 22
 
 class GRemoteSession @Inject constructor(
-    private val processSession: Provider<LibSshSession>,
     private val credentialsStateManager: CredentialsStateManager,
 ) : RemoteSession {
-    private var session: LibSshSession? = null
+    private var session: Session? = null
 
     override fun exec(commandName: String, timeout: Int): Process {
         println("Running command $commandName")
@@ -32,44 +28,33 @@ class GRemoteSession @Inject constructor(
     }
 
     fun setup(uri: URIish) {
-        val session = processSession.get()
-        session.setOptions(LibSshOptions.SSH_OPTIONS_HOST, uri.host)
+        val session = Session()
+        session.setup(uri.host, uri.user, uri.port)
 
-        uri.user?.let {
-            session.setOptions(LibSshOptions.SSH_OPTIONS_USER, uri.user)
-        }
+        var result = session.publicKeyAuth()
 
-        session.setOptions(
-            LibSshOptions.SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES,
-            "ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,rsa-sha2-512,rsa-sha2-256,ssh-dss"
-        )
-        session.loadOptionsFromConfig()
-
-        session.connect()
-        var result = session.userAuthPublicKeyAuto(null, "")
-
-        if (result == 1) {
-            credentialsStateManager.updateState(CredentialsRequested.SshCredentialsRequested)
-
-            var credentials = credentialsStateManager.currentCredentialsState
-            while (credentials is CredentialsRequested) {
-                credentials = credentialsStateManager.currentCredentialsState
-            }
-
-            val password = if (credentials !is CredentialsAccepted.SshCredentialsAccepted)
-                throw CancellationException("Credentials cancelled")
-            else
-                credentials.password
-
-            result = session.userAuthPublicKeyAuto(null, password)
-
-            if (result != 0) {
-                result = session.userAuthPassword(password)
-            }
-        }
-
-        if (result != 0)
-            throw Exception("Something went wrong with authentication. Code $result")
+//        if (result == 1) {
+//            credentialsStateManager.updateState(CredentialsRequested.SshCredentialsRequested)
+//
+//            var credentials = credentialsStateManager.currentCredentialsState
+//            while (credentials is CredentialsRequested) {
+//                credentials = credentialsStateManager.currentCredentialsState
+//            }
+//
+//            val password = if (credentials !is CredentialsAccepted.SshCredentialsAccepted)
+//                throw CancellationException("Credentials cancelled")
+//            else
+//                credentials.password
+//
+//            result = session.userAuthPublicKeyAuto(null, password)
+//
+//            if (result != 0) {
+//                result = session.userAuthPassword(password)
+//            }
+//        }
+//
+//        if (result != 0)
+//            throw Exception("Something went wrong with authentication. Code $result")
 
         this.session = session
     }
diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/LibSshChannel.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/LibSshChannel.kt
index 97c6a94..cf60b67 100644
--- a/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/LibSshChannel.kt
+++ b/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/LibSshChannel.kt
@@ -3,30 +3,29 @@ package com.jetpackduba.gitnuro.ssh.libssh
 import com.jetpackduba.gitnuro.ssh.libssh.streams.LibSshChannelInputErrStream
 import com.jetpackduba.gitnuro.ssh.libssh.streams.LibSshChannelInputStream
 import com.jetpackduba.gitnuro.ssh.libssh.streams.LibSshChannelOutputStream
+import uniffi.gitnuro.Channel
+import uniffi.gitnuro.Session
 
-class LibSshChannel internal constructor(sshSession: ssh_session) {
-    private val sshLib = SSHLibrary.INSTANCE
-    private var channel: ssh_channel = sshLib.ssh_channel_new(sshSession)
+class LibSshChannel internal constructor(sshSession: Session) {
+    private var channel = Channel(sshSession)
 
     val outputStream = LibSshChannelOutputStream(channel)
     val inputStream = LibSshChannelInputStream(channel)
     val errorOutputStream = LibSshChannelInputErrStream(channel)
 
-
     fun openSession() {
-        sshLib.ssh_channel_open_session(channel)
+        channel.openSession()
     }
 
     fun requestExec(commandName: String) {
-        sshLib.ssh_channel_request_exec(channel, commandName)
+        channel.requestExec(commandName)
     }
 
     fun isOpen(): Boolean {
-        return sshLib.ssh_channel_is_open(channel) == 1
+        return channel.isOpen()
     }
 
-    fun close(): Int {
-        return sshLib.ssh_channel_close(channel)
+    fun close() {
+        channel.close()
     }
-
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/LibSshOptions.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/LibSshOptions.kt
deleted file mode 100644
index f98ed13..0000000
--- a/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/LibSshOptions.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.jetpackduba.gitnuro.ssh.libssh
-
-/**
- * Enum based on the enum "ssh_options_e" of libssh/libssh.h
- */
-enum class LibSshOptions {
-    SSH_OPTIONS_HOST,
-    SSH_OPTIONS_PORT,
-    SSH_OPTIONS_PORT_STR,
-    SSH_OPTIONS_FD,
-    SSH_OPTIONS_USER,
-    SSH_OPTIONS_SSH_DIR,
-    SSH_OPTIONS_IDENTITY,
-    SSH_OPTIONS_ADD_IDENTITY,
-    SSH_OPTIONS_KNOWNHOSTS,
-    SSH_OPTIONS_TIMEOUT,
-    SSH_OPTIONS_TIMEOUT_USEC,
-    SSH_OPTIONS_SSH1,
-    SSH_OPTIONS_SSH2,
-    SSH_OPTIONS_LOG_VERBOSITY,
-    SSH_OPTIONS_LOG_VERBOSITY_STR,
-    SSH_OPTIONS_CIPHERS_C_S,
-    SSH_OPTIONS_CIPHERS_S_C,
-    SSH_OPTIONS_COMPRESSION_C_S,
-    SSH_OPTIONS_COMPRESSION_S_C,
-    SSH_OPTIONS_PROXYCOMMAND,
-    SSH_OPTIONS_BINDADDR,
-    SSH_OPTIONS_STRICTHOSTKEYCHECK,
-    SSH_OPTIONS_COMPRESSION,
-    SSH_OPTIONS_COMPRESSION_LEVEL,
-    SSH_OPTIONS_KEY_EXCHANGE,
-    SSH_OPTIONS_HOSTKEYS,
-    SSH_OPTIONS_GSSAPI_SERVER_IDENTITY,
-    SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY,
-    SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS,
-    SSH_OPTIONS_HMAC_C_S,
-    SSH_OPTIONS_HMAC_S_C,
-    SSH_OPTIONS_PASSWORD_AUTH,
-    SSH_OPTIONS_PUBKEY_AUTH,
-    SSH_OPTIONS_KBDINT_AUTH,
-    SSH_OPTIONS_GSSAPI_AUTH,
-    SSH_OPTIONS_GLOBAL_KNOWNHOSTS,
-    SSH_OPTIONS_NODELAY,
-    SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES,
-    SSH_OPTIONS_PROCESS_CONFIG,
-    SSH_OPTIONS_REKEY_DATA,
-    SSH_OPTIONS_REKEY_TIME,
-    SSH_OPTIONS_RSA_MIN_SIZE,
-    SSH_OPTIONS_IDENTITY_AGENT
-}
\ No newline at end of file
diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/LibSshSession.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/LibSshSession.kt
deleted file mode 100644
index 7720540..0000000
--- a/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/LibSshSession.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.jetpackduba.gitnuro.ssh.libssh
-
-import com.jetpackduba.gitnuro.logging.printError
-import com.jetpackduba.gitnuro.ssh.libssh.streams.checkValidResult
-import javax.inject.Inject
-
-private const val TAG = "LibSshSession"
-
-class LibSshSession @Inject constructor() {
-    private val sshLib = SSHLibrary.INSTANCE
-
-    private var session: ssh_session = sshLib.ssh_new()
-    private var channel: LibSshChannel? = null
-
-    fun setOptions(option: LibSshOptions, value: String) {
-        sshLib.ssh_options_set(session, option.ordinal, value)
-    }
-
-    fun loadOptionsFromConfig() {
-        checkValidResult("loadOptionsFromConfig", sshLib.ssh_options_parse_config(session, null))
-    }
-
-    fun connect() {
-        sshLib.ssh_connect(session)
-    }
-
-    fun userAuthPublicKeyAuto(username: String?, password: String?): Int {
-        val result = sshLib.ssh_userauth_publickey_auto(session, username, password)
-
-        if (result != 0)
-            printError(TAG, "Result is: $result.\nError is: ${getError()}")
-
-        return result
-    }
-
-    fun userAuthPassword(password: String): Int {
-        val result = sshLib.ssh_userauth_password(session, null, password)
-
-        if (result != 0)
-            printError(TAG, "Result is: $result.\nError is: ${getError()}")
-
-        return result
-    }
-
-    fun createChannel(): LibSshChannel {
-        val newChannel = LibSshChannel(session)
-
-        this.channel = newChannel
-
-        return newChannel
-    }
-
-    private fun getError(): String {
-        return sshLib.ssh_get_error(session)
-    }
-
-    fun disconnect() {
-        sshLib.ssh_disconnect(session)
-    }
-}
-
-
diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/LibSshWrapper.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/LibSshWrapper.kt
deleted file mode 100644
index eafc8d3..0000000
--- a/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/LibSshWrapper.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.jetpackduba.gitnuro.ssh.libssh
-
-import com.sun.jna.Library
-import com.sun.jna.Native
-import com.sun.jna.PointerType
-
-class ssh_session : PointerType()
-class ssh_channel : PointerType()
-
-@Suppress("FunctionName")
-interface SSHLibrary : Library {
-    fun ssh_new(): ssh_session
-    fun ssh_disconnect(session: ssh_session): ssh_session
-    fun ssh_options_set(session: ssh_session, enumValue: Int, value: String)
-
-    fun ssh_options_parse_config(session: ssh_session, fileName: String?): Int
-
-    fun ssh_connect(session: ssh_session): Int
-
-    fun ssh_userauth_publickey_auto(session: ssh_session, username: String?, password: String?): Int
-    fun ssh_userauth_password(session: ssh_session, username: String?, password: String?): Int
-    fun ssh_get_error(session: ssh_session): String
-
-    fun ssh_channel_new(sshSession: ssh_session): ssh_channel
-
-    fun ssh_channel_open_session(sshChannel: ssh_channel): Int
-
-    fun ssh_channel_request_exec(sshChannel: ssh_channel, command: String): Int
-
-    fun ssh_channel_read(sshChannel: ssh_channel, buffer: ByteArray, count: Int, isStderr: Int): Int
-
-    fun ssh_channel_poll(sshChannel: ssh_channel, isStderr: Int): Int
-
-    fun ssh_channel_write(sshChannel: ssh_channel, data: ByteArray, len: Int): Int
-
-    fun ssh_channel_close(sshChannel: ssh_channel): Int
-
-    fun ssh_channel_is_open(sshChannel: ssh_channel): Int
-
-
-    companion object {
-        val INSTANCE = Native.load("ssh", SSHLibrary::class.java) as SSHLibrary
-    }
-}
\ No newline at end of file
diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/streams/LibSshChannelInputErrStream.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/streams/LibSshChannelInputErrStream.kt
index 4faaed4..49b4ebb 100644
--- a/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/streams/LibSshChannelInputErrStream.kt
+++ b/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/streams/LibSshChannelInputErrStream.kt
@@ -1,20 +1,17 @@
 package com.jetpackduba.gitnuro.ssh.libssh.streams
 
-import com.jetpackduba.gitnuro.ssh.libssh.SSHLibrary
-import com.jetpackduba.gitnuro.ssh.libssh.ssh_channel
+import uniffi.gitnuro.Channel
 import java.io.InputStream
 
-class LibSshChannelInputErrStream(private val sshChannel: ssh_channel) : InputStream() {
+class LibSshChannelInputErrStream(private val sshChannel: Channel) : InputStream() {
     private var cancelled = false
-    private val sshLib = SSHLibrary.INSTANCE
 
     override fun read(): Int {
-        val buffer = ByteArray(1)
+        return if (sshChannel.pollHasBytes(true)) {
+            val read = sshChannel.read(true, 1u)
+            val byteArray = read.data
 
-        return if (sshLib.ssh_channel_poll(sshChannel, 1) > 0) {
-            sshLib.ssh_channel_read(sshChannel, buffer, 1, 1)
-
-            val first = buffer.first()
+            val first = byteArray.first()
 
             first.toInt()
         } else
diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/streams/LibSshChannelInputStream.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/streams/LibSshChannelInputStream.kt
index 34389ad..5af2833 100644
--- a/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/streams/LibSshChannelInputStream.kt
+++ b/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/streams/LibSshChannelInputStream.kt
@@ -1,28 +1,26 @@
 package com.jetpackduba.gitnuro.ssh.libssh.streams
 
-import com.jetpackduba.gitnuro.ssh.libssh.SSHLibrary
-import com.jetpackduba.gitnuro.ssh.libssh.ssh_channel
+import uniffi.gitnuro.Channel
 import java.io.InputStream
 
-class LibSshChannelInputStream(private val sshChannel: ssh_channel) : InputStream() {
-    private val sshLib = SSHLibrary.INSTANCE
-
+class LibSshChannelInputStream(private val sshChannel: Channel) : InputStream() {
     override fun read(b: ByteArray, off: Int, len: Int): Int {
-        val byteArray = ByteArray(len)
-        val result = sshLib.ssh_channel_read(sshChannel, byteArray, len, 0)
+        val result = sshChannel.read(false, len.toULong())
+        val byteArray = result.data
+        val read = result.readCount
+
         for (i in 0 until len) {
             b[off + i] = byteArray[i]
         }
 
-        return result
+        return read.toInt()
     }
 
     override fun read(): Int {
-        val buffer = ByteArray(1)
 
-        sshLib.ssh_channel_read(sshChannel, buffer, 1, 0)
+        val result = sshChannel.read(false, 1u)
 
-        val first = buffer.first()
+        val first = result.data.first()
 
         return first.toInt()
     }
diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/streams/LibSshChannelOutputStream.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/streams/LibSshChannelOutputStream.kt
index fed94e9..9293c9c 100644
--- a/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/streams/LibSshChannelOutputStream.kt
+++ b/src/main/kotlin/com/jetpackduba/gitnuro/ssh/libssh/streams/LibSshChannelOutputStream.kt
@@ -1,26 +1,18 @@
 package com.jetpackduba.gitnuro.ssh.libssh.streams
 
-import com.jetpackduba.gitnuro.ssh.libssh.SSHLibrary
-import com.jetpackduba.gitnuro.ssh.libssh.ssh_channel
+import uniffi.gitnuro.Channel
 import java.io.OutputStream
 
-class LibSshChannelOutputStream(private val sshChannel: ssh_channel) : OutputStream() {
-    private val sshLib = SSHLibrary.INSTANCE
-
+class LibSshChannelOutputStream(private val sshChannel: Channel) : OutputStream() {
     override fun write(b: Int) {
         val byteArrayData = byteArrayOf(b.toByte())
         write(byteArrayData)
     }
 
     override fun write(b: ByteArray) {
-        sshLib.ssh_channel_write(sshChannel, b, b.size)
+        sshChannel.writeBytes(b)
     }
 
     override fun close() {
     }
 }
-
-fun checkValidResult(tag: String, result: Int) {
-    if (result != 0)
-        throw Exception("$tag - Result is $result")
-}
\ No newline at end of file