diff --git a/apps/xsCli/build.gradle.kts b/apps/xsCli/build.gradle.kts new file mode 100644 index 0000000..76b5001 --- /dev/null +++ b/apps/xsCli/build.gradle.kts @@ -0,0 +1,3 @@ +dependencies { + implementation(project(":libraries:httpClient")) +} \ No newline at end of file diff --git a/apps/xsCli/src/main/kotlin/de/itkl/xsCli/App.kt b/apps/xsCli/src/main/kotlin/de/itkl/xsCli/App.kt new file mode 100644 index 0000000..bd60254 --- /dev/null +++ b/apps/xsCli/src/main/kotlin/de/itkl/xsCli/App.kt @@ -0,0 +1,48 @@ +package de.itkl.xsCli + +import com.github.ajalt.clikt.core.CliktCommand +import com.github.ajalt.clikt.core.subcommands +import com.github.ajalt.clikt.parameters.options.option +import com.github.ajalt.clikt.parameters.options.convert +import com.github.ajalt.clikt.parameters.options.required +import com.github.ajalt.clikt.parameters.types.int +import de.itkl.httpClient.clients.XsClient +import de.itkl.httpClient.httpClientModule +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject +import org.koin.core.context.startKoin +import java.io.File +import java.nio.file.Paths + +class Cli : CliktCommand() { + override fun run() {} + + inner class StressAnalyse : CliktCommand(name = "stress-analyse") { + val inputDirectory: File by option(help="Input directory path").convert { File(it) }.required() + val tasks: Int by option(help="Number of tasks").int().required() + + override fun run() { + // TODO: Use inputDirectory and tasks here + } + } + + init { + subcommands(StressAnalyse()) + } +} + +class XsCli : KoinComponent { + private val xsClient: XsClient by inject() + + suspend fun run() { + xsClient.analyse(Paths.get("assets/xs-reg/00001.jpg")) + } +} + +suspend fun main(args: Array) { + startKoin { + modules(httpClientModule) + } + XsCli().run() +// Cli().main(args) +} \ No newline at end of file diff --git a/apps/xsViewer/build.gradle.kts b/apps/xsViewer/build.gradle.kts new file mode 100644 index 0000000..30436c0 --- /dev/null +++ b/apps/xsViewer/build.gradle.kts @@ -0,0 +1,15 @@ +import korlibs.korge.gradle.korge + +plugins { + id("com.soywiz.korge") version "5.3.0" +} + +dependencies { + jvmMainImplementation("ch.qos.logback:logback-classic:1.4.14") + jvmMainImplementation(project(":libraries:docthor-core")) +} + +korge { + targetJvm() + serializationJson() +} diff --git a/build.gradle.kts b/build.gradle.kts index 832ce8c..6f8ef0f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,7 +3,7 @@ project(":libraries").subprojects { } project(":apps").subprojects { - if(name != "documentViewerKorge") { + if(name != "documentViewerKorge" && name != "xsViewer") { apply(plugin = "docthor.kotlin-application-conventions") } diff --git a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/BearerToken.kt b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/BearerToken.kt deleted file mode 100644 index 20f94ea..0000000 --- a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/BearerToken.kt +++ /dev/null @@ -1,10 +0,0 @@ -package de.itkl.httpClient - -import kotlinx.datetime.Instant -import kotlinx.serialization.Serializable - -@Serializable -data class BearerToken( - val tokenString: String, - val validUntil: Instant -) \ No newline at end of file diff --git a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/SmartCloudAuthPlugin.kt b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/SmartCloudAuthPlugin.kt index b804f84..2605832 100644 --- a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/SmartCloudAuthPlugin.kt +++ b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/SmartCloudAuthPlugin.kt @@ -12,9 +12,10 @@ private val Log = KotlinLogging.logger { } val smartCloudAuthPlugin = createClientPlugin("SmartCloudAuth") { val smartCloudAuthStrategy = SmartCloudAuthStrategy() on(Send) { request -> - val token = smartCloudAuthStrategy.login(client, request) ?: error("login failed") - request.headers { - set(HttpHeaders.Authorization, "Bearer ${token.toBearer()}") + smartCloudAuthStrategy.login(client, request)?.let { token -> + request.headers { + set(HttpHeaders.Authorization, token.toBearer()) + } } proceed(request) } diff --git a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/TrustAllX509TrustManager.kt b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/TrustAllX509TrustManager.kt new file mode 100644 index 0000000..1381a8a --- /dev/null +++ b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/TrustAllX509TrustManager.kt @@ -0,0 +1,12 @@ +package de.itkl.httpClient + +import java.security.cert.X509Certificate +import javax.net.ssl.X509TrustManager + +class TrustAllX509TrustManager : X509TrustManager { + override fun getAcceptedIssuers(): Array = arrayOfNulls(0) + + override fun checkClientTrusted(certs: Array?, authType: String?) {} + + override fun checkServerTrusted(certs: Array?, authType: String?) {} +} \ No newline at end of file diff --git a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/auth/AuthenticationToken.kt b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/auth/AuthenticationToken.kt index 130be6d..cedd39a 100644 --- a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/auth/AuthenticationToken.kt +++ b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/auth/AuthenticationToken.kt @@ -1,12 +1,14 @@ package de.itkl.httpClient.auth import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable sealed class AuthenticationToken { abstract val expires: Expires abstract fun toBearer(): String } +@Serializable data class BearerToken(val token: String, val validUntil: Instant) : AuthenticationToken() { override val expires: Expires get() = Expires.ExpiresAt(validUntil) diff --git a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/auth/Credentials.kt b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/auth/Credentials.kt index 513ecc8..132971e 100644 --- a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/auth/Credentials.kt +++ b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/auth/Credentials.kt @@ -4,5 +4,5 @@ import kotlinx.serialization.Serializable sealed class Credentials { @Serializable - data class LoginAndPassword(val login: String, val password: String) : Credentials() + data class LoginAndPassword(val username: String, val password: String) : Credentials() } \ No newline at end of file diff --git a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/clients/XsClient.kt b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/clients/XsClient.kt index 076de34..7599fb7 100644 --- a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/clients/XsClient.kt +++ b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/clients/XsClient.kt @@ -8,6 +8,7 @@ import io.ktor.client.statement.* import io.ktor.client.utils.EmptyContent.contentType import io.ktor.http.* import io.ktor.http.content.* +import io.ktor.util.* import io.ktor.util.cio.* import io.ktor.utils.io.* import io.ktor.utils.io.streams.* @@ -44,10 +45,12 @@ class XsClient : KoinComponent { } ) } - ) + ) { + this.attributes.put(AttributeKey("username"), "xs.dev.klara") + } val responseText = response.bodyAsText() - Log.info { "Form submitted successfully: ${response.status}: $responseText" } + Log.info { "Form submitted: ${response.status}: $responseText" } } } diff --git a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/createHttpClient.kt b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/createHttpClient.kt index 4196d85..edc2dae 100644 --- a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/createHttpClient.kt +++ b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/createHttpClient.kt @@ -1,9 +1,13 @@ package de.itkl.httpClient import io.ktor.client.* +import io.ktor.client.engine.* import io.ktor.client.engine.cio.* +import io.ktor.client.plugins.* import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.http.* import io.ktor.serialization.kotlinx.json.* +import kotlin.time.Duration.Companion.minutes fun createHttpClient(): HttpClient { return HttpClient(CIO) { @@ -11,5 +15,15 @@ fun createHttpClient(): HttpClient { json() } install(smartCloudAuthPlugin) + install(HttpTimeout) { + requestTimeoutMillis = 1.minutes.inWholeMilliseconds + } + + engine { + proxy = ProxyBuilder.http(Url("http://localhost:9999")) + https { + trustManager = TrustAllX509TrustManager() + } + } } } \ No newline at end of file diff --git a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/implementation/SmartCloudAuthStrategy.kt b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/implementation/SmartCloudAuthStrategy.kt index dffd38a..e371301 100644 --- a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/implementation/SmartCloudAuthStrategy.kt +++ b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/implementation/SmartCloudAuthStrategy.kt @@ -17,7 +17,10 @@ class SmartCloudAuthStrategy : AuthStrategy, KoinComponent { private val credentialsProvider: CredentialsProvider by inject() override suspend fun login(httpClient: HttpClient, request: HttpRequestBuilder): AuthenticationToken? { Log.debug { "Attempting login..." } - val user = request.attributes.getOrNull(AttributeKey("username")) ?: error("No username is specified for this request: $request") + val user = request.attributes.getOrNull(AttributeKey("username")) ?: run { + Log.info { "No username is specified for this request" } + return null + } val credentials: Credentials = credentialsProvider.lookupByUsername(user) ?: error("No credentials found for user: $user") val loginAndPassword: Credentials.LoginAndPassword = credentials as? Credentials.LoginAndPassword ?: error("Only username and password is supported by smartcloud auth login")