1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/ui/webui/about_ui.h"
6 
7 #include <memory>
8 #include <string>
9 
10 #include "base/base64.h"
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/files/file_path.h"
14 #include "base/files/file_util.h"
15 #include "base/files/scoped_temp_dir.h"
16 #include "base/macros.h"
17 #include "base/memory/ref_counted_memory.h"
18 #include "base/strings/strcat.h"
19 #include "base/strings/string_piece.h"
20 #include "base/strings/string_util.h"
21 #include "base/task/post_task.h"
22 #include "chrome/browser/chromeos/login/demo_mode/demo_setup_controller.h"
23 #include "chrome/browser/chromeos/login/ui/fake_login_display_host.h"
24 #include "chrome/browser/chromeos/login/wizard_controller.h"
25 #include "chrome/browser/ui/webui/chromeos/login/demo_preferences_screen_handler.h"
26 #include "chrome/common/url_constants.h"
27 #include "chrome/common/webui_url_constants.h"
28 #include "chrome/test/base/scoped_browser_locale.h"
29 #include "chromeos/dbus/dbus_thread_manager.h"
30 #include "chromeos/system/fake_statistics_provider.h"
31 #include "chromeos/system/statistics_provider.h"
32 #include "content/public/browser/browser_task_traits.h"
33 #include "content/public/test/browser_task_environment.h"
34 #include "testing/gmock/include/gmock/gmock.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36 
37 namespace {
38 
39 class TestDataReceiver {
40  public:
41   TestDataReceiver() = default;
42   virtual ~TestDataReceiver() = default;
43 
data_received() const44   bool data_received() const { return data_received_; }
45 
data() const46   std::string data() const { return data_; }
47 
Base64DecodedData() const48   std::string Base64DecodedData() const {
49     std::string decoded;
50     base::Base64Decode(data_, &decoded);
51     return decoded;
52   }
53 
OnDataReceived(scoped_refptr<base::RefCountedMemory> bytes)54   void OnDataReceived(scoped_refptr<base::RefCountedMemory> bytes) {
55     data_received_ = true;
56     data_ = base::StringPiece(reinterpret_cast<const char*>(bytes->front()),
57                               bytes->size())
58                 .as_string();
59   }
60 
61  private:
62   bool data_received_ = false;
63   std::string data_;
64 
65   DISALLOW_COPY_AND_ASSIGN(TestDataReceiver);
66 };
67 
68 }  // namespace
69 
70 // Base class for ChromeOS offline terms tests.
71 class ChromeOSTermsTest : public testing::Test {
72  protected:
ChromeOSTermsTest()73   ChromeOSTermsTest() {}
74   ~ChromeOSTermsTest() override = default;
75 
SetUp()76   void SetUp() override {
77     // Create root tmp directory for fake ARC ToS data.
78     base::FilePath root_path;
79     base::CreateNewTempDirectory(FILE_PATH_LITERAL(""), &root_path);
80     ASSERT_TRUE(preinstalled_offline_resources_dir_.Set(root_path));
81     arc_tos_dir_ =
82         preinstalled_offline_resources_dir_.GetPath().Append("arc_tos");
83     ASSERT_TRUE(base::CreateDirectory(arc_tos_dir_));
84 
85     tested_html_source_ = std::make_unique<AboutUIHTMLSource>(
86         chrome::kChromeUITermsHost, nullptr);
87   }
88 
89   // Creates directory for the given |locale| that contains terms.html. Writes
90   // the |locale| string to the created file.
CreateTermsForLocale(const std::string & locale)91   bool CreateTermsForLocale(const std::string& locale) {
92     base::FilePath dir = arc_tos_dir_.Append(base::ToLowerASCII(locale));
93     if (!base::CreateDirectory(dir))
94       return false;
95 
96     if (base::WriteFile(dir.AppendASCII("terms.html"), locale.c_str(),
97                         locale.length()) != static_cast<int>(locale.length())) {
98       return false;
99     }
100     return true;
101   }
102 
103   // Creates directory for the given |locale| that contains privacy_policy.pdf.
104   // Writes the |locale| string to the created file.
CreatePrivacyPolicyForLocale(const std::string & locale)105   bool CreatePrivacyPolicyForLocale(const std::string& locale) {
106     base::FilePath dir = arc_tos_dir_.Append(base::ToLowerASCII(locale));
107     if (!base::CreateDirectory(dir))
108       return false;
109 
110     if (base::WriteFile(dir.AppendASCII("privacy_policy.pdf"), locale.c_str(),
111                         locale.length()) != static_cast<int>(locale.length())) {
112       return false;
113     }
114     return true;
115   }
116 
117   // Sets device region in VPD.
SetRegion(const std::string & region)118   void SetRegion(const std::string& region) {
119     statistics_provider_.SetMachineStatistic(chromeos::system::kRegionKey,
120                                              region);
121   }
122 
123   // Starts data request with the |request_url|.
StartRequest(const std::string & request_url,TestDataReceiver * data_receiver)124   void StartRequest(const std::string& request_url,
125                     TestDataReceiver* data_receiver) {
126     content::WebContents::Getter wc_getter;
127     tested_html_source_->StartDataRequest(
128         GURL(base::StrCat(
129             {"chrome://", chrome::kChromeUITermsHost, "/", request_url})),
130         std::move(wc_getter),
131         base::BindRepeating(&TestDataReceiver::OnDataReceived,
132                             base::Unretained(data_receiver)));
133     task_environment_.RunUntilIdle();
134   }
135 
PreinstalledOfflineResourcesPath()136   const base::FilePath& PreinstalledOfflineResourcesPath() {
137     return preinstalled_offline_resources_dir_.GetPath();
138   }
139 
140  private:
141   base::ScopedTempDir preinstalled_offline_resources_dir_;
142   base::FilePath arc_tos_dir_;
143 
144   content::BrowserTaskEnvironment task_environment_;
145 
146   chromeos::system::ScopedFakeStatisticsProvider statistics_provider_;
147 
148   std::unique_ptr<AboutUIHTMLSource> tested_html_source_;
149 
150   DISALLOW_COPY_AND_ASSIGN(ChromeOSTermsTest);
151 };
152 
TEST_F(ChromeOSTermsTest,NoData)153 TEST_F(ChromeOSTermsTest, NoData) {
154   SetRegion("ca");
155   ScopedBrowserLocale browser_locale("en-CA");
156 
157   TestDataReceiver terms_data_receiver;
158   StartRequest(chrome::kArcTermsURLPath, &terms_data_receiver);
159 
160   EXPECT_TRUE(terms_data_receiver.data_received());
161   EXPECT_EQ("", terms_data_receiver.data());
162 
163   TestDataReceiver privacy_policy_data_receiver;
164   StartRequest(chrome::kArcPrivacyPolicyURLPath, &privacy_policy_data_receiver);
165 
166   EXPECT_TRUE(privacy_policy_data_receiver.data_received());
167   EXPECT_EQ("", privacy_policy_data_receiver.data());
168 }
169 
170 // Demo mode ARC++ ToS and privacy policy test.
171 class DemoModeChromeOSTermsTest : public ChromeOSTermsTest {
172  protected:
173   DemoModeChromeOSTermsTest() = default;
174   ~DemoModeChromeOSTermsTest() override = default;
175 
SetUp()176   void SetUp() override {
177     ChromeOSTermsTest::SetUp();
178     AddDemoModeLocale();
179 
180     // Simulate Demo Mode setup.
181     chromeos::DBusThreadManager::Initialize();
182     fake_login_display_host_ =
183         std::make_unique<chromeos::FakeLoginDisplayHost>();
184     fake_login_display_host_->StartWizard(
185         chromeos::DemoPreferencesScreenView::kScreenId);
186     fake_login_display_host_->GetWizardController()
187         ->SimulateDemoModeSetupForTesting();
188     fake_login_display_host_->GetWizardController()
189         ->demo_setup_controller()
190         ->SetPreinstalledOfflineResourcesPathForTesting(
191             PreinstalledOfflineResourcesPath());
192     fake_login_display_host_->GetWizardController()
193         ->demo_setup_controller()
194         ->TryMountPreinstalledDemoResources(base::DoNothing());
195   }
196 
TearDown()197   void TearDown() override { chromeos::DBusThreadManager::Shutdown(); }
198 
199   // Adds locales supported by demo mode.
AddDemoModeLocale()200   void AddDemoModeLocale() {
201     ASSERT_TRUE(CreateTermsForLocale("apac"));
202     ASSERT_TRUE(CreateTermsForLocale("da-DK"));
203     ASSERT_TRUE(CreateTermsForLocale("de-de"));
204     ASSERT_TRUE(CreateTermsForLocale("emea"));
205     ASSERT_TRUE(CreateTermsForLocale("en-CA"));
206     ASSERT_TRUE(CreateTermsForLocale("en-GB"));
207     ASSERT_TRUE(CreateTermsForLocale("en-IE"));
208     ASSERT_TRUE(CreateTermsForLocale("en-US"));
209     ASSERT_TRUE(CreateTermsForLocale("eu"));
210     ASSERT_TRUE(CreateTermsForLocale("fi-FI"));
211     ASSERT_TRUE(CreateTermsForLocale("fr-BE"));
212     ASSERT_TRUE(CreateTermsForLocale("fr-CA"));
213     ASSERT_TRUE(CreateTermsForLocale("fr-FR"));
214     ASSERT_TRUE(CreateTermsForLocale("ko-KR"));
215     ASSERT_TRUE(CreateTermsForLocale("nb-NO"));
216     ASSERT_TRUE(CreateTermsForLocale("nl-BE"));
217     ASSERT_TRUE(CreateTermsForLocale("nl-NL"));
218     ASSERT_TRUE(CreateTermsForLocale("sv-SE"));
219 
220     ASSERT_TRUE(CreatePrivacyPolicyForLocale("da-DK"));
221     ASSERT_TRUE(CreatePrivacyPolicyForLocale("de-de"));
222     ASSERT_TRUE(CreatePrivacyPolicyForLocale("en-US"));
223     ASSERT_TRUE(CreatePrivacyPolicyForLocale("eu"));
224     ASSERT_TRUE(CreatePrivacyPolicyForLocale("fi-FI"));
225     ASSERT_TRUE(CreatePrivacyPolicyForLocale("fr-BE"));
226     ASSERT_TRUE(CreatePrivacyPolicyForLocale("fr-CA"));
227     ASSERT_TRUE(CreatePrivacyPolicyForLocale("fr-FR"));
228     ASSERT_TRUE(CreatePrivacyPolicyForLocale("ko-KR"));
229     ASSERT_TRUE(CreatePrivacyPolicyForLocale("nb-NO"));
230     ASSERT_TRUE(CreatePrivacyPolicyForLocale("nl-BE"));
231     ASSERT_TRUE(CreatePrivacyPolicyForLocale("nl-NL"));
232     ASSERT_TRUE(CreatePrivacyPolicyForLocale("sv-SE"));
233   }
234 
235  private:
236   std::unique_ptr<chromeos::FakeLoginDisplayHost> fake_login_display_host_;
237 
238   DISALLOW_COPY_AND_ASSIGN(DemoModeChromeOSTermsTest);
239 };
240 
TEST_F(DemoModeChromeOSTermsTest,TermsSimpleRegion)241 TEST_F(DemoModeChromeOSTermsTest, TermsSimpleRegion) {
242   SetRegion("ca");
243   for (const char* locale : {"en-CA", "fr-CA"}) {
244     ScopedBrowserLocale browser_locale(locale);
245 
246     TestDataReceiver data_receiver;
247     StartRequest(chrome::kArcTermsURLPath, &data_receiver);
248 
249     EXPECT_TRUE(data_receiver.data_received());
250     EXPECT_EQ(locale, data_receiver.data());
251   }
252 }
253 
TEST_F(DemoModeChromeOSTermsTest,ComplexRegion)254 TEST_F(DemoModeChromeOSTermsTest, ComplexRegion) {
255   const std::string kLocale = "en-CA";
256   ScopedBrowserLocale browser_locale(kLocale);
257   for (const char* region :
258        {"ca.hybridansi", "ca.ansi", "ca.multix", "ca.fr"}) {
259     SetRegion(region);
260 
261     TestDataReceiver terms_data_receiver;
262     StartRequest(chrome::kArcTermsURLPath, &terms_data_receiver);
263 
264     EXPECT_TRUE(terms_data_receiver.data_received());
265     EXPECT_EQ(kLocale, terms_data_receiver.data());
266 
267     TestDataReceiver privacy_data_receiver;
268     StartRequest(chrome::kArcPrivacyPolicyURLPath, &privacy_data_receiver);
269 
270     // Privacy policy for en-CA defaults to en-US.
271     EXPECT_TRUE(privacy_data_receiver.data_received());
272     EXPECT_EQ("en-US", privacy_data_receiver.Base64DecodedData());
273   }
274 }
275 
TEST_F(DemoModeChromeOSTermsTest,NotCaseSensitive)276 TEST_F(DemoModeChromeOSTermsTest, NotCaseSensitive) {
277   SetRegion("CA");
278   for (const char* locale : {"EN-CA", "en-CA", "EN-ca"}) {
279     ScopedBrowserLocale browser_locale(locale);
280 
281     TestDataReceiver terms_data_receiver;
282     StartRequest(chrome::kArcTermsURLPath, &terms_data_receiver);
283 
284     EXPECT_TRUE(terms_data_receiver.data_received());
285     EXPECT_EQ("en-CA", terms_data_receiver.data());
286 
287     TestDataReceiver privacy_data_receiver;
288     StartRequest(chrome::kArcPrivacyPolicyURLPath, &privacy_data_receiver);
289 
290     // Privacy policy for en-CA defaults to en-US.
291     EXPECT_TRUE(privacy_data_receiver.data_received());
292     EXPECT_EQ("en-US", privacy_data_receiver.Base64DecodedData());
293   }
294 }
295 
TEST_F(DemoModeChromeOSTermsTest,DefaultsForEuRegion)296 TEST_F(DemoModeChromeOSTermsTest, DefaultsForEuRegion) {
297   const std::string kLocale = "pl-PL";
298   ScopedBrowserLocale browser_locale(kLocale);
299   SetRegion("pl");
300 
301   TestDataReceiver terms_data_receiver;
302   StartRequest(chrome::kArcTermsURLPath, &terms_data_receiver);
303 
304   EXPECT_TRUE(terms_data_receiver.data_received());
305   EXPECT_EQ("eu", terms_data_receiver.data());
306 
307   TestDataReceiver privacy_data_receiver;
308   StartRequest(chrome::kArcPrivacyPolicyURLPath, &privacy_data_receiver);
309 
310   EXPECT_TRUE(privacy_data_receiver.data_received());
311   EXPECT_EQ("eu", privacy_data_receiver.Base64DecodedData());
312 }
313 
TEST_F(DemoModeChromeOSTermsTest,DefaultsForEmeaRegion)314 TEST_F(DemoModeChromeOSTermsTest, DefaultsForEmeaRegion) {
315   const std::string kLocale = "fr-CH";
316   ScopedBrowserLocale browser_locale(kLocale);
317   SetRegion("ch");
318 
319   TestDataReceiver terms_data_receiver;
320   StartRequest(chrome::kArcTermsURLPath, &terms_data_receiver);
321 
322   EXPECT_TRUE(terms_data_receiver.data_received());
323   EXPECT_EQ("emea", terms_data_receiver.data());
324 
325   TestDataReceiver privacy_data_receiver;
326   StartRequest(chrome::kArcPrivacyPolicyURLPath, &privacy_data_receiver);
327 
328   // Privacy policy for EMEA defaults to en-US.
329   EXPECT_TRUE(privacy_data_receiver.data_received());
330   EXPECT_EQ("en-US", privacy_data_receiver.Base64DecodedData());
331 }
332 
TEST_F(DemoModeChromeOSTermsTest,DefaultsForApacRegion)333 TEST_F(DemoModeChromeOSTermsTest, DefaultsForApacRegion) {
334   const std::string kLocale = "en-PH";
335   ScopedBrowserLocale browser_locale(kLocale);
336   SetRegion("ph");
337 
338   TestDataReceiver terms_data_receiver;
339   StartRequest(chrome::kArcTermsURLPath, &terms_data_receiver);
340 
341   EXPECT_TRUE(terms_data_receiver.data_received());
342   EXPECT_EQ("apac", terms_data_receiver.data());
343 
344   TestDataReceiver privacy_data_receiver;
345   StartRequest(chrome::kArcPrivacyPolicyURLPath, &privacy_data_receiver);
346 
347   // Privacy policy for APAC defaults to en-US.
348   EXPECT_TRUE(privacy_data_receiver.data_received());
349   EXPECT_EQ("en-US", privacy_data_receiver.Base64DecodedData());
350 }
351 
TEST_F(DemoModeChromeOSTermsTest,DefaultsForAmericasRegion)352 TEST_F(DemoModeChromeOSTermsTest, DefaultsForAmericasRegion) {
353   const std::string kLocale = "en-MX";
354   ScopedBrowserLocale browser_locale(kLocale);
355   SetRegion("mx");
356 
357   // Both ToS and privacy policy default to en-US for AMERICAS.
358   TestDataReceiver terms_data_receiver;
359   StartRequest(chrome::kArcTermsURLPath, &terms_data_receiver);
360 
361   EXPECT_TRUE(terms_data_receiver.data_received());
362   EXPECT_EQ("en-US", terms_data_receiver.data());
363 
364   TestDataReceiver privacy_data_receiver;
365   StartRequest(chrome::kArcPrivacyPolicyURLPath, &privacy_data_receiver);
366 
367   EXPECT_TRUE(privacy_data_receiver.data_received());
368   EXPECT_EQ("en-US", privacy_data_receiver.Base64DecodedData());
369 }
370 
TEST_F(DemoModeChromeOSTermsTest,DefaultsToEnUs)371 TEST_F(DemoModeChromeOSTermsTest, DefaultsToEnUs) {
372   const std::string kLocale = "en-SA";
373   ScopedBrowserLocale browser_locale(kLocale);
374   SetRegion("sa");
375 
376   TestDataReceiver terms_data_receiver;
377   StartRequest(chrome::kArcTermsURLPath, &terms_data_receiver);
378 
379   EXPECT_TRUE(terms_data_receiver.data_received());
380   EXPECT_EQ("en-US", terms_data_receiver.data());
381 
382   TestDataReceiver privacy_data_receiver;
383   StartRequest(chrome::kArcPrivacyPolicyURLPath, &privacy_data_receiver);
384 
385   EXPECT_TRUE(privacy_data_receiver.data_received());
386   EXPECT_EQ("en-US", privacy_data_receiver.Base64DecodedData());
387 }
388 
TEST_F(DemoModeChromeOSTermsTest,NoLangCountryCombination)389 TEST_F(DemoModeChromeOSTermsTest, NoLangCountryCombination) {
390   SetRegion("be");
391   {
392     const std::string kLocale = "nl-BE";
393     ScopedBrowserLocale browser_locale(kLocale);
394 
395     TestDataReceiver terms_data_receiver;
396     StartRequest(chrome::kArcTermsURLPath, &terms_data_receiver);
397 
398     EXPECT_TRUE(terms_data_receiver.data_received());
399     EXPECT_EQ(kLocale, terms_data_receiver.data());
400 
401     TestDataReceiver privacy_data_receiver;
402     StartRequest(chrome::kArcPrivacyPolicyURLPath, &privacy_data_receiver);
403 
404     EXPECT_TRUE(privacy_data_receiver.data_received());
405     EXPECT_EQ(kLocale, privacy_data_receiver.Base64DecodedData());
406   }
407   {
408     const std::string kLocale = "de-BE";
409     ScopedBrowserLocale browser_locale(kLocale);
410 
411     TestDataReceiver terms_data_receiver;
412     StartRequest(chrome::kArcTermsURLPath, &terms_data_receiver);
413 
414     // No language - country combination - defaults to region.
415     EXPECT_TRUE(terms_data_receiver.data_received());
416     EXPECT_EQ("eu", terms_data_receiver.data());
417 
418     TestDataReceiver privacy_data_receiver;
419     StartRequest(chrome::kArcPrivacyPolicyURLPath, &privacy_data_receiver);
420 
421     EXPECT_TRUE(privacy_data_receiver.data_received());
422     EXPECT_EQ("eu", privacy_data_receiver.Base64DecodedData());
423   }
424 }
425 
TEST_F(DemoModeChromeOSTermsTest,InvalidRegion)426 TEST_F(DemoModeChromeOSTermsTest, InvalidRegion) {
427   const std::string kLocale = "da-DK";
428   ScopedBrowserLocale browser_locale(kLocale);
429   for (const char* region : {"", " ", ".", "..", "-", "xyz"}) {
430     SetRegion(region);
431     TestDataReceiver terms_data_receiver;
432     StartRequest(chrome::kArcTermsURLPath, &terms_data_receiver);
433 
434     EXPECT_TRUE(terms_data_receiver.data_received());
435     EXPECT_EQ("en-US", terms_data_receiver.data());
436 
437     TestDataReceiver privacy_data_receiver;
438     StartRequest(chrome::kArcPrivacyPolicyURLPath, &privacy_data_receiver);
439 
440     EXPECT_TRUE(privacy_data_receiver.data_received());
441     EXPECT_EQ("en-US", privacy_data_receiver.Base64DecodedData());
442   }
443 }
444 
TEST_F(DemoModeChromeOSTermsTest,InvalidLocale)445 TEST_F(DemoModeChromeOSTermsTest, InvalidLocale) {
446   SetRegion("se");
447   for (const char* locale : {"", " ", ".", "-", "-sv"}) {
448     ScopedBrowserLocale browser_locale(locale);
449 
450     TestDataReceiver terms_data_receiver;
451     StartRequest(chrome::kArcTermsURLPath, &terms_data_receiver);
452 
453     EXPECT_TRUE(terms_data_receiver.data_received());
454     EXPECT_EQ("eu", terms_data_receiver.data());
455 
456     TestDataReceiver privacy_data_receiver;
457     StartRequest(chrome::kArcPrivacyPolicyURLPath, &privacy_data_receiver);
458 
459     EXPECT_TRUE(privacy_data_receiver.data_received());
460     EXPECT_EQ("eu", privacy_data_receiver.Base64DecodedData());
461   }
462 }
463