| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| |
| #include "components/feedback/feedback_util.h" |
| |
| #include <string> |
| |
| #include "base/files/file_util.h" |
| #include "base/files/scoped_file.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/json/json_writer.h" |
| #include "base/rand_util.h" |
| #include "base/test/values_test_util.h" |
| #include "components/feedback/feedback_report.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace feedback_util { |
| |
| // Note: This file is excluded from win build. |
| // See https://crbug.com/1119560. |
| class FeedbackUtilTest : public ::testing::Test { |
| public: |
| void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); } |
| |
| base::ScopedTempDir temp_dir_; |
| }; |
| |
| TEST_F(FeedbackUtilTest, ReadEndOfFileEmpty) { |
| base::FilePath file_path = temp_dir_.GetPath().Append("test_empty.txt"); |
| |
| EXPECT_TRUE(WriteFile(file_path, "")); |
| |
| EXPECT_THAT(feedback_util::ReadEndOfFile(file_path, 10), |
| testing::Optional(std::string())); |
| } |
| |
| TEST_F(FeedbackUtilTest, ReadEndOfFileSmall) { |
| const char kTestData[] = "0123456789"; // Length of 10 |
| base::FilePath file_path = temp_dir_.GetPath().Append("test_small.txt"); |
| |
| EXPECT_TRUE(WriteFile(file_path, kTestData)); |
| |
| EXPECT_THAT(feedback_util::ReadEndOfFile(file_path, 15), |
| testing::Optional(std::string(kTestData))); |
| |
| EXPECT_THAT(feedback_util::ReadEndOfFile(file_path, 10), |
| testing::Optional(std::string(kTestData))); |
| |
| EXPECT_THAT(feedback_util::ReadEndOfFile(file_path, 2), |
| testing::Optional(std::string("89"))); |
| |
| EXPECT_THAT(feedback_util::ReadEndOfFile(file_path, 3), |
| testing::Optional(std::string("789"))); |
| |
| EXPECT_THAT(feedback_util::ReadEndOfFile(file_path, 5), |
| testing::Optional(std::string("56789"))); |
| } |
| |
| TEST_F(FeedbackUtilTest, ReadEndOfFileWithZeros) { |
| const size_t test_size = 10; |
| std::string test_data("abcd\0\0\0\0hi", test_size); |
| |
| base::FilePath file_path = temp_dir_.GetPath().Append("test_zero.txt"); |
| |
| EXPECT_TRUE(WriteFile(file_path, test_data)); |
| |
| EXPECT_THAT(feedback_util::ReadEndOfFile(file_path, 15), |
| testing::Optional(test_data)); |
| |
| EXPECT_THAT(feedback_util::ReadEndOfFile(file_path, 10), |
| testing::Optional(test_data)); |
| |
| EXPECT_THAT(feedback_util::ReadEndOfFile(file_path, 2), |
| testing::Optional(test_data.substr(test_size - 2, 2))); |
| |
| EXPECT_THAT(feedback_util::ReadEndOfFile(file_path, 3), |
| testing::Optional(test_data.substr(test_size - 3, 3))); |
| |
| EXPECT_THAT(feedback_util::ReadEndOfFile(file_path, 5), |
| testing::Optional(test_data.substr(test_size - 5, 5))); |
| } |
| |
| TEST_F(FeedbackUtilTest, ReadEndOfFileMedium) { |
| std::string test_data = base::RandBytesAsString(10000); // 10KB data |
| |
| const size_t test_size = test_data.length(); |
| |
| base::FilePath file_path = temp_dir_.GetPath().Append("test_med.txt"); |
| |
| EXPECT_TRUE(WriteFile(file_path, test_data)); |
| |
| EXPECT_THAT(feedback_util::ReadEndOfFile(file_path, 15000), |
| testing::Optional(test_data)); |
| |
| EXPECT_THAT(feedback_util::ReadEndOfFile(file_path, 10000), |
| testing::Optional(test_data)); |
| |
| EXPECT_THAT(feedback_util::ReadEndOfFile(file_path, 1000), |
| testing::Optional(test_data.substr(test_size - 1000, 1000))); |
| |
| EXPECT_THAT(feedback_util::ReadEndOfFile(file_path, 300), |
| testing::Optional(test_data.substr(test_size - 300, 300))); |
| |
| EXPECT_THAT(feedback_util::ReadEndOfFile(file_path, 175), |
| testing::Optional(test_data.substr(test_size - 175, 175))); |
| } |
| |
| TEST_F(FeedbackUtilTest, LogsToStringShouldSkipFeedbackUserCtlConsentKey) { |
| FeedbackCommon::SystemLogsMap sys_info; |
| sys_info[feedback::FeedbackReport::kFeedbackUserCtlConsentKey] = "true"; |
| |
| std::string logs = feedback_util::LogsToString(sys_info); |
| EXPECT_TRUE(logs.empty()); |
| |
| // Now add a fake key expected to be in system_logs. |
| sys_info["fake_key"] = "fake_value"; |
| logs = feedback_util::LogsToString(sys_info); |
| EXPECT_EQ("fake_key=fake_value\n", logs); |
| } |
| |
| TEST_F(FeedbackUtilTest, RemoveUrlsFromAutofillData) { |
| base::DictValue autofill_data = base::test::ParseJsonDict( |
| R"({ |
| "formStructures": [ |
| { |
| "formSignature": "123", |
| "sourceUrl": "https://www.example.com", |
| "mainFrameUrl": "https://www.example.com" |
| }, |
| { |
| "formSignature": "456", |
| "sourceUrl": "https://www.another-example.com", |
| "mainFrameUrl": "https://www.another-example.com" |
| } |
| ]})"); |
| std::string autofill_data_str = base::WriteJson(autofill_data).value_or(""); |
| |
| base::ListValue* form_structures = autofill_data.FindList("formStructures"); |
| ASSERT_TRUE(form_structures); |
| for (base::Value& item : *form_structures) { |
| auto& dict = item.GetDict(); |
| dict.Remove("sourceUrl"); |
| dict.Remove("mainFrameUrl"); |
| } |
| |
| std::string expected_autofill_data_str = |
| base::WriteJson(autofill_data).value_or(""); |
| |
| feedback_util::RemoveUrlsFromAutofillData(autofill_data_str); |
| EXPECT_EQ(autofill_data_str, expected_autofill_data_str); |
| } |
| |
| TEST_F(FeedbackUtilTest, ZipStringTraversal) { |
| // Create a temp directory, and target a file within it: |
| base::ScopedTempDir root_dir; |
| ASSERT_TRUE(root_dir.CreateUniqueTempDir()); |
| base::FilePath sensitive_file = |
| root_dir.GetPath().AppendASCII("sensitive.txt"); |
| |
| // Construct a traversal back to that file in a platform-dependent way: |
| std::string sensitive_path_str = sensitive_file.AsUTF8Unsafe(); |
| #if BUILDFLAG(IS_WIN) |
| // Remove "C:" if present |
| if (sensitive_path_str.size() >= 2 && sensitive_path_str[1] == ':') { |
| sensitive_path_str = sensitive_path_str.substr(2); |
| } |
| // Remove leading backslash |
| if (!sensitive_path_str.empty() && sensitive_path_str[0] == '\\') { |
| sensitive_path_str = sensitive_path_str.substr(1); |
| } |
| base::FilePath traversal( |
| FILE_PATH_LITERAL("..\\..\\..\\..\\..\\..\\..\\..\\")); |
| #else |
| // Remove leading slash |
| if (!sensitive_path_str.empty() && sensitive_path_str[0] == '/') { |
| sensitive_path_str = sensitive_path_str.substr(1); |
| } |
| base::FilePath traversal(FILE_PATH_LITERAL("../../../../../../../../")); |
| #endif |
| |
| base::FilePath malicious_filename = |
| traversal.Append(base::FilePath::FromUTF8Unsafe(sensitive_path_str)); |
| |
| // Call ZipString. |
| std::optional<std::string> result = |
| feedback_util::ZipString(malicious_filename, "maliciousness"); |
| |
| EXPECT_FALSE(result.has_value()); |
| EXPECT_FALSE(base::PathExists(sensitive_file)); |
| } |
| |
| } // namespace feedback_util |