Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java |
| index 99c2a0418e6c33bcb9d4d677230334e3549929bd..864650352bb039debbef5d7e1fb8a7751d3649e1 100644 |
| --- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java |
| @@ -7,6 +7,7 @@ package org.chromium.chrome.browser.externalnav; |
| import android.content.ActivityNotFoundException; |
| import android.content.ComponentName; |
| import android.content.Intent; |
| +import android.content.pm.PackageManager; |
| import android.content.pm.ResolveInfo; |
| import android.net.Uri; |
| import android.os.SystemClock; |
| @@ -28,8 +29,10 @@ import org.chromium.chrome.browser.util.UrlUtilities; |
| import org.chromium.ui.base.PageTransition; |
| import java.net.URI; |
| +import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| +import java.util.Set; |
| import java.util.concurrent.TimeUnit; |
| /** |
| @@ -112,6 +115,10 @@ public class ExternalNavigationHandler { |
| browserFallbackUrl = null; |
| } |
| + if (!intentPackageSignatureMatches(intent)) { |
| + return OverrideUrlLoadingResult.NO_OVERRIDE; |
| + } |
| + |
| long time = SystemClock.elapsedRealtime(); |
| OverrideUrlLoadingResult result = shouldOverrideUrlLoadingInternal( |
| params, intent, hasBrowserFallbackUrl, browserFallbackUrl); |
| @@ -127,6 +134,71 @@ public class ExternalNavigationHandler { |
| return result; |
| } |
| + /** |
| + * When a custom scheme intent trying to launch another application, verify the signature |
| + * fingerprint of intent, if the fingerprint matches fingerprints of target application, the |
| + * intent should be override, or it shouldn't. |
| + * |
| + * @param intent intent from url |
| + * @return boolean, true if the feature is not supported or url should override, |
| + * false if the the intent should not override. |
| + */ |
| + private boolean intentPackageSignatureMatches(Intent intent) { |
| + try { |
| + //This new feature is based on custom scheme, string "scheme" used to check whether |
|
please use gerrit instead
2016/07/29 16:59:52
1) "//" should always be followed by " " before th
|
| + //the intent url has extra custom scheme, if not, the new feature won't work. |
| + String scheme = intent.getData().getScheme(); |
| + String fragment = intent.getData().getFragment(); |
| + if (!TextUtils.isEmpty(scheme) && fragment != null && fragment.contains(";")) { |
| + String[] parts = fragment.split(";"); |
| + Set<Set<String>> allFingerPrint256 = new HashSet<>(); |
| + //Consider that apks could have same package name, different keystores. |
| + //1. An apk's signature may update and differ from old, so you might need config and |
| + //support new and old signatures, but this is optional. (e.g. (1)only config new |
| + //fingerprint. (2)only config old fingerprint.(3)config new and old fingerprint) |
| + //2. An apk itself may contain more than one keystore to sign. |
| + //example: suppose apk's new signature is sha256_1,sha256_2,and old signature |
| + //is sha256_3. You can config the intent like "...;sha256=sha256_1,sha256_2;..." |
| + //or "...;sha256=sha256_1,sha256_2|sha256_3;..." |
| + String pkgName = ""; |
| + String fingerPrint256 = ""; |
| + String[] fingerPrint256DifGroups; |
| + for (int i = 0; i < parts.length; ++i) { |
| + String[] part = parts[i].split("="); |
| + if (part[0].equals("sha256")) { |
| + fingerPrint256 = part[1]; |
| + } |
| + if (part[0].equals("package")) { |
| + pkgName = part[1]; |
| + } |
| + } |
| + if (!TextUtils.isEmpty(pkgName) && !TextUtils.isEmpty(fingerPrint256)) { |
| + fingerPrint256DifGroups = fingerPrint256.split("\\|"); |
| + for (int i = 0; i < fingerPrint256DifGroups.length; ++i) { |
| + Set<String> fingerPrint256GroupSignKeySet = new HashSet<>(); |
| + Collections.addAll(fingerPrint256GroupSignKeySet, fingerPrint256DifGroups[i] |
| + .split(",")); |
| + allFingerPrint256.add(fingerPrint256GroupSignKeySet); |
| + } |
| + Set<String> fingerPrint256Set = mDelegate.getPackageSHA256Fingerprints(pkgName); |
| + if (!allFingerPrint256.contains(fingerPrint256Set)) { |
| + return false; |
| + } |
| + } |
| + } |
| + } catch (PackageManager.NameNotFoundException e) { |
|
please use gerrit instead
2016/07/29 16:59:52
Modify getPackageSHA256FingerPrints() to return nu
|
| + return false; |
| + } catch (Throwable ignore) { |
|
please use gerrit instead
2016/07/29 16:59:52
Don't surround large blocks of code with try-catch
|
| + //1. In method getPackageSHA256Fingerprints() , if no SHA-256 implementation found, |
| + //we consider this new feature won't work, so it should reset to the original way |
| + //to handle the intent , we should ignore ths throwable. |
| + //2. In the process above, any other exception or error happens except |
| + //"NameNotFoundException", we can consider the feature fail ,and catch the throwable |
| + // and continue next work. |
| + } |
| + return true; |
| + } |
| + |
| private boolean resolversSubsetOf(List<ResolveInfo> infos, List<ResolveInfo> container) { |
| HashSet<ComponentName> containerSet = new HashSet<>(); |
| for (ResolveInfo info : container) { |