diff --git a/demo/src/main/java/ramp/network/demo/MainActivity.kt b/demo/src/main/java/ramp/network/demo/MainActivity.kt index 179e0d8..0549e2a 100644 --- a/demo/src/main/java/ramp/network/demo/MainActivity.kt +++ b/demo/src/main/java/ramp/network/demo/MainActivity.kt @@ -31,12 +31,8 @@ class MainActivity : AppCompatActivity() { val config = Config( hostLogoUrl = "https://ramp.network/assets/images/Logo.svg", hostAppName = "My App", - userAddress = "0x4b7f8e04b82ad7f9e4b4cc9e1f81c5938e1b719f", - url = "https://ri-widget-staging.firebaseapp.com/", - swapAsset = "ETH", - fiatCurrency = "USD", - fiatValue = "10", - selectedCountryCode = "US" + url = "https://ri-widget-dev2.firebaseapp.com", + hostApiKey = "input your host api key" ) // 4. Implement callbacks val callback = object : RampCallback { diff --git a/rampsdk/build.gradle b/rampsdk/build.gradle index 2624356..cf41af9 100644 --- a/rampsdk/build.gradle +++ b/rampsdk/build.gradle @@ -22,8 +22,8 @@ android { defaultConfig { minSdkVersion 21 targetSdkVersion 32 - versionCode 13 - versionName "1.3.10" + versionCode 14 + versionName "1.3.11" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles 'consumer-rules.pro' @@ -39,6 +39,12 @@ android { buildFeatures { viewBinding true } + + testOptions { + unitTests.all { + useJUnitPlatform() + } + } } @@ -67,9 +73,10 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - testImplementation 'junit:junit:4.13.2' + testImplementation "org.junit.jupiter:junit-jupiter:5.8.0" androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + } afterEvaluate { @@ -79,7 +86,7 @@ afterEvaluate { from components.release groupId = 'com.github.RampNetwork' artifactId = 'ramp-sdk-android' - version = '1.3.10' + version = '1.3.11' } } } diff --git a/rampsdk/src/main/java/network/ramp/sdk/ui/activity/RampPresenter.kt b/rampsdk/src/main/java/network/ramp/sdk/ui/activity/RampPresenter.kt index 0c22e98..3f62961 100644 --- a/rampsdk/src/main/java/network/ramp/sdk/ui/activity/RampPresenter.kt +++ b/rampsdk/src/main/java/network/ramp/sdk/ui/activity/RampPresenter.kt @@ -13,6 +13,7 @@ import kotlinx.coroutines.launch import network.ramp.sdk.events.EventBus import network.ramp.sdk.events.model.* import network.ramp.sdk.facade.Config +import network.ramp.sdk.utils.UrlSafeChecker import timber.log.Timber internal class RampPresenter( @@ -93,7 +94,7 @@ internal class RampPresenter( override fun buildUrl(config: Config): String { return config.url + - "?hostAppName=${config.hostAppName}" + + "/?hostAppName=${config.hostAppName}" + "&hostLogoUrl=${config.hostLogoUrl}" + concatenateIfNotBlank("&swapAsset=", config.swapAsset) + concatenateIfNotBlank("&swapAmount=", config.swapAmount) + @@ -189,7 +190,9 @@ internal class RampPresenter( systemOnBackPressed() } - private fun postMessage(event: T) { + fun isUrlSafe(url: String): Boolean = UrlSafeChecker.isUrlSafe(url) + + fun postMessage(event: T) { val eventJson = moshi .adapter(Event::class.java) .toJson(event) diff --git a/rampsdk/src/main/java/network/ramp/sdk/ui/activity/RampWidgetActivity.kt b/rampsdk/src/main/java/network/ramp/sdk/ui/activity/RampWidgetActivity.kt index 57be711..d8ad3d9 100644 --- a/rampsdk/src/main/java/network/ramp/sdk/ui/activity/RampWidgetActivity.kt +++ b/rampsdk/src/main/java/network/ramp/sdk/ui/activity/RampWidgetActivity.kt @@ -1,6 +1,7 @@ package network.ramp.sdk.ui.activity +import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import kotlinx.coroutines.CoroutineScope @@ -48,10 +49,24 @@ internal class RampWidgetActivity : AppCompatActivity(), Contract.View { if (savedInstanceState == null) { Timber.d(rampPresenter.buildUrl(config)) - binding.webView.loadUrl(rampPresenter.buildUrl(config)) + securityCheck(intent)?.let { + binding.webView.loadUrl(it) + } ?: close() } } + private fun securityCheck(intent: Intent): String? = + if (isInternalIntent(intent) && rampPresenter.isUrlSafe(config.url)) + rampPresenter.buildUrl(config) + else { + Timber.e("SECURITY ALERT - UNAUTHORIZED CALL") + null + } + + private fun isInternalIntent(intent: Intent): Boolean = + intent.data?.scheme == null + + override fun sendPostMessage(data: String) { val url = "javascript:(function f() { window.postMessage($data, \"*\"); })()" binding.webView.post { @@ -100,7 +115,5 @@ internal class RampWidgetActivity : AppCompatActivity(), Contract.View { companion object { const val ACTION_VIEW_INTENT = "android.intent.action.VIEW" - const val RAMP_PREFIX = "ramp" - const val HTTPS_SCHEME = "https" } } diff --git a/rampsdk/src/main/java/network/ramp/sdk/utils/UrlSafeChecker.kt b/rampsdk/src/main/java/network/ramp/sdk/utils/UrlSafeChecker.kt new file mode 100644 index 0000000..5123b70 --- /dev/null +++ b/rampsdk/src/main/java/network/ramp/sdk/utils/UrlSafeChecker.kt @@ -0,0 +1,25 @@ +package network.ramp.sdk.utils + +object UrlSafeChecker { + + private val listOfSafeUrls = listOf( + "https://ri-widget-dev2.firebaseapp.com", + "https://ri-widget-staging.firebaseapp.com", + "https://buy.ramp.network" + ) + private val listOfSafeRegex = listOf("^https://ri-widget-dev-(\\d+)\\.firebaseapp\\.com$") + + fun isUrlSafe(url: String) = checkStaticUrls(url) || checkRegexList(url) + + private fun checkStaticUrls(url: String): Boolean = listOfSafeUrls.contains(url) + + private fun checkRegexList(url: String): Boolean { + var isMatch = false + listOfSafeRegex.forEach { + val regex = Regex(pattern = it, options = setOf(RegexOption.IGNORE_CASE)) + if (regex.matches(url)) + isMatch = true + } + return isMatch + } +} \ No newline at end of file diff --git a/rampsdk/src/test/java/network/ramp/sdk/ExampleUnitTest.kt b/rampsdk/src/test/java/network/ramp/sdk/ExampleUnitTest.kt deleted file mode 100644 index af16a24..0000000 --- a/rampsdk/src/test/java/network/ramp/sdk/ExampleUnitTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -package network.ramp.sdk - -import org.junit.Test - -import org.junit.Assert.* - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} diff --git a/rampsdk/src/test/java/network/ramp/sdk/utils/UrlSafeCheckerTest.kt b/rampsdk/src/test/java/network/ramp/sdk/utils/UrlSafeCheckerTest.kt new file mode 100644 index 0000000..1e52008 --- /dev/null +++ b/rampsdk/src/test/java/network/ramp/sdk/utils/UrlSafeCheckerTest.kt @@ -0,0 +1,51 @@ +package network.ramp.sdk.utils + +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test + + +internal class UrlSafeCheckerTest { + + @Test + fun `isUrlSafe should return true fore safe urls`() { + val safeUrl1 = "https://ri-widget-dev2.firebaseapp.com" + val safeUrl2 = "https://ri-widget-staging.firebaseapp.com" + val safeUrl3 = "https://buy.ramp.network" + val safeUrl4 = "https://ri-widget-dev-5.firebaseapp.com" + val safeUrl5 = "https://ri-widget-dev-42.firebaseapp.com" + + + Assertions.assertAll( + { Assertions.assertTrue(UrlSafeChecker.isUrlSafe(safeUrl1)) }, + { Assertions.assertTrue(UrlSafeChecker.isUrlSafe(safeUrl2)) }, + { Assertions.assertTrue(UrlSafeChecker.isUrlSafe(safeUrl3)) }, + { Assertions.assertTrue(UrlSafeChecker.isUrlSafe(safeUrl4)) }, + { Assertions.assertTrue(UrlSafeChecker.isUrlSafe(safeUrl5)) } + ) + } + + @Test + fun `isUrlSafe should return false fore unsafe urls`() { + + val unsafeUrl1 = "https://ri-widget-devs2.firebaseapp.com" + val unsafeUrl2 = "ri-widget-staging.firebaseapp.com" + val unsafeUrl3 = "https://ngrok.io/buy.ramp.network" + val unsafeUrl4 = "https://ri-widget-dev-5.firebaseapp.com/sadasd" + val unsafeUrl5 = "https://ri-widget-dev.com/?https://ri-widget-devs2.firebaseapp.com" + val unsafeUrl6 = "https://ri-widget-dev-s.firebaseapp.com" + val unsafeUrl7 = "https://ri-widget-dev-10.firebaseapp.comsd" + val unsafeUrl8 = "https://ri-widget-dev-.firebaseapp.com" + + + Assertions.assertAll( + { Assertions.assertFalse(UrlSafeChecker.isUrlSafe(unsafeUrl1)) }, + { Assertions.assertFalse(UrlSafeChecker.isUrlSafe(unsafeUrl2)) }, + { Assertions.assertFalse(UrlSafeChecker.isUrlSafe(unsafeUrl3)) }, + { Assertions.assertFalse(UrlSafeChecker.isUrlSafe(unsafeUrl4)) }, + { Assertions.assertFalse(UrlSafeChecker.isUrlSafe(unsafeUrl5)) }, + { Assertions.assertFalse(UrlSafeChecker.isUrlSafe(unsafeUrl6)) }, + { Assertions.assertFalse(UrlSafeChecker.isUrlSafe(unsafeUrl7)) }, + { Assertions.assertFalse(UrlSafeChecker.isUrlSafe(unsafeUrl8)) } + ) + } +} \ No newline at end of file