diff --git a/sidecar/src/main/kotlin/dev/sanderling/sidecar/DriverBackend.kt b/sidecar/src/main/kotlin/dev/sanderling/sidecar/DriverBackend.kt index 36e4572..9553f20 100644 --- a/sidecar/src/main/kotlin/dev/sanderling/sidecar/DriverBackend.kt +++ b/sidecar/src/main/kotlin/dev/sanderling/sidecar/DriverBackend.kt @@ -552,7 +552,9 @@ class StubDriverBackend( // FAST_INPUT_SAFE matches text that can be typed with adb `input text`: short, // ASCII, and free of shell metacharacters and spaces. Anything else (unicode, // injection payloads, overflow-length strings) falls back to the driver path. -internal val FAST_INPUT_SAFE = Regex("^[A-Za-z0-9@._+-]{1,64}$") +// The first character excludes '-' so the text can never be read as an option +// by `input text`. +internal val FAST_INPUT_SAFE = Regex("^[A-Za-z0-9@._+][A-Za-z0-9@._+-]{0,63}$") class MaestroDriverBackend(private val serial: String?) : DriverBackend { private val dadb: dadb.Dadb diff --git a/sidecar/src/test/kotlin/dev/sanderling/sidecar/DadbTargetTest.kt b/sidecar/src/test/kotlin/dev/sanderling/sidecar/DadbTargetTest.kt index ae75b2c..7db71f8 100644 --- a/sidecar/src/test/kotlin/dev/sanderling/sidecar/DadbTargetTest.kt +++ b/sidecar/src/test/kotlin/dev/sanderling/sidecar/DadbTargetTest.kt @@ -16,4 +16,10 @@ class DadbTargetTest { @Test fun usbSerialRoutesThroughAdbServer() { assertEquals(DadbTarget.Server("663c91b1"), dadbTargetFor("663c91b1")) } + + // A colon with a non-numeric port is a USB serial that merely contains a + // colon, not a host:port, so it must route through the adb server. + @Test fun colonWithNonNumericPortIsAServerSerial() { + assertEquals(DadbTarget.Server("emulator:5554x"), dadbTargetFor("emulator:5554x")) + } } diff --git a/sidecar/src/test/kotlin/dev/sanderling/sidecar/InputTextTest.kt b/sidecar/src/test/kotlin/dev/sanderling/sidecar/InputTextTest.kt index e6e566f..4534a12 100644 --- a/sidecar/src/test/kotlin/dev/sanderling/sidecar/InputTextTest.kt +++ b/sidecar/src/test/kotlin/dev/sanderling/sidecar/InputTextTest.kt @@ -13,12 +13,13 @@ class InputTextTest { // correctly. A regression here would corrupt edge-case input or shell-inject // the device. @Test fun fastInputPathAcceptsOnlyShellSafeAscii() { - for (safe in listOf("demo@folio.app", "ledger123", "Checking", "-1", "1e10", "0.0000001")) { + for (safe in listOf("demo@folio.app", "ledger123", "Checking", "1e10", "0.0000001", "42")) { assertTrue(FAST_INPUT_SAFE.matches(safe), "expected fast path for: $safe") } val fallback = listOf( "Emergency Fund", "🙂🔥💸", " ", "\t\n", "'; DROP TABLE--", "", "../../etc/passwd", "%s%n", "", "a".repeat(4096), + "-1", "-rf", // a leading dash could be read as an option by `input text` ) for (text in fallback) { assertTrue(!FAST_INPUT_SAFE.matches(text), "expected driver fallback for: $text")