Commit 614a8266 authored by Owen Min's avatar Owen Min Committed by Commit Bot

Implement a helper function that builds ChromeDesktopReportRequest.

Building the protobuf based on
Input from extension API:
1) Machine name
2) OS information (x86/x64)
3) OS User
4) Chrome Profile and its extensions/plugins
Other information that is stored in Chrome.
1) OS Information (Platform name and its version)
2) Browser version/channel.
3) Current profile ID based on its path
4) All policies affect the current profile.

Please note that only one profile will be added into the report.



Change-Id: I703ff554932388611c9839473b7dcadcf0cac3c1
Reviewed-on: https://chromium-review.googlesource.com/986946
Commit-Queue: Owen Min <zmin@chromium.org>
Reviewed-by: default avatarKaran Bhatia <karandeepb@chromium.org>
Reviewed-by: default avatarMarc-André Decoste <mad@chromium.org>
Cr-Commit-Position: refs/heads/master@{#550596}
parent 21168346
...@@ -1005,6 +1005,8 @@ static_library("extensions") { ...@@ -1005,6 +1005,8 @@ static_library("extensions") {
} }
} else { } else {
sources += [ sources += [
"api/enterprise_reporting_private/chrome_desktop_report_request_helper.cc",
"api/enterprise_reporting_private/chrome_desktop_report_request_helper.h",
"api/enterprise_reporting_private/enterprise_reporting_private_api.cc", "api/enterprise_reporting_private/enterprise_reporting_private_api.cc",
"api/enterprise_reporting_private/enterprise_reporting_private_api.h", "api/enterprise_reporting_private/enterprise_reporting_private_api.h",
"api/image_writer_private/operation_nonchromeos.cc", "api/image_writer_private/operation_nonchromeos.cc",
......
// Copyright 2018 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 "chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper.h"
#include <string>
#include "base/json/json_writer.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/policy/policy_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/channel_info.h"
#include "chrome/common/chrome_paths.h"
#include "components/policy/core/common/cloud/cloud_policy_util.h"
#include "components/policy/proto/device_management_backend.pb.h"
#include "components/version_info/channel.h"
#include "components/version_info/version_info.h"
namespace em = enterprise_management;
namespace extensions {
namespace {
// JSON key in extension arguments.
const char kMachineName[] = "machineName";
const char kOSInfo[] = "osInfo";
const char kOSUser[] = "osUser";
const char kBrowserReport[] = "browserReport";
const char kChromeUserProfileReport[] = "chromeUserProfileReport";
const char kChromeSignInUser[] = "chromeSignInUser";
const char kExtensionData[] = "extensionData";
const char kPlugins[] = "plugins";
// JSON key in the os_info field.
const char kOS[] = "os";
const char kOSVersion[] = "os_version";
const char kDefaultDictionary[] = "{}";
const char kDefaultList[] = "[]";
enum Type {
LIST,
DICTIONARY,
};
std::string GetChromePath() {
base::FilePath path;
base::PathService::Get(chrome::DIR_APP, &path);
return path.AsUTF8Unsafe();
}
std::string GetProfileId(const Profile* profile) {
return profile->GetOriginalProfile()->GetPath().AsUTF8Unsafe();
}
void AppendAdditionalBrowserInformation(em::ChromeDesktopReportRequest* request,
Profile* profile) {
// Set Chrome version number
request->mutable_browser_report()->set_browser_version(
version_info::GetVersionNumber());
// Set Chrome channel
request->mutable_browser_report()->set_channel(
static_cast<em::BrowserReport_Channel>(chrome::GetChannel()));
// Set Chrome executable path
request->mutable_browser_report()->set_executable_path(GetChromePath());
// Add a new profile report if extension doesn't report any profile.
if (request->browser_report().chrome_user_profile_reports_size() == 0)
request->mutable_browser_report()->add_chrome_user_profile_reports();
DCHECK_EQ(1, request->browser_report().chrome_user_profile_reports_size());
// Set profile ID for the first profile.
request->mutable_browser_report()
->mutable_chrome_user_profile_reports(0)
->set_id(GetProfileId(profile));
// Set policy data of the first profile. Extension will report this data in
// the future.
request->mutable_browser_report()
->mutable_chrome_user_profile_reports(0)
->set_policy_data(policy::GetAllPolicyValuesAsJSON(profile, true));
}
bool UpdateJSONEncodedStringEntry(const base::Value& dict_value,
const char key[],
std::string* entry,
const Type type) {
if (const base::Value* value = dict_value.FindKey(key)) {
if ((type == DICTIONARY && !value->is_dict()) ||
(type == LIST && !value->is_list())) {
return false;
}
base::JSONWriter::Write(*value, entry);
} else {
if (type == DICTIONARY)
*entry = kDefaultDictionary;
else if (type == LIST)
*entry = kDefaultList;
}
return true;
}
bool UpdateOSInfoEntry(const base::Value& report, std::string* os_info_string) {
base::Value writable_os_info(base::Value::Type::DICTIONARY);
if (const base::Value* os_info = report.FindKey(kOSInfo)) {
if (!os_info->is_dict())
return false;
writable_os_info = os_info->Clone();
}
writable_os_info.SetKey(kOS, base::Value(policy::GetOSPlatform()));
writable_os_info.SetKey(kOSVersion, base::Value(policy::GetOSVersion()));
base::JSONWriter::Write(writable_os_info, os_info_string);
return true;
}
std::unique_ptr<em::ChromeUserProfileReport>
GenerateChromeUserProfileReportRequest(const base::Value& profile_report) {
if (!profile_report.is_dict())
return nullptr;
std::unique_ptr<em::ChromeUserProfileReport> request =
std::make_unique<em::ChromeUserProfileReport>();
if (!UpdateJSONEncodedStringEntry(profile_report, kChromeSignInUser,
request->mutable_chrome_signed_in_user(),
DICTIONARY) ||
!UpdateJSONEncodedStringEntry(profile_report, kExtensionData,
request->mutable_extension_data(), LIST) ||
!UpdateJSONEncodedStringEntry(profile_report, kPlugins,
request->mutable_plugins(), LIST)) {
return nullptr;
}
return request;
}
} // namespace
std::unique_ptr<em::ChromeDesktopReportRequest>
GenerateChromeDesktopReportRequest(const base::DictionaryValue& report,
Profile* profile) {
std::unique_ptr<em::ChromeDesktopReportRequest> request =
std::make_unique<em::ChromeDesktopReportRequest>();
if (!UpdateJSONEncodedStringEntry(
report, kMachineName, request->mutable_machine_name(), DICTIONARY) ||
!UpdateJSONEncodedStringEntry(report, kOSUser, request->mutable_os_user(),
DICTIONARY) ||
!UpdateOSInfoEntry(report, request->mutable_os_info())) {
return nullptr;
}
if (const base::Value* browser_report =
report.FindKeyOfType(kBrowserReport, base::Value::Type::DICTIONARY)) {
if (const base::Value* profile_reports = browser_report->FindKeyOfType(
kChromeUserProfileReport, base::Value::Type::LIST)) {
if (profile_reports->GetList().size() > 0) {
DCHECK_EQ(1u, profile_reports->GetList().size());
// Currently, profile send their browser reports individually.
std::unique_ptr<em::ChromeUserProfileReport> profile_report_request =
GenerateChromeUserProfileReportRequest(
profile_reports->GetList()[0]);
if (!profile_report_request)
return nullptr;
request->mutable_browser_report()
->mutable_chrome_user_profile_reports()
->AddAllocated(profile_report_request.release());
}
}
}
AppendAdditionalBrowserInformation(request.get(), profile);
return request;
}
} // namespace extensions
// Copyright 2018 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 CHROME_BROWSER_EXTENSIONS_API_ENTERPRISE_REPORTING_PRIVATE_CHROME_DESKTOP_REPORT_REQUEST_HELPER_H_
#define CHROME_BROWSER_EXTENSIONS_API_ENTERPRISE_REPORTING_PRIVATE_CHROME_DESKTOP_REPORT_REQUEST_HELPER_H_
#include <memory>
#include "components/policy/proto/device_management_backend.pb.h"
class Profile;
namespace base {
class DictionaryValue;
} // namespace base
namespace extensions {
// Transfer the input from Json file to protobuf. Return nullptr if the input
// is not valid.
std::unique_ptr<enterprise_management::ChromeDesktopReportRequest>
GenerateChromeDesktopReportRequest(const base::DictionaryValue& report,
Profile* profile);
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_ENTERPRISE_REPORTING_PRIVATE_CHROME_DESKTOP_REPORT_REQUEST_HELPER_H_
// Copyright 2018 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 "chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper.h"
#include "base/json/json_reader.h"
#include "base/values.h"
#include "chrome/test/base/testing_profile.h"
#include "components/policy/core/common/cloud/cloud_policy_util.h"
#include "components/policy/proto/device_management_backend.pb.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace em = enterprise_management;
namespace extensions {
class ChromeDesktopReportRequestGeneratorTest : public ::testing::Test {
protected:
content::TestBrowserThreadBundle test_browser_thread_bundle_;
TestingProfile profile_;
};
TEST_F(ChromeDesktopReportRequestGeneratorTest, OSInfo) {
std::unique_ptr<em::ChromeDesktopReportRequest> request;
std::string expected_os_info;
// Platform and its version will be the |os_info| by default.
expected_os_info = base::StringPrintf("{\"os\":\"%s\",\"os_version\":\"%s\"}",
policy::GetOSPlatform().c_str(),
policy::GetOSVersion().c_str());
request =
GenerateChromeDesktopReportRequest(base::DictionaryValue(), &profile_);
ASSERT_TRUE(request);
EXPECT_EQ(expected_os_info, request->os_info());
// Platform and its version will be merged with other |os_info|.
expected_os_info = base::StringPrintf(
"{\"os\":\"%s\",\"os_version\":\"%s\",\"other_info\":\"info\"}",
policy::GetOSPlatform().c_str(), policy::GetOSVersion().c_str());
std::unique_ptr<base::DictionaryValue> report = base::DictionaryValue::From(
base::JSONReader::Read("{\"osInfo\": {\"other_info\":\"info\"}}"));
ASSERT_TRUE(report);
request = GenerateChromeDesktopReportRequest(*report, &profile_);
ASSERT_TRUE(request);
EXPECT_EQ(expected_os_info, request->os_info());
}
TEST_F(ChromeDesktopReportRequestGeneratorTest, MachineName) {
std::unique_ptr<em::ChromeDesktopReportRequest> request;
std::string expected_machine_name;
// Machine name will be a empty dict by default.
expected_machine_name = "{}";
request =
GenerateChromeDesktopReportRequest(base::DictionaryValue(), &profile_);
ASSERT_TRUE(request);
EXPECT_EQ(expected_machine_name, request->machine_name());
// Machine name will be copied from the |report|.
expected_machine_name = "{\"computername\":\"name\"}";
std::unique_ptr<base::DictionaryValue> report = base::DictionaryValue::From(
base::JSONReader::Read("{\"machineName\":{\"computername\":\"name\"}}"));
ASSERT_TRUE(report);
request = GenerateChromeDesktopReportRequest(*report, &profile_);
ASSERT_TRUE(request);
EXPECT_EQ(expected_machine_name, request->machine_name());
}
TEST_F(ChromeDesktopReportRequestGeneratorTest, ExtensionList) {
std::unique_ptr<em::ChromeDesktopReportRequest> request;
std::unique_ptr<base::DictionaryValue> report;
std::string expected_extension_list;
// Extension list will be a empty list by default.
expected_extension_list = "[]";
report = base::DictionaryValue::From(base::JSONReader::Read(
"{\"browserReport\": {\"chromeUserProfileReport\":[{}]}}"));
ASSERT_TRUE(report);
request = GenerateChromeDesktopReportRequest(*report, &profile_);
ASSERT_TRUE(request);
EXPECT_EQ(expected_extension_list, request->browser_report()
.chrome_user_profile_reports(0)
.extension_data());
// Extension list will be copied from the |report|.
expected_extension_list = "[{\"id\":\"1\"}]";
report = base::DictionaryValue::From(base::JSONReader::Read(
"{\"browserReport\": "
"{\"chromeUserProfileReport\":[{\"extensionData\":[{\"id\":\"1\"}]}]}}"));
ASSERT_TRUE(report);
request = GenerateChromeDesktopReportRequest(*report, &profile_);
ASSERT_TRUE(request);
EXPECT_EQ(expected_extension_list, request->browser_report()
.chrome_user_profile_reports(0)
.extension_data());
}
TEST_F(ChromeDesktopReportRequestGeneratorTest, ProfileID) {
std::unique_ptr<em::ChromeDesktopReportRequest> request;
// |chrome_user_profile_report| will be created with Profile ID by default.
request =
GenerateChromeDesktopReportRequest(base::DictionaryValue(), &profile_);
ASSERT_TRUE(request);
EXPECT_EQ(profile_.GetPath().AsUTF8Unsafe(),
request->browser_report().chrome_user_profile_reports(0).id());
// Profile ID will be merged into the first item of
// |chrome_user_profile_reports|
std::unique_ptr<base::DictionaryValue> report = base::DictionaryValue::From(
base::JSONReader::Read("{\"browserReport\": "
"{\"chromeUserProfileReport\":[{\"extensionData\":"
"[{\"id\":\"1\"}]}]}}"));
ASSERT_TRUE(report);
request = GenerateChromeDesktopReportRequest(*report, &profile_);
ASSERT_TRUE(request);
EXPECT_EQ(profile_.GetPath().AsUTF8Unsafe(),
request->browser_report().chrome_user_profile_reports(0).id());
}
TEST_F(ChromeDesktopReportRequestGeneratorTest, InvalidInput) {
// |request| will not be generated if the type of input is invalid.
std::unique_ptr<base::DictionaryValue> report;
report = base::DictionaryValue::From(
base::JSONReader::Read("{\"osInfo\": \"info\"}"));
ASSERT_TRUE(report);
EXPECT_FALSE(GenerateChromeDesktopReportRequest(*report, &profile_));
report = base::DictionaryValue::From(
base::JSONReader::Read("{\"machineName\": \"info\"}"));
ASSERT_TRUE(report);
EXPECT_FALSE(GenerateChromeDesktopReportRequest(*report, &profile_));
report = base::DictionaryValue::From(base::JSONReader::Read(
"{\"browserReport\": "
"{\"chromeUserProfileReport\":[{\"extensionData\":{}}]}}"));
ASSERT_TRUE(report);
EXPECT_FALSE(GenerateChromeDesktopReportRequest(*report, &profile_));
}
} // namespace extensions
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/json/json_writer.h" #include "base/json/json_writer.h"
#include "base/values.h" #include "base/values.h"
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper.h"
#include "chrome/browser/policy/browser_dm_token_storage.h" #include "chrome/browser/policy/browser_dm_token_storage.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h" #include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
...@@ -22,43 +23,6 @@ ...@@ -22,43 +23,6 @@
namespace em = enterprise_management; namespace em = enterprise_management;
namespace extensions { namespace extensions {
namespace {
const char kMachineName[] = "machineName";
const char kOSInfo[] = "osInfo";
const char kOSUser[] = "osUser";
bool UpdateJSONEncodedStringEntry(const base::Value& dict_value,
const char key[],
std::string* entry) {
if (const base::Value* value = dict_value.FindKey(key)) {
if (!value->is_dict() && !value->is_list())
return false;
base::JSONWriter::Write(*value, entry);
}
return true;
}
// Transfer the input from Json file to protobuf. Return nullptr if the input
// is not valid.
std::unique_ptr<enterprise_management::ChromeDesktopReportRequest>
GenerateChromeDesktopReportRequest(const base::DictionaryValue& report) {
std::unique_ptr<em::ChromeDesktopReportRequest> request =
std::make_unique<em::ChromeDesktopReportRequest>();
if (!UpdateJSONEncodedStringEntry(report, kMachineName,
request->mutable_machine_name()) ||
!UpdateJSONEncodedStringEntry(report, kOSInfo,
request->mutable_os_info()) ||
!UpdateJSONEncodedStringEntry(report, kOSUser,
request->mutable_os_user())) {
return nullptr;
}
return request;
}
} // namespace
namespace enterprise_reporting { namespace enterprise_reporting {
const char kInvalidInputErrorMessage[] = "The report is not valid."; const char kInvalidInputErrorMessage[] = "The report is not valid.";
...@@ -96,7 +60,9 @@ EnterpriseReportingPrivateUploadChromeDesktopReportFunction::Run() { ...@@ -96,7 +60,9 @@ EnterpriseReportingPrivateUploadChromeDesktopReportFunction::Run() {
Params::Create(*args_)); Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get()); EXTENSION_FUNCTION_VALIDATE(params.get());
std::unique_ptr<em::ChromeDesktopReportRequest> request = std::unique_ptr<em::ChromeDesktopReportRequest> request =
GenerateChromeDesktopReportRequest(params->report.additional_properties); GenerateChromeDesktopReportRequest(
params->report.additional_properties,
Profile::FromBrowserContext(browser_context()));
if (!request) { if (!request) {
return RespondNow(Error(enterprise_reporting::kInvalidInputErrorMessage)); return RespondNow(Error(enterprise_reporting::kInvalidInputErrorMessage));
} }
......
...@@ -3598,6 +3598,7 @@ test("unit_tests") { ...@@ -3598,6 +3598,7 @@ test("unit_tests") {
] ]
} else { } else {
sources += [ sources += [
"../browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper_unittest.cc",
"../browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc", "../browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc",
"../browser/extensions/api/messaging/native_message_process_host_unittest.cc", "../browser/extensions/api/messaging/native_message_process_host_unittest.cc",
"../browser/extensions/api/messaging/native_messaging_host_manifest_unittest.cc", "../browser/extensions/api/messaging/native_messaging_host_manifest_unittest.cc",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment