-
Notifications
You must be signed in to change notification settings - Fork 6.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[UPMLocalSettings] Introduce ChromeNativePasswordCheckController
Introduces the implementation of PasswordyCheckController, which would run password check using chrome native (non-GMS core) password check. Bug: b/312930046 Change-Id: Ibddc96b24652fad58cd1db69d8d1bb2c439af669 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5134817 Commit-Queue: Anna Tsvirchkova <atsvirchkova@google.com> Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com> Reviewed-by: Rainhard Findling <rainhard@chromium.org> Reviewed-by: Ioana Pandele <ioanap@chromium.org> Cr-Commit-Position: refs/heads/main@{#1244013}
- Loading branch information
Anna Tsvirchkova
authored and
Chromium LUCI CQ
committed
Jan 8, 2024
1 parent
1113821
commit 0090b38
Showing
6 changed files
with
342 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
82 changes: 82 additions & 0 deletions
82
...rc/org/chromium/chrome/browser/pwd_check_wrapper/ChromeNativePasswordCheckController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// Copyright 2024 The Chromium Authors | ||
// 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.pwd_check_wrapper; | ||
|
||
import org.chromium.chrome.browser.password_check.PasswordCheck; | ||
import org.chromium.chrome.browser.password_check.PasswordCheckFactory; | ||
import org.chromium.chrome.browser.password_check.PasswordCheckUIStatus; | ||
import org.chromium.components.browser_ui.settings.SettingsLauncher; | ||
|
||
import java.util.concurrent.CompletableFuture; | ||
|
||
class ChromeNativePasswordCheckController | ||
implements PasswordCheckController, PasswordCheck.Observer { | ||
private CompletableFuture<Integer> mPasswordsTotalCount; | ||
private CompletableFuture<PasswordCheckResult> mPasswordCheckResult; | ||
private final PasswordCheck mPasswordCheck; | ||
|
||
public ChromeNativePasswordCheckController(SettingsLauncher settingsLauncher) { | ||
mPasswordCheck = PasswordCheckFactory.getOrCreate(settingsLauncher); | ||
} | ||
|
||
@Override | ||
public CompletableFuture<PasswordCheckResult> checkPasswords( | ||
@PasswordStoreType int passwordStoreType) { | ||
mPasswordCheckResult = new CompletableFuture<>(); | ||
mPasswordsTotalCount = new CompletableFuture<>(); | ||
// Start observing the password check events (including data loads). | ||
mPasswordCheck.addObserver(this, false); | ||
mPasswordCheck.startCheck(); | ||
return mPasswordCheckResult; | ||
} | ||
|
||
@Override | ||
public CompletableFuture<PasswordCheckResult> getBreachedCredentialsCount( | ||
int passwordStoreType) { | ||
mPasswordCheckResult = new CompletableFuture<>(); | ||
mPasswordsTotalCount = new CompletableFuture<>(); | ||
mPasswordCheck.addObserver(this, true); | ||
return mPasswordCheckResult; | ||
} | ||
|
||
// PasswordCheck.Observer implementation. | ||
@Override | ||
public void onCompromisedCredentialsFetchCompleted() { | ||
mPasswordsTotalCount.thenAccept( | ||
totalCount -> { | ||
int breachedCount = mPasswordCheck.getCompromisedCredentialsCount(); | ||
mPasswordCheckResult.complete( | ||
new PasswordCheckResult(totalCount, breachedCount)); | ||
}); | ||
} | ||
|
||
@Override | ||
public void onSavedPasswordsFetchCompleted() { | ||
int totalCount = mPasswordCheck.getSavedPasswordsCount(); | ||
mPasswordsTotalCount.complete(totalCount); | ||
} | ||
|
||
@Override | ||
public void onPasswordCheckStatusChanged(@PasswordCheckUIStatus int status) { | ||
if (status == PasswordCheckUIStatus.RUNNING) { | ||
return; | ||
} | ||
|
||
// Handle error state. | ||
if (status != PasswordCheckUIStatus.IDLE) { | ||
PasswordCheckNativeException error = | ||
new PasswordCheckNativeException( | ||
"Password check finished with the error " + status + ".", status); | ||
mPasswordCheckResult.complete(new PasswordCheckResult(error)); | ||
|
||
mPasswordCheck.removeObserver(this); | ||
} | ||
} | ||
|
||
/** Not relevant for this controller. */ | ||
@Override | ||
public void onPasswordCheckProgressChanged(int alreadyProcessed, int remainingInQueue) {} | ||
// End of PasswordCheck.Observer implementation. | ||
} |
165 changes: 165 additions & 0 deletions
165
...rg/chromium/chrome/browser/pwd_check_wrapper/ChromeNativePasswordCheckControllerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
// Copyright 2024 The Chromium Authors | ||
// 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.pwd_check_wrapper; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
import static org.mockito.Mockito.verify; | ||
import static org.mockito.Mockito.when; | ||
|
||
import org.junit.Before; | ||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.mockito.Mock; | ||
import org.mockito.MockitoAnnotations; | ||
import org.mockito.junit.MockitoJUnit; | ||
import org.mockito.junit.MockitoRule; | ||
import org.mockito.quality.Strictness; | ||
import org.robolectric.annotation.Config; | ||
|
||
import org.chromium.base.test.BaseRobolectricTestRunner; | ||
import org.chromium.chrome.browser.password_check.PasswordCheck; | ||
import org.chromium.chrome.browser.password_check.PasswordCheckFactory; | ||
import org.chromium.chrome.browser.password_check.PasswordCheckUIStatus; | ||
import org.chromium.chrome.browser.pwd_check_wrapper.PasswordCheckController.PasswordCheckResult; | ||
import org.chromium.chrome.browser.pwd_check_wrapper.PasswordCheckController.PasswordStoreType; | ||
import org.chromium.components.browser_ui.settings.SettingsLauncher; | ||
|
||
import java.util.OptionalInt; | ||
import java.util.concurrent.CompletableFuture; | ||
import java.util.concurrent.ExecutionException; | ||
|
||
/** Unit tests for {@link ChromeNativePasswordCheckController}. */ | ||
@RunWith(BaseRobolectricTestRunner.class) | ||
@Config(manifest = Config.NONE) | ||
public class ChromeNativePasswordCheckControllerTest { | ||
@Rule public MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS); | ||
|
||
@Mock private SettingsLauncher mSettingsLauncher; | ||
@Mock private PasswordCheck mPasswordCheck; | ||
private ChromeNativePasswordCheckController mController; | ||
|
||
@Before | ||
public void setUp() { | ||
MockitoAnnotations.openMocks(this); | ||
PasswordCheckFactory.setPasswordCheckForTesting(mPasswordCheck); | ||
mController = new ChromeNativePasswordCheckController(mSettingsLauncher); | ||
} | ||
|
||
/** | ||
* The flow: checkPasswords is called -> as a result of password check 0 breached credentials | ||
* are obtained -> passwords loading has finished. | ||
*/ | ||
@Test | ||
public void passwordCheckReturnsNoBreachedPasswords() | ||
throws ExecutionException, InterruptedException { | ||
// Set fake to return 0 breached credentials. | ||
when(mPasswordCheck.getSavedPasswordsCount()).thenReturn(10); | ||
when(mPasswordCheck.getCompromisedCredentialsCount()).thenReturn(0); | ||
|
||
CompletableFuture<PasswordCheckResult> passwordCheckResultFuture = | ||
mController.checkPasswords(PasswordStoreType.PROFILE_STORE); | ||
verify(mPasswordCheck).startCheck(); | ||
|
||
mController.onCompromisedCredentialsFetchCompleted(); | ||
mController.onSavedPasswordsFetchCompleted(); | ||
|
||
PasswordCheckResult passwordCheckResult = passwordCheckResultFuture.get(); | ||
assertEquals(OptionalInt.of(0), passwordCheckResult.getBreachedCount()); | ||
assertEquals(OptionalInt.of(10), passwordCheckResult.getTotalPasswordsCount()); | ||
assertEquals(null, passwordCheckResult.getError()); | ||
} | ||
|
||
/** | ||
* The flow: passwords loading has finished and there are 0 passwords -> as a result of password | ||
* check 0 breached credentials are obtained. | ||
*/ | ||
@Test | ||
public void passwordCheckReturnsNoAnyPasswords() | ||
throws ExecutionException, InterruptedException { | ||
// Set fake to return 0 breached credentials. | ||
when(mPasswordCheck.getSavedPasswordsCount()).thenReturn(0); | ||
when(mPasswordCheck.getCompromisedCredentialsCount()).thenReturn(0); | ||
|
||
CompletableFuture<PasswordCheckResult> passwordCheckResultFuture = | ||
mController.checkPasswords(PasswordStoreType.PROFILE_STORE); | ||
verify(mPasswordCheck).startCheck(); | ||
|
||
mController.onSavedPasswordsFetchCompleted(); | ||
mController.onCompromisedCredentialsFetchCompleted(); | ||
mController.onPasswordCheckStatusChanged(PasswordCheckUIStatus.ERROR_NO_PASSWORDS); | ||
|
||
PasswordCheckResult passwordCheckResult = passwordCheckResultFuture.get(); | ||
assertEquals(OptionalInt.of(0), passwordCheckResult.getBreachedCount()); | ||
assertEquals(OptionalInt.of(0), passwordCheckResult.getTotalPasswordsCount()); | ||
assertEquals(null, passwordCheckResult.getError()); | ||
} | ||
|
||
/** | ||
* The flow: passwords loading has finished -> checkPasswords is called -> obtained 1 breached | ||
* credential. | ||
*/ | ||
@Test | ||
public void passwordCheckReturnsBreachedPassword() | ||
throws ExecutionException, InterruptedException { | ||
// Set fake to return 1 breached credential. | ||
final int breachedCount = 1; | ||
when(mPasswordCheck.getCompromisedCredentialsCount()).thenReturn(breachedCount); | ||
when(mPasswordCheck.getSavedPasswordsCount()).thenReturn(10); | ||
|
||
CompletableFuture<PasswordCheckResult> passwordCheckResultFuture = | ||
mController.checkPasswords(PasswordStoreType.PROFILE_STORE); | ||
verify(mPasswordCheck).startCheck(); | ||
|
||
mController.onCompromisedCredentialsFetchCompleted(); | ||
mController.onSavedPasswordsFetchCompleted(); | ||
|
||
PasswordCheckResult passwordCheckResult = passwordCheckResultFuture.get(); | ||
assertEquals(OptionalInt.of(breachedCount), passwordCheckResult.getBreachedCount()); | ||
assertEquals(OptionalInt.of(10), passwordCheckResult.getTotalPasswordsCount()); | ||
assertEquals(null, passwordCheckResult.getError()); | ||
} | ||
|
||
/** The flow: passwords loading has finished -> checkPasswords returns an error state. */ | ||
@Test | ||
public void passwordCheckReturnsOfflineError() throws ExecutionException, InterruptedException { | ||
CompletableFuture<PasswordCheckResult> passwordCheckResultFuture = | ||
mController.checkPasswords(PasswordStoreType.PROFILE_STORE); | ||
verify(mPasswordCheck).startCheck(); | ||
|
||
mController.onPasswordCheckStatusChanged(PasswordCheckUIStatus.ERROR_OFFLINE); | ||
|
||
PasswordCheckResult passwordCheckResult = passwordCheckResultFuture.get(); | ||
assertEquals(OptionalInt.empty(), passwordCheckResult.getBreachedCount()); | ||
assertEquals(OptionalInt.empty(), passwordCheckResult.getTotalPasswordsCount()); | ||
assertEquals( | ||
PasswordCheckUIStatus.ERROR_OFFLINE, | ||
((PasswordCheckNativeException) passwordCheckResult.getError()).errorCode); | ||
} | ||
|
||
/** | ||
* The flow: getBreachedCredentialsCount is called -> breached credentials fetch completed | ||
* giving 1 breached credential -> then all passwords fetch is completed. | ||
*/ | ||
@Test | ||
public void getBreachedCredentialsCountTest() throws ExecutionException, InterruptedException { | ||
// Set fake to return 1 breached credential. | ||
final int breachedCount = 1; | ||
when(mPasswordCheck.getCompromisedCredentialsCount()).thenReturn(breachedCount); | ||
when(mPasswordCheck.getSavedPasswordsCount()).thenReturn(10); | ||
|
||
CompletableFuture<PasswordCheckResult> passwordCheckResultFuture = | ||
mController.getBreachedCredentialsCount(PasswordStoreType.PROFILE_STORE); | ||
verify(mPasswordCheck).addObserver(mController, true); | ||
|
||
mController.onCompromisedCredentialsFetchCompleted(); | ||
mController.onSavedPasswordsFetchCompleted(); | ||
|
||
PasswordCheckResult passwordCheckResult = passwordCheckResultFuture.get(); | ||
assertEquals(OptionalInt.of(breachedCount), passwordCheckResult.getBreachedCount()); | ||
assertEquals(OptionalInt.of(10), passwordCheckResult.getTotalPasswordsCount()); | ||
assertEquals(null, passwordCheckResult.getError()); | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
.../java/src/org/chromium/chrome/browser/pwd_check_wrapper/PasswordCheckNativeException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// Copyright 2024 The Chromium Authors | ||
// 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.pwd_check_wrapper; | ||
|
||
import org.chromium.chrome.browser.password_check.PasswordCheckUIStatus; | ||
|
||
/** | ||
* The exception returned by {@link ChromeNativePasswordCheckController} notifying there was an | ||
* error during password check. | ||
*/ | ||
public class PasswordCheckNativeException extends Exception { | ||
public @PasswordCheckUIStatus int errorCode; | ||
|
||
public PasswordCheckNativeException(String message, @PasswordCheckUIStatus int status) { | ||
super(message); | ||
errorCode = status; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.