From c13352bfa0cb921622504ccef4d6bdbeeddc65ed Mon Sep 17 00:00:00 2001 From: Juma Allan Date: Thu, 26 Sep 2024 14:13:10 +0300 Subject: [PATCH 1/3] fix unsecure object serialization --- .../main/java/com/smileidentity/SmileID.kt | 2 ++ .../fragment/BiometricKYCFragment.kt | 16 ++++++++++---- .../fragment/DocumentVerificationFragment.kt | 21 +++++++++++++------ .../EnhancedDocumentVerificationFragment.kt | 21 +++++++++++++------ .../SmartSelfieAuthenticationFragment.kt | 16 ++++++++++---- .../fragment/SmartSelfieEnrollmentFragment.kt | 13 ++++++++---- .../com/smileidentity/networking/Retrofit.kt | 9 ++++++++ 7 files changed, 74 insertions(+), 24 deletions(-) diff --git a/lib/src/main/java/com/smileidentity/SmileID.kt b/lib/src/main/java/com/smileidentity/SmileID.kt index 549c6cf3..ece4d144 100644 --- a/lib/src/main/java/com/smileidentity/SmileID.kt +++ b/lib/src/main/java/com/smileidentity/SmileID.kt @@ -20,6 +20,7 @@ import com.smileidentity.models.UploadRequest import com.smileidentity.networking.BiometricKycJobResultAdapter import com.smileidentity.networking.DocumentVerificationJobResultAdapter import com.smileidentity.networking.EnhancedDocumentVerificationJobResultAdapter +import com.smileidentity.networking.FileAdapter import com.smileidentity.networking.FileNameAdapter import com.smileidentity.networking.GzipRequestInterceptor import com.smileidentity.networking.JobResultAdapter @@ -496,6 +497,7 @@ object SmileID { .add(StringifiedBooleanAdapter) .add(MetadataAdapter) .add(FileNameAdapter) + .add(FileAdapter) .add(SmartSelfieJobResultAdapter) .add(DocumentVerificationJobResultAdapter) .add(BiometricKycJobResultAdapter) diff --git a/lib/src/main/java/com/smileidentity/fragment/BiometricKYCFragment.kt b/lib/src/main/java/com/smileidentity/fragment/BiometricKYCFragment.kt index caf0c95f..24a251ae 100644 --- a/lib/src/main/java/com/smileidentity/fragment/BiometricKYCFragment.kt +++ b/lib/src/main/java/com/smileidentity/fragment/BiometricKYCFragment.kt @@ -20,9 +20,9 @@ import com.smileidentity.models.IdInfo import com.smileidentity.results.BiometricKycResult import com.smileidentity.results.SmileIDResult import com.smileidentity.util.getParcelableCompat -import com.smileidentity.util.getSerializableCompat import com.smileidentity.util.randomJobId import com.smileidentity.util.randomUserId +import com.squareup.moshi.Types import kotlinx.collections.immutable.toImmutableMap /** @@ -125,6 +125,8 @@ class BiometricKYCFragment : Fragment() { } } +private val moshi = SmileID.moshi + private const val KEY_ID_INFO = "idInfo" private var Bundle.idInfo: IdInfo get() = getParcelableCompat(KEY_ID_INFO)!! @@ -161,9 +163,15 @@ private var Bundle.showInstructions: Boolean set(value) = putBoolean(KEY_SHOW_INSTRUCTIONS, value) private const val KEY_EXTRA_PARTNER_PARAMS = "extraPartnerParams" -private var Bundle.extraPartnerParams: HashMap? - get() = getSerializableCompat(KEY_EXTRA_PARTNER_PARAMS) - set(value) = putSerializable(KEY_EXTRA_PARTNER_PARAMS, value) +private val type = Types.newParameterizedType( + Map::class.java, + String::class.java, + String::class.java, +) +private val adapter = moshi.adapter>(type) +private var Bundle.extraPartnerParams: Map? + get() = getString(KEY_EXTRA_PARTNER_PARAMS)?.let { adapter.fromJson(it) } + set(value) = putString(KEY_EXTRA_PARTNER_PARAMS, value?.let { adapter.toJson(it) }) private var Bundle.smileIDResult: SmileIDResult get() = getParcelableCompat(KEY_RESULT)!! diff --git a/lib/src/main/java/com/smileidentity/fragment/DocumentVerificationFragment.kt b/lib/src/main/java/com/smileidentity/fragment/DocumentVerificationFragment.kt index 39a4e005..0c70bd4a 100644 --- a/lib/src/main/java/com/smileidentity/fragment/DocumentVerificationFragment.kt +++ b/lib/src/main/java/com/smileidentity/fragment/DocumentVerificationFragment.kt @@ -19,9 +19,9 @@ import com.smileidentity.fragment.SmartSelfieEnrollmentFragment.Companion.result import com.smileidentity.results.DocumentVerificationResult import com.smileidentity.results.SmileIDResult import com.smileidentity.util.getParcelableCompat -import com.smileidentity.util.getSerializableCompat import com.smileidentity.util.randomJobId import com.smileidentity.util.randomUserId +import com.squareup.moshi.Types import java.io.File import kotlinx.collections.immutable.toImmutableMap @@ -138,6 +138,8 @@ class DocumentVerificationFragment : Fragment() { } } +private val moshi = SmileID.moshi + private const val KEY_USER_ID = "userId" private var Bundle.userId: String get() = getString(KEY_USER_ID)!! @@ -197,14 +199,21 @@ private var Bundle.captureBothSides: Boolean set(value) = putBoolean(KEY_CAPTURE_BOTH_SIDES, value) private const val KEY_BYPASS_SELFIE_CAPTURE_WITH_FILE = "bypassSelfieCaptureWithFile" +private val fileAdapter = moshi.adapter(File::class.java) private var Bundle.bypassSelfieCaptureWithFile: File? - get() = getSerializableCompat(KEY_BYPASS_SELFIE_CAPTURE_WITH_FILE) as File? - set(value) = putSerializable(KEY_BYPASS_SELFIE_CAPTURE_WITH_FILE, value) + get() = getString(KEY_BYPASS_SELFIE_CAPTURE_WITH_FILE)?.let { fileAdapter.fromJson(it) } + set(value) = putString(KEY_BYPASS_SELFIE_CAPTURE_WITH_FILE, fileAdapter.toJson(value)) private const val KEY_EXTRA_PARTNER_PARAMS = "extraPartnerParams" -private var Bundle.extraPartnerParams: HashMap? - get() = getSerializableCompat(KEY_EXTRA_PARTNER_PARAMS) - set(value) = putSerializable(KEY_EXTRA_PARTNER_PARAMS, value) +private val type = Types.newParameterizedType( + Map::class.java, + String::class.java, + String::class.java, +) +private val adapter = moshi.adapter>(type) +private var Bundle.extraPartnerParams: Map? + get() = getString(KEY_EXTRA_PARTNER_PARAMS)?.let { adapter.fromJson(it) } + set(value) = putString(KEY_EXTRA_PARTNER_PARAMS, value?.let { adapter.toJson(it) }) private var Bundle.smileIDResult: SmileIDResult get() = getParcelableCompat(KEY_RESULT)!! diff --git a/lib/src/main/java/com/smileidentity/fragment/EnhancedDocumentVerificationFragment.kt b/lib/src/main/java/com/smileidentity/fragment/EnhancedDocumentVerificationFragment.kt index 5c499ca3..feba1b8d 100644 --- a/lib/src/main/java/com/smileidentity/fragment/EnhancedDocumentVerificationFragment.kt +++ b/lib/src/main/java/com/smileidentity/fragment/EnhancedDocumentVerificationFragment.kt @@ -17,9 +17,9 @@ import com.smileidentity.fragment.SmartSelfieEnrollmentFragment.Companion.result import com.smileidentity.results.EnhancedDocumentVerificationResult import com.smileidentity.results.SmileIDResult import com.smileidentity.util.getParcelableCompat -import com.smileidentity.util.getSerializableCompat import com.smileidentity.util.randomJobId import com.smileidentity.util.randomUserId +import com.squareup.moshi.Types import java.io.File import kotlinx.collections.immutable.toImmutableMap @@ -136,6 +136,8 @@ class EnhancedDocumentVerificationFragment : Fragment() { } } +private val moshi = SmileID.moshi + private const val KEY_USER_ID = "userId" private var Bundle.userId: String get() = getString(KEY_USER_ID)!! @@ -190,9 +192,10 @@ private var Bundle.idAspectRatio: Float set(value) = putFloat(KEY_ID_ASPECT_RATIO, value) private const val KEY_BYPASS_SELFIE_CAPTURE_WITH_FILE = "bypassSelfieCaptureWithFile" +private val fileAdapter = moshi.adapter(File::class.java) private var Bundle.bypassSelfieCaptureWithFile: File? - get() = getSerializableCompat(KEY_BYPASS_SELFIE_CAPTURE_WITH_FILE) as File? - set(value) = putSerializable(KEY_BYPASS_SELFIE_CAPTURE_WITH_FILE, value) + get() = getString(KEY_BYPASS_SELFIE_CAPTURE_WITH_FILE)?.let { fileAdapter.fromJson(it) } + set(value) = putString(KEY_BYPASS_SELFIE_CAPTURE_WITH_FILE, fileAdapter.toJson(value)) private const val KEY_CAPTURE_BOTH_SIDES = "captureBothSides" @@ -201,9 +204,15 @@ private var Bundle.captureBothSides: Boolean set(value) = putBoolean(KEY_CAPTURE_BOTH_SIDES, value) private const val KEY_EXTRA_PARTNER_PARAMS = "extraPartnerParams" -private var Bundle.extraPartnerParams: HashMap? - get() = getSerializableCompat(KEY_EXTRA_PARTNER_PARAMS) - set(value) = putSerializable(KEY_EXTRA_PARTNER_PARAMS, value) +private val type = Types.newParameterizedType( + Map::class.java, + String::class.java, + String::class.java, +) +private val adapter = moshi.adapter>(type) +private var Bundle.extraPartnerParams: Map? + get() = getString(KEY_EXTRA_PARTNER_PARAMS)?.let { adapter.fromJson(it) } + set(value) = putString(KEY_EXTRA_PARTNER_PARAMS, value?.let { adapter.toJson(it) }) private var Bundle.smileIDResult: SmileIDResult get() = getParcelableCompat(DocumentVerificationFragment.KEY_RESULT)!! diff --git a/lib/src/main/java/com/smileidentity/fragment/SmartSelfieAuthenticationFragment.kt b/lib/src/main/java/com/smileidentity/fragment/SmartSelfieAuthenticationFragment.kt index 27fa072b..15913fb9 100644 --- a/lib/src/main/java/com/smileidentity/fragment/SmartSelfieAuthenticationFragment.kt +++ b/lib/src/main/java/com/smileidentity/fragment/SmartSelfieAuthenticationFragment.kt @@ -17,9 +17,9 @@ import com.smileidentity.fragment.SmartSelfieEnrollmentFragment.Companion.result import com.smileidentity.results.SmartSelfieResult import com.smileidentity.results.SmileIDResult import com.smileidentity.util.getParcelableCompat -import com.smileidentity.util.getSerializableCompat import com.smileidentity.util.randomJobId import com.smileidentity.util.randomUserId +import com.squareup.moshi.Types import kotlinx.collections.immutable.toImmutableMap /** @@ -131,6 +131,8 @@ class SmartSelfieAuthenticationFragment : Fragment() { } } +private val moshi = SmileID.moshi + private const val KEY_ALLOW_AGENT_MODE = "allowAgentMode" private var Bundle.allowAgentMode: Boolean get() = getBoolean(KEY_ALLOW_AGENT_MODE) @@ -162,9 +164,15 @@ private var Bundle.showInstructions: Boolean set(value) = putBoolean(KEY_SHOW_INSTRUCTIONS, value) private const val KEY_EXTRA_PARTNER_PARAMS = "extraPartnerParams" -private var Bundle.extraPartnerParams: HashMap? - get() = getSerializableCompat(KEY_EXTRA_PARTNER_PARAMS) - set(value) = putSerializable(KEY_EXTRA_PARTNER_PARAMS, value) +private val type = Types.newParameterizedType( + Map::class.java, + String::class.java, + String::class.java, +) +private val adapter = moshi.adapter>(type) +private var Bundle.extraPartnerParams: Map? + get() = getString(KEY_EXTRA_PARTNER_PARAMS)?.let { adapter.fromJson(it) } + set(value) = putString(KEY_EXTRA_PARTNER_PARAMS, value?.let { adapter.toJson(it) }) private var Bundle.smileIdResult: SmileIDResult get() = getParcelableCompat(KEY_RESULT)!! diff --git a/lib/src/main/java/com/smileidentity/fragment/SmartSelfieEnrollmentFragment.kt b/lib/src/main/java/com/smileidentity/fragment/SmartSelfieEnrollmentFragment.kt index 088dc0ca..07af2230 100644 --- a/lib/src/main/java/com/smileidentity/fragment/SmartSelfieEnrollmentFragment.kt +++ b/lib/src/main/java/com/smileidentity/fragment/SmartSelfieEnrollmentFragment.kt @@ -15,9 +15,9 @@ import com.smileidentity.fragment.SmartSelfieEnrollmentFragment.Companion.result import com.smileidentity.results.SmartSelfieResult import com.smileidentity.results.SmileIDResult import com.smileidentity.util.getParcelableCompat -import com.smileidentity.util.getSerializableCompat import com.smileidentity.util.randomJobId import com.smileidentity.util.randomUserId +import com.squareup.moshi.Types import kotlinx.collections.immutable.toImmutableMap /** @@ -128,6 +128,8 @@ class SmartSelfieEnrollmentFragment : Fragment() { } } +private val moshi = SmileID.moshi + private const val KEY_ALLOW_AGENT_MODE = "allowAgentMode" private var Bundle.allowAgentMode: Boolean get() = getBoolean(KEY_ALLOW_AGENT_MODE) @@ -159,9 +161,12 @@ private var Bundle.showInstructions: Boolean set(value) = putBoolean(KEY_SHOW_INSTRUCTIONS, value) private const val KEY_EXTRA_PARTNER_PARAMS = "extraPartnerParams" -private var Bundle.extraPartnerParams: HashMap? - get() = getSerializableCompat(KEY_EXTRA_PARTNER_PARAMS) - set(value) = putSerializable(KEY_EXTRA_PARTNER_PARAMS, value) +private val type = + Types.newParameterizedType(Map::class.java, String::class.java, String::class.java) +private val adapter = moshi.adapter>(type) +private var Bundle.extraPartnerParams: Map? + get() = getString(KEY_EXTRA_PARTNER_PARAMS)?.let { adapter.fromJson(it) } + set(value) = putString(KEY_EXTRA_PARTNER_PARAMS, value?.let { adapter.toJson(it) }) private var Bundle.smileIdResult: SmileIDResult get() = getParcelableCompat(KEY_RESULT)!! diff --git a/lib/src/main/java/com/smileidentity/networking/Retrofit.kt b/lib/src/main/java/com/smileidentity/networking/Retrofit.kt index 8c54ba14..288d7e00 100644 --- a/lib/src/main/java/com/smileidentity/networking/Retrofit.kt +++ b/lib/src/main/java/com/smileidentity/networking/Retrofit.kt @@ -118,6 +118,15 @@ object FileNameAdapter { fun fromJson(fileName: String): File = File(fileName) } +@Suppress("unused") +object FileAdapter { + @ToJson + fun toJson(file: File): String = file.absolutePath + + @FromJson + fun fromJson(path: String): File = File(path) +} + @Suppress("unused") object JobResultAdapter { @FromJson From 585d240e285439437d7c3c4403b81ecbbd405457 Mon Sep 17 00:00:00 2001 From: Juma Allan Date: Thu, 26 Sep 2024 16:27:50 +0300 Subject: [PATCH 2/3] updated CHANGELOG.md --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0319cf61..4c8c0c3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,12 @@ # Release Notes +## Unreleased + +* Fix insecure object serialization on fragments + ## 10.3.0 -* Changed initialize() to return a deferred result (allow partners to handle errors) +* Changed `initialize()` to return a deferred result (allow partners to handle errors) * Update to Compose Fragment and remove ComposeView ## 10.2.7 From e9c8c00808d3721334d0181b5f8e99a92fe93d67 Mon Sep 17 00:00:00 2001 From: Juma Allan Date: Fri, 27 Sep 2024 11:19:12 +0300 Subject: [PATCH 3/3] updated CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c8c0c3e..0b70141d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Release Notes -## Unreleased +## 10.3.1 * Fix insecure object serialization on fragments