From c4a0bc1416cc57c30fe88be13c6131ddeb62f34a Mon Sep 17 00:00:00 2001 From: Gabriel Peal Date: Mon, 1 Apr 2024 16:18:18 -0700 Subject: [PATCH] Fix Let's Encrypt TLS on old API versions (#2489) --- gradle/libs.versions.toml | 1 + snapshot-tests/build.gradle | 1 + .../snapshots/utils/HappoSnapshotter.kt | 48 ++++++++++++++++-- .../src/main/res/raw/isrgrootx1.der | Bin 0 -> 1391 bytes 4 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 snapshot-tests/src/main/res/raw/isrgrootx1.der diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 30e34993a9..3c37d092b1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -57,6 +57,7 @@ mockito-kotlin = "org.mockito:mockito-android:_" 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 ba1e5a0648..adde4e3f1e 100644 --- a/snapshot-tests/build.gradle +++ b/snapshot-tests/build.gradle @@ -60,6 +60,7 @@ dependencies { 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 82ea63a59b..ac613bde2c 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.os.Build 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.amazonaws.services.s3.model.CannedAccessControlList 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.io.IOException 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 @@ class HappoSnapshotter( // 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 @@ class HappoSnapshotter( 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 0000000000000000000000000000000000000000..9d2132e7f1e352fabac7eafb231488b5da91ffb2 GIT binary patch literal 1391 zcmXqLV$C*aVh&!w%*4pVB*@StaDKxjhsTjF$q#lXH+3@@@Un4gwRyCC=VfH%W@Rw& zH{>?pWMd9xVH0Kw4K~y?PzQ0igcUsVN>YpRQcDzqQMi96N{2F6x@sQ zOA8D|4TM2TnT2^ggM-`^g7WiA6e0`_)UeSUJ_S;M+V-u>HW)=goaf7yL{%}fvF;1?F_{JHX*^)7mb z_cWAjyQP1@qPLp4KvBB%lYz~z{&jb6C9i%h=6|S9(7WzD_ly5q%k{o&s`h%|Bc#ex z(95j3;9;=J8{wPpB=-w!_Uf_kT$~tqZ%sS8l;RAn=gy-c5l%vESRjulRoaDHHpQelw1#&mWmj<25Ut_nWV1qwMTG%s)L@ zZ#3Rz-J*5P@#PxEvZ-ABH|}5EDDklY(M=kbokat@+bL(=ez`Qo=d9_8$g;*;h-`WLMh;lRc_g>Iv-DFqo zCF5PpD)i^rs|NwXHO`YuHlHea-Y3t;=GdnK4#`;nE(6$dNYTB&bR(NQ2+$oz?wqHJLsjX!HYm3h*_fBZ@a%uek ze*2NA(-ox)>ah}I#svAgPldH?sMd^L9VXJTe#U|j5E;9$T9Os}&1 zjEw(TSb({M&43@o7Y6ZJ4VZzHfhFz=l^iUlGsD^9O_ z?o;@C)1`#9mMgeli7SS+ehlD?e0}ag-X~KPhVT7{&D4o6YKug*3J5*#Pa(8&H7gpwUsuC^Ywq~GKr43@rUtb$j%*V zXSzC!JAHIpY?|)Bn-;WsJ~s2)HigcR z-KW{sqcnToqipMNtEK|qJDkTmPjj*R=DdjQJNf?H>f^h&YWulf^SYpR=4sI>j;y6q zAB!&hzU1vmo%p4{|F6+t(%W~vdiUeP>Iq_(+2h=TYs}f5dM+QCHs|Whty&MJN;P<_ z^RZ+cWl3o${YKsGG(t*4WP8`@Gk9!gJ;MzXRq} z=D1zmBD#56Ufpb-X;wRebnUN2Km5&csO6u^ip8C`)?_`D(Av1dIWhXO{2lAwvQN4% zdQ0z%8|T;t|E@mm82|syq6>)@52x)|6WeWmz4WT_ftiBq<~klMDs9=v