Commit 60fc679e authored by Maxim Kolosovskiy's avatar Maxim Kolosovskiy Committed by Commit Bot

[Password Manager] Pressing "Change password" buttons launches CCT

Bug: 1086114, 1092444
Change-Id: I2906d756d0090734b23a711da27f497ec7296937
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2336595
Commit-Queue: Maxim Kolosovskiy  <kolos@chromium.org>
Reviewed-by: default avatarLukasz Suder <lsuder@chromium.org>
Reviewed-by: default avatarFriedrich [CET] <fhorschig@chromium.org>
Cr-Commit-Position: refs/heads/master@{#795390}
parent ced56e1f
......@@ -70,6 +70,7 @@ android_library("internal_java") {
"//third_party/android_deps:androidx_lifecycle_lifecycle_common_java",
"//third_party/android_deps:androidx_preference_preference_java",
"//third_party/android_deps:androidx_recyclerview_recyclerview_java",
"//third_party/android_sdk/androidx_browser:androidx_browser_java",
"//ui/android:ui_full_java",
_public_target,
]
......
......@@ -4,13 +4,21 @@
package org.chromium.chrome.browser.password_check;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.provider.Browser;
import android.view.MenuItem;
import androidx.annotation.VisibleForTesting;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
import org.chromium.base.IntentUtils;
import org.chromium.chrome.browser.IntentHandler;
import org.chromium.chrome.browser.LaunchIntentDispatcher;
import org.chromium.chrome.browser.help.HelpAndFeedback;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.ui.modelutil.PropertyModel;
......@@ -21,8 +29,18 @@ import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
* of the leaked password.
*/
class PasswordCheckCoordinator implements PasswordCheckComponentUi, LifecycleObserver {
private static final String WELL_KNOWN_URL_PATH = "/.well-known/change-password";
private static final String AUTOFILL_ASSISTANT_PACKAGE =
"org.chromium.chrome.browser.autofill_assistant.";
private static final String AUTOFILL_ASSISTANT_ENABLED_KEY =
AUTOFILL_ASSISTANT_PACKAGE + "ENABLED";
private static final String PASSWORD_CHANGE_USERNAME_PARAMETER = "PASSWORD_CHANGE_USERNAME";
private static final String INTENT_PARAMETER = "INTENT";
private static final String INTENT = "PASSWORD_CHANGE";
private final PasswordCheckFragmentView mFragmentView;
private final PasswordCheckMediator mMediator = new PasswordCheckMediator();
private final PasswordCheckMediator mMediator = new PasswordCheckMediator(
this::launchCctWithChangePasswordUrl, this::launchCctWithScript);
private PropertyModel mModel;
/**
......@@ -95,4 +113,56 @@ class PasswordCheckCoordinator implements PasswordCheckComponentUi, LifecycleObs
PropertyModelChangeProcessor.create(
model, view, PasswordCheckViewBinder::bindPasswordCheckView);
}
/**
* Launches a CCT that points to the change password form or home page of |origin|.
* @param origin Origin of the site to be opened in a CCT.
*/
private void launchCctWithChangePasswordUrl(String origin) {
// TODO(crbug.com/1092444): Handle the case when an app should be opened. Consider to set
// |browser_fallback_url|, it is used in case of error while opening a CCT.
Intent intent = buildIntent(origin + WELL_KNOWN_URL_PATH);
IntentUtils.safeStartActivity(mFragmentView.getActivity(), intent);
}
/**
* Launches a CCT that starts a password change script for a {@link CompromisedCredential}.
* @param credential A {@link CompromisedCredential} to be changed with a script.
*/
private void launchCctWithScript(CompromisedCredential credential) {
Intent intent = buildIntent(credential.getOriginUrl());
populateAutofillAssistantExtras(intent, credential.getUsername());
IntentUtils.safeStartActivity(mFragmentView.getActivity(), intent);
}
/**
* Builds an intent to launch a CCT.
* @param initialUrl Initial URL to launch a CCT.
* @return {@link Intent} for CCT.
*/
private Intent buildIntent(String initialUrl) {
final Activity activity = mFragmentView.getActivity();
CustomTabsIntent customTabIntent =
new CustomTabsIntent.Builder().setShowTitle(true).build();
customTabIntent.intent.setData(Uri.parse(initialUrl));
Intent intent = LaunchIntentDispatcher.createCustomTabActivityIntent(
activity, customTabIntent.intent);
intent.setPackage(activity.getPackageName());
intent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPackageName());
IntentHandler.addTrustedIntentExtras(intent);
return intent;
}
/**
* Populates intent extras for an Autofill Assistant script.
* @param intent An {@link Intent} to be populated.
* @param username A username for a password change script. One of extras to put.
*/
private void populateAutofillAssistantExtras(Intent intent, String username) {
intent.putExtra(AUTOFILL_ASSISTANT_ENABLED_KEY, /* value= */ true);
intent.putExtra(AUTOFILL_ASSISTANT_PACKAGE + PASSWORD_CHANGE_USERNAME_PARAMETER, username);
intent.putExtra(AUTOFILL_ASSISTANT_PACKAGE + INTENT_PARAMETER, INTENT);
// TODO(crbug.com/1086114): Also add the following parameters when server side changes is
// ready: CALLER, SOURCE. That would be useful for metrics.
}
}
......@@ -9,6 +9,7 @@ import static org.chromium.chrome.browser.password_check.PasswordCheckProperties
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_STATUS;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.ITEMS;
import org.chromium.base.Consumer;
import org.chromium.ui.modelutil.ListModel;
import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
import org.chromium.ui.modelutil.PropertyModel;
......@@ -21,6 +22,14 @@ class PasswordCheckMediator
implements PasswordCheckCoordinator.CredentialEventHandler, PasswordCheck.Observer {
private PropertyModel mModel;
private PasswordCheckComponentUi.Delegate mDelegate;
private final Consumer<String> mLaunchCctWithChangePasswordUrl;
private final Consumer<CompromisedCredential> mLaunchCctWithScript;
PasswordCheckMediator(Consumer<String> launchCctWithChangePasswordUrl,
Consumer<CompromisedCredential> launchCctWithScript) {
this.mLaunchCctWithChangePasswordUrl = launchCctWithChangePasswordUrl;
this.mLaunchCctWithScript = launchCctWithScript;
}
void initialize(PropertyModel model, PasswordCheckComponentUi.Delegate delegate) {
mModel = model;
......@@ -96,12 +105,13 @@ class PasswordCheckMediator
@Override
public void onChangePasswordButtonClick(CompromisedCredential credential) {
// TODO(crbug.com/1092444): Implement the action for the button.
mLaunchCctWithChangePasswordUrl.accept(credential.getOriginUrl());
}
@Override
public void onChangePasswordWithScriptButtonClick(CompromisedCredential credential) {
// TODO(crbug.com/1086109): Implement the action for the button.
assert credential.hasScript();
mLaunchCctWithScript.accept(credential);
}
private PasswordCheck getPasswordCheck() {
......
......@@ -26,6 +26,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.chromium.base.Consumer;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.password_check.PasswordCheckProperties.ItemType;
......@@ -53,6 +54,10 @@ public class PasswordCheckControllerTest {
@Mock
private PasswordCheckComponentUi.Delegate mDelegate;
@Mock
private Consumer<String> mLaunchCctWithChangePasswordUrlConsumer;
@Mock
private Consumer<CompromisedCredential> mLaunchCctWithScriptConsumer;
@Mock
private PasswordCheck mPasswordCheck;
// DO NOT INITIALIZE HERE! The objects would be shared here which leaks state between tests.
......@@ -63,7 +68,8 @@ public class PasswordCheckControllerTest {
public void setUp() {
MockitoAnnotations.initMocks(this);
mModel = PasswordCheckProperties.createDefaultModel();
mMediator = new PasswordCheckMediator();
mMediator = new PasswordCheckMediator(
mLaunchCctWithChangePasswordUrlConsumer, mLaunchCctWithScriptConsumer);
PasswordCheckFactory.setPasswordCheckForTesting(mPasswordCheck);
mMediator.initialize(mModel, mDelegate);
}
......@@ -122,4 +128,16 @@ public class PasswordCheckControllerTest {
mMediator.onRemove(ANA);
verify(mDelegate).removeCredential(eq(ANA));
}
@Test
public void testOnChangePasswordButtonClick() {
mMediator.onChangePasswordButtonClick(ANA);
verify(mLaunchCctWithChangePasswordUrlConsumer).accept(eq(ANA.getOriginUrl()));
}
@Test
public void testOnChangePasswordWithScriptButtonClick() {
mMediator.onChangePasswordWithScriptButtonClick(BOB);
verify(mLaunchCctWithScriptConsumer).accept(eq(BOB));
}
}
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