Skip to content

Commit

Permalink
merge(#21): feat: validate config url and intent origin check
Browse files Browse the repository at this point in the history
  • Loading branch information
pawel-zak authored Nov 8, 2022
1 parent 414eb73 commit a1dedb4
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 32 deletions.
8 changes: 2 additions & 6 deletions demo/src/main/java/ramp/network/demo/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
15 changes: 11 additions & 4 deletions rampsdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -39,6 +39,12 @@ android {
buildFeatures {
viewBinding true
}

testOptions {
unitTests.all {
useJUnitPlatform()
}
}
}


Expand Down Expand Up @@ -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 {
Expand All @@ -79,7 +86,7 @@ afterEvaluate {
from components.release
groupId = 'com.github.RampNetwork'
artifactId = 'ramp-sdk-android'
version = '1.3.10'
version = '1.3.11'
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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) +
Expand Down Expand Up @@ -189,7 +190,9 @@ internal class RampPresenter(
systemOnBackPressed()
}

private fun <T : Event> postMessage(event: T) {
fun isUrlSafe(url: String): Boolean = UrlSafeChecker.isUrlSafe(url)

fun <T : Event> postMessage(event: T) {
val eventJson = moshi
.adapter(Event::class.java)
.toJson(event)
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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"
}
}
25 changes: 25 additions & 0 deletions rampsdk/src/main/java/network/ramp/sdk/utils/UrlSafeChecker.kt
Original file line number Diff line number Diff line change
@@ -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
}
}
17 changes: 0 additions & 17 deletions rampsdk/src/test/java/network/ramp/sdk/ExampleUnitTest.kt

This file was deleted.

51 changes: 51 additions & 0 deletions rampsdk/src/test/java/network/ramp/sdk/utils/UrlSafeCheckerTest.kt
Original file line number Diff line number Diff line change
@@ -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)) }
)
}
}

0 comments on commit a1dedb4

Please sign in to comment.