Home | History | Annotate | Download | only in tracked
      1 // Copyright 2014 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/prefs/tracked/pref_hash_calculator_helper.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/bind.h"
     11 #include "base/callback.h"
     12 #include "base/logging.h"
     13 #include "base/memory/ref_counted.h"
     14 #include "base/strings/string_number_conversions.h"
     15 #include "base/strings/string_util.h"
     16 #include "chrome/browser/extensions/api/music_manager_private/device_id.h"
     17 #include "content/public/test/test_browser_thread_bundle.h"
     18 #include "content/public/test/test_utils.h"
     19 #include "crypto/hmac.h"
     20 #include "rlz/lib/machine_id.h"
     21 #include "testing/gtest/include/gtest/gtest.h"
     22 
     23 namespace {
     24 
     25 // extensions::api::DeviceId::GetDeviceId() signs the extension_id in
     26 // GetRawDeviceIdCallback to get the final device_id, our code replicating this
     27 // id needs to do the same thing.
     28 const char kFakeExtensionId[] = "foo";
     29 
     30 // Sets |media_device_id_out| to |media_device_id_in| and unblocks the original
     31 // binder by calling |unblock_callback|.
     32 void SetMediaDeviceIdAndUnblock(const base::Closure& unblock_callback,
     33                                 std::string* media_device_id_out,
     34                                 const std::string& media_device_id_in) {
     35   if (media_device_id_in.empty())
     36     LOG(WARNING) << "Media device ID is empty.";
     37   *media_device_id_out = media_device_id_in;
     38   unblock_callback.Run();
     39 }
     40 
     41 // Returns the device id from extensions::api::DeviceId::GetDeviceId()
     42 // synchronously.
     43 std::string GetMediaDeviceIdSynchronously() {
     44   std::string media_device_id;
     45   const scoped_refptr<content::MessageLoopRunner> runner(
     46       new content::MessageLoopRunner);
     47   extensions::api::DeviceId::GetDeviceId(kFakeExtensionId,
     48                                base::Bind(&SetMediaDeviceIdAndUnblock,
     49                                           runner->QuitClosure(),
     50                                           base::Unretained(&media_device_id)));
     51   // Run the message loop until SetMediaDeviceIdAndUnblock() calls the
     52   // QuitClosure when done.
     53   runner->Run();
     54   return media_device_id;
     55 }
     56 
     57 // Copy functionality from GetRawDeviceIdCallback() to get the final device id
     58 // from the |raw_device_id|. Signing |kExtension| with an HMAC-SHA256 using
     59 // |raw_device_id| as its key.
     60 std::string GetDeviceIdFromRawDeviceId(const std::string& raw_device_id) {
     61   crypto::HMAC hmac(crypto::HMAC::SHA256);
     62   const size_t digest_length = hmac.DigestLength();
     63   std::vector<uint8> digest(digest_length);
     64   bool result = hmac.Init(raw_device_id) &&
     65       hmac.Sign(kFakeExtensionId, &digest[0], digest.size());
     66   if (!result) {
     67     ADD_FAILURE();
     68     return std::string();
     69   }
     70   return StringToLowerASCII(base::HexEncode(digest.data(), digest.size()));
     71 }
     72 
     73 std::string GetLegacyIdBasedOnRlzId() {
     74   std::string rlz_machine_id;
     75   rlz_lib::GetMachineId(&rlz_machine_id);
     76   EXPECT_FALSE(rlz_machine_id.empty());
     77 
     78   const std::string raw_legacy_device_id(GetLegacyDeviceId(rlz_machine_id));
     79 
     80   if (raw_legacy_device_id.empty()) {
     81     LOG(WARNING) << "Raw legacy device ID based on RLZ ID is empty.";
     82     return std::string();
     83   }
     84 
     85   const std::string legacy_device_id(
     86       GetDeviceIdFromRawDeviceId(raw_legacy_device_id));
     87   EXPECT_FALSE(legacy_device_id.empty());
     88 
     89   return legacy_device_id;
     90 }
     91 
     92 // Simulate browser threads (required by extensions::api::DeviceId) off of the
     93 // main message loop.
     94 class PrefHashCalculatorHelperTest : public testing::Test {
     95  private:
     96   content::TestBrowserThreadBundle test_browser_thread_bundle;
     97 };
     98 
     99 }  // namespace
    100 
    101 // The implementation for the legacy ID on Windows is copied from
    102 // the M33 version of extensions::api::DeviceId::GetDeviceId(). We no longer
    103 // depend on it as of M34, but should make sure that we are generating the same
    104 // results in the mean time (it will be okay for the extension API's
    105 // implementation to diverge on M34+ and this test can be removed once M34 ships
    106 // to stable).
    107 TEST_F(PrefHashCalculatorHelperTest, ResultMatchesMediaId) {
    108   EXPECT_EQ(GetMediaDeviceIdSynchronously(), GetLegacyIdBasedOnRlzId());
    109 }
    110 
    111 TEST_F(PrefHashCalculatorHelperTest, MediaIdIsDeterministic) {
    112   EXPECT_EQ(GetMediaDeviceIdSynchronously(), GetMediaDeviceIdSynchronously());
    113 }
    114 
    115 TEST_F(PrefHashCalculatorHelperTest, RlzBasedIdIsDeterministic) {
    116   EXPECT_EQ(GetLegacyIdBasedOnRlzId(), GetLegacyIdBasedOnRlzId());
    117 }
    118