[go: nahoru, domu]

blob: 7f7e9caaa000ca566c891014d34d3a43a9d0f74d [file] [log] [blame]
// Copyright 2023 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.android_webview.test;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.UseParametersRunnerFactory;
import org.chromium.android_webview.AwContents;
import org.chromium.android_webview.JsReplyProxy;
import org.chromium.android_webview.WebMessageListener;
import org.chromium.android_webview.common.AwFeatures;
import org.chromium.android_webview.common.AwSupervisedUserUrlClassifierDelegate;
import org.chromium.android_webview.common.PlatformServiceBridge;
import org.chromium.base.Callback;
import org.chromium.base.test.util.Batch;
import org.chromium.base.test.util.CallbackHelper;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Feature;
import org.chromium.content_public.browser.MessagePayload;
import org.chromium.content_public.browser.MessagePort;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.net.test.util.TestWebServer;
import org.chromium.url.GURL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeoutException;
/**
* Tests for blocking mature sites for supervised users.
*
* These tests only check the url loading part of the integration, not
* the call to GMS core which would check if the current user can load
* a particular url.
*/
@RunWith(Parameterized.class)
@UseParametersRunnerFactory(AwJUnit4ClassRunnerWithParameters.Factory.class)
@Batch(Batch.PER_CLASS)
public class AwSupervisedUserTest extends AwParameterizedTest {
private static final String SAFE_SITE_TITLE = "Safe site";
private static final String SAFE_SITE_PATH = "/safe.html";
private static final String SAFE_SITE_IFRAME_TITLE = "IFrame safe site";
private static final String SAFE_SITE_IFRAME_PATH = "/safe-inner.html";
private static final String MATURE_SITE_TITLE = "Mature site";
private static final String MATURE_SITE_PATH = "/mature.html";
private static final String MATURE_SITE_IFRAME_TITLE = "IFrame mature site";
private static final String MATURE_SITE_IFRAME_PATH = "/mature-inner.html";
private static final String BLOCKED_SITE_TITLE = "This website is blocked by your parent.";
private static String makeTestPage(String title, @Nullable String iFrameUrl) {
StringBuilder sb = new StringBuilder();
sb.append("<html><head><title>").append(title).append("</title></head><body>Hello world!");
if (iFrameUrl != null) {
sb.append("<iframe id='testIframe' src='").append(iFrameUrl).append("'></iframe>");
sb.append("<script>");
sb.append("document.getElementById('testIframe').addEventListener('load', function(){");
sb.append("var title;");
sb.append("try {");
sb.append("title = this.contentWindow.document.title");
sb.append("} catch (error){ if (error.name == 'SecurityError') {title = '")
.append(BLOCKED_SITE_TITLE)
.append("';}}");
sb.append("myObject.postMessage(title)});");
sb.append("</script>");
}
sb.append("</body></html>");
return sb.toString();
}
@Rule public AwActivityTestRule mActivityTestRule;
private OnProgressChangedClient mContentsClient = new OnProgressChangedClient();
private AwContents mAwContents;
private TestWebServer mWebServer;
private IFrameLoadedListener mIFrameLoadedListener = new IFrameLoadedListener();
public AwSupervisedUserTest(AwSettingsMutation param) {
this.mActivityTestRule = new AwActivityTestRule(param.getMutation());
}
@Before
public void setUp() throws Exception {
mWebServer = TestWebServer.start();
PlatformServiceBridge.injectInstance(new TestPlatformServiceBridge());
AwTestContainerView testContainerView =
mActivityTestRule.createAwTestContainerViewOnMainSync(mContentsClient);
mAwContents = testContainerView.getAwContents();
AwActivityTestRule.enableJavaScriptOnUiThread(mAwContents);
TestThreadUtils.runOnUiThreadBlocking(
() -> {
mAwContents.addWebMessageListener(
"myObject", new String[] {"*"}, mIFrameLoadedListener);
});
}
@After
public void tearDown() throws Exception {
mActivityTestRule.destroyAwContentsOnMainSync(mAwContents);
mWebServer.shutdown();
}
@Test
@SmallTest
@Feature({"AndroidWebView"})
@CommandLineFlags.Add("enable-features=" + AwFeatures.WEBVIEW_SUPERVISED_USER_SITE_BLOCK)
public void testAllowedSiteIsLoaded() throws Throwable {
String embeddedUrl = setUpWebPage(SAFE_SITE_IFRAME_PATH, SAFE_SITE_IFRAME_TITLE, null);
String requestUrl = setUpWebPage(SAFE_SITE_PATH, SAFE_SITE_TITLE, embeddedUrl);
loadUrl(requestUrl);
assertPageTitle(SAFE_SITE_TITLE);
assertIframeTitle(SAFE_SITE_IFRAME_TITLE);
}
@Test
@SmallTest
@Feature({"AndroidWebView"})
@CommandLineFlags.Add("enable-features=" + AwFeatures.WEBVIEW_SUPERVISED_USER_SITE_BLOCK)
public void testDisallowedSiteIsBlocked() throws Throwable {
String requestUrl = setUpWebPage(MATURE_SITE_PATH, MATURE_SITE_TITLE, null);
loadUrl(requestUrl);
assertPageTitle(BLOCKED_SITE_TITLE);
}
@Test
@SmallTest
@Feature({"AndroidWebView"})
@CommandLineFlags.Add("enable-features=" + AwFeatures.WEBVIEW_SUPERVISED_USER_SITE_BLOCK)
public void testDisallowedEmbeddedSiteIsBlocked() throws Throwable {
String embeddedUrl = setUpWebPage(MATURE_SITE_IFRAME_PATH, MATURE_SITE_IFRAME_TITLE, null);
String requestUrl = setUpWebPage(SAFE_SITE_PATH, SAFE_SITE_TITLE, embeddedUrl);
loadUrl(requestUrl);
assertPageTitle(SAFE_SITE_TITLE);
assertIframeTitle(BLOCKED_SITE_TITLE);
}
@Test
@SmallTest
@Feature({"AndroidWebView"})
@CommandLineFlags.Add("enable-features=" + AwFeatures.WEBVIEW_SUPERVISED_USER_SITE_BLOCK)
public void testDisallowedSiteRedirectIsBlocked() throws Throwable {
String requestUrl = mWebServer.setRedirect(MATURE_SITE_PATH, SAFE_SITE_PATH);
loadUrl(requestUrl);
assertPageTitle(BLOCKED_SITE_TITLE);
}
@Test
@SmallTest
@Feature({"AndroidWebView"})
@CommandLineFlags.Add("enable-features=" + AwFeatures.WEBVIEW_SUPERVISED_USER_SITE_BLOCK)
public void testDisallowedRedirectIsBlocked() throws Throwable {
String requestUrl = mWebServer.setRedirect(SAFE_SITE_PATH, MATURE_SITE_PATH);
loadUrl(requestUrl);
assertPageTitle(BLOCKED_SITE_TITLE);
}
@Test
@SmallTest
@Feature({"AndroidWebView"})
@CommandLineFlags.Add(
"disable-features="
+ AwFeatures.WEBVIEW_SUPERVISED_USER_SITE_BLOCK
+ ","
+ AwFeatures.WEBVIEW_SUPERVISED_USER_SITE_DETECTION)
public void testDisallowedSiteIsLoadedFeatureOff() throws Throwable {
String embeddedUrl = setUpWebPage(MATURE_SITE_IFRAME_PATH, MATURE_SITE_IFRAME_TITLE, null);
String requestUrl = setUpWebPage(MATURE_SITE_PATH, MATURE_SITE_TITLE, embeddedUrl);
loadUrl(requestUrl);
assertPageTitle(MATURE_SITE_TITLE);
assertIframeTitle(MATURE_SITE_IFRAME_TITLE);
}
private String setUpWebPage(String path, String title, @Nullable String iFrameUrl) {
return mWebServer.setResponse(path, makeTestPage(title, iFrameUrl), null);
}
private void loadUrl(String requestUrl) throws TimeoutException {
InstrumentationRegistry.getInstrumentation()
.runOnMainSync(() -> mAwContents.loadUrl(requestUrl, null));
mContentsClient.waitForFullLoad();
}
private void assertPageTitle(String expectedTitle) {
Assert.assertEquals(expectedTitle, mAwContents.getTitle());
}
private void assertIframeTitle(String expectedTitle) throws Exception {
String iFrameTitle = mIFrameLoadedListener.waitForResult();
Assert.assertEquals(expectedTitle, iFrameTitle);
}
private static class OnProgressChangedClient extends TestAwContentsClient {
private final List<Integer> mProgresses = new ArrayList<>();
private final CallbackHelper mCallbackHelper = new CallbackHelper();
@Override
public void onProgressChanged(int progress) {
super.onProgressChanged(progress);
mProgresses.add(Integer.valueOf(progress));
if (progress == 100 && mCallbackHelper.getCallCount() == 0) {
mCallbackHelper.notifyCalled();
}
}
public void waitForFullLoad() throws TimeoutException {
mCallbackHelper.waitForFirst();
}
}
private static class IFrameLoadedListener implements WebMessageListener {
private final CallbackHelper mCallbackHelper = new CallbackHelper();
private volatile String mResult;
@Override
public void onPostMessage(
MessagePayload payload,
Uri topLevelOrigin,
Uri sourceOrigin,
boolean isMainFrame,
JsReplyProxy replyProxy,
MessagePort[] ports) {
mResult = payload.getAsString();
mCallbackHelper.notifyCalled();
}
public String waitForResult() throws TimeoutException {
mCallbackHelper.waitForNext();
return mResult;
}
}
private static class TestPlatformServiceBridge extends PlatformServiceBridge {
private class TestAwSupervisedUserUrlClassifierDelegate
implements AwSupervisedUserUrlClassifierDelegate {
@Override
public void shouldBlockUrl(GURL requestUrl, @NonNull final Callback<Boolean> callback) {
String path = requestUrl.getPath();
if (path.equals(SAFE_SITE_PATH) || path.equals(SAFE_SITE_IFRAME_PATH)) {
callback.onResult(false);
return;
} else if (path.equals(MATURE_SITE_PATH) || path.equals(MATURE_SITE_IFRAME_PATH)) {
callback.onResult(true);
return;
}
assert false;
}
}
@Override
public AwSupervisedUserUrlClassifierDelegate getUrlClassifierDelegate() {
return new TestAwSupervisedUserUrlClassifierDelegate();
}
}
}