Skip to content

Commit

Permalink
Handle more cases of mistyped vnc:// URIs + Refactor VncUri
Browse files Browse the repository at this point in the history
  • Loading branch information
gujjwal00 committed Feb 6, 2024
1 parent 4a91bd5 commit 7920cc9
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 39 deletions.
35 changes: 11 additions & 24 deletions app/src/androidTest/java/com/gaurav/avnc/vnc/VncUriTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,18 @@

package com.gaurav.avnc.vnc

import android.net.Uri
import com.gaurav.avnc.model.ServerProfile
import org.junit.Assert.assertEquals
import org.junit.Test

class VncUriTest {

@Test
fun blankStringTest() {
fun blankTest() {
val uri = VncUri("")
assertEquals("", uri.host)
}

@Test
fun blankUriTest() {
val uri = VncUri(Uri.parse(""))
assertEquals("", uri.host)
}

@Test
fun basicHostTest() {
val uri = VncUri("host")
Expand All @@ -37,19 +30,7 @@ class VncUriTest {
}

@Test
fun simpleUriTest1() {
val uri = VncUri(Uri.parse("vnc://10.0.0.1:5901/?VncPassword=foo&SecurityType=2&ViewOnly=true"))
assertEquals("10.0.0.1", uri.host)
assertEquals(5901, uri.port)
assertEquals("", uri.username)
assertEquals("foo", uri.password)
assertEquals(2, uri.securityType)
assertEquals(true, uri.viewOnly)
assertEquals(ServerProfile.CHANNEL_TCP, uri.channelType)
}

@Test
fun simpleUriTest2() { //Same as above but with String argument to constructor
fun simpleUriTest() {
val uri = VncUri("vnc://10.0.0.1:5901/?VncPassword=foo&SecurityType=2&ViewOnly=true")
assertEquals("10.0.0.1", uri.host)
assertEquals(5901, uri.port)
Expand Down Expand Up @@ -86,8 +67,14 @@ class VncUriTest {
}

@Test
fun opaqueUri() {
// Correct format is 'vnc://host'
assertEquals("", VncUri("vnc:host").host)
fun schemaVariationTest() {
// We should gracefully handle these "invalid" schema types
assertEquals("vnc://host", VncUri("host").toString()) // Completely missing
assertEquals("vnc://host", VncUri("vnc:host").toString()) // Slashes missing
assertEquals("vnc://host", VncUri("vnc:/host").toString()) // Slash missing
assertEquals("vnc://host", VncUri("VNC://host").toString()) // Uppercase

// Make sure only start of URI is checked for variations
assertEquals("vnc://avnc://host", VncUri("avnc://host").toString())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class IntentReceiverActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)

if (intent.data?.scheme == "vnc")
launchFromVncUri(VncUri(intent.data!!))
launchFromVncUri(VncUri(intent.data!!.toString()))
else if (intent.hasExtra(SHORTCUT_PROFILE_ID_KEY))
launchFromProfileId(intent.getLongExtra(SHORTCUT_PROFILE_ID_KEY, 0))
else
Expand Down
29 changes: 15 additions & 14 deletions app/src/main/java/com/gaurav/avnc/vnc/VncUri.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,31 @@ import java.net.URI
* This class implements the `vnc` URI scheme.
* Reference: https://tools.ietf.org/html/rfc7869
*
* If `host` in URI is an IPv6 address, it MUST be wrapped in square brackets.
* If host in given URI string is an IPv6 address, it MUST be wrapped in square brackets.
* (This requirement come from using Java [URI] internally.)
*
* If given URI doesn't start with 'vnc://' schema, it will be automatically added.
*/
class VncUri(private val uri: Uri) {
class VncUri(str: String) {

/**
* Create new instance from URI string.
* VNC schema will be added if missing.
* Add schema if missing.
* It is also common for users to accidentally type 'vnc:host' instead of 'vnc://host',
* so we gracefully handle that case too.
*/
constructor(uriString: String) : this(
if (uriString.startsWith("vnc://"))
Uri.parse(uriString)
else
Uri.parse("vnc://$uriString")
)
private val uriString = str.replaceFirst(Regex("^(vnc:/?/?)?", RegexOption.IGNORE_CASE), "vnc://")

private val uri = Uri.parse(uriString)

/**
* Older versions of Android [Uri] does not support IPv6, so we need to use Java [URI] for host & port.
*
* It also serves as a validation step because [URI] verifies that address is well-formed.
*/
private val javaUri = runCatching { URI(uri.toString()).also { check(!it.isOpaque) } }.getOrDefault(URI(""))
private val javaUri = runCatching { URI(uriString) }.getOrNull()


val host = javaUri.host?.trim('[', ']') ?: ""
val port = if (javaUri.port == -1) 5900 else javaUri.port
val host = javaUri?.host?.trim('[', ']') ?: ""
val port = if (javaUri?.port == -1) 5900 else javaUri?.port ?: 5900
val connectionName = uri.getQueryParameter("ConnectionName") ?: ""
val username = uri.getQueryParameter("VncUsername") ?: ""
val password = uri.getQueryParameter("VncPassword") ?: ""
Expand Down Expand Up @@ -74,4 +73,6 @@ class VncUri(private val uri: Uri) {
sshAuthType = ServerProfile.SSH_AUTH_PASSWORD,
sshPassword = sshPassword
)

override fun toString() = uriString
}

0 comments on commit 7920cc9

Please sign in to comment.