From 87c40f3b6021f7805c0cb68b6c7d00026c33b208 Mon Sep 17 00:00:00 2001 From: Arc Wang Date: Thu, 27 Dec 2018 10:19:21 +0800 Subject: [PATCH] Fix ZXing Wi-Fi QR code parsing bug. ZXing Wi-Fi QR code uses ';' as the delimiter for key/value pairs, should not treat an escaped "\;" as the delimiter. This fix also change the parsing result: If there is no specified key, the result value is null. If specified key exists with empty value, the result value is an empty string. Bug: 118797380 Test: atest WifiQrCodetest Change-Id: I786ce7c4fa66dcb31d8a61d7a3251c2f539ccc99 --- .../android/settings/wifi/dpp/WifiQrCode.java | 64 +++++++++++-------- ...ifiQrCodetest.java => WifiQrCodeTest.java} | 39 ++++++++--- 2 files changed, 68 insertions(+), 35 deletions(-) rename tests/unit/src/com/android/settings/wifi/dpp/{WifiQrCodetest.java => WifiQrCodeTest.java} (83%) diff --git a/src/com/android/settings/wifi/dpp/WifiQrCode.java b/src/com/android/settings/wifi/dpp/WifiQrCode.java index ebc39c371cb..d67533fdd46 100644 --- a/src/com/android/settings/wifi/dpp/WifiQrCode.java +++ b/src/com/android/settings/wifi/dpp/WifiQrCode.java @@ -22,7 +22,8 @@ import android.text.TextUtils; import androidx.annotation.Keep; import androidx.annotation.VisibleForTesting; -import java.util.regex.Matcher; +import java.util.Arrays; +import java.util.List; import java.util.regex.Pattern; /** @@ -62,7 +63,7 @@ public class WifiQrCode { public static final String PREFIX_ZXING_PASSWORD = "P:"; public static final String PREFIX_ZXING_HIDDEN_SSID = "H:"; - public static final String SUFFIX_QR_CODE = ";"; + public static final String DELIMITER_QR_CODE = ";"; private String mQrCode; @@ -100,22 +101,27 @@ public class WifiQrCode { /** Parses Wi-Fi DPP QR code string */ private void parseWifiDppQrCode(String qrCode) throws IllegalArgumentException { - String publicKey = getSubStringOrNull(qrCode, PREFIX_DPP_PUBLIC_KEY, SUFFIX_QR_CODE); + List keyValueList = getKeyValueList(qrCode, PREFIX_DPP, DELIMITER_QR_CODE); + + String publicKey = getValueOrNull(keyValueList, PREFIX_DPP_PUBLIC_KEY); if (TextUtils.isEmpty(publicKey)) { throw new IllegalArgumentException("Invalid format"); } mPublicKey = publicKey; - mInformation = getSubStringOrNull(qrCode, PREFIX_DPP_INFORMATION, SUFFIX_QR_CODE); + mInformation = getValueOrNull(keyValueList, PREFIX_DPP_INFORMATION); } /** Parses ZXing reader library's Wi-Fi Network config format */ private void parseZxingWifiQrCode(String qrCode) throws IllegalArgumentException { - String security = getSubStringOrNull(qrCode, PREFIX_ZXING_SECURITY, SUFFIX_QR_CODE); - String ssid = getSubStringOrNull(qrCode, PREFIX_ZXING_SSID, SUFFIX_QR_CODE); - String password = getSubStringOrNull(qrCode, PREFIX_ZXING_PASSWORD, SUFFIX_QR_CODE); - String hiddenSsidString = getSubStringOrNull(qrCode, PREFIX_ZXING_HIDDEN_SSID, - SUFFIX_QR_CODE); + List keyValueList = getKeyValueList(qrCode, PREFIX_ZXING_WIFI_NETWORK_CONFIG, + DELIMITER_QR_CODE); + + String security = getValueOrNull(keyValueList, PREFIX_ZXING_SECURITY); + String ssid = getValueOrNull(keyValueList, PREFIX_ZXING_SSID); + String password = getValueOrNull(keyValueList, PREFIX_ZXING_PASSWORD); + String hiddenSsidString = getValueOrNull(keyValueList, PREFIX_ZXING_HIDDEN_SSID); + boolean hiddenSsid = "true".equalsIgnoreCase(hiddenSsidString); //"\", ";", "," and ":" are escaped with a backslash "\", should remove at first @@ -132,33 +138,37 @@ public class WifiQrCode { } /** - * Gets the substring between prefix & suffix from input. + * Splits key/value pairs from qrCode * - * @param prefix the string before the returned substring - * @param suffix the string after the returned substring - * @return null if not exists, non-null otherwise + * @param qrCode the QR code raw string + * @param prefixQrCode the string before all key/value pairs in qrCode + * @param delimiter the string to split key/value pairs, can't contain a backslash + * @return a list contains string of key/value (e.g. K:key1) */ - private static String getSubStringOrNull(String input, String prefix, String suffix) { - StringBuilder sb = new StringBuilder(); - String regex = sb.append(prefix).append("(.*?)").append(suffix).toString(); - Pattern pattern = Pattern.compile(regex); - Matcher matcher = pattern.matcher(input); + private List getKeyValueList(String qrCode, String prefixQrCode, + String delimiter) { + String keyValueString = qrCode.substring(prefixQrCode.length()); - if (!matcher.find()) { - return null; + // Should not treat \delimiter as a delimiter + String regex = "(? result = Arrays.asList(keyValueString.split(regex)); + return result; + } + + private String getValueOrNull(List keyValueList, String prefix) { + for (String keyValue : keyValueList) { + if (keyValue.startsWith(prefix)) { + return keyValue.substring(prefix.length()); + } } - String target = matcher.group(1); - if (TextUtils.isEmpty(target)) { - return null; - } - - return target; + return null; } @Keep @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) - protected static String removeBackSlash(String input) { + protected String removeBackSlash(String input) { if (input == null) { return null; } diff --git a/tests/unit/src/com/android/settings/wifi/dpp/WifiQrCodetest.java b/tests/unit/src/com/android/settings/wifi/dpp/WifiQrCodeTest.java similarity index 83% rename from tests/unit/src/com/android/settings/wifi/dpp/WifiQrCodetest.java rename to tests/unit/src/com/android/settings/wifi/dpp/WifiQrCodeTest.java index 775ca489ffe..3595597160b 100644 --- a/tests/unit/src/com/android/settings/wifi/dpp/WifiQrCodetest.java +++ b/tests/unit/src/com/android/settings/wifi/dpp/WifiQrCodeTest.java @@ -29,7 +29,7 @@ import org.junit.runner.RunWith; @SmallTest @RunWith(AndroidJUnit4.class) -public class WifiQrCodetest { +public class WifiQrCodeTest { // Valid Wi-Fi DPP QR code & it's parameters private static final String VALID_WIFI_DPP_QR_CODE = "DPP:I:SN=4774LH2b4044;M:010203040506;K:" + "MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgADURzxmttZoIRIPWGoQMV00XHWCAQIhXruVWOz0NjlkIA=;;"; @@ -57,6 +57,13 @@ public class WifiQrCodetest { private static final String SSID_OF_VALID_ZXING_WIFI_QR_CODE = "mynetwork"; private static final String PASSWORD_OF_VALID_ZXING_WIFI_QR_CODE = "mypass"; + // Valid ZXing reader library's Wi-Fi Network config format - escaped characters + private static final String VALID_ZXING_WIFI_QR_CODE_SPECIAL_CHARACTERS = + "WIFI:T:WPA;S:mynetwork;P:m\\;y\\:p\\\\a\\,ss;H:true;;"; + + private static final String PASSWORD_OF_VALID_ZXING_WIFI_QR_CODE_SPECIAL_CHARACTERS = + "m;y:p\\a,ss"; + // Invalid scheme QR code private static final String INVALID_SCHEME_QR_CODE = "BT:T:WPA;S:mynetwork;P:mypass;H:true;;"; @@ -118,19 +125,35 @@ public class WifiQrCodetest { assertEquals(WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG, wifiQrCode.getScheme()); assertNotNull(config); - assertNull(config.getSecurity()); + assertEquals("", config.getSecurity()); assertEquals(SSID_OF_VALID_ZXING_WIFI_QR_CODE, config.getSsid()); - assertNull(config.getPreSharedKey()); + assertEquals("", config.getPreSharedKey()); assertEquals(false, config.getHiddenSsid()); } + @Test + public void parseValidZxingWifiQrCode_specialCharacters() { + WifiQrCode wifiQrCode = new WifiQrCode(VALID_ZXING_WIFI_QR_CODE_SPECIAL_CHARACTERS); + WifiNetworkConfig config = wifiQrCode.getWifiNetworkConfig(); + + assertEquals(WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG, wifiQrCode.getScheme()); + assertNotNull(config); + assertEquals(SECURITY_OF_VALID_ZXING_WIFI_QR_CODE, config.getSecurity()); + assertEquals(SSID_OF_VALID_ZXING_WIFI_QR_CODE, config.getSsid()); + assertEquals(PASSWORD_OF_VALID_ZXING_WIFI_QR_CODE_SPECIAL_CHARACTERS, + config.getPreSharedKey()); + assertEquals(true, config.getHiddenSsid()); + } + @Test public void testRemoveBackSlash() { - assertEquals("\\", WifiQrCode.removeBackSlash("\\\\")); - assertEquals("ab", WifiQrCode.removeBackSlash("a\\b")); - assertEquals("a", WifiQrCode.removeBackSlash("\\a")); - assertEquals("\\b", WifiQrCode.removeBackSlash("\\\\b")); - assertEquals("c\\", WifiQrCode.removeBackSlash("c\\\\")); + WifiQrCode wifiQrCode = new WifiQrCode(VALID_WIFI_DPP_QR_CODE); + + assertEquals("\\", wifiQrCode.removeBackSlash("\\\\")); + assertEquals("ab", wifiQrCode.removeBackSlash("a\\b")); + assertEquals("a", wifiQrCode.removeBackSlash("\\a")); + assertEquals("\\b", wifiQrCode.removeBackSlash("\\\\b")); + assertEquals("c\\", wifiQrCode.removeBackSlash("c\\\\")); } @Test