Added basic error and port handling
This commit is contained in:
parent
6dee4fbc93
commit
865109d8d4
12 changed files with 135 additions and 121 deletions
|
@ -19,12 +19,20 @@ interface WatcherInitError {
|
||||||
MaxFilesWatch();
|
MaxFilesWatch();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum AuthStatus {
|
||||||
|
"Success",
|
||||||
|
"Denied",
|
||||||
|
"Partial",
|
||||||
|
"Info",
|
||||||
|
"Again",
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
interface Session {
|
interface Session {
|
||||||
constructor();
|
constructor();
|
||||||
void setup(string host, string? user, i32 port);
|
void setup(string host, string? user, u16? port);
|
||||||
void public_key_auth();
|
AuthStatus public_key_auth(string password);
|
||||||
void password_auth(string password);
|
AuthStatus password_auth(string password);
|
||||||
void disconnect();
|
void disconnect();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,10 @@ use std::sync::mpsc::{channel, RecvTimeoutError};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use libssh_rs::{PollStatus, SshOption};
|
use libssh_rs::{AuthStatus, PollStatus, SshOption};
|
||||||
use notify::{Config, Error, ErrorKind, Event, RecommendedWatcher, RecursiveMode, Watcher};
|
use notify::{Config, Error, ErrorKind, Event, RecommendedWatcher, RecursiveMode, Watcher};
|
||||||
|
|
||||||
|
|
||||||
uniffi::include_scaffolding!("gitnuro");
|
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";
|
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();
|
let session = self.session.write().unwrap();
|
||||||
session.set_option(SshOption::Hostname(host)).unwrap();
|
session.set_option(SshOption::Hostname(host)).unwrap();
|
||||||
|
|
||||||
|
@ -141,7 +142,7 @@ impl Session {
|
||||||
session.set_option(SshOption::User(Some(user))).unwrap();
|
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();
|
session.set_option(SshOption::Port(port)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,14 +151,21 @@ impl Session {
|
||||||
session.connect().unwrap();
|
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();
|
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();
|
let session = self.session.write().unwrap();
|
||||||
session.userauth_password(None, Some(&password)).unwrap();
|
session.userauth_password(None, Some(&password)).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disconnect(&self) {
|
fn disconnect(&self) {
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -18,7 +18,7 @@ class GSessionManager @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
class MySessionFactory @Inject constructor(
|
class MySessionFactory @Inject constructor(
|
||||||
private val sessionProvider: Provider<GRemoteSession>
|
private val sessionProvider: Provider<SshRemoteSession>
|
||||||
) : SshSessionFactory(), CredentialsCache {
|
) : SshSessionFactory(), CredentialsCache {
|
||||||
override fun getSession(
|
override fun getSession(
|
||||||
uri: URIish,
|
uri: URIish,
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
package com.jetpackduba.gitnuro.credentials
|
package com.jetpackduba.gitnuro.credentials
|
||||||
|
|
||||||
import com.jetpackduba.gitnuro.ssh.libssh.LibSshChannel
|
import com.jetpackduba.gitnuro.ssh.libssh.ChannelWrapper
|
||||||
import uniffi.gitnuro.Channel
|
|
||||||
import uniffi.gitnuro.Session
|
import uniffi.gitnuro.Session
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
class GProcessLibSsh : Process() {
|
class SshProcess : Process() {
|
||||||
private lateinit var channel: LibSshChannel
|
private lateinit var channel: ChannelWrapper
|
||||||
private lateinit var session: Session
|
private lateinit var session: Session
|
||||||
|
|
||||||
private val outputStream by lazy {
|
private val outputStream by lazy {
|
||||||
|
@ -61,7 +60,7 @@ class GProcessLibSsh : Process() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setup(session: Session, commandName: String) {
|
fun setup(session: Session, commandName: String) {
|
||||||
val channel = LibSshChannel(session)
|
val channel = ChannelWrapper(session)
|
||||||
|
|
||||||
channel.openSession()
|
channel.openSession()
|
||||||
channel.requestExec(commandName)
|
channel.requestExec(commandName)
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
|
||||||
}
|
|
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,7 +3,7 @@ package com.jetpackduba.gitnuro.ssh.libssh.streams
|
||||||
import uniffi.gitnuro.Channel
|
import uniffi.gitnuro.Channel
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
class LibSshChannelInputErrStream(private val sshChannel: Channel) : InputStream() {
|
class SshChannelInputErrStream(private val sshChannel: Channel) : InputStream() {
|
||||||
private var cancelled = false
|
private var cancelled = false
|
||||||
|
|
||||||
override fun read(): Int {
|
override fun read(): Int {
|
|
@ -3,7 +3,7 @@ package com.jetpackduba.gitnuro.ssh.libssh.streams
|
||||||
import uniffi.gitnuro.Channel
|
import uniffi.gitnuro.Channel
|
||||||
import java.io.InputStream
|
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 {
|
override fun read(b: ByteArray, off: Int, len: Int): Int {
|
||||||
val result = sshChannel.read(false, len.toULong())
|
val result = sshChannel.read(false, len.toULong())
|
||||||
val byteArray = result.data
|
val byteArray = result.data
|
|
@ -3,7 +3,7 @@ package com.jetpackduba.gitnuro.ssh.libssh.streams
|
||||||
import uniffi.gitnuro.Channel
|
import uniffi.gitnuro.Channel
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
class LibSshChannelOutputStream(private val sshChannel: Channel) : OutputStream() {
|
class SshChannelOutputStream(private val sshChannel: Channel) : OutputStream() {
|
||||||
override fun write(b: Int) {
|
override fun write(b: Int) {
|
||||||
val byteArrayData = byteArrayOf(b.toByte())
|
val byteArrayData = byteArrayOf(b.toByte())
|
||||||
write(byteArrayData)
|
write(byteArrayData)
|
Loading…
Reference in a new issue