Revert 144071 - Add a regenerate button to regenerate the password in Windows.
BUG=120480 TEST=Not tested. Review URL: https://chromiumcodereview.appspot.com/10642009 TBR=zysxqn@google.com Review URL: https://chromiumcodereview.appspot.com/10659022 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@144074 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
chrome/browser/ui/views
rlz
DEPSOWNERS
lib
assert.ccassert.hcrc32.hcrc32_unittest.cccrc32_wrapper.cccrc8.cccrc8.hcrc8_unittest.ccfinancial_ping.ccfinancial_ping.hfinancial_ping_test.cclib_values.cclib_values.hlib_values_unittest.ccmachine_id.ccmachine_id.hmachine_id_unittest.ccrlz_enums.hrlz_lib.ccrlz_lib.hrlz_lib_clear.ccrlz_lib_test.ccrlz_value_store.hstring_utils.ccstring_utils.hstring_utils_unittest.cc
mac
rlz.gyptest
win
@ -2487,8 +2487,6 @@ void BrowserView::ShowPasswordGenerationBubble(
|
||||
const gfx::Rect& rect,
|
||||
autofill::PasswordGenerator* password_generator,
|
||||
const webkit::forms::PasswordForm& form) {
|
||||
ui::ThemeProvider* theme_provider = GetWidget()->GetThemeProvider();
|
||||
|
||||
// Create a rect in the content bounds that the bubble will point to.
|
||||
gfx::Point origin(rect.origin());
|
||||
views::View::ConvertPointToScreen(GetTabContentsContainerView(), &origin);
|
||||
@ -2507,8 +2505,7 @@ void BrowserView::ShowPasswordGenerationBubble(
|
||||
tab_contents->web_contents()->GetRenderViewHost(),
|
||||
password_generator,
|
||||
browser_.get(),
|
||||
tab_contents->password_manager(),
|
||||
theme_provider);
|
||||
tab_contents->password_manager());
|
||||
|
||||
views::BubbleDelegateView::CreateBubble(bubble);
|
||||
bubble->SetAlignment(views::BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR);
|
||||
|
@ -15,10 +15,7 @@
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "googleurl/src/gurl.h"
|
||||
#include "grit/generated_resources.h"
|
||||
#include "grit/theme_resources_standard.h"
|
||||
#include "ui/base/theme_provider.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/views/controls/button/image_button.h"
|
||||
#include "ui/views/controls/button/text_button.h"
|
||||
#include "ui/views/controls/label.h"
|
||||
#include "ui/views/controls/link.h"
|
||||
@ -36,19 +33,16 @@ PasswordGenerationBubbleView::PasswordGenerationBubbleView(
|
||||
content::RenderViewHost* render_view_host,
|
||||
autofill::PasswordGenerator* password_generator,
|
||||
content::PageNavigator* navigator,
|
||||
PasswordManager* password_manager,
|
||||
ui::ThemeProvider* theme_provider)
|
||||
PasswordManager* password_manager)
|
||||
: BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_LEFT),
|
||||
accept_button_(NULL),
|
||||
regenerate_button_(NULL),
|
||||
text_field_(NULL),
|
||||
anchor_rect_(anchor_rect),
|
||||
form_(form),
|
||||
render_view_host_(render_view_host),
|
||||
password_generator_(password_generator),
|
||||
navigator_(navigator),
|
||||
password_manager_(password_manager),
|
||||
theme_provider_(theme_provider) {}
|
||||
password_manager_(password_manager) {}
|
||||
|
||||
PasswordGenerationBubbleView::~PasswordGenerationBubbleView() {}
|
||||
|
||||
@ -58,15 +52,6 @@ void PasswordGenerationBubbleView::Init() {
|
||||
accept_button_ = new views::NativeTextButton(this,
|
||||
ASCIIToUTF16("Try It"));
|
||||
|
||||
regenerate_button_ = new views::ImageButton(this);
|
||||
regenerate_button_->SetImage(views::CustomButton::BS_NORMAL,
|
||||
theme_provider_->GetImageSkiaNamed(IDR_RELOAD));
|
||||
regenerate_button_->SetImage(views::CustomButton::BS_HOT,
|
||||
theme_provider_->GetImageSkiaNamed(IDR_RELOAD_H));
|
||||
regenerate_button_->SetImage(views::CustomButton::BS_PUSHED,
|
||||
theme_provider_->GetImageSkiaNamed(IDR_RELOAD_P));
|
||||
regenerate_button_->SetTooltipText(ASCIIToUTF16("Regenerate"));
|
||||
|
||||
text_field_ = new views::Textfield();
|
||||
text_field_->SetText(
|
||||
ASCIIToUTF16(password_generator_->Generate()));
|
||||
@ -94,8 +79,6 @@ void PasswordGenerationBubbleView::Init() {
|
||||
cs = layout->AddColumnSet(1);
|
||||
cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0,
|
||||
GridLayout::USE_PREF, 0, 100);
|
||||
cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0, GridLayout::FIXED,
|
||||
regenerate_button_->GetPreferredSize().width(), 100);
|
||||
cs->AddPaddingColumn(1, views::kRelatedControlHorizontalSpacing);
|
||||
cs->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0,
|
||||
GridLayout::USE_PREF, 0, 0);
|
||||
@ -106,7 +89,6 @@ void PasswordGenerationBubbleView::Init() {
|
||||
|
||||
layout->StartRow(0, 1);
|
||||
layout->AddView(text_field_);
|
||||
layout->AddView(regenerate_button_);
|
||||
layout->AddView(accept_button_);
|
||||
}
|
||||
|
||||
@ -121,9 +103,6 @@ void PasswordGenerationBubbleView::ButtonPressed(views::Button* sender,
|
||||
render_view_host_->GetRoutingID(), text_field_->text()));
|
||||
password_manager_->SetFormHasGeneratedPassword(form_);
|
||||
StartFade(false);
|
||||
} else if (sender == regenerate_button_) {
|
||||
text_field_->SetText(
|
||||
ASCIIToUTF16(password_generator_->Generate()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,6 @@ class RenderViewHost;
|
||||
}
|
||||
|
||||
namespace views {
|
||||
class ImageButton;
|
||||
class TextButton;
|
||||
class Textfield;
|
||||
}
|
||||
@ -45,8 +44,7 @@ class PasswordGenerationBubbleView : public views::BubbleDelegateView,
|
||||
content::RenderViewHost* render_view_host,
|
||||
autofill::PasswordGenerator* password_generator,
|
||||
content::PageNavigator* navigator,
|
||||
PasswordManager* password_manager,
|
||||
ui::ThemeProvider* theme_provider);
|
||||
PasswordManager* password_manager);
|
||||
virtual ~PasswordGenerationBubbleView();
|
||||
|
||||
private:
|
||||
@ -66,7 +64,6 @@ class PasswordGenerationBubbleView : public views::BubbleDelegateView,
|
||||
|
||||
// Subviews
|
||||
views::TextButton* accept_button_;
|
||||
views::ImageButton* regenerate_button_;
|
||||
views::Textfield* text_field_;
|
||||
|
||||
// Location that the bubble points to
|
||||
@ -88,9 +85,6 @@ class PasswordGenerationBubbleView : public views::BubbleDelegateView,
|
||||
// PasswordManager associated with this tab.
|
||||
PasswordManager* password_manager_;
|
||||
|
||||
// Theme provider used to draw the regenerate button.
|
||||
ui::ThemeProvider* theme_provider_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PasswordGenerationBubbleView);
|
||||
};
|
||||
|
||||
|
70
rlz/DEPS
Normal file
70
rlz/DEPS
Normal file
@ -0,0 +1,70 @@
|
||||
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
#
|
||||
# This DEPS file exists so that it can capture the dependenciez of RLZ. This
|
||||
# allows external projects to check it out and build it independently from all
|
||||
# of chrome.
|
||||
|
||||
vars = {
|
||||
"chrev": "@119173"
|
||||
}
|
||||
|
||||
deps = {
|
||||
"src/base":
|
||||
"http://src.chromium.org/svn/trunk/src/base" + Var("chrev"),
|
||||
|
||||
"src/build":
|
||||
"http://src.chromium.org/svn/trunk/src/build" + Var("chrev"),
|
||||
|
||||
"src/third_party/icu":
|
||||
"http://src.chromium.org/svn/trunk/deps/third_party/icu42" + Var("chrev"),
|
||||
|
||||
"src/third_party/modp_b64":
|
||||
"http://src.chromium.org/svn/trunk/src/third_party/modp_b64" + Var("chrev"),
|
||||
|
||||
"src/third_party/nss":
|
||||
"http://src.chromium.org/svn/trunk/deps/third_party/nss" + Var("chrev"),
|
||||
|
||||
"src/third_party/sqlite":
|
||||
"http://src.chromium.org/svn/trunk/src/third_party/sqlite" + Var("chrev"),
|
||||
|
||||
"src/third_party/wtl":
|
||||
"http://src.chromium.org/svn/trunk/src/third_party/wtl" + Var("chrev"),
|
||||
|
||||
"src/third_party/zlib":
|
||||
"http://src.chromium.org/svn/trunk/src/third_party/zlib" + Var("chrev"),
|
||||
|
||||
"src/testing":
|
||||
"http://src.chromium.org/svn/trunk/src/testing" + Var("chrev"),
|
||||
|
||||
"src/testing/gmock":
|
||||
"http://googlemock.googlecode.com/svn/trunk@374",
|
||||
|
||||
"src/testing/gtest":
|
||||
"http://googletest.googlecode.com/svn/trunk@492",
|
||||
|
||||
"src/tools/gyp":
|
||||
"http://gyp.googlecode.com/svn/trunk@1233",
|
||||
|
||||
"src/tools/win":
|
||||
"http://src.chromium.org/svn/trunk/src/tools/win" + Var("chrev"),
|
||||
|
||||
# If using rlz with chrome's networking library, add it and its dependencies
|
||||
# here.
|
||||
}
|
||||
|
||||
include_rules = [
|
||||
"+build",
|
||||
"+net", # This is only used when force_rlz_use_chrome_net=1 is passed to gyp.
|
||||
"+third_party/zlib",
|
||||
]
|
||||
|
||||
hooks = [
|
||||
{
|
||||
# A change to a .gyp, .gypi, or to GYP itself should run the generator.
|
||||
"pattern": ".",
|
||||
"action": ["python", "src/build/gyp_chromium", "src/rlz/rlz.gyp"],
|
||||
}
|
||||
]
|
||||
|
4
rlz/OWNERS
Normal file
4
rlz/OWNERS
Normal file
@ -0,0 +1,4 @@
|
||||
set noparent
|
||||
rogerta@chromium.org
|
||||
gwilson@chromium.org
|
||||
thakis@chromium.org
|
15
rlz/lib/assert.cc
Normal file
15
rlz/lib/assert.cc
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Macros specific to the RLZ library.
|
||||
|
||||
#include "rlz/lib/assert.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
#ifdef MUTE_EXPECTED_ASSERTS
|
||||
std::string expected_assertion_;
|
||||
#endif
|
||||
|
||||
} // namespace rlz_lib
|
53
rlz/lib/assert.h
Normal file
53
rlz/lib/assert.h
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Macros specific to the RLZ library.
|
||||
|
||||
#ifndef RLZ_LIB_ASSERT_H_
|
||||
#define RLZ_LIB_ASSERT_H_
|
||||
|
||||
#include <string>
|
||||
#include "base/logging.h"
|
||||
|
||||
// An assertion macro.
|
||||
// Can mute expected assertions in debug mode.
|
||||
|
||||
#ifndef ASSERT_STRING
|
||||
#ifndef MUTE_EXPECTED_ASSERTS
|
||||
#define ASSERT_STRING(expr) LOG_IF(FATAL, false) << (expr)
|
||||
#else
|
||||
#define ASSERT_STRING(expr) \
|
||||
do { \
|
||||
std::string expr_string(expr); \
|
||||
if (rlz_lib::expected_assertion_ != expr_string) { \
|
||||
LOG_IF(FATAL, false) << (expr); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef VERIFY
|
||||
#ifdef _DEBUG
|
||||
#define VERIFY(expr) LOG_IF(FATAL, !(expr)) << #expr
|
||||
#else
|
||||
#define VERIFY(expr) (void)(expr)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
#ifdef MUTE_EXPECTED_ASSERTS
|
||||
extern std::string expected_assertion_;
|
||||
#endif
|
||||
|
||||
inline void SetExpectedAssertion(const char* s) {
|
||||
#ifdef MUTE_EXPECTED_ASSERTS
|
||||
expected_assertion_ = s;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // rlz_lib
|
||||
|
||||
#endif // RLZ_LIB_ASSERT_H_
|
17
rlz/lib/crc32.h
Normal file
17
rlz/lib/crc32.h
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// A wrapper around ZLib's CRC function.
|
||||
|
||||
#ifndef RLZ_LIB_CRC32_H_
|
||||
#define RLZ_LIB_CRC32_H_
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
int Crc32(const unsigned char* buf, int length);
|
||||
bool Crc32(const char* text, int* crc);
|
||||
|
||||
} // namespace rlz_lib
|
||||
|
||||
#endif // RLZ_LIB_CRC32_H_
|
52
rlz/lib/crc32_unittest.cc
Normal file
52
rlz/lib/crc32_unittest.cc
Normal file
@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// A test for ZLib's checksum function.
|
||||
|
||||
#include "rlz/lib/crc32.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
TEST(Crc32Unittest, ByteTest) {
|
||||
struct {
|
||||
const char* data;
|
||||
int len;
|
||||
// Externally calculated at http://crc32-checksum.waraxe.us/
|
||||
int crc;
|
||||
} kData[] = {
|
||||
{"Hello" , 5, 0xF7D18982},
|
||||
{"Google" , 6, 0x62B0F067},
|
||||
{"" , 0, 0x0},
|
||||
{"One more string.", 16, 0x0CA14970},
|
||||
{NULL , 0, 0x0},
|
||||
};
|
||||
|
||||
for (int i = 0; kData[i].data; i++)
|
||||
EXPECT_EQ(kData[i].crc,
|
||||
rlz_lib::Crc32(reinterpret_cast<const unsigned char*>(kData[i].data),
|
||||
kData[i].len));
|
||||
}
|
||||
|
||||
TEST(Crc32Unittest, CharTest) {
|
||||
struct {
|
||||
const char* data;
|
||||
// Externally calculated at http://crc32-checksum.waraxe.us/
|
||||
int crc;
|
||||
} kData[] = {
|
||||
{"Hello" , 0xF7D18982},
|
||||
{"Google" , 0x62B0F067},
|
||||
{"" , 0x0},
|
||||
{"One more string.", 0x0CA14970},
|
||||
{"Google\r\n" , 0x83A3E860},
|
||||
{NULL , 0x0},
|
||||
};
|
||||
|
||||
int crc;
|
||||
for (int i = 0; kData[i].data; i++) {
|
||||
EXPECT_TRUE(rlz_lib::Crc32(kData[i].data, &crc));
|
||||
EXPECT_EQ(kData[i].crc, crc);
|
||||
}
|
||||
}
|
36
rlz/lib/crc32_wrapper.cc
Normal file
36
rlz/lib/crc32_wrapper.cc
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// A wrapper around ZLib's CRC functions to put them in the rlz_lib namespace
|
||||
// and use our types.
|
||||
|
||||
#include "rlz/lib/assert.h"
|
||||
#include "rlz/lib/crc32.h"
|
||||
#include "rlz/lib/string_utils.h"
|
||||
#include "third_party/zlib/zlib.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
int Crc32(const unsigned char* buf, int length) {
|
||||
return crc32(0L, buf, length);
|
||||
}
|
||||
|
||||
bool Crc32(const char* text, int* crc) {
|
||||
if (!crc) {
|
||||
ASSERT_STRING("Crc32: crc is NULL.");
|
||||
return false;
|
||||
}
|
||||
|
||||
*crc = 0;
|
||||
for (int i = 0; text[i]; i++) {
|
||||
if (!IsAscii(text[i]))
|
||||
return false;
|
||||
|
||||
*crc = crc32(*crc, reinterpret_cast<const unsigned char*>(text + i), 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rlz_lib
|
90
rlz/lib/crc8.cc
Normal file
90
rlz/lib/crc8.cc
Normal file
@ -0,0 +1,90 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "rlz/lib/crc8.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// The CRC lookup table used for ATM HES (Polynomial = 0x07).
|
||||
// These are 256 unique 8-bit values.
|
||||
const unsigned char kCrcTable[256] = {
|
||||
0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
|
||||
0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
|
||||
0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
|
||||
0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
|
||||
0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
|
||||
0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
|
||||
0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
|
||||
0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
|
||||
0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
|
||||
0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
|
||||
0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
|
||||
0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
|
||||
0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
|
||||
0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
|
||||
0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
|
||||
0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
|
||||
0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
|
||||
0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
|
||||
0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
|
||||
0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
|
||||
0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
|
||||
0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
|
||||
0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
|
||||
0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
|
||||
0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
|
||||
0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
|
||||
0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
|
||||
0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
|
||||
0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
|
||||
0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
|
||||
0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
|
||||
0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
|
||||
};
|
||||
|
||||
} // namespace anonymous
|
||||
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
bool Crc8::Generate(const unsigned char *data, int length,
|
||||
unsigned char* check_sum) {
|
||||
if (!check_sum)
|
||||
return false;
|
||||
|
||||
*check_sum = 0;
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
// The inital and final constants are as used in the ATM HEC.
|
||||
static const unsigned char kInitial = 0x00;
|
||||
static const unsigned char kFinal = 0x55;
|
||||
unsigned char crc = kInitial;
|
||||
for (int i = 0; i < length; ++i) {
|
||||
crc = kCrcTable[(data[i] ^ crc) & 0xFFU];
|
||||
}
|
||||
|
||||
*check_sum = crc ^ kFinal;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Crc8::Verify(const unsigned char* data, int length,
|
||||
unsigned char check_sum, bool* matches) {
|
||||
if (!matches)
|
||||
return false;
|
||||
|
||||
*matches = false;
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
unsigned char calculated_crc;
|
||||
if (!Generate(data, length, &calculated_crc))
|
||||
return false;
|
||||
|
||||
*matches = check_sum == calculated_crc;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rlz_lib
|
24
rlz/lib/crc8.h
Normal file
24
rlz/lib/crc8.h
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Crc8 utility functions.
|
||||
|
||||
#ifndef RLZ_LIB_CRC8_H_
|
||||
#define RLZ_LIB_CRC8_H_
|
||||
|
||||
namespace rlz_lib {
|
||||
// CRC-8 methods:
|
||||
class Crc8 {
|
||||
public:
|
||||
static bool Generate(const unsigned char* data,
|
||||
int length,
|
||||
unsigned char* check_sum);
|
||||
static bool Verify(const unsigned char* data,
|
||||
int length,
|
||||
unsigned char checksum,
|
||||
bool * matches);
|
||||
};
|
||||
}; // namespace rlz_lib
|
||||
|
||||
#endif // RLZ_LIB_CRC8_H_
|
51
rlz/lib/crc8_unittest.cc
Normal file
51
rlz/lib/crc8_unittest.cc
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Uniitest for data encryption functions.
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
#include "rlz/lib/crc8.h"
|
||||
|
||||
TEST(Crc8Unittest, TestCrc8) {
|
||||
struct Data {
|
||||
char string[10];
|
||||
// Externally calculated checksums use
|
||||
// http://www.zorc.breitbandkatze.de/crc.html
|
||||
// with the ATM HEC paramters:
|
||||
// CRC-8, Polynomial 0x07, Initial value 0x00, Final XOR value 0x55
|
||||
// (direct, don't reverse data byes, don't reverse CRC before final XOR)
|
||||
unsigned char external_crc;
|
||||
int random_byte;
|
||||
unsigned char corrupt_value;
|
||||
} data[] = {
|
||||
{"Google", 0x01, 2, 0x53},
|
||||
{"GOOGLE", 0xA6, 4, 0x11},
|
||||
{"My CRC 8!", 0xDC, 0, 0x50},
|
||||
};
|
||||
|
||||
unsigned char* bytes;
|
||||
unsigned char crc;
|
||||
bool matches;
|
||||
int length;
|
||||
for (size_t i = 0; i < sizeof(data) / sizeof(data[0]); ++i) {
|
||||
bytes = reinterpret_cast<unsigned char*>(data[i].string);
|
||||
crc = 0;
|
||||
matches = false;
|
||||
length = strlen(data[i].string);
|
||||
|
||||
// Calculate CRC and compare against external value.
|
||||
rlz_lib::Crc8::Generate(bytes, length, &crc);
|
||||
EXPECT_TRUE(crc == data[i].external_crc);
|
||||
rlz_lib::Crc8::Verify(bytes, length, crc, &matches);
|
||||
EXPECT_TRUE(matches);
|
||||
|
||||
// Corrupt string and see if CRC still matches.
|
||||
data[i].string[data[i].random_byte] = data[i].corrupt_value;
|
||||
rlz_lib::Crc8::Verify(bytes, length, crc, &matches);
|
||||
EXPECT_FALSE(matches);
|
||||
}
|
||||
}
|
354
rlz/lib/financial_ping.cc
Normal file
354
rlz/lib/financial_ping.cc
Normal file
@ -0,0 +1,354 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Library functions related to the Financial Server ping.
|
||||
|
||||
#include "rlz/lib/financial_ping.h"
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/string_util.h"
|
||||
#include "base/stringprintf.h"
|
||||
#include "base/utf_string_conversions.h"
|
||||
#include "rlz/lib/assert.h"
|
||||
#include "rlz/lib/lib_values.h"
|
||||
#include "rlz/lib/machine_id.h"
|
||||
#include "rlz/lib/rlz_lib.h"
|
||||
#include "rlz/lib/rlz_value_store.h"
|
||||
#include "rlz/lib/string_utils.h"
|
||||
|
||||
#if !defined(OS_WIN)
|
||||
#include "base/time.h"
|
||||
#endif
|
||||
|
||||
#if defined(RLZ_NETWORK_IMPLEMENTATION_WIN_INET)
|
||||
|
||||
#include <windows.h>
|
||||
#include <wininet.h>
|
||||
|
||||
namespace {
|
||||
|
||||
class InternetHandle {
|
||||
public:
|
||||
InternetHandle(HINTERNET handle) { handle_ = handle; }
|
||||
~InternetHandle() { if (handle_) InternetCloseHandle(handle_); }
|
||||
operator HINTERNET() const { return handle_; }
|
||||
bool operator!() const { return (handle_ == NULL); }
|
||||
|
||||
private:
|
||||
HINTERNET handle_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#else
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "base/time.h"
|
||||
#include "googleurl/src/gurl.h"
|
||||
#include "net/base/load_flags.h"
|
||||
#include "net/url_request/url_fetcher.h"
|
||||
#include "net/url_request/url_fetcher_delegate.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
// Returns the time relative to a fixed point in the past in multiples of
|
||||
// 100 ns stepts. The point in the past is arbitrary but can't change, as the
|
||||
// result of this value is stored on disk.
|
||||
int64 GetSystemTimeAsInt64() {
|
||||
#if defined(OS_WIN)
|
||||
FILETIME now_as_file_time;
|
||||
// Relative to Jan 1, 1601 (UTC).
|
||||
GetSystemTimeAsFileTime(&now_as_file_time);
|
||||
|
||||
LARGE_INTEGER integer;
|
||||
integer.HighPart = now_as_file_time.dwHighDateTime;
|
||||
integer.LowPart = now_as_file_time.dwLowDateTime;
|
||||
return integer.QuadPart;
|
||||
#else
|
||||
// Seconds since epoch (Jan 1, 1970).
|
||||
double now_seconds = base::Time::Now().ToDoubleT();
|
||||
return static_cast<int64>(now_seconds * 1000 * 1000 * 10);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
bool FinancialPing::FormRequest(Product product,
|
||||
const AccessPoint* access_points, const char* product_signature,
|
||||
const char* product_brand, const char* product_id,
|
||||
const char* product_lang, bool exclude_machine_id,
|
||||
std::string* request) {
|
||||
if (!request) {
|
||||
ASSERT_STRING("FinancialPing::FormRequest: request is NULL");
|
||||
return false;
|
||||
}
|
||||
|
||||
request->clear();
|
||||
|
||||
ScopedRlzValueStoreLock lock;
|
||||
RlzValueStore* store = lock.GetStore();
|
||||
if (!store || !store->HasAccess(RlzValueStore::kReadAccess))
|
||||
return false;
|
||||
|
||||
if (!access_points) {
|
||||
ASSERT_STRING("FinancialPing::FormRequest: access_points is NULL");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!product_signature) {
|
||||
ASSERT_STRING("FinancialPing::FormRequest: product_signature is NULL");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SupplementaryBranding::GetBrand().empty()) {
|
||||
if (SupplementaryBranding::GetBrand() != product_brand) {
|
||||
ASSERT_STRING("FinancialPing::FormRequest: supplementary branding bad");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
base::StringAppendF(request, "%s?", kFinancialPingPath);
|
||||
|
||||
// Add the signature, brand, product id and language.
|
||||
base::StringAppendF(request, "%s=%s", kProductSignatureCgiVariable,
|
||||
product_signature);
|
||||
if (product_brand)
|
||||
base::StringAppendF(request, "&%s=%s", kProductBrandCgiVariable,
|
||||
product_brand);
|
||||
|
||||
if (product_id)
|
||||
base::StringAppendF(request, "&%s=%s", kProductIdCgiVariable, product_id);
|
||||
|
||||
if (product_lang)
|
||||
base::StringAppendF(request, "&%s=%s", kProductLanguageCgiVariable,
|
||||
product_lang);
|
||||
|
||||
// Add the product events.
|
||||
char cgi[kMaxCgiLength + 1];
|
||||
cgi[0] = 0;
|
||||
bool has_events = GetProductEventsAsCgi(product, cgi, arraysize(cgi));
|
||||
if (has_events)
|
||||
base::StringAppendF(request, "&%s", cgi);
|
||||
|
||||
// If we don't have any events, we should ping all the AP's on the system
|
||||
// that we know about and have a current RLZ value, even if they are not
|
||||
// used by this product.
|
||||
AccessPoint all_points[LAST_ACCESS_POINT];
|
||||
if (!has_events) {
|
||||
char rlz[kMaxRlzLength + 1];
|
||||
int idx = 0;
|
||||
for (int ap = NO_ACCESS_POINT + 1; ap < LAST_ACCESS_POINT; ap++) {
|
||||
rlz[0] = 0;
|
||||
AccessPoint point = static_cast<AccessPoint>(ap);
|
||||
if (GetAccessPointRlz(point, rlz, arraysize(rlz)) &&
|
||||
rlz[0] != '\0')
|
||||
all_points[idx++] = point;
|
||||
}
|
||||
all_points[idx] = NO_ACCESS_POINT;
|
||||
}
|
||||
|
||||
// Add the RLZ's and the DCC if needed. This is the same as get PingParams.
|
||||
// This will also include the RLZ Exchange Protocol CGI Argument.
|
||||
cgi[0] = 0;
|
||||
if (GetPingParams(product, has_events ? access_points : all_points,
|
||||
cgi, arraysize(cgi)))
|
||||
base::StringAppendF(request, "&%s", cgi);
|
||||
|
||||
if (has_events && !exclude_machine_id) {
|
||||
std::string machine_id;
|
||||
if (GetMachineId(&machine_id)) {
|
||||
base::StringAppendF(request, "&%s=%s", kMachineIdCgiVariable,
|
||||
machine_id.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(RLZ_NETWORK_IMPLEMENTATION_CHROME_NET)
|
||||
// The URLRequestContextGetter used by FinancialPing::PingServer().
|
||||
net::URLRequestContextGetter* g_context;
|
||||
|
||||
bool FinancialPing::SetURLRequestContext(
|
||||
net::URLRequestContextGetter* context) {
|
||||
ScopedRlzValueStoreLock lock;
|
||||
RlzValueStore* store = lock.GetStore();
|
||||
if (!store)
|
||||
return false;
|
||||
|
||||
g_context = context;
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class FinancialPingUrlFetcherDelegate : public net::URLFetcherDelegate {
|
||||
public:
|
||||
FinancialPingUrlFetcherDelegate(MessageLoop* loop) : loop_(loop) { }
|
||||
virtual void OnURLFetchComplete(const net::URLFetcher* source);
|
||||
private:
|
||||
MessageLoop* loop_;
|
||||
};
|
||||
|
||||
void FinancialPingUrlFetcherDelegate::OnURLFetchComplete(
|
||||
const net::URLFetcher* source) {
|
||||
loop_->Quit();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
||||
bool FinancialPing::PingServer(const char* request, std::string* response) {
|
||||
if (!response)
|
||||
return false;
|
||||
|
||||
response->clear();
|
||||
|
||||
#if defined(RLZ_NETWORK_IMPLEMENTATION_WIN_INET)
|
||||
// Initialize WinInet.
|
||||
InternetHandle inet_handle = InternetOpenA(kFinancialPingUserAgent,
|
||||
INTERNET_OPEN_TYPE_PRECONFIG,
|
||||
NULL, NULL, 0);
|
||||
if (!inet_handle)
|
||||
return false;
|
||||
|
||||
// Open network connection.
|
||||
InternetHandle connection_handle = InternetConnectA(inet_handle,
|
||||
kFinancialServer, kFinancialPort, "", "", INTERNET_SERVICE_HTTP,
|
||||
INTERNET_FLAG_NO_CACHE_WRITE, 0);
|
||||
if (!connection_handle)
|
||||
return false;
|
||||
|
||||
// Prepare the HTTP request.
|
||||
InternetHandle http_handle = HttpOpenRequestA(connection_handle,
|
||||
"GET", request, NULL, NULL, kFinancialPingResponseObjects,
|
||||
INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES, NULL);
|
||||
if (!http_handle)
|
||||
return false;
|
||||
|
||||
// Timeouts are probably:
|
||||
// INTERNET_OPTION_SEND_TIMEOUT, INTERNET_OPTION_RECEIVE_TIMEOUT
|
||||
|
||||
// Send the HTTP request. Note: Fails if user is working in off-line mode.
|
||||
if (!HttpSendRequest(http_handle, NULL, 0, NULL, 0))
|
||||
return false;
|
||||
|
||||
// Check the response status.
|
||||
DWORD status;
|
||||
DWORD status_size = sizeof(status);
|
||||
if (!HttpQueryInfo(http_handle, HTTP_QUERY_STATUS_CODE |
|
||||
HTTP_QUERY_FLAG_NUMBER, &status, &status_size, NULL) ||
|
||||
200 != status)
|
||||
return false;
|
||||
|
||||
// Get the response text.
|
||||
scoped_array<char> buffer(new char[kMaxPingResponseLength]);
|
||||
if (buffer.get() == NULL)
|
||||
return false;
|
||||
|
||||
DWORD bytes_read = 0;
|
||||
while (InternetReadFile(http_handle, buffer.get(), kMaxPingResponseLength,
|
||||
&bytes_read) && bytes_read > 0) {
|
||||
response->append(buffer.get(), bytes_read);
|
||||
bytes_read = 0;
|
||||
};
|
||||
|
||||
return true;
|
||||
#else
|
||||
// Run a blocking event loop to match the win inet implementation.
|
||||
MessageLoop loop;
|
||||
FinancialPingUrlFetcherDelegate delegate(&loop);
|
||||
|
||||
std::string url = base::StringPrintf("http://%s:%d%s",
|
||||
kFinancialServer, kFinancialPort,
|
||||
request);
|
||||
|
||||
scoped_ptr<net::URLFetcher> fetcher(net::URLFetcher::Create(
|
||||
GURL(url), net::URLFetcher::GET, &delegate));
|
||||
|
||||
fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE |
|
||||
net::LOAD_DO_NOT_SEND_AUTH_DATA |
|
||||
net::LOAD_DO_NOT_PROMPT_FOR_LOGIN |
|
||||
net::LOAD_DO_NOT_SEND_COOKIES |
|
||||
net::LOAD_DO_NOT_SAVE_COOKIES);
|
||||
|
||||
// Ensure rlz_lib::SetURLRequestContext() has been called before sending
|
||||
// pings.
|
||||
CHECK(g_context);
|
||||
fetcher->SetRequestContext(g_context);
|
||||
|
||||
const base::TimeDelta kTimeout = base::TimeDelta::FromMinutes(5);
|
||||
loop.PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&net::URLFetcher::Start, base::Unretained(fetcher.get())));
|
||||
loop.PostNonNestableDelayedTask(
|
||||
FROM_HERE, MessageLoop::QuitClosure(), kTimeout);
|
||||
|
||||
loop.Run();
|
||||
|
||||
if (fetcher->GetResponseCode() != 200)
|
||||
return false;
|
||||
|
||||
return fetcher->GetResponseAsString(response);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FinancialPing::IsPingTime(Product product, bool no_delay) {
|
||||
ScopedRlzValueStoreLock lock;
|
||||
RlzValueStore* store = lock.GetStore();
|
||||
if (!store || !store->HasAccess(RlzValueStore::kReadAccess))
|
||||
return false;
|
||||
|
||||
int64 last_ping = 0;
|
||||
if (!store->ReadPingTime(product, &last_ping))
|
||||
return true;
|
||||
|
||||
uint64 now = GetSystemTimeAsInt64();
|
||||
int64 interval = now - last_ping;
|
||||
|
||||
// If interval is negative, clock was probably reset. So ping.
|
||||
if (interval < 0)
|
||||
return true;
|
||||
|
||||
// Check if this product has any unreported events.
|
||||
char cgi[kMaxCgiLength + 1];
|
||||
cgi[0] = 0;
|
||||
bool has_events = GetProductEventsAsCgi(product, cgi, arraysize(cgi));
|
||||
if (no_delay && has_events)
|
||||
return true;
|
||||
|
||||
return interval >= (has_events ? kEventsPingInterval : kNoEventsPingInterval);
|
||||
}
|
||||
|
||||
|
||||
bool FinancialPing::UpdateLastPingTime(Product product) {
|
||||
ScopedRlzValueStoreLock lock;
|
||||
RlzValueStore* store = lock.GetStore();
|
||||
if (!store || !store->HasAccess(RlzValueStore::kWriteAccess))
|
||||
return false;
|
||||
|
||||
uint64 now = GetSystemTimeAsInt64();
|
||||
return store->WritePingTime(product, now);
|
||||
}
|
||||
|
||||
|
||||
bool FinancialPing::ClearLastPingTime(Product product) {
|
||||
ScopedRlzValueStoreLock lock;
|
||||
RlzValueStore* store = lock.GetStore();
|
||||
if (!store || !store->HasAccess(RlzValueStore::kWriteAccess))
|
||||
return false;
|
||||
return store->ClearPingTime(product);
|
||||
}
|
||||
|
||||
} // namespace
|
64
rlz/lib/financial_ping.h
Normal file
64
rlz/lib/financial_ping.h
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Library functions related to the Financial Server ping.
|
||||
|
||||
#ifndef RLZ_LIB_FINANCIAL_PING_H_
|
||||
#define RLZ_LIB_FINANCIAL_PING_H_
|
||||
|
||||
#include <string>
|
||||
#include "rlz/lib/rlz_enums.h"
|
||||
|
||||
#if defined(RLZ_NETWORK_IMPLEMENTATION_CHROME_NET)
|
||||
namespace net {
|
||||
class URLRequestContextGetter;
|
||||
} // namespace net
|
||||
#endif
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
class FinancialPing {
|
||||
public:
|
||||
// Form the HTTP request to send to the PSO server.
|
||||
// Will look something like:
|
||||
// /pso/ping?as=swg&brand=GGLD&id=124&hl=en&
|
||||
// events=I7S&rep=1&rlz=I7:val,W1:&dcc=dval
|
||||
static bool FormRequest(Product product, const AccessPoint* access_points,
|
||||
const char* product_signature,
|
||||
const char* product_brand, const char* product_id,
|
||||
const char* product_lang, bool exclude_machine_id,
|
||||
std::string* request);
|
||||
|
||||
// Returns whether the time is right to send a ping.
|
||||
// If no_delay is true, this should always ping if there are events,
|
||||
// or one week has passed since last_ping when there are no new events.
|
||||
// If no_delay is false, this should ping if current time < last_ping time
|
||||
// (case of time reset) or if one day has passed since last_ping and there
|
||||
// are events, or one week has passed since last_ping when there are
|
||||
// no new events.
|
||||
static bool IsPingTime(Product product, bool no_delay);
|
||||
|
||||
// Set the last ping time to be now. Writes to RlzValueStore.
|
||||
static bool UpdateLastPingTime(Product product);
|
||||
|
||||
// Clear the last ping time - should be called on uninstall.
|
||||
// Writes to RlzValueStore.
|
||||
static bool ClearLastPingTime(Product product);
|
||||
|
||||
// Ping the financial server with request. Writes to RlzValueStore.
|
||||
static bool PingServer(const char* request, std::string* response);
|
||||
|
||||
#if defined(RLZ_NETWORK_IMPLEMENTATION_CHROME_NET)
|
||||
static bool SetURLRequestContext(net::URLRequestContextGetter* context);
|
||||
#endif
|
||||
|
||||
private:
|
||||
FinancialPing() {}
|
||||
~FinancialPing() {}
|
||||
};
|
||||
|
||||
} // namespace rlz_lib
|
||||
|
||||
|
||||
#endif // RLZ_LIB_FINANCIAL_PING_H_
|
293
rlz/lib/financial_ping_test.cc
Normal file
293
rlz/lib/financial_ping_test.cc
Normal file
@ -0,0 +1,293 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// A test application for the FinancialPing class.
|
||||
//
|
||||
// These tests should not be executed on the build server:
|
||||
// - They modify machine state (registry).
|
||||
//
|
||||
// These tests require write access to HKCU and HKLM.
|
||||
//
|
||||
// The "GGLA" brand is used to test the normal code flow of the code, and the
|
||||
// "TEST" brand is used to test the supplementary brand code code flow. In one
|
||||
// case below, the brand "GOOG" is used because the code wants to use a brand
|
||||
// that is neither of the two mentioned above.
|
||||
|
||||
#include "rlz/lib/financial_ping.h"
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/string_util.h"
|
||||
#include "base/stringprintf.h"
|
||||
#include "base/utf_string_conversions.h"
|
||||
#include "rlz/lib/lib_values.h"
|
||||
#include "rlz/lib/machine_id.h"
|
||||
#include "rlz/lib/rlz_lib.h"
|
||||
#include "rlz/lib/rlz_value_store.h"
|
||||
#include "rlz/test/rlz_test_helpers.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "rlz/win/lib/machine_deal.h"
|
||||
#else
|
||||
#include "base/time.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
// Must match the implementation in file_time.cc.
|
||||
int64 GetSystemTimeAsInt64() {
|
||||
#if defined(OS_WIN)
|
||||
FILETIME now_as_file_time;
|
||||
GetSystemTimeAsFileTime(&now_as_file_time);
|
||||
LARGE_INTEGER integer;
|
||||
integer.HighPart = now_as_file_time.dwHighDateTime;
|
||||
integer.LowPart = now_as_file_time.dwLowDateTime;
|
||||
return integer.QuadPart;
|
||||
#else
|
||||
double now_seconds = base::Time::Now().ToDoubleT();
|
||||
return static_cast<int64>(now_seconds * 1000 * 1000 * 10);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Ping times in 100-nanosecond intervals.
|
||||
const int64 k1MinuteInterval = 60LL * 10000000LL; // 1 minute
|
||||
|
||||
} // namespace anonymous
|
||||
|
||||
class FinancialPingTest : public RlzLibTestBase {
|
||||
};
|
||||
|
||||
TEST_F(FinancialPingTest, FormRequest) {
|
||||
std::string brand_string = rlz_lib::SupplementaryBranding::GetBrand();
|
||||
const char* brand = brand_string.empty() ? "GGLA" : brand_string.c_str();
|
||||
|
||||
#if defined(OS_WIN)
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::Set("dcc_value"));
|
||||
#define DCC_PARAM "&dcc=dcc_value"
|
||||
#else
|
||||
#define DCC_PARAM ""
|
||||
#endif
|
||||
|
||||
EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX,
|
||||
"TbRlzValue"));
|
||||
|
||||
EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL));
|
||||
|
||||
rlz_lib::AccessPoint points[] =
|
||||
{rlz_lib::IETB_SEARCH_BOX, rlz_lib::NO_ACCESS_POINT,
|
||||
rlz_lib::NO_ACCESS_POINT};
|
||||
|
||||
std::string machine_id;
|
||||
bool got_machine_id = rlz_lib::GetMachineId(&machine_id);
|
||||
|
||||
std::string request;
|
||||
EXPECT_TRUE(rlz_lib::FinancialPing::FormRequest(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
points, "swg", brand, NULL, "en", false, &request));
|
||||
std::string expected_response;
|
||||
base::StringAppendF(&expected_response,
|
||||
"/tools/pso/ping?as=swg&brand=%s&hl=en&"
|
||||
"events=I7S,W1I&rep=2&rlz=T4:TbRlzValue" DCC_PARAM
|
||||
, brand);
|
||||
|
||||
if (got_machine_id)
|
||||
base::StringAppendF(&expected_response, "&id=%s", machine_id.c_str());
|
||||
EXPECT_EQ(expected_response, request);
|
||||
|
||||
EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, ""));
|
||||
EXPECT_TRUE(rlz_lib::FinancialPing::FormRequest(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
points, "swg", brand, "IdOk2", NULL, false, &request));
|
||||
expected_response.clear();
|
||||
base::StringAppendF(&expected_response,
|
||||
"/tools/pso/ping?as=swg&brand=%s&pid=IdOk2&"
|
||||
"events=I7S,W1I&rep=2&rlz=T4:" DCC_PARAM, brand);
|
||||
|
||||
if (got_machine_id)
|
||||
base::StringAppendF(&expected_response, "&id=%s", machine_id.c_str());
|
||||
EXPECT_EQ(expected_response, request);
|
||||
|
||||
EXPECT_TRUE(rlz_lib::FinancialPing::FormRequest(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
points, "swg", brand, "IdOk", NULL, true, &request));
|
||||
expected_response.clear();
|
||||
base::StringAppendF(&expected_response,
|
||||
"/tools/pso/ping?as=swg&brand=%s&pid=IdOk&"
|
||||
"events=I7S,W1I&rep=2&rlz=T4:" DCC_PARAM, brand);
|
||||
EXPECT_EQ(expected_response, request);
|
||||
|
||||
EXPECT_TRUE(rlz_lib::FinancialPing::FormRequest(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
points, "swg", brand, NULL, NULL, true, &request));
|
||||
expected_response.clear();
|
||||
base::StringAppendF(&expected_response,
|
||||
"/tools/pso/ping?as=swg&brand=%s&events=I7S,W1I&rep=2"
|
||||
"&rlz=T4:" DCC_PARAM, brand);
|
||||
EXPECT_EQ(expected_response, request);
|
||||
|
||||
|
||||
// Clear all events.
|
||||
EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER));
|
||||
|
||||
// Clear all RLZs.
|
||||
char rlz[rlz_lib::kMaxRlzLength + 1];
|
||||
for (int ap = rlz_lib::NO_ACCESS_POINT + 1;
|
||||
ap < rlz_lib::LAST_ACCESS_POINT; ap++) {
|
||||
rlz[0] = 0;
|
||||
rlz_lib::AccessPoint point = static_cast<rlz_lib::AccessPoint>(ap);
|
||||
if (rlz_lib::GetAccessPointRlz(point, rlz, arraysize(rlz)) && rlz[0]) {
|
||||
rlz_lib::SetAccessPointRlz(point, "");
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX,
|
||||
"TbRlzValue"));
|
||||
EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::QUICK_SEARCH_BOX,
|
||||
"QsbRlzValue"));
|
||||
EXPECT_TRUE(rlz_lib::FinancialPing::FormRequest(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
points, "swg", brand, NULL, NULL, false, &request));
|
||||
expected_response.clear();
|
||||
base::StringAppendF(&expected_response,
|
||||
"/tools/pso/ping?as=swg&brand=%s&rep=2&rlz=T4:TbRlzValue,"
|
||||
"Q1:QsbRlzValue" DCC_PARAM, brand);
|
||||
EXPECT_STREQ(expected_response.c_str(), request.c_str());
|
||||
|
||||
if (!GetAccessPointRlz(rlz_lib::IE_HOME_PAGE, rlz, arraysize(rlz))) {
|
||||
points[2] = rlz_lib::IE_HOME_PAGE;
|
||||
EXPECT_TRUE(rlz_lib::FinancialPing::FormRequest(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
points, "swg", brand, "MyId", "en-US", true, &request));
|
||||
expected_response.clear();
|
||||
base::StringAppendF(&expected_response,
|
||||
"/tools/pso/ping?as=swg&brand=%s&hl=en-US&pid=MyId&rep=2"
|
||||
"&rlz=T4:TbRlzValue,Q1:QsbRlzValue" DCC_PARAM, brand);
|
||||
EXPECT_STREQ(expected_response.c_str(), request.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(FinancialPingTest, FormRequestBadBrand) {
|
||||
rlz_lib::AccessPoint points[] =
|
||||
{rlz_lib::IETB_SEARCH_BOX, rlz_lib::NO_ACCESS_POINT,
|
||||
rlz_lib::NO_ACCESS_POINT};
|
||||
|
||||
std::string request;
|
||||
bool ok = rlz_lib::FinancialPing::FormRequest(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
points, "swg", "GOOG", NULL, "en", false, &request);
|
||||
EXPECT_EQ(rlz_lib::SupplementaryBranding::GetBrand().empty(), ok);
|
||||
}
|
||||
|
||||
|
||||
static void SetLastPingTime(int64 time, rlz_lib::Product product) {
|
||||
rlz_lib::ScopedRlzValueStoreLock lock;
|
||||
rlz_lib::RlzValueStore* store = lock.GetStore();
|
||||
ASSERT_TRUE(store);
|
||||
ASSERT_TRUE(store->HasAccess(rlz_lib::RlzValueStore::kWriteAccess));
|
||||
store->WritePingTime(product, time);
|
||||
}
|
||||
|
||||
TEST_F(FinancialPingTest, IsPingTime) {
|
||||
int64 now = GetSystemTimeAsInt64();
|
||||
int64 last_ping = now - rlz_lib::kEventsPingInterval - k1MinuteInterval;
|
||||
SetLastPingTime(last_ping, rlz_lib::TOOLBAR_NOTIFIER);
|
||||
|
||||
// No events, last ping just over a day ago.
|
||||
EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER));
|
||||
EXPECT_FALSE(rlz_lib::FinancialPing::IsPingTime(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
false));
|
||||
|
||||
// Has events, last ping just over a day ago.
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::FinancialPing::IsPingTime(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
false));
|
||||
|
||||
// Has events, last ping just under a day ago.
|
||||
last_ping = now - rlz_lib::kEventsPingInterval + k1MinuteInterval;
|
||||
SetLastPingTime(last_ping, rlz_lib::TOOLBAR_NOTIFIER);
|
||||
EXPECT_FALSE(rlz_lib::FinancialPing::IsPingTime(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
false));
|
||||
|
||||
EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER));
|
||||
|
||||
// No events, last ping just under a week ago.
|
||||
last_ping = now - rlz_lib::kNoEventsPingInterval + k1MinuteInterval;
|
||||
SetLastPingTime(last_ping, rlz_lib::TOOLBAR_NOTIFIER);
|
||||
EXPECT_FALSE(rlz_lib::FinancialPing::IsPingTime(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
false));
|
||||
|
||||
// No events, last ping just over a week ago.
|
||||
last_ping = now - rlz_lib::kNoEventsPingInterval - k1MinuteInterval;
|
||||
SetLastPingTime(last_ping, rlz_lib::TOOLBAR_NOTIFIER);
|
||||
EXPECT_TRUE(rlz_lib::FinancialPing::IsPingTime(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
false));
|
||||
|
||||
// Last ping was in future (invalid).
|
||||
last_ping = now + k1MinuteInterval;
|
||||
SetLastPingTime(last_ping, rlz_lib::TOOLBAR_NOTIFIER);
|
||||
EXPECT_TRUE(rlz_lib::FinancialPing::IsPingTime(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
false));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::FinancialPing::IsPingTime(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
false));
|
||||
}
|
||||
|
||||
TEST_F(FinancialPingTest, BrandingIsPingTime) {
|
||||
// Don't run these tests if a supplementary brand is already in place. That
|
||||
// way we can control the branding.
|
||||
if (!rlz_lib::SupplementaryBranding::GetBrand().empty())
|
||||
return;
|
||||
|
||||
int64 now = GetSystemTimeAsInt64();
|
||||
int64 last_ping = now - rlz_lib::kEventsPingInterval - k1MinuteInterval;
|
||||
SetLastPingTime(last_ping, rlz_lib::TOOLBAR_NOTIFIER);
|
||||
|
||||
// Has events, last ping just over a day ago.
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::FinancialPing::IsPingTime(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
false));
|
||||
|
||||
{
|
||||
rlz_lib::SupplementaryBranding branding("TEST");
|
||||
SetLastPingTime(last_ping, rlz_lib::TOOLBAR_NOTIFIER);
|
||||
|
||||
// Has events, last ping just over a day ago.
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::FinancialPing::IsPingTime(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
false));
|
||||
}
|
||||
|
||||
last_ping = now - k1MinuteInterval;
|
||||
SetLastPingTime(last_ping, rlz_lib::TOOLBAR_NOTIFIER);
|
||||
|
||||
EXPECT_FALSE(rlz_lib::FinancialPing::IsPingTime(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
false));
|
||||
|
||||
{
|
||||
rlz_lib::SupplementaryBranding branding("TEST");
|
||||
EXPECT_TRUE(rlz_lib::FinancialPing::IsPingTime(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
false));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(FinancialPingTest, ClearLastPingTime) {
|
||||
int64 now = GetSystemTimeAsInt64();
|
||||
int64 last_ping = now - rlz_lib::kEventsPingInterval + k1MinuteInterval;
|
||||
SetLastPingTime(last_ping, rlz_lib::TOOLBAR_NOTIFIER);
|
||||
|
||||
// Has events, last ping just under a day ago.
|
||||
EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_FALSE(rlz_lib::FinancialPing::IsPingTime(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
false));
|
||||
|
||||
EXPECT_TRUE(rlz_lib::FinancialPing::ClearLastPingTime(
|
||||
rlz_lib::TOOLBAR_NOTIFIER));
|
||||
EXPECT_TRUE(rlz_lib::FinancialPing::IsPingTime(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
false));
|
||||
}
|
208
rlz/lib/lib_values.cc
Normal file
208
rlz/lib/lib_values.cc
Normal file
@ -0,0 +1,208 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Key and value names of the location of the RLZ shared state.
|
||||
|
||||
#include "rlz/lib/lib_values.h"
|
||||
|
||||
#include "base/stringprintf.h"
|
||||
#include "rlz/lib/assert.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
//
|
||||
// Ping information.
|
||||
//
|
||||
|
||||
// rep=2: includes the new stateful events.
|
||||
const char kProtocolCgiArgument[] = "rep=2";
|
||||
|
||||
const char kEventsCgiVariable[] = "events";
|
||||
const char kStatefulEventsCgiVariable[] = "stateful-events";
|
||||
const char kEventsCgiSeparator = ',';
|
||||
|
||||
const char kRlzCgiVariable[] = "rlz";
|
||||
const char kRlzCgiSeparator[] = ",";
|
||||
const char kRlzCgiIndicator[] = ":";
|
||||
|
||||
const char kProductSignatureCgiVariable[] = "as";
|
||||
const char kProductBrandCgiVariable[] = "brand";
|
||||
const char kProductLanguageCgiVariable[] = "hl";
|
||||
const char kProductIdCgiVariable[] = "pid";
|
||||
|
||||
const char kDccCgiVariable[] = "dcc";
|
||||
const char kRlsCgiVariable[] = "rls";
|
||||
const char kMachineIdCgiVariable[] = "id";
|
||||
const char kSetDccResponseVariable[] = "set_dcc";
|
||||
|
||||
//
|
||||
// Financial server information.
|
||||
//
|
||||
|
||||
const char kFinancialPingPath[] = "/tools/pso/ping";
|
||||
const char kFinancialServer[] = "clients1.google.com";
|
||||
const int kFinancialPort = 80;
|
||||
|
||||
// Ping times in 100-nanosecond intervals.
|
||||
const int64 kEventsPingInterval = 24LL * 3600LL * 10000000LL; // 1 day
|
||||
const int64 kNoEventsPingInterval = kEventsPingInterval * 7LL; // 1 week
|
||||
|
||||
const char kFinancialPingUserAgent[] = "Mozilla/4.0 (compatible; Win32)";
|
||||
const char* kFinancialPingResponseObjects[] = { "text/*", NULL };
|
||||
|
||||
//
|
||||
// AccessPoint and Event names.
|
||||
//
|
||||
//
|
||||
|
||||
const char* GetAccessPointName(AccessPoint point) {
|
||||
switch (point) {
|
||||
case NO_ACCESS_POINT: return "";
|
||||
case IE_DEFAULT_SEARCH: return "I7";
|
||||
case IE_HOME_PAGE: return "W1";
|
||||
case IETB_SEARCH_BOX: return "T4";
|
||||
case QUICK_SEARCH_BOX: return "Q1";
|
||||
case GD_DESKBAND: return "D1";
|
||||
case GD_SEARCH_GADGET: return "D2";
|
||||
case GD_WEB_SERVER: return "D3";
|
||||
case GD_OUTLOOK: return "D4";
|
||||
case CHROME_OMNIBOX: return "C1";
|
||||
case CHROME_HOME_PAGE: return "C2";
|
||||
case FFTB2_BOX: return "B2";
|
||||
case FFTB3_BOX: return "B3";
|
||||
case PINYIN_IME_BHO: return "N1";
|
||||
case IGOOGLE_WEBPAGE: return "G1";
|
||||
case MOBILE_IDLE_SCREEN_BLACKBERRY: return "H1";
|
||||
case MOBILE_IDLE_SCREEN_WINMOB: return "H2";
|
||||
case MOBILE_IDLE_SCREEN_SYMBIAN: return "H3";
|
||||
case FF_HOME_PAGE: return "R0";
|
||||
case FF_SEARCH_BOX: return "R1";
|
||||
case IE_BROWSED_PAGE: return "R2";
|
||||
case QSB_WIN_BOX: return "R3";
|
||||
case WEBAPPS_CALENDAR: return "R4";
|
||||
case WEBAPPS_DOCS: return "R5";
|
||||
case WEBAPPS_GMAIL: return "R6";
|
||||
case IETB_LINKDOCTOR: return "R7";
|
||||
case FFTB_LINKDOCTOR: return "R8";
|
||||
case IETB7_SEARCH_BOX: return "T7";
|
||||
case TB8_SEARCH_BOX: return "T8";
|
||||
case CHROME_FRAME: return "C3";
|
||||
case PARTNER_AP_1: return "V1";
|
||||
case PARTNER_AP_2: return "V2";
|
||||
case PARTNER_AP_3: return "V3";
|
||||
case PARTNER_AP_4: return "V4";
|
||||
case PARTNER_AP_5: return "V5";
|
||||
case UNDEFINED_AP_H: return "RH";
|
||||
case UNDEFINED_AP_I: return "RI";
|
||||
case UNDEFINED_AP_J: return "RJ";
|
||||
case UNDEFINED_AP_K: return "RK";
|
||||
case UNDEFINED_AP_L: return "RL";
|
||||
case UNDEFINED_AP_M: return "RM";
|
||||
case UNDEFINED_AP_N: return "RN";
|
||||
case UNDEFINED_AP_O: return "RO";
|
||||
case UNDEFINED_AP_P: return "RP";
|
||||
case UNDEFINED_AP_Q: return "RQ";
|
||||
case UNDEFINED_AP_R: return "RR";
|
||||
case UNDEFINED_AP_S: return "RS";
|
||||
case UNDEFINED_AP_T: return "RT";
|
||||
case UNDEFINED_AP_U: return "RU";
|
||||
case UNDEFINED_AP_V: return "RV";
|
||||
case UNDEFINED_AP_W: return "RW";
|
||||
case UNDEFINED_AP_X: return "RX";
|
||||
case UNDEFINED_AP_Y: return "RY";
|
||||
case UNDEFINED_AP_Z: return "RZ";
|
||||
case PACK_AP0: return "U0";
|
||||
case PACK_AP1: return "U1";
|
||||
case PACK_AP2: return "U2";
|
||||
case PACK_AP3: return "U3";
|
||||
case PACK_AP4: return "U4";
|
||||
case PACK_AP5: return "U5";
|
||||
case PACK_AP6: return "U6";
|
||||
case PACK_AP7: return "U7";
|
||||
case PACK_AP8: return "U8";
|
||||
case PACK_AP9: return "U9";
|
||||
case PACK_AP10: return "UA";
|
||||
case PACK_AP11: return "UB";
|
||||
case PACK_AP12: return "UC";
|
||||
case PACK_AP13: return "UD";
|
||||
case LAST_ACCESS_POINT: ; // Fall through.
|
||||
}
|
||||
|
||||
ASSERT_STRING("GetAccessPointName: Unknown Access Point");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool GetAccessPointFromName(const char* name, AccessPoint* point) {
|
||||
if (!point) {
|
||||
ASSERT_STRING("GetAccessPointFromName: point is NULL");
|
||||
return false;
|
||||
}
|
||||
*point = NO_ACCESS_POINT;
|
||||
if (!name)
|
||||
return false;
|
||||
|
||||
for (int i = NO_ACCESS_POINT; i < LAST_ACCESS_POINT; i++)
|
||||
if (strcmp(name, GetAccessPointName(static_cast<AccessPoint>(i))) == 0) {
|
||||
*point = static_cast<AccessPoint>(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const char* GetEventName(Event event) {
|
||||
switch (event) {
|
||||
case INVALID_EVENT: return "";
|
||||
case INSTALL: return "I";
|
||||
case SET_TO_GOOGLE: return "S";
|
||||
case FIRST_SEARCH: return "F";
|
||||
case REPORT_RLS: return "R";
|
||||
case ACTIVATE: return "A";
|
||||
case LAST_EVENT: ; // Fall through.
|
||||
}
|
||||
|
||||
ASSERT_STRING("GetPointName: Unknown Event");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool GetEventFromName(const char* name, Event* event) {
|
||||
if (!event) {
|
||||
ASSERT_STRING("GetEventFromName: event is NULL");
|
||||
return false;
|
||||
}
|
||||
*event = INVALID_EVENT;
|
||||
if (!name)
|
||||
return false;
|
||||
|
||||
for (int i = INVALID_EVENT; i < LAST_EVENT; i++)
|
||||
if (strcmp(name, GetEventName(static_cast<Event>(i))) == 0) {
|
||||
*event = static_cast<Event>(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* GetProductName(Product product) {
|
||||
switch (product) {
|
||||
case IE_TOOLBAR: return "T";
|
||||
case TOOLBAR_NOTIFIER: return "P";
|
||||
case PACK: return "U";
|
||||
case DESKTOP: return "D";
|
||||
case CHROME: return "C";
|
||||
case FF_TOOLBAR: return "B";
|
||||
case QSB_WIN: return "K";
|
||||
case WEBAPPS: return "W";
|
||||
case PINYIN_IME: return "N";
|
||||
case PARTNER: return "V";
|
||||
}
|
||||
|
||||
ASSERT_STRING("GetProductName: Unknown Product");
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace rlz_lib
|
99
rlz/lib/lib_values.h
Normal file
99
rlz/lib/lib_values.h
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Key and value names of the location of the RLZ shared state.
|
||||
|
||||
#ifndef RLZ_LIB_LIB_VALUES_H_
|
||||
#define RLZ_LIB_LIB_VALUES_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "rlz/lib/rlz_enums.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
//
|
||||
// Ping CGI arguments:
|
||||
//
|
||||
// Events are reported as (without spaces):
|
||||
// kEventsCgiVariable = <AccessPoint1><Event1> kEventsCgiSeparator <P2><E2>...
|
||||
//
|
||||
// Event responses from the server look like:
|
||||
// kEventsCgiVariable : <AccessPoint1><Event1> kEventsCgiSeparator <P2><E2>...
|
||||
//
|
||||
// RLZ's are reported as (without spaces):
|
||||
// kRlzCgiVariable = <AccessPoint> <kRlzCgiIndicator> <RLZ value>
|
||||
// <kRlzCgiSeparator> <AP2><Indicator><V2><Separator> ....
|
||||
//
|
||||
// RLZ responses from the server look like (without spaces):
|
||||
// kRlzCgiVariable<Access Point> : <RLZ value>
|
||||
//
|
||||
// DCC if reported should look like (without spaces):
|
||||
// kDccCgiVariable = <DCC Value>
|
||||
//
|
||||
// RLS if reported should look like (without spaces):
|
||||
// kRlsCgiVariable = <RLS Value>
|
||||
//
|
||||
// Machine ID if reported should look like (without spaces):
|
||||
// kMachineIdCgiVariable = <Machine ID Value>
|
||||
//
|
||||
// A server response setting / confirming the DCC will look like (no spaces):
|
||||
// kDccCgiVariable : <DCC Value>
|
||||
//
|
||||
// Each ping to the server must also contain kProtocolCgiArgument as well.
|
||||
//
|
||||
// Pings may also contain (but not necessarily controlled by this Lib):
|
||||
// - The product signature: kProductSignatureCgiVariable = <signature>
|
||||
// - The product brand: kProductBrandCgiVariable = <brand>
|
||||
// - The product installation ID: kProductIdCgiVariable = <id>
|
||||
extern const char kEventsCgiVariable[];
|
||||
extern const char kStatefulEventsCgiVariable[];
|
||||
extern const char kEventsCgiSeparator;
|
||||
|
||||
extern const char kDccCgiVariable[];
|
||||
extern const char kProtocolCgiArgument[];
|
||||
|
||||
extern const char kProductSignatureCgiVariable[];
|
||||
extern const char kProductBrandCgiVariable[];
|
||||
extern const char kProductLanguageCgiVariable[];
|
||||
extern const char kProductIdCgiVariable[];
|
||||
|
||||
extern const char kRlzCgiVariable[];
|
||||
extern const char kRlzCgiSeparator[];
|
||||
extern const char kRlzCgiIndicator[];
|
||||
|
||||
extern const char kRlsCgiVariable[];
|
||||
extern const char kMachineIdCgiVariable[];
|
||||
extern const char kSetDccResponseVariable[];
|
||||
|
||||
//
|
||||
// Financial ping server information.
|
||||
//
|
||||
|
||||
extern const char kFinancialPingPath[];
|
||||
extern const char kFinancialServer[];
|
||||
|
||||
extern const int kFinancialPort;
|
||||
|
||||
extern const int64 kEventsPingInterval;
|
||||
extern const int64 kNoEventsPingInterval;
|
||||
|
||||
extern const char kFinancialPingUserAgent[];
|
||||
extern const char* kFinancialPingResponseObjects[];
|
||||
|
||||
//
|
||||
// The names for AccessPoints and Events that we use MUST be the same
|
||||
// as those used/understood by the server.
|
||||
//
|
||||
const char* GetAccessPointName(AccessPoint point);
|
||||
bool GetAccessPointFromName(const char* name, AccessPoint* point);
|
||||
|
||||
const char* GetEventName(Event event);
|
||||
bool GetEventFromName(const char* name, Event* event);
|
||||
|
||||
// The names for products are used only client-side.
|
||||
const char* GetProductName(Product product);
|
||||
|
||||
} // namespace rlz_lib
|
||||
|
||||
#endif // RLZ_LIB_LIB_VALUES_H_
|
61
rlz/lib/lib_values_unittest.cc
Normal file
61
rlz/lib/lib_values_unittest.cc
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "rlz/lib/lib_values.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "rlz/lib/assert.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
TEST(LibValuesUnittest, GetAccessPointFromName) {
|
||||
rlz_lib::SetExpectedAssertion("GetAccessPointFromName: point is NULL");
|
||||
EXPECT_FALSE(rlz_lib::GetAccessPointFromName("", NULL));
|
||||
rlz_lib::SetExpectedAssertion("");
|
||||
|
||||
rlz_lib::AccessPoint point;
|
||||
EXPECT_FALSE(rlz_lib::GetAccessPointFromName(NULL, &point));
|
||||
EXPECT_EQ(rlz_lib::NO_ACCESS_POINT, point);
|
||||
|
||||
EXPECT_TRUE(rlz_lib::GetAccessPointFromName("", &point));
|
||||
EXPECT_EQ(rlz_lib::NO_ACCESS_POINT, point);
|
||||
|
||||
EXPECT_FALSE(rlz_lib::GetAccessPointFromName("i1", &point));
|
||||
EXPECT_EQ(rlz_lib::NO_ACCESS_POINT, point);
|
||||
|
||||
EXPECT_TRUE(rlz_lib::GetAccessPointFromName("I7", &point));
|
||||
EXPECT_EQ(rlz_lib::IE_DEFAULT_SEARCH, point);
|
||||
|
||||
EXPECT_TRUE(rlz_lib::GetAccessPointFromName("T4", &point));
|
||||
EXPECT_EQ(rlz_lib::IETB_SEARCH_BOX, point);
|
||||
|
||||
EXPECT_FALSE(rlz_lib::GetAccessPointFromName("T4 ", &point));
|
||||
EXPECT_EQ(rlz_lib::NO_ACCESS_POINT, point);
|
||||
}
|
||||
|
||||
|
||||
TEST(LibValuesUnittest, GetEventFromName) {
|
||||
rlz_lib::SetExpectedAssertion("GetEventFromName: event is NULL");
|
||||
EXPECT_FALSE(rlz_lib::GetEventFromName("", NULL));
|
||||
rlz_lib::SetExpectedAssertion("");
|
||||
|
||||
rlz_lib::Event event;
|
||||
EXPECT_FALSE(rlz_lib::GetEventFromName(NULL, &event));
|
||||
EXPECT_EQ(rlz_lib::INVALID_EVENT, event);
|
||||
|
||||
EXPECT_TRUE(rlz_lib::GetEventFromName("", &event));
|
||||
EXPECT_EQ(rlz_lib::INVALID_EVENT, event);
|
||||
|
||||
EXPECT_FALSE(rlz_lib::GetEventFromName("i1", &event));
|
||||
EXPECT_EQ(rlz_lib::INVALID_EVENT, event);
|
||||
|
||||
EXPECT_TRUE(rlz_lib::GetEventFromName("I", &event));
|
||||
EXPECT_EQ(rlz_lib::INSTALL, event);
|
||||
|
||||
EXPECT_TRUE(rlz_lib::GetEventFromName("F", &event));
|
||||
EXPECT_EQ(rlz_lib::FIRST_SEARCH, event);
|
||||
|
||||
EXPECT_FALSE(rlz_lib::GetEventFromName("F ", &event));
|
||||
EXPECT_EQ(rlz_lib::INVALID_EVENT, event);
|
||||
}
|
84
rlz/lib/machine_id.cc
Normal file
84
rlz/lib/machine_id.cc
Normal file
@ -0,0 +1,84 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "rlz/lib/machine_id.h"
|
||||
|
||||
#include "base/sha1.h"
|
||||
#include "rlz/lib/assert.h"
|
||||
#include "rlz/lib/crc8.h"
|
||||
#include "rlz/lib/string_utils.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
bool GetMachineId(std::string* machine_id) {
|
||||
if (!machine_id)
|
||||
return false;
|
||||
|
||||
static std::string calculated_id;
|
||||
static bool calculated = false;
|
||||
if (calculated) {
|
||||
*machine_id = calculated_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
string16 sid_string;
|
||||
int volume_id;
|
||||
if (!GetRawMachineId(&sid_string, &volume_id))
|
||||
return false;
|
||||
|
||||
if (!testing::GetMachineIdImpl(sid_string, volume_id, machine_id))
|
||||
return false;
|
||||
|
||||
calculated = true;
|
||||
calculated_id = *machine_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace testing {
|
||||
|
||||
bool GetMachineIdImpl(const string16& sid_string,
|
||||
int volume_id,
|
||||
std::string* machine_id) {
|
||||
machine_id->clear();
|
||||
|
||||
// The ID should be the SID hash + the Hard Drive SNo. + checksum byte.
|
||||
static const int kSizeWithoutChecksum = base::kSHA1Length + sizeof(int);
|
||||
std::basic_string<unsigned char> id_binary(kSizeWithoutChecksum + 1, 0);
|
||||
|
||||
if (!sid_string.empty()) {
|
||||
// In order to be compatible with the old version of RLZ, the hash of the
|
||||
// SID must be done with all the original bytes from the unicode string.
|
||||
// However, the chromebase SHA1 hash function takes only an std::string as
|
||||
// input, so the unicode string needs to be converted to std::string
|
||||
// "as is".
|
||||
size_t byte_count = sid_string.size() * sizeof(string16::value_type);
|
||||
const char* buffer = reinterpret_cast<const char*>(sid_string.c_str());
|
||||
std::string sid_string_buffer(buffer, byte_count);
|
||||
|
||||
// Note that digest can have embedded nulls.
|
||||
std::string digest(base::SHA1HashString(sid_string_buffer));
|
||||
VERIFY(digest.size() == base::kSHA1Length);
|
||||
std::copy(digest.begin(), digest.end(), id_binary.begin());
|
||||
}
|
||||
|
||||
// Convert from int to binary (makes big-endian).
|
||||
for (size_t i = 0; i < sizeof(int); i++) {
|
||||
int shift_bits = 8 * (sizeof(int) - i - 1);
|
||||
id_binary[base::kSHA1Length + i] = static_cast<unsigned char>(
|
||||
(volume_id >> shift_bits) & 0xFF);
|
||||
}
|
||||
|
||||
// Append the checksum byte.
|
||||
if (!sid_string.empty() || (0 != volume_id))
|
||||
rlz_lib::Crc8::Generate(id_binary.c_str(),
|
||||
kSizeWithoutChecksum,
|
||||
&id_binary[kSizeWithoutChecksum]);
|
||||
|
||||
return rlz_lib::BytesToString(
|
||||
id_binary.c_str(), kSizeWithoutChecksum + 1, machine_id);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
} // namespace rlz_lib
|
34
rlz/lib/machine_id.h
Normal file
34
rlz/lib/machine_id.h
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef RLZ_LIB_MACHINE_ID_H_
|
||||
#define RLZ_LIB_MACHINE_ID_H_
|
||||
|
||||
#include "base/string16.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
// Gets the unique ID for the machine used for RLZ tracking purposes. On
|
||||
// Windows, this ID is derived from the Windows machine SID, and is the string
|
||||
// representation of a 20 byte hash + 4 bytes volum id + a 1 byte checksum.
|
||||
// Included in financial pings with events, unless explicitly forbidden by the
|
||||
// calling application.
|
||||
bool GetMachineId(std::string* machine_id);
|
||||
|
||||
// Retrieves a raw machine identifier string and a machine-specific
|
||||
// 4 byte value. GetMachineId() will SHA1 |data|, append |more_data|, compute
|
||||
// the Crc8 of that, and return a hex-encoded string of that data.
|
||||
bool GetRawMachineId(string16* data, int* more_data);
|
||||
|
||||
namespace testing {
|
||||
bool GetMachineIdImpl(const string16& sid_string,
|
||||
int volume_id,
|
||||
std::string* machine_id);
|
||||
} // namespace testing
|
||||
|
||||
} // namespace rlz_lib
|
||||
|
||||
#endif // RLZ_LIB_MACHINE_ID_H_
|
20
rlz/lib/machine_id_unittest.cc
Normal file
20
rlz/lib/machine_id_unittest.cc
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "rlz/lib/machine_id.h"
|
||||
|
||||
#include "base/string16.h"
|
||||
#include "base/utf_string_conversions.h"
|
||||
#include "rlz/test/rlz_test_helpers.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
// This test will fail if the behavior of GetMachineId changes.
|
||||
TEST(MachineDealCodeTestMachineId, MachineId) {
|
||||
string16 computer_sid(UTF8ToUTF16(
|
||||
"S-1-5-21-2345599882-2448789067-1921365677"));
|
||||
std::string id;
|
||||
rlz_lib::testing::GetMachineIdImpl(computer_sid, 2651229008, &id);
|
||||
EXPECT_STREQ("A341BA986A7E86840688977FCF20C86E253F00919E068B50F8",
|
||||
id.c_str());
|
||||
}
|
132
rlz/lib/rlz_enums.h
Normal file
132
rlz/lib/rlz_enums.h
Normal file
@ -0,0 +1,132 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef RLZ_LIB_RLZ_ENUMS_H_
|
||||
#define RLZ_LIB_RLZ_ENUMS_H_
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
// An Access Point offers a way to search using Google.
|
||||
enum AccessPoint {
|
||||
NO_ACCESS_POINT = 0,
|
||||
|
||||
// Access points on Windows PCs.
|
||||
IE_DEFAULT_SEARCH, // The IE7+ chrome search box next to the address bar.
|
||||
IE_HOME_PAGE, // Search box on IE 5+ primary home page when Google.
|
||||
IETB_SEARCH_BOX, // IE Toolbar v4+ search box.
|
||||
QUICK_SEARCH_BOX, // Search box brought up by ctrl-ctrl key sequence,
|
||||
// distributed as a part of Google Desktop
|
||||
GD_DESKBAND, // Search box in deskbar when GD in deskbar mode.
|
||||
GD_SEARCH_GADGET, // Search gadget when GD in sidebar mode.
|
||||
GD_WEB_SERVER, // Boxes in web pages shown by local GD web server.
|
||||
GD_OUTLOOK, // Search box installed within outlook by GD.
|
||||
CHROME_OMNIBOX, // Chrome searches through the address bar omnibox.
|
||||
CHROME_HOME_PAGE, // Chrome searches through Google as home page.
|
||||
FFTB2_BOX, // Firefox Toolbar v2 Search Box.
|
||||
FFTB3_BOX, // Firefox Toolbar v3+ Search Box.
|
||||
PINYIN_IME_BHO, // Goopy Input Method Editor BHO (Pinyin).
|
||||
IGOOGLE_WEBPAGE, // Searches on iGoogle through partner deals.
|
||||
|
||||
// Mobile idle screen search for different platforms.
|
||||
MOBILE_IDLE_SCREEN_BLACKBERRY,
|
||||
MOBILE_IDLE_SCREEN_WINMOB,
|
||||
MOBILE_IDLE_SCREEN_SYMBIAN,
|
||||
|
||||
FF_HOME_PAGE, // Firefox home page when set to Google.
|
||||
FF_SEARCH_BOX, // Firefox search box when set to Google.
|
||||
IE_BROWSED_PAGE, // Search made in IE through user action (no product).
|
||||
QSB_WIN_BOX, // Search box brought up by ctrl+space by default,
|
||||
// distributed by toolbar and separate from the GD QSB
|
||||
WEBAPPS_CALENDAR, // Webapps use of calendar.
|
||||
WEBAPPS_DOCS, // Webapps use of writely.
|
||||
WEBAPPS_GMAIL, // Webapps use of Gmail.
|
||||
|
||||
IETB_LINKDOCTOR, // Linkdoctor of IE Toolbar
|
||||
FFTB_LINKDOCTOR, // Linkdoctor of FF Toolbar
|
||||
IETB7_SEARCH_BOX, // IE Toolbar search box.
|
||||
TB8_SEARCH_BOX, // IE/FF Toolbar search box.
|
||||
CHROME_FRAME, // Chrome Frame.
|
||||
|
||||
// Partner access points.
|
||||
PARTNER_AP_1,
|
||||
PARTNER_AP_2,
|
||||
PARTNER_AP_3,
|
||||
PARTNER_AP_4,
|
||||
PARTNER_AP_5,
|
||||
|
||||
// Unclaimed access points - should be used first before creating new APs.
|
||||
// Please also make sure you re-name the enum before using an unclaimed value;
|
||||
// this acts as a check to ensure we don't have collisions.
|
||||
UNDEFINED_AP_H,
|
||||
UNDEFINED_AP_I,
|
||||
UNDEFINED_AP_J,
|
||||
UNDEFINED_AP_K,
|
||||
UNDEFINED_AP_L,
|
||||
UNDEFINED_AP_M,
|
||||
UNDEFINED_AP_N,
|
||||
UNDEFINED_AP_O,
|
||||
UNDEFINED_AP_P,
|
||||
UNDEFINED_AP_Q,
|
||||
UNDEFINED_AP_R,
|
||||
UNDEFINED_AP_S,
|
||||
UNDEFINED_AP_T,
|
||||
UNDEFINED_AP_U,
|
||||
UNDEFINED_AP_V,
|
||||
UNDEFINED_AP_W,
|
||||
UNDEFINED_AP_X,
|
||||
UNDEFINED_AP_Y,
|
||||
UNDEFINED_AP_Z,
|
||||
|
||||
PACK_AP0,
|
||||
PACK_AP1,
|
||||
PACK_AP2,
|
||||
PACK_AP3,
|
||||
PACK_AP4,
|
||||
PACK_AP5,
|
||||
PACK_AP6,
|
||||
PACK_AP7,
|
||||
PACK_AP8,
|
||||
PACK_AP9,
|
||||
PACK_AP10,
|
||||
PACK_AP11,
|
||||
PACK_AP12,
|
||||
PACK_AP13,
|
||||
|
||||
// New Access Points should be added here without changing existing enums,
|
||||
// (i.e. before LAST_ACCESS_POINT)
|
||||
LAST_ACCESS_POINT
|
||||
};
|
||||
|
||||
// A product is an entity which wants to gets credit for setting
|
||||
// an Access Point.
|
||||
enum Product {
|
||||
IE_TOOLBAR = 1,
|
||||
TOOLBAR_NOTIFIER,
|
||||
PACK,
|
||||
DESKTOP,
|
||||
CHROME,
|
||||
FF_TOOLBAR,
|
||||
QSB_WIN,
|
||||
WEBAPPS,
|
||||
PINYIN_IME,
|
||||
PARTNER
|
||||
// New Products should be added here without changing existing enums.
|
||||
};
|
||||
|
||||
// Events that note Product and Access Point modifications.
|
||||
enum Event {
|
||||
INVALID_EVENT = 0,
|
||||
INSTALL = 1, // Access Point added to the system.
|
||||
SET_TO_GOOGLE, // Point set from non-Google provider to Google.
|
||||
FIRST_SEARCH, // First search from point since INSTALL
|
||||
REPORT_RLS, // Report old system "RLS" financial value for this point.
|
||||
// New Events should be added here without changing existing enums,
|
||||
// before LAST_EVENT.
|
||||
ACTIVATE, // Product being used for a period of time.
|
||||
LAST_EVENT
|
||||
};
|
||||
|
||||
} // namespace rlz_lib
|
||||
|
||||
#endif // RLZ_LIB_RLZ_ENUMS_H_
|
651
rlz/lib/rlz_lib.cc
Normal file
651
rlz/lib/rlz_lib.cc
Normal file
@ -0,0 +1,651 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// A library to manage RLZ information for access-points shared
|
||||
// across different client applications.
|
||||
|
||||
#include "rlz/lib/rlz_lib.h"
|
||||
|
||||
#include "base/string_util.h"
|
||||
#include "base/stringprintf.h"
|
||||
#include "rlz/lib/assert.h"
|
||||
#include "rlz/lib/crc32.h"
|
||||
#include "rlz/lib/financial_ping.h"
|
||||
#include "rlz/lib/lib_values.h"
|
||||
#include "rlz/lib/rlz_value_store.h"
|
||||
#include "rlz/lib/string_utils.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Event information returned from ping response.
|
||||
struct ReturnedEvent {
|
||||
rlz_lib::AccessPoint access_point;
|
||||
rlz_lib::Event event_type;
|
||||
};
|
||||
|
||||
// Helper functions
|
||||
|
||||
bool IsAccessPointSupported(rlz_lib::AccessPoint point) {
|
||||
switch (point) {
|
||||
case rlz_lib::NO_ACCESS_POINT:
|
||||
case rlz_lib::LAST_ACCESS_POINT:
|
||||
|
||||
case rlz_lib::MOBILE_IDLE_SCREEN_BLACKBERRY:
|
||||
case rlz_lib::MOBILE_IDLE_SCREEN_WINMOB:
|
||||
case rlz_lib::MOBILE_IDLE_SCREEN_SYMBIAN:
|
||||
// These AP's are never available on Windows PCs.
|
||||
return false;
|
||||
|
||||
case rlz_lib::IE_DEFAULT_SEARCH:
|
||||
case rlz_lib::IE_HOME_PAGE:
|
||||
case rlz_lib::IETB_SEARCH_BOX:
|
||||
case rlz_lib::QUICK_SEARCH_BOX:
|
||||
case rlz_lib::GD_DESKBAND:
|
||||
case rlz_lib::GD_SEARCH_GADGET:
|
||||
case rlz_lib::GD_WEB_SERVER:
|
||||
case rlz_lib::GD_OUTLOOK:
|
||||
case rlz_lib::CHROME_OMNIBOX:
|
||||
case rlz_lib::CHROME_HOME_PAGE:
|
||||
// TODO: Figure out when these settings are set to Google.
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Current RLZ can only use [a-zA-Z0-9_\-]
|
||||
// We will be more liberal and allow some additional chars, but not url meta
|
||||
// chars.
|
||||
bool IsGoodRlzChar(const char ch) {
|
||||
if (IsAsciiAlpha(ch) || IsAsciiDigit(ch))
|
||||
return true;
|
||||
|
||||
switch (ch) {
|
||||
case '_':
|
||||
case '-':
|
||||
case '!':
|
||||
case '@':
|
||||
case '$':
|
||||
case '*':
|
||||
case '(':
|
||||
case ')':
|
||||
case ';':
|
||||
case '.':
|
||||
case '<':
|
||||
case '>':
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// This function will remove bad rlz chars and also limit the max rlz to some
|
||||
// reasonable size. It also assumes that normalized_rlz is at least
|
||||
// kMaxRlzLength+1 long.
|
||||
void NormalizeRlz(const char* raw_rlz, char* normalized_rlz) {
|
||||
int index = 0;
|
||||
for (; raw_rlz[index] != 0 && index < rlz_lib::kMaxRlzLength; ++index) {
|
||||
char current = raw_rlz[index];
|
||||
if (IsGoodRlzChar(current)) {
|
||||
normalized_rlz[index] = current;
|
||||
} else {
|
||||
normalized_rlz[index] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
normalized_rlz[index] = 0;
|
||||
}
|
||||
|
||||
void GetEventsFromResponseString(
|
||||
const std::string& response_line,
|
||||
const std::string& field_header,
|
||||
std::vector<ReturnedEvent>* event_array) {
|
||||
// Get the string of events.
|
||||
std::string events = response_line.substr(field_header.size());
|
||||
TrimWhitespaceASCII(events, TRIM_LEADING, &events);
|
||||
|
||||
int events_length = events.find_first_of("\r\n ");
|
||||
if (events_length < 0)
|
||||
events_length = events.size();
|
||||
events = events.substr(0, events_length);
|
||||
|
||||
// Break this up into individual events
|
||||
int event_end_index = -1;
|
||||
do {
|
||||
int event_begin = event_end_index + 1;
|
||||
event_end_index = events.find(rlz_lib::kEventsCgiSeparator, event_begin);
|
||||
int event_end = event_end_index;
|
||||
if (event_end < 0)
|
||||
event_end = events_length;
|
||||
|
||||
std::string event_string = events.substr(event_begin,
|
||||
event_end - event_begin);
|
||||
if (event_string.size() != 3) // 3 = 2(AP) + 1(E)
|
||||
continue;
|
||||
|
||||
rlz_lib::AccessPoint point = rlz_lib::NO_ACCESS_POINT;
|
||||
rlz_lib::Event event = rlz_lib::INVALID_EVENT;
|
||||
if (!GetAccessPointFromName(event_string.substr(0, 2).c_str(), &point) ||
|
||||
point == rlz_lib::NO_ACCESS_POINT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!GetEventFromName(event_string.substr(event_string.size() - 1).c_str(),
|
||||
&event) || event == rlz_lib::INVALID_EVENT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ReturnedEvent current_event = {point, event};
|
||||
event_array->push_back(current_event);
|
||||
} while (event_end_index >= 0);
|
||||
}
|
||||
|
||||
// Event storage functions.
|
||||
bool RecordStatefulEvent(rlz_lib::Product product, rlz_lib::AccessPoint point,
|
||||
rlz_lib::Event event) {
|
||||
rlz_lib::ScopedRlzValueStoreLock lock;
|
||||
rlz_lib::RlzValueStore* store = lock.GetStore();
|
||||
if (!store || !store->HasAccess(rlz_lib::RlzValueStore::kWriteAccess))
|
||||
return false;
|
||||
|
||||
// Write the new event to the value store.
|
||||
const char* point_name = GetAccessPointName(point);
|
||||
const char* event_name = GetEventName(event);
|
||||
if (!point_name || !event_name)
|
||||
return false;
|
||||
|
||||
if (!point_name[0] || !event_name[0])
|
||||
return false;
|
||||
|
||||
std::string new_event_value;
|
||||
base::StringAppendF(&new_event_value, "%s%s", point_name, event_name);
|
||||
return store->AddStatefulEvent(product, new_event_value.c_str());
|
||||
}
|
||||
|
||||
bool GetProductEventsAsCgiHelper(rlz_lib::Product product, char* cgi,
|
||||
size_t cgi_size,
|
||||
rlz_lib::RlzValueStore* store) {
|
||||
// Prepend the CGI param key to the buffer.
|
||||
std::string cgi_arg;
|
||||
base::StringAppendF(&cgi_arg, "%s=", rlz_lib::kEventsCgiVariable);
|
||||
if (cgi_size <= cgi_arg.size())
|
||||
return false;
|
||||
|
||||
size_t index;
|
||||
for (index = 0; index < cgi_arg.size(); ++index)
|
||||
cgi[index] = cgi_arg[index];
|
||||
|
||||
// Read stored events.
|
||||
std::vector<std::string> events;
|
||||
if (!store->ReadProductEvents(product, &events))
|
||||
return false;
|
||||
|
||||
// Append the events to the buffer.
|
||||
size_t num_values = 0;
|
||||
|
||||
for (num_values = 0; num_values < events.size(); ++num_values) {
|
||||
cgi[index] = '\0';
|
||||
|
||||
int divider = num_values > 0 ? 1 : 0;
|
||||
int size = cgi_size - (index + divider);
|
||||
if (size <= 0)
|
||||
return cgi_size >= (rlz_lib::kMaxCgiLength + 1);
|
||||
|
||||
strncpy(cgi + index + divider, events[num_values].c_str(), size);
|
||||
if (divider)
|
||||
cgi[index] = rlz_lib::kEventsCgiSeparator;
|
||||
|
||||
index += std::min((int)events[num_values].length(), size) + divider;
|
||||
}
|
||||
|
||||
cgi[index] = '\0';
|
||||
|
||||
return num_values > 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
#if defined(RLZ_NETWORK_IMPLEMENTATION_CHROME_NET)
|
||||
bool SetURLRequestContext(net::URLRequestContextGetter* context) {
|
||||
return FinancialPing::SetURLRequestContext(context);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool GetProductEventsAsCgi(Product product, char* cgi, size_t cgi_size) {
|
||||
if (!cgi || cgi_size <= 0) {
|
||||
ASSERT_STRING("GetProductEventsAsCgi: Invalid buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
cgi[0] = 0;
|
||||
|
||||
ScopedRlzValueStoreLock lock;
|
||||
RlzValueStore* store = lock.GetStore();
|
||||
if (!store || !store->HasAccess(RlzValueStore::kReadAccess))
|
||||
return false;
|
||||
|
||||
size_t size_local = std::min(
|
||||
static_cast<size_t>(kMaxCgiLength + 1), cgi_size);
|
||||
bool result = GetProductEventsAsCgiHelper(product, cgi, size_local, store);
|
||||
|
||||
if (!result) {
|
||||
ASSERT_STRING("GetProductEventsAsCgi: Possibly insufficient buffer size");
|
||||
cgi[0] = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordProductEvent(Product product, AccessPoint point, Event event) {
|
||||
ScopedRlzValueStoreLock lock;
|
||||
RlzValueStore* store = lock.GetStore();
|
||||
if (!store || !store->HasAccess(RlzValueStore::kWriteAccess))
|
||||
return false;
|
||||
|
||||
// Get this event's value.
|
||||
const char* point_name = GetAccessPointName(point);
|
||||
const char* event_name = GetEventName(event);
|
||||
if (!point_name || !event_name)
|
||||
return false;
|
||||
|
||||
if (!point_name[0] || !event_name[0])
|
||||
return false;
|
||||
|
||||
std::string new_event_value;
|
||||
base::StringAppendF(&new_event_value, "%s%s", point_name, event_name);
|
||||
|
||||
// Check whether this event is a stateful event. If so, don't record it.
|
||||
if (store->IsStatefulEvent(product, new_event_value.c_str())) {
|
||||
// For a stateful event we skip recording, this function is also
|
||||
// considered successful.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Write the new event to the value store.
|
||||
return store->AddProductEvent(product, new_event_value.c_str());
|
||||
}
|
||||
|
||||
bool ClearProductEvent(Product product, AccessPoint point, Event event) {
|
||||
ScopedRlzValueStoreLock lock;
|
||||
RlzValueStore* store = lock.GetStore();
|
||||
if (!store || !store->HasAccess(RlzValueStore::kWriteAccess))
|
||||
return false;
|
||||
|
||||
// Get the event's value store value and delete it.
|
||||
const char* point_name = GetAccessPointName(point);
|
||||
const char* event_name = GetEventName(event);
|
||||
if (!point_name || !event_name)
|
||||
return false;
|
||||
|
||||
if (!point_name[0] || !event_name[0])
|
||||
return false;
|
||||
|
||||
std::string event_value;
|
||||
base::StringAppendF(&event_value, "%s%s", point_name, event_name);
|
||||
return store->ClearProductEvent(product, event_value.c_str());
|
||||
}
|
||||
|
||||
// RLZ storage functions.
|
||||
|
||||
bool GetAccessPointRlz(AccessPoint point, char* rlz, size_t rlz_size) {
|
||||
if (!rlz || rlz_size <= 0) {
|
||||
ASSERT_STRING("GetAccessPointRlz: Invalid buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
rlz[0] = 0;
|
||||
|
||||
ScopedRlzValueStoreLock lock;
|
||||
RlzValueStore* store = lock.GetStore();
|
||||
if (!store || !store->HasAccess(RlzValueStore::kReadAccess))
|
||||
return false;
|
||||
|
||||
if (!IsAccessPointSupported(point))
|
||||
return false;
|
||||
|
||||
return store->ReadAccessPointRlz(point, rlz, rlz_size);
|
||||
}
|
||||
|
||||
bool SetAccessPointRlz(AccessPoint point, const char* new_rlz) {
|
||||
ScopedRlzValueStoreLock lock;
|
||||
RlzValueStore* store = lock.GetStore();
|
||||
if (!store || !store->HasAccess(RlzValueStore::kWriteAccess))
|
||||
return false;
|
||||
|
||||
if (!new_rlz) {
|
||||
ASSERT_STRING("SetAccessPointRlz: Invalid buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return false if the access point is not set to Google.
|
||||
if (!IsAccessPointSupported(point)) {
|
||||
ASSERT_STRING(("SetAccessPointRlz: "
|
||||
"Cannot set RLZ for unsupported access point."));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify the RLZ length.
|
||||
size_t rlz_length = strlen(new_rlz);
|
||||
if (rlz_length > kMaxRlzLength) {
|
||||
ASSERT_STRING("SetAccessPointRlz: RLZ length is exceeds max allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
char normalized_rlz[kMaxRlzLength + 1];
|
||||
NormalizeRlz(new_rlz, normalized_rlz);
|
||||
VERIFY(strlen(new_rlz) == rlz_length);
|
||||
|
||||
// Setting RLZ to empty == clearing.
|
||||
if (normalized_rlz[0] == 0)
|
||||
return store->ClearAccessPointRlz(point);
|
||||
return store->WriteAccessPointRlz(point, normalized_rlz);
|
||||
}
|
||||
|
||||
// Financial Server pinging functions.
|
||||
|
||||
bool FormFinancialPingRequest(Product product, const AccessPoint* access_points,
|
||||
const char* product_signature,
|
||||
const char* product_brand,
|
||||
const char* product_id,
|
||||
const char* product_lang,
|
||||
bool exclude_machine_id,
|
||||
char* request, size_t request_buffer_size) {
|
||||
if (!request || request_buffer_size == 0)
|
||||
return false;
|
||||
|
||||
request[0] = 0;
|
||||
|
||||
std::string request_string;
|
||||
if (!FinancialPing::FormRequest(product, access_points, product_signature,
|
||||
product_brand, product_id, product_lang,
|
||||
exclude_machine_id, &request_string))
|
||||
return false;
|
||||
|
||||
if (request_string.size() >= request_buffer_size)
|
||||
return false;
|
||||
|
||||
strncpy(request, request_string.c_str(), request_buffer_size);
|
||||
request[request_buffer_size - 1] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PingFinancialServer(Product product, const char* request, char* response,
|
||||
size_t response_buffer_size) {
|
||||
if (!response || response_buffer_size == 0)
|
||||
return false;
|
||||
response[0] = 0;
|
||||
|
||||
// Check if the time is right to ping.
|
||||
if (!FinancialPing::IsPingTime(product, false))
|
||||
return false;
|
||||
|
||||
// Send out the ping.
|
||||
std::string response_string;
|
||||
if (!FinancialPing::PingServer(request, &response_string))
|
||||
return false;
|
||||
|
||||
if (response_string.size() >= response_buffer_size)
|
||||
return false;
|
||||
|
||||
strncpy(response, response_string.c_str(), response_buffer_size);
|
||||
response[response_buffer_size - 1] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsPingResponseValid(const char* response, int* checksum_idx) {
|
||||
if (!response || !response[0])
|
||||
return false;
|
||||
|
||||
if (checksum_idx)
|
||||
*checksum_idx = -1;
|
||||
|
||||
if (strlen(response) > kMaxPingResponseLength) {
|
||||
ASSERT_STRING("IsPingResponseValid: response is too long to parse.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the checksum line.
|
||||
std::string response_string(response);
|
||||
|
||||
std::string checksum_param("\ncrc32: ");
|
||||
int calculated_crc;
|
||||
int checksum_index = response_string.find(checksum_param);
|
||||
if (checksum_index >= 0) {
|
||||
// Calculate checksum of message preceeding checksum line.
|
||||
// (+ 1 to include the \n)
|
||||
std::string message(response_string.substr(0, checksum_index + 1));
|
||||
if (!Crc32(message.c_str(), &calculated_crc))
|
||||
return false;
|
||||
} else {
|
||||
checksum_param = "crc32: "; // Empty response case.
|
||||
if (!StartsWithASCII(response_string, checksum_param, true))
|
||||
return false;
|
||||
|
||||
checksum_index = 0;
|
||||
if (!Crc32("", &calculated_crc))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the checksum value on the response.
|
||||
int checksum_end = response_string.find("\n", checksum_index + 1);
|
||||
if (checksum_end < 0)
|
||||
checksum_end = response_string.size();
|
||||
|
||||
int checksum_begin = checksum_index + checksum_param.size();
|
||||
std::string checksum = response_string.substr(checksum_begin,
|
||||
checksum_end - checksum_begin + 1);
|
||||
TrimWhitespaceASCII(checksum, TRIM_ALL, &checksum);
|
||||
|
||||
if (checksum_idx)
|
||||
*checksum_idx = checksum_index;
|
||||
|
||||
return calculated_crc == HexStringToInteger(checksum.c_str());
|
||||
}
|
||||
|
||||
// Complex helpers built on top of other functions.
|
||||
|
||||
bool ParseFinancialPingResponse(Product product, const char* response) {
|
||||
// Update the last ping time irrespective of success.
|
||||
FinancialPing::UpdateLastPingTime(product);
|
||||
// Parse the ping response - update RLZs, clear events.
|
||||
return ParsePingResponse(product, response);
|
||||
}
|
||||
|
||||
bool SendFinancialPing(Product product, const AccessPoint* access_points,
|
||||
const char* product_signature,
|
||||
const char* product_brand,
|
||||
const char* product_id, const char* product_lang,
|
||||
bool exclude_machine_id) {
|
||||
return SendFinancialPing(product, access_points, product_signature,
|
||||
product_brand, product_id, product_lang,
|
||||
exclude_machine_id, false);
|
||||
}
|
||||
|
||||
|
||||
bool SendFinancialPing(Product product, const AccessPoint* access_points,
|
||||
const char* product_signature,
|
||||
const char* product_brand,
|
||||
const char* product_id, const char* product_lang,
|
||||
bool exclude_machine_id,
|
||||
const bool skip_time_check) {
|
||||
// Create the financial ping request.
|
||||
std::string request;
|
||||
if (!FinancialPing::FormRequest(product, access_points, product_signature,
|
||||
product_brand, product_id, product_lang,
|
||||
exclude_machine_id, &request))
|
||||
return false;
|
||||
|
||||
// Check if the time is right to ping.
|
||||
if (!FinancialPing::IsPingTime(product, skip_time_check))
|
||||
return false;
|
||||
|
||||
// Send out the ping, update the last ping time irrespective of success.
|
||||
FinancialPing::UpdateLastPingTime(product);
|
||||
std::string response;
|
||||
if (!FinancialPing::PingServer(request.c_str(), &response))
|
||||
return false;
|
||||
|
||||
// Parse the ping response - update RLZs, clear events.
|
||||
return ParsePingResponse(product, response.c_str());
|
||||
}
|
||||
|
||||
// TODO: Use something like RSA to make sure the response is
|
||||
// from a Google server.
|
||||
bool ParsePingResponse(Product product, const char* response) {
|
||||
rlz_lib::ScopedRlzValueStoreLock lock;
|
||||
rlz_lib::RlzValueStore* store = lock.GetStore();
|
||||
if (!store || !store->HasAccess(rlz_lib::RlzValueStore::kWriteAccess))
|
||||
return false;
|
||||
|
||||
std::string response_string(response);
|
||||
int response_length = -1;
|
||||
if (!IsPingResponseValid(response, &response_length))
|
||||
return false;
|
||||
|
||||
if (0 == response_length)
|
||||
return true; // Empty response - no parsing.
|
||||
|
||||
std::string events_variable;
|
||||
std::string stateful_events_variable;
|
||||
base::SStringPrintf(&events_variable, "%s: ", kEventsCgiVariable);
|
||||
base::SStringPrintf(&stateful_events_variable, "%s: ",
|
||||
kStatefulEventsCgiVariable);
|
||||
|
||||
int rlz_cgi_length = strlen(kRlzCgiVariable);
|
||||
|
||||
// Split response lines. Expected response format is lines of the form:
|
||||
// rlzW1: 1R1_____en__252
|
||||
int line_end_index = -1;
|
||||
do {
|
||||
int line_begin = line_end_index + 1;
|
||||
line_end_index = response_string.find("\n", line_begin);
|
||||
|
||||
int line_end = line_end_index;
|
||||
if (line_end < 0)
|
||||
line_end = response_length;
|
||||
|
||||
if (line_end <= line_begin)
|
||||
continue; // Empty line.
|
||||
|
||||
std::string response_line;
|
||||
response_line = response_string.substr(line_begin, line_end - line_begin);
|
||||
|
||||
if (StartsWithASCII(response_line, kRlzCgiVariable, true)) { // An RLZ.
|
||||
int separator_index = -1;
|
||||
if ((separator_index = response_line.find(": ")) < 0)
|
||||
continue; // Not a valid key-value pair.
|
||||
|
||||
// Get the access point.
|
||||
std::string point_name =
|
||||
response_line.substr(3, separator_index - rlz_cgi_length);
|
||||
AccessPoint point = NO_ACCESS_POINT;
|
||||
if (!GetAccessPointFromName(point_name.c_str(), &point) ||
|
||||
point == NO_ACCESS_POINT)
|
||||
continue; // Not a valid access point.
|
||||
|
||||
// Get the new RLZ.
|
||||
std::string rlz_value(response_line.substr(separator_index + 2));
|
||||
TrimWhitespaceASCII(rlz_value, TRIM_LEADING, &rlz_value);
|
||||
|
||||
int rlz_length = rlz_value.find_first_of("\r\n ");
|
||||
if (rlz_length < 0)
|
||||
rlz_length = rlz_value.size();
|
||||
|
||||
if (rlz_length > kMaxRlzLength)
|
||||
continue; // Too long.
|
||||
|
||||
if (IsAccessPointSupported(point))
|
||||
SetAccessPointRlz(point, rlz_value.substr(0, rlz_length).c_str());
|
||||
} else if (StartsWithASCII(response_line, events_variable, true)) {
|
||||
// Clear events which server parsed.
|
||||
std::vector<ReturnedEvent> event_array;
|
||||
GetEventsFromResponseString(response_line, events_variable, &event_array);
|
||||
for (size_t i = 0; i < event_array.size(); ++i) {
|
||||
ClearProductEvent(product, event_array[i].access_point,
|
||||
event_array[i].event_type);
|
||||
}
|
||||
} else if (StartsWithASCII(response_line, stateful_events_variable, true)) {
|
||||
// Record any stateful events the server send over.
|
||||
std::vector<ReturnedEvent> event_array;
|
||||
GetEventsFromResponseString(response_line, stateful_events_variable,
|
||||
&event_array);
|
||||
for (size_t i = 0; i < event_array.size(); ++i) {
|
||||
RecordStatefulEvent(product, event_array[i].access_point,
|
||||
event_array[i].event_type);
|
||||
}
|
||||
}
|
||||
} while (line_end_index >= 0);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Update the DCC in registry if needed.
|
||||
SetMachineDealCodeFromPingResponse(response);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetPingParams(Product product, const AccessPoint* access_points,
|
||||
char* cgi, size_t cgi_size) {
|
||||
if (!cgi || cgi_size <= 0) {
|
||||
ASSERT_STRING("GetPingParams: Invalid buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
cgi[0] = 0;
|
||||
|
||||
if (!access_points) {
|
||||
ASSERT_STRING("GetPingParams: access_points is NULL");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add the RLZ Exchange Protocol version.
|
||||
std::string cgi_string(kProtocolCgiArgument);
|
||||
|
||||
// Copy the &rlz= over.
|
||||
base::StringAppendF(&cgi_string, "&%s=", kRlzCgiVariable);
|
||||
|
||||
{
|
||||
// Now add each of the RLZ's. Keep the lock during all GetAccessPointRlz()
|
||||
// calls below.
|
||||
ScopedRlzValueStoreLock lock;
|
||||
RlzValueStore* store = lock.GetStore();
|
||||
if (!store || !store->HasAccess(RlzValueStore::kReadAccess))
|
||||
return false;
|
||||
bool first_rlz = true; // comma before every RLZ but the first.
|
||||
for (int i = 0; access_points[i] != NO_ACCESS_POINT; i++) {
|
||||
char rlz[kMaxRlzLength + 1];
|
||||
if (GetAccessPointRlz(access_points[i], rlz, arraysize(rlz))) {
|
||||
const char* access_point = GetAccessPointName(access_points[i]);
|
||||
if (!access_point)
|
||||
continue;
|
||||
|
||||
base::StringAppendF(&cgi_string, "%s%s%s%s",
|
||||
first_rlz ? "" : kRlzCgiSeparator,
|
||||
access_point, kRlzCgiIndicator, rlz);
|
||||
first_rlz = false;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Report the DCC too if not empty. DCCs are windows-only.
|
||||
char dcc[kMaxDccLength + 1];
|
||||
dcc[0] = 0;
|
||||
if (GetMachineDealCode(dcc, arraysize(dcc)) && dcc[0])
|
||||
base::StringAppendF(&cgi_string, "&%s=%s", kDccCgiVariable, dcc);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (cgi_string.size() >= cgi_size)
|
||||
return false;
|
||||
|
||||
strncpy(cgi, cgi_string.c_str(), cgi_size);
|
||||
cgi[cgi_size - 1] = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rlz_lib
|
335
rlz/lib/rlz_lib.h
Normal file
335
rlz/lib/rlz_lib.h
Normal file
@ -0,0 +1,335 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// A library to manage RLZ information for access-points shared
|
||||
// across different client applications.
|
||||
//
|
||||
// All functions return true on success and false on error.
|
||||
// This implemenation is thread safe.
|
||||
|
||||
|
||||
#ifndef RLZ_LIB_RLZ_LIB_H_
|
||||
#define RLZ_LIB_RLZ_LIB_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#include "rlz/lib/rlz_enums.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#define RLZ_LIB_API __cdecl
|
||||
#else
|
||||
#define RLZ_LIB_API
|
||||
#endif
|
||||
|
||||
// Define one of
|
||||
// + RLZ_NETWORK_IMPLEMENTATION_WIN_INET: Uses win inet to send financial pings.
|
||||
// + RLZ_NETWORK_IMPLEMENTATION_CHROME_NET: Uses chrome's network stack to send
|
||||
// financial pings. rlz_lib::SetURLRequestContext() must be called before
|
||||
// any calls to SendFinancialPing().
|
||||
#if defined(RLZ_NETWORK_IMPLEMENTATION_WIN_INET) && \
|
||||
defined(RLZ_NETWORK_IMPLEMENTATION_CHROME_NET)
|
||||
#error Exactly one of RLZ_NETWORK_IMPLEMENTATION_WIN_INET and \
|
||||
RLZ_NETWORK_IMPLEMENTATION_CHROME_NET should be defined.
|
||||
#endif
|
||||
#if !defined(RLZ_NETWORK_IMPLEMENTATION_WIN_INET) && \
|
||||
!defined(RLZ_NETWORK_IMPLEMENTATION_CHROME_NET)
|
||||
#if defined(OS_WIN)
|
||||
#define RLZ_NETWORK_IMPLEMENTATION_WIN_INET
|
||||
#else
|
||||
#define RLZ_NETWORK_IMPLEMENTATION_CHROME_NET
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(RLZ_NETWORK_IMPLEMENTATION_CHROME_NET)
|
||||
namespace net {
|
||||
class URLRequestContextGetter;
|
||||
} // namespace net
|
||||
#endif
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
class ScopedRlzValueStoreLock;
|
||||
|
||||
// The maximum length of an access points RLZ in bytes.
|
||||
const int kMaxRlzLength = 64;
|
||||
// The maximum length of an access points RLZ in bytes.
|
||||
const int kMaxDccLength = 128;
|
||||
// The maximum length of a CGI string in bytes.
|
||||
const int kMaxCgiLength = 2048;
|
||||
// The maximum length of a ping response we will parse in bytes. If the response
|
||||
// is bigger, please break it up into separate calls.
|
||||
const int kMaxPingResponseLength = 0x4000; // 16K
|
||||
|
||||
#if defined(RLZ_NETWORK_IMPLEMENTATION_CHROME_NET)
|
||||
// Set the URLRequestContextGetter used by SendFinancialPing(). The IO message
|
||||
// loop returned by this context will be used for the IO done by
|
||||
// SendFinancialPing().
|
||||
bool RLZ_LIB_API SetURLRequestContext(net::URLRequestContextGetter* context);
|
||||
#endif
|
||||
|
||||
// RLZ storage functions.
|
||||
|
||||
// Get all the events reported by this product as a CGI string to append to
|
||||
// the daily ping.
|
||||
// Access: HKCU read.
|
||||
bool RLZ_LIB_API GetProductEventsAsCgi(Product product, char* unescaped_cgi,
|
||||
size_t unescaped_cgi_size);
|
||||
|
||||
// Records an RLZ event.
|
||||
// Some events can be product-independent (e.g: First search from home page),
|
||||
// and some can be access point independent (e.g. Pack installed). However,
|
||||
// product independent events must still include the product which cares about
|
||||
// that information being reported.
|
||||
// Access: HKCU write.
|
||||
bool RLZ_LIB_API RecordProductEvent(Product product, AccessPoint point,
|
||||
Event event_id);
|
||||
|
||||
// Clear an event reported by this product. This should be called after a
|
||||
// successful ping to the RLZ server.
|
||||
// Access: HKCU write.
|
||||
bool RLZ_LIB_API ClearProductEvent(Product product, AccessPoint point,
|
||||
Event event_id);
|
||||
|
||||
// Clear all reported events and recorded stateful events of this product.
|
||||
// This should be called on complete uninstallation of the product.
|
||||
// Access: HKCU write.
|
||||
bool RLZ_LIB_API ClearAllProductEvents(Product product);
|
||||
|
||||
// Clears all product-specifc state from the RLZ registry.
|
||||
// Should be called during product uninstallation.
|
||||
// This removes outstanding product events, product financial ping times,
|
||||
// the product RLS argument (if any), and any RLZ's for access points being
|
||||
// uninstalled with the product.
|
||||
// access_points is an array terminated with NO_ACCESS_POINT.
|
||||
// IMPORTANT: These are the access_points the product is removing as part
|
||||
// of the uninstallation, not necessarily all the access points passed to
|
||||
// SendFinancialPing() and GetPingParams().
|
||||
// access_points can be NULL if no points are being uninstalled.
|
||||
// No return value - this is best effort. Will assert in debug mode on
|
||||
// failed attempts.
|
||||
// Access: HKCU write.
|
||||
void RLZ_LIB_API ClearProductState(Product product,
|
||||
const AccessPoint* access_points);
|
||||
|
||||
// Get the RLZ value of the access point. If the access point is not Google, the
|
||||
// RLZ will be the empty string and the function will return false.
|
||||
// Access: HKCU read.
|
||||
bool RLZ_LIB_API GetAccessPointRlz(AccessPoint point, char* rlz,
|
||||
size_t rlz_size);
|
||||
|
||||
// Set the RLZ for the access-point. Fails and asserts if called when the access
|
||||
// point is not set to Google.
|
||||
// new_rlz should come from a server-response. Client applications should not
|
||||
// create their own RLZ values.
|
||||
// Access: HKCU write.
|
||||
bool RLZ_LIB_API SetAccessPointRlz(AccessPoint point, const char* new_rlz);
|
||||
|
||||
// Financial Server pinging functions.
|
||||
// These functions deal with pinging the RLZ financial server and parsing and
|
||||
// acting upon the response. Clients should SendFinancialPing() to avoid needing
|
||||
// these functions. However, these functions allow clients to split the various
|
||||
// parts of the pinging process up as needed (to avoid firewalls, etc).
|
||||
|
||||
// Forms the HTTP request to send to the RLZ financial server.
|
||||
//
|
||||
// product : The product to ping for.
|
||||
// access_points : The access points this product affects. Array must be
|
||||
// terminated with NO_ACCESS_POINT.
|
||||
// product_signature : The signature sent with daily pings (e.g. swg, ietb)
|
||||
// product_brand : The brand of the pinging product, if any.
|
||||
// product_id : The product-specific installation ID (can be NULL).
|
||||
// product_lang : The language for the product (used to determine cohort).
|
||||
// exclude_machine_id : Whether the Machine ID should be explicitly excluded
|
||||
// based on the products privacy policy.
|
||||
// request : The buffer where the function returns the HTTP request.
|
||||
// request_buffer_size: The size of the request buffer in bytes. The buffer
|
||||
// size (kMaxCgiLength+1) is guaranteed to be enough.
|
||||
//
|
||||
// Access: HKCU read.
|
||||
bool RLZ_LIB_API FormFinancialPingRequest(Product product,
|
||||
const AccessPoint* access_points,
|
||||
const char* product_signature,
|
||||
const char* product_brand,
|
||||
const char* product_id,
|
||||
const char* product_lang,
|
||||
bool exclude_machine_id,
|
||||
char* request,
|
||||
size_t request_buffer_size);
|
||||
|
||||
// Pings the financial server and returns the HTTP response. This will fail
|
||||
// if it is too early to ping the server since the last ping.
|
||||
//
|
||||
// If RLZ_NETWORK_IMPLEMENTATION_CHROME_NET is set, SetURLRequestContext() needs
|
||||
// to be called before calling this function.
|
||||
//
|
||||
// product : The product to ping for.
|
||||
// request : The HTTP request (for example, returned by
|
||||
// FormFinancialPingRequest).
|
||||
// response : The buffer in which the HTTP response is returned.
|
||||
// response_buffer_size : The size of the response buffer in bytes. The buffer
|
||||
// size (kMaxPingResponseLength+1) is enough for all
|
||||
// legitimate server responses (any response that is
|
||||
// bigger should be considered the same way as a general
|
||||
// network problem).
|
||||
//
|
||||
// Access: HKCU read.
|
||||
bool RLZ_LIB_API PingFinancialServer(Product product,
|
||||
const char* request,
|
||||
char* response,
|
||||
size_t response_buffer_size);
|
||||
|
||||
// Checks if a ping response is valid - ie. it has a checksum line which
|
||||
// is the CRC-32 checksum of the message uptil the checksum. If
|
||||
// checksum_idx is not NULL, it will get the index of the checksum, i.e. -
|
||||
// the effective end of the message.
|
||||
// Access: No restrictions.
|
||||
bool RLZ_LIB_API IsPingResponseValid(const char* response,
|
||||
int* checksum_idx);
|
||||
|
||||
|
||||
// Complex helpers built on top of other functions.
|
||||
|
||||
// Parses the responses from the financial server and updates product state
|
||||
// and access point RLZ's in registry. Like ParsePingResponse(), but also
|
||||
// updates the last ping time.
|
||||
// Access: HKCU write.
|
||||
bool RLZ_LIB_API ParseFinancialPingResponse(Product product,
|
||||
const char* response);
|
||||
|
||||
// Send the ping with RLZs and events to the PSO server.
|
||||
// This ping method should be called daily. (More frequent calls will fail).
|
||||
// Also, if there are no events, the call will succeed only once a week.
|
||||
//
|
||||
// If RLZ_NETWORK_IMPLEMENTATION_CHROME_NET is set, SetURLRequestContext() needs
|
||||
// to be called before calling this function.
|
||||
//
|
||||
// product : The product to ping for.
|
||||
// access_points : The access points this product affects. Array must be
|
||||
// terminated with NO_ACCESS_POINT.
|
||||
// product_signature : The signature sent with daily pings (e.g. swg, ietb)
|
||||
// product_brand : The brand of the pinging product, if any.
|
||||
// product_id : The product-specific installation ID (can be NULL).
|
||||
// product_lang : The language for the product (used to determine cohort).
|
||||
// exclude_machine_id : Whether the Machine ID should be explicitly excluded
|
||||
// based on the products privacy policy.
|
||||
//
|
||||
// Returns true on successful ping and response, false otherwise.
|
||||
// Access: HKCU write.
|
||||
bool RLZ_LIB_API SendFinancialPing(Product product,
|
||||
const AccessPoint* access_points,
|
||||
const char* product_signature,
|
||||
const char* product_brand,
|
||||
const char* product_id,
|
||||
const char* product_lang,
|
||||
bool exclude_machine_id);
|
||||
|
||||
// An alternate implementations of SendFinancialPing with the same behavior,
|
||||
// except the caller can optionally choose to skip the timing check.
|
||||
bool RLZ_LIB_API SendFinancialPing(Product product,
|
||||
const AccessPoint* access_points,
|
||||
const char* product_signature,
|
||||
const char* product_brand,
|
||||
const char* product_id,
|
||||
const char* product_lang,
|
||||
bool exclude_machine_id,
|
||||
const bool skip_time_check);
|
||||
|
||||
// Parses RLZ related ping response information from the server.
|
||||
// Updates stored RLZ values and clears stored events accordingly.
|
||||
// Access: HKCU write.
|
||||
bool RLZ_LIB_API ParsePingResponse(Product product, const char* response);
|
||||
|
||||
|
||||
// Copies the events associated with the product and the RLZ's for each access
|
||||
// point in access_points into cgi. This string can be directly appended
|
||||
// to a ping (will need an & if not first paramter).
|
||||
// access_points must be an array of AccessPoints terminated with
|
||||
// NO_ACCESS_POINT.
|
||||
// Access: HKCU read.
|
||||
bool RLZ_LIB_API GetPingParams(Product product,
|
||||
const AccessPoint* access_points,
|
||||
char* unescaped_cgi, size_t unescaped_cgi_size);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// OEM Deal confirmation storage functions. OEM Deals are windows-only.
|
||||
|
||||
// Makes the OEM Deal Confirmation code writable by all users on the machine.
|
||||
// This should be called before calling SetMachineDealCode from a non-admin
|
||||
// account.
|
||||
// Access: HKLM write.
|
||||
bool RLZ_LIB_API CreateMachineState(void);
|
||||
|
||||
// Set the OEM Deal Confirmation Code (DCC). This information is used for RLZ
|
||||
// initalization.
|
||||
// Access: HKLM write, or
|
||||
// HKCU read if rlz_lib::CreateMachineState() has been sucessfully called.
|
||||
bool RLZ_LIB_API SetMachineDealCode(const char* dcc);
|
||||
|
||||
// Get the DCC cgi argument string to append to a daily ping.
|
||||
// Should be used only by OEM deal trackers. Applications should use the
|
||||
// GetMachineDealCode method which has an AccessPoint paramter.
|
||||
// Access: HKLM read.
|
||||
bool RLZ_LIB_API GetMachineDealCodeAsCgi(char* cgi, size_t cgi_size);
|
||||
|
||||
// Get the DCC value stored in registry.
|
||||
// Should be used only by OEM deal trackers. Applications should use the
|
||||
// GetMachineDealCode method which has an AccessPoint paramter.
|
||||
// Access: HKLM read.
|
||||
bool RLZ_LIB_API GetMachineDealCode(char* dcc, size_t dcc_size);
|
||||
|
||||
// Parses a ping response, checks if it is valid and sets the machine DCC
|
||||
// from the response. The ping must also contain the current DCC value in
|
||||
// order to be considered valid.
|
||||
// Access: HKLM write;
|
||||
// HKCU write if CreateMachineState() has been successfully called.
|
||||
bool RLZ_LIB_API SetMachineDealCodeFromPingResponse(const char* response);
|
||||
|
||||
#endif
|
||||
|
||||
// Segment RLZ persistence based on branding information.
|
||||
// All information for a given product is persisted under keys with the either
|
||||
// product's name or its access point's name. This assumes that only
|
||||
// one instance of the product is installed on the machine, and that only one
|
||||
// product brand is associated with it.
|
||||
//
|
||||
// In some cases, a given product may be using supplementary brands. The RLZ
|
||||
// information must be kept separately for each of these brands. To achieve
|
||||
// this segmentation, scope all RLZ library calls that deal with supplementary
|
||||
// brands within the lifetime of an rlz_lib::ProductBranding instance.
|
||||
//
|
||||
// For example, to record events for a supplementary brand, do the following:
|
||||
//
|
||||
// {
|
||||
// rlz_lib::SupplementaryBranding branding("AAAA");
|
||||
// // This call to RecordProductEvent is scoped to the AAAA brand.
|
||||
// rlz_lib::RecordProductEvent(rlz_lib::DESKTOP, rlz_lib::GD_DESKBAND,
|
||||
// rlz_lib::INSTALL);
|
||||
// }
|
||||
//
|
||||
// // This call to RecordProductEvent is not scoped to any supplementary brand.
|
||||
// rlz_lib::RecordProductEvent(rlz_lib::DESKTOP, rlz_lib::GD_DESKBAND,
|
||||
// rlz_lib::INSTALL);
|
||||
//
|
||||
// In particular, this affects the recording of stateful events and the sending
|
||||
// of financial pings. In the former case, a stateful event recorded while
|
||||
// scoped to a supplementary brand will be recorded again when scoped to a
|
||||
// different supplementary brand (or not scoped at all). In the latter case,
|
||||
// the time skip check is specific to each supplementary brand.
|
||||
class SupplementaryBranding {
|
||||
public:
|
||||
SupplementaryBranding(const char* brand);
|
||||
~SupplementaryBranding();
|
||||
|
||||
static const std::string& GetBrand();
|
||||
|
||||
private:
|
||||
ScopedRlzValueStoreLock* lock_;
|
||||
};
|
||||
|
||||
} // namespace rlz_lib
|
||||
|
||||
#endif // RLZ_LIB_RLZ_LIB_H_
|
82
rlz/lib/rlz_lib_clear.cc
Normal file
82
rlz/lib/rlz_lib_clear.cc
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// The methods in this file belong conceptually to rlz_lib.cc. However, some
|
||||
// programs depend on rlz only to call ClearAllProductEvents(), so this file
|
||||
// contains this in fairly self-contained form to make it easier for linkers
|
||||
// to strip away most of rlz. In particular, this file should not reference any
|
||||
// symbols defined in financial_ping.cc.
|
||||
|
||||
#include "rlz/lib/rlz_lib.h"
|
||||
|
||||
#include "base/lazy_instance.h"
|
||||
#include "rlz/lib/assert.h"
|
||||
#include "rlz/lib/rlz_value_store.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
bool ClearAllProductEvents(Product product) {
|
||||
rlz_lib::ScopedRlzValueStoreLock lock;
|
||||
rlz_lib::RlzValueStore* store = lock.GetStore();
|
||||
if (!store || !store->HasAccess(rlz_lib::RlzValueStore::kWriteAccess))
|
||||
return false;
|
||||
|
||||
bool result;
|
||||
result = store->ClearAllProductEvents(product);
|
||||
result &= store->ClearAllStatefulEvents(product);
|
||||
return result;
|
||||
}
|
||||
|
||||
void ClearProductState(Product product, const AccessPoint* access_points) {
|
||||
rlz_lib::ScopedRlzValueStoreLock lock;
|
||||
rlz_lib::RlzValueStore* store = lock.GetStore();
|
||||
if (!store || !store->HasAccess(rlz_lib::RlzValueStore::kWriteAccess))
|
||||
return;
|
||||
|
||||
// Delete all product specific state.
|
||||
VERIFY(ClearAllProductEvents(product));
|
||||
VERIFY(store->ClearPingTime(product));
|
||||
|
||||
// Delete all RLZ's for access points being uninstalled.
|
||||
if (access_points) {
|
||||
for (int i = 0; access_points[i] != NO_ACCESS_POINT; i++) {
|
||||
VERIFY(store->ClearAccessPointRlz(access_points[i]));
|
||||
}
|
||||
}
|
||||
|
||||
store->CollectGarbage();
|
||||
}
|
||||
|
||||
static base::LazyInstance<std::string>::Leaky g_supplemental_branding;
|
||||
|
||||
SupplementaryBranding::SupplementaryBranding(const char* brand)
|
||||
: lock_(new ScopedRlzValueStoreLock) {
|
||||
if (!lock_->GetStore())
|
||||
return;
|
||||
|
||||
if (!g_supplemental_branding.Get().empty()) {
|
||||
ASSERT_STRING("ProductBranding: existing brand is not empty");
|
||||
return;
|
||||
}
|
||||
|
||||
if (brand == NULL || brand[0] == 0) {
|
||||
ASSERT_STRING("ProductBranding: new brand is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
g_supplemental_branding.Get() = brand;
|
||||
}
|
||||
|
||||
SupplementaryBranding::~SupplementaryBranding() {
|
||||
if (lock_->GetStore())
|
||||
g_supplemental_branding.Get().clear();
|
||||
delete lock_;
|
||||
}
|
||||
|
||||
// static
|
||||
const std::string& SupplementaryBranding::GetBrand() {
|
||||
return g_supplemental_branding.Get();
|
||||
}
|
||||
|
||||
} // namespace rlz_lib
|
824
rlz/lib/rlz_lib_test.cc
Normal file
824
rlz/lib/rlz_lib_test.cc
Normal file
@ -0,0 +1,824 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// A test application for the RLZ library.
|
||||
//
|
||||
// These tests should not be executed on the build server:
|
||||
// - They assert for the failed cases.
|
||||
// - They modify machine state (registry).
|
||||
//
|
||||
// These tests require write access to HKLM and HKCU.
|
||||
//
|
||||
// The "GGLA" brand is used to test the normal code flow of the code, and the
|
||||
// "TEST" brand is used to test the supplementary brand code code flow.
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
#include "rlz/lib/rlz_lib.h"
|
||||
#include "rlz/test/rlz_test_helpers.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <Windows.h>
|
||||
#include "rlz/win/lib/machine_deal.h"
|
||||
#endif
|
||||
|
||||
#if defined(RLZ_NETWORK_IMPLEMENTATION_CHROME_NET)
|
||||
#include "base/mac/scoped_nsautorelease_pool.h"
|
||||
#include "base/threading/thread.h"
|
||||
#include "net/url_request/url_request_test_util.h"
|
||||
#endif
|
||||
|
||||
|
||||
class MachineDealCodeHelper
|
||||
#if defined(OS_WIN)
|
||||
: public rlz_lib::MachineDealCode
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
static bool Clear() {
|
||||
#if defined(OS_WIN)
|
||||
return rlz_lib::MachineDealCode::Clear();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
MachineDealCodeHelper() {}
|
||||
~MachineDealCodeHelper() {}
|
||||
};
|
||||
|
||||
class RlzLibTest : public RlzLibTestBase {
|
||||
};
|
||||
|
||||
TEST_F(RlzLibTest, RecordProductEvent) {
|
||||
char cgi_50[50];
|
||||
|
||||
EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
cgi_50, 50));
|
||||
EXPECT_STREQ("events=I7S", cgi_50);
|
||||
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL));
|
||||
EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
cgi_50, 50));
|
||||
EXPECT_STREQ("events=I7S,W1I", cgi_50);
|
||||
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
cgi_50, 50));
|
||||
EXPECT_STREQ("events=I7S,W1I", cgi_50);
|
||||
}
|
||||
|
||||
TEST_F(RlzLibTest, ClearProductEvent) {
|
||||
char cgi_50[50];
|
||||
|
||||
// Clear 1 of 1 events.
|
||||
EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
cgi_50, 50));
|
||||
EXPECT_STREQ("events=I7S", cgi_50);
|
||||
EXPECT_TRUE(rlz_lib::ClearProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_FALSE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
cgi_50, 50));
|
||||
EXPECT_STREQ("", cgi_50);
|
||||
|
||||
// Clear 1 of 2 events.
|
||||
EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL));
|
||||
EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
cgi_50, 50));
|
||||
EXPECT_STREQ("events=I7S,W1I", cgi_50);
|
||||
EXPECT_TRUE(rlz_lib::ClearProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
cgi_50, 50));
|
||||
EXPECT_STREQ("events=W1I", cgi_50);
|
||||
|
||||
// Clear a non-recorded event.
|
||||
EXPECT_TRUE(rlz_lib::ClearProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IETB_SEARCH_BOX, rlz_lib::FIRST_SEARCH));
|
||||
EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
cgi_50, 50));
|
||||
EXPECT_STREQ("events=W1I", cgi_50);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(RlzLibTest, GetProductEventsAsCgi) {
|
||||
char cgi_50[50];
|
||||
char cgi_1[1];
|
||||
|
||||
EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
cgi_50, 50));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL));
|
||||
|
||||
EXPECT_FALSE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
cgi_1, 1));
|
||||
EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
cgi_50, 50));
|
||||
EXPECT_STREQ("events=I7S,W1I", cgi_50);
|
||||
}
|
||||
|
||||
TEST_F(RlzLibTest, ClearAllAllProductEvents) {
|
||||
char cgi_50[50];
|
||||
|
||||
EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
cgi_50, 50));
|
||||
EXPECT_STREQ("events=I7S", cgi_50);
|
||||
|
||||
EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER));
|
||||
EXPECT_FALSE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
cgi_50, 50));
|
||||
EXPECT_STREQ("", cgi_50);
|
||||
}
|
||||
|
||||
TEST_F(RlzLibTest, SetAccessPointRlz) {
|
||||
char rlz_50[50];
|
||||
EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, ""));
|
||||
EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, rlz_50, 50));
|
||||
EXPECT_STREQ("", rlz_50);
|
||||
|
||||
EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, "IeTbRlz"));
|
||||
EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, rlz_50, 50));
|
||||
EXPECT_STREQ("IeTbRlz", rlz_50);
|
||||
}
|
||||
|
||||
TEST_F(RlzLibTest, GetAccessPointRlz) {
|
||||
char rlz_1[1];
|
||||
char rlz_50[50];
|
||||
EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, ""));
|
||||
EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, rlz_1, 1));
|
||||
EXPECT_STREQ("", rlz_1);
|
||||
|
||||
EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, "IeTbRlz"));
|
||||
EXPECT_FALSE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, rlz_1, 1));
|
||||
EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, rlz_50, 50));
|
||||
EXPECT_STREQ("IeTbRlz", rlz_50);
|
||||
}
|
||||
|
||||
TEST_F(RlzLibTest, GetPingParams) {
|
||||
MachineDealCodeHelper::Clear();
|
||||
|
||||
EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX,
|
||||
"TbRlzValue"));
|
||||
EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IE_HOME_PAGE, ""));
|
||||
|
||||
char cgi[2048];
|
||||
rlz_lib::AccessPoint points[] =
|
||||
{rlz_lib::IETB_SEARCH_BOX, rlz_lib::NO_ACCESS_POINT,
|
||||
rlz_lib::NO_ACCESS_POINT};
|
||||
|
||||
EXPECT_TRUE(rlz_lib::GetPingParams(rlz_lib::TOOLBAR_NOTIFIER, points,
|
||||
cgi, 2048));
|
||||
EXPECT_STREQ("rep=2&rlz=T4:TbRlzValue", cgi);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::Set("dcc_value"));
|
||||
#define DCC_PARAM "&dcc=dcc_value"
|
||||
#else
|
||||
#define DCC_PARAM ""
|
||||
#endif
|
||||
|
||||
EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, ""));
|
||||
EXPECT_TRUE(rlz_lib::GetPingParams(rlz_lib::TOOLBAR_NOTIFIER, points,
|
||||
cgi, 2048));
|
||||
EXPECT_STREQ("rep=2&rlz=T4:" DCC_PARAM, cgi);
|
||||
|
||||
EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX,
|
||||
"TbRlzValue"));
|
||||
EXPECT_FALSE(rlz_lib::GetPingParams(rlz_lib::TOOLBAR_NOTIFIER, points,
|
||||
cgi, 23 + strlen(DCC_PARAM)));
|
||||
EXPECT_STREQ("", cgi);
|
||||
EXPECT_TRUE(rlz_lib::GetPingParams(rlz_lib::TOOLBAR_NOTIFIER, points,
|
||||
cgi, 24 + strlen(DCC_PARAM)));
|
||||
EXPECT_STREQ("rep=2&rlz=T4:TbRlzValue" DCC_PARAM, cgi);
|
||||
|
||||
EXPECT_TRUE(GetAccessPointRlz(rlz_lib::IE_HOME_PAGE, cgi, 2048));
|
||||
points[2] = rlz_lib::IE_HOME_PAGE;
|
||||
EXPECT_TRUE(rlz_lib::GetPingParams(rlz_lib::TOOLBAR_NOTIFIER, points,
|
||||
cgi, 2048));
|
||||
EXPECT_STREQ("rep=2&rlz=T4:TbRlzValue" DCC_PARAM, cgi);
|
||||
}
|
||||
|
||||
TEST_F(RlzLibTest, IsPingResponseValid) {
|
||||
const char* kBadPingResponses[] = {
|
||||
// No checksum.
|
||||
"version: 3.0.914.7250\r\n"
|
||||
"url: http://www.corp.google.com/~av/45/opt/SearchWithGoogleUpdate.exe\r\n"
|
||||
"launch-action: custom-action\r\n"
|
||||
"launch-target: SearchWithGoogleUpdate.exe\r\n"
|
||||
"signature: c08a3f4438e1442c4fe5678ee147cf6c5516e5d62bb64e\r\n"
|
||||
"rlz: 1R1_____en__252\r\n"
|
||||
"rlzXX: 1R1_____en__250\r\n",
|
||||
|
||||
// Invalid checksum.
|
||||
"version: 3.0.914.7250\r\n"
|
||||
"url: http://www.corp.google.com/~av/45/opt/SearchWithGoogleUpdate.exe\r\n"
|
||||
"launch-action: custom-action\r\n"
|
||||
"launch-target: SearchWithGoogleUpdate.exe\r\n"
|
||||
"signature: c08a3f4438e1442c4fe5678ee147cf6c5516e5d62bb64e\r\n"
|
||||
"rlz: 1R1_____en__252\r\n"
|
||||
"rlzXX: 1R1_____en__250\r\n"
|
||||
"rlzT4 1T4_____en__251\r\n"
|
||||
"rlzT4: 1T4_____en__252\r\n"
|
||||
"rlz\r\n"
|
||||
"crc32: B12CC79A",
|
||||
|
||||
// Misplaced checksum.
|
||||
"version: 3.0.914.7250\r\n"
|
||||
"url: http://www.corp.google.com/~av/45/opt/SearchWithGoogleUpdate.exe\r\n"
|
||||
"launch-action: custom-action\r\n"
|
||||
"launch-target: SearchWithGoogleUpdate.exe\r\n"
|
||||
"signature: c08a3f4438e1442c4fe5678ee147cf6c5516e5d62bb64e\r\n"
|
||||
"rlz: 1R1_____en__252\r\n"
|
||||
"rlzXX: 1R1_____en__250\r\n"
|
||||
"crc32: B12CC79C\r\n"
|
||||
"rlzT4 1T4_____en__251\r\n"
|
||||
"rlzT4: 1T4_____en__252\r\n"
|
||||
"rlz\r\n",
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* kGoodPingResponses[] = {
|
||||
"version: 3.0.914.7250\r\n"
|
||||
"url: http://www.corp.google.com/~av/45/opt/SearchWithGoogleUpdate.exe\r\n"
|
||||
"launch-action: custom-action\r\n"
|
||||
"launch-target: SearchWithGoogleUpdate.exe\r\n"
|
||||
"signature: c08a3f4438e1442c4fe5678ee147cf6c5516e5d62bb64e\r\n"
|
||||
"rlz: 1R1_____en__252\r\n"
|
||||
"rlzXX: 1R1_____en__250\r\n"
|
||||
"rlzT4 1T4_____en__251\r\n"
|
||||
"rlzT4: 1T4_____en__252\r\n"
|
||||
"rlz\r\n"
|
||||
"crc32: D6FD55A3",
|
||||
|
||||
"version: 3.0.914.7250\r\n"
|
||||
"url: http://www.corp.google.com/~av/45/opt/SearchWithGoogleUpdate.exe\r\n"
|
||||
"launch-action: custom-action\r\n"
|
||||
"launch-target: SearchWithGoogleUpdate.exe\r\n"
|
||||
"signature: c08a3f4438e1442c4fe5678ee147cf6c5516e5d62bb64e\r\n"
|
||||
"rlz: 1R1_____en__252\r\n"
|
||||
"rlzXX: 1R1_____en__250\r\n"
|
||||
"rlzT4 1T4_____en__251\r\n"
|
||||
"rlzT4: 1T4_____en__252\r\n"
|
||||
"rlz\r\n"
|
||||
"crc32: D6FD55A3\r\n"
|
||||
"extradata: not checksummed",
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
for (int i = 0; kBadPingResponses[i]; i++)
|
||||
EXPECT_FALSE(rlz_lib::IsPingResponseValid(kBadPingResponses[i], NULL));
|
||||
|
||||
for (int i = 0; kGoodPingResponses[i]; i++)
|
||||
EXPECT_TRUE(rlz_lib::IsPingResponseValid(kGoodPingResponses[i], NULL));
|
||||
}
|
||||
|
||||
TEST_F(RlzLibTest, ParsePingResponse) {
|
||||
const char* kPingResponse =
|
||||
"version: 3.0.914.7250\r\n"
|
||||
"url: http://www.corp.google.com/~av/45/opt/SearchWithGoogleUpdate.exe\r\n"
|
||||
"launch-action: custom-action\r\n"
|
||||
"launch-target: SearchWithGoogleUpdate.exe\r\n"
|
||||
"signature: c08a3f4438e1442c4fe5678ee147cf6c5516e5d62bb64e\r\n"
|
||||
"rlz: 1R1_____en__252\r\n" // Invalid RLZ - no access point.
|
||||
"rlzXX: 1R1_____en__250\r\n" // Invalid RLZ - bad access point.
|
||||
"rlzT4 1T4_____en__251\r\n" // Invalid RLZ - missing colon.
|
||||
"rlzT4: 1T4_____en__252\r\n" // GoodRLZ.
|
||||
"events: I7S,W1I\r\n" // Clear all events.
|
||||
"rlz\r\n"
|
||||
"dcc: dcc_value\r\n"
|
||||
"crc32: F9070F81";
|
||||
|
||||
#if defined(OS_WIN)
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::Set("dcc_value2"));
|
||||
#endif
|
||||
|
||||
// Record some product events to check that they get cleared.
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL));
|
||||
|
||||
EXPECT_TRUE(rlz_lib::SetAccessPointRlz(
|
||||
rlz_lib::IETB_SEARCH_BOX, "TbRlzValue"));
|
||||
|
||||
EXPECT_TRUE(rlz_lib::ParsePingResponse(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
kPingResponse));
|
||||
|
||||
#if defined(OS_WIN)
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::Set("dcc_value"));
|
||||
#endif
|
||||
EXPECT_TRUE(rlz_lib::ParsePingResponse(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
kPingResponse));
|
||||
|
||||
char value[50];
|
||||
EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, value, 50));
|
||||
EXPECT_STREQ("1T4_____en__252", value);
|
||||
EXPECT_FALSE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
value, 50));
|
||||
EXPECT_STREQ("", value);
|
||||
|
||||
const char* kPingResponse2 =
|
||||
"rlzT4: 1T4_____de__253 \r\n" // Good with extra spaces.
|
||||
"crc32: 321334F5\r\n";
|
||||
EXPECT_TRUE(rlz_lib::ParsePingResponse(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
kPingResponse2));
|
||||
EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, value, 50));
|
||||
EXPECT_STREQ("1T4_____de__253", value);
|
||||
|
||||
const char* kPingResponse3 =
|
||||
"crc32: 0\r\n"; // Good RLZ - empty response.
|
||||
EXPECT_TRUE(rlz_lib::ParsePingResponse(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
kPingResponse3));
|
||||
EXPECT_STREQ("1T4_____de__253", value);
|
||||
}
|
||||
|
||||
// Test whether a stateful event will only be sent in financial pings once.
|
||||
TEST_F(RlzLibTest, ParsePingResponseWithStatefulEvents) {
|
||||
const char* kPingResponse =
|
||||
"version: 3.0.914.7250\r\n"
|
||||
"url: http://www.corp.google.com/~av/45/opt/SearchWithGoogleUpdate.exe\r\n"
|
||||
"launch-action: custom-action\r\n"
|
||||
"launch-target: SearchWithGoogleUpdate.exe\r\n"
|
||||
"signature: c08a3f4438e1442c4fe5678ee147cf6c5516e5d62bb64e\r\n"
|
||||
"rlzT4: 1T4_____en__252\r\n" // GoodRLZ.
|
||||
"events: I7S,W1I\r\n" // Clear all events.
|
||||
"stateful-events: W1I\r\n" // W1I as an stateful event.
|
||||
"rlz\r\n"
|
||||
"dcc: dcc_value\r\n"
|
||||
"crc32: 55191759";
|
||||
|
||||
EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER));
|
||||
|
||||
// Record some product events to check that they get cleared.
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL));
|
||||
|
||||
EXPECT_TRUE(rlz_lib::SetAccessPointRlz(
|
||||
rlz_lib::IETB_SEARCH_BOX, "TbRlzValue"));
|
||||
|
||||
EXPECT_TRUE(rlz_lib::ParsePingResponse(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
kPingResponse));
|
||||
|
||||
// Check all the events sent earlier are cleared.
|
||||
char value[50];
|
||||
EXPECT_FALSE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
value, 50));
|
||||
EXPECT_STREQ("", value);
|
||||
|
||||
// Record both events (one is stateless and the other is stateful) again.
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL));
|
||||
|
||||
// Check the stateful event won't be sent again while the stateless one will.
|
||||
EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
value, 50));
|
||||
EXPECT_STREQ("events=I7S", value);
|
||||
|
||||
// Test that stateful events are cleared by ClearAllProductEvents(). After
|
||||
// calling it, trying to record a stateful again should result in it being
|
||||
// recorded again.
|
||||
EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL));
|
||||
EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
value, 50));
|
||||
EXPECT_STREQ("events=W1I", value);
|
||||
}
|
||||
|
||||
TEST_F(RlzLibTest, SendFinancialPing) {
|
||||
// We don't really check a value or result in this test. All this does is
|
||||
// attempt to ping the financial server, which you can verify in Fiddler.
|
||||
// TODO: Make this a measurable test.
|
||||
|
||||
#if defined(RLZ_NETWORK_IMPLEMENTATION_CHROME_NET)
|
||||
#if defined(OS_MACOSX)
|
||||
base::mac::ScopedNSAutoreleasePool pool;
|
||||
#endif
|
||||
|
||||
base::Thread::Options options;
|
||||
options.message_loop_type = MessageLoop::TYPE_IO;
|
||||
|
||||
base::Thread io_thread("rlz_unittest_io_thread");
|
||||
ASSERT_TRUE(io_thread.StartWithOptions(options));
|
||||
|
||||
scoped_refptr<TestURLRequestContextGetter> context =
|
||||
new TestURLRequestContextGetter(
|
||||
io_thread.message_loop()->message_loop_proxy());
|
||||
rlz_lib::SetURLRequestContext(context.get());
|
||||
|
||||
class URLRequestRAII {
|
||||
public:
|
||||
URLRequestRAII(net::URLRequestContextGetter* context) {
|
||||
rlz_lib::SetURLRequestContext(context);
|
||||
}
|
||||
~URLRequestRAII() {
|
||||
rlz_lib::SetURLRequestContext(NULL);
|
||||
}
|
||||
};
|
||||
|
||||
URLRequestRAII set_context(context.get());
|
||||
#endif
|
||||
|
||||
MachineDealCodeHelper::Clear();
|
||||
#if defined(OS_WIN)
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::Set("dcc_value"));
|
||||
#endif
|
||||
|
||||
EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX,
|
||||
"TbRlzValue"));
|
||||
|
||||
EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL));
|
||||
|
||||
rlz_lib::AccessPoint points[] =
|
||||
{rlz_lib::IETB_SEARCH_BOX, rlz_lib::NO_ACCESS_POINT,
|
||||
rlz_lib::NO_ACCESS_POINT};
|
||||
|
||||
std::string request;
|
||||
rlz_lib::SendFinancialPing(rlz_lib::TOOLBAR_NOTIFIER, points,
|
||||
"swg", "GGLA", "SwgProductId1234", "en-UK", false,
|
||||
/*skip_time_check=*/true);
|
||||
}
|
||||
|
||||
TEST_F(RlzLibTest, ClearProductState) {
|
||||
MachineDealCodeHelper::Clear();
|
||||
|
||||
EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX,
|
||||
"TbRlzValue"));
|
||||
EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::GD_DESKBAND,
|
||||
"GdbRlzValue"));
|
||||
|
||||
rlz_lib::AccessPoint points[] =
|
||||
{ rlz_lib::IETB_SEARCH_BOX, rlz_lib::NO_ACCESS_POINT };
|
||||
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IETB_SEARCH_BOX, rlz_lib::INSTALL));
|
||||
|
||||
rlz_lib::AccessPoint points2[] =
|
||||
{ rlz_lib::IETB_SEARCH_BOX,
|
||||
rlz_lib::GD_DESKBAND,
|
||||
rlz_lib::NO_ACCESS_POINT };
|
||||
|
||||
char cgi[2048];
|
||||
EXPECT_TRUE(rlz_lib::GetPingParams(rlz_lib::TOOLBAR_NOTIFIER, points2,
|
||||
cgi, 2048));
|
||||
EXPECT_STREQ("rep=2&rlz=T4:TbRlzValue,D1:GdbRlzValue", cgi);
|
||||
|
||||
EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
cgi, 2048));
|
||||
std::string events(cgi);
|
||||
EXPECT_LT(0u, events.find("I7S"));
|
||||
EXPECT_LT(0u, events.find("T4I"));
|
||||
EXPECT_LT(0u, events.find("T4R"));
|
||||
|
||||
rlz_lib::ClearProductState(rlz_lib::TOOLBAR_NOTIFIER, points);
|
||||
|
||||
EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX,
|
||||
cgi, 2048));
|
||||
EXPECT_STREQ("", cgi);
|
||||
EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::GD_DESKBAND,
|
||||
cgi, 2048));
|
||||
EXPECT_STREQ("GdbRlzValue", cgi);
|
||||
|
||||
EXPECT_FALSE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
cgi, 2048));
|
||||
EXPECT_STREQ("", cgi);
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
template<class T>
|
||||
class typed_buffer_ptr {
|
||||
scoped_array<char> buffer_;
|
||||
|
||||
public:
|
||||
typed_buffer_ptr() {
|
||||
}
|
||||
|
||||
explicit typed_buffer_ptr(size_t size) : buffer_(new char[size]) {
|
||||
}
|
||||
|
||||
void reset(size_t size) {
|
||||
buffer_.reset(new char[size]);
|
||||
}
|
||||
|
||||
operator T*() {
|
||||
return reinterpret_cast<T*>(buffer_.get());
|
||||
}
|
||||
};
|
||||
|
||||
namespace rlz_lib {
|
||||
bool HasAccess(PSID sid, ACCESS_MASK access_mask, ACL* dacl);
|
||||
}
|
||||
|
||||
bool EmptyAcl(ACL* acl) {
|
||||
ACL_SIZE_INFORMATION info;
|
||||
bool ret = GetAclInformation(acl, &info, sizeof(info), AclSizeInformation);
|
||||
EXPECT_TRUE(ret);
|
||||
|
||||
for (DWORD i = 0; i < info.AceCount && ret; ++i) {
|
||||
ret = DeleteAce(acl, 0);
|
||||
EXPECT_TRUE(ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
TEST_F(RlzLibTest, HasAccess) {
|
||||
// Create a SID that represents ALL USERS.
|
||||
DWORD users_sid_size = SECURITY_MAX_SID_SIZE;
|
||||
typed_buffer_ptr<SID> users_sid(users_sid_size);
|
||||
CreateWellKnownSid(WinBuiltinUsersSid, NULL, users_sid, &users_sid_size);
|
||||
|
||||
// RLZ always asks for KEY_ALL_ACCESS access to the key. This is what we
|
||||
// test here.
|
||||
|
||||
// No ACL mean no access.
|
||||
EXPECT_FALSE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, NULL));
|
||||
|
||||
// Create an ACL for these tests.
|
||||
const DWORD kMaxAclSize = 1024;
|
||||
typed_buffer_ptr<ACL> dacl(kMaxAclSize);
|
||||
InitializeAcl(dacl, kMaxAclSize, ACL_REVISION);
|
||||
|
||||
// Empty DACL mean no access.
|
||||
EXPECT_FALSE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl));
|
||||
|
||||
// ACE without all needed privileges should mean no access.
|
||||
EXPECT_TRUE(AddAccessAllowedAce(dacl, ACL_REVISION, KEY_READ, users_sid));
|
||||
EXPECT_FALSE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl));
|
||||
|
||||
// ACE without all needed privileges should mean no access.
|
||||
EXPECT_TRUE(EmptyAcl(dacl));
|
||||
EXPECT_TRUE(AddAccessAllowedAce(dacl, ACL_REVISION, KEY_WRITE, users_sid));
|
||||
EXPECT_FALSE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl));
|
||||
|
||||
// A deny ACE before an allow ACE should not give access.
|
||||
EXPECT_TRUE(EmptyAcl(dacl));
|
||||
EXPECT_TRUE(AddAccessDeniedAce(dacl, ACL_REVISION, KEY_ALL_ACCESS,
|
||||
users_sid));
|
||||
EXPECT_TRUE(AddAccessAllowedAce(dacl, ACL_REVISION, KEY_ALL_ACCESS,
|
||||
users_sid));
|
||||
EXPECT_FALSE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl));
|
||||
|
||||
// A deny ACE before an allow ACE should not give access.
|
||||
EXPECT_TRUE(EmptyAcl(dacl));
|
||||
EXPECT_TRUE(AddAccessDeniedAce(dacl, ACL_REVISION, KEY_READ, users_sid));
|
||||
EXPECT_TRUE(AddAccessAllowedAce(dacl, ACL_REVISION, KEY_ALL_ACCESS,
|
||||
users_sid));
|
||||
EXPECT_FALSE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl));
|
||||
|
||||
|
||||
// An allow ACE without all required bits should not give access.
|
||||
EXPECT_TRUE(EmptyAcl(dacl));
|
||||
EXPECT_TRUE(AddAccessAllowedAce(dacl, ACL_REVISION, KEY_WRITE, users_sid));
|
||||
EXPECT_FALSE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl));
|
||||
|
||||
// An allow ACE with all required bits should give access.
|
||||
EXPECT_TRUE(EmptyAcl(dacl));
|
||||
EXPECT_TRUE(AddAccessAllowedAce(dacl, ACL_REVISION, KEY_ALL_ACCESS,
|
||||
users_sid));
|
||||
EXPECT_TRUE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl));
|
||||
|
||||
// A deny ACE after an allow ACE should not give access.
|
||||
EXPECT_TRUE(EmptyAcl(dacl));
|
||||
EXPECT_TRUE(AddAccessAllowedAce(dacl, ACL_REVISION, KEY_ALL_ACCESS,
|
||||
users_sid));
|
||||
EXPECT_TRUE(AddAccessDeniedAce(dacl, ACL_REVISION, KEY_READ, users_sid));
|
||||
EXPECT_TRUE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl));
|
||||
|
||||
// An inherit-only allow ACE should not give access.
|
||||
EXPECT_TRUE(EmptyAcl(dacl));
|
||||
EXPECT_TRUE(AddAccessAllowedAceEx(dacl, ACL_REVISION, INHERIT_ONLY_ACE,
|
||||
KEY_ALL_ACCESS, users_sid));
|
||||
EXPECT_FALSE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl));
|
||||
|
||||
// An inherit-only deny ACE should not apply.
|
||||
EXPECT_TRUE(EmptyAcl(dacl));
|
||||
EXPECT_TRUE(AddAccessDeniedAceEx(dacl, ACL_REVISION, INHERIT_ONLY_ACE,
|
||||
KEY_ALL_ACCESS, users_sid));
|
||||
EXPECT_TRUE(AddAccessAllowedAce(dacl, ACL_REVISION, KEY_ALL_ACCESS,
|
||||
users_sid));
|
||||
EXPECT_TRUE(rlz_lib::HasAccess(users_sid, KEY_ALL_ACCESS, dacl));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(RlzLibTest, BrandingRecordProductEvent) {
|
||||
// Don't run these tests if a supplementary brand is already in place. That
|
||||
// way we can control the branding.
|
||||
if (!rlz_lib::SupplementaryBranding::GetBrand().empty())
|
||||
return;
|
||||
|
||||
char cgi_50[50];
|
||||
|
||||
// Record different events for the same product with diffrent branding, and
|
||||
// make sure that the information remains separate.
|
||||
EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER));
|
||||
{
|
||||
rlz_lib::SupplementaryBranding branding("TEST");
|
||||
EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER));
|
||||
}
|
||||
|
||||
// Test that recording events with the default brand and a supplementary
|
||||
// brand don't overwrite each other.
|
||||
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
cgi_50, 50));
|
||||
EXPECT_STREQ("events=I7S", cgi_50);
|
||||
|
||||
{
|
||||
rlz_lib::SupplementaryBranding branding("TEST");
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::INSTALL));
|
||||
EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
cgi_50, 50));
|
||||
EXPECT_STREQ("events=I7I", cgi_50);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
cgi_50, 50));
|
||||
EXPECT_STREQ("events=I7S", cgi_50);
|
||||
}
|
||||
|
||||
TEST_F(RlzLibTest, BrandingSetAccessPointRlz) {
|
||||
// Don't run these tests if a supplementary brand is already in place. That
|
||||
// way we can control the branding.
|
||||
if (!rlz_lib::SupplementaryBranding::GetBrand().empty())
|
||||
return;
|
||||
|
||||
char rlz_50[50];
|
||||
|
||||
// Test that setting RLZ strings with the default brand and a supplementary
|
||||
// brand don't overwrite each other.
|
||||
|
||||
EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, "IeTbRlz"));
|
||||
EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, rlz_50, 50));
|
||||
EXPECT_STREQ("IeTbRlz", rlz_50);
|
||||
|
||||
{
|
||||
rlz_lib::SupplementaryBranding branding("TEST");
|
||||
|
||||
EXPECT_TRUE(rlz_lib::SetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, "SuppRlz"));
|
||||
EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, rlz_50,
|
||||
50));
|
||||
EXPECT_STREQ("SuppRlz", rlz_50);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(rlz_lib::GetAccessPointRlz(rlz_lib::IETB_SEARCH_BOX, rlz_50, 50));
|
||||
EXPECT_STREQ("IeTbRlz", rlz_50);
|
||||
|
||||
}
|
||||
|
||||
TEST_F(RlzLibTest, BrandingWithStatefulEvents) {
|
||||
// Don't run these tests if a supplementary brand is already in place. That
|
||||
// way we can control the branding.
|
||||
if (!rlz_lib::SupplementaryBranding::GetBrand().empty())
|
||||
return;
|
||||
|
||||
const char* kPingResponse =
|
||||
"version: 3.0.914.7250\r\n"
|
||||
"url: http://www.corp.google.com/~av/45/opt/SearchWithGoogleUpdate.exe\r\n"
|
||||
"launch-action: custom-action\r\n"
|
||||
"launch-target: SearchWithGoogleUpdate.exe\r\n"
|
||||
"signature: c08a3f4438e1442c4fe5678ee147cf6c5516e5d62bb64e\r\n"
|
||||
"rlzT4: 1T4_____en__252\r\n" // GoodRLZ.
|
||||
"events: I7S,W1I\r\n" // Clear all events.
|
||||
"stateful-events: W1I\r\n" // W1I as an stateful event.
|
||||
"rlz\r\n"
|
||||
"dcc: dcc_value\r\n"
|
||||
"crc32: 55191759";
|
||||
|
||||
EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER));
|
||||
{
|
||||
rlz_lib::SupplementaryBranding branding("TEST");
|
||||
EXPECT_TRUE(rlz_lib::ClearAllProductEvents(rlz_lib::TOOLBAR_NOTIFIER));
|
||||
}
|
||||
|
||||
// Record some product events for the default and supplementary brand.
|
||||
// Check that they get cleared only for the default brand.
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL));
|
||||
|
||||
{
|
||||
rlz_lib::SupplementaryBranding branding("TEST");
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL));
|
||||
}
|
||||
|
||||
EXPECT_TRUE(rlz_lib::ParsePingResponse(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
kPingResponse));
|
||||
|
||||
// Check all the events sent earlier are cleared only for default brand.
|
||||
char value[50];
|
||||
EXPECT_FALSE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
value, 50));
|
||||
EXPECT_STREQ("", value);
|
||||
|
||||
{
|
||||
rlz_lib::SupplementaryBranding branding("TEST");
|
||||
EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
value, 50));
|
||||
EXPECT_STREQ("events=I7S,W1I", value);
|
||||
}
|
||||
|
||||
// Record both events (one is stateless and the other is stateful) again.
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_HOME_PAGE, rlz_lib::INSTALL));
|
||||
|
||||
// Check the stateful event won't be sent again while the stateless one will.
|
||||
EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
value, 50));
|
||||
EXPECT_STREQ("events=I7S", value);
|
||||
|
||||
{
|
||||
rlz_lib::SupplementaryBranding branding("TEST");
|
||||
EXPECT_TRUE(rlz_lib::ParsePingResponse(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
kPingResponse));
|
||||
|
||||
EXPECT_FALSE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
value, 50));
|
||||
EXPECT_STREQ("", value);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(rlz_lib::GetProductEventsAsCgi(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
value, 50));
|
||||
EXPECT_STREQ("events=I7S", value);
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
class ReadonlyRlzDirectoryTest : public RlzLibTestNoMachineState {
|
||||
protected:
|
||||
virtual void SetUp() OVERRIDE;
|
||||
};
|
||||
|
||||
void ReadonlyRlzDirectoryTest::SetUp() {
|
||||
RlzLibTestNoMachineState::SetUp();
|
||||
// Make the rlz directory non-writeable.
|
||||
chmod(temp_dir_.path().value().c_str(), 0500);
|
||||
}
|
||||
|
||||
TEST_F(ReadonlyRlzDirectoryTest, WriteFails) {
|
||||
// The rlz test runner runs every test twice: Once normally, and once with
|
||||
// a SupplementaryBranding on the stack. In the latter case, the rlz lock
|
||||
// has already been acquired before the rlz directory got changed to
|
||||
// read-only, which makes this test pointless. So run it only in the first
|
||||
// pass.
|
||||
if (!rlz_lib::SupplementaryBranding::GetBrand().empty())
|
||||
return;
|
||||
|
||||
EXPECT_FALSE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::SET_TO_GOOGLE));
|
||||
}
|
||||
|
||||
// Regression test for http://crbug.com/121255
|
||||
TEST_F(ReadonlyRlzDirectoryTest, SupplementaryBrandingDoesNotCrash) {
|
||||
// See the comment at the top of WriteFails.
|
||||
if (!rlz_lib::SupplementaryBranding::GetBrand().empty())
|
||||
return;
|
||||
|
||||
rlz_lib::SupplementaryBranding branding("TEST");
|
||||
EXPECT_FALSE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER,
|
||||
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::INSTALL));
|
||||
}
|
||||
#endif
|
116
rlz/lib/rlz_value_store.h
Normal file
116
rlz/lib/rlz_value_store.h
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef RLZ_VALUE_STORE_H_
|
||||
#define RLZ_VALUE_STORE_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "rlz/lib/rlz_enums.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "rlz/win/lib/lib_mutex.h"
|
||||
#endif
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#include "base/mac/scoped_nsautorelease_pool.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class FilePath;
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
// Abstracts away rlz's key value store. On windows, this usually writes to
|
||||
// the registry. On mac, it writes to an NSDefaults object.
|
||||
class RlzValueStore {
|
||||
public:
|
||||
virtual ~RlzValueStore() {}
|
||||
|
||||
enum AccessType { kReadAccess, kWriteAccess };
|
||||
virtual bool HasAccess(AccessType type) = 0;
|
||||
|
||||
// Ping times.
|
||||
virtual bool WritePingTime(Product product, int64 time) = 0;
|
||||
virtual bool ReadPingTime(Product product, int64* time) = 0;
|
||||
virtual bool ClearPingTime(Product product) = 0;
|
||||
|
||||
// Access point RLZs.
|
||||
virtual bool WriteAccessPointRlz(AccessPoint access_point,
|
||||
const char* new_rlz) = 0;
|
||||
virtual bool ReadAccessPointRlz(AccessPoint access_point,
|
||||
char* rlz, // At most kMaxRlzLength + 1 bytes
|
||||
size_t rlz_size) = 0;
|
||||
virtual bool ClearAccessPointRlz(AccessPoint access_point) = 0;
|
||||
|
||||
// Product events.
|
||||
// Stores |event_rlz| for product |product| as product event.
|
||||
virtual bool AddProductEvent(Product product, const char* event_rlz) = 0;
|
||||
// Appends all events for |product| to |events|, in arbirtrary order.
|
||||
virtual bool ReadProductEvents(Product product,
|
||||
std::vector<std::string>* events) = 0;
|
||||
// Removes the stored event |event_rlz| for |product| if it exists.
|
||||
virtual bool ClearProductEvent(Product product, const char* event_rlz) = 0;
|
||||
// Removes all stored product events for |product|.
|
||||
virtual bool ClearAllProductEvents(Product product) = 0;
|
||||
|
||||
// Stateful events.
|
||||
// Stores |event_rlz| for product |product| as stateful event.
|
||||
virtual bool AddStatefulEvent(Product product, const char* event_rlz) = 0;
|
||||
// Checks if |event_rlz| has been stored as stateful event for |product|.
|
||||
virtual bool IsStatefulEvent(Product product, const char* event_rlz) = 0;
|
||||
// Removes all stored stateful events for |product|.
|
||||
virtual bool ClearAllStatefulEvents(Product product) = 0;
|
||||
|
||||
// Tells the value store to clean up unimportant internal data structures, for
|
||||
// example empty registry folders, that might remain after clearing other
|
||||
// data. Best-effort.
|
||||
virtual void CollectGarbage() = 0;
|
||||
};
|
||||
|
||||
// All methods of RlzValueStore must stays consistent even when accessed from
|
||||
// multiple threads in multiple processes. To enforce this through the type
|
||||
// system, the only way to access the RlzValueStore is through a
|
||||
// ScopedRlzValueStoreLock, which is a cross-process lock. It is active while
|
||||
// it is in scope. If the class fails to acquire a lock, its GetStore() method
|
||||
// returns NULL. If the lock fails to be acquired, it must not be taken
|
||||
// recursively. That is, all user code should look like this:
|
||||
// ScopedRlzValueStoreLock lock;
|
||||
// RlzValueStore* store = lock.GetStore();
|
||||
// if (!store)
|
||||
// return some_error_code;
|
||||
// ...
|
||||
class ScopedRlzValueStoreLock {
|
||||
public:
|
||||
ScopedRlzValueStoreLock();
|
||||
~ScopedRlzValueStoreLock();
|
||||
|
||||
// Returns a RlzValueStore protected by a cross-process lock, or NULL if the
|
||||
// lock can't be obtained. The lifetime of the returned object is limited to
|
||||
// the lifetime of this ScopedRlzValueStoreLock object.
|
||||
RlzValueStore* GetStore();
|
||||
|
||||
private:
|
||||
scoped_ptr<RlzValueStore> store_;
|
||||
#if defined(OS_WIN)
|
||||
LibMutex lock_;
|
||||
#else
|
||||
base::mac::ScopedNSAutoreleasePool autorelease_pool_;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
namespace testing {
|
||||
// Prefix |directory| to the path where the RLZ data file lives, for tests.
|
||||
void SetRlzStoreDirectory(const FilePath& directory);
|
||||
} // namespace testing
|
||||
#endif // defined(OS_MACOSX)
|
||||
|
||||
|
||||
} // namespace rlz_lib
|
||||
|
||||
#endif // RLZ_VALUE_STORE_H_
|
92
rlz/lib/string_utils.cc
Normal file
92
rlz/lib/string_utils.cc
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// String manipulation functions used in the RLZ library.
|
||||
|
||||
#include "rlz/lib/string_utils.h"
|
||||
|
||||
#include "rlz/lib/assert.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
bool IsAscii(char letter) {
|
||||
return (letter >= 0x0 && letter < 0x80);
|
||||
}
|
||||
|
||||
bool GetHexValue(char letter, int* value) {
|
||||
if (!value) {
|
||||
ASSERT_STRING("GetHexValue: Invalid output paramter");
|
||||
return false;
|
||||
}
|
||||
*value = 0;
|
||||
|
||||
if (letter >= '0' && letter <= '9')
|
||||
*value = letter - '0';
|
||||
else if (letter >= 'a' && letter <= 'f')
|
||||
*value = (letter - 'a') + 0xA;
|
||||
else if (letter >= 'A' && letter <= 'F')
|
||||
*value = (letter - 'A') + 0xA;
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int HexStringToInteger(const char* text) {
|
||||
if (!text) {
|
||||
ASSERT_STRING("HexStringToInteger: text is NULL.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int idx = 0;
|
||||
// Ignore leading whitespace.
|
||||
while (text[idx] == '\t' || text[idx] == ' ')
|
||||
idx++;
|
||||
|
||||
if ((text[idx] == '0') &&
|
||||
(text[idx + 1] == 'X' || text[idx + 1] == 'x'))
|
||||
idx +=2; // String is of the form 0x...
|
||||
|
||||
int number = 0;
|
||||
int digit = 0;
|
||||
for (; text[idx] != '\0'; idx++) {
|
||||
if (!GetHexValue(text[idx], &digit)) {
|
||||
// Ignore trailing whitespaces, but assert on other trailing characters.
|
||||
bool only_whitespaces = true;
|
||||
while (only_whitespaces && text[idx])
|
||||
only_whitespaces = (text[idx++] == ' ');
|
||||
if (!only_whitespaces)
|
||||
ASSERT_STRING("HexStringToInteger: text contains non-hex characters.");
|
||||
return number;
|
||||
}
|
||||
number = (number << 4) | digit;
|
||||
}
|
||||
|
||||
return number;
|
||||
}
|
||||
|
||||
bool BytesToString(const unsigned char* data,
|
||||
int data_len,
|
||||
std::string* string) {
|
||||
if (!string)
|
||||
return false;
|
||||
|
||||
string->clear();
|
||||
if (data_len < 1 || !data)
|
||||
return false;
|
||||
|
||||
static const char kHex[] = "0123456789ABCDEF";
|
||||
|
||||
// Fix the buffer size to begin with to avoid repeated re-allocation.
|
||||
string->resize(data_len * 2);
|
||||
int index = data_len;
|
||||
while (index--) {
|
||||
string->at(2 * index) = kHex[data[index] >> 4]; // high digit
|
||||
string->at(2 * index + 1) = kHex[data[index] & 0x0F]; // low digit
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rlz_lib
|
26
rlz/lib/string_utils.h
Normal file
26
rlz/lib/string_utils.h
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// String manipulation functions used in the RLZ library.
|
||||
|
||||
#ifndef RLZ_LIB_STRING_UTILS_H_
|
||||
#define RLZ_LIB_STRING_UTILS_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
bool IsAscii(char letter);
|
||||
|
||||
bool BytesToString(const unsigned char* data,
|
||||
int data_len,
|
||||
std::string* string);
|
||||
|
||||
bool GetHexValue(char letter, int* value);
|
||||
|
||||
int HexStringToInteger(const char* text);
|
||||
|
||||
}; // namespace
|
||||
|
||||
#endif // RLZ_LIB_STRING_UTILS_H_
|
69
rlz/lib/string_utils_unittest.cc
Normal file
69
rlz/lib/string_utils_unittest.cc
Normal file
@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Unit test for string manipulation functions used in the RLZ library.
|
||||
|
||||
#include "rlz/lib/string_utils.h"
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/utf_string_conversions.h"
|
||||
#include "rlz/lib/assert.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
TEST(StringUtilsUnittest, IsAscii) {
|
||||
rlz_lib::SetExpectedAssertion("");
|
||||
|
||||
char bad_letters[] = {'\x80', '\xA0', '\xFF'};
|
||||
for (size_t i = 0; i < arraysize(bad_letters); ++i)
|
||||
EXPECT_FALSE(rlz_lib::IsAscii(bad_letters[i]));
|
||||
|
||||
char good_letters[] = {'A', '~', '\n', 0x7F, 0x00};
|
||||
for (size_t i = 0; i < arraysize(good_letters); ++i)
|
||||
EXPECT_TRUE(rlz_lib::IsAscii(good_letters[i]));
|
||||
}
|
||||
|
||||
TEST(StringUtilsUnittest, HexStringToInteger) {
|
||||
rlz_lib::SetExpectedAssertion("HexStringToInteger: text is NULL.");
|
||||
EXPECT_EQ(0, rlz_lib::HexStringToInteger(NULL));
|
||||
|
||||
rlz_lib::SetExpectedAssertion("");
|
||||
EXPECT_EQ(0, rlz_lib::HexStringToInteger(""));
|
||||
EXPECT_EQ(0, rlz_lib::HexStringToInteger(" "));
|
||||
EXPECT_EQ(0, rlz_lib::HexStringToInteger(" 0x "));
|
||||
EXPECT_EQ(0, rlz_lib::HexStringToInteger(" 0x0 "));
|
||||
EXPECT_EQ(0x12345, rlz_lib::HexStringToInteger("12345"));
|
||||
EXPECT_EQ(0xa34Ed0, rlz_lib::HexStringToInteger("a34Ed0"));
|
||||
EXPECT_EQ(0xa34Ed0, rlz_lib::HexStringToInteger("0xa34Ed0"));
|
||||
EXPECT_EQ(0xa34Ed0, rlz_lib::HexStringToInteger(" 0xa34Ed0"));
|
||||
EXPECT_EQ(0xa34Ed0, rlz_lib::HexStringToInteger("0xa34Ed0 "));
|
||||
EXPECT_EQ(0xa34Ed0, rlz_lib::HexStringToInteger(" 0xa34Ed0 "));
|
||||
EXPECT_EQ(0xa34Ed0, rlz_lib::HexStringToInteger(" 0x000a34Ed0 "));
|
||||
EXPECT_EQ(0xa34Ed0, rlz_lib::HexStringToInteger(" 000a34Ed0 "));
|
||||
|
||||
rlz_lib::SetExpectedAssertion(
|
||||
"HexStringToInteger: text contains non-hex characters.");
|
||||
EXPECT_EQ(0x12ff, rlz_lib::HexStringToInteger("12ffg"));
|
||||
EXPECT_EQ(0x12f, rlz_lib::HexStringToInteger("12f 121"));
|
||||
EXPECT_EQ(0x12f, rlz_lib::HexStringToInteger("12f 121"));
|
||||
EXPECT_EQ(0, rlz_lib::HexStringToInteger("g12f"));
|
||||
EXPECT_EQ(0, rlz_lib::HexStringToInteger(" 0x0 \n"));
|
||||
|
||||
rlz_lib::SetExpectedAssertion("");
|
||||
}
|
||||
|
||||
TEST(StringUtilsUnittest, TestBytesToString) {
|
||||
unsigned char data[] = {0x1E, 0x00, 0x21, 0x67, 0xFF};
|
||||
std::string result;
|
||||
|
||||
EXPECT_FALSE(rlz_lib::BytesToString(NULL, 5, &result));
|
||||
EXPECT_FALSE(rlz_lib::BytesToString(data, 5, NULL));
|
||||
EXPECT_FALSE(rlz_lib::BytesToString(NULL, 5, NULL));
|
||||
|
||||
EXPECT_TRUE(rlz_lib::BytesToString(data, 5, &result));
|
||||
EXPECT_EQ(std::string("1E002167FF"), result);
|
||||
EXPECT_TRUE(rlz_lib::BytesToString(data, 4, &result));
|
||||
EXPECT_EQ(std::string("1E002167"), result);
|
||||
}
|
147
rlz/mac/lib/machine_id_mac.cc
Normal file
147
rlz/mac/lib/machine_id_mac.cc
Normal file
@ -0,0 +1,147 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/network/IOEthernetInterface.h>
|
||||
#include <IOKit/network/IONetworkInterface.h>
|
||||
#include <IOKit/network/IOEthernetController.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/mac/foundation_util.h"
|
||||
#include "base/mac/scoped_cftyperef.h"
|
||||
#include "base/mac/scoped_ioobject.h"
|
||||
#include "base/string16.h"
|
||||
#include "base/stringprintf.h"
|
||||
#include "base/sys_string_conversions.h"
|
||||
#include "base/utf_string_conversions.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
namespace {
|
||||
|
||||
// See http://developer.apple.com/library/mac/#technotes/tn1103/_index.html
|
||||
|
||||
// The caller is responsible for freeing |matching_services|.
|
||||
bool FindEthernetInterfaces(io_iterator_t* matching_services) {
|
||||
base::mac::ScopedCFTypeRef<CFMutableDictionaryRef> matching_dict(
|
||||
IOServiceMatching(kIOEthernetInterfaceClass));
|
||||
if (!matching_dict)
|
||||
return false;
|
||||
|
||||
base::mac::ScopedCFTypeRef<CFMutableDictionaryRef> primary_interface(
|
||||
CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks));
|
||||
if (!primary_interface)
|
||||
return false;
|
||||
|
||||
CFDictionarySetValue(
|
||||
primary_interface, CFSTR(kIOPrimaryInterface), kCFBooleanTrue);
|
||||
CFDictionarySetValue(
|
||||
matching_dict, CFSTR(kIOPropertyMatchKey), primary_interface);
|
||||
|
||||
kern_return_t kern_result = IOServiceGetMatchingServices(
|
||||
kIOMasterPortDefault, matching_dict.release(), matching_services);
|
||||
|
||||
return kern_result == KERN_SUCCESS;
|
||||
}
|
||||
|
||||
bool GetMACAddressFromIterator(io_iterator_t primary_interface_iterator,
|
||||
uint8_t* buffer, size_t buffer_size) {
|
||||
if (buffer_size < kIOEthernetAddressSize)
|
||||
return false;
|
||||
|
||||
bool success = false;
|
||||
|
||||
bzero(buffer, buffer_size);
|
||||
base::mac::ScopedIOObject<io_object_t> primary_interface;
|
||||
while (primary_interface.reset(IOIteratorNext(primary_interface_iterator)),
|
||||
primary_interface) {
|
||||
io_object_t primary_interface_parent;
|
||||
kern_return_t kern_result = IORegistryEntryGetParentEntry(
|
||||
primary_interface, kIOServicePlane, &primary_interface_parent);
|
||||
base::mac::ScopedIOObject<io_object_t> primary_interface_parent_deleter(
|
||||
primary_interface_parent);
|
||||
success = kern_result == KERN_SUCCESS;
|
||||
|
||||
if (!success)
|
||||
continue;
|
||||
|
||||
base::mac::ScopedCFTypeRef<CFTypeRef> mac_data(
|
||||
IORegistryEntryCreateCFProperty(primary_interface_parent,
|
||||
CFSTR(kIOMACAddress),
|
||||
kCFAllocatorDefault,
|
||||
0));
|
||||
CFDataRef mac_data_data = base::mac::CFCast<CFDataRef>(mac_data);
|
||||
if (mac_data_data) {
|
||||
CFDataGetBytes(
|
||||
mac_data_data, CFRangeMake(0, kIOEthernetAddressSize), buffer);
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GetMacAddress(unsigned char* buffer, size_t size) {
|
||||
io_iterator_t primary_interface_iterator;
|
||||
if (!FindEthernetInterfaces(&primary_interface_iterator))
|
||||
return false;
|
||||
bool result = GetMACAddressFromIterator(
|
||||
primary_interface_iterator, buffer, size);
|
||||
IOObjectRelease(primary_interface_iterator);
|
||||
return result;
|
||||
}
|
||||
|
||||
CFStringRef CopySerialNumber() {
|
||||
base::mac::ScopedIOObject<io_service_t> expert_device(
|
||||
IOServiceGetMatchingService(kIOMasterPortDefault,
|
||||
IOServiceMatching("IOPlatformExpertDevice")));
|
||||
if (!expert_device)
|
||||
return NULL;
|
||||
|
||||
base::mac::ScopedCFTypeRef<CFTypeRef> serial_number(
|
||||
IORegistryEntryCreateCFProperty(expert_device,
|
||||
CFSTR(kIOPlatformSerialNumberKey),
|
||||
kCFAllocatorDefault,
|
||||
0));
|
||||
CFStringRef serial_number_cfstring =
|
||||
base::mac::CFCast<CFStringRef>(serial_number);
|
||||
if (!serial_number_cfstring)
|
||||
return NULL;
|
||||
|
||||
ignore_result(serial_number.release());
|
||||
return serial_number_cfstring;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool GetRawMachineId(string16* data, int* more_data) {
|
||||
uint8_t mac_address[kIOEthernetAddressSize];
|
||||
|
||||
data->clear();
|
||||
if (GetMacAddress(mac_address, sizeof(mac_address))) {
|
||||
*data += ASCIIToUTF16(StringPrintf("mac:%02x%02x%02x%02x%02x%02x",
|
||||
mac_address[0], mac_address[1], mac_address[2],
|
||||
mac_address[3], mac_address[4], mac_address[5]));
|
||||
}
|
||||
|
||||
// A MAC address is enough to uniquely identify a machine, but it's only 6
|
||||
// bytes, 3 of which are manufacturer-determined. To make brute-forcing the
|
||||
// SHA1 of this harder, also append the system's serial number.
|
||||
CFStringRef serial = CopySerialNumber();
|
||||
if (serial) {
|
||||
if (!data->empty())
|
||||
*data += UTF8ToUTF16(" ");
|
||||
*data += UTF8ToUTF16("serial:") + base::SysCFStringRefToUTF16(serial);
|
||||
CFRelease(serial);
|
||||
}
|
||||
|
||||
// On windows, this is set to the volume id. Since it's not scrambled before
|
||||
// being sent, just set it to 1.
|
||||
*more_data = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rlz_lib
|
80
rlz/mac/lib/rlz_value_store_mac.h
Normal file
80
rlz/mac/lib/rlz_value_store_mac.h
Normal file
@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef RLZ_MAC_LIB_RLZ_VALUE_STORE_MAC_H_
|
||||
#define RLZ_MAC_LIB_RLZ_VALUE_STORE_MAC_H_
|
||||
|
||||
#include "rlz/lib/rlz_value_store.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/memory/scoped_nsobject.h"
|
||||
|
||||
@class NSDictionary;
|
||||
@class NSMutableDictionary;
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
// An implementation of RlzValueStore for mac. It stores information in a
|
||||
// plist file in the user's Application Support folder.
|
||||
class RlzValueStoreMac : public RlzValueStore {
|
||||
public:
|
||||
virtual bool HasAccess(AccessType type) OVERRIDE;
|
||||
|
||||
virtual bool WritePingTime(Product product, int64 time) OVERRIDE;
|
||||
virtual bool ReadPingTime(Product product, int64* time) OVERRIDE;
|
||||
virtual bool ClearPingTime(Product product) OVERRIDE;
|
||||
|
||||
virtual bool WriteAccessPointRlz(AccessPoint access_point,
|
||||
const char* new_rlz) OVERRIDE;
|
||||
virtual bool ReadAccessPointRlz(AccessPoint access_point,
|
||||
char* rlz,
|
||||
size_t rlz_size) OVERRIDE;
|
||||
virtual bool ClearAccessPointRlz(AccessPoint access_point) OVERRIDE;
|
||||
|
||||
virtual bool AddProductEvent(Product product, const char* event_rlz) OVERRIDE;
|
||||
virtual bool ReadProductEvents(Product product,
|
||||
std::vector<std::string>* events) OVERRIDE;
|
||||
virtual bool ClearProductEvent(Product product,
|
||||
const char* event_rlz) OVERRIDE;
|
||||
virtual bool ClearAllProductEvents(Product product) OVERRIDE;
|
||||
|
||||
virtual bool AddStatefulEvent(Product product,
|
||||
const char* event_rlz) OVERRIDE;
|
||||
virtual bool IsStatefulEvent(Product product,
|
||||
const char* event_rlz) OVERRIDE;
|
||||
virtual bool ClearAllStatefulEvents(Product product) OVERRIDE;
|
||||
|
||||
virtual void CollectGarbage() OVERRIDE;
|
||||
|
||||
private:
|
||||
// |dict| is the dictionary that backs all data. plist_path is the name of the
|
||||
// plist file, used solely for implementing HasAccess().
|
||||
RlzValueStoreMac(NSMutableDictionary* dict, NSString* plist_path);
|
||||
virtual ~RlzValueStoreMac();
|
||||
friend class ScopedRlzValueStoreLock;
|
||||
|
||||
// Returns the backing dictionary that should be written to disk.
|
||||
NSDictionary* dictionary();
|
||||
|
||||
// Returns the dictionary to which all data should be written. Usually, this
|
||||
// is just |dictionary()|, but if supplementary branding is used, it's a
|
||||
// subdirectory at key "brand_<supplementary branding code>".
|
||||
// Note that windows stores data at
|
||||
// rlz/name (e.g. "pingtime")/supplementalbranding/productcode
|
||||
// Mac on the other hand does
|
||||
// supplementalbranding/productcode/pingtime.
|
||||
NSMutableDictionary* WorkingDict();
|
||||
|
||||
// Returns the subdirectory of |WorkingDict()| used to store data for
|
||||
// product p.
|
||||
NSMutableDictionary* ProductDict(Product p);
|
||||
|
||||
scoped_nsobject<NSMutableDictionary> dict_;
|
||||
scoped_nsobject<NSString> plist_path_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RlzValueStoreMac);
|
||||
};
|
||||
|
||||
} // namespace rlz_lib
|
||||
|
||||
#endif // RLZ_MAC_LIB_RLZ_VALUE_STORE_MAC_H_
|
447
rlz/mac/lib/rlz_value_store_mac.mm
Normal file
447
rlz/mac/lib/rlz_value_store_mac.mm
Normal file
@ -0,0 +1,447 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "rlz/mac/lib/rlz_value_store_mac.h"
|
||||
|
||||
#include "base/mac/foundation_util.h"
|
||||
#include "base/file_path.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/sys_string_conversions.h"
|
||||
#include "rlz/lib/assert.h"
|
||||
#include "rlz/lib/lib_values.h"
|
||||
#include "rlz/lib/rlz_lib.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <pthread.h>
|
||||
|
||||
using base::mac::ObjCCast;
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
// These are written to disk and should not be changed.
|
||||
NSString* const kPingTimeKey = @"pingTime";
|
||||
NSString* const kAccessPointKey = @"accessPoints";
|
||||
NSString* const kProductEventKey = @"productEvents";
|
||||
NSString* const kStatefulEventKey = @"statefulEvents";
|
||||
|
||||
namespace {
|
||||
|
||||
NSString* GetNSProductName(Product product) {
|
||||
return base::SysUTF8ToNSString(GetProductName(product));
|
||||
}
|
||||
|
||||
NSString* GetNSAccessPointName(AccessPoint p) {
|
||||
return base::SysUTF8ToNSString(GetAccessPointName(p));
|
||||
}
|
||||
|
||||
// Retrieves a subdictionary in |p| for key |k|, creating it if necessary.
|
||||
// If the dictionary contains an object for |k| that is not a mutable
|
||||
// dictionary, that object is replaced with an empty mutable dictinary.
|
||||
NSMutableDictionary* GetOrCreateDict(
|
||||
NSMutableDictionary* p, NSString* k) {
|
||||
NSMutableDictionary* d = ObjCCast<NSMutableDictionary>([p objectForKey:k]);
|
||||
if (!d) {
|
||||
d = [NSMutableDictionary dictionaryWithCapacity:0];
|
||||
[p setObject:d forKey:k];
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RlzValueStoreMac::RlzValueStoreMac(NSMutableDictionary* dict,
|
||||
NSString* plist_path)
|
||||
: dict_([dict retain]), plist_path_([plist_path retain]) {
|
||||
}
|
||||
|
||||
RlzValueStoreMac::~RlzValueStoreMac() {
|
||||
}
|
||||
|
||||
bool RlzValueStoreMac::HasAccess(AccessType type) {
|
||||
NSFileManager* manager = [NSFileManager defaultManager];
|
||||
switch (type) {
|
||||
case kReadAccess: return [manager isReadableFileAtPath:plist_path_];
|
||||
case kWriteAccess: return [manager isWritableFileAtPath:plist_path_];
|
||||
}
|
||||
}
|
||||
|
||||
bool RlzValueStoreMac::WritePingTime(Product product, int64 time) {
|
||||
NSNumber* n = [NSNumber numberWithLongLong:time];
|
||||
[ProductDict(product) setObject:n forKey:kPingTimeKey];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RlzValueStoreMac::ReadPingTime(Product product, int64* time) {
|
||||
if (NSNumber* n =
|
||||
ObjCCast<NSNumber>([ProductDict(product) objectForKey:kPingTimeKey])) {
|
||||
*time = [n longLongValue];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RlzValueStoreMac::ClearPingTime(Product product) {
|
||||
[ProductDict(product) removeObjectForKey:kPingTimeKey];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool RlzValueStoreMac::WriteAccessPointRlz(AccessPoint access_point,
|
||||
const char* new_rlz) {
|
||||
NSMutableDictionary* d = GetOrCreateDict(WorkingDict(), kAccessPointKey);
|
||||
[d setObject:base::SysUTF8ToNSString(new_rlz)
|
||||
forKey:GetNSAccessPointName(access_point)];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RlzValueStoreMac::ReadAccessPointRlz(AccessPoint access_point,
|
||||
char* rlz,
|
||||
size_t rlz_size) {
|
||||
// Reading a non-existent access point counts as success.
|
||||
if (NSDictionary* d = ObjCCast<NSDictionary>(
|
||||
[WorkingDict() objectForKey:kAccessPointKey])) {
|
||||
NSString* val = ObjCCast<NSString>(
|
||||
[d objectForKey:GetNSAccessPointName(access_point)]);
|
||||
if (!val) {
|
||||
if (rlz_size > 0)
|
||||
rlz[0] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string s = base::SysNSStringToUTF8(val);
|
||||
if (s.size() >= rlz_size) {
|
||||
rlz[0] = 0;
|
||||
ASSERT_STRING("GetAccessPointRlz: Insufficient buffer size");
|
||||
return false;
|
||||
}
|
||||
strncpy(rlz, s.c_str(), rlz_size);
|
||||
return true;
|
||||
}
|
||||
if (rlz_size > 0)
|
||||
rlz[0] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RlzValueStoreMac::ClearAccessPointRlz(AccessPoint access_point) {
|
||||
if (NSMutableDictionary* d = ObjCCast<NSMutableDictionary>(
|
||||
[WorkingDict() objectForKey:kAccessPointKey])) {
|
||||
[d removeObjectForKey:GetNSAccessPointName(access_point)];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool RlzValueStoreMac::AddProductEvent(Product product,
|
||||
const char* event_rlz) {
|
||||
[GetOrCreateDict(ProductDict(product), kProductEventKey)
|
||||
setObject:[NSNumber numberWithBool:YES]
|
||||
forKey:base::SysUTF8ToNSString(event_rlz)];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RlzValueStoreMac::ReadProductEvents(Product product,
|
||||
std::vector<std::string>* events) {
|
||||
if (NSDictionary* d = ObjCCast<NSDictionary>(
|
||||
[ProductDict(product) objectForKey:kProductEventKey])) {
|
||||
for (NSString* s in d)
|
||||
events->push_back(base::SysNSStringToUTF8(s));
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RlzValueStoreMac::ClearProductEvent(Product product,
|
||||
const char* event_rlz) {
|
||||
if (NSMutableDictionary* d = ObjCCast<NSMutableDictionary>(
|
||||
[ProductDict(product) objectForKey:kProductEventKey])) {
|
||||
[d removeObjectForKey:base::SysUTF8ToNSString(event_rlz)];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RlzValueStoreMac::ClearAllProductEvents(Product product) {
|
||||
[ProductDict(product) removeObjectForKey:kProductEventKey];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool RlzValueStoreMac::AddStatefulEvent(Product product,
|
||||
const char* event_rlz) {
|
||||
[GetOrCreateDict(ProductDict(product), kStatefulEventKey)
|
||||
setObject:[NSNumber numberWithBool:YES]
|
||||
forKey:base::SysUTF8ToNSString(event_rlz)];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RlzValueStoreMac::IsStatefulEvent(Product product,
|
||||
const char* event_rlz) {
|
||||
if (NSDictionary* d = ObjCCast<NSDictionary>(
|
||||
[ProductDict(product) objectForKey:kStatefulEventKey])) {
|
||||
return [d objectForKey:base::SysUTF8ToNSString(event_rlz)] != nil;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RlzValueStoreMac::ClearAllStatefulEvents(Product product) {
|
||||
[ProductDict(product) removeObjectForKey:kStatefulEventKey];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void RlzValueStoreMac::CollectGarbage() {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
NSDictionary* RlzValueStoreMac::dictionary() {
|
||||
return dict_.get();
|
||||
}
|
||||
|
||||
NSMutableDictionary* RlzValueStoreMac::WorkingDict() {
|
||||
std::string brand(SupplementaryBranding::GetBrand());
|
||||
if (brand.empty())
|
||||
return dict_;
|
||||
|
||||
NSString* brand_ns =
|
||||
[@"brand_" stringByAppendingString:base::SysUTF8ToNSString(brand)];
|
||||
|
||||
return GetOrCreateDict(dict_.get(), brand_ns);
|
||||
}
|
||||
|
||||
NSMutableDictionary* RlzValueStoreMac::ProductDict(Product p) {
|
||||
return GetOrCreateDict(WorkingDict(), GetNSProductName(p));
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
// Creating a recursive cross-process mutex on windows is one line. On mac,
|
||||
// there's no primitve for that, so this lock is emulated by an in-process
|
||||
// mutex to get the recursive part, followed by a cross-process lock for the
|
||||
// cross-process part.
|
||||
|
||||
// This is a struct so that it doesn't need a static initializer.
|
||||
struct RecursiveCrossProcessLock {
|
||||
// Tries to acquire a recursive cross-process lock. Note that this _always_
|
||||
// acquires the in-process lock (if it wasn't already acquired). The parent
|
||||
// directory of |lock_file| must exist.
|
||||
bool TryGetCrossProcessLock(NSString* lock_filename);
|
||||
|
||||
// Releases the lock. Should always be called, even if
|
||||
// TryGetCrossProcessLock() returns false.
|
||||
void ReleaseLock();
|
||||
|
||||
pthread_mutex_t recursive_lock_;
|
||||
pthread_t locking_thread_;
|
||||
|
||||
NSDistributedLock* file_lock_;
|
||||
} g_recursive_lock = {
|
||||
// PTHREAD_RECURSIVE_MUTEX_INITIALIZER doesn't exist before 10.7 and is buggy
|
||||
// on 10.7 (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51906#c34), so emulate
|
||||
// recursive locking with a normal non-recursive mutex.
|
||||
PTHREAD_MUTEX_INITIALIZER
|
||||
};
|
||||
|
||||
bool RecursiveCrossProcessLock::TryGetCrossProcessLock(
|
||||
NSString* lock_filename) {
|
||||
bool just_got_lock = false;
|
||||
|
||||
// Emulate a recursive mutex with a non-recursive one.
|
||||
if (pthread_mutex_trylock(&recursive_lock_) == EBUSY) {
|
||||
if (pthread_equal(pthread_self(), locking_thread_) == 0) {
|
||||
// Some other thread has the lock, wait for it.
|
||||
pthread_mutex_lock(&recursive_lock_);
|
||||
CHECK(locking_thread_ == 0);
|
||||
just_got_lock = true;
|
||||
}
|
||||
} else {
|
||||
just_got_lock = true;
|
||||
}
|
||||
|
||||
locking_thread_ = pthread_self();
|
||||
|
||||
// Try to acquire file lock.
|
||||
if (just_got_lock) {
|
||||
const int kMaxTimeoutMS = 5000; // Matches windows.
|
||||
const int kSleepPerTryMS = 200;
|
||||
|
||||
CHECK(!file_lock_);
|
||||
file_lock_ = [[NSDistributedLock alloc] initWithPath:lock_filename];
|
||||
|
||||
BOOL got_file_lock = NO;
|
||||
int elapsedMS = 0;
|
||||
while (!(got_file_lock = [file_lock_ tryLock]) &&
|
||||
elapsedMS < kMaxTimeoutMS) {
|
||||
usleep(kSleepPerTryMS * 1000);
|
||||
elapsedMS += kSleepPerTryMS;
|
||||
}
|
||||
|
||||
if (!got_file_lock) {
|
||||
[file_lock_ release];
|
||||
file_lock_ = nil;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return file_lock_ != nil;
|
||||
}
|
||||
}
|
||||
|
||||
void RecursiveCrossProcessLock::ReleaseLock() {
|
||||
if (file_lock_) {
|
||||
[file_lock_ unlock];
|
||||
[file_lock_ release];
|
||||
file_lock_ = nil;
|
||||
}
|
||||
|
||||
locking_thread_ = 0;
|
||||
pthread_mutex_unlock(&recursive_lock_);
|
||||
}
|
||||
|
||||
|
||||
// This is set during test execution, to write RLZ files into a temporary
|
||||
// directory instead of the user's Application Support folder.
|
||||
NSString* g_test_folder;
|
||||
|
||||
// RlzValueStoreMac keeps its data in memory and only writes it to disk when
|
||||
// ScopedRlzValueStoreLock goes out of scope. Hence, if several
|
||||
// ScopedRlzValueStoreLocks are nested, they all need to use the same store
|
||||
// object.
|
||||
|
||||
// This counts the nesting depth.
|
||||
int g_lock_depth = 0;
|
||||
|
||||
// This is the store object that might be shared. Only set if g_lock_depth > 0.
|
||||
RlzValueStoreMac* g_store_object = NULL;
|
||||
|
||||
|
||||
NSString* CreateRlzDirectory() {
|
||||
NSFileManager* manager = [NSFileManager defaultManager];
|
||||
NSArray* paths = NSSearchPathForDirectoriesInDomains(
|
||||
NSApplicationSupportDirectory, NSUserDomainMask, /*expandTilde=*/YES);
|
||||
NSString* folder = nil;
|
||||
if ([paths count] > 0)
|
||||
folder = ObjCCast<NSString>([paths objectAtIndex:0]);
|
||||
if (!folder)
|
||||
folder = [@"~/Library/Application Support" stringByStandardizingPath];
|
||||
folder = [folder stringByAppendingPathComponent:@"Google/RLZ"];
|
||||
|
||||
if (g_test_folder)
|
||||
folder = [g_test_folder stringByAppendingPathComponent:folder];
|
||||
|
||||
[manager createDirectoryAtPath:folder
|
||||
withIntermediateDirectories:YES
|
||||
attributes:nil
|
||||
error:nil];
|
||||
return folder;
|
||||
}
|
||||
|
||||
// Returns the path of the rlz plist store, also creates the parent directory
|
||||
// path if it doesn't exist.
|
||||
NSString* RlzPlistFilename() {
|
||||
NSString* const kRlzFile = @"RlzStore.plist";
|
||||
return [CreateRlzDirectory() stringByAppendingPathComponent:kRlzFile];
|
||||
}
|
||||
|
||||
// Returns the path of the rlz lock file, also creates the parent directory
|
||||
// path if it doesn't exist.
|
||||
NSString* RlzLockFilename() {
|
||||
NSString* const kRlzFile = @"lockfile";
|
||||
return [CreateRlzDirectory() stringByAppendingPathComponent:kRlzFile];
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ScopedRlzValueStoreLock::ScopedRlzValueStoreLock() {
|
||||
bool got_distributed_lock =
|
||||
g_recursive_lock.TryGetCrossProcessLock(RlzLockFilename());
|
||||
// At this point, we hold the in-process lock, no matter the value of
|
||||
// |got_distributed_lock|.
|
||||
|
||||
++g_lock_depth;
|
||||
|
||||
if (!got_distributed_lock) {
|
||||
// Give up. |store_| isn't set, which signals to callers that acquiring
|
||||
// the lock failed. |g_recursive_lock| will be released by the
|
||||
// destructor.
|
||||
CHECK(!g_store_object);
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_lock_depth > 1) {
|
||||
// Reuse the already existing store object.
|
||||
CHECK(g_store_object);
|
||||
store_.reset(g_store_object);
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK(!g_store_object);
|
||||
|
||||
NSString* plist = RlzPlistFilename();
|
||||
|
||||
// Create an empty file if none exists yet.
|
||||
NSFileManager* manager = [NSFileManager defaultManager];
|
||||
if (![manager fileExistsAtPath:plist isDirectory:NULL])
|
||||
[[NSDictionary dictionary] writeToFile:plist atomically:YES];
|
||||
|
||||
NSMutableDictionary* dict =
|
||||
[NSMutableDictionary dictionaryWithContentsOfFile:plist];
|
||||
VERIFY(dict);
|
||||
|
||||
if (dict) {
|
||||
store_.reset(new RlzValueStoreMac(dict, plist));
|
||||
g_store_object = (RlzValueStoreMac*)store_.get();
|
||||
}
|
||||
}
|
||||
|
||||
ScopedRlzValueStoreLock::~ScopedRlzValueStoreLock() {
|
||||
--g_lock_depth;
|
||||
CHECK(g_lock_depth >= 0);
|
||||
|
||||
if (g_lock_depth > 0) {
|
||||
// Other locks are still using store_, don't free it yet.
|
||||
ignore_result(store_.release());
|
||||
return;
|
||||
}
|
||||
|
||||
if (store_.get()) {
|
||||
g_store_object = NULL;
|
||||
|
||||
NSDictionary* dict =
|
||||
static_cast<RlzValueStoreMac*>(store_.get())->dictionary();
|
||||
VERIFY([dict writeToFile:RlzPlistFilename() atomically:YES]);
|
||||
}
|
||||
|
||||
// Check that "store_ set" => "file_lock acquired". The converse isn't true,
|
||||
// for example if the rlz data file can't be read.
|
||||
if (store_.get())
|
||||
CHECK(g_recursive_lock.file_lock_);
|
||||
if (!g_recursive_lock.file_lock_)
|
||||
CHECK(!store_.get());
|
||||
|
||||
g_recursive_lock.ReleaseLock();
|
||||
}
|
||||
|
||||
RlzValueStore* ScopedRlzValueStoreLock::GetStore() {
|
||||
return store_.get();
|
||||
}
|
||||
|
||||
namespace testing {
|
||||
|
||||
void SetRlzStoreDirectory(const FilePath& directory) {
|
||||
base::mac::ScopedNSAutoreleasePool pool;
|
||||
|
||||
[g_test_folder release];
|
||||
if (directory.empty()) {
|
||||
g_test_folder = nil;
|
||||
} else {
|
||||
// Not Unsafe on OS X.
|
||||
g_test_folder =
|
||||
[[NSString alloc] initWithUTF8String:directory.AsUTF8Unsafe().c_str()];
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
} // namespace rlz_lib
|
151
rlz/rlz.gyp
Normal file
151
rlz/rlz.gyp
Normal file
@ -0,0 +1,151 @@
|
||||
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
{
|
||||
'variables': {
|
||||
'chromium_code': 1,
|
||||
'variables': {
|
||||
# Set force_rlz_use_chrome_net to 1 to use chrome's network stack instead
|
||||
# of win inet.
|
||||
'force_rlz_use_chrome_net%': 0,
|
||||
},
|
||||
'conditions': [
|
||||
['force_rlz_use_chrome_net or OS=="mac"', {
|
||||
'rlz_use_chrome_net%': 1,
|
||||
}, {
|
||||
'rlz_use_chrome_net%': 0,
|
||||
}],
|
||||
],
|
||||
},
|
||||
'target_defaults': {
|
||||
'include_dirs': [
|
||||
'..',
|
||||
],
|
||||
},
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'rlz_lib',
|
||||
'type': 'static_library',
|
||||
'include_dirs': [],
|
||||
'dependencies': [
|
||||
'../base/base.gyp:base',
|
||||
'../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
|
||||
],
|
||||
'sources': [
|
||||
'lib/assert.cc',
|
||||
'lib/assert.h',
|
||||
'lib/crc32.h',
|
||||
'lib/crc32_wrapper.cc',
|
||||
'lib/crc8.h',
|
||||
'lib/crc8.cc',
|
||||
'lib/financial_ping.cc',
|
||||
'lib/financial_ping.h',
|
||||
'lib/lib_values.cc',
|
||||
'lib/machine_id.cc',
|
||||
'lib/machine_id.h',
|
||||
'lib/rlz_enums.h',
|
||||
'lib/rlz_lib.cc',
|
||||
'lib/rlz_lib.h',
|
||||
'lib/rlz_lib_clear.cc',
|
||||
'lib/lib_values.h',
|
||||
'lib/rlz_value_store.h',
|
||||
'lib/string_utils.cc',
|
||||
'lib/string_utils.h',
|
||||
'mac/lib/machine_id_mac.cc',
|
||||
'mac/lib/rlz_value_store_mac.mm',
|
||||
'mac/lib/rlz_value_store_mac.h',
|
||||
'win/lib/lib_mutex.cc',
|
||||
'win/lib/lib_mutex.h',
|
||||
'win/lib/machine_deal.cc',
|
||||
'win/lib/machine_deal.h',
|
||||
'win/lib/machine_id_win.cc',
|
||||
'win/lib/process_info.cc',
|
||||
'win/lib/process_info.h',
|
||||
'win/lib/registry_util.cc',
|
||||
'win/lib/registry_util.h',
|
||||
'win/lib/rlz_lib.h',
|
||||
'win/lib/rlz_lib_win.cc',
|
||||
'win/lib/rlz_value_store_registry.cc',
|
||||
'win/lib/rlz_value_store_registry.h',
|
||||
'win/lib/vista_winnt.h',
|
||||
],
|
||||
'conditions': [
|
||||
['rlz_use_chrome_net==1', {
|
||||
'defines': [
|
||||
'RLZ_NETWORK_IMPLEMENTATION_CHROME_NET',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'defines': [
|
||||
'RLZ_NETWORK_IMPLEMENTATION_CHROME_NET',
|
||||
],
|
||||
},
|
||||
'dependencies': [
|
||||
'../build/temp_gyp/googleurl.gyp:googleurl',
|
||||
'../net/net.gyp:net',
|
||||
],
|
||||
}, {
|
||||
'defines': [
|
||||
'RLZ_NETWORK_IMPLEMENTATION_WIN_INET',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'defines': [
|
||||
'RLZ_NETWORK_IMPLEMENTATION_WIN_INET',
|
||||
],
|
||||
},
|
||||
}],
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'rlz_unittests',
|
||||
'type': 'executable',
|
||||
'include_dirs': [],
|
||||
'dependencies': [
|
||||
':rlz_lib',
|
||||
'../base/base.gyp:base',
|
||||
'../testing/gmock.gyp:gmock',
|
||||
'../testing/gtest.gyp:gtest',
|
||||
'../third_party/zlib/zlib.gyp:zlib',
|
||||
],
|
||||
'sources': [
|
||||
'lib/crc32_unittest.cc',
|
||||
'lib/crc8_unittest.cc',
|
||||
'lib/financial_ping_test.cc',
|
||||
'lib/lib_values_unittest.cc',
|
||||
'lib/machine_id_unittest.cc',
|
||||
'lib/rlz_lib_test.cc',
|
||||
'lib/string_utils_unittest.cc',
|
||||
'test/rlz_test_helpers.cc',
|
||||
'test/rlz_test_helpers.h',
|
||||
'test/rlz_unittest_main.cc',
|
||||
'win/lib/machine_deal_test.cc',
|
||||
],
|
||||
'conditions': [
|
||||
['rlz_use_chrome_net==1', {
|
||||
'dependencies': [
|
||||
'../net/net.gyp:net_test_support',
|
||||
],
|
||||
}]
|
||||
],
|
||||
},
|
||||
],
|
||||
'conditions': [
|
||||
['OS=="win"', {
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'rlz',
|
||||
'type': 'shared_library',
|
||||
'include_dirs': [],
|
||||
'sources': [
|
||||
'win/dll/dll_main.cc',
|
||||
'win/dll/exports.cc',
|
||||
],
|
||||
'dependencies': [
|
||||
':rlz_lib',
|
||||
'../third_party/zlib/zlib.gyp:zlib',
|
||||
],
|
||||
},
|
||||
],
|
||||
}],
|
||||
],
|
||||
}
|
86
rlz/test/rlz_test_helpers.cc
Normal file
86
rlz/test/rlz_test_helpers.cc
Normal file
@ -0,0 +1,86 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Main entry point for all unit tests.
|
||||
|
||||
#include "rlz_test_helpers.h"
|
||||
|
||||
#include "rlz/lib/rlz_lib.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <shlwapi.h>
|
||||
#include "base/win/registry.h"
|
||||
#include "rlz/win/lib/rlz_lib.h"
|
||||
#elif defined(OS_MACOSX)
|
||||
#include "base/file_path.h"
|
||||
#include "rlz/lib/rlz_value_store.h"
|
||||
#endif
|
||||
|
||||
#if defined(OS_WIN)
|
||||
namespace {
|
||||
|
||||
const wchar_t* kHKCUReplacement = L"Software\\Google\\RlzUtilUnittest\\HKCU";
|
||||
const wchar_t* kHKLMReplacement = L"Software\\Google\\RlzUtilUnittest\\HKLM";
|
||||
|
||||
void OverrideRegistryHives() {
|
||||
// Wipe the keys we redirect to.
|
||||
// This gives us a stable run, even in the presence of previous
|
||||
// crashes or failures.
|
||||
LSTATUS err = SHDeleteKey(HKEY_CURRENT_USER, kHKCUReplacement);
|
||||
EXPECT_TRUE(err == ERROR_SUCCESS || err == ERROR_FILE_NOT_FOUND);
|
||||
err = SHDeleteKey(HKEY_CURRENT_USER, kHKLMReplacement);
|
||||
EXPECT_TRUE(err == ERROR_SUCCESS || err == ERROR_FILE_NOT_FOUND);
|
||||
|
||||
// Create the keys we're redirecting HKCU and HKLM to.
|
||||
base::win::RegKey hkcu;
|
||||
base::win::RegKey hklm;
|
||||
ASSERT_EQ(ERROR_SUCCESS,
|
||||
hkcu.Create(HKEY_CURRENT_USER, kHKCUReplacement, KEY_READ));
|
||||
ASSERT_EQ(ERROR_SUCCESS,
|
||||
hklm.Create(HKEY_CURRENT_USER, kHKLMReplacement, KEY_READ));
|
||||
|
||||
rlz_lib::InitializeTempHivesForTesting(hklm, hkcu);
|
||||
|
||||
// And do the switcharoo.
|
||||
ASSERT_EQ(ERROR_SUCCESS,
|
||||
::RegOverridePredefKey(HKEY_CURRENT_USER, hkcu.Handle()));
|
||||
ASSERT_EQ(ERROR_SUCCESS,
|
||||
::RegOverridePredefKey(HKEY_LOCAL_MACHINE, hklm.Handle()));
|
||||
}
|
||||
|
||||
void UndoOverrideRegistryHives() {
|
||||
// Undo the redirection.
|
||||
EXPECT_EQ(ERROR_SUCCESS, ::RegOverridePredefKey(HKEY_CURRENT_USER, NULL));
|
||||
EXPECT_EQ(ERROR_SUCCESS, ::RegOverridePredefKey(HKEY_LOCAL_MACHINE, NULL));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
|
||||
void RlzLibTestNoMachineState::SetUp() {
|
||||
#if defined(OS_WIN)
|
||||
OverrideRegistryHives();
|
||||
#elif defined(OS_MACOSX)
|
||||
base::mac::ScopedNSAutoreleasePool pool;
|
||||
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
|
||||
rlz_lib::testing::SetRlzStoreDirectory(temp_dir_.path());
|
||||
#endif // defined(OS_WIN)
|
||||
}
|
||||
|
||||
void RlzLibTestNoMachineState::TearDown() {
|
||||
#if defined(OS_WIN)
|
||||
UndoOverrideRegistryHives();
|
||||
#elif defined(OS_MACOSX)
|
||||
rlz_lib::testing::SetRlzStoreDirectory(FilePath());
|
||||
#endif // defined(OS_WIN)
|
||||
}
|
||||
|
||||
void RlzLibTestBase::SetUp() {
|
||||
RlzLibTestNoMachineState::SetUp();
|
||||
#if defined(OS_WIN)
|
||||
rlz_lib::CreateMachineState();
|
||||
#endif // defined(OS_WIN)
|
||||
}
|
33
rlz/test/rlz_test_helpers.h
Normal file
33
rlz/test/rlz_test_helpers.h
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Helper functions used by the tests.
|
||||
|
||||
#ifndef RLZ_TEST_RLZ_TEST_HELPERS_H
|
||||
#define RLZ_TEST_RLZ_TEST_HELPERS_H
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#include "base/scoped_temp_dir.h"
|
||||
#endif
|
||||
|
||||
class RlzLibTestNoMachineState : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() OVERRIDE;
|
||||
virtual void TearDown() OVERRIDE;
|
||||
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
ScopedTempDir temp_dir_;
|
||||
#endif
|
||||
};
|
||||
|
||||
class RlzLibTestBase : public RlzLibTestNoMachineState {
|
||||
virtual void SetUp() OVERRIDE;
|
||||
};
|
||||
|
||||
|
||||
#endif // RLZ_TEST_RLZ_TEST_HELPERS_H
|
29
rlz/test/rlz_unittest_main.cc
Normal file
29
rlz/test/rlz_unittest_main.cc
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Main entry point for all unit tests.
|
||||
|
||||
#include "base/at_exit.h"
|
||||
#include "base/command_line.h"
|
||||
#include "rlz/lib/rlz_lib.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
base::AtExitManager at_exit;
|
||||
CommandLine::Init(argc, argv);
|
||||
|
||||
testing::InitGoogleMock(&argc, argv);
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
int ret = RUN_ALL_TESTS();
|
||||
if (ret == 0) {
|
||||
// Now re-run all the tests using a supplementary brand code. This brand
|
||||
// code will remain in effect for the lifetime of the branding object.
|
||||
rlz_lib::SupplementaryBranding branding("TEST");
|
||||
ret = RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
15
rlz/win/dll/dll_main.cc
Normal file
15
rlz/win/dll/dll_main.cc
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Main function for the RLZ DLL.
|
||||
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
BOOL APIENTRY DllMain(HANDLE module, DWORD reason, LPVOID reserved) {
|
||||
return TRUE;
|
||||
}
|
||||
|
108
rlz/win/dll/exports.cc
Normal file
108
rlz/win/dll/exports.cc
Normal file
@ -0,0 +1,108 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Functions exported by the RLZ DLL.
|
||||
|
||||
#include "rlz/win/lib/rlz_lib.h"
|
||||
|
||||
#define RLZ_DLL_EXPORT extern "C" __declspec(dllexport)
|
||||
|
||||
RLZ_DLL_EXPORT bool RecordProductEvent(rlz_lib::Product product,
|
||||
rlz_lib::AccessPoint point,
|
||||
rlz_lib::Event event_id) {
|
||||
return rlz_lib::RecordProductEvent(product, point, event_id);
|
||||
}
|
||||
|
||||
RLZ_DLL_EXPORT bool GetProductEventsAsCgi(rlz_lib::Product product,
|
||||
char* unescaped_cgi,
|
||||
size_t unescaped_cgi_size) {
|
||||
return rlz_lib::GetProductEventsAsCgi(product, unescaped_cgi,
|
||||
unescaped_cgi_size);
|
||||
}
|
||||
RLZ_DLL_EXPORT bool ClearAllProductEvents(rlz_lib::Product product) {
|
||||
return rlz_lib::ClearAllProductEvents(product);
|
||||
}
|
||||
|
||||
RLZ_DLL_EXPORT bool ClearProductEvent(rlz_lib::Product product,
|
||||
rlz_lib::AccessPoint point,
|
||||
rlz_lib::Event event_id) {
|
||||
return rlz_lib::ClearProductEvent(product, point, event_id);
|
||||
}
|
||||
|
||||
RLZ_DLL_EXPORT bool GetAccessPointRlz(rlz_lib::AccessPoint point,
|
||||
char* rlz,
|
||||
size_t rlz_size) {
|
||||
return rlz_lib::GetAccessPointRlz(point, rlz, rlz_size);
|
||||
}
|
||||
|
||||
RLZ_DLL_EXPORT bool SetAccessPointRlz(rlz_lib::AccessPoint point,
|
||||
const char* new_rlz) {
|
||||
return rlz_lib::SetAccessPointRlz(point, new_rlz);
|
||||
}
|
||||
|
||||
RLZ_DLL_EXPORT bool CreateMachineState() {
|
||||
return rlz_lib::CreateMachineState();
|
||||
}
|
||||
|
||||
RLZ_DLL_EXPORT bool SetMachineDealCode(const char* dcc) {
|
||||
return rlz_lib::SetMachineDealCode(dcc);
|
||||
}
|
||||
|
||||
RLZ_DLL_EXPORT bool GetMachineDealCodeAsCgi(char* cgi, size_t cgi_size) {
|
||||
return rlz_lib::GetMachineDealCodeAsCgi(cgi, cgi_size);
|
||||
}
|
||||
|
||||
RLZ_DLL_EXPORT bool GetMachineDealCode2(char* dcc, size_t dcc_size) {
|
||||
return rlz_lib::GetMachineDealCode(dcc, dcc_size);
|
||||
}
|
||||
|
||||
RLZ_DLL_EXPORT bool GetPingParams(rlz_lib::Product product,
|
||||
const rlz_lib::AccessPoint* access_points,
|
||||
char* unescaped_cgi,
|
||||
size_t unescaped_cgi_size) {
|
||||
return rlz_lib::GetPingParams(product, access_points, unescaped_cgi,
|
||||
unescaped_cgi_size);
|
||||
}
|
||||
|
||||
RLZ_DLL_EXPORT bool ParsePingResponse(rlz_lib::Product product,
|
||||
const char* response) {
|
||||
return rlz_lib::ParsePingResponse(product, response);
|
||||
}
|
||||
|
||||
RLZ_DLL_EXPORT bool IsPingResponseValid(const char* response,
|
||||
int* checksum_idx) {
|
||||
return rlz_lib::IsPingResponseValid(response, checksum_idx);
|
||||
}
|
||||
|
||||
RLZ_DLL_EXPORT bool SetMachineDealCodeFromPingResponse(const char* response) {
|
||||
return rlz_lib::SetMachineDealCodeFromPingResponse(response);
|
||||
}
|
||||
|
||||
RLZ_DLL_EXPORT bool SendFinancialPing(rlz_lib::Product product,
|
||||
const rlz_lib::AccessPoint* access_points,
|
||||
const char* product_signature,
|
||||
const char* product_brand,
|
||||
const char* product_id,
|
||||
const char* product_lang,
|
||||
bool exclude_machine_id) {
|
||||
return rlz_lib::SendFinancialPing(product, access_points, product_signature,
|
||||
product_brand, product_id, product_lang, exclude_machine_id);
|
||||
}
|
||||
|
||||
RLZ_DLL_EXPORT bool SendFinancialPingNoDelay(
|
||||
rlz_lib::Product product,
|
||||
const rlz_lib::AccessPoint* access_points,
|
||||
const char* product_signature,
|
||||
const char* product_brand,
|
||||
const char* product_id,
|
||||
const char* product_lang,
|
||||
bool exclude_machine_id) {
|
||||
return rlz_lib::SendFinancialPing(product, access_points, product_signature,
|
||||
product_brand, product_id, product_lang, exclude_machine_id, true);
|
||||
}
|
||||
|
||||
RLZ_DLL_EXPORT void ClearProductState(
|
||||
rlz_lib::Product product, const rlz_lib::AccessPoint* access_points) {
|
||||
return rlz_lib::ClearProductState(product, access_points);
|
||||
}
|
67
rlz/win/lib/lib_mutex.cc
Normal file
67
rlz/win/lib/lib_mutex.cc
Normal file
@ -0,0 +1,67 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Mutex to guarantee serialization of RLZ key accesses.
|
||||
|
||||
#include "rlz/win/lib/lib_mutex.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <Sddl.h> // For SDDL_REVISION_1, ConvertStringSecurityDescript..
|
||||
#include <Aclapi.h> // For SetSecurityInfo
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/win/windows_version.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const wchar_t kMutexName[] = L"{A946A6A9-917E-4949-B9BC-6BADA8C7FD63}";
|
||||
|
||||
} // namespace anonymous
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
// Needed to allow synchronization across integrity levels.
|
||||
static bool SetObjectToLowIntegrity(HANDLE object,
|
||||
SE_OBJECT_TYPE type = SE_KERNEL_OBJECT) {
|
||||
if (base::win::GetVersion() < base::win::VERSION_VISTA)
|
||||
return true; // Not needed on XP.
|
||||
|
||||
// The LABEL_SECURITY_INFORMATION SDDL SACL to be set for low integrity.
|
||||
static const wchar_t kLowIntegritySddlSacl[] = L"S:(ML;;NW;;;LW)";
|
||||
|
||||
bool result = false;
|
||||
DWORD error = ERROR_SUCCESS;
|
||||
PSECURITY_DESCRIPTOR security_descriptor = NULL;
|
||||
PACL sacl = NULL;
|
||||
BOOL sacl_present = FALSE;
|
||||
BOOL sacl_defaulted = FALSE;
|
||||
|
||||
if (ConvertStringSecurityDescriptorToSecurityDescriptorW(
|
||||
kLowIntegritySddlSacl, SDDL_REVISION_1, &security_descriptor, NULL)) {
|
||||
if (GetSecurityDescriptorSacl(security_descriptor, &sacl_present,
|
||||
&sacl, &sacl_defaulted)) {
|
||||
error = SetSecurityInfo(object, type, LABEL_SECURITY_INFORMATION,
|
||||
NULL, NULL, NULL, sacl);
|
||||
result = (ERROR_SUCCESS == error);
|
||||
}
|
||||
LocalFree(security_descriptor);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
LibMutex::LibMutex() : acquired_(false), mutex_(NULL) {
|
||||
mutex_ = CreateMutex(NULL, false, kMutexName);
|
||||
bool result = SetObjectToLowIntegrity(mutex_);
|
||||
if (result) {
|
||||
acquired_ = (WAIT_OBJECT_0 == WaitForSingleObject(mutex_, 5000L));
|
||||
}
|
||||
}
|
||||
|
||||
LibMutex::~LibMutex() {
|
||||
if (acquired_) ReleaseMutex(mutex_);
|
||||
CloseHandle(mutex_);
|
||||
}
|
||||
|
||||
} // namespace rlz_lib
|
28
rlz/win/lib/lib_mutex.h
Normal file
28
rlz/win/lib/lib_mutex.h
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Mutex to guarantee serialization of RLZ key accesses.
|
||||
|
||||
#ifndef RLZ_WIN_LIB_LIB_MUTEX_H_
|
||||
#define RLZ_WIN_LIB_LIB_MUTEX_H_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
class LibMutex {
|
||||
public:
|
||||
LibMutex();
|
||||
~LibMutex();
|
||||
|
||||
bool failed(void) { return !acquired_; }
|
||||
|
||||
private:
|
||||
bool acquired_;
|
||||
HANDLE mutex_;
|
||||
};
|
||||
|
||||
} // namespace rlz_lib
|
||||
|
||||
#endif // RLZ_WIN_LIB_LIB_MUTEX_H_
|
300
rlz/win/lib/machine_deal.cc
Normal file
300
rlz/win/lib/machine_deal.cc
Normal file
@ -0,0 +1,300 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Library functions related to the OEM Deal Confirmation Code.
|
||||
|
||||
#include "rlz/win/lib/machine_deal.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/string_split.h"
|
||||
#include "base/string_util.h"
|
||||
#include "base/stringprintf.h"
|
||||
#include "base/win/registry.h"
|
||||
#include "rlz/lib/assert.h"
|
||||
#include "rlz/lib/lib_values.h"
|
||||
#include "rlz/win/lib/lib_mutex.h"
|
||||
#include "rlz/win/lib/registry_util.h"
|
||||
#include "rlz/win/lib/rlz_value_store_registry.h"
|
||||
|
||||
const wchar_t kDccValueName[] = L"DCC";
|
||||
|
||||
namespace {
|
||||
|
||||
// Current DCC can only uses [a-zA-Z0-9_-!@$*();.<>,:]
|
||||
// We will be more liberal and allow some additional chars, but not url meta
|
||||
// chars.
|
||||
bool IsGoodDccChar(char ch) {
|
||||
if (IsAsciiAlpha(ch) || IsAsciiDigit(ch))
|
||||
return true;
|
||||
|
||||
switch (ch) {
|
||||
case '_':
|
||||
case '-':
|
||||
case '!':
|
||||
case '@':
|
||||
case '$':
|
||||
case '*':
|
||||
case '(':
|
||||
case ')':
|
||||
case ';':
|
||||
case '.':
|
||||
case '<':
|
||||
case '>':
|
||||
case ',':
|
||||
case ':':
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// This function will remove bad rlz chars and also limit the max rlz to some
|
||||
// reasonable size. It also assumes that normalized_dcc is at least
|
||||
// kMaxDccLength+1 long.
|
||||
void NormalizeDcc(const char* raw_dcc, char* normalized_dcc) {
|
||||
int index = 0;
|
||||
for (; raw_dcc[index] != 0 && index < rlz_lib::kMaxDccLength; ++index) {
|
||||
char current = raw_dcc[index];
|
||||
if (IsGoodDccChar(current)) {
|
||||
normalized_dcc[index] = current;
|
||||
} else {
|
||||
normalized_dcc[index] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
normalized_dcc[index] = 0;
|
||||
}
|
||||
|
||||
bool GetResponseLine(const char* response_text, int response_length,
|
||||
int* search_index, std::string* response_line) {
|
||||
if (!response_line || !search_index || *search_index > response_length)
|
||||
return false;
|
||||
|
||||
response_line->clear();
|
||||
|
||||
if (*search_index < 0)
|
||||
return false;
|
||||
|
||||
int line_begin = *search_index;
|
||||
const char* line_end = strchr(response_text + line_begin, '\n');
|
||||
|
||||
if (line_end == NULL || line_end - response_text > response_length) {
|
||||
line_end = response_text + response_length;
|
||||
*search_index = -1;
|
||||
} else {
|
||||
*search_index = line_end - response_text + 1;
|
||||
}
|
||||
|
||||
response_line->assign(response_text + line_begin,
|
||||
line_end - response_text - line_begin);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetResponseValue(const std::string& response_line,
|
||||
const std::string& response_key,
|
||||
std::string* value) {
|
||||
if (!value)
|
||||
return false;
|
||||
|
||||
value->clear();
|
||||
|
||||
if (!StartsWithASCII(response_line, response_key, true))
|
||||
return false;
|
||||
|
||||
std::vector<std::string> tokens;
|
||||
base::SplitString(response_line, ':', &tokens);
|
||||
if (tokens.size() != 2)
|
||||
return false;
|
||||
|
||||
// The first token is the key, the second is the value. The value is already
|
||||
// trimmed for whitespace.
|
||||
*value = tokens[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace anonymous
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
bool MachineDealCode::Set(const char* dcc) {
|
||||
LibMutex lock;
|
||||
if (lock.failed())
|
||||
return false;
|
||||
|
||||
// TODO: if (!ProcessInfo::CanWriteMachineKey()) return false;
|
||||
|
||||
// Validate the new dcc value.
|
||||
size_t length = strlen(dcc);
|
||||
if (length > kMaxDccLength) {
|
||||
ASSERT_STRING("MachineDealCode::Set: DCC length is exceeds max allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
base::win::RegKey hklm_key(HKEY_LOCAL_MACHINE,
|
||||
RlzValueStoreRegistry::GetWideLibKeyName().c_str(),
|
||||
KEY_READ | KEY_WRITE | KEY_WOW64_32KEY);
|
||||
if (!hklm_key.Valid()) {
|
||||
ASSERT_STRING("MachineDealCode::Set: Unable to create / open machine key."
|
||||
" Did you call rlz_lib::CreateMachineState()?");
|
||||
return false;
|
||||
}
|
||||
|
||||
char normalized_dcc[kMaxDccLength + 1];
|
||||
NormalizeDcc(dcc, normalized_dcc);
|
||||
VERIFY(length == strlen(normalized_dcc));
|
||||
|
||||
// Write the DCC to HKLM. Note that we need to include the null character
|
||||
// when writing the string.
|
||||
if (!RegKeyWriteValue(hklm_key, kDccValueName, normalized_dcc)) {
|
||||
ASSERT_STRING("MachineDealCode::Set: Could not write the DCC value");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MachineDealCode::GetNewCodeFromPingResponse(const char* response,
|
||||
bool* has_new_dcc, char* new_dcc, int new_dcc_size) {
|
||||
if (!has_new_dcc || !new_dcc || !new_dcc_size)
|
||||
return false;
|
||||
|
||||
*has_new_dcc = false;
|
||||
new_dcc[0] = 0;
|
||||
|
||||
int response_length = -1;
|
||||
if (!IsPingResponseValid(response, &response_length))
|
||||
return false;
|
||||
|
||||
// Get the current DCC value to compare to later)
|
||||
char stored_dcc[kMaxDccLength + 1];
|
||||
if (!Get(stored_dcc, arraysize(stored_dcc)))
|
||||
stored_dcc[0] = 0;
|
||||
|
||||
int search_index = 0;
|
||||
std::string response_line;
|
||||
std::string new_dcc_value;
|
||||
bool old_dcc_confirmed = false;
|
||||
const std::string dcc_cgi(kDccCgiVariable);
|
||||
const std::string dcc_cgi_response(kSetDccResponseVariable);
|
||||
while (GetResponseLine(response, response_length, &search_index,
|
||||
&response_line)) {
|
||||
std::string value;
|
||||
|
||||
if (!old_dcc_confirmed &&
|
||||
GetResponseValue(response_line, dcc_cgi, &value)) {
|
||||
// This is the old DCC confirmation - should match value in registry.
|
||||
if (value != stored_dcc)
|
||||
return false; // Corrupted DCC - ignore this response.
|
||||
else
|
||||
old_dcc_confirmed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(*has_new_dcc) &&
|
||||
GetResponseValue(response_line, dcc_cgi_response, &value)) {
|
||||
// This is the new DCC.
|
||||
if (value.size() > kMaxDccLength) continue; // Too long
|
||||
*has_new_dcc = true;
|
||||
new_dcc_value = value;
|
||||
}
|
||||
}
|
||||
|
||||
old_dcc_confirmed |= (NULL == stored_dcc[0]);
|
||||
|
||||
base::strlcpy(new_dcc, new_dcc_value.c_str(), new_dcc_size);
|
||||
return old_dcc_confirmed;
|
||||
}
|
||||
|
||||
bool MachineDealCode::SetFromPingResponse(const char* response) {
|
||||
bool has_new_dcc = false;
|
||||
char new_dcc[kMaxDccLength + 1];
|
||||
|
||||
bool response_valid = GetNewCodeFromPingResponse(
|
||||
response, &has_new_dcc, new_dcc, arraysize(new_dcc));
|
||||
|
||||
if (response_valid && has_new_dcc)
|
||||
return Set(new_dcc);
|
||||
|
||||
return response_valid;
|
||||
}
|
||||
|
||||
bool MachineDealCode::GetAsCgi(char* cgi, int cgi_size) {
|
||||
if (!cgi || cgi_size <= 0) {
|
||||
ASSERT_STRING("MachineDealCode::GetAsCgi: Invalid buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
cgi[0] = 0;
|
||||
|
||||
std::string cgi_arg;
|
||||
base::StringAppendF(&cgi_arg, "%s=", kDccCgiVariable);
|
||||
int cgi_arg_length = cgi_arg.size();
|
||||
|
||||
if (cgi_arg_length >= cgi_size) {
|
||||
ASSERT_STRING("MachineDealCode::GetAsCgi: Insufficient buffer size");
|
||||
return false;
|
||||
}
|
||||
|
||||
base::strlcpy(cgi, cgi_arg.c_str(), cgi_size);
|
||||
|
||||
if (!Get(cgi + cgi_arg_length, cgi_size - cgi_arg_length)) {
|
||||
cgi[0] = 0;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MachineDealCode::Get(char* dcc, int dcc_size) {
|
||||
LibMutex lock;
|
||||
if (lock.failed())
|
||||
return false;
|
||||
|
||||
if (!dcc || dcc_size <= 0) {
|
||||
ASSERT_STRING("MachineDealCode::Get: Invalid buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
dcc[0] = 0;
|
||||
|
||||
base::win::RegKey dcc_key(HKEY_LOCAL_MACHINE,
|
||||
RlzValueStoreRegistry::GetWideLibKeyName().c_str(),
|
||||
KEY_READ | KEY_WOW64_32KEY);
|
||||
if (!dcc_key.Valid())
|
||||
return false; // no DCC key.
|
||||
|
||||
size_t size = dcc_size;
|
||||
if (!RegKeyReadValue(dcc_key, kDccValueName, dcc, &size)) {
|
||||
ASSERT_STRING("MachineDealCode::Get: Insufficient buffer size");
|
||||
dcc[0] = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MachineDealCode::Clear() {
|
||||
base::win::RegKey dcc_key(HKEY_LOCAL_MACHINE,
|
||||
RlzValueStoreRegistry::GetWideLibKeyName().c_str(),
|
||||
KEY_READ | KEY_WRITE | KEY_WOW64_32KEY);
|
||||
if (!dcc_key.Valid())
|
||||
return false; // no DCC key.
|
||||
|
||||
dcc_key.DeleteValue(kDccValueName);
|
||||
|
||||
// Verify deletion.
|
||||
wchar_t dcc[kMaxDccLength + 1];
|
||||
DWORD dcc_size = arraysize(dcc);
|
||||
if (dcc_key.ReadValue(kDccValueName, dcc, &dcc_size, NULL) == ERROR_SUCCESS) {
|
||||
ASSERT_STRING("MachineDealCode::Clear: Could not delete the DCC value.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rlz_lib
|
61
rlz/win/lib/machine_deal.h
Normal file
61
rlz/win/lib/machine_deal.h
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Library functions related to the OEM Deal Confirmation Code.
|
||||
|
||||
#ifndef RLZ_WIN_LIB_MACHINE_DEAL_H_
|
||||
#define RLZ_WIN_LIB_MACHINE_DEAL_H_
|
||||
|
||||
#include <string>
|
||||
#include "rlz/win/lib/rlz_lib.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
class MachineDealCode {
|
||||
public:
|
||||
// Set the OEM Deal Confirmation Code (DCC). This information is used for RLZ
|
||||
// initalization. Must have write access to HKLM - SYSTEM or admin, unless
|
||||
// rlz_lib::CreateMachineState() has been successfully called.
|
||||
static bool Set(const char* dcc);
|
||||
|
||||
// Get the OEM Deal Confirmation Code from the registry. Used to ping
|
||||
// the server.
|
||||
static bool Get(AccessPoint point,
|
||||
char* dcc,
|
||||
int dcc_size,
|
||||
const wchar_t* sid = NULL);
|
||||
|
||||
// Parses a ping response, checks if it is valid and sets the machine DCC
|
||||
// from the response. The response should also contain the current value of
|
||||
// the DCC to be considered valid.
|
||||
// Write access to HKLM (system / admin) needed, unless
|
||||
// rlz_lib::CreateMachineState() has been successfully called.
|
||||
static bool SetFromPingResponse(const char* response);
|
||||
|
||||
// Gets the new DCC to set from a ping response. Returns true if the ping
|
||||
// response is valid. Sets has_new_dcc true if there is a new DCC value.
|
||||
static bool GetNewCodeFromPingResponse(const char* response,
|
||||
bool* has_new_dcc,
|
||||
char* new_dcc,
|
||||
int new_dcc_size);
|
||||
|
||||
// Get the DCC cgi argument string to append to a daily or financial ping.
|
||||
static bool GetAsCgi(char* cgi, int cgi_size);
|
||||
|
||||
// Get the machine code.
|
||||
static bool Get(char* dcc, int dcc_size);
|
||||
|
||||
protected:
|
||||
// Clear the DCC value. Only for testing purposes.
|
||||
// Requires write access to HKLM, unless rlz_lib::CreateMachineState() has
|
||||
// been successfully called.
|
||||
static bool Clear();
|
||||
|
||||
MachineDealCode() {}
|
||||
~MachineDealCode() {}
|
||||
};
|
||||
|
||||
} // namespace rlz_lib
|
||||
|
||||
#endif // RLZ_WIN_LIB_MACHINE_DEAL_H_
|
156
rlz/win/lib/machine_deal_test.cc
Normal file
156
rlz/win/lib/machine_deal_test.cc
Normal file
@ -0,0 +1,156 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// A test application for the MachineDealCode class.
|
||||
//
|
||||
// These tests should not be executed on the build server:
|
||||
// - They assert for the failed cases.
|
||||
// - They modify machine state (registry).
|
||||
//
|
||||
// These tests require write access to HKLM and HKCU, unless
|
||||
// rlz_lib::CreateMachineState() has been successfully called.
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
#include "rlz/test/rlz_test_helpers.h"
|
||||
#include "rlz/win/lib/machine_deal.h"
|
||||
|
||||
class MachineDealCodeHelper : public rlz_lib::MachineDealCode {
|
||||
public:
|
||||
static bool Clear() { return rlz_lib::MachineDealCode::Clear(); }
|
||||
|
||||
private:
|
||||
MachineDealCodeHelper() {}
|
||||
~MachineDealCodeHelper() {}
|
||||
};
|
||||
|
||||
class MachineDealCodeTest : public RlzLibTestBase {
|
||||
};
|
||||
|
||||
TEST_F(MachineDealCodeTest, CreateMachineState) {
|
||||
EXPECT_TRUE(rlz_lib::CreateMachineState());
|
||||
}
|
||||
|
||||
TEST_F(MachineDealCodeTest, Set) {
|
||||
MachineDealCodeHelper::Clear();
|
||||
char dcc_50[50];
|
||||
dcc_50[0] = 0;
|
||||
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::Set("dcc_value"));
|
||||
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50));
|
||||
EXPECT_STREQ("dcc_value", dcc_50);
|
||||
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::Set("dcc_value_2"));
|
||||
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50));
|
||||
EXPECT_STREQ("dcc_value_2", dcc_50);
|
||||
}
|
||||
|
||||
TEST_F(MachineDealCodeTest, Get) {
|
||||
MachineDealCodeHelper::Clear();
|
||||
char dcc_50[50], dcc_2[2];
|
||||
dcc_50[0] = 0;
|
||||
dcc_2[0] = 0;
|
||||
|
||||
EXPECT_FALSE(rlz_lib::MachineDealCode::Get(dcc_50, 50));
|
||||
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::Set("dcc_value"));
|
||||
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50));
|
||||
EXPECT_STREQ("dcc_value", dcc_50);
|
||||
|
||||
EXPECT_FALSE(rlz_lib::MachineDealCode::Get(dcc_2, 2));
|
||||
}
|
||||
|
||||
TEST_F(MachineDealCodeTest, SetFromPingResponse) {
|
||||
rlz_lib::MachineDealCode::Set("MyDCCode");
|
||||
char dcc_50[50];
|
||||
|
||||
// Bad responses
|
||||
|
||||
char* kBadDccResponse =
|
||||
"dcc: NotMyDCCode \r\n"
|
||||
"set_dcc: NewDCCode\r\n"
|
||||
"crc32: 1B4D6BB3";
|
||||
EXPECT_FALSE(rlz_lib::MachineDealCode::SetFromPingResponse(
|
||||
kBadDccResponse));
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50));
|
||||
EXPECT_STREQ("MyDCCode", dcc_50);
|
||||
|
||||
char* kBadCrcResponse =
|
||||
"dcc: MyDCCode \r\n"
|
||||
"set_dcc: NewDCCode\r\n"
|
||||
"crc32: 90707106";
|
||||
EXPECT_FALSE(rlz_lib::MachineDealCode::SetFromPingResponse(
|
||||
kBadCrcResponse));
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50));
|
||||
EXPECT_STREQ("MyDCCode", dcc_50);
|
||||
|
||||
// Good responses
|
||||
|
||||
char* kMissingSetResponse =
|
||||
"dcc: MyDCCode \r\n"
|
||||
"crc32: 35F2E717";
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::SetFromPingResponse(
|
||||
kMissingSetResponse));
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50));
|
||||
EXPECT_STREQ("MyDCCode", dcc_50);
|
||||
|
||||
char* kGoodResponse =
|
||||
"dcc: MyDCCode \r\n"
|
||||
"set_dcc: NewDCCode\r\n"
|
||||
"crc32: C8540E02";
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::SetFromPingResponse(
|
||||
kGoodResponse));
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50));
|
||||
EXPECT_STREQ("NewDCCode", dcc_50);
|
||||
|
||||
char* kGoodResponse2 =
|
||||
"set_dcc: NewDCCode2 \r\n"
|
||||
"dcc: NewDCCode \r\n"
|
||||
"crc32: 60B6409A";
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::SetFromPingResponse(
|
||||
kGoodResponse2));
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50));
|
||||
EXPECT_STREQ("NewDCCode2", dcc_50);
|
||||
|
||||
MachineDealCodeHelper::Clear();
|
||||
char* kGoodResponse3 =
|
||||
"set_dcc: NewDCCode \r\n"
|
||||
"crc32: 374C1C47";
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::SetFromPingResponse(
|
||||
kGoodResponse3));
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50));
|
||||
EXPECT_STREQ("NewDCCode", dcc_50);
|
||||
|
||||
MachineDealCodeHelper::Clear();
|
||||
char* kGoodResponse4 =
|
||||
"dcc: \r\n"
|
||||
"set_dcc: NewDCCode \r\n"
|
||||
"crc32: 0AB1FB39";
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::SetFromPingResponse(
|
||||
kGoodResponse4));
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50));
|
||||
EXPECT_STREQ("NewDCCode", dcc_50);
|
||||
}
|
||||
|
||||
TEST_F(MachineDealCodeTest, GetAsCgi) {
|
||||
MachineDealCodeHelper::Clear();
|
||||
char cgi_50[50], cgi_2[2];
|
||||
cgi_50[0] = 0;
|
||||
cgi_2[0] = 0;
|
||||
|
||||
EXPECT_FALSE(rlz_lib::MachineDealCode::GetAsCgi(cgi_50, 50));
|
||||
EXPECT_STREQ("", cgi_50);
|
||||
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::Set("dcc_value"));
|
||||
|
||||
EXPECT_TRUE(rlz_lib::MachineDealCode::GetAsCgi(cgi_50, 50));
|
||||
EXPECT_STREQ("dcc=dcc_value", cgi_50);
|
||||
|
||||
EXPECT_FALSE(rlz_lib::MachineDealCode::GetAsCgi(cgi_2, 2));
|
||||
}
|
130
rlz/win/lib/machine_id_win.cc
Normal file
130
rlz/win/lib/machine_id_win.cc
Normal file
@ -0,0 +1,130 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <windows.h>
|
||||
#include <Sddl.h> // For ConvertSidToStringSidW.
|
||||
#include <string>
|
||||
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/string16.h"
|
||||
#include "rlz/lib/assert.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
namespace {
|
||||
|
||||
bool GetSystemVolumeSerialNumber(int* number) {
|
||||
if (!number)
|
||||
return false;
|
||||
|
||||
*number = 0;
|
||||
|
||||
// Find the system root path (e.g: C:\).
|
||||
wchar_t system_path[MAX_PATH + 1];
|
||||
if (!GetSystemDirectoryW(system_path, MAX_PATH))
|
||||
return false;
|
||||
|
||||
wchar_t* first_slash = wcspbrk(system_path, L"\\/");
|
||||
if (first_slash != NULL)
|
||||
*(first_slash + 1) = 0;
|
||||
|
||||
DWORD number_local = 0;
|
||||
if (!GetVolumeInformationW(system_path, NULL, 0, &number_local, NULL, NULL,
|
||||
NULL, 0))
|
||||
return false;
|
||||
|
||||
*number = number_local;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetComputerSid(const wchar_t* account_name, SID* sid, DWORD sid_size) {
|
||||
static const DWORD kStartDomainLength = 128; // reasonable to start with
|
||||
|
||||
scoped_array<wchar_t> domain_buffer(new wchar_t[kStartDomainLength]);
|
||||
DWORD domain_size = kStartDomainLength;
|
||||
DWORD sid_dword_size = sid_size;
|
||||
SID_NAME_USE sid_name_use;
|
||||
|
||||
BOOL success = ::LookupAccountNameW(NULL, account_name, sid,
|
||||
&sid_dword_size, domain_buffer.get(),
|
||||
&domain_size, &sid_name_use);
|
||||
if (!success && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||||
// We could have gotten the insufficient buffer error because
|
||||
// one or both of sid and szDomain was too small. Check for that
|
||||
// here.
|
||||
if (sid_dword_size > sid_size)
|
||||
return false;
|
||||
|
||||
if (domain_size > kStartDomainLength)
|
||||
domain_buffer.reset(new wchar_t[domain_size]);
|
||||
|
||||
success = ::LookupAccountNameW(NULL, account_name, sid, &sid_dword_size,
|
||||
domain_buffer.get(), &domain_size,
|
||||
&sid_name_use);
|
||||
}
|
||||
|
||||
return success != FALSE;
|
||||
}
|
||||
|
||||
std::wstring ConvertSidToString(SID* sid) {
|
||||
std::wstring sid_string;
|
||||
#if _WIN32_WINNT >= 0x500
|
||||
wchar_t* sid_buffer = NULL;
|
||||
if (ConvertSidToStringSidW(sid, &sid_buffer)) {
|
||||
sid_string = sid_buffer;
|
||||
LocalFree(sid_buffer);
|
||||
}
|
||||
#else
|
||||
SID_IDENTIFIER_AUTHORITY* sia = ::GetSidIdentifierAuthority(sid);
|
||||
|
||||
if(sia->Value[0] || sia->Value[1]) {
|
||||
base::SStringPrintf(
|
||||
&sid_string, L"S-%d-0x%02hx%02hx%02hx%02hx%02hx%02hx",
|
||||
SID_REVISION, (USHORT)sia->Value[0], (USHORT)sia->Value[1],
|
||||
(USHORT)sia->Value[2], (USHORT)sia->Value[3], (USHORT)sia->Value[4],
|
||||
(USHORT)sia->Value[5]);
|
||||
} else {
|
||||
ULONG authority = 0;
|
||||
for (int i = 2; i < 6; ++i) {
|
||||
authority <<= 8;
|
||||
authority |= sia->Value[i];
|
||||
}
|
||||
base::SStringPrintf(&sid_string, L"S-%d-%lu", SID_REVISION, authority);
|
||||
}
|
||||
|
||||
int sub_auth_count = *::GetSidSubAuthorityCount(sid);
|
||||
for(int i = 0; i < sub_auth_count; ++i)
|
||||
base::StringAppendF(&sid_string, L"-%lu", *::GetSidSubAuthority(sid, i));
|
||||
#endif
|
||||
|
||||
return sid_string;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool GetRawMachineId(string16* sid_string, int* volume_id) {
|
||||
// Calculate the Windows SID.
|
||||
|
||||
wchar_t computer_name[MAX_COMPUTERNAME_LENGTH + 1] = {0};
|
||||
DWORD size = arraysize(computer_name);
|
||||
|
||||
if (GetComputerNameW(computer_name, &size)) {
|
||||
char sid_buffer[SECURITY_MAX_SID_SIZE];
|
||||
SID* sid = reinterpret_cast<SID*>(sid_buffer);
|
||||
if (GetComputerSid(computer_name, sid, SECURITY_MAX_SID_SIZE)) {
|
||||
*sid_string = ConvertSidToString(sid);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the system drive volume serial number.
|
||||
*volume_id = 0;
|
||||
if (!GetSystemVolumeSerialNumber(volume_id)) {
|
||||
ASSERT_STRING("GetMachineId: Failed to retrieve volume serial number");
|
||||
*volume_id = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rlz_lib
|
196
rlz/win/lib/process_info.cc
Normal file
196
rlz/win/lib/process_info.cc
Normal file
@ -0,0 +1,196 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Information about the current process.
|
||||
|
||||
#include "rlz/win/lib/process_info.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <Sddl.h> // For ConvertSidToStringSid.
|
||||
#include <LMCons.h> // For UNLEN
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/process_util.h"
|
||||
#include "base/win/scoped_handle.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "rlz/lib/assert.h"
|
||||
#include "rlz/win/lib/vista_winnt.h"
|
||||
|
||||
namespace {
|
||||
|
||||
HRESULT GetCurrentUser(std::wstring* name,
|
||||
std::wstring* domain,
|
||||
std::wstring* sid) {
|
||||
DWORD err;
|
||||
|
||||
// Get the current username & domain the hard way. (GetUserNameEx would be
|
||||
// nice, but unfortunately requires connectivity to a domain controller.
|
||||
// Useless.)
|
||||
|
||||
// (Following call doesn't work if running as a Service - because a Service
|
||||
// runs under special accounts like LOCAL_SYSTEM, not as the logged in user.
|
||||
// In which case, search for and use the process handle of a running
|
||||
// Explorer.exe.)
|
||||
HANDLE token;
|
||||
if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token))
|
||||
return E_FAIL;
|
||||
|
||||
base::win::ScopedHandle scoped_process_token(token);
|
||||
|
||||
// (Following call will fail with ERROR_INSUFFICIENT_BUFFER and give us the
|
||||
// required size.)
|
||||
scoped_array<char> token_user_bytes;
|
||||
DWORD token_user_size;
|
||||
DWORD token_user_size2;
|
||||
BOOL result = ::GetTokenInformation(token, TokenUser, NULL, 0,
|
||||
&token_user_size);
|
||||
err = ::GetLastError();
|
||||
CHECK(!result && err == ERROR_INSUFFICIENT_BUFFER);
|
||||
|
||||
token_user_bytes.reset(new char[token_user_size]);
|
||||
if (!token_user_bytes.get())
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
if (!::GetTokenInformation(token, TokenUser, token_user_bytes.get(),
|
||||
token_user_size, &token_user_size2)) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
WCHAR user_name[UNLEN + 1]; // max username length
|
||||
WCHAR domain_name[UNLEN + 1];
|
||||
DWORD user_name_size = UNLEN + 1;
|
||||
DWORD domain_name_size = UNLEN + 1;
|
||||
SID_NAME_USE sid_type;
|
||||
TOKEN_USER* token_user =
|
||||
reinterpret_cast<TOKEN_USER*>(token_user_bytes.get());
|
||||
if (!token_user)
|
||||
return E_FAIL;
|
||||
PSID user_sid = token_user->User.Sid;
|
||||
if (!::LookupAccountSidW(NULL, user_sid, user_name, &user_name_size,
|
||||
domain_name, &domain_name_size, &sid_type)) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
if (name != NULL) {
|
||||
*name = user_name;
|
||||
}
|
||||
if (domain != NULL) {
|
||||
*domain = domain_name;
|
||||
}
|
||||
if (sid != NULL) {
|
||||
LPWSTR string_sid;
|
||||
ConvertSidToStringSidW(user_sid, &string_sid);
|
||||
*sid = string_sid; // copy out to cstring
|
||||
// free memory, as documented for ConvertSidToStringSid
|
||||
LocalFree(string_sid);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT GetElevationType(PTOKEN_ELEVATION_TYPE elevation) {
|
||||
if (!elevation)
|
||||
return E_POINTER;
|
||||
|
||||
*elevation = TokenElevationTypeDefault;
|
||||
|
||||
if (base::win::GetVersion() < base::win::VERSION_VISTA)
|
||||
return E_FAIL;
|
||||
|
||||
HANDLE process_token;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &process_token))
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
base::win::ScopedHandle scoped_process_token(process_token);
|
||||
|
||||
DWORD size;
|
||||
TOKEN_ELEVATION_TYPE elevation_type;
|
||||
if (!GetTokenInformation(process_token, TokenElevationType, &elevation_type,
|
||||
sizeof(elevation_type), &size)) {
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
*elevation = elevation_type;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// based on http://msdn2.microsoft.com/en-us/library/aa376389.aspx
|
||||
bool GetUserGroup(long* group) {
|
||||
if (!group)
|
||||
return false;
|
||||
|
||||
*group = 0;
|
||||
|
||||
// groups are listed in DECREASING order of importance
|
||||
// (eg. If a user is a member of both the admin group and
|
||||
// the power user group, it is more useful to list the user
|
||||
// as an admin)
|
||||
DWORD user_groups[] = {DOMAIN_ALIAS_RID_ADMINS,
|
||||
DOMAIN_ALIAS_RID_POWER_USERS};
|
||||
SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY;
|
||||
|
||||
for (int i = 0; i < arraysize(user_groups) && *group == 0; ++i) {
|
||||
PSID current_group;
|
||||
if (AllocateAndInitializeSid(&nt_authority, 2,
|
||||
SECURITY_BUILTIN_DOMAIN_RID,
|
||||
user_groups[i], 0, 0, 0, 0,
|
||||
0, 0, ¤t_group)) {
|
||||
BOOL current_level;
|
||||
if (CheckTokenMembership(NULL, current_group, ¤t_level) &&
|
||||
current_level) {
|
||||
*group = user_groups[i];
|
||||
}
|
||||
|
||||
FreeSid(current_group);
|
||||
}
|
||||
}
|
||||
|
||||
return group != 0;
|
||||
}
|
||||
} //anonymous
|
||||
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
bool ProcessInfo::IsRunningAsSystem() {
|
||||
static std::wstring name;
|
||||
static std::wstring domain;
|
||||
static std::wstring sid;
|
||||
if (name.empty())
|
||||
CHECK(SUCCEEDED(GetCurrentUser(&name, &domain, &sid)));
|
||||
|
||||
return (name == L"SYSTEM");
|
||||
}
|
||||
|
||||
bool ProcessInfo::HasAdminRights() {
|
||||
static bool evaluated = false;
|
||||
static bool has_rights = false;
|
||||
|
||||
if (!evaluated) {
|
||||
if (IsRunningAsSystem()) {
|
||||
has_rights = true;
|
||||
} else if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
|
||||
TOKEN_ELEVATION_TYPE elevation;
|
||||
base::IntegrityLevel level;
|
||||
|
||||
if (SUCCEEDED(GetElevationType(&elevation)) &&
|
||||
base::GetProcessIntegrityLevel(base::GetCurrentProcessHandle(), &level))
|
||||
has_rights = (elevation == TokenElevationTypeFull) ||
|
||||
(level == HIGH_INTEGRITY);
|
||||
} else {
|
||||
long group = 0;
|
||||
if (GetUserGroup(&group))
|
||||
has_rights = (group == DOMAIN_ALIAS_RID_ADMINS);
|
||||
}
|
||||
}
|
||||
|
||||
evaluated = true;
|
||||
if (!has_rights)
|
||||
ASSERT_STRING("ProcessInfo::HasAdminRights: Does not have admin rights.");
|
||||
|
||||
return has_rights;
|
||||
}
|
||||
|
||||
}; // namespace
|
32
rlz/win/lib/process_info.h
Normal file
32
rlz/win/lib/process_info.h
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Information about the current process.
|
||||
|
||||
#ifndef RLZ_WIN_LIB_PROCESS_INFO_H_
|
||||
#define RLZ_WIN_LIB_PROCESS_INFO_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
class ProcessInfo {
|
||||
public:
|
||||
enum IntegrityLevel {
|
||||
INTEGRITY_UNKNOWN,
|
||||
LOW_INTEGRITY,
|
||||
MEDIUM_INTEGRITY,
|
||||
HIGH_INTEGRITY,
|
||||
};
|
||||
|
||||
// All these functions cache the result after first run.
|
||||
static bool IsRunningAsSystem();
|
||||
static bool HasAdminRights(); // System / Admin / High Elevation on Vista
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(ProcessInfo);
|
||||
}; // class
|
||||
}; // namespace
|
||||
|
||||
#endif // RLZ_WIN_LIB_PROCESS_INFO_H_
|
77
rlz/win/lib/registry_util.cc
Normal file
77
rlz/win/lib/registry_util.cc
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// A helper library to keep track of a user's key by SID.
|
||||
// Used by RLZ libary. Also to be used by SearchWithGoogle library.
|
||||
|
||||
#include "rlz/win/lib/registry_util.h"
|
||||
|
||||
#include "base/process_util.h"
|
||||
#include "base/utf_string_conversions.h"
|
||||
#include "base/win/registry.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "rlz/lib/assert.h"
|
||||
#include "rlz/win/lib/process_info.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
bool RegKeyReadValue(base::win::RegKey& key, const wchar_t* name,
|
||||
char* value, size_t* value_size) {
|
||||
value[0] = 0;
|
||||
|
||||
std::wstring value_string;
|
||||
if (key.ReadValue(name, &value_string) != ERROR_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value_string.length() > *value_size) {
|
||||
*value_size = value_string.length();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note that RLZ string are always ASCII by design.
|
||||
strncpy(value, WideToUTF8(value_string).c_str(), *value_size);
|
||||
value[*value_size - 1] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RegKeyWriteValue(base::win::RegKey& key, const wchar_t* name,
|
||||
const char* value) {
|
||||
std::wstring value_string(ASCIIToWide(value));
|
||||
return key.WriteValue(name, value_string.c_str()) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool HasUserKeyAccess(bool write_access) {
|
||||
// The caller is trying to access HKEY_CURRENT_USER. Test to see if we can
|
||||
// read from there. Don't try HKEY_CURRENT_USER because this will cause
|
||||
// problems in the unit tests: if we open HKEY_CURRENT_USER directly here,
|
||||
// the overriding done for unit tests will no longer work. So we try subkey
|
||||
// "Software" which is known to always exist.
|
||||
base::win::RegKey key;
|
||||
if (key.Open(HKEY_CURRENT_USER, L"Software", KEY_READ) != ERROR_SUCCESS)
|
||||
ASSERT_STRING("Could not open HKEY_CURRENT_USER");
|
||||
|
||||
if (ProcessInfo::IsRunningAsSystem()) {
|
||||
ASSERT_STRING("UserKey::HasAccess: No access as SYSTEM without SID set.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (write_access) {
|
||||
if (base::win::GetVersion() < base::win::VERSION_VISTA) return true;
|
||||
base::ProcessHandle process_handle = base::GetCurrentProcessHandle();
|
||||
base::IntegrityLevel level = base::INTEGRITY_UNKNOWN;
|
||||
|
||||
if (!base::GetProcessIntegrityLevel(process_handle, &level)) {
|
||||
ASSERT_STRING("UserKey::HasAccess: Cannot determine Integrity Level.");
|
||||
return false;
|
||||
}
|
||||
if (level <= base::LOW_INTEGRITY) {
|
||||
ASSERT_STRING("UserKey::HasAccess: Cannot write from Low Integrity.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rlz_lib
|
29
rlz/win/lib/registry_util.h
Normal file
29
rlz/win/lib/registry_util.h
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef RLZ_WIN_LIB_REGISTRY_UTIL_H_
|
||||
#define RLZ_WIN_LIB_REGISTRY_UTIL_H_
|
||||
|
||||
namespace base {
|
||||
namespace win {
|
||||
class RegKey;
|
||||
} // namespace win
|
||||
} // namespace base
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
bool RegKeyReadValue(base::win::RegKey& key,
|
||||
const wchar_t* name,
|
||||
char* value,
|
||||
size_t* value_size);
|
||||
|
||||
bool RegKeyWriteValue(base::win::RegKey& key,
|
||||
const wchar_t* name,
|
||||
const char* value);
|
||||
|
||||
bool HasUserKeyAccess(bool write_access);
|
||||
|
||||
} // namespace rlz_lib
|
||||
|
||||
#endif // RLZ_WIN_LIB_REGISTRY_UTIL_H_
|
56
rlz/win/lib/rlz_lib.h
Normal file
56
rlz/win/lib/rlz_lib.h
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// A library to manage RLZ information for access-points shared
|
||||
// across different client applications.
|
||||
//
|
||||
// All functions return true on success and false on error.
|
||||
// This implemenation is thread safe.
|
||||
//
|
||||
// Each prototype mentions the registry access requirements:
|
||||
//
|
||||
// HKLM read: Will work from any process and at any privilege level on Vista.
|
||||
// HKCU read: Calls made from the SYSTEM account must pass the current user's
|
||||
// SID as the optional 'sid' param. Can be called from low integrity
|
||||
// process on Vista.
|
||||
// HKCU write: Calls made from the SYSTEM account must pass the current user's
|
||||
// SID as the optional 'sid' param. Calls require at least medium
|
||||
// integrity on Vista (e.g. Toolbar will need to use their broker)
|
||||
// HKLM write: Calls must be made from an account with admin rights. No SID
|
||||
// need be passed when running as SYSTEM.
|
||||
// Functions which do not access registry will be marked with "no restrictions".
|
||||
|
||||
#ifndef RLZ_WIN_LIB_RLZ_LIB_H_
|
||||
#define RLZ_WIN_LIB_RLZ_LIB_H_
|
||||
|
||||
// Clients can get away by just including rlz/lib/rlz_lib.h. This file only
|
||||
// contains function definitions for files used by tests. It's mostly kept
|
||||
// around for backwards-compatibility.
|
||||
|
||||
#include "rlz/lib/rlz_lib.h"
|
||||
|
||||
#include "base/win/registry.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
#if defined(OS_WIN)
|
||||
|
||||
// Initialize temporary HKLM/HKCU registry hives used for testing.
|
||||
// Testing RLZ requires reading and writing to the Windows registry. To keep
|
||||
// the tests isolated from the machine's state, as well as to prevent the tests
|
||||
// from causing side effects in the registry, HKCU and HKLM are overridden for
|
||||
// the duration of the tests. RLZ tests don't expect the HKCU and KHLM hives to
|
||||
// be empty though, and this function initializes the minimum value needed so
|
||||
// that the test will run successfully.
|
||||
//
|
||||
// The two arguments to this function should be the keys that will represent
|
||||
// the HKLM and HKCU registry hives during the tests. This function should be
|
||||
// called *before* the hives are overridden.
|
||||
void InitializeTempHivesForTesting(const base::win::RegKey& temp_hklm_key,
|
||||
const base::win::RegKey& temp_hkcu_key);
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
} // namespace rlz_lib
|
||||
|
||||
#endif // RLZ_WIN_LIB_RLZ_LIB_H_
|
260
rlz/win/lib/rlz_lib_win.cc
Normal file
260
rlz/win/lib/rlz_lib_win.cc
Normal file
@ -0,0 +1,260 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// A library to manage RLZ information for access-points shared
|
||||
// across different client applications.
|
||||
|
||||
#include "rlz/win/lib/rlz_lib.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <aclapi.h>
|
||||
#include <winerror.h>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/win/registry.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "rlz/lib/assert.h"
|
||||
#include "rlz/lib/rlz_value_store.h"
|
||||
#include "rlz/win/lib/machine_deal.h"
|
||||
#include "rlz/win/lib/rlz_value_store_registry.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Path to recursively copy into the replacemment hives. These are needed
|
||||
// to make sure certain win32 APIs continue to run correctly once the real
|
||||
// hives are replaced.
|
||||
const wchar_t* kHKLMAccessProviders =
|
||||
L"System\\CurrentControlSet\\Control\\Lsa\\AccessProviders";
|
||||
|
||||
// Helper functions
|
||||
|
||||
void CopyRegistryTree(const base::win::RegKey& src, base::win::RegKey* dest) {
|
||||
// First copy values.
|
||||
for (base::win::RegistryValueIterator i(src.Handle(), L"");
|
||||
i.Valid(); ++i) {
|
||||
dest->WriteValue(i.Name(), reinterpret_cast<const void*>(i.Value()),
|
||||
i.ValueSize(), i.Type());
|
||||
}
|
||||
|
||||
// Next copy subkeys recursively.
|
||||
for (base::win::RegistryKeyIterator i(src.Handle(), L"");
|
||||
i.Valid(); ++i) {
|
||||
base::win::RegKey subkey(dest->Handle(), i.Name(), KEY_ALL_ACCESS);
|
||||
CopyRegistryTree(base::win::RegKey(src.Handle(), i.Name(), KEY_READ),
|
||||
&subkey);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace anonymous
|
||||
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
// OEM Deal confirmation storage functions.
|
||||
|
||||
template<class T>
|
||||
class typed_buffer_ptr {
|
||||
scoped_array<char> buffer_;
|
||||
|
||||
public:
|
||||
typed_buffer_ptr() {
|
||||
}
|
||||
|
||||
explicit typed_buffer_ptr(size_t size) : buffer_(new char[size]) {
|
||||
}
|
||||
|
||||
void reset(size_t size) {
|
||||
buffer_.reset(new char[size]);
|
||||
}
|
||||
|
||||
operator T*() {
|
||||
return reinterpret_cast<T*>(buffer_.get());
|
||||
}
|
||||
};
|
||||
|
||||
// Check if this SID has the desired access by scanning the ACEs in the DACL.
|
||||
// This function is part of the rlz_lib namespace so that it can be called from
|
||||
// unit tests. Non-unit test code should not call this function.
|
||||
bool HasAccess(PSID sid, ACCESS_MASK access_mask, ACL* dacl) {
|
||||
if (dacl == NULL)
|
||||
return false;
|
||||
|
||||
ACL_SIZE_INFORMATION info;
|
||||
if (!GetAclInformation(dacl, &info, sizeof(info), AclSizeInformation))
|
||||
return false;
|
||||
|
||||
GENERIC_MAPPING generic_mapping = {KEY_READ, KEY_WRITE, KEY_EXECUTE,
|
||||
KEY_ALL_ACCESS};
|
||||
MapGenericMask(&access_mask, &generic_mapping);
|
||||
|
||||
for (DWORD i = 0; i < info.AceCount; ++i) {
|
||||
ACCESS_ALLOWED_ACE* ace;
|
||||
if (GetAce(dacl, i, reinterpret_cast<void**>(&ace))) {
|
||||
if ((ace->Header.AceFlags & INHERIT_ONLY_ACE) == INHERIT_ONLY_ACE)
|
||||
continue;
|
||||
|
||||
PSID existing_sid = reinterpret_cast<PSID>(&ace->SidStart);
|
||||
DWORD mask = ace->Mask;
|
||||
MapGenericMask(&mask, &generic_mapping);
|
||||
|
||||
if (ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE &&
|
||||
(mask & access_mask) == access_mask && EqualSid(existing_sid, sid))
|
||||
return true;
|
||||
|
||||
if (ace->Header.AceType == ACCESS_DENIED_ACE_TYPE &&
|
||||
(mask & access_mask) != 0 && EqualSid(existing_sid, sid))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CreateMachineState() {
|
||||
LibMutex lock;
|
||||
if (lock.failed())
|
||||
return false;
|
||||
|
||||
base::win::RegKey hklm_key;
|
||||
if (hklm_key.Create(HKEY_LOCAL_MACHINE,
|
||||
RlzValueStoreRegistry::GetWideLibKeyName().c_str(),
|
||||
KEY_ALL_ACCESS | KEY_WOW64_32KEY) != ERROR_SUCCESS) {
|
||||
ASSERT_STRING("rlz_lib::CreateMachineState: "
|
||||
"Unable to create / open machine key.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a SID that represents ALL USERS.
|
||||
DWORD users_sid_size = SECURITY_MAX_SID_SIZE;
|
||||
typed_buffer_ptr<SID> users_sid(users_sid_size);
|
||||
CreateWellKnownSid(WinBuiltinUsersSid, NULL, users_sid, &users_sid_size);
|
||||
|
||||
// Get the security descriptor for the registry key.
|
||||
DWORD original_sd_size = 0;
|
||||
::RegGetKeySecurity(hklm_key.Handle(), DACL_SECURITY_INFORMATION, NULL,
|
||||
&original_sd_size);
|
||||
typed_buffer_ptr<SECURITY_DESCRIPTOR> original_sd(original_sd_size);
|
||||
|
||||
LONG result = ::RegGetKeySecurity(hklm_key.Handle(),
|
||||
DACL_SECURITY_INFORMATION, original_sd, &original_sd_size);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
ASSERT_STRING("rlz_lib::CreateMachineState: "
|
||||
"Unable to create / open machine key.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make a copy of the security descriptor so we can modify it. The one
|
||||
// returned by RegGetKeySecurity() is self-relative, so we need to make it
|
||||
// absolute.
|
||||
DWORD new_sd_size = 0;
|
||||
DWORD dacl_size = 0;
|
||||
DWORD sacl_size = 0;
|
||||
DWORD owner_size = 0;
|
||||
DWORD group_size = 0;
|
||||
::MakeAbsoluteSD(original_sd, NULL, &new_sd_size, NULL, &dacl_size,
|
||||
NULL, &sacl_size, NULL, &owner_size,
|
||||
NULL, &group_size);
|
||||
|
||||
typed_buffer_ptr<SECURITY_DESCRIPTOR> new_sd(new_sd_size);
|
||||
// Make sure the DACL is big enough to add one more ACE.
|
||||
typed_buffer_ptr<ACL> dacl(dacl_size + SECURITY_MAX_SID_SIZE);
|
||||
typed_buffer_ptr<ACL> sacl(sacl_size);
|
||||
typed_buffer_ptr<SID> owner(owner_size);
|
||||
typed_buffer_ptr<SID> group(group_size);
|
||||
|
||||
if (!::MakeAbsoluteSD(original_sd, new_sd, &new_sd_size, dacl, &dacl_size,
|
||||
sacl, &sacl_size, owner, &owner_size,
|
||||
group, &group_size)) {
|
||||
ASSERT_STRING("rlz_lib::CreateMachineState: MakeAbsoluteSD failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If all users already have read/write access to the registry key, then
|
||||
// nothing to do. Otherwise change the security descriptor of the key to
|
||||
// give everyone access.
|
||||
if (HasAccess(users_sid, KEY_ALL_ACCESS, dacl)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add ALL-USERS ALL-ACCESS ACL.
|
||||
EXPLICIT_ACCESS ea;
|
||||
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
|
||||
ea.grfAccessPermissions = GENERIC_ALL | KEY_ALL_ACCESS;
|
||||
ea.grfAccessMode = GRANT_ACCESS;
|
||||
ea.grfInheritance= SUB_CONTAINERS_AND_OBJECTS_INHERIT;
|
||||
ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
|
||||
ea.Trustee.ptstrName = L"Everyone";
|
||||
|
||||
ACL* new_dacl = NULL;
|
||||
result = SetEntriesInAcl(1, &ea, dacl, &new_dacl);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
ASSERT_STRING("rlz_lib::CreateMachineState: SetEntriesInAcl failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOL ok = SetSecurityDescriptorDacl(new_sd, TRUE, new_dacl, FALSE);
|
||||
if (!ok) {
|
||||
ASSERT_STRING("rlz_lib::CreateMachineState: "
|
||||
"SetSecurityDescriptorOwner failed");
|
||||
LocalFree(new_dacl);
|
||||
return false;
|
||||
}
|
||||
|
||||
result = ::RegSetKeySecurity(hklm_key.Handle(),
|
||||
DACL_SECURITY_INFORMATION,
|
||||
new_sd);
|
||||
// Note that the new DACL cannot be freed until after the call to
|
||||
// RegSetKeySecurity().
|
||||
LocalFree(new_dacl);
|
||||
|
||||
bool success = true;
|
||||
if (result != ERROR_SUCCESS) {
|
||||
ASSERT_STRING("rlz_lib::CreateMachineState: "
|
||||
"Unable to create / open machine key.");
|
||||
success = false;
|
||||
}
|
||||
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool SetMachineDealCode(const char* dcc) {
|
||||
return MachineDealCode::Set(dcc);
|
||||
}
|
||||
|
||||
bool GetMachineDealCodeAsCgi(char* cgi, size_t cgi_size) {
|
||||
return MachineDealCode::GetAsCgi(cgi, cgi_size);
|
||||
}
|
||||
|
||||
bool GetMachineDealCode(char* dcc, size_t dcc_size) {
|
||||
return MachineDealCode::Get(dcc, dcc_size);
|
||||
}
|
||||
|
||||
// Combined functions.
|
||||
|
||||
bool SetMachineDealCodeFromPingResponse(const char* response) {
|
||||
return MachineDealCode::SetFromPingResponse(response);
|
||||
}
|
||||
|
||||
void InitializeTempHivesForTesting(const base::win::RegKey& temp_hklm_key,
|
||||
const base::win::RegKey& temp_hkcu_key) {
|
||||
// For the moment, the HKCU hive requires no initialization.
|
||||
|
||||
if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
|
||||
// Copy the following HKLM subtrees to the temporary location so that the
|
||||
// win32 APIs used by the tests continue to work:
|
||||
//
|
||||
// HKLM\System\CurrentControlSet\Control\Lsa\AccessProviders
|
||||
//
|
||||
// This seems to be required since Win7.
|
||||
base::win::RegKey dest(temp_hklm_key.Handle(), kHKLMAccessProviders,
|
||||
KEY_ALL_ACCESS);
|
||||
CopyRegistryTree(base::win::RegKey(HKEY_LOCAL_MACHINE,
|
||||
kHKLMAccessProviders,
|
||||
KEY_READ),
|
||||
&dest);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rlz_lib
|
384
rlz/win/lib/rlz_value_store_registry.cc
Normal file
384
rlz/win/lib/rlz_value_store_registry.cc
Normal file
@ -0,0 +1,384 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "rlz/win/lib/rlz_value_store_registry.h"
|
||||
|
||||
#include "base/win/registry.h"
|
||||
#include "base/stringprintf.h"
|
||||
#include "base/utf_string_conversions.h"
|
||||
#include "rlz/lib/assert.h"
|
||||
#include "rlz/lib/lib_values.h"
|
||||
#include "rlz/lib/rlz_lib.h"
|
||||
#include "rlz/lib/string_utils.h"
|
||||
#include "rlz/win/lib/registry_util.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
namespace {
|
||||
|
||||
//
|
||||
// Registry keys:
|
||||
//
|
||||
// RLZ's are stored as:
|
||||
// <AccessPointName> = <RLZ value> @ kRootKey\kLibKeyName\kRlzsSubkeyName.
|
||||
//
|
||||
// Events are stored as:
|
||||
// <AccessPointName><EventName> = 1 @
|
||||
// HKCU\kLibKeyName\kEventsSubkeyName\GetProductName(product).
|
||||
//
|
||||
// The OEM Deal Confirmation Code (DCC) is stored as
|
||||
// kDccValueName = <DCC value> @ HKLM\kLibKeyName
|
||||
//
|
||||
// The last ping time, per product is stored as:
|
||||
// GetProductName(product) = <last ping time> @
|
||||
// HKCU\kLibKeyName\kPingTimesSubkeyName.
|
||||
//
|
||||
// The server does not care about any of these constants.
|
||||
//
|
||||
const char kLibKeyName[] = "Software\\Google\\Common\\Rlz";
|
||||
const wchar_t kGoogleKeyName[] = L"Software\\Google";
|
||||
const wchar_t kGoogleCommonKeyName[] = L"Software\\Google\\Common";
|
||||
const char kRlzsSubkeyName[] = "RLZs";
|
||||
const char kEventsSubkeyName[] = "Events";
|
||||
const char kStatefulEventsSubkeyName[] = "StatefulEvents";
|
||||
const char kPingTimesSubkeyName[] = "PTimes";
|
||||
|
||||
std::wstring GetWideProductName(Product product) {
|
||||
return ASCIIToWide(GetProductName(product));
|
||||
}
|
||||
|
||||
void AppendBrandToString(std::string* str) {
|
||||
std::string brand(SupplementaryBranding::GetBrand());
|
||||
if (!brand.empty())
|
||||
base::StringAppendF(str, "\\_%s", brand.c_str());
|
||||
}
|
||||
|
||||
// Function to get the specific registry keys.
|
||||
bool GetRegKey(const char* name, REGSAM access, base::win::RegKey* key) {
|
||||
std::string key_location;
|
||||
base::StringAppendF(&key_location, "%s\\%s", kLibKeyName, name);
|
||||
AppendBrandToString(&key_location);
|
||||
|
||||
LONG ret = ERROR_SUCCESS;
|
||||
if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) {
|
||||
ret = key->Create(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(),
|
||||
access);
|
||||
} else {
|
||||
ret = key->Open(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(),
|
||||
access);
|
||||
}
|
||||
|
||||
return ret == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool GetPingTimesRegKey(REGSAM access, base::win::RegKey* key) {
|
||||
return GetRegKey(kPingTimesSubkeyName, access, key);
|
||||
}
|
||||
|
||||
|
||||
bool GetEventsRegKey(const char* event_type,
|
||||
const rlz_lib::Product* product,
|
||||
REGSAM access, base::win::RegKey* key) {
|
||||
std::string key_location;
|
||||
base::StringAppendF(&key_location, "%s\\%s", kLibKeyName,
|
||||
event_type);
|
||||
AppendBrandToString(&key_location);
|
||||
|
||||
if (product != NULL) {
|
||||
std::string product_name = GetProductName(*product);
|
||||
if (product_name.empty())
|
||||
return false;
|
||||
|
||||
base::StringAppendF(&key_location, "\\%s", product_name.c_str());
|
||||
}
|
||||
|
||||
LONG ret = ERROR_SUCCESS;
|
||||
if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) {
|
||||
ret = key->Create(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(),
|
||||
access);
|
||||
} else {
|
||||
ret = key->Open(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(),
|
||||
access);
|
||||
}
|
||||
|
||||
return ret == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool GetAccessPointRlzsRegKey(REGSAM access, base::win::RegKey* key) {
|
||||
return GetRegKey(kRlzsSubkeyName, access, key);
|
||||
}
|
||||
|
||||
bool ClearAllProductEventValues(rlz_lib::Product product, const char* key) {
|
||||
std::wstring product_name = GetWideProductName(product);
|
||||
if (product_name.empty())
|
||||
return false;
|
||||
|
||||
base::win::RegKey reg_key;
|
||||
GetEventsRegKey(key, NULL, KEY_WRITE, ®_key);
|
||||
reg_key.DeleteKey(product_name.c_str());
|
||||
|
||||
// Verify that the value no longer exists.
|
||||
base::win::RegKey product_events(
|
||||
reg_key.Handle(), product_name.c_str(), KEY_READ);
|
||||
if (product_events.Valid()) {
|
||||
ASSERT_STRING("ClearAllProductEvents: Key deletion failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Deletes a registry key if it exists and has no subkeys or values.
|
||||
// TODO: Move this to a registry_utils file and add unittest.
|
||||
bool DeleteKeyIfEmpty(HKEY root_key, const wchar_t* key_name) {
|
||||
if (!key_name) {
|
||||
ASSERT_STRING("DeleteKeyIfEmpty: key_name is NULL");
|
||||
return false;
|
||||
} else { // Scope needed for RegKey
|
||||
base::win::RegKey key(root_key, key_name, KEY_READ);
|
||||
if (!key.Valid())
|
||||
return true; // Key does not exist - nothing to do.
|
||||
|
||||
base::win::RegistryKeyIterator key_iter(root_key, key_name);
|
||||
if (key_iter.SubkeyCount() > 0)
|
||||
return true; // Not empty, so nothing to do
|
||||
|
||||
base::win::RegistryValueIterator value_iter(root_key, key_name);
|
||||
if (value_iter.ValueCount() > 0)
|
||||
return true; // Not empty, so nothing to do
|
||||
}
|
||||
|
||||
// The key is empty - delete it now.
|
||||
base::win::RegKey key(root_key, L"", KEY_WRITE);
|
||||
return key.DeleteKey(key_name) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
std::wstring RlzValueStoreRegistry::GetWideLibKeyName() {
|
||||
return ASCIIToWide(kLibKeyName);
|
||||
}
|
||||
|
||||
bool RlzValueStoreRegistry::HasAccess(AccessType type) {
|
||||
return HasUserKeyAccess(type == kWriteAccess);
|
||||
}
|
||||
|
||||
bool RlzValueStoreRegistry::WritePingTime(Product product, int64 time) {
|
||||
base::win::RegKey key;
|
||||
std::wstring product_name = GetWideProductName(product);
|
||||
return GetPingTimesRegKey(KEY_WRITE, &key) &&
|
||||
key.WriteValue(product_name.c_str(), &time, sizeof(time),
|
||||
REG_QWORD) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool RlzValueStoreRegistry::ReadPingTime(Product product, int64* time) {
|
||||
base::win::RegKey key;
|
||||
std::wstring product_name = GetWideProductName(product);
|
||||
return GetPingTimesRegKey(KEY_READ, &key) &&
|
||||
key.ReadInt64(product_name.c_str(), time) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool RlzValueStoreRegistry::ClearPingTime(Product product) {
|
||||
base::win::RegKey key;
|
||||
GetPingTimesRegKey(KEY_WRITE, &key);
|
||||
|
||||
std::wstring product_name = GetWideProductName(product);
|
||||
key.DeleteValue(product_name.c_str());
|
||||
|
||||
// Verify deletion.
|
||||
uint64 value;
|
||||
DWORD size = sizeof(value);
|
||||
if (key.ReadValue(
|
||||
product_name.c_str(), &value, &size, NULL) == ERROR_SUCCESS) {
|
||||
ASSERT_STRING("RlzValueStoreRegistry::ClearPingTime: Failed to delete.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RlzValueStoreRegistry::WriteAccessPointRlz(AccessPoint access_point,
|
||||
const char* new_rlz) {
|
||||
const char* access_point_name = GetAccessPointName(access_point);
|
||||
if (!access_point_name)
|
||||
return false;
|
||||
|
||||
std::wstring access_point_name_wide(ASCIIToWide(access_point_name));
|
||||
base::win::RegKey key;
|
||||
GetAccessPointRlzsRegKey(KEY_WRITE, &key);
|
||||
|
||||
if (!RegKeyWriteValue(key, access_point_name_wide.c_str(), new_rlz)) {
|
||||
ASSERT_STRING("SetAccessPointRlz: Could not write the new RLZ value");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RlzValueStoreRegistry::ReadAccessPointRlz(AccessPoint access_point,
|
||||
char* rlz,
|
||||
size_t rlz_size) {
|
||||
const char* access_point_name = GetAccessPointName(access_point);
|
||||
if (!access_point_name)
|
||||
return false;
|
||||
|
||||
size_t size = rlz_size;
|
||||
base::win::RegKey key;
|
||||
GetAccessPointRlzsRegKey(KEY_READ, &key);
|
||||
if (!RegKeyReadValue(key, ASCIIToWide(access_point_name).c_str(),
|
||||
rlz, &size)) {
|
||||
rlz[0] = 0;
|
||||
if (size > rlz_size) {
|
||||
ASSERT_STRING("GetAccessPointRlz: Insufficient buffer size");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RlzValueStoreRegistry::ClearAccessPointRlz(AccessPoint access_point) {
|
||||
const char* access_point_name = GetAccessPointName(access_point);
|
||||
if (!access_point_name)
|
||||
return false;
|
||||
|
||||
std::wstring access_point_name_wide(ASCIIToWide(access_point_name));
|
||||
base::win::RegKey key;
|
||||
GetAccessPointRlzsRegKey(KEY_WRITE, &key);
|
||||
|
||||
key.DeleteValue(access_point_name_wide.c_str());
|
||||
|
||||
// Verify deletion.
|
||||
DWORD value;
|
||||
if (key.ReadValueDW(access_point_name_wide.c_str(), &value) ==
|
||||
ERROR_SUCCESS) {
|
||||
ASSERT_STRING("SetAccessPointRlz: Could not clear the RLZ value.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RlzValueStoreRegistry::AddProductEvent(Product product,
|
||||
const char* event_rlz) {
|
||||
std::wstring event_rlz_wide(ASCIIToWide(event_rlz));
|
||||
base::win::RegKey reg_key;
|
||||
GetEventsRegKey(kEventsSubkeyName, &product, KEY_WRITE, ®_key);
|
||||
if (reg_key.WriteValue(event_rlz_wide.c_str(), 1) != ERROR_SUCCESS) {
|
||||
ASSERT_STRING("AddProductEvent: Could not write the new event value");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RlzValueStoreRegistry::ReadProductEvents(Product product,
|
||||
std::vector<std::string>* events) {
|
||||
// Open the events key.
|
||||
base::win::RegKey events_key;
|
||||
GetEventsRegKey(kEventsSubkeyName, &product, KEY_READ, &events_key);
|
||||
if (!events_key.Valid())
|
||||
return false;
|
||||
|
||||
// Append the events to the buffer.
|
||||
int num_values = 0;
|
||||
LONG result = ERROR_SUCCESS;
|
||||
for (num_values = 0; result == ERROR_SUCCESS; ++num_values) {
|
||||
// Max 32767 bytes according to MSDN, but we never use that much.
|
||||
const size_t kMaxValueNameLength = 2048;
|
||||
char buffer[kMaxValueNameLength];
|
||||
DWORD size = arraysize(buffer);
|
||||
|
||||
result = RegEnumValueA(events_key.Handle(), num_values, buffer, &size,
|
||||
NULL, NULL, NULL, NULL);
|
||||
if (result == ERROR_SUCCESS)
|
||||
events->push_back(std::string(buffer));
|
||||
}
|
||||
|
||||
return result == ERROR_NO_MORE_ITEMS;
|
||||
}
|
||||
|
||||
bool RlzValueStoreRegistry::ClearProductEvent(Product product,
|
||||
const char* event_rlz) {
|
||||
std::wstring event_rlz_wide(ASCIIToWide(event_rlz));
|
||||
base::win::RegKey key;
|
||||
GetEventsRegKey(kEventsSubkeyName, &product, KEY_WRITE, &key);
|
||||
key.DeleteValue(event_rlz_wide.c_str());
|
||||
|
||||
// Verify deletion.
|
||||
DWORD value;
|
||||
if (key.ReadValueDW(event_rlz_wide.c_str(), &value) == ERROR_SUCCESS) {
|
||||
ASSERT_STRING("ClearProductEvent: Could not delete the event value.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RlzValueStoreRegistry::ClearAllProductEvents(Product product) {
|
||||
return ClearAllProductEventValues(product, kEventsSubkeyName);
|
||||
}
|
||||
|
||||
bool RlzValueStoreRegistry::AddStatefulEvent(Product product,
|
||||
const char* event_rlz) {
|
||||
base::win::RegKey key;
|
||||
std::wstring event_rlz_wide(ASCIIToWide(event_rlz));
|
||||
if (!GetEventsRegKey(kStatefulEventsSubkeyName, &product, KEY_WRITE, &key) ||
|
||||
key.WriteValue(event_rlz_wide.c_str(), 1) != ERROR_SUCCESS) {
|
||||
ASSERT_STRING(
|
||||
"AddStatefulEvent: Could not write the new stateful event");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RlzValueStoreRegistry::IsStatefulEvent(Product product,
|
||||
const char* event_rlz) {
|
||||
DWORD value;
|
||||
base::win::RegKey key;
|
||||
GetEventsRegKey(kStatefulEventsSubkeyName, &product, KEY_READ, &key);
|
||||
std::wstring event_rlz_wide(ASCIIToWide(event_rlz));
|
||||
return key.ReadValueDW(event_rlz_wide.c_str(), &value) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool RlzValueStoreRegistry::ClearAllStatefulEvents(Product product) {
|
||||
return ClearAllProductEventValues(product, kStatefulEventsSubkeyName);
|
||||
}
|
||||
|
||||
void RlzValueStoreRegistry::CollectGarbage() {
|
||||
// Delete each of the known subkeys if empty.
|
||||
const char* subkeys[] = {
|
||||
kRlzsSubkeyName,
|
||||
kEventsSubkeyName,
|
||||
kStatefulEventsSubkeyName,
|
||||
kPingTimesSubkeyName
|
||||
};
|
||||
|
||||
for (int i = 0; i < arraysize(subkeys); i++) {
|
||||
std::string subkey_name;
|
||||
base::StringAppendF(&subkey_name, "%s\\%s", kLibKeyName, subkeys[i]);
|
||||
AppendBrandToString(&subkey_name);
|
||||
|
||||
VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER,
|
||||
ASCIIToWide(subkey_name).c_str()));
|
||||
}
|
||||
|
||||
// Delete the library key and its parents too now if empty.
|
||||
VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, GetWideLibKeyName().c_str()));
|
||||
VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, kGoogleCommonKeyName));
|
||||
VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, kGoogleKeyName));
|
||||
}
|
||||
|
||||
ScopedRlzValueStoreLock::ScopedRlzValueStoreLock() {
|
||||
if (!lock_.failed())
|
||||
store_.reset(new RlzValueStoreRegistry);
|
||||
}
|
||||
|
||||
ScopedRlzValueStoreLock::~ScopedRlzValueStoreLock() {
|
||||
}
|
||||
|
||||
RlzValueStore* ScopedRlzValueStoreLock::GetStore() {
|
||||
return store_.get();
|
||||
}
|
||||
|
||||
} // namespace rlz_lib
|
55
rlz/win/lib/rlz_value_store_registry.h
Normal file
55
rlz/win/lib/rlz_value_store_registry.h
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef RLZ_WIN_LIB_RLZ_VALUE_STORE_REGISTRY_H_
|
||||
#define RLZ_WIN_LIB_RLZ_VALUE_STORE_REGISTRY_H_
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "rlz/lib/rlz_value_store.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
// Implements RlzValueStore by storing values in the windows registry.
|
||||
class RlzValueStoreRegistry : public RlzValueStore {
|
||||
public:
|
||||
static std::wstring GetWideLibKeyName();
|
||||
|
||||
virtual bool HasAccess(AccessType type) OVERRIDE;
|
||||
|
||||
virtual bool WritePingTime(Product product, int64 time) OVERRIDE;
|
||||
virtual bool ReadPingTime(Product product, int64* time) OVERRIDE;
|
||||
virtual bool ClearPingTime(Product product) OVERRIDE;
|
||||
|
||||
virtual bool WriteAccessPointRlz(AccessPoint access_point,
|
||||
const char* new_rlz) OVERRIDE;
|
||||
virtual bool ReadAccessPointRlz(AccessPoint access_point,
|
||||
char* rlz,
|
||||
size_t rlz_size) OVERRIDE;
|
||||
virtual bool ClearAccessPointRlz(AccessPoint access_point) OVERRIDE;
|
||||
|
||||
virtual bool AddProductEvent(Product product, const char* event_rlz) OVERRIDE;
|
||||
virtual bool ReadProductEvents(Product product,
|
||||
std::vector<std::string>* events) OVERRIDE;
|
||||
virtual bool ClearProductEvent(Product product,
|
||||
const char* event_rlz) OVERRIDE;
|
||||
virtual bool ClearAllProductEvents(Product product) OVERRIDE;
|
||||
|
||||
virtual bool AddStatefulEvent(Product product,
|
||||
const char* event_rlz) OVERRIDE;
|
||||
virtual bool IsStatefulEvent(Product product,
|
||||
const char* event_rlz) OVERRIDE;
|
||||
virtual bool ClearAllStatefulEvents(Product product) OVERRIDE;
|
||||
|
||||
virtual void CollectGarbage() OVERRIDE;
|
||||
|
||||
private:
|
||||
RlzValueStoreRegistry() {}
|
||||
DISALLOW_COPY_AND_ASSIGN(RlzValueStoreRegistry);
|
||||
friend class ScopedRlzValueStoreLock;
|
||||
};
|
||||
|
||||
} // namespace rlz_lib
|
||||
|
||||
#endif // RLZ_WIN_LIB_RLZ_VALUE_STORE_REGISTRY_H_
|
||||
|
99
rlz/win/lib/vista_winnt.h
Normal file
99
rlz/win/lib/vista_winnt.h
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// This file contains snippets borrowed from the Vista SDK version of
|
||||
// WinNT.h, (c) Microsoft (2006)
|
||||
|
||||
#ifndef RLZ_WIN_LIB_VISTA_WINNT_H_
|
||||
#define RLZ_WIN_LIB_VISTA_WINNT_H_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// If no Vista SDK yet, borrow these from Vista's version of WinNT.h
|
||||
#ifndef SE_GROUP_INTEGRITY
|
||||
|
||||
// TOKEN_MANDATORY_LABEL.Label.Attributes = SE_GROUP_INTEGRITY
|
||||
#define SE_GROUP_INTEGRITY (0x00000020L)
|
||||
#define SE_GROUP_INTEGRITY_ENABLED (0x00000040L)
|
||||
|
||||
typedef struct _TOKEN_MANDATORY_LABEL {
|
||||
SID_AND_ATTRIBUTES Label;
|
||||
} TOKEN_MANDATORY_LABEL, *PTOKEN_MANDATORY_LABEL;
|
||||
|
||||
// These are a few new enums for TOKEN_INFORMATION_CLASS
|
||||
#define TokenElevationType static_cast<TOKEN_INFORMATION_CLASS>(18)
|
||||
#define TokenLinkedToken static_cast<TOKEN_INFORMATION_CLASS>(19)
|
||||
#define TokenElevation static_cast<TOKEN_INFORMATION_CLASS>(20)
|
||||
#define TokenHasRestrictions static_cast<TOKEN_INFORMATION_CLASS>(21)
|
||||
#define TokenAccessInformation static_cast<TOKEN_INFORMATION_CLASS>(22)
|
||||
#define TokenVirtualizationAllowed static_cast<TOKEN_INFORMATION_CLASS>(23)
|
||||
#define TokenVirtualizationEnabled static_cast<TOKEN_INFORMATION_CLASS>(24)
|
||||
// TokenIntegrityLevel is the proces's privilege level, low, med, or high
|
||||
#define TokenIntegrityLevel static_cast<TOKEN_INFORMATION_CLASS>(25)
|
||||
// TokenIntegrityLevelDeasktop is an alternate level used for access apis
|
||||
// (screen readers, imes)
|
||||
#define TokenIntegrityLevelDesktop static_cast<TOKEN_INFORMATION_CLASS>(26)
|
||||
|
||||
// This is a new flag to pass to GetNamedSecurityInfo or SetNamedSecurityInfo
|
||||
// that puts the mandatory level label info in an access control list (ACL)
|
||||
// structure in the parameter normally used for system acls (SACL)
|
||||
#define LABEL_SECURITY_INFORMATION (0x00000010L)
|
||||
|
||||
// The new Access Control Entry type identifier for mandatory labels
|
||||
#define SYSTEM_MANDATORY_LABEL_ACE_TYPE (0x11)
|
||||
|
||||
// The structure of mandatory label acess control binary entry
|
||||
typedef struct _SYSTEM_MANDATORY_LABEL_ACE {
|
||||
ACE_HEADER Header;
|
||||
ACCESS_MASK Mask;
|
||||
DWORD SidStart;
|
||||
} SYSTEM_MANDATORY_LABEL_ACE, *PSYSTEM_MANDATORY_LABEL_ACE;
|
||||
|
||||
// Masks for ACCESS_MASK above
|
||||
#define SYSTEM_MANDATORY_LABEL_NO_WRITE_UP 0x1
|
||||
#define SYSTEM_MANDATORY_LABEL_NO_READ_UP 0x2
|
||||
#define SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP 0x4
|
||||
#define SYSTEM_MANDATORY_LABEL_VALID_MASK \
|
||||
(SYSTEM_MANDATORY_LABEL_NO_WRITE_UP | \
|
||||
SYSTEM_MANDATORY_LABEL_NO_READ_UP | \
|
||||
SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP)
|
||||
|
||||
// The SID authority for mandatory labels
|
||||
#define SECURITY_MANDATORY_LABEL_AUTHORITY {0, 0, 0, 0, 0, 16}
|
||||
|
||||
// the RID values (sub authorities) that define mandatory label levels
|
||||
#define SECURITY_MANDATORY_UNTRUSTED_RID (0x00000000L)
|
||||
#define SECURITY_MANDATORY_LOW_RID (0x00001000L)
|
||||
#define SECURITY_MANDATORY_MEDIUM_RID (0x00002000L)
|
||||
#define SECURITY_MANDATORY_HIGH_RID (0x00003000L)
|
||||
#define SECURITY_MANDATORY_SYSTEM_RID (0x00004000L)
|
||||
#define SECURITY_MANDATORY_UI_ACCESS_RID (0x00004100L)
|
||||
#define SECURITY_MANDATORY_PROTECTED_PROCESS_RID (0x00005000L)
|
||||
|
||||
// Vista's mandatory labels, enumerated
|
||||
typedef enum _MANDATORY_LEVEL {
|
||||
MandatoryLevelUntrusted = 0,
|
||||
MandatoryLevelLow,
|
||||
MandatoryLevelMedium,
|
||||
MandatoryLevelHigh,
|
||||
MandatoryLevelSystem,
|
||||
MandatoryLevelSecureProcess,
|
||||
MandatoryLevelCount
|
||||
} MANDATORY_LEVEL, *PMANDATORY_LEVEL;
|
||||
|
||||
|
||||
// Token elevation values describe the relative strength of a given token.
|
||||
// A full token is a token with all groups and privileges to which the
|
||||
// principal is authorized. A limited token is one with some groups or
|
||||
// privileges removed.
|
||||
|
||||
typedef enum _TOKEN_ELEVATION_TYPE {
|
||||
TokenElevationTypeDefault = 1,
|
||||
TokenElevationTypeFull,
|
||||
TokenElevationTypeLimited,
|
||||
} TOKEN_ELEVATION_TYPE, *PTOKEN_ELEVATION_TYPE;
|
||||
|
||||
#endif // #ifndef SE_GROUP_INTEGRITY
|
||||
|
||||
#endif // RLZ_WIN_LIB_VISTA_WINNT_H_
|
Reference in New Issue
Block a user