Index: chrome/android/java/src/org/chromium/chrome/browser/customtabs/OriginVerifier.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/OriginVerifier.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/OriginVerifier.java |
index b7c6ba4a3dbd0868bec566fd0e1b4674832cc9b6..9754d33ec4977a9bbeb67bb8938cc7bb8d65e037 100644 |
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/OriginVerifier.java |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/OriginVerifier.java |
@@ -30,8 +30,10 @@ import java.security.cert.CertificateException; |
import java.security.cert.CertificateFactory; |
import java.security.cert.X509Certificate; |
import java.util.HashMap; |
+import java.util.HashSet; |
import java.util.Locale; |
import java.util.Map; |
+import java.util.Set; |
/** |
* Used to verify postMessage origin for a designated package name. |
@@ -47,21 +49,25 @@ import java.util.Map; |
class OriginVerifier { |
private static final String TAG = "OriginVerifier"; |
private static final char[] HEX_CHAR_LOOKUP = "0123456789ABCDEF".toCharArray(); |
- private static Map<String, Uri> sCachedOriginMap; |
+ private static Map<String, Set<Uri>> sPackageToCachedOrigins; |
private final OriginVerificationListener mListener; |
private final String mPackageName; |
private final String mSignatureFingerprint; |
private long mNativeOriginVerifier = 0; |
private Uri mOrigin; |
- /** |
- * To be used for prepopulating verified origin for testing functionality. |
- * @param packageName The package name to prepopulate for. |
- * @param origin The origin to add as verified. |
- */ |
- @VisibleForTesting |
- static void prePopulateVerifiedOriginForTesting(String packageName, Uri origin) { |
- cacheVerifiedOriginIfNeeded(packageName, origin); |
+ /** Small helper class to post a result of origin verification. */ |
+ private class VerifiedCallback implements Runnable { |
+ private final boolean mResult; |
+ |
+ public VerifiedCallback(boolean result) { |
+ this.mResult = result; |
+ } |
+ |
+ @Override |
+ public void run() { |
+ originVerified(mResult); |
+ } |
} |
private static Uri getPostMessageOriginFromVerifiedOrigin( |
@@ -70,11 +76,44 @@ class OriginVerifier { |
+ verifiedOrigin.getHost() + "/" + packageName); |
} |
- private static void cacheVerifiedOriginIfNeeded(String packageName, Uri origin) { |
- if (sCachedOriginMap == null) sCachedOriginMap = new HashMap<>(); |
- if (!sCachedOriginMap.containsKey(packageName)) { |
- sCachedOriginMap.put(packageName, origin); |
+ /** Clears all known relations. */ |
+ @VisibleForTesting |
+ static void reset() { |
+ ThreadUtils.assertOnUiThread(); |
+ if (sPackageToCachedOrigins != null) sPackageToCachedOrigins.clear(); |
+ } |
+ |
+ /** |
+ * Mark an origin as verified for a package. |
+ * @param packageName The package name to prepopulate for. |
+ * @param origin The origin to add as verified. |
+ */ |
+ static void addVerifiedOriginForPackage(String packageName, Uri origin) { |
+ ThreadUtils.assertOnUiThread(); |
+ if (sPackageToCachedOrigins == null) sPackageToCachedOrigins = new HashMap<>(); |
+ Set<Uri> cachedOrigins = sPackageToCachedOrigins.get(packageName); |
+ if (cachedOrigins == null) { |
+ cachedOrigins = new HashSet<Uri>(); |
+ sPackageToCachedOrigins.put(packageName, cachedOrigins); |
} |
+ cachedOrigins.add(origin); |
+ } |
+ |
+ /** |
+ * Returns whether an origin is first-party relative to a given package name. |
+ * |
+ * This only returns data from previously cached relations, and does not |
+ * trigger an asynchronous validation. |
+ * |
+ * @param packageName The package name |
+ * @param origin The origin to verify |
+ */ |
+ static boolean isValidOrigin(String packageName, Uri origin) { |
+ ThreadUtils.assertOnUiThread(); |
+ if (sPackageToCachedOrigins == null) return false; |
+ Set<Uri> cachedOrigins = sPackageToCachedOrigins.get(packageName); |
+ if (cachedOrigins == null) return false; |
+ return cachedOrigins.contains(origin); |
} |
/** |
@@ -112,24 +151,13 @@ class OriginVerifier { |
ThreadUtils.assertOnUiThread(); |
mOrigin = origin; |
if (!UrlConstants.HTTPS_SCHEME.equals(mOrigin.getScheme().toLowerCase(Locale.US))) { |
- ThreadUtils.postOnUiThread(new Runnable() { |
- @Override |
- public void run() { |
- originVerified(false); |
- } |
- }); |
+ ThreadUtils.runOnUiThread(new VerifiedCallback(false)); |
return; |
} |
// If this origin is cached as verified already, use that. |
- Uri cachedOrigin = getCachedOriginIfExists(); |
- if (cachedOrigin != null && cachedOrigin.equals(origin)) { |
- ThreadUtils.postOnUiThread(new Runnable() { |
- @Override |
- public void run() { |
- originVerified(true); |
- } |
- }); |
+ if (isValidOrigin(mPackageName, origin)) { |
+ ThreadUtils.runOnUiThread(new VerifiedCallback(true)); |
return; |
} |
if (mNativeOriginVerifier != 0) cleanUp(); |
@@ -142,14 +170,7 @@ class OriginVerifier { |
assert mNativeOriginVerifier != 0; |
boolean success = nativeVerifyOrigin( |
mNativeOriginVerifier, mPackageName, mSignatureFingerprint, mOrigin.toString()); |
- if (!success) { |
- ThreadUtils.postOnUiThread(new Runnable() { |
- @Override |
- public void run() { |
- originVerified(false); |
- } |
- }); |
- } |
+ if (!success) ThreadUtils.runOnUiThread(new VerifiedCallback(false)); |
} |
/** |
@@ -219,18 +240,13 @@ class OriginVerifier { |
@CalledByNative |
private void originVerified(boolean originVerified) { |
if (originVerified) { |
- cacheVerifiedOriginIfNeeded(mPackageName, mOrigin); |
+ addVerifiedOriginForPackage(mPackageName, mOrigin); |
mOrigin = getPostMessageOriginFromVerifiedOrigin(mPackageName, mOrigin); |
} |
mListener.onOriginVerified(mPackageName, mOrigin, originVerified); |
cleanUp(); |
} |
- private Uri getCachedOriginIfExists() { |
- if (sCachedOriginMap == null) return null; |
- return sCachedOriginMap.get(mPackageName); |
- } |
- |
private native long nativeInit(Profile profile); |
private native boolean nativeVerifyOrigin(long nativeOriginVerifier, String packageName, |
String signatureFingerprint, String origin); |