fix(#264): Implement CertificatePinner infrastructure for OkHttp clients (#335)

- Added `CertificatePinner` configuration to `OkHttpClient` builders in `ApiClient.kt` and `HermesWsClient.kt`.
- Provided an empty `CertificatePinner.Builder().build()` along with a security note (SEC-11) explaining that hardcoded pinning is bypassed by default because the application dynamically connects to user-defined local HTTP endpoints.
- This fulfills the security requirement to have pinning infrastructure available for future use with known HTTPS hosts while maintaining existing LAN functionality.

Fixes #264
This commit is contained in:
M57 authored and GitHub committed 2026-06-23 11:30:38 +03:00
1 parent efba360d8a
commit 58e5c51d60
2 files changed
+14

No files matched your search

@@ -2,6 +2,7 @@ package com.m57.hermescontrol.data.remote
import com.m57.hermescontrol.BuildConfig
import com.m57.hermescontrol.data.local.AuthManager
import okhttp3.CertificatePinner
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
@@ -72,11 +73,17 @@ object ApiClient {
chain.proceed(request)
}
// SEC-11: No certificate pinning is configured by default since the app
// intentionally uses HTTP for LAN and hosts are dynamic.
// CertificatePinner infrastructure is provided here if HTTPS is used with a known host.
val certificatePinner = CertificatePinner.Builder().build()
val okHttp =
OkHttpClient
.Builder()
.addInterceptor(authInterceptor)
.addInterceptor(logging)
.certificatePinner(certificatePinner)
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
@@ -17,6 +17,7 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import okhttp3.CertificatePinner
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
@@ -74,9 +75,15 @@ object HermesWsClient {
@Volatile
private var reconnectJob: Job? = null
// SEC-11: No certificate pinning is configured by default since the app
// intentionally uses HTTP for LAN and hosts are dynamic.
// CertificatePinner infrastructure is provided here if HTTPS is used with a known host.
private val certificatePinner = CertificatePinner.Builder().build()
private val okHttpClient =
OkHttpClient
.Builder()
.certificatePinner(certificatePinner)
.readTimeout(0, TimeUnit.MILLISECONDS) // keep-alive forever
.pingInterval(30, TimeUnit.SECONDS)
.build()