Added basic error and port handling

This commit is contained in:
Abdelilah El Aissaoui 2023-09-20 15:40:31 +02:00
parent 6dee4fbc93
commit 865109d8d4
No known key found for this signature in database
GPG key ID: 7587FC860F594869
12 changed files with 135 additions and 121 deletions

View file

@ -19,12 +19,20 @@ interface WatcherInitError {
MaxFilesWatch();
};
enum AuthStatus {
"Success",
"Denied",
"Partial",
"Info",
"Again",
};
interface Session {
constructor();
void setup(string host, string? user, i32 port);
void public_key_auth();
void password_auth(string password);
void setup(string host, string? user, u16? port);
AuthStatus public_key_auth(string password);
AuthStatus password_auth(string password);
void disconnect();
};

View file

@ -7,9 +7,10 @@ use std::sync::mpsc::{channel, RecvTimeoutError};
use std::sync::{Arc, RwLock};
use std::time::Duration;
use libssh_rs::{PollStatus, SshOption};
use libssh_rs::{AuthStatus, PollStatus, SshOption};
use notify::{Config, Error, ErrorKind, Event, RecommendedWatcher, RecursiveMode, 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";
@ -133,7 +134,7 @@ impl Session {
}
}
fn setup(&self, host: String, user: Option<String>, port: i32) {
fn setup(&self, host: String, user: Option<String>, port: Option<u16>) {
let session = self.session.write().unwrap();
session.set_option(SshOption::Hostname(host)).unwrap();
@ -141,7 +142,7 @@ impl Session {
session.set_option(SshOption::User(Some(user))).unwrap();
}
if let Ok(port) = port.try_into() {
if let Some(port) = port {
session.set_option(SshOption::Port(port)).unwrap();
}
@ -150,14 +151,21 @@ impl Session {
session.connect().unwrap();
}
fn public_key_auth(&self) {
fn public_key_auth(&self, password: String) -> AuthStatus {
println!("Public key auth");
let session = self.session.write().unwrap();
session.userauth_public_key_auto(None, Some("")).unwrap();
let status = session.userauth_public_key_auto(None, Some(&password)).unwrap();
println!("Status is {status:?}");
status
}
fn password_auth(&self, password: String) {
fn password_auth(&self, password: String) -> AuthStatus {
let session = self.session.write().unwrap();
session.userauth_password(None, Some(&password)).unwrap();
session.userauth_password(None, Some(&password)).unwrap()
}
fn disconnect(&self) {

View file

@ -1,61 +0,0 @@
package com.jetpackduba.gitnuro.credentials
import org.eclipse.jgit.transport.RemoteSession
import org.eclipse.jgit.transport.URIish
import uniffi.gitnuro.Session
import javax.inject.Inject
private const val DEFAULT_SSH_PORT = 22
class GRemoteSession @Inject constructor(
private val credentialsStateManager: CredentialsStateManager,
) : RemoteSession {
private var session: Session? = null
override fun exec(commandName: String, timeout: Int): Process {
println("Running command $commandName")
val session = this.session ?: throw Exception("Session is null")
val process = GProcessLibSsh()
process.setup(session, commandName)
return process
}
override fun disconnect() {
session?.disconnect()
}
fun setup(uri: URIish) {
val session = Session()
session.setup(uri.host, uri.user, uri.port)
var result = session.publicKeyAuth()
// 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
}
}

View file

@ -18,7 +18,7 @@ class GSessionManager @Inject constructor(
}
class MySessionFactory @Inject constructor(
private val sessionProvider: Provider<GRemoteSession>
private val sessionProvider: Provider<SshRemoteSession>
) : SshSessionFactory(), CredentialsCache {
override fun getSession(
uri: URIish,

View file

@ -1,13 +1,12 @@
package com.jetpackduba.gitnuro.credentials
import com.jetpackduba.gitnuro.ssh.libssh.LibSshChannel
import uniffi.gitnuro.Channel
import com.jetpackduba.gitnuro.ssh.libssh.ChannelWrapper
import uniffi.gitnuro.Session
import java.io.InputStream
import java.io.OutputStream
class GProcessLibSsh : Process() {
private lateinit var channel: LibSshChannel
class SshProcess : Process() {
private lateinit var channel: ChannelWrapper
private lateinit var session: Session
private val outputStream by lazy {
@ -61,7 +60,7 @@ class GProcessLibSsh : Process() {
}
fun setup(session: Session, commandName: String) {
val channel = LibSshChannel(session)
val channel = ChannelWrapper(session)
channel.openSession()
channel.requestExec(commandName)

View file

@ -0,0 +1,70 @@
package com.jetpackduba.gitnuro.credentials
import org.eclipse.jgit.transport.RemoteSession
import org.eclipse.jgit.transport.URIish
import uniffi.gitnuro.AuthStatus
import uniffi.gitnuro.Session
import java.util.concurrent.CancellationException
import javax.inject.Inject
private const val DEFAULT_SSH_PORT = 22
private const val NOT_EXPLICIT_PORT = -1
class SshRemoteSession @Inject constructor(
private val credentialsStateManager: CredentialsStateManager,
) : RemoteSession {
private var session: Session? = null
override fun exec(commandName: String, timeout: Int): Process {
println("Running command $commandName")
val session = this.session ?: throw Exception("Session is null")
val process = SshProcess()
process.setup(session, commandName)
return process
}
override fun disconnect() {
session?.disconnect()
}
fun setup(uri: URIish) {
val session = Session()
val port = if (uri.port == NOT_EXPLICIT_PORT) {
null
} else
uri.port
session.setup(uri.host, uri.user, port?.toUShort())
var result = session.publicKeyAuth("")
if (result == AuthStatus.DENIED) {
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.publicKeyAuth(password)
if (result != AuthStatus.SUCCESS) {
result = session.passwordAuth(password)
}
}
if (result != AuthStatus.SUCCESS)
throw Exception("Something went wrong with authentication. Code $result")
this.session = session
}
}

View file

@ -0,0 +1,31 @@
package com.jetpackduba.gitnuro.ssh.libssh
import com.jetpackduba.gitnuro.ssh.libssh.streams.SshChannelInputErrStream
import com.jetpackduba.gitnuro.ssh.libssh.streams.SshChannelInputStream
import com.jetpackduba.gitnuro.ssh.libssh.streams.SshChannelOutputStream
import uniffi.gitnuro.Channel
import uniffi.gitnuro.Session
class ChannelWrapper internal constructor(sshSession: Session) {
private var channel = Channel(sshSession)
val outputStream = SshChannelOutputStream(channel)
val inputStream = SshChannelInputStream(channel)
val errorOutputStream = SshChannelInputErrStream(channel)
fun openSession() {
channel.openSession()
}
fun requestExec(commandName: String) {
channel.requestExec(commandName)
}
fun isOpen(): Boolean {
return channel.isOpen()
}
fun close() {
channel.close()
}
}

View file

@ -1,10 +0,0 @@
package com.jetpackduba.gitnuro.ssh.libssh
enum class sshAuthE(val value: Int) {
SSH_AUTH_SUCCESS(0),
SSH_AUTH_DENIED(1),
SSH_AUTH_PARTIAL(2),
SSH_AUTH_INFO(3),
SSH_AUTH_AGAIN(4),
SSH_AUTH_ERROR(-1)
}

View file

@ -1,31 +0,0 @@
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: Session) {
private var channel = Channel(sshSession)
val outputStream = LibSshChannelOutputStream(channel)
val inputStream = LibSshChannelInputStream(channel)
val errorOutputStream = LibSshChannelInputErrStream(channel)
fun openSession() {
channel.openSession()
}
fun requestExec(commandName: String) {
channel.requestExec(commandName)
}
fun isOpen(): Boolean {
return channel.isOpen()
}
fun close() {
channel.close()
}
}

View file

@ -3,7 +3,7 @@ package com.jetpackduba.gitnuro.ssh.libssh.streams
import uniffi.gitnuro.Channel
import java.io.InputStream
class LibSshChannelInputErrStream(private val sshChannel: Channel) : InputStream() {
class SshChannelInputErrStream(private val sshChannel: Channel) : InputStream() {
private var cancelled = false
override fun read(): Int {

View file

@ -3,7 +3,7 @@ package com.jetpackduba.gitnuro.ssh.libssh.streams
import uniffi.gitnuro.Channel
import java.io.InputStream
class LibSshChannelInputStream(private val sshChannel: Channel) : InputStream() {
class SshChannelInputStream(private val sshChannel: Channel) : InputStream() {
override fun read(b: ByteArray, off: Int, len: Int): Int {
val result = sshChannel.read(false, len.toULong())
val byteArray = result.data

View file

@ -3,7 +3,7 @@ package com.jetpackduba.gitnuro.ssh.libssh.streams
import uniffi.gitnuro.Channel
import java.io.OutputStream
class LibSshChannelOutputStream(private val sshChannel: Channel) : OutputStream() {
class SshChannelOutputStream(private val sshChannel: Channel) : OutputStream() {
override fun write(b: Int) {
val byteArrayData = byteArrayOf(b.toByte())
write(byteArrayData)