-
Notifications
You must be signed in to change notification settings - Fork 892
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a farbling-determined voice name to getVoices
call upstream function if farbling is off add DEPS exit early if no voices extend test timeout move exit condition earlier feedback
- Loading branch information
1 parent
408ef81
commit 8a6e84d
Showing
6 changed files
with
270 additions
and
0 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
150 changes: 150 additions & 0 deletions
150
browser/farbling/brave_speech_synthesis_farbling_browsertest.cc
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,150 @@ | ||
/* Copyright (c) 2021 The Brave Authors. All rights reserved. | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
* You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
#include "base/path_service.h" | ||
#include "brave/browser/brave_content_browser_client.h" | ||
#include "brave/common/brave_paths.h" | ||
#include "brave/components/brave_component_updater/browser/local_data_files_service.h" | ||
#include "brave/components/brave_shields/browser/brave_shields_util.h" | ||
#include "chrome/browser/chrome_content_browser_client.h" | ||
#include "chrome/browser/content_settings/host_content_settings_map_factory.h" | ||
#include "chrome/browser/profiles/profile.h" | ||
#include "chrome/browser/ui/browser.h" | ||
#include "chrome/common/chrome_content_client.h" | ||
#include "chrome/test/base/in_process_browser_test.h" | ||
#include "chrome/test/base/ui_test_utils.h" | ||
#include "content/public/browser/render_frame_host.h" | ||
#include "content/public/test/browser_test.h" | ||
#include "content/public/test/browser_test_utils.h" | ||
#include "net/dns/mock_host_resolver.h" | ||
#include "net/test/embedded_test_server/embedded_test_server.h" | ||
|
||
using brave_shields::ControlType; | ||
|
||
namespace { | ||
const char kEmbeddedTestServerDirectory[] = "speech"; | ||
const char kTitleScript[] = "document.title"; | ||
} // namespace | ||
|
||
class BraveSpeechSynthesisFarblingBrowserTest : public InProcessBrowserTest { | ||
public: | ||
void SetUpOnMainThread() override { | ||
InProcessBrowserTest::SetUpOnMainThread(); | ||
|
||
content_client_.reset(new ChromeContentClient); | ||
content::SetContentClient(content_client_.get()); | ||
browser_content_client_.reset(new BraveContentBrowserClient()); | ||
content::SetBrowserClientForTesting(browser_content_client_.get()); | ||
|
||
host_resolver()->AddRule("*", "127.0.0.1"); | ||
content::SetupCrossSiteRedirector(embedded_test_server()); | ||
|
||
brave::RegisterPathProvider(); | ||
base::FilePath test_data_dir; | ||
base::PathService::Get(brave::DIR_TEST_DATA, &test_data_dir); | ||
test_data_dir = test_data_dir.AppendASCII(kEmbeddedTestServerDirectory); | ||
embedded_test_server()->ServeFilesFromDirectory(test_data_dir); | ||
|
||
ASSERT_TRUE(embedded_test_server()->Start()); | ||
} | ||
|
||
void TearDown() override { | ||
browser_content_client_.reset(); | ||
content_client_.reset(); | ||
} | ||
|
||
HostContentSettingsMap* content_settings() { | ||
return HostContentSettingsMapFactory::GetForProfile(browser()->profile()); | ||
} | ||
|
||
void AllowFingerprinting(std::string domain) { | ||
brave_shields::SetFingerprintingControlType( | ||
content_settings(), ControlType::ALLOW, | ||
embedded_test_server()->GetURL(domain, "/")); | ||
} | ||
|
||
void BlockFingerprinting(std::string domain) { | ||
brave_shields::SetFingerprintingControlType( | ||
content_settings(), ControlType::BLOCK, | ||
embedded_test_server()->GetURL(domain, "/")); | ||
} | ||
|
||
void SetFingerprintingDefault(std::string domain) { | ||
brave_shields::SetFingerprintingControlType( | ||
content_settings(), ControlType::DEFAULT, | ||
embedded_test_server()->GetURL(domain, "/")); | ||
} | ||
|
||
content::WebContents* web_contents() { | ||
return browser()->tab_strip_model()->GetActiveWebContents(); | ||
} | ||
|
||
bool NavigateToURLUntilLoadStop(const GURL& url) { | ||
EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); | ||
return WaitForLoadStop(web_contents()); | ||
} | ||
|
||
private: | ||
std::unique_ptr<ChromeContentClient> content_client_; | ||
std::unique_ptr<BraveContentBrowserClient> browser_content_client_; | ||
}; | ||
|
||
// Tests results of farbling voices list | ||
IN_PROC_BROWSER_TEST_F(BraveSpeechSynthesisFarblingBrowserTest, FarbleVoices) { | ||
std::string domain_b = "b.com"; | ||
std::string domain_z = "z.com"; | ||
GURL url_b = | ||
embedded_test_server()->GetURL(domain_b, "/voices-farbling.html"); | ||
GURL url_z = | ||
embedded_test_server()->GetURL(domain_z, "/voices-farbling.html"); | ||
// Farbling level: off | ||
// The voices list should be the real voices list. | ||
AllowFingerprinting(domain_b); | ||
NavigateToURLUntilLoadStop(url_b); | ||
std::string off_voices_b = | ||
EvalJs(web_contents(), kTitleScript).ExtractString(); | ||
ASSERT_NE("failed", off_voices_b); | ||
|
||
// On platforms without any voices, the rest of this test is invalid. | ||
if (off_voices_b == "") | ||
return; | ||
|
||
AllowFingerprinting(domain_z); | ||
NavigateToURLUntilLoadStop(url_z); | ||
std::string off_voices_z = | ||
EvalJs(web_contents(), kTitleScript).ExtractString(); | ||
ASSERT_NE("failed", off_voices_z); | ||
// The voices list should be the same on every domain if farbling is off. | ||
EXPECT_EQ(off_voices_b, off_voices_z); | ||
|
||
// Farbling level: default | ||
// The voices list is farbled per domain. | ||
SetFingerprintingDefault(domain_b); | ||
NavigateToURLUntilLoadStop(url_b); | ||
std::string default_voices_b = | ||
EvalJs(web_contents(), kTitleScript).ExtractString(); | ||
SetFingerprintingDefault(domain_z); | ||
NavigateToURLUntilLoadStop(url_z); | ||
std::string default_voices_z = | ||
EvalJs(web_contents(), kTitleScript).ExtractString(); | ||
// The farbled voices list should be different from the unfarbled voices | ||
// list, and each domain's lists should be different from each other. | ||
// (That is not true of all domains, because there are a finite number of | ||
// farbling choices, but it should be true of these two domains.) | ||
EXPECT_NE(off_voices_b, default_voices_b); | ||
EXPECT_NE(off_voices_z, default_voices_z); | ||
EXPECT_NE(default_voices_b, default_voices_z); | ||
|
||
// Farbling level: maximum | ||
// The voices list is empty. | ||
BlockFingerprinting(domain_b); | ||
NavigateToURLUntilLoadStop(url_b); | ||
auto max_voices_b = EvalJs(web_contents(), kTitleScript); | ||
EXPECT_EQ("", max_voices_b); | ||
BlockFingerprinting(domain_z); | ||
NavigateToURLUntilLoadStop(url_z); | ||
auto max_voices_z = EvalJs(web_contents(), kTitleScript); | ||
EXPECT_EQ("", max_voices_z); | ||
} |
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,3 @@ | ||
include_rules = [ | ||
"+../../../../../../../third_party/blink/renderer/modules/speech", | ||
] |
63 changes: 63 additions & 0 deletions
63
chromium_src/third_party/blink/renderer/modules/speech/speech_synthesis.cc
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,63 @@ | ||
/* Copyright (c) 2021 The Brave Authors. All rights reserved. | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
* you can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
#include "third_party/blink/renderer/modules/speech/speech_synthesis.h" | ||
#include "brave/third_party/blink/renderer/brave_farbling_constants.h" | ||
#include "third_party/blink/public/platform/web_content_settings_client.h" | ||
|
||
#define OnSetVoiceList OnSetVoiceList_ChromiumImpl | ||
#include "../../../../../../../third_party/blink/renderer/modules/speech/speech_synthesis.cc" | ||
#undef OnSetVoiceList | ||
|
||
namespace blink { | ||
|
||
void SpeechSynthesis::OnSetVoiceList( | ||
Vector<mojom::blink::SpeechSynthesisVoicePtr> mojom_voices) { | ||
voice_list_.clear(); | ||
BraveFarblingLevel farbling_level = BraveFarblingLevel::OFF; | ||
if (ExecutionContext* context = GetExecutionContext()) { | ||
if (blink::WebContentSettingsClient* settings = | ||
brave::GetContentSettingsClientFor(context)) { | ||
farbling_level = settings->GetBraveFarblingLevel(); | ||
} | ||
} | ||
if (farbling_level == BraveFarblingLevel::OFF) { | ||
// farbling off -> call upstream function | ||
OnSetVoiceList_ChromiumImpl(std::move(mojom_voices)); | ||
return; | ||
} | ||
if (farbling_level == BraveFarblingLevel::MAXIMUM) { | ||
// maximum farbling -> return empty voice list | ||
VoicesDidChange(); | ||
return; | ||
} | ||
mojom::blink::SpeechSynthesisVoicePtr fake_voice; | ||
for (auto& mojom_voice : mojom_voices) { | ||
if (!fake_voice && mojom_voice->is_default) { | ||
// balanced farbling -> return real voices + one fake voice | ||
if (ExecutionContext* context = GetExecutionContext()) { | ||
fake_voice = mojom_voice.Clone(); | ||
fake_voice->is_default = false; | ||
std::mt19937_64 prng = brave::BraveSessionCache::From(*context) | ||
.MakePseudoRandomGenerator(); | ||
const char* kFakeNames[] = { | ||
"Hubert", "Vernon", "Rudolph", "Clayton", "Irving", | ||
"Wilson", "Alva", "Harley", "Beauregard", "Cleveland", | ||
"Cecil", "Reuben", "Sylvester", "Jasper"}; | ||
const int kFakeNamesCount = 14; | ||
fake_voice->name = WTF::String(kFakeNames[prng() % kFakeNamesCount]); | ||
} | ||
} | ||
voice_list_.push_back( | ||
MakeGarbageCollected<SpeechSynthesisVoice>(std::move(mojom_voice))); | ||
} | ||
if (fake_voice) { | ||
voice_list_.push_back( | ||
MakeGarbageCollected<SpeechSynthesisVoice>(std::move(fake_voice))); | ||
} | ||
VoicesDidChange(); | ||
} | ||
|
||
} // namespace blink |
21 changes: 21 additions & 0 deletions
21
chromium_src/third_party/blink/renderer/modules/speech/speech_synthesis.h
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,21 @@ | ||
/* Copyright (c) 2021 The Brave Authors. All rights reserved. | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
* you can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
#ifndef BRAVE_CHROMIUM_SRC_THIRD_PARTY_BLINK_RENDERER_MODULES_SPEECH_SPEECH_SYNTHESIS_H_ | ||
#define BRAVE_CHROMIUM_SRC_THIRD_PARTY_BLINK_RENDERER_MODULES_SPEECH_SPEECH_SYNTHESIS_H_ | ||
|
||
// We need to include this here before redefining OnSetVoiceList to avoid a | ||
// name collision with a method in the mojom class. | ||
#include "third_party/blink/public/mojom/speech/speech_synthesis.mojom-blink.h" | ||
|
||
#define OnSetVoiceList \ | ||
OnSetVoiceList_ChromiumImpl( \ | ||
Vector<mojom::blink::SpeechSynthesisVoicePtr> voices); \ | ||
void OnSetVoiceList | ||
|
||
#include "../../../../../../../third_party/blink/renderer/modules/speech/speech_synthesis.h" | ||
#undef OnSetVoiceList | ||
|
||
#endif // BRAVE_CHROMIUM_SRC_THIRD_PARTY_BLINK_RENDERER_MODULES_SPEECH_SPEECH_SYNTHESIS_H_ |
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,32 @@ | ||
<html> | ||
<head><title>failed</title></head> | ||
<body></body> | ||
<script> | ||
if (window.speechSynthesis !== undefined) { | ||
var voicesFormatted = function (voices) { | ||
return voices.map(x => `${x.name} (${x.voiceURI})`).toString() | ||
} | ||
var speechTimeout = 1000 | ||
var speechSynthesisTimerId | ||
|
||
var onVoicesChanged = function () { | ||
clearTimeout(speechSynthesisTimerId) | ||
var voices = window.speechSynthesis.getVoices() | ||
document.title=voicesFormatted(voices); | ||
} | ||
|
||
speechSynthesisTimerId = setTimeout(function () { | ||
window.speechSynthesis.removeEventListener('voiceschanged', onVoicesChanged) | ||
document.title=""; | ||
}, speechTimeout) | ||
|
||
var voices = window.speechSynthesis.getVoices(); | ||
if (voices.length !== 0) { | ||
clearTimeout(speechSynthesisTimerId) | ||
document.title=voicesFormatted(voices); | ||
} else { | ||
window.speechSynthesis.addEventListener('voiceschanged', onVoicesChanged) | ||
} | ||
} | ||
</script> | ||
</html> |