Added basic clone code and ssh authentication code using Apache SSHD

This commit is contained in:
Abdelilah El Aissaoui 2021-10-02 18:08:33 +02:00
parent ef39c6f6d5
commit 54f013d291
6 changed files with 207 additions and 0 deletions

View file

@ -21,6 +21,7 @@ repositories {
dependencies { dependencies {
implementation(compose.desktop.currentOs) implementation(compose.desktop.currentOs)
implementation("org.eclipse.jgit:org.eclipse.jgit:5.13.0.202109080827-r") implementation("org.eclipse.jgit:org.eclipse.jgit:5.13.0.202109080827-r")
implementation("org.apache.sshd:sshd-core:2.7.0")
} }
tasks.withType<KotlinCompile>() { tasks.withType<KotlinCompile>() {

View file

@ -0,0 +1,11 @@
package credentials
class CredentialsStateManager {
}
sealed class CredentialsState {
object CredentialsRequested: CredentialsState()
object CredentialsDenied: CredentialsState()
data class CredentialsAccepted(val user: String, val password: String): CredentialsState()
}

View file

@ -0,0 +1,65 @@
package credentials
import org.apache.sshd.client.channel.ChannelExec
import org.apache.sshd.client.session.ClientSession
import java.io.InputStream
import java.io.OutputStream
import java.io.PipedInputStream
import java.io.PipedOutputStream
class GProcess : Process() {
private lateinit var channel: ChannelExec
private val outputStream = PipedOutputStream()
private val inputStream = PipedInputStream()
private val errorOutputStream = PipedOutputStream()
private val pipedInputStream = PipedInputStream(outputStream)
private val pipedOutputStream = PipedOutputStream(inputStream)
private val pipedErrorInputStream = PipedInputStream(errorOutputStream)
override fun getOutputStream(): OutputStream {
return pipedOutputStream
}
override fun getInputStream(): InputStream {
return pipedInputStream
}
override fun getErrorStream(): InputStream {
return pipedErrorInputStream
}
override fun waitFor(): Int {
if (isRunning())
Thread.sleep(100)
return exitValue()
}
override fun exitValue(): Int {
check(!isRunning())
return channel.exitStatus
}
override fun destroy() {
if (channel.isOpen) {
channel.close()
}
}
private fun isRunning(): Boolean {
return channel.exitStatus < 0 && channel.isOpen
}
fun setup(session: ClientSession, commandName: String) {
val channel = session.createExecChannel(commandName)
channel.out = outputStream
channel.err = errorOutputStream
channel.`in` = inputStream
channel.open().verify()
this.channel = channel
}
}

View file

@ -0,0 +1,45 @@
package credentials
import org.apache.sshd.client.SshClient
import org.apache.sshd.client.future.ConnectFuture
import org.eclipse.jgit.transport.RemoteSession
import org.eclipse.jgit.transport.URIish
import java.io.PipedInputStream
import java.io.PipedOutputStream
private const val DEFAULT_SSH_PORT = 22
class GRemoteSession : RemoteSession {
private val client = SshClient.setUpDefaultClient()
private var connectFuture: ConnectFuture? = null
override fun exec(commandName: String, timeout: Int): Process {
println(commandName)
val connectFuture = checkNotNull(connectFuture)
val session = connectFuture.clientSession
session.auth().verify()
val process = GProcess()
process.setup(session, commandName)
return process
}
override fun disconnect() {
client.close()
}
fun setup(uri: URIish) {
client.open()
val port = if (uri.port == -1) {
DEFAULT_SSH_PORT
} else
uri.port
val connectFuture = client.connect(uri.user, uri.host, port)
connectFuture.await()
this.connectFuture = connectFuture
}
}

View file

@ -0,0 +1,29 @@
package credentials
import org.eclipse.jgit.transport.CredentialsProvider
import org.eclipse.jgit.transport.RemoteSession
import org.eclipse.jgit.transport.SshSessionFactory
import org.eclipse.jgit.transport.URIish
import org.eclipse.jgit.util.FS
class GSessionManager {
fun generateSshSessionFactory(): SshSessionFactory {
return object : SshSessionFactory() {
override fun getSession(
uri: URIish,
credentialsProvider: CredentialsProvider?,
fs: FS?,
tms: Int
): RemoteSession {
val remoteSession = GRemoteSession()
remoteSession.setup(uri)
return remoteSession
}
override fun getType(): String {
return "ssh" //TODO What should be the value of this?
}
}
}
}

View file

@ -0,0 +1,56 @@
package git
import credentials.GRemoteSession
import credentials.GSessionManager
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.transport.*
import org.eclipse.jgit.util.FS
import java.io.File
import java.io.IOException
private const val REMOTE_URL = ""
class CloneManager {
private val sessionManager = GSessionManager()
fun cloneTest() {
// prepare a new folder for the cloned repository
// prepare a new folder for the cloned repository
val localPath = File.createTempFile("TestGitRepository", "")
if (!localPath.delete()) {
throw IOException("Could not delete temporary file $localPath")
}
Git.cloneRepository()
.setURI(REMOTE_URL)
.setDirectory(localPath)
.setTransportConfigCallback {
if (it is SshTransport) {
it.sshSessionFactory = sessionManager.generateSshSessionFactory()
} else if (it is HttpTransport) {
it.credentialsProvider = object : CredentialsProvider() {
override fun isInteractive(): Boolean {
return true
}
override fun supports(vararg items: CredentialItem?): Boolean {
println(items)
return true
}
override fun get(uri: URIish?, vararg items: CredentialItem?): Boolean {
return true
}
}
}
}
.call().use { result ->
// Note: the call() returns an opened repository already which needs to be closed to avoid file handle leaks!
println("Having repository: " + result.repository.directory)
}
}
}