mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 22:56:12 -04:00
Fix crash caused by invalid preferences
PiperOrigin-RevId: 533179434
This commit is contained in:
@@ -194,6 +194,12 @@ bool PreferencesManager::Commit() {
|
||||
}
|
||||
|
||||
bool PreferencesManager::SetValue(absl::string_view key, const json& value) {
|
||||
if (!value_.is_object()) {
|
||||
NEARBY_LOGS(ERROR) << "Preferences is no longer an object! value_="
|
||||
<< value_.dump(4);
|
||||
value_ = json::object();
|
||||
}
|
||||
|
||||
if (value_[absl::StrCat(key)] == value) {
|
||||
return false;
|
||||
}
|
||||
@@ -205,6 +211,12 @@ bool PreferencesManager::SetValue(absl::string_view key, const json& value) {
|
||||
template <typename T>
|
||||
T PreferencesManager::GetValue(absl::string_view key,
|
||||
const T& default_value) const {
|
||||
if (!value_.is_object()) {
|
||||
NEARBY_LOGS(ERROR) << "Preferences is no longer an object! value_="
|
||||
<< value_.dump(4);
|
||||
return default_value;
|
||||
}
|
||||
|
||||
auto it = value_.find(absl::StrCat(key));
|
||||
if (it == value_.end()) {
|
||||
return default_value;
|
||||
@@ -215,6 +227,12 @@ T PreferencesManager::GetValue(absl::string_view key,
|
||||
template <typename T>
|
||||
bool PreferencesManager::SetArrayValue(absl::string_view key,
|
||||
absl::Span<const T> value) {
|
||||
if (!value_.is_object()) {
|
||||
NEARBY_LOGS(ERROR) << "Preferences is no longer an object! value_="
|
||||
<< value_.dump(4);
|
||||
value_ = json::object();
|
||||
}
|
||||
|
||||
json array_value = json::array();
|
||||
for (const T& item_value : value) {
|
||||
array_value.push_back(item_value);
|
||||
@@ -233,6 +251,16 @@ std::vector<T> PreferencesManager::GetArrayValue(
|
||||
absl::string_view key, absl::Span<const T> default_value) const {
|
||||
std::vector<T> result;
|
||||
|
||||
if (!value_.is_object()) {
|
||||
NEARBY_LOGS(ERROR) << "Preferences is no longer an object! value_="
|
||||
<< value_.dump(4);
|
||||
|
||||
for (const T& value : default_value) {
|
||||
result.push_back(value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
auto array_value = value_.find(absl::StrCat(key));
|
||||
if (array_value == value_.end() || !array_value->is_array()) {
|
||||
for (const T& value : default_value) {
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <codecvt>
|
||||
#include <filesystem> // NOLINT(build/c++17)
|
||||
#include <fstream>
|
||||
#include <locale>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -29,6 +31,7 @@
|
||||
#include "absl/types/span.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "nlohmann/json_fwd.hpp"
|
||||
#include "internal/platform/logging.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
@@ -38,27 +41,27 @@ constexpr absl::Duration kTimeOut = absl::Milliseconds(200);
|
||||
constexpr char kPreferencesFilePath[] = "Google/Nearby/Sharing";
|
||||
} // namespace
|
||||
|
||||
|
||||
TEST(PreferencesManager, CorruptedConfigFile) {
|
||||
std::filesystem::path settingsPath =
|
||||
std::filesystem::temp_directory_path() / "settings.json";
|
||||
std::ofstream output_stream{settingsPath};
|
||||
output_stream << "{\"data\":8, \"names\": [\"In valid\"}" << std::endl;
|
||||
output_stream.close();
|
||||
std::filesystem::temp_directory_path();
|
||||
std::ofstream output_stream{settingsPath / "preferences.json"};
|
||||
output_stream << "CORRUPTED" << std::endl;
|
||||
|
||||
// Should use an empty setting for a corrupted configuration file.
|
||||
EXPECT_EQ(PreferencesManager(kPreferencesFilePath).GetInteger("data", 100),
|
||||
NEARBY_LOGS(INFO) << "Loading preferences from: " << settingsPath.string();
|
||||
EXPECT_EQ(PreferencesManager(settingsPath.string()).GetInteger("data", 100),
|
||||
100);
|
||||
}
|
||||
|
||||
TEST(PreferencesManager, ValidConfigFile) {
|
||||
std::filesystem::path settingsPath =
|
||||
std::filesystem::temp_directory_path() / "settings.json";
|
||||
std::ofstream output_stream{settingsPath};
|
||||
std::filesystem::temp_directory_path();
|
||||
std::ofstream output_stream{settingsPath / "preferences.json"};
|
||||
output_stream << "{\"data\":8, \"name\": \"Valid\"}" << std::endl;
|
||||
output_stream.close();
|
||||
|
||||
// Should use an empty setting for a corrupted configuration file.
|
||||
EXPECT_EQ(PreferencesManager(kPreferencesFilePath).GetInteger("data", 100),
|
||||
NEARBY_LOGS(INFO) << "Loading preferences from: " << settingsPath.string();
|
||||
EXPECT_EQ(PreferencesManager(settingsPath.string()).GetInteger("data", 100),
|
||||
8);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,15 @@ json PreferencesRepository::LoadPreferences() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
std::optional<json> preferences = AttemptLoad();
|
||||
if (preferences.has_value()) {
|
||||
// The top level root should be an object, if it's not then something went
|
||||
// wrong or the file was corrupted.
|
||||
if (!preferences.value().is_object()) {
|
||||
NEARBY_LOGS(ERROR) << "Preferences loaded was not a valid object: "
|
||||
<< preferences.value().dump(4);
|
||||
|
||||
return json::object();
|
||||
}
|
||||
|
||||
return preferences.value();
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,25 @@ TEST(PreferencesRepository, LoadWithBadPath) {
|
||||
EXPECT_TRUE(result.empty());
|
||||
}
|
||||
|
||||
TEST(PreferencesRepository, RecoverFromBadPreferences) {
|
||||
std::optional<std::filesystem::path> app_data_path =
|
||||
api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath();
|
||||
ASSERT_TRUE(app_data_path.has_value());
|
||||
std::filesystem::path full_path = *app_data_path / kPreferencesPath;
|
||||
std::filesystem::path full_name = full_path / kPreferencesFileName;
|
||||
|
||||
if (std::filesystem::exists(full_name)) {
|
||||
std::filesystem::remove(full_name);
|
||||
}
|
||||
|
||||
std::ofstream pref_file(full_name.c_str());
|
||||
pref_file << "\"Bad top level object\"";
|
||||
pref_file.close();
|
||||
|
||||
PreferencesRepository preferences_repository{full_path.string()};
|
||||
EXPECT_EQ(preferences_repository.LoadPreferences(), json::object());
|
||||
}
|
||||
|
||||
TEST(PreferencesRepository, SaveAndLoadPreferences) {
|
||||
std::optional<std::filesystem::path> app_data_path =
|
||||
api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath();
|
||||
|
||||
Reference in New Issue
Block a user