Commit 38ae8d49 authored by Peter E Conn's avatar Peter E Conn Committed by Commit Bot

📎 Split TWA specific code from TrustedWebActivityVerifier.

In this first step we split TrustedWebActivityVerifier up into:
- TrustedWebActivityVerifier, which contains the logic for checking
  whether the current url is verified at the appropriate times (eg
  page load, tab switching) and notifying the outside world.
- TwaVerifiedDelegate, which contains the logic specific to TWAs,
  primarily gathering the origins the client app claims it is verified
  for and running Digital Asset Link verification.
- TwaRegistrar, which essentially contains the logic from
  TrustedWebActivtyVerifier#registerClientAppForOrigin

The next steps are:
- Rename TrustedWebActivityVerifier to just Verifier (I didn't do this
  in this CL to make the code review easier).
- Make Verifier agnostic to whether we verify for origins or scopes.
- Moving the TwaRegistrar dependency from Verifier to the
  TWACoordinator.
- Removing the knowledge about the client package name from the
  Verifier - the Verifier shouldn't be the source of truth for this.

Bug: 1017114
Change-Id: If6e508ed99130e0fbbc0c5fd148f65f1a0cae66d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1875750Reviewed-by: default avatarPeter Beverloo <peter@chromium.org>
Reviewed-by: default avatarPeter Kotwicz <pkotwicz@chromium.org>
Commit-Queue: Peter Conn <peconn@chromium.org>
Cr-Commit-Position: refs/heads/master@{#709096}
parent cbd845c9
...@@ -169,6 +169,9 @@ chrome_java_sources = [ ...@@ -169,6 +169,9 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityDisclosureController.java", "java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityDisclosureController.java",
"java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityOpenTimeRecorder.java", "java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityOpenTimeRecorder.java",
"java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityVerifier.java", "java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityVerifier.java",
"java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TwaRegistrar.java",
"java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TwaVerifierDelegate.java",
"java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/VerifierDelegate.java",
"java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/sharing/TwaSharingController.java", "java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/sharing/TwaSharingController.java",
"java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/splashscreen/SplashImageHolder.java", "java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/splashscreen/SplashImageHolder.java",
"java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/splashscreen/TwaSplashController.java", "java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/splashscreen/TwaSplashController.java",
......
...@@ -30,6 +30,7 @@ chrome_junit_test_java_sources = [ ...@@ -30,6 +30,7 @@ chrome_junit_test_java_sources = [
"junit/src/org/chromium/chrome/browser/browserservices/permissiondelegation/NotificationChannelPreserverTest.java", "junit/src/org/chromium/chrome/browser/browserservices/permissiondelegation/NotificationChannelPreserverTest.java",
"junit/src/org/chromium/chrome/browser/browserservices/permissiondelegation/NotificationPermissionUpdaterTest.java", "junit/src/org/chromium/chrome/browser/browserservices/permissiondelegation/NotificationPermissionUpdaterTest.java",
"junit/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/ClientAppDataRecorderTest.java", "junit/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/ClientAppDataRecorderTest.java",
"junit/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TestVerifierDelegate.java",
"junit/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityDisclosureControllerTest.java", "junit/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityDisclosureControllerTest.java",
"junit/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityOpenTimeRecorderTest.java", "junit/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityOpenTimeRecorderTest.java",
"junit/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityVerifierTest.java", "junit/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityVerifierTest.java",
......
// Copyright 2019 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.chrome.browser.browserservices.trustedwebactivityui.controller;
import static org.chromium.chrome.browser.dependency_injection.ChromeCommonQualifiers.APP_CONTEXT;
import android.content.Context;
import org.chromium.chrome.browser.browserservices.Origin;
import org.chromium.chrome.browser.browserservices.TrustedWebActivityClient;
import org.chromium.chrome.browser.browserservices.permissiondelegation.NotificationPermissionUpdater;
import java.util.HashSet;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import dagger.Lazy;
/**
* Records in all the appropriate places that a TWA has successfully been verified.
*/
public class TwaRegistrar {
private final Context mAppContext;
private final NotificationPermissionUpdater mNotificationPermissionUpdater;
private final Lazy<ClientAppDataRecorder> mClientAppDataRecorder;
// These origins have already been registered so we don't need to do so again.
private final Set<Origin> mRegisteredOrigins = new HashSet<>();
@Inject
public TwaRegistrar(@Named(APP_CONTEXT) Context appContext,
NotificationPermissionUpdater permissionUpdater,
Lazy<ClientAppDataRecorder> clientAppDataRecorder) {
mAppContext = appContext;
mNotificationPermissionUpdater = permissionUpdater;
mClientAppDataRecorder = clientAppDataRecorder;
}
/**
* Registers to various stores that the client app is linked with the origin.
*
* We do this here, when the Trusted Web Activity UI is shown instead of in OriginVerifier when
* verification completes because when an origin is being verified, we don't know whether it is
* for the purposes of Trusted Web Activities or for Post Message (where this behaviour is not
* required).
*
* Additionally we do it on every page navigation because an app can be verified for more than
* one Origin, eg:
* 1) App verifies with https://www.myfirsttwa.com/.
* 2) App verifies with https://www.mysecondtwa.com/.
* 3) App launches a TWA to https://www.myfirsttwa.com/.
* 4) App navigates to https://www.mysecondtwa.com/.
*
* At step 2, we don't know why the app is verifying with that origin (it could be for TWAs or
* for PostMessage). Only at step 4 do we know that Chrome should associate the browsing data
* for that origin with that app.
*/
void registerClient(String packageName, Origin origin) {
if (mRegisteredOrigins.contains(origin)) return;
// Register that we should wipe data for this origin when the client app is uninstalled.
mClientAppDataRecorder.get().register(packageName, origin);
// Register that we trust the client app to forward notifications from this origin to.
TrustedWebActivityClient.registerClient(mAppContext, origin, packageName);
// Update Chrome's notification permission for the website to that of the client app.
mNotificationPermissionUpdater.onOriginVerified(origin, packageName);
mRegisteredOrigins.add(origin);
}
}
// Copyright 2019 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.chrome.browser.browserservices.trustedwebactivityui.controller;
import android.os.Bundle;
import org.chromium.base.Promise;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.browserservices.Origin;
import org.chromium.chrome.browser.browserservices.OriginVerifier;
import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
import org.chromium.chrome.browser.customtabs.CustomTabsConnection;
import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabProvider;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.lifecycle.Destroyable;
import org.chromium.chrome.browser.lifecycle.NativeInitObserver;
import org.chromium.chrome.browser.lifecycle.SaveInstanceStateObserver;
import org.chromium.content_public.browser.WebContents;
import javax.inject.Inject;
import androidx.browser.customtabs.CustomTabsService;
/**
* Provides Trusted Web Activity specific behaviour for the {@link TrustedWebActivityVerifier}.
*/
public class TwaVerifierDelegate implements VerifierDelegate, Destroyable, NativeInitObserver,
SaveInstanceStateObserver {
/** The Digital Asset Link relationship used for Trusted Web Activities. */
private static final int RELATIONSHIP = CustomTabsService.RELATION_HANDLE_ALL_URLS;
/** Used in activity instance state */
private static final String KEY_CLIENT_PACKAGE = "twaClientPackageName";
private final CustomTabsConnection mCustomTabsConnection;
private final CustomTabIntentDataProvider mIntentDataProvider;
private final OriginVerifier mOriginVerifier;
private final String mClientPackageName;
@Inject
public TwaVerifierDelegate(
ChromeActivity activity,
ActivityLifecycleDispatcher lifecycleDispatcher,
CustomTabIntentDataProvider intentDataProvider,
CustomTabsConnection customTabsConnection,
OriginVerifier.Factory originVerifierFactory,
CustomTabActivityTabProvider tabProvider) {
mCustomTabsConnection = customTabsConnection;
mIntentDataProvider = intentDataProvider;
Bundle savedInstanceState = activity.getSavedInstanceState();
if (savedInstanceState != null) {
mClientPackageName = savedInstanceState.getString(KEY_CLIENT_PACKAGE);
} else {
mClientPackageName = customTabsConnection.getClientPackageNameForSession(
intentDataProvider.getSession());
}
assert mClientPackageName != null;
// TODO(peconn): See if we can get rid of the dependency on Web Contents.
WebContents webContents =
tabProvider.getTab() != null ? tabProvider.getTab().getWebContents() : null;
mOriginVerifier =
originVerifierFactory.create(mClientPackageName, RELATIONSHIP, webContents);
lifecycleDispatcher.register(this);
}
@Override
public String getClientPackageName() {
return mClientPackageName;
}
@Override
public boolean wasPreviouslyVerified(Origin origin) {
return mOriginVerifier.wasPreviouslyVerified(origin);
}
@Override
public Promise<Boolean> verify(Origin origin) {
Promise<Boolean> promise = new Promise<>();
mOriginVerifier.start((packageName, unused, verified, online) -> promise.fulfill(verified),
origin);
return promise;
}
@Override
public void destroy() {
// Verification may finish after activity is destroyed.
mOriginVerifier.removeListener();
}
@Override
public void onSaveInstanceState(Bundle outState) {
// TODO(pshmakov): address this problem in a more general way, http://crbug.com/952221
outState.putString(KEY_CLIENT_PACKAGE, mClientPackageName);
}
@Override
public void onFinishNativeInitialization() {
// This doesn't belong here, but doesn't deserve a separate class. Do extract it if more
// PostMessage-related code appears.
if (!ChromeFeatureList.isEnabled(ChromeFeatureList.TRUSTED_WEB_ACTIVITY_POST_MESSAGE)) {
mCustomTabsConnection.resetPostMessageHandlerForSession(
mIntentDataProvider.getSession(), null);
}
}
}
// Copyright 2019 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.chrome.browser.browserservices.trustedwebactivityui.controller;
import org.chromium.base.Promise;
import org.chromium.chrome.browser.browserservices.Origin;
/**
* A Delegate for the {@link TrustedWebActivityVerifier} that provides implementation specific to
* Trusted Web Activities, WebAPKs or A2HS as appropriate.
*/
public interface VerifierDelegate {
// TODO(peconn): Make distinction between verify and wasPreviouslyVerified more clear.
/** Asynchronously checks whether the given Origin is verified. */
Promise<Boolean> verify(Origin origin);
/** Synchronously checks whether verification was successful for the given Origin. */
boolean wasPreviouslyVerified(Origin origin);
// TODO(peconn): Get rid of this method.
/** Gets the package name of the connected app. */
String getClientPackageName();
}
...@@ -6,6 +6,8 @@ package org.chromium.chrome.browser.customtabs.dependency_injection; ...@@ -6,6 +6,8 @@ package org.chromium.chrome.browser.customtabs.dependency_injection;
import org.chromium.chrome.browser.browserservices.ClientAppDataRegister; import org.chromium.chrome.browser.browserservices.ClientAppDataRegister;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.TwaIntentHandlingStrategy; import org.chromium.chrome.browser.browserservices.trustedwebactivityui.TwaIntentHandlingStrategy;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.TwaVerifierDelegate;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.VerifierDelegate;
import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider; import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
import org.chromium.chrome.browser.customtabs.CustomTabNightModeStateController; import org.chromium.chrome.browser.customtabs.CustomTabNightModeStateController;
import org.chromium.chrome.browser.customtabs.content.CustomTabIntentHandler.IntentIgnoringCriterion; import org.chromium.chrome.browser.customtabs.content.CustomTabIntentHandler.IntentIgnoringCriterion;
...@@ -61,6 +63,12 @@ public class CustomTabActivityModule { ...@@ -61,6 +63,12 @@ public class CustomTabActivityModule {
return mIntentDataProvider.isTrustedWebActivity() ? twaHandler.get() : defaultHandler.get(); return mIntentDataProvider.isTrustedWebActivity() ? twaHandler.get() : defaultHandler.get();
} }
@Provides
public VerifierDelegate provideVerifierDelegate(Lazy<TwaVerifierDelegate> twaVerifierDelegate) {
// TODO(peconn): Add handing of WebAPK/A2HS delegate.
return twaVerifierDelegate.get();
}
@Provides @Provides
public IntentIgnoringCriterion provideIntentIgnoringCriterion() { public IntentIgnoringCriterion provideIntentIgnoringCriterion() {
return mIntentIgnoringCriterion; return mIntentIgnoringCriterion;
......
// Copyright 2019 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.chrome.browser.browserservices.trustedwebactivityui.controller;
import org.chromium.base.Promise;
import org.chromium.chrome.browser.browserservices.Origin;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* A {@link VerifierDelegate} for testing.
*/
class TestVerifierDelegate implements VerifierDelegate {
private final Set<Origin> mPreviouslyVerifiedOrigins = new HashSet<>();
private final Map<Origin, Promise<Boolean>> mPendingVerifications = new HashMap<>();
private final String mPackageName;
TestVerifierDelegate(String packageName) {
mPackageName = packageName;
}
@Override
public Promise<Boolean> verify(Origin origin) {
Promise<Boolean> promise = new Promise<>();
mPendingVerifications.put(origin, promise);
return promise;
}
@Override
public boolean wasPreviouslyVerified(Origin origin) {
return mPreviouslyVerifiedOrigins.contains(origin);
}
@Override
public String getClientPackageName() {
return mPackageName;
}
public void passVerification(Origin origin) {
completeVerification(origin, true);
}
public void failVerification(Origin origin) {
completeVerification(origin, false);
}
private void completeVerification(Origin origin, boolean success) {
if (mPendingVerifications.get(origin) == null) return;
mPendingVerifications.get(origin).fulfill(success);
mPendingVerifications.remove(origin);
if (success) mPreviouslyVerifiedOrigins.add(origin);
}
public boolean hasPendingVerification(Origin origin) {
return mPendingVerifications.containsKey(origin);
}
public boolean hasAnyPendingVerifications() {
return mPendingVerifications.size() != 0;
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment