Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[*.{kt,kts}]
ij_kotlin_allow_trailing_comma = false
ij_kotlin_allow_trailing_comma_on_call_site = false
ktlint_code_style = intellij_idea
ktlint_standard_no-unused-imports = enabled
22 changes: 11 additions & 11 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
kotlin("jvm") version "2.1.0"
kotlin("plugin.spring") version "2.1.0"
kotlin("jvm") version "2.4.0"
kotlin("plugin.spring") version "2.4.0"
id("jacoco")
id("org.jmailen.kotlinter") version "5.3.0"
id("org.jmailen.kotlinter") version "5.5.0"
id("com.adarshr.test-logger") version "4.0.0"
id("com.github.ben-manes.versions") version "0.53.0"
id("com.github.ben-manes.versions") version "0.54.0"
id("org.springframework.boot") version "4.0.1"
id("io.spring.dependency-management") version "1.1.7"
id("maven-publish")
id("net.thebugmc.gradle.sonatype-central-portal-publisher") version "1.2.4"
}

group = "com.valensas"
version = "0.2.24"

java.sourceCompatibility = JavaVersion.VERSION_21

Expand All @@ -34,21 +34,21 @@ dependencies {
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
implementation("com.valensas:graalvm-native-support:1.0.8")
implementation("com.valensas:graalvm-native-support:1.1.0")

// Ftp
implementation("commons-net:commons-net:3.12.0")
implementation("com.github.mwiede:jsch:2.27.7")
implementation("commons-net:commons-net:3.13.0")
implementation("com.github.mwiede:jsch:2.28.3")
implementation("org.apache.sshd:sshd-core:2.16.0")
implementation("org.apache.sshd:sshd-common:2.16.0")
implementation("org.apache.sshd:sshd-sftp:2.16.0")
implementation("org.apache.ftpserver:ftpserver-core:1.2.1")
}

tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs += "-Xjsr305=strict"
jvmTarget = "21"
compilerOptions {
freeCompilerArgs.add("-Xjsr305=strict")
jvmTarget.set(JvmTarget.JVM_21)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ import org.springframework.context.annotation.ImportRuntimeHints
@Configuration
@ImportRuntimeHints(
CustomRuntimeHintsRegistrar::class,
JschRuntimeHintsRegistrar::class,
JschRuntimeHintsRegistrar::class
)
class RuntimeHintsAutoConfiguration
13 changes: 6 additions & 7 deletions src/main/kotlin/com/valensas/ftp/factory/FtpClientFactory.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ import com.valensas.ftp.model.SFTPClient
class FtpClientFactory {
fun createFtpClient(
type: ConnectionType,
variant: ConnectionVariant? = null,
): FTPClient =
when (type) {
ConnectionType.FTP -> FTPClient()
ConnectionType.FTPS -> FTPSClient(variant == ConnectionVariant.Implicit)
ConnectionType.SFTP -> SFTPClient()
}
variant: ConnectionVariant? = null
): FTPClient = when (type) {
ConnectionType.FTP -> FTPClient()
ConnectionType.FTPS -> FTPSClient(variant == ConnectionVariant.Implicit)
ConnectionType.SFTP -> SFTPClient()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ class CustomRuntimeHintsRegistrar : RuntimeHintsRegistrar {

override fun registerHints(
hints: RuntimeHints,
classLoader: ClassLoader?,
classLoader: ClassLoader?
) {
val packages = listOf("com.valensas.ftp.model")

logger.info(
"Setting reflection hints for classes in packages: {}",
packages.joinToString(", "),
packages.joinToString(", ")
)

TypeScanner
Expand All @@ -32,7 +32,7 @@ class CustomRuntimeHintsRegistrar : RuntimeHintsRegistrar {
HintUtils.registerSerializationHints(
hints,
clazz,
classLoader,
classLoader
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import org.springframework.aot.hint.RuntimeHintsRegistrar
class JschRuntimeHintsRegistrar : RuntimeHintsRegistrar {
override fun registerHints(
hints: RuntimeHints,
classLoader: ClassLoader?,
classLoader: ClassLoader?
) {
val reflection = hints.reflection()

Expand All @@ -19,12 +19,12 @@ class JschRuntimeHintsRegistrar : RuntimeHintsRegistrar {
"javax.crypto.KeyAgreement",
"java.security.MessageDigest",
"java.security.KeyPairGenerator",
"java.security.Signature",
"java.security.Signature"
).forEach {
reflection.registerTypeIfPresent(
classLoader,
it,
::configureForReflection,
::configureForReflection
)
}

Expand Down Expand Up @@ -59,14 +59,14 @@ class JschRuntimeHintsRegistrar : RuntimeHintsRegistrar {
"com.jcraft.jsch.DHG1",
"com.jcraft.jsch.DHG14",
"com.jcraft.jsch.DHGEX",
"com.jcraft.jsch.DHGEX256",
"com.jcraft.jsch.DHGEX256"
)

jschClasses.forEach {
reflection.registerTypeIfPresent(
classLoader,
it,
::configureForReflection,
::configureForReflection
)
}
}
Expand All @@ -75,7 +75,7 @@ class JschRuntimeHintsRegistrar : RuntimeHintsRegistrar {
typeHint.withMembers(
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_DECLARED_METHODS,
MemberCategory.DECLARED_FIELDS,
MemberCategory.DECLARED_FIELDS
)
}
}
2 changes: 1 addition & 1 deletion src/main/kotlin/com/valensas/ftp/model/ConnectionMode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ package com.valensas.ftp.model

enum class ConnectionMode {
Active,
Passive,
Passive
}
2 changes: 1 addition & 1 deletion src/main/kotlin/com/valensas/ftp/model/ConnectionModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ data class ConnectionModel(
val connectionMode: ConnectionMode? = null,
val connectionTimeout: Int? = null,
val strictHostKeyChecking: String = "no",
val retryBackoffDurationsInSecond: List<Int> = listOf(0),
val retryBackoffDurationsInSecond: List<Int> = listOf(0)
)
4 changes: 2 additions & 2 deletions src/main/kotlin/com/valensas/ftp/model/ConnectionResult.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ package com.valensas.ftp.model
data class ConnectionResult(
val connected: Boolean,
val retryCount: Int = 0,
val errors: Set<Error> = emptySet(),
val errors: Set<Error> = emptySet()
) {
class Error(
val description: String,
val count: Int,
val count: Int
)
}
2 changes: 1 addition & 1 deletion src/main/kotlin/com/valensas/ftp/model/ConnectionType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ package com.valensas.ftp.model
enum class ConnectionType {
FTP,
FTPS,
SFTP,
SFTP
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ package com.valensas.ftp.model

enum class ConnectionVariant {
Explicit,
Implicit,
Implicit
}
2 changes: 1 addition & 1 deletion src/main/kotlin/com/valensas/ftp/model/FTPClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ open class FTPClient : FTPClient() {
return ConnectionResult(
connected = connected,
retryCount = retryCount,
errors = errors.groupBy { it }.map { ConnectionResult.Error(it.key, it.value.size) }.toSet(),
errors = errors.groupBy { it }.map { ConnectionResult.Error(it.key, it.value.size) }.toSet()
)
}

Expand Down
17 changes: 8 additions & 9 deletions src/main/kotlin/com/valensas/ftp/model/FTPSClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import javax.net.ssl.SSLException
import javax.net.ssl.TrustManager

class FTPSClient(
isImplicit: Boolean = false,
isImplicit: Boolean = false
) : FTPClient() {
private val logger: Logger = LoggerFactory.getLogger(javaClass)

Expand Down Expand Up @@ -86,14 +86,13 @@ class FTPSClient(
@Throws(IOException::class)
override fun sendCommand(
command: String,
args: String?,
): Int =
try {
ftpsClient.sendCommand(command, args)
} catch (e: Throwable) {
logger.error("An error occurred while sending command $command to the FTPS server", e)
throw e
}
args: String?
): Int = try {
ftpsClient.sendCommand(command, args)
} catch (e: Throwable) {
logger.error("An error occurred while sending command $command to the FTPS server", e)
throw e
}

@Throws(IOException::class)
override fun isConnected(): Boolean = ftpsClient.isConnected
Expand Down
34 changes: 16 additions & 18 deletions src/main/kotlin/com/valensas/ftp/model/SFTPClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,30 +39,28 @@ class SFTPClient : FTPClient() {

override fun retrieveFileStream(remoteFileName: String): InputStream = channel.get(remoteFileName)

override fun deleteFile(remoteFileName: String): Boolean =
try {
channel.rm(remoteFileName)
true
} catch (e: Exception) {
logger.warn("Can not delete $remoteFileName file.", e)
throw e
}
override fun deleteFile(remoteFileName: String): Boolean = try {
channel.rm(remoteFileName)
true
} catch (e: Exception) {
logger.warn("Can not delete $remoteFileName file.", e)
throw e
}

override fun rename(
from: String?,
to: String?,
): Boolean =
try {
channel.rename(from, to)
true
} catch (e: Exception) {
logger.warn("Can not move file from $from to $to.", e)
throw e
}
to: String?
): Boolean = try {
channel.rename(from, to)
true
} catch (e: Exception) {
logger.warn("Can not move file from $from to $to.", e)
throw e
}

override fun storeFile(
remote: String?,
local: InputStream?,
local: InputStream?
): Boolean {
try {
channel.put(local, remote)
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/com/valensas/ftp/server/EmbeddedFtpServer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class EmbeddedFtpServer {
isImplicit: Boolean = false,
certificatePath: String? = null,
path: Path? = Files.createTempDirectory("ftp-test"),
connectionConfig: ConnectionConfig? = null,
connectionConfig: ConnectionConfig? = null
) {
val serverFactory = FtpServerFactory()
listenerFactory = ListenerFactory()
Expand All @@ -52,7 +52,7 @@ class EmbeddedFtpServer {
user.password = password
user.authorities =
listOf(
WritePermission(),
WritePermission()
)
path?.let {
user.homeDirectory = it.toAbsolutePath().toString()
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/com/valensas/ftp/server/EmbeddedSftpServer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class EmbeddedSftpServer {
path: Path? = Files.createTempDirectory("ftp-test"),
clientPublicKey: PublicKey? = null,
algorithm: String = "RSA",
keySize: Int = 2048,
keySize: Int = 2048
) {
sshServer = SshServer.setUpDefaultServer()
val fileSystemFactory = VirtualFileSystemFactory()
Expand Down Expand Up @@ -72,7 +72,7 @@ class EmbeddedSftpServer {

private fun setProvider(
algorithm: String,
keySize: Int,
keySize: Int
): SimpleGeneratorHostKeyProvider {
val provider = SimpleGeneratorHostKeyProvider()
provider.algorithm = algorithm
Expand Down
3 changes: 1 addition & 2 deletions src/test/kotlin/com/valensas/ftp/Fake.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.valensas.ftp

object Fake {
fun privateKey() =
"-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCGmT4IL7gjhLgm\n09Okeh8FnOfihgEoTOIxDKA2Dx9Ce+LSV36DMg4LTfZl6N78yuwIYe6AUIGDtCgD\n6g5LHT4uBQJnA/4I2B/gnJmj2DdagPwr1oqMouETomzfGtDEAJbEzMGxKK3JlIAu\nQn3PFgvbgFvlkeOvUjtEQQ7H6surKLnmKc9rRsKH7RtDh34pwx1n07AJbWX3GTr0\n7p8n3gCTLOTdtp6JzHdme8uRdO4ZPPIvaFKBRQWHN/IxcXn4yNpQqnTDFi77MmWC\nJO9AHd3LYgM328Nbo0elXcojAuqRCrxJ++ky1nZvSc8bPJDV1bHg1oj0hVmfzaXZ\n1RQu5RwFAgMBAAECggEAMS8WJ8+oLfJ1iFqnX9bwNxDa+z+UdLGDhgDjGl30Qksa\n21n1dON5lk/q1dp+gUl1bqq6iFDiwsm2RZflmTUaX56c/h/LWFgBbgZLbj+4Gm4/\nt5UyE6oBLTeRKQWXe8frUAayUJZYyuxk2oKZjm6z7oW9Dup8lLgryAkt6Ye23NgB\nSjZb8kyvW8fol8L/zSV/zxhXXYLBC54KjHLhSfZhJTvIvfm1zBS011b3nYRubn0j\n6S2ZCTe1V0NQvu5lij54cjcO14mR87FilnHh6rhfRv+Xnw50gbNvTcG6Zt7PdVCl\ntf2/EiHRZdfm7OIhV8VVLVRthyIa3SUMMZytTiHokQKBgQC3a/DTW7XsFUDyjHiE\nesg1JbaMxHN2h4IQQcn3DjXfeWE/pWhLQFkU6lzgmWjCXCPJvJFMr/+vxe9rHLUN\noEKANV8o2pquaFc5RJZIUuuZcN9sTdFZxUikFDOr4IrtPrrR8rDxjSfwQIW9OeJ/\nBVSOBfSVg0fYNeHn4+YgfCwxHwKBgQC726zA9dxVOWz07+PV+lnSnZ387/K5csOy\n54IRMZAQumO4GcrXx2SUg0N8/J9OYp/IC1ilMa9ku1UvL8TicK8Hs7yDCjcSSK0C\n2exKhGlcxp4kKaTzA5rPVwA2XpdkioofCPataxeLyatC38IqKr2iZOR8Z7V3gGnI\nPLvH1v2aWwKBgQCrqJNr2wq49XMhDCHGKnqwcqkTuM8ugMdSm59+XYhBqwE+ZXjj\n5Eb6chOWBzypmT3NEXMSSCyMvjvBDM7M/8z82/ZA78WPsArhh7T13tSrd51BaNqi\nnyXKmTV6h9y9B9YjonPCvI5CJMCFRWUZ500o1Z3/Ryu3x0WylfDLOirJlQKBgCAn\nJDVOn2ySzJxLptJL7C3JPm45X3DwPKCVUUTCF+dVD5ZGC9rMzOFCaj2tO1L+PFzP\n3FdB3sQ98AGIiok7QinuUHiZOf3OJJaVWAUVDreLYyvLWOkjF88fE/E6VW0m7ScM\nsLPT3Y7WcJKcm6397MErxZOpaHzQpMpZ4sX8fSF7AoGAIDvjVsTMMFC8kBDe2GxF\nDM5GkI8rI9y7a6fxiY239zHSdNLPqi4tO/qBkP2TjMpWhVNQD7UwAc7bLMkXC28X\nEniUcKI28G0347OMgRPcnJAKHCeiFbf35+vKhrkdFh1u586UbJP8wPPIhdI+d/OC\noKMplwiuEfKeCbA378EjqSs=\n-----END PRIVATE KEY-----"
fun privateKey() = "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCGmT4IL7gjhLgm\n09Okeh8FnOfihgEoTOIxDKA2Dx9Ce+LSV36DMg4LTfZl6N78yuwIYe6AUIGDtCgD\n6g5LHT4uBQJnA/4I2B/gnJmj2DdagPwr1oqMouETomzfGtDEAJbEzMGxKK3JlIAu\nQn3PFgvbgFvlkeOvUjtEQQ7H6surKLnmKc9rRsKH7RtDh34pwx1n07AJbWX3GTr0\n7p8n3gCTLOTdtp6JzHdme8uRdO4ZPPIvaFKBRQWHN/IxcXn4yNpQqnTDFi77MmWC\nJO9AHd3LYgM328Nbo0elXcojAuqRCrxJ++ky1nZvSc8bPJDV1bHg1oj0hVmfzaXZ\n1RQu5RwFAgMBAAECggEAMS8WJ8+oLfJ1iFqnX9bwNxDa+z+UdLGDhgDjGl30Qksa\n21n1dON5lk/q1dp+gUl1bqq6iFDiwsm2RZflmTUaX56c/h/LWFgBbgZLbj+4Gm4/\nt5UyE6oBLTeRKQWXe8frUAayUJZYyuxk2oKZjm6z7oW9Dup8lLgryAkt6Ye23NgB\nSjZb8kyvW8fol8L/zSV/zxhXXYLBC54KjHLhSfZhJTvIvfm1zBS011b3nYRubn0j\n6S2ZCTe1V0NQvu5lij54cjcO14mR87FilnHh6rhfRv+Xnw50gbNvTcG6Zt7PdVCl\ntf2/EiHRZdfm7OIhV8VVLVRthyIa3SUMMZytTiHokQKBgQC3a/DTW7XsFUDyjHiE\nesg1JbaMxHN2h4IQQcn3DjXfeWE/pWhLQFkU6lzgmWjCXCPJvJFMr/+vxe9rHLUN\noEKANV8o2pquaFc5RJZIUuuZcN9sTdFZxUikFDOr4IrtPrrR8rDxjSfwQIW9OeJ/\nBVSOBfSVg0fYNeHn4+YgfCwxHwKBgQC726zA9dxVOWz07+PV+lnSnZ387/K5csOy\n54IRMZAQumO4GcrXx2SUg0N8/J9OYp/IC1ilMa9ku1UvL8TicK8Hs7yDCjcSSK0C\n2exKhGlcxp4kKaTzA5rPVwA2XpdkioofCPataxeLyatC38IqKr2iZOR8Z7V3gGnI\nPLvH1v2aWwKBgQCrqJNr2wq49XMhDCHGKnqwcqkTuM8ugMdSm59+XYhBqwE+ZXjj\n5Eb6chOWBzypmT3NEXMSSCyMvjvBDM7M/8z82/ZA78WPsArhh7T13tSrd51BaNqi\nnyXKmTV6h9y9B9YjonPCvI5CJMCFRWUZ500o1Z3/Ryu3x0WylfDLOirJlQKBgCAn\nJDVOn2ySzJxLptJL7C3JPm45X3DwPKCVUUTCF+dVD5ZGC9rMzOFCaj2tO1L+PFzP\n3FdB3sQ98AGIiok7QinuUHiZOf3OJJaVWAUVDreLYyvLWOkjF88fE/E6VW0m7ScM\nsLPT3Y7WcJKcm6397MErxZOpaHzQpMpZ4sX8fSF7AoGAIDvjVsTMMFC8kBDe2GxF\nDM5GkI8rI9y7a6fxiY239zHSdNLPqi4tO/qBkP2TjMpWhVNQD7UwAc7bLMkXC28X\nEniUcKI28G0347OMgRPcnJAKHCeiFbf35+vKhrkdFh1u586UbJP8wPPIhdI+d/OC\noKMplwiuEfKeCbA378EjqSs=\n-----END PRIVATE KEY-----"
}
Loading
Loading