Fix Let's Encrypt TLS on old API versions (#2489)
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 30e3499..3c37d09 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -57,6 +57,7 @@
mpandroidchart = "com.github.PhilJay:MPAndroidChart:_"
nullaway = "com.uber.nullaway:nullaway:_"
okhttp = "com.squareup.okhttp3:okhttp:_"
+okhttp-tls = "com.squareup.okhttp3:okhttp-tls:_"
okio = "com.squareup.okio:okio:_"
profileinstaller = "androidx.profileinstaller:profileinstaller:_"
qrcodereaderview = "com.dlazaro66.qrcodereaderview:qrcodereaderview:_"
diff --git a/snapshot-tests/build.gradle b/snapshot-tests/build.gradle
index ba1e5a0..adde4e3 100644
--- a/snapshot-tests/build.gradle
+++ b/snapshot-tests/build.gradle
@@ -60,6 +60,7 @@
implementation libs.compose.material
implementation libs.okhttp
+ implementation libs.okhttp.tls
androidTestImplementation libs.aws.android.sdk.s3
androidTestImplementation(libs.aws.android.sdk.mobile.client) { transitive = true }
diff --git a/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/utils/HappoSnapshotter.kt b/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/utils/HappoSnapshotter.kt
index 82ea63a..ac613bd 100644
--- a/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/utils/HappoSnapshotter.kt
+++ b/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/utils/HappoSnapshotter.kt
@@ -6,6 +6,7 @@
import android.util.Log
import com.airbnb.lottie.L
import com.airbnb.lottie.snapshots.BuildConfig
+import com.airbnb.lottie.snapshots.R
import com.amazonaws.auth.BasicAWSCredentials
import com.amazonaws.mobileconnectors.s3.transferutility.TransferObserver
import com.amazonaws.mobileconnectors.s3.transferutility.TransferUtility
@@ -14,10 +15,20 @@
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject
-import kotlinx.coroutines.*
-import okhttp3.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import okhttp3.Call
+import okhttp3.Callback
+import okhttp3.Credentials
import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.OkHttpClient
+import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
+import okhttp3.Response
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
@@ -25,8 +36,14 @@
import java.math.BigInteger
import java.net.URLEncoder
import java.nio.charset.Charset
+import java.security.KeyStore
import java.security.MessageDigest
-import java.util.*
+import java.security.cert.CertificateFactory
+import java.security.cert.X509Certificate
+import java.util.UUID
+import javax.net.ssl.SSLContext
+import javax.net.ssl.TrustManagerFactory
+import javax.net.ssl.X509TrustManager
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
@@ -60,7 +77,28 @@
// private val reportNamePrefixes = listOf(System.currentTimeMillis().toString()).filter { it.isNotBlank() }
private val reportNames = reportNamePrefixes.map { "$it-$androidVersion" }
- private val okhttp = OkHttpClient()
+ private val okhttp by lazy {
+ // https://androiddev.social/@botteaap/112108241212116279
+ // https://letsencrypt.org/2023/07/10/cross-sign-expiration.html
+ // https://letsencrypt.org/certs/isrgrootx1.der
+ val ca: X509Certificate = context.resources.openRawResource(R.raw.isrgrootx1).use {
+ CertificateFactory.getInstance("X.509").generateCertificate(it) as X509Certificate
+ }
+
+ val keyStore = KeyStore.getInstance(KeyStore.getDefaultType())
+ keyStore.load(null, null)
+ keyStore.setCertificateEntry("ca", ca)
+
+ val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
+ trustManagerFactory.init(keyStore)
+
+ val sslContext: SSLContext = SSLContext.getInstance("TLS")
+ sslContext.init(null, trustManagerFactory.trustManagers, null)
+
+ OkHttpClient.Builder()
+ .sslSocketFactory(sslContext.socketFactory, trustManagerFactory.trustManagers[0] as X509TrustManager)
+ .build()
+ }
private val transferUtility = TransferUtility.builder()
.context(context)
@@ -155,4 +193,4 @@
digest.update(this, 0, this.size)
return BigInteger(1, digest.digest()).toString(16)
}
-}
\ No newline at end of file
+}
diff --git a/snapshot-tests/src/main/res/raw/isrgrootx1.der b/snapshot-tests/src/main/res/raw/isrgrootx1.der
new file mode 100644
index 0000000..9d2132e
--- /dev/null
+++ b/snapshot-tests/src/main/res/raw/isrgrootx1.der
Binary files differ