Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser.externalnav; | 5 package org.chromium.chrome.browser.externalnav; |
| 6 | 6 |
| 7 import android.content.ActivityNotFoundException; | 7 import android.content.ActivityNotFoundException; |
| 8 import android.content.ComponentName; | 8 import android.content.ComponentName; |
| 9 import android.content.Intent; | 9 import android.content.Intent; |
| 10 import android.content.pm.PackageManager; | |
| 10 import android.content.pm.ResolveInfo; | 11 import android.content.pm.ResolveInfo; |
| 12 import android.content.pm.Signature; | |
| 11 import android.net.Uri; | 13 import android.net.Uri; |
| 12 import android.os.SystemClock; | 14 import android.os.SystemClock; |
| 13 import android.provider.Browser; | 15 import android.provider.Browser; |
| 14 import android.text.TextUtils; | 16 import android.text.TextUtils; |
| 15 import android.webkit.WebView; | 17 import android.webkit.WebView; |
| 16 | 18 |
| 17 import org.chromium.base.CommandLine; | 19 import org.chromium.base.CommandLine; |
| 18 import org.chromium.base.Log; | 20 import org.chromium.base.Log; |
| 19 import org.chromium.base.VisibleForTesting; | 21 import org.chromium.base.VisibleForTesting; |
| 20 import org.chromium.base.metrics.RecordHistogram; | 22 import org.chromium.base.metrics.RecordHistogram; |
| 21 import org.chromium.chrome.browser.ChromeSwitches; | 23 import org.chromium.chrome.browser.ChromeSwitches; |
| 22 import org.chromium.chrome.browser.IntentHandler; | 24 import org.chromium.chrome.browser.IntentHandler; |
| 23 import org.chromium.chrome.browser.UrlConstants; | 25 import org.chromium.chrome.browser.UrlConstants; |
| 24 import org.chromium.chrome.browser.tab.Tab; | 26 import org.chromium.chrome.browser.tab.Tab; |
| 25 import org.chromium.chrome.browser.tab.TabRedirectHandler; | 27 import org.chromium.chrome.browser.tab.TabRedirectHandler; |
| 26 import org.chromium.chrome.browser.util.IntentUtils; | 28 import org.chromium.chrome.browser.util.IntentUtils; |
| 27 import org.chromium.chrome.browser.util.UrlUtilities; | 29 import org.chromium.chrome.browser.util.UrlUtilities; |
| 28 import org.chromium.ui.base.PageTransition; | 30 import org.chromium.ui.base.PageTransition; |
| 29 | 31 |
| 30 import java.net.URI; | 32 import java.net.URI; |
| 33 import java.security.MessageDigest; | |
| 34 import java.security.NoSuchAlgorithmException; | |
| 35 import java.util.Collections; | |
| 31 import java.util.HashSet; | 36 import java.util.HashSet; |
| 32 import java.util.List; | 37 import java.util.List; |
| 38 import java.util.Set; | |
| 33 import java.util.concurrent.TimeUnit; | 39 import java.util.concurrent.TimeUnit; |
| 34 | 40 |
| 35 /** | 41 /** |
| 36 * Logic related to the URL overriding/intercepting functionality. | 42 * Logic related to the URL overriding/intercepting functionality. |
| 37 * This feature allows Chrome to convert certain navigations to Android Intents allowing | 43 * This feature allows Chrome to convert certain navigations to Android Intents allowing |
| 38 * applications like Youtube to direct users clicking on a http(s) link to their native app. | 44 * applications like Youtube to direct users clicking on a http(s) link to their native app. |
| 39 */ | 45 */ |
| 40 public class ExternalNavigationHandler { | 46 public class ExternalNavigationHandler { |
| 41 private static final String TAG = "UrlHandler"; | 47 private static final String TAG = "UrlHandler"; |
| 42 private static final String SCHEME_WTAI = "wtai://wp/"; | 48 private static final String SCHEME_WTAI = "wtai://wp/"; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 105 boolean hasBrowserFallbackUrl = false; | 111 boolean hasBrowserFallbackUrl = false; |
| 106 String browserFallbackUrl = | 112 String browserFallbackUrl = |
| 107 IntentUtils.safeGetStringExtra(intent, EXTRA_BROWSER_FALLBACK_UR L); | 113 IntentUtils.safeGetStringExtra(intent, EXTRA_BROWSER_FALLBACK_UR L); |
| 108 if (browserFallbackUrl != null | 114 if (browserFallbackUrl != null |
| 109 && UrlUtilities.isValidForIntentFallbackNavigation(browserFallba ckUrl)) { | 115 && UrlUtilities.isValidForIntentFallbackNavigation(browserFallba ckUrl)) { |
| 110 hasBrowserFallbackUrl = true; | 116 hasBrowserFallbackUrl = true; |
| 111 } else { | 117 } else { |
| 112 browserFallbackUrl = null; | 118 browserFallbackUrl = null; |
| 113 } | 119 } |
| 114 | 120 |
| 121 try { | |
| 122 //scheme | |
| 123 String scheme = intent.getData().getScheme(); | |
| 124 String fragment = intent.getData().getFragment(); | |
| 125 if (!TextUtils.isEmpty(scheme) && null != fragment && fragment.conta ins(";")) { | |
| 126 String[] parts = fragment.split(";"); | |
| 127 String[] part = null; | |
|
palmer
2016/07/20 18:53:48
Declare this where it's used (line 146).
| |
| 128 Set<Set<String>> allFingerPrint256 = new HashSet<>(); | |
| 129 String fingerPrint256 = ""; | |
|
palmer
2016/07/20 18:53:48
Declare this where it's used (line 148).
| |
| 130 String pkgName = ""; | |
| 131 /** | |
| 132 * same package name , different keystores, generated fingerprin t256 set. | |
| 133 * | |
| 134 * 1.an app's signature may update and change from old, so need config and | |
| 135 * support new and old, but this is optional.(e.g. a.only config new fingerprint | |
| 136 * b. only config old fingerprint. c.config new and old fingerpr int) | |
| 137 * | |
| 138 * 2.one apk itself may contain more than one keystore to sign. | |
| 139 * | |
| 140 * example: suppose apk's new signature is 3A4FXXXXXX,12XXXXXXX, and old signature | |
| 141 * is 1B2AXXXX. you can config the intent like "...;sha256=3A4FX XXXXX,12XXXXXXX;.." | |
| 142 * or "..;sha256=3A4FXXXXXX,12XXXXXXX|1B2AXXXX;.." | |
| 143 */ | |
| 144 String[] fingerPrint256DifGroups; | |
| 145 for (String each : parts) { | |
| 146 part = each.split("="); | |
| 147 if (part[0].equals("sha256")) { | |
| 148 fingerPrint256 = part[1]; | |
| 149 fingerPrint256DifGroups = fingerPrint256.split("\\|"); | |
| 150 for (String v : fingerPrint256DifGroups) { | |
| 151 Set<String> fingerPrint256GroupSignKeySet = new Hash Set<>(); | |
| 152 Collections.addAll(fingerPrint256GroupSignKeySet, v. split(",")); | |
| 153 allFingerPrint256.add(fingerPrint256GroupSignKeySet) ; | |
| 154 } | |
| 155 } | |
| 156 if (part[0].equals("package")) { | |
| 157 pkgName = part[1]; | |
| 158 } | |
| 159 } | |
| 160 if (!TextUtils.isEmpty(pkgName) && !TextUtils.isEmpty(fingerPrin t256)) { | |
| 161 PackageManager pm = mDelegate.getAssociatedActivityContext() | |
| 162 .getPackageManager(); | |
| 163 Signature[] signatures = pm.getPackageInfo(pkgName, | |
| 164 PackageManager.GET_SIGNATURES).signatures; | |
| 165 HashSet<String> fingerPrint256Set = new HashSet<String>(); | |
| 166 String fingerPrint = ""; | |
|
palmer
2016/07/20 18:53:48
Declare this where it's used (line 169).
| |
| 167 if (signatures.length > 0) { | |
| 168 for (Signature each : signatures) { | |
| 169 fingerPrint = computeNormalizedSha256Fingerprint(eac h.toByteArray()); | |
| 170 fingerPrint256Set.add(fingerPrint); | |
| 171 } | |
| 172 } | |
| 173 if (!allFingerPrint256.contains(fingerPrint256Set)) { | |
| 174 return OverrideUrlLoadingResult.NO_OVERRIDE; | |
| 175 } | |
| 176 } | |
| 177 } | |
| 178 } catch (PackageManager.NameNotFoundException e) { | |
| 179 return OverrideUrlLoadingResult.NO_OVERRIDE; | |
| 180 } catch (Exception ignore) { | |
| 181 //ignore the check sign miss | |
|
palmer
2016/07/20 18:53:48
Why?
| |
| 182 } | |
| 183 | |
| 115 long time = SystemClock.elapsedRealtime(); | 184 long time = SystemClock.elapsedRealtime(); |
| 116 OverrideUrlLoadingResult result = shouldOverrideUrlLoadingInternal( | 185 OverrideUrlLoadingResult result = shouldOverrideUrlLoadingInternal( |
| 117 params, intent, hasBrowserFallbackUrl, browserFallbackUrl); | 186 params, intent, hasBrowserFallbackUrl, browserFallbackUrl); |
| 118 RecordHistogram.recordTimesHistogram("Android.StrictMode.OverrideUrlLoad ingTime", | 187 RecordHistogram.recordTimesHistogram("Android.StrictMode.OverrideUrlLoad ingTime", |
| 119 SystemClock.elapsedRealtime() - time, TimeUnit.MILLISECONDS); | 188 SystemClock.elapsedRealtime() - time, TimeUnit.MILLISECONDS); |
| 120 | 189 |
| 121 if (result == OverrideUrlLoadingResult.NO_OVERRIDE && hasBrowserFallback Url | 190 if (result == OverrideUrlLoadingResult.NO_OVERRIDE && hasBrowserFallback Url |
| 122 && (params.getRedirectHandler() == null | 191 && (params.getRedirectHandler() == null |
| 123 // For instance, if this is a chained fallback URL, we i gnore it. | 192 // For instance, if this is a chained fallback URL, we i gnore it. |
| 124 || !params.getRedirectHandler().shouldNotOverrideUrlLoad ing())) { | 193 || !params.getRedirectHandler().shouldNotOverrideUrlLoad ing())) { |
| (...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 513 String defaultSmsPackageName = mDelegate.getDefaultSmsPackageName(); | 582 String defaultSmsPackageName = mDelegate.getDefaultSmsPackageName(); |
| 514 if (defaultSmsPackageName == null) return null; | 583 if (defaultSmsPackageName == null) return null; |
| 515 // Makes sure that the default SMS app actually resolves the intent. | 584 // Makes sure that the default SMS app actually resolves the intent. |
| 516 for (ResolveInfo resolveInfo : resolvingComponentNames) { | 585 for (ResolveInfo resolveInfo : resolvingComponentNames) { |
| 517 if (defaultSmsPackageName.equals(resolveInfo.activityInfo.packageNam e)) { | 586 if (defaultSmsPackageName.equals(resolveInfo.activityInfo.packageNam e)) { |
| 518 return defaultSmsPackageName; | 587 return defaultSmsPackageName; |
| 519 } | 588 } |
| 520 } | 589 } |
| 521 return null; | 590 return null; |
| 522 } | 591 } |
| 592 | |
| 593 /** | |
| 594 * compute normalized sha256fingerprint from signatures | |
| 595 * | |
| 596 * @return hexString of the fingerprint | |
| 597 */ | |
| 598 private static String computeNormalizedSha256Fingerprint(byte[] signature) { | |
|
palmer
2016/07/20 18:53:48
Although this is for Android package signatures, i
| |
| 599 MessageDigest digester; | |
| 600 try { | |
| 601 digester = MessageDigest.getInstance("SHA-256"); | |
| 602 } catch (NoSuchAlgorithmException e) { | |
| 603 throw new AssertionError("No SHA-256 implementation found."); | |
| 604 } | |
| 605 digester.update(signature); | |
| 606 return byteArrayToHexString(digester.digest()); | |
| 607 } | |
| 608 | |
| 609 /** | |
| 610 * convert byteArray to String | |
| 611 * | |
| 612 * @return hexString | |
| 613 */ | |
| 614 private static String byteArrayToHexString(byte[] array) { | |
|
palmer
2016/07/20 18:53:48
Is there not already a function that does this som
| |
| 615 if (array.length == 0) { | |
| 616 return ""; | |
| 617 } | |
| 618 StringBuilder data = new StringBuilder(); | |
| 619 for (byte anArray : array) { | |
|
palmer
2016/07/20 18:53:47
Use more concise names:
for (byte b : bytes)
| |
| 620 data.append(Integer.toHexString((anArray >> 4) & 0x0f)); | |
| 621 data.append(Integer.toHexString(anArray & 0x0f)); | |
| 622 } | |
| 623 return data.toString().toUpperCase(); | |
| 624 } | |
| 523 } | 625 } |
| OLD | NEW |