| Index: chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkValidator.java
|
| diff --git a/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkValidator.java b/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkValidator.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3d9eb4a5f7aaa07878b0817ef08515fe287f0acd
|
| --- /dev/null
|
| +++ b/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkValidator.java
|
| @@ -0,0 +1,123 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +package org.chromium.webapk.lib.client;
|
| +
|
| +import static org.chromium.webapk.lib.common.WebApkConstants.WEBAPK_PACKAGE_PREFIX;
|
| +
|
| +import android.content.Context;
|
| +import android.content.Intent;
|
| +import android.content.pm.PackageInfo;
|
| +import android.content.pm.PackageManager;
|
| +import android.content.pm.PackageManager.NameNotFoundException;
|
| +import android.content.pm.ResolveInfo;
|
| +import android.content.pm.Signature;
|
| +import android.util.Log;
|
| +
|
| +import java.util.Arrays;
|
| +import java.util.List;
|
| +
|
| +/**
|
| + * Checks whether a URL belongs to a WebAPK, and whether a WebAPK is signed by the WebAPK Minting
|
| + * Server.
|
| + */
|
| +public class WebApkValidator {
|
| +
|
| + private static final String TAG = "WebApkValidator";
|
| + private static byte[] sExpectedSignature;
|
| +
|
| + /**
|
| + * Queries the PackageManager to determine whether a WebAPK can handle the URL. Ignores
|
| + * whether the user has selected a default handler for the URL and whether the default
|
| + * handler is the WebAPK.
|
| + *
|
| + * NOTE(yfriedman): This can fail if multiple WebAPKs can match the supplied url.
|
| + *
|
| + * @param context The application context.
|
| + * @param url The url to check.
|
| + * @return Package name of WebAPK which can handle the URL. Null if the url should not be
|
| + * handled by a WebAPK.
|
| + */
|
| + public static String queryWebApkPackage(Context context, String url) {
|
| + Intent intent;
|
| + try {
|
| + intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
|
| + } catch (Exception e) {
|
| + return null;
|
| + }
|
| +
|
| + intent.addCategory(Intent.CATEGORY_BROWSABLE);
|
| + intent.setComponent(null);
|
| + Intent selector = intent.getSelector();
|
| + if (selector != null) {
|
| + selector.addCategory(Intent.CATEGORY_BROWSABLE);
|
| + selector.setComponent(null);
|
| + }
|
| +
|
| + List<ResolveInfo> resolveInfos = context.getPackageManager().queryIntentActivities(
|
| + intent, PackageManager.GET_RESOLVED_FILTER);
|
| + return findWebApkPackage(resolveInfos);
|
| + }
|
| +
|
| + /**
|
| + * @param The ResolveInfos to search.
|
| + * @return Package name of the ResolveInfo which corresponds to a WebAPK. Null if none of the
|
| + * ResolveInfos corresponds to a WebAPK.
|
| + */
|
| + public static String findWebApkPackage(List<ResolveInfo> infos) {
|
| + for (ResolveInfo info : infos) {
|
| + if (info.activityInfo != null
|
| + && info.activityInfo.packageName.startsWith(WEBAPK_PACKAGE_PREFIX)) {
|
| + return info.activityInfo.packageName;
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Returns whether the provided WebAPK is installed and passes signature checks.
|
| + * @param context A context
|
| + * @param webappPackageName The package name to check
|
| + * @return true iff the WebAPK is installed and passes security checks
|
| + */
|
| + public static boolean isValidWebApk(Context context, String webappPackageName) {
|
| + if (sExpectedSignature == null) {
|
| + Log.wtf(TAG, "WebApk validation failure - expected signature not set."
|
| + + "missing call to WebApkValidator.initWithBrowserHostSignature");
|
| + }
|
| + if (webappPackageName != null && webappPackageName.startsWith(WEBAPK_PACKAGE_PREFIX)) {
|
| + // check signature
|
| + PackageInfo packageInfo = null;
|
| + try {
|
| + packageInfo = context.getPackageManager().getPackageInfo(webappPackageName,
|
| + PackageManager.GET_SIGNATURES);
|
| + } catch (NameNotFoundException e) {
|
| + e.printStackTrace();
|
| + Log.d(TAG, "WebApk not found");
|
| + return false;
|
| + }
|
| +
|
| + final Signature[] arrSignatures = packageInfo.signatures;
|
| + if (arrSignatures != null) {
|
| + for (Signature signature : arrSignatures) {
|
| + if (Arrays.equals(sExpectedSignature, signature.toByteArray())) {
|
| + Log.d(TAG, "WebApk valid - signature match!");
|
| + return true;
|
| + }
|
| + }
|
| + }
|
| + }
|
| + Log.d(TAG, "WebApk invalid");
|
| + return false;
|
| + }
|
| +
|
| + /**
|
| + * Initializes the WebApkValidator with the expected signature that WebAPKs must be signed
|
| + * with for the current host.
|
| + * @param expectedSignature
|
| + */
|
| + public static void initWithBrowserHostSignature(byte[] expectedSignature) {
|
| + sExpectedSignature = Arrays.copyOf(expectedSignature, expectedSignature.length);
|
| + }
|
| +}
|
|
|