From a4927b2f2e5379a049d823aa46d2d3ff2b831fc4 Mon Sep 17 00:00:00 2001 From: Julien Calixte Date: Fri, 20 Mar 2026 11:29:43 +0100 Subject: [PATCH] feat: add failOnError option for Certificate Transparency on Android Adds a certificateTransparency.android.failOnError config option (defaults to true). Lets projects pinned to appmattus/certificatetransparency 2.5.74 (Kotlin 1.x / Expo < 55) soft-fail CT validation to avoid stale log list rejecting valid connections. --- android/build.gradle | 1 + .../java/tech/bam/rnas/HttpClientOverride.kt | 6 +++- plugin/src/index.ts | 2 ++ plugin/src/types.ts | 3 ++ plugin/src/withCertificateTransparency.ts | 32 +++++++++++++++++++ 5 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 plugin/src/withCertificateTransparency.ts diff --git a/android/build.gradle b/android/build.gradle index a207444..4863dd4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -75,6 +75,7 @@ android { // package-specific config fields buildConfigField("String", "RNAS_PINNING_CONFIG", "\"${safeExtGet("RNAS_PINNING_CONFIG", "{}")}\"") buildConfigField("boolean", "RNAS_PREVENT_RECENT_SCREENSHOTS", safeExtGet("RNAS_PREVENT_RECENT_SCREENSHOTS", "false")) + buildConfigField("boolean", "RNAS_CT_FAIL_ON_ERROR", safeExtGet("RNAS_CT_FAIL_ON_ERROR", "true")) } lintOptions { abortOnError false diff --git a/android/src/main/java/tech/bam/rnas/HttpClientOverride.kt b/android/src/main/java/tech/bam/rnas/HttpClientOverride.kt index 50ef5a1..4f945de 100644 --- a/android/src/main/java/tech/bam/rnas/HttpClientOverride.kt +++ b/android/src/main/java/tech/bam/rnas/HttpClientOverride.kt @@ -37,7 +37,11 @@ public class SSLPinning : OkHttpClientFactory { * See more : https://github.com/appmattus/certificatetransparency#getting-started */ if (Build.VERSION.SDK_INT >= 26) { - clientBuilder.addNetworkInterceptor(CTInterceptorBuilder().build()) + clientBuilder.addNetworkInterceptor( + CTInterceptorBuilder() + .failOnError(BuildConfig.RNAS_CT_FAIL_ON_ERROR) + .build() + ) } return clientBuilder.build() diff --git a/plugin/src/index.ts b/plugin/src/index.ts index 735d5b0..09adcdf 100644 --- a/plugin/src/index.ts +++ b/plugin/src/index.ts @@ -1,5 +1,6 @@ import { ConfigPlugin } from "@expo/config-plugins"; import { RNASConfig } from "./types"; +import withCertificateTransparency from "./withCertificateTransparency"; import withDisableCache from "./withDisableCache"; import withpreventRecentScreenshots from "./withPreventRecentScreenshots"; import withSSLPinning from "./withSSLPinning"; @@ -9,6 +10,7 @@ const withRNAS: ConfigPlugin = (config, props) => { config = withpreventRecentScreenshots(config, props.preventRecentScreenshots); config = withDisableCache(config, props.disableCache); + config = withCertificateTransparency(config, props.certificateTransparency); return config; }; diff --git a/plugin/src/types.ts b/plugin/src/types.ts index 3abf251..a9bc958 100644 --- a/plugin/src/types.ts +++ b/plugin/src/types.ts @@ -9,4 +9,7 @@ export type RNASConfig = { disableCache?: { ios?: { enabled: boolean }; }; + certificateTransparency?: { + android?: { failOnError?: boolean }; + }; }; diff --git a/plugin/src/withCertificateTransparency.ts b/plugin/src/withCertificateTransparency.ts new file mode 100644 index 0000000..6df13f2 --- /dev/null +++ b/plugin/src/withCertificateTransparency.ts @@ -0,0 +1,32 @@ +import { ConfigPlugin, withGradleProperties } from "@expo/config-plugins"; +import { RNASConfig } from "./types"; + +type Props = RNASConfig["certificateTransparency"]; + +const withCertificateTransparency: ConfigPlugin = (config, props) => { + config = withGradleProperties(config, (config) => { + const gradleProperties = config.modResults; + + const failOnError = props?.android?.failOnError ?? true; + + const existingIndex = gradleProperties.findIndex( + (prop) => + prop.type === "property" && prop.key === "RNAS_CT_FAIL_ON_ERROR" + ); + if (existingIndex !== -1) { + gradleProperties.splice(existingIndex, 1); + } + + gradleProperties.push({ + type: "property", + key: "RNAS_CT_FAIL_ON_ERROR", + value: String(failOnError), + }); + + return config; + }); + + return config; +}; + +export default withCertificateTransparency;