Skip to content

Commit 375b829

Browse files
nice77Minnullin Niyaz
and
Minnullin Niyaz
authored
Add trustAllCerts flag (#12)
* Add way to create an unsafe client * Add way to create an unsafe client * Add tests --------- Co-authored-by: Minnullin Niyaz <minnullin.niyaz@x5.ru>
1 parent bcad454 commit 375b829

File tree

12 files changed

+96
-13
lines changed

12 files changed

+96
-13
lines changed
Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,28 @@
11
package com.piasy.kmp.socketio.engineio.transports
22

3-
import io.ktor.client.HttpClientConfig
43
import io.ktor.client.HttpClient
4+
import io.ktor.client.HttpClientConfig
55
import io.ktor.client.engine.darwin.Darwin
6+
import platform.Foundation.NSURLCredential
7+
import platform.Foundation.NSURLSessionAuthChallengePerformDefaultHandling
8+
import platform.Foundation.NSURLSessionAuthChallengeUseCredential
9+
import platform.Foundation.create
10+
import platform.Foundation.serverTrust
11+
import platform.Security.SecTrustRef
612

7-
actual fun httpClient(config: HttpClientConfig<*>.() -> Unit): HttpClient = HttpClient(Darwin) {
13+
actual fun httpClient(trustAllCerts: Boolean, config: HttpClientConfig<*>.() -> Unit): HttpClient = HttpClient(Darwin) {
814
config(this)
15+
engine {
16+
if (trustAllCerts) {
17+
handleChallenge { session, task, challenge, completionHandler ->
18+
val serverTrust: SecTrustRef? = challenge.protectionSpace.serverTrust
19+
if (serverTrust != null) {
20+
val credential = NSURLCredential.create(trust = serverTrust)
21+
completionHandler(NSURLSessionAuthChallengeUseCredential.toLong(), credential)
22+
} else {
23+
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling.toLong(), null)
24+
}
25+
}
26+
}
27+
}
928
}

kmp-socketio/src/commonMain/kotlin/com/piasy/kmp/socketio/engineio/EngineSocket.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ class EngineSocket(
217217
opts.timestampRequests = options?.timestampRequests ?: opt.timestampRequests
218218
opts.timestampParam = options?.timestampParam ?: opt.timestampParam
219219
opts.extraHeaders = opt.extraHeaders
220+
opts.trustAllCerts = opt.trustAllCerts
220221

221222
val transport = factory.create(name, opts, scope, rawMessage)
222223
emit(EVENT_TRANSPORT, transport)

kmp-socketio/src/commonMain/kotlin/com/piasy/kmp/socketio/engineio/Transport.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ abstract class Transport(
3939

4040
@JvmField
4141
var extraHeaders: Map<String, List<String>> = emptyMap()
42+
43+
@JvmField
44+
var trustAllCerts: Boolean = false
4245
}
4346

4447
protected var state = State.INIT

kmp-socketio/src/commonMain/kotlin/com/piasy/kmp/socketio/engineio/transports/PollingXHR.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ open class PollingXHR(
1717
opt: Options,
1818
scope: CoroutineScope,
1919
private val ioScope: CoroutineScope = CoroutineScope(Dispatchers.Default),
20-
private val factory: HttpClientFactory = DefaultHttpClientFactory,
20+
private val factory: HttpClientFactory = DefaultHttpClientFactory(trustAllCerts = opt.trustAllCerts),
2121
rawMessage: Boolean,
2222
) : Transport(opt, scope, NAME, rawMessage) {
2323
private var polling = false

kmp-socketio/src/commonMain/kotlin/com/piasy/kmp/socketio/engineio/transports/WebSocket.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ open class WebSocket(
2323
opt: Options,
2424
scope: CoroutineScope,
2525
private val ioScope: CoroutineScope = CoroutineScope(Dispatchers.Default),
26-
private val factory: HttpClientFactory = DefaultHttpClientFactory,
26+
private val factory: HttpClientFactory = DefaultHttpClientFactory(trustAllCerts = opt.trustAllCerts),
2727
rawMessage: Boolean,
2828
) : Transport(opt, scope, NAME, rawMessage) {
2929
private var ws: DefaultClientWebSocketSession? = null

kmp-socketio/src/commonMain/kotlin/com/piasy/kmp/socketio/engineio/transports/transport.kt

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import io.ktor.client.statement.*
1111
import io.ktor.http.*
1212
import kotlinx.coroutines.CoroutineScope
1313

14-
expect fun httpClient(config: HttpClientConfig<*>.() -> Unit = {}): HttpClient
14+
expect fun httpClient(trustAllCerts: Boolean = false, config: HttpClientConfig<*>.() -> Unit = {}): HttpClient
1515

1616
internal fun putHeaders(
1717
builder: HeadersBuilder,
@@ -59,8 +59,12 @@ interface HttpClientFactory {
5959
): HttpResponse
6060
}
6161

62-
object DefaultHttpClientFactory : HttpClientFactory {
63-
private val wsClient = httpClient {
62+
class DefaultHttpClientFactory(
63+
trustAllCerts: Boolean = false,
64+
): HttpClientFactory {
65+
private val wsClient = httpClient(
66+
trustAllCerts = trustAllCerts,
67+
) {
6468
install(Logging) {
6569
logger = object : Logger {
6670
override fun log(message: String) {
@@ -76,7 +80,9 @@ object DefaultHttpClientFactory : HttpClientFactory {
7680
// Linux curl engine doesn't work for simultaneous websocket and http request.
7781
// see https://youtrack.jetbrains.com/issue/KTOR-8259/
7882
// Use two http client could work around it.
79-
private val httpClient: HttpClient = if (!Platform.isLinux) wsClient else httpClient {
83+
private val httpClient: HttpClient = if (!Platform.isLinux) wsClient else httpClient(
84+
trustAllCerts = trustAllCerts,
85+
) {
8086
install(Logging) {
8187
logger = object : Logger {
8288
override fun log(message: String) {

kmp-socketio/src/commonTest/kotlin/com/piasy/kmp/socketio/socketio/ConnectionTest.kt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.piasy.kmp.socketio.socketio
22

3+
import com.piasy.kmp.socketio.engineio.transports.DefaultHttpClientFactory
34
import com.piasy.kmp.socketio.engineio.transports.WebSocket
45
import com.piasy.kmp.xlog.Logging
56
import io.ktor.util.date.*
@@ -75,6 +76,33 @@ abstract class ConnectionTest {
7576
assertEquals(now.toString(), args[3])
7677
}
7778

79+
@Test
80+
fun shouldConnectUntrusted() = doTest {
81+
val trustAllCertsHttpClientFactory = DefaultHttpClientFactory(
82+
trustAllCerts = true,
83+
)
84+
val responseResult = runCatching {
85+
trustAllCertsHttpClientFactory.httpRequest(
86+
url = "https://expired.badssl.com/",
87+
) {}
88+
}
89+
assertTrue(responseResult.isSuccess)
90+
assertEquals(responseResult.getOrThrow().status.value, 200)
91+
}
92+
93+
@Test
94+
fun shouldResetConnectionUntrusted() = doTest {
95+
val trustAllCertsHttpClientFactory = DefaultHttpClientFactory(
96+
trustAllCerts = false,
97+
)
98+
val responseResult = runCatching {
99+
trustAllCertsHttpClientFactory.httpRequest(
100+
url = "https://expired.badssl.com/",
101+
) {}
102+
}
103+
assertTrue(responseResult.isFailure)
104+
}
105+
78106
companion object {
79107
const val TAG = "ConnectionTest"
80108
}

kmp-socketio/src/jsMain/kotlin/com/piasy/kmp/socketio/engineio/transports/transport_impl.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import io.ktor.client.HttpClientConfig
44
import io.ktor.client.HttpClient
55
import io.ktor.client.engine.js.Js
66

7-
actual fun httpClient(config: HttpClientConfig<*>.() -> Unit): HttpClient = HttpClient(Js) {
7+
actual fun httpClient(trustAllCerts: Boolean, config: HttpClientConfig<*>.() -> Unit): HttpClient = HttpClient(Js) {
88
config(this)
9+
/** Ignore `unsafeClient` variable */
910
}

kmp-socketio/src/jvmMain/kotlin/com/piasy/kmp/socketio/engineio/transports/transport_impl.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,22 @@ package com.piasy.kmp.socketio.engineio.transports
33
import io.ktor.client.HttpClientConfig
44
import io.ktor.client.HttpClient
55
import io.ktor.client.engine.cio.CIO
6+
import java.security.cert.X509Certificate
7+
import javax.net.ssl.X509TrustManager
68

7-
actual fun httpClient(config: HttpClientConfig<*>.() -> Unit): HttpClient = HttpClient(CIO) {
9+
actual fun httpClient(trustAllCerts: Boolean, config: HttpClientConfig<*>.() -> Unit): HttpClient = HttpClient(CIO) {
810
config(this)
11+
if (trustAllCerts) {
12+
engine {
13+
https {
14+
trustManager = object: X509TrustManager {
15+
override fun checkClientTrusted(p0: Array<out X509Certificate>?, p1: String?) { }
16+
17+
override fun checkServerTrusted(p0: Array<out X509Certificate>?, p1: String?) { }
18+
19+
override fun getAcceptedIssuers(): Array<X509Certificate>? = null
20+
}
21+
}
22+
}
23+
}
924
}

kmp-socketio/src/jvmTest/kotlin/com/piasy/kmp/socketio/engineio/TestUtil.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ object TestUtil {
1717
fun transportFactory() = DefaultTransportFactory
1818

1919
@JvmStatic
20-
fun httpFactory() = DefaultHttpClientFactory
20+
fun httpFactory() = DefaultHttpClientFactory()
2121

2222
@JvmStatic
2323
fun getOpt(socket: EngineSocket) = socket.opt

kmp-socketio/src/linuxMain/kotlin/com/piasy/kmp/socketio/engineio/transports/transport_impl.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ import io.ktor.client.HttpClientConfig
44
import io.ktor.client.HttpClient
55
import io.ktor.client.engine.curl.Curl
66

7-
actual fun httpClient(config: HttpClientConfig<*>.() -> Unit): HttpClient = HttpClient(Curl) {
7+
actual fun httpClient(trustAllCerts: Boolean, config: HttpClientConfig<*>.() -> Unit): HttpClient = HttpClient(Curl) {
88
config(this)
9+
if (trustAllCerts) {
10+
engine {
11+
sslVerify = false
12+
}
13+
}
914
}

kmp-socketio/src/mingwMain/kotlin/com/piasy/kmp/socketio/engineio/transports/transport_impl.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ import io.ktor.client.HttpClientConfig
44
import io.ktor.client.HttpClient
55
import io.ktor.client.engine.winhttp.WinHttp
66

7-
actual fun httpClient(config: HttpClientConfig<*>.() -> Unit): HttpClient = HttpClient(WinHttp) {
7+
actual fun httpClient(trustAllCerts: Boolean, config: HttpClientConfig<*>.() -> Unit): HttpClient = HttpClient(WinHttp) {
88
config(this)
9+
if (trustAllCerts) {
10+
engine {
11+
sslVerify = false
12+
}
13+
}
914
}

0 commit comments

Comments
 (0)