Various tweaks to extended SecureConnectionException exceptions

This commit is contained in:
Niels van Velzen 2023-09-02 14:25:37 +02:00 committed by Niels van Velzen
parent be2c217bfe
commit c79081d0cb
11 changed files with 71 additions and 65 deletions

View File

@ -27,7 +27,7 @@ import org.jellyfin.sdk.api.client.exception.InvalidStatusException
import org.jellyfin.sdk.api.client.exception.SecureConnectionException
import org.jellyfin.sdk.api.client.exception.TimeoutException
import org.jellyfin.sdk.api.client.exception.ssl.BadPeerSSLKeyException
import org.jellyfin.sdk.api.client.exception.ssl.HandShakeCertificateException
import org.jellyfin.sdk.api.client.exception.ssl.HandshakeCertificateException
import org.jellyfin.sdk.api.client.exception.ssl.InvalidSSLProtocolImplementationException
import org.jellyfin.sdk.api.client.exception.ssl.PeerNotAuthenticatedException
import org.jellyfin.sdk.api.client.util.ApiSerializer
@ -142,25 +142,21 @@ public actual open class KtorClient actual constructor(
} catch (err: SerializationException) {
logger.error(err) { "Serialization failed" }
throw InvalidContentException("Serialization failed", err)
} catch (err: SSLKeyException) {
logger.error(err) { "Invalid SSL peer key format" }
throw BadPeerSSLKeyException("Invalid SSL peer key format", err)
} catch (err: SSLPeerUnverifiedException) {
logger.error(err) { "Couldn't authenticate peer" }
throw PeerNotAuthenticatedException("Couldn't authenticate peer", err)
} catch (err: SSLHandshakeException) {
logger.error(err) { "SSL Invalid handshake" }
throw HandshakeCertificateException("Invalid handshake", err)
} catch (err: SSLProtocolException) {
logger.error(err) { "Invalid SSL protocol implementation" }
throw InvalidSSLProtocolImplementationException("Invalid SSL protocol implementation", err)
} catch (err: SSLException) {
logger.error(err) { "SSL error occurred" }
when (err) {
is SSLKeyException -> {
throw BadPeerSSLKeyException("Invalid SSL peer key format", err)
}
is SSLPeerUnverifiedException -> {
throw PeerNotAuthenticatedException("Couldn't authenticate peer", err)
}
is SSLHandshakeException -> {
throw HandShakeCertificateException("Invalid hand shake certificate", err)
}
is SSLProtocolException -> {
throw InvalidSSLProtocolImplementationException("Invalid SSL protocol implementation", err)
}
else -> {
throw SecureConnectionException("Unknown SSL error occurred", err)
}
}
logger.error(err) { "Unknown SSL error occurred" }
throw SecureConnectionException("Unknown SSL error occurred", err)
} catch (err: IOException) {
logger.error(err) { "Unknown IO error occurred!" }
throw ApiClientException("Unknown IO error occurred!", err)

View File

@ -129,7 +129,7 @@ public final class org/jellyfin/sdk/api/client/exception/ssl/BadPeerSSLKeyExcept
public fun <init> (Ljava/lang/String;Ljava/lang/Throwable;)V
}
public final class org/jellyfin/sdk/api/client/exception/ssl/HandShakeCertificateException : org/jellyfin/sdk/api/client/exception/SecureConnectionException {
public final class org/jellyfin/sdk/api/client/exception/ssl/HandshakeCertificateException : org/jellyfin/sdk/api/client/exception/SecureConnectionException {
public fun <init> (Ljava/lang/String;Ljava/lang/Throwable;)V
}

View File

@ -7,5 +7,6 @@ import org.jellyfin.sdk.api.client.exception.SecureConnectionException
* This can happen when a bad key format is given.
*/
public class BadPeerSSLKeyException(
message: String, exception: Throwable
): SecureConnectionException(message, exception)
message: String,
exception: Throwable,
) : SecureConnectionException(message, exception)

View File

@ -7,6 +7,6 @@ import org.jellyfin.sdk.api.client.exception.SecureConnectionException
* Indicates that the client and server could not negotiate the desired level of security or the certificate was
* revoked.
*/
public class HandShakeCertificateException(
public class HandshakeCertificateException(
message: String, exception: Throwable
): SecureConnectionException(message, exception)

View File

@ -7,5 +7,6 @@ import org.jellyfin.sdk.api.client.exception.SecureConnectionException
* Normally this indicates a flaw in one of the protocol implementations.
*/
public class InvalidSSLProtocolImplementationException(
message: String, exception: Throwable
): SecureConnectionException(message, exception)
message: String,
exception: Throwable,
) : SecureConnectionException(message, exception)

View File

@ -10,5 +10,6 @@ import org.jellyfin.sdk.api.client.exception.SecureConnectionException
* this exception is thrown.
*/
public class PeerNotAuthenticatedException(
message: String, exception: Throwable
): SecureConnectionException(message, exception)
message: String,
exception: Throwable,
) : SecureConnectionException(message, exception)

View File

@ -245,12 +245,12 @@ public final class org/jellyfin/sdk/discovery/RecommendedServerIssue$SecureConne
}
public final class org/jellyfin/sdk/discovery/RecommendedServerIssue$ServerUnreachable : org/jellyfin/sdk/discovery/RecommendedServerIssue {
public fun <init> (Ljava/lang/Throwable;)V
public final fun component1 ()Ljava/lang/Throwable;
public final fun copy (Ljava/lang/Throwable;)Lorg/jellyfin/sdk/discovery/RecommendedServerIssue$ServerUnreachable;
public static synthetic fun copy$default (Lorg/jellyfin/sdk/discovery/RecommendedServerIssue$ServerUnreachable;Ljava/lang/Throwable;ILjava/lang/Object;)Lorg/jellyfin/sdk/discovery/RecommendedServerIssue$ServerUnreachable;
public fun <init> (Lorg/jellyfin/sdk/api/client/exception/TimeoutException;)V
public final fun component1 ()Lorg/jellyfin/sdk/api/client/exception/TimeoutException;
public final fun copy (Lorg/jellyfin/sdk/api/client/exception/TimeoutException;)Lorg/jellyfin/sdk/discovery/RecommendedServerIssue$ServerUnreachable;
public static synthetic fun copy$default (Lorg/jellyfin/sdk/discovery/RecommendedServerIssue$ServerUnreachable;Lorg/jellyfin/sdk/api/client/exception/TimeoutException;ILjava/lang/Object;)Lorg/jellyfin/sdk/discovery/RecommendedServerIssue$ServerUnreachable;
public fun equals (Ljava/lang/Object;)Z
public final fun getThrowable ()Ljava/lang/Throwable;
public final fun getThrowable ()Lorg/jellyfin/sdk/api/client/exception/TimeoutException;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

View File

@ -230,12 +230,12 @@ public final class org/jellyfin/sdk/discovery/RecommendedServerIssue$SecureConne
}
public final class org/jellyfin/sdk/discovery/RecommendedServerIssue$ServerUnreachable : org/jellyfin/sdk/discovery/RecommendedServerIssue {
public fun <init> (Ljava/lang/Throwable;)V
public final fun component1 ()Ljava/lang/Throwable;
public final fun copy (Ljava/lang/Throwable;)Lorg/jellyfin/sdk/discovery/RecommendedServerIssue$ServerUnreachable;
public static synthetic fun copy$default (Lorg/jellyfin/sdk/discovery/RecommendedServerIssue$ServerUnreachable;Ljava/lang/Throwable;ILjava/lang/Object;)Lorg/jellyfin/sdk/discovery/RecommendedServerIssue$ServerUnreachable;
public fun <init> (Lorg/jellyfin/sdk/api/client/exception/TimeoutException;)V
public final fun component1 ()Lorg/jellyfin/sdk/api/client/exception/TimeoutException;
public final fun copy (Lorg/jellyfin/sdk/api/client/exception/TimeoutException;)Lorg/jellyfin/sdk/discovery/RecommendedServerIssue$ServerUnreachable;
public static synthetic fun copy$default (Lorg/jellyfin/sdk/discovery/RecommendedServerIssue$ServerUnreachable;Lorg/jellyfin/sdk/api/client/exception/TimeoutException;ILjava/lang/Object;)Lorg/jellyfin/sdk/discovery/RecommendedServerIssue$ServerUnreachable;
public fun equals (Ljava/lang/Object;)Z
public final fun getThrowable ()Ljava/lang/Throwable;
public final fun getThrowable ()Lorg/jellyfin/sdk/api/client/exception/TimeoutException;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

View File

@ -50,25 +50,20 @@ public class RecommendedServerDiscovery constructor(
// Failure checks
result.systemInfo.exceptionOrNull()?.let { exception ->
when (exception) {
is SecureConnectionException -> {
issues.add(RecommendedServerIssue.SecureConnectionFailed(exception))
}
is TimeoutException -> {
issues.add(RecommendedServerIssue.ServerUnreachable(exception))
}
else -> {
// Did not reply with a system information
issues.add(RecommendedServerIssue.MissingSystemInfo(result.systemInfo.exceptionOrNull()))
}
is SecureConnectionException -> issues.add(RecommendedServerIssue.SecureConnectionFailed(exception))
is TimeoutException -> issues.add(RecommendedServerIssue.ServerUnreachable(exception))
// Did not reply with a system information
else -> issues.add(RecommendedServerIssue.MissingSystemInfo(result.systemInfo.exceptionOrNull()))
}
scores.add(RecommendedServerInfoScore.BAD)
}
// System Info data validation
when {
// Wrong product name - might be a different service on this connection
!systemInfo?.productName.equals(PRODUCT_NAME) -> {
issues.add(RecommendedServerIssue.InvalidProductName(systemInfo?.productName))
systemInfo != null && !systemInfo.productName.equals(PRODUCT_NAME) -> {
issues.add(RecommendedServerIssue.InvalidProductName(systemInfo.productName))
scores.add(RecommendedServerInfoScore.BAD)
}
}

View File

@ -1,18 +1,23 @@
package org.jellyfin.sdk.discovery
import org.jellyfin.sdk.api.client.exception.SecureConnectionException
import org.jellyfin.sdk.api.client.exception.TimeoutException
import org.jellyfin.sdk.model.ServerVersion
public sealed interface RecommendedServerIssue {
/**
* Failed to acquire a secure connection. This happens due to incorrect SSL configurations.
*/
public data class SecureConnectionFailed(public val sslException: SecureConnectionException) : RecommendedServerIssue
public data class SecureConnectionFailed(
public val sslException: SecureConnectionException,
) : RecommendedServerIssue
/**
* Server is unreachable. This happens when the server is overloaded, unstable or the client is unable to establish a connection.
* Server is unreachable. This happens when the server is overloaded, unstable or the client is unable to establish
* a connection.
*/
public data class ServerUnreachable(public val throwable: Throwable) : RecommendedServerIssue
public data class ServerUnreachable(public val throwable: TimeoutException) : RecommendedServerIssue
/**
* No system information found from server. Server is returning invalid system info.
*/

View File

@ -1,48 +1,55 @@
package org.jellyfin.sdk.api;
import io.kotest.assertions.retry
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.FunSpec
import org.jellyfin.sdk.api.client.exception.SecureConnectionException
import org.jellyfin.sdk.api.client.exception.ssl.HandShakeCertificateException
import org.jellyfin.sdk.api.client.exception.ssl.HandshakeCertificateException
import org.jellyfin.sdk.api.client.exception.ssl.PeerNotAuthenticatedException
import org.jellyfin.sdk.createJellyfin
import org.jellyfin.sdk.model.ClientInfo
import org.jellyfin.sdk.model.DeviceInfo
import kotlin.time.Duration.Companion.minutes
class SSLResolverTests : FunSpec({
val jellyfin = createJellyfin {
fun getInstance() = createJellyfin {
clientInfo = ClientInfo("Jellyfin Testing SSL Errors", "TEST")
deviceInfo = DeviceInfo("test", "test")
}
test("should throw HandShakeCertificateException when calling an https endpoint with revoked certificate") {
val api = jellyfin.createApi(
val api = getInstance().createApi(
baseUrl = "https://revoked.badssl.com"
)
shouldThrow<HandShakeCertificateException> {
api.request(pathTemplate = "/")
retry(3, 1.minutes) {
shouldThrow<HandshakeCertificateException> {
api.request(pathTemplate = "/")
}
}
}
test("should throw PeerNotAuthenticatedException when wrong host is returned from https endpoint") {
val api = jellyfin.createApi(
val api = getInstance().createApi(
baseUrl = "https://wrong.host.badssl.com"
)
shouldThrow<PeerNotAuthenticatedException> {
api.request(pathTemplate = "/")
retry(3, 1.minutes) {
shouldThrow<PeerNotAuthenticatedException> {
api.request(pathTemplate = "/")
}
}
}
test("should throw SecureConnectionException when using wrong https port") {
val api = jellyfin.createApi(
val api = getInstance().createApi(
baseUrl = "https://badssl.com:80"
)
shouldThrow<SecureConnectionException> {
api.request(pathTemplate = "/")
retry(3, 1.minutes) {
shouldThrow<SecureConnectionException> {
api.request(pathTemplate = "/")
}
}
}
})