| 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) {
|
|
|