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..c3d00f1e84bd3f1a76f710cf78730e28215edaf1 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 |
@@ -28,8 +28,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 +114,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 +133,65 @@ public class ExternalNavigationHandler { |
return result; |
} |
+ /** |
+ * Check if the signature specified in the intent matches the signatures of |
+ * the package to launch. |
+ * |
+ * @param intent The intent to launch. |
+ * @return True if OK to launch the intent based on the signature. |
+ */ |
+ private boolean intentPackageSignatureMatches(Intent intent) { |
+ // This feature relies on a custom scheme. Variable scheme is used to check whether |
+ // the intent url has an extra custom scheme, if not, the 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(";"); |
+ // Consider that apks may have same package name but different keystores. |
+ // 1. An apk's signature may update and differ from old, so you may 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. |
+ // e.g. suppose apk's new signatures are sha256_1 and sha256_2, 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 intentFingerPrint = ""; |
+ // Fingerprints which has the same pkgName but different key signatures. |
+ String[] fingerPrintDiffSignKeys; |
+ for (int i = 0; i < parts.length; ++i) { |
+ String[] part = parts[i].split("="); |
+ if (part.length < 2) { |
+ continue; |
+ } |
+ if (part[0].equals("sha256")) { |
+ intentFingerPrint = part[1]; |
+ } |
+ if (part[0].equals("package")) { |
+ pkgName = part[1]; |
+ } |
+ } |
+ // All fingerprints contained in the intent url. |
+ Set<Set<String>> intentFingerPrints = new HashSet<>(); |
+ if (!TextUtils.isEmpty(pkgName) && !TextUtils.isEmpty(intentFingerPrint)) { |
+ fingerPrintDiffSignKeys = intentFingerPrint.split("\\|"); |
+ for (int i = 0; i < fingerPrintDiffSignKeys.length; ++i) { |
+ // Fingerprints which has the same package and same signature. |
+ Set<String> fingerPrintSameSignKey = new HashSet<>(); |
+ Collections.addAll(fingerPrintSameSignKey, |
+ fingerPrintDiffSignKeys[i].split(",")); |
+ intentFingerPrints.add(fingerPrintSameSignKey); |
+ } |
+ // All fingerprints contained in the package to launch. |
+ Set<String> localFingerPrints = mDelegate.getPackageSHA256Fingerprints(pkgName); |
+ if (localFingerPrints == null || !intentFingerPrints.contains(localFingerPrints)) { |
+ return false; |
+ } |
+ } |
+ } |
+ return true; |
+ } |
+ |
private boolean resolversSubsetOf(List<ResolveInfo> infos, List<ResolveInfo> container) { |
HashSet<ComponentName> containerSet = new HashSet<>(); |
for (ResolveInfo info : container) { |