This source file includes following definitions.
- GetTimezoneOffset
- GetOperatingSystemVersion
- AddFontsToFingerprint
- AddPluginsToFingerprint
- AddAcceptLanguagesToFingerprint
- AddScreenInfoToFingerprint
- AddCpuInfoToFingerprint
- AddGpuInfoToFingerprint
- OnGotGeoposition
- LoadGeoposition
- callback_
- OnGpuInfoUpdate
- OnGotFonts
- OnGotPlugins
- OnGotGeoposition
- MaybeFillFingerprint
- FillFingerprint
- GetFingerprintInternal
- GetFingerprint
#include "components/autofill/content/browser/risk/fingerprint.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/cpu.h"
#include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observer.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "base/sys_info.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/values.h"
#include "components/autofill/content/browser/risk/proto/fingerprint.pb.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/font_list_async.h"
#include "content/public/browser/geolocation_provider.h"
#include "content/public/browser/gpu_data_manager.h"
#include "content/public/browser/gpu_data_manager_observer.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "content/public/common/geoposition.h"
#include "content/public/common/webplugininfo.h"
#include "gpu/config/gpu_info.h"
#include "third_party/WebKit/public/platform/WebRect.h"
#include "third_party/WebKit/public/platform/WebScreenInfo.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/screen.h"
using blink::WebScreenInfo;
namespace autofill {
namespace risk {
namespace {
const int32 kFingerprinterVersion = 1;
const int kTimeoutSeconds = 4;
base::TimeDelta GetTimezoneOffset() {
const base::Time utc = base::Time::Now();
base::Time::Exploded local;
utc.LocalExplode(&local);
return base::Time::FromUTCExploded(local) - utc;
}
std::string GetOperatingSystemVersion() {
return base::SysInfo::OperatingSystemName() + " " +
base::SysInfo::OperatingSystemVersion();
}
void AddFontsToFingerprint(const base::ListValue& fonts,
Fingerprint::MachineCharacteristics* machine) {
for (base::ListValue::const_iterator it = fonts.begin();
it != fonts.end(); ++it) {
const base::ListValue* font_description = NULL;
bool success = (*it)->GetAsList(&font_description);
DCHECK(success);
std::string font_name;
success = font_description->GetString(1, &font_name);
DCHECK(success);
machine->add_font(font_name);
}
}
void AddPluginsToFingerprint(const std::vector<content::WebPluginInfo>& plugins,
Fingerprint::MachineCharacteristics* machine) {
for (std::vector<content::WebPluginInfo>::const_iterator it = plugins.begin();
it != plugins.end(); ++it) {
Fingerprint::MachineCharacteristics::Plugin* plugin =
machine->add_plugin();
plugin->set_name(base::UTF16ToUTF8(it->name));
plugin->set_description(base::UTF16ToUTF8(it->desc));
for (std::vector<content::WebPluginMimeType>::const_iterator mime_type =
it->mime_types.begin();
mime_type != it->mime_types.end(); ++mime_type) {
plugin->add_mime_type(mime_type->mime_type);
}
plugin->set_version(base::UTF16ToUTF8(it->version));
}
}
void AddAcceptLanguagesToFingerprint(
const std::string& accept_languages_str,
Fingerprint::MachineCharacteristics* machine) {
std::vector<std::string> accept_languages;
base::SplitString(accept_languages_str, ',', &accept_languages);
for (std::vector<std::string>::const_iterator it = accept_languages.begin();
it != accept_languages.end(); ++it) {
machine->add_requested_language(*it);
}
}
void AddScreenInfoToFingerprint(const WebScreenInfo& screen_info,
Fingerprint::MachineCharacteristics* machine) {
machine->set_screen_count(
gfx::Screen::GetNativeScreen()->GetNumDisplays());
const gfx::Size screen_size =
gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().GetSizeInPixel();
machine->mutable_screen_size()->set_width(screen_size.width());
machine->mutable_screen_size()->set_height(screen_size.height());
machine->set_screen_color_depth(screen_info.depth);
const gfx::Rect screen_rect(screen_info.rect);
const gfx::Rect available_rect(screen_info.availableRect);
const gfx::Rect unavailable_rect =
gfx::SubtractRects(screen_rect, available_rect);
machine->mutable_unavailable_screen_size()->set_width(
unavailable_rect.width());
machine->mutable_unavailable_screen_size()->set_height(
unavailable_rect.height());
}
void AddCpuInfoToFingerprint(Fingerprint::MachineCharacteristics* machine) {
base::CPU cpu;
machine->mutable_cpu()->set_vendor_name(cpu.vendor_name());
machine->mutable_cpu()->set_brand(cpu.cpu_brand());
}
void AddGpuInfoToFingerprint(Fingerprint::MachineCharacteristics* machine) {
const gpu::GPUInfo& gpu_info =
content::GpuDataManager::GetInstance()->GetGPUInfo();
if (!gpu_info.finalized)
return;
Fingerprint::MachineCharacteristics::Graphics* graphics =
machine->mutable_graphics_card();
graphics->set_vendor_id(gpu_info.gpu.vendor_id);
graphics->set_device_id(gpu_info.gpu.device_id);
graphics->set_driver_version(gpu_info.driver_version);
graphics->set_driver_date(gpu_info.driver_date);
Fingerprint::MachineCharacteristics::Graphics::PerformanceStatistics*
gpu_performance = graphics->mutable_performance_statistics();
gpu_performance->set_graphics_score(gpu_info.performance_stats.graphics);
gpu_performance->set_gaming_score(gpu_info.performance_stats.gaming);
gpu_performance->set_overall_score(gpu_info.performance_stats.overall);
}
class GeopositionLoader {
public:
GeopositionLoader(
const base::TimeDelta& timeout,
const base::Callback<void(const content::Geoposition&)>& callback);
~GeopositionLoader() {}
private:
void OnGotGeoposition(const content::Geoposition& geoposition);
const base::Callback<void(const content::Geoposition&)> callback_;
content::GeolocationProvider::LocationUpdateCallback geolocation_callback_;
base::OneShotTimer<GeopositionLoader> timeout_timer_;
};
GeopositionLoader::GeopositionLoader(
const base::TimeDelta& timeout,
const base::Callback<void(const content::Geoposition&)>& callback)
: callback_(callback) {
timeout_timer_.Start(FROM_HERE, timeout,
base::Bind(&GeopositionLoader::OnGotGeoposition,
base::Unretained(this),
content::Geoposition()));
geolocation_callback_ =
base::Bind(&GeopositionLoader::OnGotGeoposition, base::Unretained(this));
content::GeolocationProvider::GetInstance()->AddLocationUpdateCallback(
geolocation_callback_, false);
}
void GeopositionLoader::OnGotGeoposition(
const content::Geoposition& geoposition) {
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
base::Bind(callback_, geoposition));
bool removed =
content::GeolocationProvider::GetInstance()->RemoveLocationUpdateCallback(
geolocation_callback_);
DCHECK(removed);
delete this;
}
void LoadGeoposition(
const base::TimeDelta& timeout,
const base::Callback<void(const content::Geoposition&)>& callback) {
new GeopositionLoader(timeout, callback);
}
class FingerprintDataLoader : public content::GpuDataManagerObserver {
public:
FingerprintDataLoader(
uint64 obfuscated_gaia_id,
const gfx::Rect& window_bounds,
const gfx::Rect& content_bounds,
const WebScreenInfo& screen_info,
const std::string& version,
const std::string& charset,
const std::string& accept_languages,
const base::Time& install_time,
const std::string& app_locale,
const std::string& user_agent,
const base::TimeDelta& timeout,
const base::Callback<void(scoped_ptr<Fingerprint>)>& callback);
private:
virtual ~FingerprintDataLoader() {}
virtual void OnGpuInfoUpdate() OVERRIDE;
void OnGotFonts(scoped_ptr<base::ListValue> fonts);
void OnGotPlugins(const std::vector<content::WebPluginInfo>& plugins);
void OnGotGeoposition(const content::Geoposition& geoposition);
void MaybeFillFingerprint();
void FillFingerprint();
content::GpuDataManager* const gpu_data_manager_;
ScopedObserver<content::GpuDataManager, FingerprintDataLoader> gpu_observer_;
const uint64 obfuscated_gaia_id_;
const gfx::Rect window_bounds_;
const gfx::Rect content_bounds_;
const WebScreenInfo screen_info_;
const std::string version_;
const std::string charset_;
const std::string accept_languages_;
const std::string app_locale_;
const std::string user_agent_;
const base::Time install_time_;
scoped_ptr<base::ListValue> fonts_;
std::vector<content::WebPluginInfo> plugins_;
bool waiting_on_plugins_;
content::Geoposition geoposition_;
base::OneShotTimer<FingerprintDataLoader> timeout_timer_;
base::WeakPtrFactory<FingerprintDataLoader> weak_ptr_factory_;
base::Callback<void(scoped_ptr<Fingerprint>)> callback_;
DISALLOW_COPY_AND_ASSIGN(FingerprintDataLoader);
};
FingerprintDataLoader::FingerprintDataLoader(
uint64 obfuscated_gaia_id,
const gfx::Rect& window_bounds,
const gfx::Rect& content_bounds,
const WebScreenInfo& screen_info,
const std::string& version,
const std::string& charset,
const std::string& accept_languages,
const base::Time& install_time,
const std::string& app_locale,
const std::string& user_agent,
const base::TimeDelta& timeout,
const base::Callback<void(scoped_ptr<Fingerprint>)>& callback)
: gpu_data_manager_(content::GpuDataManager::GetInstance()),
gpu_observer_(this),
obfuscated_gaia_id_(obfuscated_gaia_id),
window_bounds_(window_bounds),
content_bounds_(content_bounds),
screen_info_(screen_info),
version_(version),
charset_(charset),
accept_languages_(accept_languages),
app_locale_(app_locale),
user_agent_(user_agent),
install_time_(install_time),
waiting_on_plugins_(true),
weak_ptr_factory_(this),
callback_(callback) {
DCHECK(!install_time_.is_null());
timeout_timer_.Start(FROM_HERE, timeout,
base::Bind(&FingerprintDataLoader::MaybeFillFingerprint,
weak_ptr_factory_.GetWeakPtr()));
if (gpu_data_manager_->GpuAccessAllowed(NULL) &&
!gpu_data_manager_->IsCompleteGpuInfoAvailable()) {
gpu_observer_.Add(gpu_data_manager_);
gpu_data_manager_->RequestCompleteGpuInfoIfNeeded();
}
#if defined(ENABLE_PLUGINS)
content::PluginService::GetInstance()->GetPlugins(
base::Bind(&FingerprintDataLoader::OnGotPlugins,
weak_ptr_factory_.GetWeakPtr()));
#else
waiting_on_plugins_ = false;
#endif
content::GetFontListAsync(
base::Bind(&FingerprintDataLoader::OnGotFonts,
weak_ptr_factory_.GetWeakPtr()));
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&LoadGeoposition,
timeout,
base::Bind(&FingerprintDataLoader::OnGotGeoposition,
weak_ptr_factory_.GetWeakPtr())));
}
void FingerprintDataLoader::OnGpuInfoUpdate() {
if (!gpu_data_manager_->IsCompleteGpuInfoAvailable())
return;
gpu_observer_.Remove(gpu_data_manager_);
MaybeFillFingerprint();
}
void FingerprintDataLoader::OnGotFonts(scoped_ptr<base::ListValue> fonts) {
DCHECK(!fonts_);
fonts_.reset(fonts.release());
MaybeFillFingerprint();
}
void FingerprintDataLoader::OnGotPlugins(
const std::vector<content::WebPluginInfo>& plugins) {
DCHECK(waiting_on_plugins_);
waiting_on_plugins_ = false;
plugins_ = plugins;
MaybeFillFingerprint();
}
void FingerprintDataLoader::OnGotGeoposition(
const content::Geoposition& geoposition) {
DCHECK(!geoposition_.Validate());
geoposition_ = geoposition;
DCHECK(geoposition_.Validate() ||
geoposition_.error_code != content::Geoposition::ERROR_CODE_NONE);
MaybeFillFingerprint();
}
void FingerprintDataLoader::MaybeFillFingerprint() {
if (!timeout_timer_.IsRunning() ||
((!gpu_data_manager_->GpuAccessAllowed(NULL) ||
gpu_data_manager_->IsCompleteGpuInfoAvailable()) &&
fonts_ &&
!waiting_on_plugins_ &&
(geoposition_.Validate() ||
geoposition_.error_code != content::Geoposition::ERROR_CODE_NONE))) {
FillFingerprint();
delete this;
}
}
void FingerprintDataLoader::FillFingerprint() {
scoped_ptr<Fingerprint> fingerprint(new Fingerprint);
Fingerprint::MachineCharacteristics* machine =
fingerprint->mutable_machine_characteristics();
machine->set_operating_system_build(GetOperatingSystemVersion());
machine->set_browser_install_time_hours(
(install_time_ - base::Time::UnixEpoch()).InHours());
machine->set_utc_offset_ms(GetTimezoneOffset().InMilliseconds());
machine->set_browser_language(app_locale_);
machine->set_charset(charset_);
machine->set_user_agent(user_agent_);
machine->set_ram(base::SysInfo::AmountOfPhysicalMemory());
machine->set_browser_build(version_);
machine->set_browser_feature(
Fingerprint::MachineCharacteristics::FEATURE_REQUEST_AUTOCOMPLETE);
if (fonts_)
AddFontsToFingerprint(*fonts_, machine);
AddPluginsToFingerprint(plugins_, machine);
AddAcceptLanguagesToFingerprint(accept_languages_, machine);
AddScreenInfoToFingerprint(screen_info_, machine);
AddCpuInfoToFingerprint(machine);
AddGpuInfoToFingerprint(machine);
Fingerprint::TransientState* transient_state =
fingerprint->mutable_transient_state();
Fingerprint::Dimension* inner_window_size =
transient_state->mutable_inner_window_size();
inner_window_size->set_width(content_bounds_.width());
inner_window_size->set_height(content_bounds_.height());
Fingerprint::Dimension* outer_window_size =
transient_state->mutable_outer_window_size();
outer_window_size->set_width(window_bounds_.width());
outer_window_size->set_height(window_bounds_.height());
if (geoposition_.Validate() &&
geoposition_.error_code == content::Geoposition::ERROR_CODE_NONE) {
Fingerprint::UserCharacteristics::Location* location =
fingerprint->mutable_user_characteristics()->mutable_location();
location->set_altitude(geoposition_.altitude);
location->set_latitude(geoposition_.latitude);
location->set_longitude(geoposition_.longitude);
location->set_accuracy(geoposition_.accuracy);
location->set_time_in_ms(
(geoposition_.timestamp - base::Time::UnixEpoch()).InMilliseconds());
}
Fingerprint::Metadata* metadata = fingerprint->mutable_metadata();
metadata->set_timestamp_ms(
(base::Time::Now() - base::Time::UnixEpoch()).InMilliseconds());
metadata->set_obfuscated_gaia_id(obfuscated_gaia_id_);
metadata->set_fingerprinter_version(kFingerprinterVersion);
callback_.Run(fingerprint.Pass());
}
}
namespace internal {
void GetFingerprintInternal(
uint64 obfuscated_gaia_id,
const gfx::Rect& window_bounds,
const gfx::Rect& content_bounds,
const blink::WebScreenInfo& screen_info,
const std::string& version,
const std::string& charset,
const std::string& accept_languages,
const base::Time& install_time,
const std::string& app_locale,
const std::string& user_agent,
const base::TimeDelta& timeout,
const base::Callback<void(scoped_ptr<Fingerprint>)>& callback) {
new FingerprintDataLoader(obfuscated_gaia_id, window_bounds, content_bounds,
screen_info, version, charset, accept_languages,
install_time, app_locale, user_agent, timeout,
callback);
}
}
void GetFingerprint(
uint64 obfuscated_gaia_id,
const gfx::Rect& window_bounds,
const content::WebContents& web_contents,
const std::string& version,
const std::string& charset,
const std::string& accept_languages,
const base::Time& install_time,
const std::string& app_locale,
const std::string& user_agent,
const base::Callback<void(scoped_ptr<Fingerprint>)>& callback) {
gfx::Rect content_bounds;
web_contents.GetView()->GetContainerBounds(&content_bounds);
blink::WebScreenInfo screen_info;
content::RenderWidgetHostView* host_view =
web_contents.GetRenderWidgetHostView();
if (host_view)
host_view->GetRenderWidgetHost()->GetWebScreenInfo(&screen_info);
internal::GetFingerprintInternal(
obfuscated_gaia_id, window_bounds, content_bounds, screen_info, version,
charset, accept_languages, install_time, app_locale, user_agent,
base::TimeDelta::FromSeconds(kTimeoutSeconds), callback);
}
}
}