From eb47509d98cbbe8ba39ebb7f42ee89f7a1ce0965 Mon Sep 17 00:00:00 2001 From: oisupov Date: Fri, 2 Dec 2022 20:20:57 +0400 Subject: [PATCH 01/15] Add pin-related RPC calls to IpfsService Resolves https://github.com/brave/brave-browser/issues/19283 --- components/ipfs/ipfs_constants.cc | 6 + components/ipfs/ipfs_constants.h | 6 + components/ipfs/ipfs_json_parser.cc | 126 +++++++++++++ components/ipfs/ipfs_json_parser.h | 9 + components/ipfs/ipfs_json_parser_unittest.cc | 106 +++++++++++ components/ipfs/ipfs_service.cc | 186 ++++++++++++++++++- components/ipfs/ipfs_service.h | 39 +++- components/ipfs/pin/ipfs_pin_rpc_types.cc | 16 ++ components/ipfs/pin/ipfs_pin_rpc_types.h | 29 +++ 9 files changed, 519 insertions(+), 4 deletions(-) create mode 100644 components/ipfs/pin/ipfs_pin_rpc_types.cc create mode 100644 components/ipfs/pin/ipfs_pin_rpc_types.h diff --git a/components/ipfs/ipfs_constants.cc b/components/ipfs/ipfs_constants.cc index 042a820b6c22..99da29342948 100644 --- a/components/ipfs/ipfs_constants.cc +++ b/components/ipfs/ipfs_constants.cc @@ -45,4 +45,10 @@ const char kFileValueName[] = "file"; const char kFileMimeType[] = "application/octet-stream"; const char kDirectoryMimeType[] = "application/x-directory"; const char kIPFSImportTextMimeType[] = "application/octet-stream"; + +// Local pins +const char kAddPinPath[] = "api/v0/pin/add"; +const char kRemovePinPath[] = "api/v0/pin/rm"; +const char kGetPinsPath[] = "api/v0/pin/ls"; + } // namespace ipfs diff --git a/components/ipfs/ipfs_constants.h b/components/ipfs/ipfs_constants.h index 41677495ef44..15547af8b954 100644 --- a/components/ipfs/ipfs_constants.h +++ b/components/ipfs/ipfs_constants.h @@ -42,6 +42,12 @@ extern const char kFileValueName[]; extern const char kFileMimeType[]; extern const char kDirectoryMimeType[]; extern const char kIPFSImportTextMimeType[]; +extern const char kNodeInfoPath[]; + +// Local pins +extern const char kAddPinPath[]; +extern const char kRemovePinPath[]; +extern const char kGetPinsPath[]; // Keep it synced with IPFSResolveMethodTypes in // browser/resources/settings/brave_ipfs_page/brave_ipfs_page.js diff --git a/components/ipfs/ipfs_json_parser.cc b/components/ipfs/ipfs_json_parser.cc index 4d069d81efc9..a80b20c94031 100644 --- a/components/ipfs/ipfs_json_parser.cc +++ b/components/ipfs/ipfs_json_parser.cc @@ -40,6 +40,132 @@ bool RemoveValueFromList(base::Value::List* root, const T& value_to_remove) { } // namespace +// static +// Response format /api/v0/pin/add +// { +// "Pins": [ +// "" +// ], +// "Progress": "" +// } +bool IPFSJSONParser::GetAddPinsResultFromJSON( + const std::string& json, + ipfs::AddPinResult* add_pin_result) { + absl::optional records_v = + base::JSONReader::Read(json, base::JSON_PARSE_CHROMIUM_EXTENSIONS | + base::JSONParserOptions::JSON_PARSE_RFC); + + if (!records_v) { + VLOG(1) << "Invalid response, could not parse JSON, JSON is: " << json; + return false; + } + + const base::Value* pins_arr = records_v->FindKey("Pins"); + if (!pins_arr || !pins_arr->is_list()) { + VLOG(1) << "Invalid response, can not find Pins array."; + return false; + } + + auto progress = records_v->FindIntKey("Progress"); + if (progress) { + add_pin_result->progress = *progress; + } else { + add_pin_result->progress = -1; + } + + for (const base::Value& val : pins_arr->GetList()) { + add_pin_result->pins.push_back(val.GetString()); + } + return true; +} + +// static +// Response format /api/v0/pin/rm +// { +// "Pins": [ +// "" +// ] +// } +bool IPFSJSONParser::GetRemovePinsResultFromJSON( + const std::string& json, + ipfs::RemovePinResult* remove_pin_result) { + absl::optional records_v = + base::JSONReader::Read(json, base::JSON_PARSE_CHROMIUM_EXTENSIONS | + base::JSONParserOptions::JSON_PARSE_RFC); + + if (!records_v) { + VLOG(1) << "Invalid response, could not parse JSON, JSON is: " << json; + return false; + } + + const base::Value* pins_arr = records_v->FindKey("Pins"); + if (!pins_arr || !pins_arr->is_list()) { + VLOG(1) << "Invalid response, can not find Pins array."; + return false; + } + + ipfs::RemovePinResult result; + for (const base::Value& val : pins_arr->GetList()) { + auto* val_as_str = val.GetIfString(); + if (!val_as_str) { + return false; + } + result.push_back(*val_as_str); + } + *remove_pin_result = result; + return true; +} + +// static +// Response format /api/v0/pin/ls +// { +// "PinLsList": { +// "Keys": { +// "": { +// "Type": "" +// } +// } +// }, +// "PinLsObject": { +// "Cid": "", +// "Type": "" +// } +// } +bool IPFSJSONParser::GetGetPinsResultFromJSON( + const std::string& json, + ipfs::GetPinsResult* get_pins_result) { + DCHECK(get_pins_result); + absl::optional records_v = + base::JSONReader::Read(json, base::JSON_PARSE_CHROMIUM_EXTENSIONS | + base::JSONParserOptions::JSON_PARSE_RFC); + + if (!records_v) { + VLOG(1) << "Invalid response, could not parse JSON, JSON is: " << json; + return false; + } + + const base::Value* keys = records_v->FindKey("Keys"); + if (!keys || !keys->is_dict()) { + VLOG(1) << "Invalid response, can not find Keys in PinLsList dict."; + return false; + } + + for (const auto it : keys->GetDict()) { + if (!it.second.is_dict()) { + VLOG(1) << "Missing Type for " << it.first; + return false; + } + const std::string* type = it.second.FindStringKey("Type"); + if (!type) { + VLOG(1) << "Missing Type for " << it.first; + return false; + } + (*get_pins_result)[it.first] = *type; + } + + return true; +} + // static // Response Format for /api/v0/swarm/peers // { diff --git a/components/ipfs/ipfs_json_parser.h b/components/ipfs/ipfs_json_parser.h index 8ac6fb5cc42a..aef6dfb56152 100644 --- a/components/ipfs/ipfs_json_parser.h +++ b/components/ipfs/ipfs_json_parser.h @@ -14,6 +14,7 @@ #include "brave/components/ipfs/addresses_config.h" #include "brave/components/ipfs/import/imported_data.h" #include "brave/components/ipfs/node_info.h" +#include "brave/components/ipfs/pin/ipfs_pin_rpc_types.h" #include "brave/components/ipfs/repo_stats.h" class IPFSJSONParser { @@ -46,6 +47,14 @@ class IPFSJSONParser { static std::string RemovePeerFromConfigJSON(const std::string& json, const std::string& peer_id, const std::string& address); + // Local pins + static bool GetAddPinsResultFromJSON(const std::string& json, + ipfs::AddPinResult* add_pin_result); + static bool GetGetPinsResultFromJSON(const std::string& json, + ipfs::GetPinsResult* result); + static bool GetRemovePinsResultFromJSON( + const std::string& json, + ipfs::RemovePinResult* add_pin_result); }; #endif // BRAVE_COMPONENTS_IPFS_IPFS_JSON_PARSER_H_ diff --git a/components/ipfs/ipfs_json_parser_unittest.cc b/components/ipfs/ipfs_json_parser_unittest.cc index 90473b782d40..5f9e35270f9c 100644 --- a/components/ipfs/ipfs_json_parser_unittest.cc +++ b/components/ipfs/ipfs_json_parser_unittest.cc @@ -382,3 +382,109 @@ TEST_F(IPFSJSONParserTest, RemovePeerFromConfigJSONTest) { "{\"Peering\":{\"Peers\":" "[{\"Addrs\":[\"/b\"],\"ID\":\"QmA\"}]}}"); } + +TEST_F(IPFSJSONParserTest, GetGetPinsResultFromJSONTest) { + { + std::string json = R"({})"; + ipfs::GetPinsResult result; + EXPECT_FALSE(IPFSJSONParser::GetGetPinsResultFromJSON(json, &result)); + } + + { + std::string json = R"({"Keys":{"QmA" : {"Type" : "Recursive"}}})"; + ipfs::GetPinsResult result; + EXPECT_TRUE(IPFSJSONParser::GetGetPinsResultFromJSON(json, &result)); + EXPECT_EQ(result.at("QmA"), "Recursive"); + } + + { + std::string json = R"({"Keys":{}})"; + ipfs::GetPinsResult result; + EXPECT_TRUE(IPFSJSONParser::GetGetPinsResultFromJSON(json, &result)); + EXPECT_TRUE(result.empty()); + } + + { + std::string json = R"({"Keys":[]})"; + ipfs::GetPinsResult result; + EXPECT_FALSE(IPFSJSONParser::GetGetPinsResultFromJSON(json, &result)); + } + + { + std::string json = + R"({"Keys":{"QmA" : {"Type" :"Recursive"}, "QmB" : {"Type" :"Direct"}}})"; + ipfs::GetPinsResult result; + EXPECT_TRUE(IPFSJSONParser::GetGetPinsResultFromJSON(json, &result)); + EXPECT_EQ(result.at("QmA"), "Recursive"); + EXPECT_EQ(result.at("QmB"), "Direct"); + } +} + +TEST_F(IPFSJSONParserTest, GetRemovePinsResultFromJSONTest) { + { + std::string json = R"({})"; + ipfs::RemovePinResult result; + EXPECT_FALSE(IPFSJSONParser::GetRemovePinsResultFromJSON(json, &result)); + } + + { + std::string json = R"({"Pins" : {}})"; + ipfs::RemovePinResult result; + EXPECT_FALSE(IPFSJSONParser::GetRemovePinsResultFromJSON(json, &result)); + } + + { + std::string json = R"({"Pins" : []})"; + ipfs::RemovePinResult result; + EXPECT_TRUE(IPFSJSONParser::GetRemovePinsResultFromJSON(json, &result)); + EXPECT_TRUE(result.empty()); + } + + { + std::string json = R"({"Pins" : ["QmA", "QmB"]})"; + ipfs::RemovePinResult result; + EXPECT_TRUE(IPFSJSONParser::GetRemovePinsResultFromJSON(json, &result)); + EXPECT_EQ(result.at(0), "QmA"); + EXPECT_EQ(result.at(1), "QmB"); + } +} + +TEST_F(IPFSJSONParserTest, GetAddPinsResultFromJSONTest) { + { + std::string json = R"({})"; + ipfs::AddPinResult result; + EXPECT_FALSE(IPFSJSONParser::GetAddPinsResultFromJSON(json, &result)); + } + + { + std::string json = R"({"Pins" : {}})"; + ipfs::AddPinResult result; + EXPECT_FALSE(IPFSJSONParser::GetAddPinsResultFromJSON(json, &result)); + } + + { + std::string json = R"({"Pins" : []})"; + ipfs::AddPinResult result; + EXPECT_TRUE(IPFSJSONParser::GetAddPinsResultFromJSON(json, &result)); + EXPECT_TRUE(result.pins.empty()); + EXPECT_EQ(result.progress, -1); + } + + { + std::string json = R"({"Pins" : ["QmA", "QmB"]})"; + ipfs::AddPinResult result; + EXPECT_TRUE(IPFSJSONParser::GetAddPinsResultFromJSON(json, &result)); + EXPECT_EQ(result.pins.at(0), "QmA"); + EXPECT_EQ(result.pins.at(1), "QmB"); + EXPECT_EQ(result.progress, -1); + } + + { + std::string json = R"({"Pins" : ["QmA", "QmB"], "Progress" : 10})"; + ipfs::AddPinResult result; + EXPECT_TRUE(IPFSJSONParser::GetAddPinsResultFromJSON(json, &result)); + EXPECT_EQ(result.pins.at(0), "QmA"); + EXPECT_EQ(result.pins.at(1), "QmB"); + EXPECT_EQ(result.progress, 10); + } +} diff --git a/components/ipfs/ipfs_service.cc b/components/ipfs/ipfs_service.cc index 92fdbf8e6259..996c1929ba9e 100644 --- a/components/ipfs/ipfs_service.cc +++ b/components/ipfs/ipfs_service.cc @@ -96,6 +96,8 @@ std::pair LoadConfigFileOnFileTaskRunner( namespace ipfs { +IpfsService::IpfsService() : ipfs_p3a_(nullptr, nullptr), weak_factory_(this) {} + IpfsService::IpfsService( PrefService* prefs, scoped_refptr url_loader_factory, @@ -141,7 +143,9 @@ IpfsService::~IpfsService() { ipfs_client_updater_->RemoveObserver(this); } #if BUILDFLAG(ENABLE_IPFS_LOCAL_NODE) - RemoveObserver(ipns_keys_manager_.get()); + if (observers_.HasObserver(ipns_keys_manager_.get())) { + RemoveObserver(ipns_keys_manager_.get()); + } #endif Shutdown(); } @@ -162,6 +166,7 @@ void IpfsService::RegisterProfilePrefs(PrefRegistrySimple* registry) { registry->RegisterStringPref(kIPFSPublicNFTGatewayAddress, kDefaultIPFSNFTGateway); registry->RegisterFilePathPref(kIPFSBinaryPath, base::FilePath()); + registry->RegisterDictionaryPref(kIPFSPinnedCids); } base::FilePath IpfsService::GetIpfsExecutablePath() const { @@ -371,6 +376,91 @@ void IpfsService::NotifyIpnsKeysLoaded(bool result) { } } +// Local pinning +void IpfsService::AddPin(const std::vector& cids, + bool recursive, + AddPinCallback callback) { + if (!IsDaemonLaunched()) { + std::move(callback).Run(false, absl::nullopt); + return; + } + + GURL gurl = server_endpoint_.Resolve(kAddPinPath); + for (const auto& cid : cids) { + gurl = net::AppendQueryParameter(gurl, kArgQueryParam, cid); + } + gurl = net::AppendQueryParameter(gurl, "recursive", + recursive ? "true" : "false"); + + auto url_loader = std::make_unique( + GetIpfsNetworkTrafficAnnotationTag(), url_loader_factory_); + auto iter = + requests_list_.insert(requests_list_.begin(), std::move(url_loader)); + + iter->get()->Request( + "POST", gurl, std::string(), std::string(), false, + base::BindOnce(&IpfsService::OnPinAddResult, base::Unretained(this), iter, + std::move(callback)), + {{net::HttpRequestHeaders::kOrigin, + url::Origin::Create(gurl).Serialize()}}); +} + +void IpfsService::RemovePin(const std::vector& cids, + RemovePinCallback callback) { + if (!IsDaemonLaunched()) { + std::move(callback).Run(false, absl::nullopt); + return; + } + + GURL gurl = server_endpoint_.Resolve(kRemovePinPath); + for (const auto& cid : cids) { + gurl = net::AppendQueryParameter(gurl, kArgQueryParam, cid); + } + LOG(ERROR) << "XXZZZ " << gurl.spec(); + + auto url_loader = std::make_unique( + GetIpfsNetworkTrafficAnnotationTag(), url_loader_factory_); + auto iter = + requests_list_.insert(requests_list_.begin(), std::move(url_loader)); + + iter->get()->Request( + "POST", gurl, std::string(), std::string(), false, + base::BindOnce(&IpfsService::OnPinRemoveResult, base::Unretained(this), + iter, std::move(callback)), + {{net::HttpRequestHeaders::kOrigin, + url::Origin::Create(gurl).Serialize()}}); +} + +void IpfsService::GetPins(const absl::optional>& cids, + const std::string& type, + bool quiet, + GetPinsCallback callback) { + if (!IsDaemonLaunched()) { + std::move(callback).Run(false, absl::nullopt); + return; + } + + GURL gurl = server_endpoint_.Resolve(kGetPinsPath); + if (cids) { + for (const auto& cid : cids.value()) { + gurl = net::AppendQueryParameter(gurl, kArgQueryParam, cid); + } + } + gurl = net::AppendQueryParameter(gurl, "type", type); + gurl = net::AppendQueryParameter(gurl, "quiet", quiet ? "true" : "false"); + + auto url_loader = std::make_unique( + GetIpfsNetworkTrafficAnnotationTag(), url_loader_factory_); + auto iter = + requests_list_.insert(requests_list_.begin(), std::move(url_loader)); + iter->get()->Request( + "POST", gurl, std::string(), std::string(), false, + base::BindOnce(&IpfsService::OnGetPinsResult, base::Unretained(this), + iter, std::move(callback)), + {{net::HttpRequestHeaders::kOrigin, + url::Origin::Create(gurl).Serialize()}}); +} + void IpfsService::ImportFileToIpfs(const base::FilePath& path, const std::string& key, ipfs::ImportCompletedCallback callback) { @@ -881,6 +971,100 @@ void IpfsService::OnPreWarmComplete( std::move(prewarm_callback_for_testing_).Run(); } +//{ +// "PinLsList": { +// "Keys": { +// "": { +// "Type": "" +// } +// } +// }, +// "PinLsObject": { +// "Cid": "", +// "Type": "" +// } +//} +void IpfsService::OnGetPinsResult( + APIRequestList::iterator iter, + GetPinsCallback callback, + api_request_helper::APIRequestResult response) { + int response_code = response.response_code(); + requests_list_.erase(iter); + + bool success = response.Is2XXResponseCode(); + + if (!success) { + VLOG(1) << "Fail to get pins, response_code = " << response_code; + std::move(callback).Run(false, absl::nullopt); + return; + } + + ipfs::GetPinsResult result; + bool parse_result = + IPFSJSONParser::GetGetPinsResultFromJSON(response.body(), &result); + if (!parse_result) { + VLOG(1) << "Fail to get pins, wrong format"; + std::move(callback).Run(false, absl::nullopt); + return; + } + + std::move(callback).Run(true, result); +} + +void IpfsService::OnPinAddResult( + APIRequestList::iterator iter, + AddPinCallback callback, + api_request_helper::APIRequestResult response) { + int response_code = response.response_code(); + requests_list_.erase(iter); + + bool success = response.Is2XXResponseCode(); + + if (!success) { + VLOG(1) << "Fail to add pin, response_code = " << response_code; + std::move(callback).Run(false, absl::nullopt); + return; + } + + ipfs::AddPinResult result; + bool parse_result = + IPFSJSONParser::GetAddPinsResultFromJSON(response.body(), &result); + if (!parse_result) { + VLOG(1) << "Fail to add pin service, wrong format"; + std::move(callback).Run(false, absl::nullopt); + return; + } + + std::move(callback).Run(true, result); +} + +void IpfsService::OnPinRemoveResult( + APIRequestList::iterator iter, + RemovePinCallback callback, + api_request_helper::APIRequestResult response) { + int response_code = response.response_code(); + requests_list_.erase(iter); + + bool success = response.Is2XXResponseCode(); + + if (!success) { + VLOG(1) << "Fail to remove pin, response_code = " << response_code; + std::move(callback).Run(false, absl::nullopt); + return; + } + + ipfs::RemovePinResult result; + bool parse_result = + IPFSJSONParser::GetRemovePinsResultFromJSON(response.body(), &result); + if (!parse_result) { + VLOG(1) << "Fail to remove pin, wrong response format"; + std::move(callback).Run(false, absl::nullopt); + return; + } + + std::move(callback).Run(true, result); +} + void IpfsService::ValidateGateway(const GURL& url, BoolCallback callback) { GURL::Replacements replacements; std::string path = "/ipfs/"; diff --git a/components/ipfs/ipfs_service.h b/components/ipfs/ipfs_service.h index 64462cc499db..3a5897b23304 100644 --- a/components/ipfs/ipfs_service.h +++ b/components/ipfs/ipfs_service.h @@ -27,6 +27,7 @@ #include "brave/components/ipfs/ipfs_dns_resolver.h" #include "brave/components/ipfs/ipfs_p3a.h" #include "brave/components/ipfs/node_info.h" +#include "brave/components/ipfs/pin/ipfs_pin_rpc_types.h" #include "brave/components/ipfs/repo_stats.h" #include "brave/components/services/ipfs/public/mojom/ipfs_service.mojom.h" #include "components/keyed_service/core/keyed_service.h" @@ -81,6 +82,13 @@ class IpfsService : public KeyedService, base::OnceCallback; using GarbageCollectionCallback = base::OnceCallback; + // Local pins + using AddPinCallback = + base::OnceCallback)>; + using RemovePinCallback = + base::OnceCallback)>; + using GetPinsCallback = + base::OnceCallback)>; using BoolCallback = base::OnceCallback; using GetConfigCallback = base::OnceCallback; @@ -112,6 +120,17 @@ class IpfsService : public KeyedService, virtual void PreWarmShareableLink(const GURL& url); #if BUILDFLAG(ENABLE_IPFS_LOCAL_NODE) + // Local pins + virtual void AddPin(const std::vector& cids, + bool recursive, + AddPinCallback callback); + virtual void RemovePin(const std::vector& cid, + RemovePinCallback callback); + virtual void GetPins(const absl::optional>& cid, + const std::string& type, + bool quiet, + GetPinsCallback callback); + virtual void ImportFileToIpfs(const base::FilePath& path, const std::string& key, ipfs::ImportCompletedCallback callback); @@ -131,12 +150,12 @@ class IpfsService : public KeyedService, const base::FilePath& target_path, BoolCallback callback); #endif - void GetConnectedPeers(GetConnectedPeersCallback callback, - int retries = kPeersDefaultRetries); + virtual void GetConnectedPeers(GetConnectedPeersCallback callback, + int retries = kPeersDefaultRetries); void GetAddressesConfig(GetAddressesConfigCallback callback); virtual void LaunchDaemon(BoolCallback callback); void ShutdownDaemon(BoolCallback callback); - void StartDaemonAndLaunch(base::OnceCallback callback); + virtual void StartDaemonAndLaunch(base::OnceCallback callback); void GetConfig(GetConfigCallback); void GetRepoStats(GetRepoStatsCallback callback); void GetNodeInfo(GetNodeInfoCallback callback); @@ -158,6 +177,7 @@ class IpfsService : public KeyedService, IpnsKeysManager* GetIpnsKeysManager() { return ipns_keys_manager_.get(); } #endif protected: + IpfsService(); void OnConfigLoaded(GetConfigCallback, const std::pair&); private: @@ -189,6 +209,18 @@ class IpfsService : public KeyedService, BoolCallback callback); #endif base::TimeDelta CalculatePeersRetryTime(); + + // Local pins + void OnGetPinsResult(APIRequestList::iterator iter, + GetPinsCallback callback, + api_request_helper::APIRequestResult response); + void OnPinAddResult(APIRequestList::iterator iter, + AddPinCallback callback, + api_request_helper::APIRequestResult response); + void OnPinRemoveResult(APIRequestList::iterator iter, + RemovePinCallback callback, + api_request_helper::APIRequestResult response); + void OnGatewayValidationComplete(SimpleURLLoaderList::iterator iter, BoolCallback callback, const GURL& initial_url, @@ -212,6 +244,7 @@ class IpfsService : public KeyedService, api_request_helper::APIRequestResult responsey); void OnPreWarmComplete(APIRequestList::iterator iter, api_request_helper::APIRequestResult response); + std::string GetStorageSize(); void OnDnsConfigChanged(absl::optional dns_server); diff --git a/components/ipfs/pin/ipfs_pin_rpc_types.cc b/components/ipfs/pin/ipfs_pin_rpc_types.cc new file mode 100644 index 000000000000..b7707013080e --- /dev/null +++ b/components/ipfs/pin/ipfs_pin_rpc_types.cc @@ -0,0 +1,16 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/components/ipfs/pin/ipfs_pin_rpc_types.h" + +namespace ipfs { + +AddPinResult::AddPinResult() {} + +AddPinResult::~AddPinResult() {} + +AddPinResult::AddPinResult(const AddPinResult& other) = default; + +} // namespace ipfs diff --git a/components/ipfs/pin/ipfs_pin_rpc_types.h b/components/ipfs/pin/ipfs_pin_rpc_types.h new file mode 100644 index 000000000000..2ad0b362e107 --- /dev/null +++ b/components/ipfs/pin/ipfs_pin_rpc_types.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_IPFS_PIN_IPFS_PIN_RPC_TYPES_H_ +#define BRAVE_COMPONENTS_IPFS_PIN_IPFS_PIN_RPC_TYPES_H_ + +#include +#include +#include + +namespace ipfs { + +struct AddPinResult { + AddPinResult(); + ~AddPinResult(); + AddPinResult(const AddPinResult&); + std::vector pins; + int progress; +}; + +using GetPinsResult = std::map; + +using RemovePinResult = std::vector; + +} // namespace ipfs + +#endif // BRAVE_COMPONENTS_IPFS_PIN_IPFS_PIN_RPC_TYPES_H_ From 5c4bb370bdf9ac4b2bd2f9a99f9e82b6f4e3c304 Mon Sep 17 00:00:00 2001 From: oisupov Date: Fri, 2 Dec 2022 20:32:40 +0400 Subject: [PATCH 02/15] Add IpfsLocalPinService --- .../ipfs/ipfs_local_pin_service_factory.cc | 52 ++ browser/ipfs/ipfs_local_pin_service_factory.h | 42 ++ browser/ipfs/sources.gni | 2 + components/ipfs/BUILD.gn | 6 + components/ipfs/pin/ipfs_base_pin_service.cc | 99 ++++ components/ipfs/pin/ipfs_base_pin_service.h | 62 +++ .../pin/ipfs_base_pin_service_unittest.cc | 112 +++++ components/ipfs/pin/ipfs_local_pin_service.cc | 284 +++++++++++ components/ipfs/pin/ipfs_local_pin_service.h | 135 ++++++ .../pin/ipfs_local_pin_service_unittest.cc | 457 ++++++++++++++++++ components/ipfs/pref_names.cc | 3 + components/ipfs/pref_names.h | 1 + components/ipfs/test/BUILD.gn | 2 + 13 files changed, 1257 insertions(+) create mode 100644 browser/ipfs/ipfs_local_pin_service_factory.cc create mode 100644 browser/ipfs/ipfs_local_pin_service_factory.h create mode 100644 components/ipfs/pin/ipfs_base_pin_service.cc create mode 100644 components/ipfs/pin/ipfs_base_pin_service.h create mode 100644 components/ipfs/pin/ipfs_base_pin_service_unittest.cc create mode 100644 components/ipfs/pin/ipfs_local_pin_service.cc create mode 100644 components/ipfs/pin/ipfs_local_pin_service.h create mode 100644 components/ipfs/pin/ipfs_local_pin_service_unittest.cc diff --git a/browser/ipfs/ipfs_local_pin_service_factory.cc b/browser/ipfs/ipfs_local_pin_service_factory.cc new file mode 100644 index 000000000000..e52e6bdb9347 --- /dev/null +++ b/browser/ipfs/ipfs_local_pin_service_factory.cc @@ -0,0 +1,52 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/ipfs/ipfs_local_pin_service_factory.h" + +#include +#include + +#include "brave/browser/ipfs/ipfs_service_factory.h" +#include "brave/components/ipfs/pin/ipfs_local_pin_service.h" +#include "chrome/browser/profiles/incognito_helpers.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/prefs/pref_service.h" +#include "components/user_prefs/user_prefs.h" + +namespace ipfs { + +// static +IpfsLocalPinServiceFactory* IpfsLocalPinServiceFactory::GetInstance() { + return base::Singleton::get(); +} + +// static +IpfsLocalPinService* IpfsLocalPinServiceFactory::GetServiceForContext( + content::BrowserContext* context) { + return static_cast( + GetInstance()->GetServiceForBrowserContext(context, true)); +} + +IpfsLocalPinServiceFactory::IpfsLocalPinServiceFactory() + : BrowserContextKeyedServiceFactory( + "IpfsLocalPinService", + BrowserContextDependencyManager::GetInstance()) { + DependsOn(ipfs::IpfsServiceFactory::GetInstance()); +} + +IpfsLocalPinServiceFactory::~IpfsLocalPinServiceFactory() = default; + +KeyedService* IpfsLocalPinServiceFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + return new IpfsLocalPinService(user_prefs::UserPrefs::Get(context), + IpfsServiceFactory::GetForContext(context)); +} + +content::BrowserContext* IpfsLocalPinServiceFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return chrome::GetBrowserContextRedirectedInIncognito(context); +} + +} // namespace ipfs diff --git a/browser/ipfs/ipfs_local_pin_service_factory.h b/browser/ipfs/ipfs_local_pin_service_factory.h new file mode 100644 index 000000000000..f8e7fc6f8f56 --- /dev/null +++ b/browser/ipfs/ipfs_local_pin_service_factory.h @@ -0,0 +1,42 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_BROWSER_IPFS_IPFS_LOCAL_PIN_SERVICE_FACTORY_H_ +#define BRAVE_BROWSER_IPFS_IPFS_LOCAL_PIN_SERVICE_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" +#include "components/keyed_service/core/keyed_service.h" +#include "content/public/browser/browser_context.h" + +namespace ipfs { + +class IpfsLocalPinService; + +class IpfsLocalPinServiceFactory : public BrowserContextKeyedServiceFactory { + public: + static IpfsLocalPinService* GetServiceForContext( + content::BrowserContext* context); + static IpfsLocalPinServiceFactory* GetInstance(); + + private: + friend struct base::DefaultSingletonTraits; + + IpfsLocalPinServiceFactory(); + ~IpfsLocalPinServiceFactory() override; + + IpfsLocalPinServiceFactory(const IpfsLocalPinServiceFactory&) = delete; + IpfsLocalPinServiceFactory& operator=(const IpfsLocalPinServiceFactory&) = + delete; + + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; +}; + +} // namespace ipfs + +#endif // BRAVE_BROWSER_IPFS_IPFS_LOCAL_PIN_SERVICE_FACTORY_H_ diff --git a/browser/ipfs/sources.gni b/browser/ipfs/sources.gni index e5d8a5498b4e..4ab3c9446647 100644 --- a/browser/ipfs/sources.gni +++ b/browser/ipfs/sources.gni @@ -23,6 +23,8 @@ if (enable_ipfs) { "//brave/browser/ipfs/ipfs_dns_resolver_impl.h", "//brave/browser/ipfs/ipfs_host_resolver.cc", "//brave/browser/ipfs/ipfs_host_resolver.h", + "//brave/browser/ipfs/ipfs_local_pin_service_factory.cc", + "//brave/browser/ipfs/ipfs_local_pin_service_factory.h", "//brave/browser/ipfs/ipfs_service_factory.cc", "//brave/browser/ipfs/ipfs_service_factory.h", "//brave/browser/ipfs/ipfs_subframe_navigation_throttle.cc", diff --git a/components/ipfs/BUILD.gn b/components/ipfs/BUILD.gn index 51b520e65dc8..6bc43e8daaaf 100644 --- a/components/ipfs/BUILD.gn +++ b/components/ipfs/BUILD.gn @@ -73,6 +73,12 @@ static_library("ipfs") { "ipfs_onboarding_page.h", "keys/ipns_keys_manager.cc", "keys/ipns_keys_manager.h", + "pin/ipfs_base_pin_service.cc", + "pin/ipfs_base_pin_service.h", + "pin/ipfs_local_pin_service.cc", + "pin/ipfs_local_pin_service.h", + "pin/ipfs_pin_rpc_types.cc", + "pin/ipfs_pin_rpc_types.h", ] deps += [ "//brave/components/l10n/common", diff --git a/components/ipfs/pin/ipfs_base_pin_service.cc b/components/ipfs/pin/ipfs_base_pin_service.cc new file mode 100644 index 000000000000..50618cfaeb94 --- /dev/null +++ b/components/ipfs/pin/ipfs_base_pin_service.cc @@ -0,0 +1,99 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/components/ipfs/pin/ipfs_base_pin_service.h" + +#include "brave/components/ipfs/ipfs_utils.h" +#include "brave/components/ipfs/pref_names.h" + +namespace ipfs { + +IpfsBaseJob::IpfsBaseJob() {} + +IpfsBaseJob::~IpfsBaseJob() {} + +IpfsBasePinService::IpfsBasePinService(PrefService* pref_service, + IpfsService* ipfs_service) + : pref_service_(pref_service), ipfs_service_(ipfs_service) { + ipfs_service_->AddObserver(this); + pref_change_registrar_.Init(pref_service_); + pref_change_registrar_.Add( + kIPFSResolveMethod, + base::BindRepeating(&IpfsBasePinService::MaybeStartDaemon, + base::Unretained(this))); +} + +IpfsBasePinService::IpfsBasePinService() {} + +IpfsBasePinService::~IpfsBasePinService() {} + +// For unit tests +void IpfsBasePinService::RemovePrefListenersForTests() { + pref_change_registrar_.RemoveAll(); +} + +void IpfsBasePinService::OnIpfsShutdown() { + daemon_ready_ = false; +} + +void IpfsBasePinService::OnGetConnectedPeers( + bool success, + const std::vector& peers) { + if (success) { + daemon_ready_ = true; + DoNextJob(); + } +} + +void IpfsBasePinService::AddJob(std::unique_ptr job) { + jobs_.push(std::move(job)); + if (!current_job_) { + DoNextJob(); + } +} + +void IpfsBasePinService::DoNextJob() { + if (jobs_.empty()) { + return; + } + + if (!IsDaemonReady()) { + MaybeStartDaemon(); + return; + } + + current_job_ = std::move(jobs_.front()); + jobs_.pop(); + + current_job_->Start(); +} + +void IpfsBasePinService::OnJobDone(bool result) { + current_job_.reset(); + DoNextJob(); +} + +bool IpfsBasePinService::IsDaemonReady() { + return daemon_ready_; +} + +void IpfsBasePinService::MaybeStartDaemon() { + if (daemon_ready_) { + return; + } + + if (!ipfs::IsLocalGatewayConfigured(pref_service_)) { + return; + } + + ipfs_service_->StartDaemonAndLaunch(base::BindOnce( + &IpfsBasePinService::OnDaemonStarted, base::Unretained(this))); +} + +void IpfsBasePinService::OnDaemonStarted() { + ipfs_service_->GetConnectedPeers(base::NullCallback(), 2); +} + +} // namespace ipfs diff --git a/components/ipfs/pin/ipfs_base_pin_service.h b/components/ipfs/pin/ipfs_base_pin_service.h new file mode 100644 index 000000000000..bf46354819f9 --- /dev/null +++ b/components/ipfs/pin/ipfs_base_pin_service.h @@ -0,0 +1,62 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_IPFS_PIN_IPFS_BASE_PIN_SERVICE_H_ +#define BRAVE_COMPONENTS_IPFS_PIN_IPFS_BASE_PIN_SERVICE_H_ + +#include +#include +#include +#include +#include + +#include "brave/components/ipfs/ipfs_service.h" +#include "components/prefs/pref_change_registrar.h" +#include "components/prefs/pref_service.h" + +namespace ipfs { + +class IpfsBaseJob { + public: + IpfsBaseJob(); + virtual ~IpfsBaseJob(); + virtual void Start() = 0; +}; + +class IpfsBasePinService : public IpfsServiceObserver { + public: + IpfsBasePinService(PrefService* pref_service, IpfsService* service); + ~IpfsBasePinService() override; + + virtual void AddJob(std::unique_ptr job); + void OnJobDone(bool result); + + void OnIpfsShutdown() override; + void OnGetConnectedPeers(bool succes, + const std::vector& peers) override; + + void RemovePrefListenersForTests(); + + protected: + // For testing + IpfsBasePinService(); + + private: + bool IsDaemonReady(); + void MaybeStartDaemon(); + void OnDaemonStarted(); + void DoNextJob(); + + bool daemon_ready_ = false; + PrefService* pref_service_; + IpfsService* ipfs_service_; + PrefChangeRegistrar pref_change_registrar_; + std::unique_ptr current_job_; + std::queue> jobs_; +}; + +} // namespace ipfs + +#endif // BRAVE_COMPONENTS_IPFS_PIN_IPFS_BASE_PIN_SERVICE_H_ diff --git a/components/ipfs/pin/ipfs_base_pin_service_unittest.cc b/components/ipfs/pin/ipfs_base_pin_service_unittest.cc new file mode 100644 index 000000000000..77811a2b5314 --- /dev/null +++ b/components/ipfs/pin/ipfs_base_pin_service_unittest.cc @@ -0,0 +1,112 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/components/ipfs/pin/ipfs_base_pin_service.h" + +#include +#include + +#include "base/test/bind.h" +#include "brave/components/ipfs/ipfs_service.h" +#include "brave/components/ipfs/pref_names.h" +#include "components/prefs/testing_pref_service.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; + +namespace ipfs { + +class MockIpfsService : public IpfsService { + public: + MockIpfsService() = default; + + ~MockIpfsService() override = default; + + MOCK_METHOD1(StartDaemonAndLaunch, void(base::OnceCallback)); + MOCK_METHOD2(GetConnectedPeers, + void(IpfsService::GetConnectedPeersCallback, int)); +}; + +class IpfsBasePinServiceTest : public testing::Test { + public: + IpfsBasePinServiceTest() = default; + + void SetUp() override { + auto* registry = pref_service_.registry(); + IpfsService::RegisterProfilePrefs(registry); + ipfs_base_pin_service_ = + std::make_unique(GetPrefs(), GetIpfsService()); + } + + void TearDown() override { + ipfs_base_pin_service_->RemovePrefListenersForTests(); + } + + void SetLocalNodeEnabled(bool enabled) { + GetPrefs()->SetInteger( + kIPFSResolveMethod, + static_cast(enabled ? IPFSResolveMethodTypes::IPFS_LOCAL + : IPFSResolveMethodTypes::IPFS_DISABLED)); + } + + PrefService* GetPrefs() { return &pref_service_; } + + testing::NiceMock* GetIpfsService() { + return &ipfs_service_; + } + + IpfsBasePinService* service() { return ipfs_base_pin_service_.get(); } + + private: + std::unique_ptr ipfs_base_pin_service_; + testing::NiceMock ipfs_service_; + TestingPrefServiceSimple pref_service_; + content::BrowserTaskEnvironment task_environment_; +}; + +class MockJob : public IpfsBaseJob { + public: + explicit MockJob(base::OnceCallback callback) { + callback_ = std::move(callback); + } + + void Start() override { + if (callback_) { + std::move(callback_).Run(); + } + } + + private: + base::OnceCallback callback_; +}; + +TEST_F(IpfsBasePinServiceTest, TasksExecuted) { + service()->OnGetConnectedPeers(true, {}); + absl::optional method_called; + std::unique_ptr first_job = std::make_unique( + base::BindLambdaForTesting([&method_called]() { method_called = true; })); + service()->AddJob(std::move(first_job)); + EXPECT_TRUE(method_called.value()); + + absl::optional second_method_called; + std::unique_ptr second_job = + std::make_unique(base::BindLambdaForTesting( + [&second_method_called]() { second_method_called = true; })); + service()->AddJob(std::move(second_job)); + EXPECT_FALSE(second_method_called.has_value()); + + service()->OnJobDone(true); + EXPECT_TRUE(second_method_called.value()); +} + +TEST_F(IpfsBasePinServiceTest, LaunchDaemon_AfterSettingChange) { + SetLocalNodeEnabled(false); + EXPECT_CALL(*GetIpfsService(), StartDaemonAndLaunch(_)).Times(1); + SetLocalNodeEnabled(true); +} + +} // namespace ipfs diff --git a/components/ipfs/pin/ipfs_local_pin_service.cc b/components/ipfs/pin/ipfs_local_pin_service.cc new file mode 100644 index 000000000000..3e02edf6e4b3 --- /dev/null +++ b/components/ipfs/pin/ipfs_local_pin_service.cc @@ -0,0 +1,284 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/components/ipfs/pin/ipfs_local_pin_service.h" + +#include +#include +#include + +#include "brave/components/ipfs/pref_names.h" +#include "components/prefs/scoped_user_pref_update.h" + +namespace ipfs { + +namespace { +const char kRecursiveMode[] = "recursive"; +} // namespace + +AddLocalPinJob::AddLocalPinJob(PrefService* prefs_service, + IpfsService* ipfs_service, + const std::string& prefix, + const std::vector& cids, + AddPinCallback callback) + : prefs_service_(prefs_service), + ipfs_service_(ipfs_service), + prefix_(prefix), + cids_(cids), + callback_(std::move(callback)) {} + +AddLocalPinJob::~AddLocalPinJob() {} + +void AddLocalPinJob::Start() { + ipfs_service_->AddPin( + cids_, true, + base::BindOnce(&AddLocalPinJob::OnAddPinResult, base::Unretained(this))); +} + +void AddLocalPinJob::OnAddPinResult(bool status, + absl::optional result) { + if (status && result) { + for (const auto& cid : cids_) { + if (std::find(result->pins.begin(), result->pins.end(), cid) == + result->pins.end()) { + std::move(callback_).Run(false); + return; + } + } + + { + DictionaryPrefUpdate update(prefs_service_, kIPFSPinnedCids); + base::Value::Dict& update_dict = update->GetDict(); + + for (const auto& cid : cids_) { + base::Value::List* list = update_dict.FindList(cid); + if (!list) { + update_dict.Set(cid, base::Value::List()); + list = update_dict.FindList(cid); + } + DCHECK(list); + list->EraseValue(base::Value(prefix_)); + list->Append(base::Value(prefix_)); + } + } + std::move(callback_).Run(true); + } else { + std::move(callback_).Run(false); + } +} + +RemoveLocalPinJob::RemoveLocalPinJob(PrefService* prefs_service, + const std::string& prefix, + RemovePinCallback callback) + : prefs_service_(prefs_service), + prefix_(prefix), + callback_(std::move(callback)) {} + +RemoveLocalPinJob::~RemoveLocalPinJob() {} + +void RemoveLocalPinJob::Start() { + { + DictionaryPrefUpdate update(prefs_service_, kIPFSPinnedCids); + base::Value::Dict& update_dict = update->GetDict(); + + std::vector remove_list; + for (auto pair : update_dict) { + base::Value::List* list = pair.second.GetIfList(); + if (list) { + list->EraseValue(base::Value(prefix_)); + if (list->empty()) { + remove_list.push_back(pair.first); + } + } + } + for (const auto& cid : remove_list) { + update_dict.Remove(cid); + } + } + std::move(callback_).Run(true); +} + +VerifyLocalPinJob::VerifyLocalPinJob(PrefService* prefs_service, + IpfsService* ipfs_service, + const std::string& prefix, + const std::vector& cids, + ValidatePinsCallback callback) + : prefs_service_(prefs_service), + ipfs_service_(ipfs_service), + prefix_(prefix), + cids_(cids), + callback_(std::move(callback)) {} + +VerifyLocalPinJob::~VerifyLocalPinJob() {} + +void VerifyLocalPinJob::Start() { + ipfs_service_->GetPins(absl::nullopt, kRecursiveMode, true, + base::BindOnce(&VerifyLocalPinJob::OnGetPinsResult, + base::Unretained(this))); +} + +void VerifyLocalPinJob::OnGetPinsResult(bool status, + absl::optional result) { + if (status && result) { + DictionaryPrefUpdate update(prefs_service_, kIPFSPinnedCids); + base::Value::Dict& update_dict = update->GetDict(); + + bool verification_pased = true; + for (const auto& cid : cids_) { + base::Value::List* list = update_dict.FindList(cid); + if (!list) { + verification_pased = false; + } else { + if (result->find(cid) != result->end()) { + list->EraseValue(base::Value(prefix_)); + list->Append(base::Value(prefix_)); + } else { + verification_pased = false; + list->EraseValue(base::Value(prefix_)); + } + if (list->empty()) { + update_dict.Remove(cid); + } + } + } + std::move(callback_).Run(verification_pased); + } else { + std::move(callback_).Run(absl::nullopt); + } +} + +GcJob::GcJob(PrefService* prefs_service, + IpfsService* ipfs_service, + GcCallback callback) + : prefs_service_(prefs_service), + ipfs_service_(ipfs_service), + callback_(std::move(callback)) {} +GcJob::~GcJob() {} + +void GcJob::Start() { + ipfs_service_->GetPins( + absl::nullopt, kRecursiveMode, true, + base::BindOnce(&GcJob::OnGetPinsResult, base::Unretained(this))); +} + +void GcJob::OnGetPinsResult(bool status, absl::optional result) { + std::vector cids_to_delete; + if (status && result) { + const base::Value::Dict& dict = prefs_service_->GetDict(kIPFSPinnedCids); + for (const auto& pair : result.value()) { + const base::Value::List* list = dict.FindList(pair.first); + if (!list || list->empty()) { + cids_to_delete.push_back(pair.first); + } + } + + if (!cids_to_delete.empty()) { + ipfs_service_->RemovePin( + cids_to_delete, + base::BindOnce(&GcJob::OnPinsRemovedResult, base::Unretained(this))); + } else { + std::move(callback_).Run(true); + } + } else { + std::move(callback_).Run(false); + } +} + +void GcJob::OnPinsRemovedResult(bool status, + absl::optional result) { + if (status && result) { + std::move(callback_).Run(true); + } else { + std::move(callback_).Run(false); + } +} + +IpfsLocalPinService::IpfsLocalPinService(PrefService* prefs_service, + IpfsService* ipfs_service) + : prefs_service_(prefs_service), ipfs_service_(ipfs_service) { + ipfs_base_pin_service_ = + std::make_unique(prefs_service_, ipfs_service_); + base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&IpfsLocalPinService::AddGcTask, base::Unretained(this)), + base::Minutes(1)); +} + +IpfsLocalPinService::IpfsLocalPinService() {} + +void IpfsLocalPinService::SetIpfsBasePinServiceForTesting( + std::unique_ptr service) { + ipfs_base_pin_service_ = std::move(service); +} + +IpfsLocalPinService::~IpfsLocalPinService() {} + +void IpfsLocalPinService::AddPins(const std::string& prefix, + const std::vector& cids, + AddPinCallback callback) { + ipfs_base_pin_service_->AddJob(std::make_unique( + prefs_service_, ipfs_service_, prefix, cids, + base::BindOnce(&IpfsLocalPinService::OnAddJobFinished, + base::Unretained(this), std::move(callback)))); +} + +void IpfsLocalPinService::RemovePins(const std::string& prefix, + RemovePinCallback callback) { + ipfs_base_pin_service_->AddJob(std::make_unique( + prefs_service_, prefix, + base::BindOnce(&IpfsLocalPinService::OnRemovePinsFinished, + base::Unretained(this), std::move(callback)))); +} + +void IpfsLocalPinService::ValidatePins(const std::string& prefix, + const std::vector& cids, + ValidatePinsCallback callback) { + ipfs_base_pin_service_->AddJob(std::make_unique( + prefs_service_, ipfs_service_, prefix, cids, + base::BindOnce(&IpfsLocalPinService::OnValidateJobFinished, + base::Unretained(this), std::move(callback)))); +} + +void IpfsLocalPinService::OnRemovePinsFinished(RemovePinCallback callback, + bool status) { + std::move(callback).Run(status); + if (status) { + base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&IpfsLocalPinService::AddGcTask, base::Unretained(this)), + base::Minutes(1)); + } + ipfs_base_pin_service_->OnJobDone(status); +} + +void IpfsLocalPinService::OnAddJobFinished(AddPinCallback callback, + bool status) { + std::move(callback).Run(status); + ipfs_base_pin_service_->OnJobDone(status); +} + +void IpfsLocalPinService::OnValidateJobFinished(ValidatePinsCallback callback, + absl::optional status) { + std::move(callback).Run(status); + ipfs_base_pin_service_->OnJobDone(status.value_or(false)); +} + +void IpfsLocalPinService::AddGcTask() { + if (gc_task_posted_) { + return; + } + gc_task_posted_ = true; + ipfs_base_pin_service_->AddJob(std::make_unique( + prefs_service_, ipfs_service_, + base::BindOnce(&IpfsLocalPinService::OnGcFinishedCallback, + base::Unretained(this)))); +} + +void IpfsLocalPinService::OnGcFinishedCallback(bool status) { + gc_task_posted_ = false; + ipfs_base_pin_service_->OnJobDone(status); +} + +} // namespace ipfs diff --git a/components/ipfs/pin/ipfs_local_pin_service.h b/components/ipfs/pin/ipfs_local_pin_service.h new file mode 100644 index 000000000000..826673b8192d --- /dev/null +++ b/components/ipfs/pin/ipfs_local_pin_service.h @@ -0,0 +1,135 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_IPFS_PIN_IPFS_LOCAL_PIN_SERVICE_H_ +#define BRAVE_COMPONENTS_IPFS_PIN_IPFS_LOCAL_PIN_SERVICE_H_ + +#include +#include +#include + +#include "brave/components/ipfs/ipfs_service.h" +#include "brave/components/ipfs/pin/ipfs_base_pin_service.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +using ipfs::IpfsService; + +namespace ipfs { + +using AddPinCallback = base::OnceCallback; +using RemovePinCallback = base::OnceCallback; +using ValidatePinsCallback = base::OnceCallback)>; +using GcCallback = base::OnceCallback; + +class AddLocalPinJob : public IpfsBaseJob { + public: + AddLocalPinJob(PrefService* prefs_service, + IpfsService* ipfs_service, + const std::string& prefix, + const std::vector& cids, + AddPinCallback callback); + ~AddLocalPinJob() override; + + void Start() override; + + private: + void OnAddPinResult(bool status, absl::optional result); + + PrefService* prefs_service_; + IpfsService* ipfs_service_; + std::string prefix_; + std::vector cids_; + AddPinCallback callback_; +}; + +class RemoveLocalPinJob : public IpfsBaseJob { + public: + RemoveLocalPinJob(PrefService* prefs_service, + const std::string& prefix, + RemovePinCallback callback); + ~RemoveLocalPinJob() override; + + void Start() override; + + private: + PrefService* prefs_service_; + std::string prefix_; + RemovePinCallback callback_; +}; + +class VerifyLocalPinJob : public IpfsBaseJob { + public: + VerifyLocalPinJob(PrefService* prefs_service, + IpfsService* ipfs_service, + const std::string& prefix, + const std::vector& cids, + ValidatePinsCallback callback); + ~VerifyLocalPinJob() override; + + void Start() override; + + private: + void OnGetPinsResult(bool status, absl::optional result); + + PrefService* prefs_service_; + IpfsService* ipfs_service_; + std::string prefix_; + std::vector cids_; + ValidatePinsCallback callback_; +}; + +class GcJob : public IpfsBaseJob { + public: + GcJob(PrefService* prefs_service, + IpfsService* ipfs_service, + GcCallback callback); + ~GcJob() override; + + void Start() override; + + private: + void OnGetPinsResult(bool status, absl::optional result); + void OnPinsRemovedResult(bool status, absl::optional result); + + PrefService* prefs_service_; + IpfsService* ipfs_service_; + GcCallback callback_; +}; + +class IpfsLocalPinService : public KeyedService { + public: + IpfsLocalPinService(PrefService* prefs_service, IpfsService* ipfs_service); + // For testing + IpfsLocalPinService(); + ~IpfsLocalPinService() override; + + virtual void AddPins(const std::string& prefix, + const std::vector& cids, + AddPinCallback callback); + virtual void RemovePins(const std::string& prefix, + RemovePinCallback callback); + virtual void ValidatePins(const std::string& prefix, + const std::vector& cids, + ValidatePinsCallback callback); + + void SetIpfsBasePinServiceForTesting(std::unique_ptr); + + private: + void AddGcTask(); + void OnRemovePinsFinished(RemovePinCallback callback, bool status); + void OnAddJobFinished(AddPinCallback callback, bool status); + void OnValidateJobFinished(ValidatePinsCallback callback, + absl::optional status); + void OnGcFinishedCallback(bool status); + + bool gc_task_posted_ = false; + std::unique_ptr ipfs_base_pin_service_; + PrefService* prefs_service_; + IpfsService* ipfs_service_; +}; + +} // namespace ipfs + +#endif // BRAVE_COMPONENTS_IPFS_PIN_IPFS_LOCAL_PIN_SERVICE_H_ diff --git a/components/ipfs/pin/ipfs_local_pin_service_unittest.cc b/components/ipfs/pin/ipfs_local_pin_service_unittest.cc new file mode 100644 index 000000000000..f28fa02fd2c0 --- /dev/null +++ b/components/ipfs/pin/ipfs_local_pin_service_unittest.cc @@ -0,0 +1,457 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/components/ipfs/pin/ipfs_local_pin_service.h" + +#include +#include + +#include "base/json/json_reader.h" +#include "base/test/bind.h" +#include "brave/components/ipfs/ipfs_service.h" +#include "brave/components/ipfs/pref_names.h" +#include "components/prefs/testing_pref_service.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; + +namespace ipfs { + +class MockIpfsService : public IpfsService { + public: + MockIpfsService() = default; + + ~MockIpfsService() override = default; + + MOCK_METHOD3(AddPin, + void(const std::vector& cids, + bool recursive, + IpfsService::AddPinCallback callback)); + MOCK_METHOD2(RemovePin, + void(const std::vector& cid, + IpfsService::RemovePinCallback callback)); + MOCK_METHOD4(GetPins, + void(const absl::optional>& cid, + const std::string& type, + bool quiet, + IpfsService::GetPinsCallback callback)); +}; + +class MockIpfsBasePinService : public IpfsBasePinService { + public: + MockIpfsBasePinService() = default; + void AddJob(std::unique_ptr job) override { + std::move(job)->Start(); + } +}; + +class IpfsLocalPinServiceTest : public testing::Test { + public: + IpfsLocalPinServiceTest() = default; + + IpfsLocalPinService* service() { return ipfs_local_pin_service_.get(); } + + protected: + void SetUp() override { + auto* registry = pref_service_.registry(); + IpfsService::RegisterProfilePrefs(registry); + ipfs_local_pin_service_ = + std::make_unique(GetPrefs(), GetIpfsService()); + ipfs_local_pin_service_->SetIpfsBasePinServiceForTesting( + std::make_unique()); + } + + PrefService* GetPrefs() { return &pref_service_; } + + testing::NiceMock* GetIpfsService() { + return &ipfs_service_; + } + + std::unique_ptr ipfs_local_pin_service_; + testing::NiceMock ipfs_service_; + TestingPrefServiceSimple pref_service_; + content::BrowserTaskEnvironment task_environment_; +}; + +TEST_F(IpfsLocalPinServiceTest, AddLocalPinJobTest) { + { + ON_CALL(*GetIpfsService(), AddPin(_, _, _)) + .WillByDefault(::testing::Invoke( + [](const std::vector& cids, bool recursive, + IpfsService::AddPinCallback callback) { + AddPinResult result; + result.pins = cids; + std::move(callback).Run(true, result); + })); + + absl::optional success; + service()->AddPins("a", {"Qma", "Qmb", "Qmc"}, + base::BindLambdaForTesting( + [&success](bool result) { success = result; })); + + std::string expected = R"({ + "Qma" : ["a"], + "Qmb" : ["a"], + "Qmc" : ["a"] + })"; + absl::optional expected_value = base::JSONReader::Read( + expected, base::JSON_PARSE_CHROMIUM_EXTENSIONS | + base::JSONParserOptions::JSON_PARSE_RFC); + EXPECT_EQ(expected_value.value(), GetPrefs()->GetDict(kIPFSPinnedCids)); + EXPECT_TRUE(success.value()); + } + + { + ON_CALL(*GetIpfsService(), AddPin(_, _, _)) + .WillByDefault(::testing::Invoke( + [](const std::vector& cids, bool recursive, + IpfsService::AddPinCallback callback) { + AddPinResult result; + result.pins = cids; + std::move(callback).Run(true, result); + })); + + absl::optional success; + service()->AddPins("b", {"Qma", "Qmb", "Qmc", "Qmd"}, + base::BindLambdaForTesting( + [&success](bool result) { success = result; })); + + std::string expected = R"({ + "Qma" : ["a", "b"], + "Qmb" : ["a", "b"], + "Qmc" : ["a", "b"], + "Qmd" : ["b"] + })"; + absl::optional expected_value = base::JSONReader::Read( + expected, base::JSON_PARSE_CHROMIUM_EXTENSIONS | + base::JSONParserOptions::JSON_PARSE_RFC); + EXPECT_EQ(expected_value.value(), GetPrefs()->GetDict(kIPFSPinnedCids)); + EXPECT_TRUE(success.value()); + } + + { + ON_CALL(*GetIpfsService(), AddPin(_, _, _)) + .WillByDefault(::testing::Invoke( + [](const std::vector& cids, bool recursive, + IpfsService::AddPinCallback callback) { + AddPinResult result; + result.pins = {"Qma", "Qmb", "Qmc"}; + std::move(callback).Run(true, result); + })); + + absl::optional success; + service()->AddPins("c", {"Qma", "Qmb", "Qmc", "Qmd", "Qme"}, + base::BindLambdaForTesting( + [&success](bool result) { success = result; })); + + std::string expected = R"({ + "Qma" : ["a", "b"], + "Qmb" : ["a", "b"], + "Qmc" : ["a", "b"], + "Qmd" : ["b"] + })"; + absl::optional expected_value = base::JSONReader::Read( + expected, base::JSON_PARSE_CHROMIUM_EXTENSIONS | + base::JSONParserOptions::JSON_PARSE_RFC); + EXPECT_EQ(expected_value.value(), GetPrefs()->GetDict(kIPFSPinnedCids)); + EXPECT_FALSE(success.value()); + } + + { + ON_CALL(*GetIpfsService(), AddPin(_, _, _)) + .WillByDefault(::testing::Invoke( + [](const std::vector& cids, bool recursive, + IpfsService::AddPinCallback callback) { + std::move(callback).Run(false, absl::nullopt); + })); + + absl::optional success; + service()->AddPins("c", {"Qma", "Qmb", "Qmc", "Qmd", "Qme"}, + base::BindLambdaForTesting( + [&success](bool result) { success = result; })); + + std::string expected = R"({ + "Qma" : ["a", "b"], + "Qmb" : ["a", "b"], + "Qmc" : ["a", "b"], + "Qmd" : ["b"] + })"; + absl::optional expected_value = base::JSONReader::Read( + expected, base::JSON_PARSE_CHROMIUM_EXTENSIONS | + base::JSONParserOptions::JSON_PARSE_RFC); + EXPECT_EQ(expected_value.value(), GetPrefs()->GetDict(kIPFSPinnedCids)); + EXPECT_FALSE(success.value()); + } +} + +TEST_F(IpfsLocalPinServiceTest, RemoveLocalPinJobTest) { + { + std::string base = R"({ + "Qma" : ["a", "b"], + "Qmb" : ["a", "b"], + "Qmc" : ["a", "b"], + "Qmd" : ["b"] + })"; + absl::optional base_value = base::JSONReader::Read( + base, base::JSON_PARSE_CHROMIUM_EXTENSIONS | + base::JSONParserOptions::JSON_PARSE_RFC); + GetPrefs()->SetDict(kIPFSPinnedCids, base_value.value().GetDict().Clone()); + } + + { + absl::optional success; + service()->RemovePins("a", + base::BindLambdaForTesting( + [&success](bool result) { success = result; })); + + std::string expected = R"({ + "Qma" : ["b"], + "Qmb" : ["b"], + "Qmc" : ["b"], + "Qmd" : ["b"] + })"; + absl::optional expected_value = base::JSONReader::Read( + expected, base::JSON_PARSE_CHROMIUM_EXTENSIONS | + base::JSONParserOptions::JSON_PARSE_RFC); + EXPECT_EQ(expected_value.value(), GetPrefs()->GetDict(kIPFSPinnedCids)); + EXPECT_TRUE(success.value()); + } + + { + absl::optional success; + service()->RemovePins("c", + base::BindLambdaForTesting( + [&success](bool result) { success = result; })); + + std::string expected = R"({ + "Qma" : ["b"], + "Qmb" : ["b"], + "Qmc" : ["b"], + "Qmd" : ["b"] + })"; + absl::optional expected_value = base::JSONReader::Read( + expected, base::JSON_PARSE_CHROMIUM_EXTENSIONS | + base::JSONParserOptions::JSON_PARSE_RFC); + EXPECT_EQ(expected_value.value(), GetPrefs()->GetDict(kIPFSPinnedCids)); + EXPECT_TRUE(success.value()); + } + + { + absl::optional success; + service()->RemovePins("b", + base::BindLambdaForTesting( + [&success](bool result) { success = result; })); + + std::string expected = R"({ + })"; + absl::optional expected_value = base::JSONReader::Read( + expected, base::JSON_PARSE_CHROMIUM_EXTENSIONS | + base::JSONParserOptions::JSON_PARSE_RFC); + EXPECT_EQ(expected_value.value(), GetPrefs()->GetDict(kIPFSPinnedCids)); + EXPECT_TRUE(success.value()); + } +} + +TEST_F(IpfsLocalPinServiceTest, VerifyLocalPinJobTest) { + { + std::string base = R"({ + "Qma" : ["a", "b"], + "Qmb" : ["a", "b"], + "Qmc" : ["a", "b"], + "Qmd" : ["b"] + })"; + absl::optional base_value = base::JSONReader::Read( + base, base::JSON_PARSE_CHROMIUM_EXTENSIONS | + base::JSONParserOptions::JSON_PARSE_RFC); + GetPrefs()->SetDict(kIPFSPinnedCids, base_value.value().GetDict().Clone()); + } + + { + ON_CALL(*GetIpfsService(), GetPins(_, _, _, _)) + .WillByDefault(::testing::Invoke([](const absl::optional< + std::vector>& cid, + const std::string& type, bool quiet, + IpfsService::GetPinsCallback + callback) { + GetPinsResult result = {{"Qma", "Recursive"}, {"Qmb", "Recursive"}}; + std::move(callback).Run(true, result); + })); + + absl::optional success; + service()->ValidatePins( + "a", {"Qma", "Qmb", "Qmc"}, + base::BindLambdaForTesting([&success](absl::optional result) { + success = result.value(); + })); + + EXPECT_TRUE(success.has_value()); + EXPECT_FALSE(success.value()); + } + + { + ON_CALL(*GetIpfsService(), GetPins(_, _, _, _)) + .WillByDefault(::testing::Invoke( + [](const absl::optional>& cid, + const std::string& type, bool quiet, + IpfsService::GetPinsCallback callback) { + GetPinsResult result = {{"Qma", "Recursive"}, + {"Qmb", "Recursive"}, + {"Qmc", "Recursive"}}; + std::move(callback).Run(true, result); + })); + + absl::optional success; + service()->ValidatePins( + "a", {"Qma", "Qmb", "Qmc"}, + base::BindLambdaForTesting([&success](absl::optional result) { + success = result.value(); + })); + EXPECT_TRUE(success.has_value()); + EXPECT_TRUE(success.value()); + } + + { + ON_CALL(*GetIpfsService(), GetPins(_, _, _, _)) + .WillByDefault(::testing::Invoke( + [](const absl::optional>& cid, + const std::string& type, bool quiet, + IpfsService::GetPinsCallback callback) { + GetPinsResult result = {}; + std::move(callback).Run(true, result); + })); + + absl::optional success = false; + service()->ValidatePins( + "b", {"Qma", "Qmb", "Qmc", "Qmd"}, + base::BindLambdaForTesting([&success](absl::optional result) { + success = result.value(); + })); + + EXPECT_TRUE(success.has_value()); + + EXPECT_FALSE(success.value()); + } + + { + absl::optional success; + VerifyLocalPinJob job( + GetPrefs(), GetIpfsService(), "b", {"Qma", "Qmb", "Qmc", "Qmd"}, + base::BindLambdaForTesting( + [&success](absl::optional result) { success = result; })); + + ON_CALL(*GetIpfsService(), GetPins(_, _, _, _)) + .WillByDefault(::testing::Invoke( + [](const absl::optional>& cid, + const std::string& type, bool quiet, + IpfsService::GetPinsCallback callback) { + std::move(callback).Run(false, absl::nullopt); + })); + + job.Start(); + + EXPECT_FALSE(success.has_value()); + } +} + +TEST_F(IpfsLocalPinServiceTest, GcJobTest) { + { + std::string base = R"({ + "Qma" : ["a", "b"], + "Qmb" : ["a", "b"], + "Qmc" : ["a", "b"], + "Qmd" : ["b"] + })"; + absl::optional base_value = base::JSONReader::Read( + base, base::JSON_PARSE_CHROMIUM_EXTENSIONS | + base::JSONParserOptions::JSON_PARSE_RFC); + GetPrefs()->SetDict(kIPFSPinnedCids, base_value.value().GetDict().Clone()); + } + + { + absl::optional success; + GcJob job(GetPrefs(), GetIpfsService(), + base::BindLambdaForTesting( + [&success](bool result) { success = result; })); + + ON_CALL(*GetIpfsService(), GetPins(_, _, _, _)) + .WillByDefault(::testing::Invoke( + [](const absl::optional>& cid, + const std::string& type, bool quiet, + IpfsService::GetPinsCallback callback) { + EXPECT_FALSE(cid.has_value()); + EXPECT_TRUE(quiet); + GetPinsResult result = {{"Qma", "Recursive"}, + {"Qmb", "Recursive"}, + {"Qmc", "Recursive"}}; + std::move(callback).Run(true, result); + })); + + EXPECT_CALL(*GetIpfsService(), RemovePin(_, _)).Times(0); + + job.Start(); + + EXPECT_TRUE(success.value()); + } + + { + absl::optional success; + GcJob job(GetPrefs(), GetIpfsService(), + base::BindLambdaForTesting( + [&success](bool result) { success = result; })); + + ON_CALL(*GetIpfsService(), GetPins(_, _, _, _)) + .WillByDefault(::testing::Invoke([](const absl::optional< + std::vector>& cid, + const std::string& type, bool quiet, + IpfsService::GetPinsCallback + callback) { + EXPECT_FALSE(cid.has_value()); + EXPECT_TRUE(quiet); + GetPinsResult result = {{"Qm1", "Recursive"}, {"Qm2", "Recursive"}}; + std::move(callback).Run(true, result); + })); + EXPECT_CALL(*GetIpfsService(), RemovePin(_, _)).Times(1); + + ON_CALL(*GetIpfsService(), RemovePin(_, _)) + .WillByDefault( + ::testing::Invoke([](const std::vector& cid, + IpfsService::RemovePinCallback callback) { + EXPECT_EQ(cid.size(), 2u); + EXPECT_EQ(cid[0], "Qm1"); + EXPECT_EQ(cid[1], "Qm2"); + RemovePinResult result = cid; + std::move(callback).Run(true, result); + })); + + job.Start(); + + EXPECT_TRUE(success.value()); + } + + { + absl::optional success; + GcJob job(GetPrefs(), GetIpfsService(), + base::BindLambdaForTesting( + [&success](bool result) { success = result; })); + + ON_CALL(*GetIpfsService(), GetPins(_, _, _, _)) + .WillByDefault(::testing::Invoke( + [](const absl::optional>& cid, + const std::string& type, bool quiet, + IpfsService::GetPinsCallback callback) { + std::move(callback).Run(false, absl::nullopt); + })); + + EXPECT_CALL(*GetIpfsService(), RemovePin(_, _)).Times(0); + + job.Start(); + + EXPECT_FALSE(success.value()); + } +} + +} // namespace ipfs diff --git a/components/ipfs/pref_names.cc b/components/ipfs/pref_names.cc index a9fb7ee14422..b5f9ca819f96 100644 --- a/components/ipfs/pref_names.cc +++ b/components/ipfs/pref_names.cc @@ -44,3 +44,6 @@ const char kIPFSPublicGatewayAddress[] = "brave.ipfs.public_gateway_address"; // Stores IPFS public gateway address to be used when translating IPFS NFT URLs. const char kIPFSPublicNFTGatewayAddress[] = "brave.ipfs.public_nft_gateway_address"; + +// Stores list of CIDs that are pinned localy +const char kIPFSPinnedCids[] = "brave.ipfs.local_pinned_cids"; diff --git a/components/ipfs/pref_names.h b/components/ipfs/pref_names.h index f0b31b9f0641..3173d879bd68 100644 --- a/components/ipfs/pref_names.h +++ b/components/ipfs/pref_names.h @@ -17,5 +17,6 @@ extern const char kIPFSPublicGatewayAddress[]; extern const char kIPFSPublicNFTGatewayAddress[]; extern const char kIPFSResolveMethod[]; extern const char kIpfsStorageMax[]; +extern const char kIPFSPinnedCids[]; #endif // BRAVE_COMPONENTS_IPFS_PREF_NAMES_H_ diff --git a/components/ipfs/test/BUILD.gn b/components/ipfs/test/BUILD.gn index 65b150155d76..a63b54a9c20b 100644 --- a/components/ipfs/test/BUILD.gn +++ b/components/ipfs/test/BUILD.gn @@ -17,6 +17,8 @@ source_set("brave_ipfs_unit_tests") { "//brave/components/ipfs/ipfs_ports_unittest.cc", "//brave/components/ipfs/ipfs_utils_unittest.cc", "//brave/components/ipfs/keys/ipns_keys_manager_unittest.cc", + "//brave/components/ipfs/pin/ipfs_base_pin_service_unittest.cc", + "//brave/components/ipfs/pin/ipfs_local_pin_service_unittest.cc", ] deps = [ From 82b5ada22ca23c1acb358f808ef2018e759b0a08 Mon Sep 17 00:00:00 2001 From: oisupov Date: Fri, 2 Dec 2022 20:35:23 +0400 Subject: [PATCH 03/15] Add BraveWalletPinService --- .../brave_wallet_pin_service_factory.cc | 81 +++ .../brave_wallet_pin_service_factory.h | 51 ++ components/brave_wallet/browser/BUILD.gn | 4 + .../brave_wallet/browser/brave_wallet_p3a.cc | 2 + .../brave_wallet/browser/brave_wallet_p3a.h | 3 + .../browser/brave_wallet_pin_service.cc | 671 ++++++++++++++++++ .../browser/brave_wallet_pin_service.h | 136 ++++ .../brave_wallet_pin_service_unittest.cc | 586 +++++++++++++++ .../browser/brave_wallet_prefs.cc | 4 + .../browser/brave_wallet_service.cc | 23 +- .../browser/brave_wallet_service.h | 7 + .../brave_wallet/browser/json_rpc_service.cc | 3 + .../brave_wallet/browser/json_rpc_service.h | 2 + .../browser/json_rpc_service_unittest.cc | 32 +- components/brave_wallet/browser/pref_names.cc | 2 + components/brave_wallet/browser/pref_names.h | 2 + components/brave_wallet/browser/test/BUILD.gn | 2 + .../brave_wallet/common/brave_wallet.mojom | 72 +- 18 files changed, 1662 insertions(+), 21 deletions(-) create mode 100644 browser/brave_wallet/brave_wallet_pin_service_factory.cc create mode 100644 browser/brave_wallet/brave_wallet_pin_service_factory.h create mode 100644 components/brave_wallet/browser/brave_wallet_pin_service.cc create mode 100644 components/brave_wallet/browser/brave_wallet_pin_service.h create mode 100644 components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc diff --git a/browser/brave_wallet/brave_wallet_pin_service_factory.cc b/browser/brave_wallet/brave_wallet_pin_service_factory.cc new file mode 100644 index 000000000000..51d92f7e1d01 --- /dev/null +++ b/browser/brave_wallet/brave_wallet_pin_service_factory.cc @@ -0,0 +1,81 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/brave_wallet/brave_wallet_pin_service_factory.h" + +#include +#include + +#include "brave/browser/brave_wallet/brave_wallet_context_utils.h" +#include "brave/browser/brave_wallet/json_rpc_service_factory.h" +#include "brave/browser/ipfs/ipfs_local_pin_service_factory.h" +#include "brave/components/brave_wallet/browser/brave_wallet_pin_service.h" +#include "brave/components/brave_wallet/browser/brave_wallet_service.h" +#include "brave/components/brave_wallet/browser/brave_wallet_service_delegate.h" +#include "chrome/browser/profiles/incognito_helpers.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/user_prefs/user_prefs.h" + +namespace brave_wallet { + +// static +BraveWalletPinServiceFactory* BraveWalletPinServiceFactory::GetInstance() { + return base::Singleton::get(); +} + +// static +mojo::PendingRemote +BraveWalletPinServiceFactory::GetForContext(content::BrowserContext* context) { + if (!IsAllowedForContext(context)) { + return mojo::PendingRemote(); + } + + return GetServiceForContext(context)->MakeRemote(); +} + +// static +BraveWalletPinService* BraveWalletPinServiceFactory::GetServiceForContext( + content::BrowserContext* context) { + if (!IsAllowedForContext(context)) { + return nullptr; + } + return static_cast( + GetInstance()->GetServiceForBrowserContext(context, true)); +} + +// static +void BraveWalletPinServiceFactory::BindForContext( + content::BrowserContext* context, + mojo::PendingReceiver receiver) { + auto* service = BraveWalletPinServiceFactory::GetServiceForContext(context); + if (service) { + service->Bind(std::move(receiver)); + } +} + +BraveWalletPinServiceFactory::BraveWalletPinServiceFactory() + : BrowserContextKeyedServiceFactory( + "BraveWalletPinService", + BrowserContextDependencyManager::GetInstance()) { + DependsOn(brave_wallet::JsonRpcServiceFactory::GetInstance()); + DependsOn(ipfs::IpfsLocalPinServiceFactory::GetInstance()); +} + +BraveWalletPinServiceFactory::~BraveWalletPinServiceFactory() = default; + +KeyedService* BraveWalletPinServiceFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + return new BraveWalletPinService( + user_prefs::UserPrefs::Get(context), + JsonRpcServiceFactory::GetServiceForContext(context), + ipfs::IpfsLocalPinServiceFactory::GetServiceForContext(context)); +} + +content::BrowserContext* BraveWalletPinServiceFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return chrome::GetBrowserContextRedirectedInIncognito(context); +} + +} // namespace brave_wallet diff --git a/browser/brave_wallet/brave_wallet_pin_service_factory.h b/browser/brave_wallet/brave_wallet_pin_service_factory.h new file mode 100644 index 000000000000..05f589429638 --- /dev/null +++ b/browser/brave_wallet/brave_wallet_pin_service_factory.h @@ -0,0 +1,51 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_BROWSER_BRAVE_WALLET_BRAVE_WALLET_PIN_SERVICE_FACTORY_H_ +#define BRAVE_BROWSER_BRAVE_WALLET_BRAVE_WALLET_PIN_SERVICE_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "brave/browser/ipfs/ipfs_service_factory.h" +#include "brave/components/brave_wallet/common/brave_wallet.mojom.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" +#include "components/keyed_service/core/keyed_service.h" +#include "content/public/browser/browser_context.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/pending_remote.h" + +namespace brave_wallet { + +class BraveWalletPinService; + +class BraveWalletPinServiceFactory : public BrowserContextKeyedServiceFactory { + public: + static mojo::PendingRemote GetForContext( + content::BrowserContext* context); + static BraveWalletPinService* GetServiceForContext( + content::BrowserContext* context); + static BraveWalletPinServiceFactory* GetInstance(); + static void BindForContext( + content::BrowserContext* context, + mojo::PendingReceiver receiver); + + private: + friend struct base::DefaultSingletonTraits; + + BraveWalletPinServiceFactory(); + ~BraveWalletPinServiceFactory() override; + + BraveWalletPinServiceFactory(const BraveWalletPinServiceFactory&) = delete; + BraveWalletPinServiceFactory& operator=(const BraveWalletPinServiceFactory&) = + delete; + + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; +}; + +} // namespace brave_wallet + +#endif // BRAVE_BROWSER_BRAVE_WALLET_BRAVE_WALLET_PIN_SERVICE_FACTORY_H_ diff --git a/components/brave_wallet/browser/BUILD.gn b/components/brave_wallet/browser/BUILD.gn index 93ac3479bccc..86c7e5788fb2 100644 --- a/components/brave_wallet/browser/BUILD.gn +++ b/components/brave_wallet/browser/BUILD.gn @@ -32,10 +32,14 @@ static_library("browser") { "blockchain_list_parser.h", "blockchain_registry.cc", "blockchain_registry.h", + "brave_wallet_auto_pin_service.cc", + "brave_wallet_auto_pin_service.h", "brave_wallet_p3a.cc", "brave_wallet_p3a.h", "brave_wallet_p3a_private.cc", "brave_wallet_p3a_private.h", + "brave_wallet_pin_service.cc", + "brave_wallet_pin_service.h", "brave_wallet_prefs.cc", "brave_wallet_prefs.h", "brave_wallet_provider_delegate.cc", diff --git a/components/brave_wallet/browser/brave_wallet_p3a.cc b/components/brave_wallet/browser/brave_wallet_p3a.cc index e754c4210baf..f1679c4dbe9c 100644 --- a/components/brave_wallet/browser/brave_wallet_p3a.cc +++ b/components/brave_wallet/browser/brave_wallet_p3a.cc @@ -108,6 +108,8 @@ BraveWalletP3A::BraveWalletP3A(BraveWalletService* wallet_service, base::Unretained(this), true)); } +BraveWalletP3A::BraveWalletP3A() {} + BraveWalletP3A::~BraveWalletP3A() = default; void BraveWalletP3A::AddObservers() { diff --git a/components/brave_wallet/browser/brave_wallet_p3a.h b/components/brave_wallet/browser/brave_wallet_p3a.h index be7fc74bdaef..c9946b09209a 100644 --- a/components/brave_wallet/browser/brave_wallet_p3a.h +++ b/components/brave_wallet/browser/brave_wallet_p3a.h @@ -47,6 +47,9 @@ class BraveWalletP3A : public mojom::BraveWalletServiceObserver, PrefService* profile_prefs, PrefService* local_state); + // For testing + BraveWalletP3A(); + ~BraveWalletP3A() override; BraveWalletP3A(const BraveWalletP3A&) = delete; BraveWalletP3A& operator=(BraveWalletP3A&) = delete; diff --git a/components/brave_wallet/browser/brave_wallet_pin_service.cc b/components/brave_wallet/browser/brave_wallet_pin_service.cc new file mode 100644 index 000000000000..169f1bf99041 --- /dev/null +++ b/components/brave_wallet/browser/brave_wallet_pin_service.cc @@ -0,0 +1,671 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_wallet/browser/brave_wallet_pin_service.h" + +#include + +#include "base/strings/strcat.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" +#include "base/task/bind_post_task.h" +#include "base/task/thread_pool.h" +#include "base/values.h" +#include "brave/components/brave_wallet/browser/brave_wallet_utils.h" +#include "brave/components/brave_wallet/browser/json_rpc_response_parser.h" +#include "brave/components/brave_wallet/browser/pref_names.h" +#include "brave/components/ipfs/ipfs_constants.h" +#include "brave/components/ipfs/ipfs_utils.h" +#include "components/prefs/scoped_user_pref_update.h" + +using brave_wallet::mojom::BlockchainToken; +using brave_wallet::mojom::BlockchainTokenPtr; + +namespace brave_wallet { + +const char kAssetStatus[] = "status"; +const char kValidateTimestamp[] = "validate_timestamp"; +const char kError[] = "error"; +const char kErrorCode[] = "error_code"; +const char kErrorMessage[] = "error_message"; +const char kAssetUrlListKey[] = "cids"; + +namespace { + +const char kNftPart[] = "nft"; +const char kLocalService[] = "local"; + +absl::optional StringToStatus( + const std::string& status) { + if (status == "not_pinned") { + return mojom::TokenPinStatusCode::STATUS_NOT_PINNED; + } else if (status == "pining_failed") { + return mojom::TokenPinStatusCode::STATUS_PINNING_FAILED; + } else if (status == "pinned") { + return mojom::TokenPinStatusCode::STATUS_PINNED; + } else if (status == "pinning_in_progress") { + return mojom::TokenPinStatusCode::STATUS_PINNING_IN_PROGRESS; + } else if (status == "unpining_in_progress") { + return mojom::TokenPinStatusCode::STATUS_UNPINNING_IN_PROGRESS; + } else if (status == "unpining_failed") { + return mojom::TokenPinStatusCode::STATUS_UNPINNING_FAILED; + } else if (status == "pinning_pendig") { + return mojom::TokenPinStatusCode::STATUS_PINNING_PENDING; + } else if (status == "unpinning_pendig") { + return mojom::TokenPinStatusCode::STATUS_UNPINNING_PENDING; + } + return absl::nullopt; +} + +absl::optional StringToErrorCode( + const std::string& error) { + if (error == "ERR_WRONG_TOKEN") { + return mojom::WalletPinServiceErrorCode::ERR_WRONG_TOKEN; + } else if (error == "ERR_NON_IPFS_TOKEN_URL") { + return mojom::WalletPinServiceErrorCode::ERR_NON_IPFS_TOKEN_URL; + } else if (error == "ERR_FETCH_METADATA_FAILED") { + return mojom::WalletPinServiceErrorCode::ERR_FETCH_METADATA_FAILED; + } else if (error == "ERR_WRONG_METADATA_FORMAT") { + return mojom::WalletPinServiceErrorCode::ERR_WRONG_METADATA_FORMAT; + } else if (error == "ERR_ALREADY_PINNED") { + return mojom::WalletPinServiceErrorCode::ERR_ALREADY_PINNED; + } else if (error == "ERR_NOT_PINNED") { + return mojom::WalletPinServiceErrorCode::ERR_NOT_PINNED; + } else if (error == "ERR_PINNING_FAILED") { + return mojom::WalletPinServiceErrorCode::ERR_PINNING_FAILED; + } + return absl::nullopt; +} + +absl::optional ExtractCID(const std::string& ipfs_url) { + GURL gurl = GURL(ipfs_url); + + if (!gurl.SchemeIs(ipfs::kIPFSScheme)) { + return absl::nullopt; + } + + std::vector result = base::SplitString( + gurl.path(), "/", base::WhitespaceHandling::KEEP_WHITESPACE, + base::SplitResult::SPLIT_WANT_NONEMPTY); + + if (result.size() == 0) { + return absl::nullopt; + } + + if (!ipfs::IsValidCID(result.at(0))) { + return absl::nullopt; + } + + return result.at(0); +} + +} // namespace + +std::string StatusToString(const mojom::TokenPinStatusCode& status) { + switch (status) { + case mojom::TokenPinStatusCode::STATUS_NOT_PINNED: + return "not_pinned"; + case mojom::TokenPinStatusCode::STATUS_PINNED: + return "pinned"; + case mojom::TokenPinStatusCode::STATUS_PINNING_IN_PROGRESS: + return "pinning_in_progress"; + case mojom::TokenPinStatusCode::STATUS_UNPINNING_IN_PROGRESS: + return "unpining_in_progress"; + case mojom::TokenPinStatusCode::STATUS_UNPINNING_FAILED: + return "unpining_failed"; + case mojom::TokenPinStatusCode::STATUS_PINNING_FAILED: + return "pining_failed"; + case mojom::TokenPinStatusCode::STATUS_PINNING_PENDING: + return "pinning_pendig"; + case mojom::TokenPinStatusCode::STATUS_UNPINNING_PENDING: + return "unpinning_pendig"; + } + NOTREACHED(); + return ""; +} + +std::string ErrorCodeToString( + const mojom::WalletPinServiceErrorCode& error_code) { + switch (error_code) { + case mojom::WalletPinServiceErrorCode::ERR_WRONG_TOKEN: + return "ERR_WRONG_TOKEN"; + case mojom::WalletPinServiceErrorCode::ERR_NON_IPFS_TOKEN_URL: + return "ERR_NON_IPFS_TOKEN_URL"; + case mojom::WalletPinServiceErrorCode::ERR_FETCH_METADATA_FAILED: + return "ERR_FETCH_METADATA_FAILED"; + case mojom::WalletPinServiceErrorCode::ERR_WRONG_METADATA_FORMAT: + return "ERR_WRONG_METADATA_FORMAT"; + case mojom::WalletPinServiceErrorCode::ERR_ALREADY_PINNED: + return "ERR_ALREADY_PINNED"; + case mojom::WalletPinServiceErrorCode::ERR_NOT_PINNED: + return "ERR_NOT_PINNED"; + case mojom::WalletPinServiceErrorCode::ERR_PINNING_FAILED: + return "ERR_PINNING_FAILED"; + } + NOTREACHED(); + return ""; +} + +BraveWalletPinService::BraveWalletPinService( + PrefService* prefs, + JsonRpcService* service, + ipfs::IpfsLocalPinService* local_pin_service) + : prefs_(prefs), + json_rpc_service_(service), + local_pin_service_(local_pin_service) {} + +BraveWalletPinService::~BraveWalletPinService() {} + +mojo::PendingRemote +BraveWalletPinService::MakeRemote() { + mojo::PendingRemote remote; + receivers_.Add(this, remote.InitWithNewPipeAndPassReceiver()); + return remote; +} + +void BraveWalletPinService::Bind( + mojo::PendingReceiver receiver) { + receivers_.Add(this, std::move(receiver)); +} + +void BraveWalletPinService::AddObserver( + ::mojo::PendingRemote observer) { + observers_.Add(std::move(observer)); +} + +// static +std::string BraveWalletPinService::GetPath( + const absl::optional& service, + const BlockchainTokenPtr& token) { + return base::StrCat({kNftPart, ".", service.value_or(kLocalService), ".", + base::NumberToString(static_cast(token->coin)), ".", + token->chain_id, ".", token->contract_address, ".", + token->token_id}); +} + +// static +BlockchainTokenPtr BraveWalletPinService::TokenFromPath( + const std::string& path) { + std::vector parts = + base::SplitString(path, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + if (parts.size() != 6) { + return nullptr; + } + mojom::BlockchainTokenPtr token = mojom::BlockchainToken::New(); + int32_t coin; + if (!base::StringToInt(parts.at(2), &coin)) { + return nullptr; + } + token->coin = static_cast(coin); + token->chain_id = parts.at(3); + token->contract_address = parts.at(4); + token->token_id = parts.at(5); + token->is_erc721 = true; + token->is_nft = true; + return token; +} + +// static +absl::optional BraveWalletPinService::ServiceFromPath( + const std::string& path) { + std::vector parts = + base::SplitString(path, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + if (parts.size() != 6) { + return nullptr; + } + if (parts.at(1) == kLocalService) { + return absl::nullopt; + } else { + return parts.at(1); + } +} + +void BraveWalletPinService::Validate(BlockchainTokenPtr token, + const absl::optional& service, + ValidateCallback callback) { + mojom::TokenPinStatusPtr status = GetTokenStatus(service, token); + if (!status) { + std::move(callback).Run(false, nullptr); + return; + } + if (status->code != mojom::TokenPinStatusCode::STATUS_PINNED) { + std::move(callback).Run(false, nullptr); + return; + } + + absl::optional> cids = + ResolvePinItems(service, token); + + if (!cids) { + SetTokenStatus(service, std::move(token), + mojom::TokenPinStatusCode::STATUS_PINNING_IN_PROGRESS, + nullptr); + std::move(callback).Run(true, nullptr); + return; + } + + if (!service) { + local_pin_service_->ValidatePins( + GetPath(absl::nullopt, token), cids.value(), + base::BindOnce(&BraveWalletPinService::OnTokenValidated, + base::Unretained(this), service, std::move(callback), + std::move(token))); + } +} + +void BraveWalletPinService::MarkAsPendingForPinning( + const mojom::BlockchainTokenPtr& token, + const absl::optional& service) { + SetTokenStatus(service, token, + mojom::TokenPinStatusCode::STATUS_PINNING_PENDING, nullptr); +} + +void BraveWalletPinService::MarkAsPendingForUnpinning( + const mojom::BlockchainTokenPtr& token, + const absl::optional& service) { + SetTokenStatus(service, token, + mojom::TokenPinStatusCode::STATUS_UNPINNING_PENDING, nullptr); +} + +void BraveWalletPinService::AddPin(BlockchainTokenPtr token, + const absl::optional& service, + AddPinCallback callback) { + if (!token->is_erc721) { + auto pin_error = + mojom::PinError::New(mojom::WalletPinServiceErrorCode::ERR_WRONG_TOKEN, + "Token is not erc721"); + + VLOG(1) << "Token is not erc721"; + FinishAddingWithResult(service, token, false, std::move(pin_error), + std::move(callback)); + return; + } + + auto token_status = GetTokenStatus(service, token); + if (token_status && + token_status->code == mojom::TokenPinStatusCode::STATUS_PINNED) { + auto pin_error = mojom::PinError::New( + mojom::WalletPinServiceErrorCode::ERR_ALREADY_PINNED, "Already pinned"); + + FinishAddingWithResult(service, token, true, std::move(pin_error), + std::move(callback)); + return; + } + + json_rpc_service_->GetERC721Metadata( + token->contract_address, token->token_id, token->chain_id, + base::BindOnce(&BraveWalletPinService::OnTokenMetaDataReceived, + base::Unretained(this), service, std::move(callback), + token.Clone())); +} + +void BraveWalletPinService::RemovePin( + BlockchainTokenPtr token, + const absl::optional& service, + RemovePinCallback callback) { + auto token_status = GetTokenStatus(service, token); + if (!token_status) { + std::move(callback).Run(true, nullptr); + return; + } + + SetTokenStatus(service, token, + mojom::TokenPinStatusCode::STATUS_UNPINNING_IN_PROGRESS, + nullptr); + + local_pin_service_->RemovePins( + GetPath(service, token), + base::BindOnce(&BraveWalletPinService::OnPinsRemoved, + base::Unretained(this), service, std::move(callback), + std::move(token))); +} + +void BraveWalletPinService::GetTokenStatus(BlockchainTokenPtr token, + GetTokenStatusCallback callback) { + mojom::TokenPinOverviewPtr result = mojom::TokenPinOverview::New(); + result->local = GetTokenStatus(absl::nullopt, token); + std::move(callback).Run(std::move(result), nullptr); +} + +void BraveWalletPinService::OnPinsRemoved(absl::optional service, + RemovePinCallback callback, + mojom::BlockchainTokenPtr token, + bool result) { + if (result) { + RemoveToken(service, token); + } else { + SetTokenStatus(service, token, + mojom::TokenPinStatusCode::STATUS_UNPINNING_FAILED, nullptr); + } + + std::move(callback).Run(result, nullptr); +} + +void BraveWalletPinService::OnTokenMetaDataReceived( + absl::optional service, + AddPinCallback callback, + mojom::BlockchainTokenPtr token, + const std::string& token_url, + const std::string& result, + mojom::ProviderError error, + const std::string& error_message) { + if (error != mojom::ProviderError::kSuccess) { + auto pin_error = mojom::PinError::New( + mojom::WalletPinServiceErrorCode::ERR_FETCH_METADATA_FAILED, + "Failed to obtain token metadata"); + SetTokenStatus(service, token, + mojom::TokenPinStatusCode::STATUS_PINNING_FAILED, pin_error); + FinishAddingWithResult(service, token, false, std::move(pin_error), + std::move(callback)); + return; + } + + GURL token_gurl = GURL(token_url); + if (!token_gurl.SchemeIs(ipfs::kIPFSScheme)) { + auto pin_error = mojom::PinError::New( + mojom::WalletPinServiceErrorCode::ERR_NON_IPFS_TOKEN_URL, + "Metadata has non-ipfs url"); + SetTokenStatus(service, token, + mojom::TokenPinStatusCode::STATUS_PINNING_FAILED, pin_error); + FinishAddingWithResult(service, token, false, std::move(pin_error), + std::move(callback)); + return; + } + + absl::optional parsed_result = base::JSONReader::Read( + result, base::JSON_PARSE_CHROMIUM_EXTENSIONS | + base::JSONParserOptions::JSON_PARSE_RFC); + if (!parsed_result || !parsed_result->is_dict()) { + auto pin_error = mojom::PinError::New( + mojom::WalletPinServiceErrorCode::ERR_WRONG_METADATA_FORMAT, + "Wrong metadata format"); + SetTokenStatus(service, token, + mojom::TokenPinStatusCode::STATUS_PINNING_FAILED, pin_error); + FinishAddingWithResult(service, token, false, std::move(pin_error), + std::move(callback)); + return; + } + + std::vector cids; + + cids.push_back(ExtractCID(token_url).value()); + auto* image = parsed_result->FindStringKey("image"); + if (image) { + cids.push_back(ExtractCID(*image).value()); + } + + CreateToken(service, token, cids); + SetTokenStatus(service, token, + mojom::TokenPinStatusCode::STATUS_PINNING_IN_PROGRESS, + nullptr); + + if (!service) { + local_pin_service_->AddPins( + GetPath(service, token), cids, + base::BindOnce(&BraveWalletPinService::OnTokenPinned, + base::Unretained(this), absl::nullopt, + std::move(callback), std::move(token))); + } +} + +void BraveWalletPinService::OnTokenPinned(absl::optional service, + AddPinCallback callback, + mojom::BlockchainTokenPtr token, + bool result) { + auto error = + !result ? mojom::PinError::New( + mojom::WalletPinServiceErrorCode::ERR_WRONG_METADATA_FORMAT, + "Wrong metadata format") + : nullptr; + SetTokenStatus(service, token, + result ? mojom::TokenPinStatusCode::STATUS_PINNED + : mojom::TokenPinStatusCode::STATUS_PINNING_FAILED, + error); + + FinishAddingWithResult(service, token, result, std::move(error), + std::move(callback)); +} + +void BraveWalletPinService::OnTokenValidated( + absl::optional service, + ValidateCallback callback, + mojom::BlockchainTokenPtr token, + absl::optional result) { + if (!result.has_value()) { + std::move(callback).Run(false, nullptr); + return; + } + + if (!result.value()) { + SetTokenStatus(service, token, + mojom::TokenPinStatusCode::STATUS_PINNING_IN_PROGRESS, + nullptr); + } else { + // Also updates verification timestamp + SetTokenStatus(service, token, mojom::TokenPinStatusCode::STATUS_PINNED, + nullptr); + } + + std::move(callback).Run(true, nullptr); +} + +void BraveWalletPinService::CreateToken(absl::optional service, + const mojom::BlockchainTokenPtr& token, + const std::vector& cids) { + DictionaryPrefUpdate update(prefs_, kPinnedErc721Assets); + base::Value::Dict& update_dict = update->GetDict(); + + base::Value::Dict token_data; + base::Value::List cids_list; + + for (const auto& cid : cids) { + cids_list.Append(cid); + } + + token_data.Set(kAssetUrlListKey, std::move(cids_list)); + token_data.Set(kAssetStatus, + StatusToString(mojom::TokenPinStatusCode::STATUS_NOT_PINNED)); + + update_dict.SetByDottedPath(GetPath(service, token), std::move(token_data)); +} + +void BraveWalletPinService::RemoveToken( + absl::optional service, + const mojom::BlockchainTokenPtr& token) { + DictionaryPrefUpdate update(prefs_, kPinnedErc721Assets); + base::Value::Dict& update_dict = update->GetDict(); + update_dict.RemoveByDottedPath(GetPath(service, token)); +} + +void BraveWalletPinService::SetTokenStatus( + absl::optional service, + const mojom::BlockchainTokenPtr& token, + mojom::TokenPinStatusCode status, + const mojom::PinErrorPtr& error) { + { + DictionaryPrefUpdate update(prefs_, kPinnedErc721Assets); + base::Value::Dict& update_dict = update->GetDict(); + + update_dict.SetByDottedPath(GetPath(service, token) + "." + kAssetStatus, + StatusToString(status)); + if (error) { + base::Value::Dict error_dict; + error_dict.Set(kErrorCode, ErrorCodeToString(error->error_code)); + error_dict.Set(kErrorMessage, error->message); + update_dict.SetByDottedPath(GetPath(service, token) + "." + kError, + std::move(error_dict)); + } else { + update_dict.RemoveByDottedPath(GetPath(service, token) + "." + kError); + } + + if (status == mojom::TokenPinStatusCode::STATUS_PINNED) { + update_dict.SetByDottedPath( + GetPath(service, token) + "." + kValidateTimestamp, + base::NumberToString(base::Time::Now().ToInternalValue())); + } else { + update_dict.RemoveByDottedPath(GetPath(service, token) + "." + + kValidateTimestamp); + } + } + for (const auto& observer : observers_) { + observer->OnTokenStatusChanged(service, token.Clone(), + GetTokenStatus(service, token)); + } +} + +absl::optional> BraveWalletPinService::ResolvePinItems( + const absl::optional& service, + const BlockchainTokenPtr& token) { + const base::Value::Dict& pinned_assets_pref = + prefs_->GetDict(kPinnedErc721Assets); + + const std::string& path = GetPath(service, token); + + auto* token_data_as_dict = pinned_assets_pref.FindDictByDottedPath(path); + if (!token_data_as_dict) { + return absl::nullopt; + } + + auto* cids = token_data_as_dict->FindList(kAssetUrlListKey); + if (!cids) { + return absl::nullopt; + } + + std::vector result; + for (const base::Value& item : *cids) { + result.push_back(item.GetString()); + } + + return result; +} + +mojom::TokenPinStatusPtr BraveWalletPinService::GetTokenStatus( + absl::optional service, + const mojom::BlockchainTokenPtr& token) { + const base::Value::Dict& pinned_assets_pref = + prefs_->GetDict(kPinnedErc721Assets); + + const std::string& path = GetPath(service, token); + + auto* token_data_as_dict = pinned_assets_pref.FindDictByDottedPath(path); + if (!token_data_as_dict) { + return nullptr; + } + + auto* status = token_data_as_dict->FindString(kAssetStatus); + if (!status) { + return mojom::TokenPinStatus::New( + mojom::TokenPinStatusCode::STATUS_NOT_PINNED, nullptr, absl::nullopt); + } + + auto pin_status = StringToStatus(*status).value_or( + mojom::TokenPinStatusCode::STATUS_NOT_PINNED); + absl::optional validate_timestamp; + mojom::PinErrorPtr error; + + { + auto* validate_timestamp_str = + token_data_as_dict->FindString(kValidateTimestamp); + uint64_t validate_timestamp_internal_value; + if (validate_timestamp_str && + base::StringToUint64(*validate_timestamp_str, + &validate_timestamp_internal_value)) { + validate_timestamp = + base::Time::FromInternalValue(validate_timestamp_internal_value); + } + + auto* error_dict = token_data_as_dict->FindDict(kError); + if (error_dict) { + auto* error_message = error_dict->FindString(kErrorMessage); + auto* error_code = error_dict->FindString(kErrorCode); + if (error_code && error_message) { + error = mojom::PinError::New( + StringToErrorCode(*error_code) + .value_or(mojom::WalletPinServiceErrorCode::ERR_PINNING_FAILED), + *error_message); + } + } + } + + return mojom::TokenPinStatus::New(pin_status, std::move(error), + validate_timestamp); +} + +absl::optional BraveWalletPinService::GetLastValidateTime( + absl::optional service, + const mojom::BlockchainTokenPtr& token) { + const base::Value::Dict& pinned_assets_pref = + prefs_->GetDict(kPinnedErc721Assets); + + const std::string& path = GetPath(service, token); + + auto* token_data_as_dict = pinned_assets_pref.FindDictByDottedPath(path); + if (!token_data_as_dict) { + return absl::nullopt; + } + + auto* time = token_data_as_dict->FindString(kValidateTimestamp); + int64_t value; + if (time && base::StringToInt64(*time, &value)) { + return base::Time::FromInternalValue(value); + } + return absl::nullopt; +} + +void BraveWalletPinService::FinishAddingWithResult( + absl::optional service, + const mojom::BlockchainTokenPtr& token, + bool result, + mojom::PinErrorPtr error, + AddPinCallback callback) { + std::move(callback).Run(result, std::move(error)); +} + +std::set BraveWalletPinService::GetTokens( + const absl::optional& service) { + std::set result; + + const base::Value::Dict& pinned_assets_pref = + prefs_->GetDict(kPinnedErc721Assets); + + const base::Value::Dict* service_dict = + pinned_assets_pref.FindDictByDottedPath( + base::StrCat({kNftPart, ".", service.value_or(kLocalService)})); + if (!service_dict) { + return result; + } + + for (auto coin_it : *service_dict) { + std::string current_coin = coin_it.first; + auto* network_dict = coin_it.second.GetIfDict(); + if (!network_dict) { + continue; + } + for (auto network_it : *network_dict) { + std::string current_network = network_it.first; + const base::Value::Dict* contract_dict = network_it.second.GetIfDict(); + if (!contract_dict) { + continue; + } + for (auto contract_it : *contract_dict) { + std::string current_contract = contract_it.first; + const base::Value::Dict* id_dict = contract_it.second.GetIfDict(); + if (!id_dict) { + continue; + } + for (auto token_id : *id_dict) { + result.insert( + base::StrCat({kNftPart, ".", service.value_or(kLocalService), ".", + current_coin, ".", current_network, ".", + current_contract, ".", token_id.first})); + } + } + } + } + + return result; +} + +} // namespace brave_wallet diff --git a/components/brave_wallet/browser/brave_wallet_pin_service.h b/components/brave_wallet/browser/brave_wallet_pin_service.h new file mode 100644 index 000000000000..9c90f47d3f46 --- /dev/null +++ b/components/brave_wallet/browser/brave_wallet_pin_service.h @@ -0,0 +1,136 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_BRAVE_WALLET_BROWSER_BRAVE_WALLET_PIN_SERVICE_H_ +#define BRAVE_COMPONENTS_BRAVE_WALLET_BROWSER_BRAVE_WALLET_PIN_SERVICE_H_ + +#include +#include +#include + +#include "base/memory/scoped_refptr.h" +#include "base/task/sequenced_task_runner.h" +#include "brave/components/brave_wallet/browser/brave_wallet_service.h" +#include "brave/components/brave_wallet/browser/json_rpc_service.h" +#include "brave/components/brave_wallet/common/brave_wallet.mojom.h" +#include "brave/components/ipfs/ipfs_service.h" +#include "brave/components/ipfs/pin/ipfs_local_pin_service.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver_set.h" +#include "mojo/public/cpp/bindings/remote_set.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +using brave_wallet::mojom::BlockchainTokenPtr; + +namespace brave_wallet { + +std::string StatusToString(const mojom::TokenPinStatusCode& status); +std::string ErrorCodeToString( + const mojom::WalletPinServiceErrorCode& error_code); + +class BraveWalletPinService : public KeyedService, + public brave_wallet::mojom::WalletPinService { + public: + BraveWalletPinService(PrefService* prefs, + JsonRpcService* service, + ipfs::IpfsLocalPinService* local_pin_service); + ~BraveWalletPinService() override; + + mojo::PendingRemote MakeRemote(); + void Bind(mojo::PendingReceiver receiver); + + static std::string GetPath(const absl::optional& service, + const BlockchainTokenPtr& token); + static BlockchainTokenPtr TokenFromPath(const std::string& path); + static absl::optional ServiceFromPath(const std::string& path); + + // WalletPinService + void AddObserver(::mojo::PendingRemote + observer) override; + void AddPin(BlockchainTokenPtr token, + const absl::optional& service, + AddPinCallback callback) override; + void RemovePin(BlockchainTokenPtr token, + const absl::optional& service, + RemovePinCallback callback) override; + void GetTokenStatus(BlockchainTokenPtr token, + GetTokenStatusCallback callback) override; + void Validate(BlockchainTokenPtr token, + const absl::optional& service, + ValidateCallback callback) override; + + virtual void MarkAsPendingForPinning( + const mojom::BlockchainTokenPtr& token, + const absl::optional& service); + virtual void MarkAsPendingForUnpinning( + const mojom::BlockchainTokenPtr& token, + const absl::optional& service); + + virtual mojom::TokenPinStatusPtr GetTokenStatus( + absl::optional service, + const mojom::BlockchainTokenPtr& token); + virtual absl::optional GetLastValidateTime( + absl::optional service, + const mojom::BlockchainTokenPtr& token); + virtual std::set GetTokens( + const absl::optional& service); + + private: + void CreateToken(absl::optional service, + const mojom::BlockchainTokenPtr& token, + const std::vector& cids); + void RemoveToken(absl::optional service, + const mojom::BlockchainTokenPtr& token); + void SetTokenStatus(absl::optional service, + const mojom::BlockchainTokenPtr& token, + mojom::TokenPinStatusCode, + const mojom::PinErrorPtr& error); + + void FinishAddingWithResult(absl::optional service, + const mojom::BlockchainTokenPtr& token, + bool result, + mojom::PinErrorPtr error, + AddPinCallback callback); + + absl::optional> ResolvePinItems( + const absl::optional& service, + const BlockchainTokenPtr& token); + + void OnPinsRemoved(absl::optional service, + RemovePinCallback callback, + mojom::BlockchainTokenPtr token, + bool result); + void OnTokenPinned(absl::optional service, + AddPinCallback callback, + mojom::BlockchainTokenPtr, + bool result); + void OnTokenValidated(absl::optional service, + ValidateCallback callback, + mojom::BlockchainTokenPtr, + absl::optional result); + + void OnTokenMetaDataReceived(absl::optional service, + AddPinCallback callback, + mojom::BlockchainTokenPtr token, + const std::string& token_url, + const std::string& result, + mojom::ProviderError error, + const std::string& error_message); + + mojo::ReceiverSet receivers_; + mojo::RemoteSet observers_; + + // Prefs service is used to store list of pinned items + PrefService* prefs_; + + // JsonRpcService is used to fetch token metadata + JsonRpcService* json_rpc_service_; + ipfs::IpfsLocalPinService* local_pin_service_; +}; + +} // namespace brave_wallet + +#endif // BRAVE_COMPONENTS_BRAVE_WALLET_BROWSER_BRAVE_WALLET_PIN_SERVICE_H_ diff --git a/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc b/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc new file mode 100644 index 000000000000..ccf5d9fc447b --- /dev/null +++ b/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc @@ -0,0 +1,586 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_wallet/browser/brave_wallet_pin_service.h" + +#include +#include +#include +#include + +#include "base/json/json_reader.h" +#include "base/test/bind.h" +#include "base/time/time_override.h" +#include "brave/components/brave_wallet/browser/brave_wallet_prefs.h" +#include "brave/components/brave_wallet/browser/json_rpc_service.h" +#include "brave/components/brave_wallet/browser/pref_names.h" +#include "brave/components/brave_wallet/common/brave_wallet.mojom.h" +#include "brave/components/ipfs/pin/ipfs_local_pin_service.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/scoped_user_pref_update.h" +#include "components/prefs/testing_pref_service.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using base::subtle::ScopedTimeClockOverrides; +using testing::_; + +namespace brave_wallet { +namespace { +const char kMonkey1Path[] = + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1"; +const char kMonkey2Path[] = + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2"; +const char kMonkey3Path[] = + "nft.nftstorage.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2"; + +const char kMonkey1Url[] = + "ipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/2413"; +const char kMonkey1[] = + R"({"image":"ipfs://Qmcyc7tm9sZB9JnvLgejPTwdzjjNjDMiRWCUvaZAfp6cUg", + "attributes":[{"trait_type":"Mouth","value":"Bored Cigarette"}, + {"trait_type":"Fur","value":"Zombie"},{"trait_type":"Background","value":"Purple"}, + {"trait_type":"Eyes","value":"Closed"},{"trait_type":"Clothes","value":"Toga"}, + {"trait_type":"Hat","value":"Cowboy Hat"}]})"; + +base::Time g_overridden_now; +std::unique_ptr OverrideWithTimeNow( + const base::Time& overridden_now) { + g_overridden_now = overridden_now; + return std::make_unique( + []() { return g_overridden_now; }, nullptr, nullptr); +} + +} // namespace + +class MockIpfsLocalPinService : public ipfs::IpfsLocalPinService { + public: + MockIpfsLocalPinService() {} + + ~MockIpfsLocalPinService() override {} + + MOCK_METHOD3(AddPins, + void(const std::string& prefix, + const std::vector& cids, + ipfs::AddPinCallback callback)); + MOCK_METHOD2(RemovePins, + void(const std::string& prefix, + ipfs::RemovePinCallback callback)); + MOCK_METHOD3(ValidatePins, + void(const std::string& prefix, + const std::vector& cids, + ipfs::ValidatePinsCallback callback)); +}; + +class MockJsonRpcService : public JsonRpcService { + public: + MockJsonRpcService() {} + + MOCK_METHOD4(GetERC721Metadata, + void(const std::string& contract_address, + const std::string& token_id, + const std::string& chain_id, + GetTokenMetadataCallback callback)); + + ~MockJsonRpcService() override {} +}; + +class BraveWalletPinServiceTest : public testing::Test { + public: + BraveWalletPinServiceTest() = default; + + BraveWalletPinService* service() { return brave_wallet_pin_service_.get(); } + + protected: + void SetUp() override { + auto* registry = pref_service_.registry(); + registry->RegisterDictionaryPref(kPinnedErc721Assets); + brave_wallet_pin_service_ = std::make_unique( + GetPrefs(), GetJsonRpcService(), GetIpfsLocalPinService()); + } + + PrefService* GetPrefs() { return &pref_service_; } + + testing::NiceMock* GetJsonRpcService() { + return &json_rpc_service_; + } + + testing::NiceMock* GetIpfsLocalPinService() { + return &ipfs_local_pin_service_; + } + + testing::NiceMock ipfs_local_pin_service_; + testing::NiceMock json_rpc_service_; + + std::unique_ptr brave_wallet_pin_service_; + TestingPrefServiceSimple pref_service_; + content::BrowserTaskEnvironment task_environment_; +}; + +TEST_F(BraveWalletPinServiceTest, AddPin) { + { + ON_CALL(*GetJsonRpcService(), GetERC721Metadata(_, _, _, _)) + .WillByDefault(::testing::Invoke( + [](const std::string& contract_address, const std::string& token_id, + const std::string& chain_id, + MockJsonRpcService::GetTokenMetadataCallback callback) { + EXPECT_EQ("0x1", chain_id); + EXPECT_EQ("0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", + contract_address); + EXPECT_EQ("0x1", token_id); + std::move(callback).Run(kMonkey1Url, kMonkey1, + mojom::ProviderError::kSuccess, ""); + })); + ON_CALL(*GetIpfsLocalPinService(), AddPins(_, _, _)) + .WillByDefault(::testing::Invoke( + [](const std::string& prefix, const std::vector& cids, + ipfs::AddPinCallback callback) { + EXPECT_EQ(kMonkey1Path, prefix); + EXPECT_EQ("QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq", + cids.at(0)); + EXPECT_EQ("Qmcyc7tm9sZB9JnvLgejPTwdzjjNjDMiRWCUvaZAfp6cUg", + cids.at(1)); + std::move(callback).Run(true); + })); + + auto scoped_override = + OverrideWithTimeNow(base::Time::FromInternalValue(123u)); + + mojom::BlockchainTokenPtr token = + BraveWalletPinService::TokenFromPath(kMonkey1Path); + + absl::optional call_status; + service()->AddPin( + std::move(token), absl::nullopt, + base::BindLambdaForTesting( + [&call_status](bool result, mojom::PinErrorPtr error) { + call_status = result; + EXPECT_FALSE(error); + })); + EXPECT_TRUE(call_status.value()); + + const base::Value::Dict* token_record = + GetPrefs() + ->GetDict(kPinnedErc721Assets) + .FindDictByDottedPath(kMonkey1Path); + + base::Value::List expected_cids; + expected_cids.Append("QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq"); + expected_cids.Append("Qmcyc7tm9sZB9JnvLgejPTwdzjjNjDMiRWCUvaZAfp6cUg"); + + EXPECT_EQ(StatusToString(mojom::TokenPinStatusCode::STATUS_PINNED), + *(token_record->FindString("status"))); + EXPECT_EQ(nullptr, token_record->FindDict("error")); + EXPECT_EQ(expected_cids, *(token_record->FindList("cids"))); + EXPECT_EQ("123", *(token_record->FindString("validate_timestamp"))); + } + + { + ON_CALL(*GetJsonRpcService(), GetERC721Metadata(_, _, _, _)) + .WillByDefault(::testing::Invoke( + [](const std::string& contract_address, const std::string& token_id, + const std::string& chain_id, + MockJsonRpcService::GetTokenMetadataCallback callback) { + EXPECT_EQ("0x1", chain_id); + EXPECT_EQ("0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", + contract_address); + EXPECT_EQ("0x2", token_id); + std::move(callback).Run( + "", "", mojom::ProviderError::kParsingError, "Parsing error"); + })); + + mojom::BlockchainTokenPtr token = + BraveWalletPinService::TokenFromPath(kMonkey2Path); + + absl::optional call_status; + service()->AddPin( + std::move(token), absl::nullopt, + base::BindLambdaForTesting( + [&call_status](bool result, mojom::PinErrorPtr error) { + call_status = result; + EXPECT_TRUE(error); + })); + + EXPECT_FALSE(call_status.value()); + + const base::Value::Dict* token_record = + GetPrefs() + ->GetDict(kPinnedErc721Assets) + .FindDictByDottedPath(kMonkey2Path); + + EXPECT_EQ(StatusToString(mojom::TokenPinStatusCode::STATUS_PINNING_FAILED), + *(token_record->FindString("status"))); + EXPECT_EQ(ErrorCodeToString( + mojom::WalletPinServiceErrorCode::ERR_FETCH_METADATA_FAILED), + token_record->FindByDottedPath("error.error_code")->GetString()); + } +} + +TEST_F(BraveWalletPinServiceTest, RemovePin) { + { + DictionaryPrefUpdate update(GetPrefs(), kPinnedErc721Assets); + base::Value::Dict& update_dict = update->GetDict(); + + base::Value::Dict item; + item.Set("status", "pinned"); + item.Set("validation_timestamp", "123"); + base::Value::List cids; + cids.Append("QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq"); + cids.Append("Qmcyc7tm9sZB9JnvLgejPTwdzjjNjDMiRWCUvaZAfp6cUg"); + + update_dict.SetByDottedPath(kMonkey1Path, std::move(item)); + } + + { + ON_CALL(*GetIpfsLocalPinService(), RemovePins(_, _)) + .WillByDefault(::testing::Invoke( + [](const std::string& prefix, ipfs::RemovePinCallback callback) { + EXPECT_EQ(kMonkey1Path, prefix); + std::move(callback).Run(false); + })); + + mojom::BlockchainTokenPtr token = + BraveWalletPinService::TokenFromPath(kMonkey1Path); + + absl::optional remove_status; + service()->RemovePin( + std::move(token), absl::nullopt, + base::BindLambdaForTesting( + [&remove_status](bool status, mojom::PinErrorPtr error) { + remove_status = status; + })); + EXPECT_FALSE(remove_status.value()); + EXPECT_EQ( + StatusToString(mojom::TokenPinStatusCode::STATUS_UNPINNING_FAILED), + *(GetPrefs() + ->GetDict(kPinnedErc721Assets) + .FindByDottedPath(kMonkey1Path) + ->FindStringKey("status"))); + } + + { + ON_CALL(*GetIpfsLocalPinService(), RemovePins(_, _)) + .WillByDefault(::testing::Invoke( + [](const std::string& prefix, ipfs::RemovePinCallback callback) { + EXPECT_EQ(kMonkey1Path, prefix); + std::move(callback).Run(true); + })); + + mojom::BlockchainTokenPtr token = + BraveWalletPinService::TokenFromPath(kMonkey1Path); + + absl::optional remove_status; + service()->RemovePin( + std::move(token), absl::nullopt, + base::BindLambdaForTesting( + [&remove_status](bool status, mojom::PinErrorPtr error) { + remove_status = status; + })); + EXPECT_TRUE(remove_status.value()); + EXPECT_EQ(nullptr, GetPrefs() + ->GetDict(kPinnedErc721Assets) + .FindDictByDottedPath(kMonkey1Path)); + } +} + +TEST_F(BraveWalletPinServiceTest, ValidatePin) { + { + DictionaryPrefUpdate update(GetPrefs(), kPinnedErc721Assets); + base::Value::Dict& update_dict = update->GetDict(); + + base::Value::Dict item; + item.Set("status", "pinned"); + item.Set("validate_timestamp", "123"); + base::Value::List cids; + cids.Append("QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq"); + cids.Append("Qmcyc7tm9sZB9JnvLgejPTwdzjjNjDMiRWCUvaZAfp6cUg"); + item.Set("cids", std::move(cids)); + + update_dict.SetByDottedPath(kMonkey1Path, std::move(item)); + } + + { + auto scoped_override = + OverrideWithTimeNow(base::Time::FromInternalValue(345u)); + + mojom::BlockchainTokenPtr token = + BraveWalletPinService::TokenFromPath(kMonkey1Path); + + ON_CALL(*GetIpfsLocalPinService(), ValidatePins(_, _, _)) + .WillByDefault(::testing::Invoke( + [](const std::string& prefix, const std::vector& cids, + ipfs::ValidatePinsCallback callback) { + EXPECT_EQ("QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq", + cids.at(0)); + EXPECT_EQ("Qmcyc7tm9sZB9JnvLgejPTwdzjjNjDMiRWCUvaZAfp6cUg", + cids.at(1)); + EXPECT_EQ(kMonkey1Path, prefix); + std::move(callback).Run(true); + })); + + absl::optional validate_status; + service()->Validate( + std::move(token), absl::nullopt, + base::BindLambdaForTesting( + [&validate_status](bool status, mojom::PinErrorPtr error) { + validate_status = status; + })); + EXPECT_TRUE(validate_status.value()); + + const base::Value::Dict* token_record = + GetPrefs() + ->GetDict(kPinnedErc721Assets) + .FindDictByDottedPath(kMonkey1Path); + EXPECT_EQ("345", *(token_record->FindString("validate_timestamp"))); + } + + { + mojom::BlockchainTokenPtr token = + BraveWalletPinService::TokenFromPath(kMonkey1Path); + + ON_CALL(*GetIpfsLocalPinService(), ValidatePins(_, _, _)) + .WillByDefault(::testing::Invoke( + [](const std::string& prefix, const std::vector& cids, + ipfs::ValidatePinsCallback callback) { + std::move(callback).Run(absl::nullopt); + })); + + absl::optional validate_status; + service()->Validate( + std::move(token), absl::nullopt, + base::BindLambdaForTesting( + [&validate_status](bool status, mojom::PinErrorPtr error) { + validate_status = status; + })); + + EXPECT_FALSE(validate_status.value()); + + const base::Value::Dict* token_record = + GetPrefs() + ->GetDict(kPinnedErc721Assets) + .FindDictByDottedPath(kMonkey1Path); + EXPECT_EQ("345", *(token_record->FindString("validate_timestamp"))); + } + + { + mojom::BlockchainTokenPtr token = + BraveWalletPinService::TokenFromPath(kMonkey1Path); + + ON_CALL(*GetIpfsLocalPinService(), ValidatePins(_, _, _)) + .WillByDefault(::testing::Invoke( + [](const std::string& prefix, const std::vector& cids, + ipfs::ValidatePinsCallback callback) { + std::move(callback).Run(false); + })); + + absl::optional validate_status; + service()->Validate( + std::move(token), absl::nullopt, + base::BindLambdaForTesting( + [&validate_status](bool status, mojom::PinErrorPtr error) { + validate_status = status; + })); + + EXPECT_TRUE(validate_status.value()); + + const base::Value::Dict* token_record = + GetPrefs() + ->GetDict(kPinnedErc721Assets) + .FindDictByDottedPath(kMonkey1Path); + + EXPECT_EQ(nullptr, token_record->FindString("validate_timestamp")); + } +} + +TEST_F(BraveWalletPinServiceTest, GetTokenStatus) { + { + DictionaryPrefUpdate update(GetPrefs(), kPinnedErc721Assets); + base::Value::Dict& update_dict = update->GetDict(); + + base::Value::Dict item; + item.Set("status", "pinned"); + item.Set("validate_timestamp", "123"); + base::Value::List cids; + cids.Append("QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq"); + cids.Append("Qmcyc7tm9sZB9JnvLgejPTwdzjjNjDMiRWCUvaZAfp6cUg"); + item.Set("cids", std::move(cids)); + + update_dict.SetByDottedPath(kMonkey1Path, std::move(item)); + } + + { + DictionaryPrefUpdate update(GetPrefs(), kPinnedErc721Assets); + base::Value::Dict& update_dict = update->GetDict(); + + base::Value::Dict item; + item.Set("status", + StatusToString(mojom::TokenPinStatusCode::STATUS_PINNING_FAILED)); + base::Value::Dict error; + error.Set("error_code", + ErrorCodeToString( + mojom::WalletPinServiceErrorCode::ERR_FETCH_METADATA_FAILED)); + error.Set("error_message", "Fail to fetch metadata"); + item.Set("error", std::move(error)); + + update_dict.SetByDottedPath(kMonkey2Path, std::move(item)); + } + + mojom::BlockchainTokenPtr token1 = + BraveWalletPinService::TokenFromPath(kMonkey1Path); + + { + mojom::TokenPinStatusPtr status = + service()->GetTokenStatus(absl::nullopt, token1); + EXPECT_EQ(mojom::TokenPinStatusCode::STATUS_PINNED, status->code); + EXPECT_TRUE(status->error.is_null()); + EXPECT_EQ(base::Time::FromInternalValue(123u), + status->validate_time.value()); + } + + { + mojom::TokenPinStatusPtr status = + service()->GetTokenStatus("nft.storage", token1); + EXPECT_TRUE(status.is_null()); + } + + mojom::BlockchainTokenPtr token2 = + BraveWalletPinService::TokenFromPath(kMonkey2Path); + + { + mojom::TokenPinStatusPtr status = + service()->GetTokenStatus(absl::nullopt, token2); + EXPECT_EQ(mojom::TokenPinStatusCode::STATUS_PINNING_FAILED, status->code); + EXPECT_EQ(mojom::WalletPinServiceErrorCode::ERR_FETCH_METADATA_FAILED, + status->error->error_code); + EXPECT_FALSE(status->validate_time.has_value()); + } +} + +TEST_F(BraveWalletPinServiceTest, GetLastValidateTime) { + { + DictionaryPrefUpdate update(GetPrefs(), kPinnedErc721Assets); + base::Value::Dict& update_dict = update->GetDict(); + + base::Value::Dict item; + item.Set("status", "pinned"); + item.Set("validate_timestamp", "123"); + base::Value::List cids; + cids.Append("QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq"); + cids.Append("Qmcyc7tm9sZB9JnvLgejPTwdzjjNjDMiRWCUvaZAfp6cUg"); + item.Set("cids", std::move(cids)); + + update_dict.SetByDottedPath(kMonkey1Path, std::move(item)); + } + + mojom::BlockchainTokenPtr token = + BraveWalletPinService::TokenFromPath(kMonkey1Path); + + { + base::Time last_validate_time = + service()->GetLastValidateTime(absl::nullopt, token).value(); + EXPECT_EQ(base::Time::FromInternalValue(123u), last_validate_time); + } + + { + EXPECT_FALSE( + service()->GetLastValidateTime("nft.storage", token).has_value()); + } +} + +TEST_F(BraveWalletPinServiceTest, TokenFromPath) { + mojom::BlockchainTokenPtr token = + BraveWalletPinService::TokenFromPath(kMonkey1Path); + EXPECT_TRUE(token->is_erc721); + EXPECT_EQ(mojom::CoinType::ETH, static_cast(token->coin)); + EXPECT_EQ("0x1", token->chain_id); + EXPECT_EQ("0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", + token->contract_address); + EXPECT_EQ("0x1", token->token_id); +} + +TEST_F(BraveWalletPinServiceTest, ServiceFromPath) { + EXPECT_FALSE( + BraveWalletPinService::ServiceFromPath(kMonkey1Path).has_value()); + + EXPECT_EQ("nftstorage", BraveWalletPinService::ServiceFromPath( + "nft.nftstorage.60.0x1." + "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1") + .value()); +} + +TEST_F(BraveWalletPinServiceTest, GetPath) { + { + mojom::BlockchainTokenPtr token = mojom::BlockchainToken::New(); + token->coin = mojom::CoinType::ETH; + token->contract_address = "abc"; + token->token_id = "0x2"; + token->chain_id = "mainnet"; + auto path = BraveWalletPinService::GetPath(absl::nullopt, token); + EXPECT_EQ("nft.local.60.mainnet.abc.0x2", path); + } + + { + mojom::BlockchainTokenPtr token = mojom::BlockchainToken::New(); + token->coin = mojom::CoinType::ETH; + token->contract_address = "abc"; + token->token_id = "0x2"; + token->chain_id = "mainnet"; + auto path = BraveWalletPinService::GetPath("nftstorage", token); + EXPECT_EQ("nft.nftstorage.60.mainnet.abc.0x2", path); + } +} + +TEST_F(BraveWalletPinServiceTest, GetTokens) { + { + DictionaryPrefUpdate update(GetPrefs(), kPinnedErc721Assets); + base::Value::Dict& update_dict = update->GetDict(); + + base::Value::Dict item; + item.Set("status", "pinned"); + + update_dict.SetByDottedPath(kMonkey1Path, std::move(item)); + } + + { + DictionaryPrefUpdate update(GetPrefs(), kPinnedErc721Assets); + base::Value::Dict& update_dict = update->GetDict(); + + base::Value::Dict item; + item.Set("status", "pinning_failed"); + + update_dict.SetByDottedPath(kMonkey2Path, std::move(item)); + } + + { + DictionaryPrefUpdate update(GetPrefs(), kPinnedErc721Assets); + base::Value::Dict& update_dict = update->GetDict(); + + base::Value::Dict item; + item.Set("status", "pinned"); + + update_dict.SetByDottedPath(kMonkey3Path, std::move(item)); + } + + { + auto tokens = service()->GetTokens(absl::nullopt); + EXPECT_EQ(2u, tokens.size()); + EXPECT_TRUE(tokens.contains(kMonkey1Path)); + EXPECT_TRUE(tokens.contains(kMonkey2Path)); + } + + { + auto tokens = service()->GetTokens("nftstorage"); + EXPECT_EQ(1u, tokens.size()); + EXPECT_TRUE(tokens.contains(kMonkey3Path)); + } + + { + auto tokens = service()->GetTokens("non_existing_storage"); + EXPECT_EQ(0u, tokens.size()); + } +} + +} // namespace brave_wallet diff --git a/components/brave_wallet/browser/brave_wallet_prefs.cc b/components/brave_wallet/browser/brave_wallet_prefs.cc index 724d803edf2c..840442318d87 100644 --- a/components/brave_wallet/browser/brave_wallet_prefs.cc +++ b/components/brave_wallet/browser/brave_wallet_prefs.cc @@ -126,6 +126,9 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { registry->RegisterTimePref(kBraveWalletP3ALastReportTime, base::Time()); registry->RegisterTimePref(kBraveWalletP3AFirstReportTime, base::Time()); registry->RegisterListPref(kBraveWalletP3AWeeklyStorage); + + registry->RegisterDictionaryPref(kPinnedErc721Assets); + registry->RegisterBooleanPref(kAutoPinEnabled, true); } void RegisterProfilePrefsForMigration( @@ -195,6 +198,7 @@ void ClearBraveWalletServicePrefs(PrefService* prefs) { prefs->ClearPref(kBraveWalletUserAssets); prefs->ClearPref(kDefaultBaseCurrency); prefs->ClearPref(kDefaultBaseCryptocurrency); + prefs->ClearPref(kPinnedErc721Assets); } void MigrateObsoleteProfilePrefs(PrefService* prefs) { diff --git a/components/brave_wallet/browser/brave_wallet_service.cc b/components/brave_wallet/browser/brave_wallet_service.cc index cf632e3b941c..f264e51fd9aa 100644 --- a/components/brave_wallet/browser/brave_wallet_service.cc +++ b/components/brave_wallet/browser/brave_wallet_service.cc @@ -207,6 +207,8 @@ BraveWalletService::BraveWalletService( weak_ptr_factory_.GetWeakPtr())); } +BraveWalletService::BraveWalletService() : weak_ptr_factory_(this) {} + BraveWalletService::~BraveWalletService() = default; mojo::PendingRemote @@ -361,6 +363,7 @@ bool BraveWalletService::AddUserAsset(mojom::BlockchainTokenPtr token, value.Set("coingecko_id", token->coingecko_id); user_assets_list->Append(std::move(value)); + return true; } @@ -373,7 +376,15 @@ void BraveWalletService::GetUserAssets(const std::string& chain_id, } bool BraveWalletService::AddUserAsset(mojom::BlockchainTokenPtr token) { - return BraveWalletService::AddUserAsset(std::move(token), profile_prefs_); + mojom::BlockchainTokenPtr clone = token.Clone(); + bool result = BraveWalletService::AddUserAsset(std::move(token), profile_prefs_); + + if (result) { + for (const auto& observer : token_observers_) { + observer->OnTokenAdded(clone.Clone()); + } + } + return result; } void BraveWalletService::AddUserAsset(mojom::BlockchainTokenPtr token, @@ -410,6 +421,11 @@ bool BraveWalletService::RemoveUserAsset(mojom::BlockchainTokenPtr token) { FindAsset(user_assets_list, *address, token->token_id, token->is_erc721); if (it != user_assets_list->end()) user_assets_list->erase(it); + + for (const auto& observer : token_observers_) { + observer->OnTokenRemoved(token.Clone()); + } + return true; } @@ -1026,6 +1042,11 @@ void BraveWalletService::AddObserver( observers_.Add(std::move(observer)); } +void BraveWalletService::AddTokenObserver( + ::mojo::PendingRemote observer) { + token_observers_.Add(std::move(observer)); +} + void BraveWalletService::OnActiveOriginChanged( const mojom::OriginInfoPtr& origin_info) { for (const auto& observer : observers_) { diff --git a/components/brave_wallet/browser/brave_wallet_service.h b/components/brave_wallet/browser/brave_wallet_service.h index 1023459885bf..36f9284e9599 100644 --- a/components/brave_wallet/browser/brave_wallet_service.h +++ b/components/brave_wallet/browser/brave_wallet_service.h @@ -66,6 +66,9 @@ class BraveWalletService : public KeyedService, TxService* tx_service, PrefService* profile_prefs, PrefService* local_state); + + // For tests + BraveWalletService(); ~BraveWalletService() override; BraveWalletService(const BraveWalletService&) = delete; @@ -93,6 +96,9 @@ class BraveWalletService : public KeyedService, // mojom::BraveWalletService: void AddObserver(::mojo::PendingRemote observer) override; + void AddTokenObserver( + ::mojo::PendingRemote observer) + override; void GetUserAssets(const std::string& chain_id, mojom::CoinType coin, @@ -306,6 +312,7 @@ class BraveWalletService : public KeyedService, decrypt_callbacks_; base::flat_map decrypt_ids_; mojo::RemoteSet observers_; + mojo::RemoteSet token_observers_; std::unique_ptr delegate_; raw_ptr keyring_service_ = nullptr; raw_ptr json_rpc_service_ = nullptr; diff --git a/components/brave_wallet/browser/json_rpc_service.cc b/components/brave_wallet/browser/json_rpc_service.cc index 9da7cae7bbed..b1a5006ea556 100644 --- a/components/brave_wallet/browser/json_rpc_service.cc +++ b/components/brave_wallet/browser/json_rpc_service.cc @@ -187,6 +187,8 @@ JsonRpcService::JsonRpcService( : JsonRpcService(std::move(url_loader_factory), std::move(prefs), nullptr) { } +JsonRpcService::JsonRpcService() : weak_ptr_factory_(this) {} + void JsonRpcService::SetAPIRequestHelperForTesting( scoped_refptr url_loader_factory) { api_request_helper_ = std::make_unique( @@ -2121,6 +2123,7 @@ void JsonRpcService::OnGetEthTokenUri(GetEthTokenUriCallback callback, std::move(callback).Run(GURL(), error, error_message); return; } + std::string token_url_spec = url.spec(); std::move(callback).Run(url, mojom::ProviderError::kSuccess, ""); } diff --git a/components/brave_wallet/browser/json_rpc_service.h b/components/brave_wallet/browser/json_rpc_service.h index 6d86743ba8e4..00f306645e11 100644 --- a/components/brave_wallet/browser/json_rpc_service.h +++ b/components/brave_wallet/browser/json_rpc_service.h @@ -55,6 +55,7 @@ class JsonRpcService : public KeyedService, public mojom::JsonRpcService { JsonRpcService( scoped_refptr url_loader_factory, PrefService* prefs); + JsonRpcService(); ~JsonRpcService() override; static void MigrateMultichainNetworks(PrefService* prefs); @@ -543,6 +544,7 @@ class JsonRpcService : public KeyedService, public mojom::JsonRpcService { const std::string& owner_address, mojom::ProviderError error, const std::string& error_message); + void OnGetEthTokenUri(GetEthTokenUriCallback callback, const APIRequestResult api_request_result); diff --git a/components/brave_wallet/browser/json_rpc_service_unittest.cc b/components/brave_wallet/browser/json_rpc_service_unittest.cc index 6b5ee3f825b9..3761affed11e 100644 --- a/components/brave_wallet/browser/json_rpc_service_unittest.cc +++ b/components/brave_wallet/browser/json_rpc_service_unittest.cc @@ -1108,14 +1108,14 @@ class JsonRpcServiceUnitTest : public testing::Test { base::RunLoop run_loop; json_rpc_service_->GetERC721Metadata( contract, token_id, chain_id, - base::BindLambdaForTesting([&](const std::string& response, - mojom::ProviderError error, - const std::string& error_message) { - EXPECT_EQ(response, expected_response); - EXPECT_EQ(error, expected_error); - EXPECT_EQ(error_message, expected_error_message); - run_loop.Quit(); - })); + base::BindLambdaForTesting( + [&](const std::string& token_url, const std::string& response, + mojom::ProviderError error, const std::string& error_message) { + EXPECT_EQ(response, expected_response); + EXPECT_EQ(error, expected_error); + EXPECT_EQ(error_message, expected_error_message); + run_loop.Quit(); + })); run_loop.Run(); } @@ -1128,14 +1128,14 @@ class JsonRpcServiceUnitTest : public testing::Test { base::RunLoop run_loop; json_rpc_service_->GetERC1155Metadata( contract, token_id, chain_id, - base::BindLambdaForTesting([&](const std::string& response, - mojom::ProviderError error, - const std::string& error_message) { - EXPECT_EQ(response, expected_response); - EXPECT_EQ(error, expected_error); - EXPECT_EQ(error_message, expected_error_message); - run_loop.Quit(); - })); + base::BindLambdaForTesting( + [&](const std::string& token_url, const std::string& response, + mojom::ProviderError error, const std::string& error_message) { + EXPECT_EQ(response, expected_response); + EXPECT_EQ(error, expected_error); + EXPECT_EQ(error_message, expected_error_message); + run_loop.Quit(); + })); run_loop.Run(); } diff --git a/components/brave_wallet/browser/pref_names.cc b/components/brave_wallet/browser/pref_names.cc index cbeffc5e55b4..aa347c29089a 100644 --- a/components/brave_wallet/browser/pref_names.cc +++ b/components/brave_wallet/browser/pref_names.cc @@ -72,3 +72,5 @@ const char kBraveWalletCurrentChainId[] = const char kBraveWalletUserAssetsDeprecated[] = "brave.wallet.user_assets"; const char kBraveWalletUserAssetsAddPreloadingNetworksMigratedDeprecated[] = "brave.wallet.user.assets.add_preloading_networks_migrated"; +const char kPinnedErc721Assets[] = "brave.wallet.user_pin_data"; +const char kAutoPinEnabled[] = "brave.wallet.auto_pin_enabled"; diff --git a/components/brave_wallet/browser/pref_names.h b/components/brave_wallet/browser/pref_names.h index 87977c67eb53..51bf85873a32 100644 --- a/components/brave_wallet/browser/pref_names.h +++ b/components/brave_wallet/browser/pref_names.h @@ -59,5 +59,7 @@ extern const char kBraveWalletCurrentChainId[]; extern const char kBraveWalletUserAssetsDeprecated[]; extern const char kBraveWalletUserAssetsAddPreloadingNetworksMigratedDeprecated[]; +extern const char kPinnedErc721Assets[]; +extern const char kAutoPinEnabled[]; #endif // BRAVE_COMPONENTS_BRAVE_WALLET_BROWSER_PREF_NAMES_H_ diff --git a/components/brave_wallet/browser/test/BUILD.gn b/components/brave_wallet/browser/test/BUILD.gn index 28aa45b91de4..f795c4e6bc41 100644 --- a/components/brave_wallet/browser/test/BUILD.gn +++ b/components/brave_wallet/browser/test/BUILD.gn @@ -13,6 +13,8 @@ source_set("brave_wallet_unit_tests") { "//brave/components/brave_wallet/browser/asset_ratio_service_unittest.cc", "//brave/components/brave_wallet/browser/blockchain_list_parser_unittest.cc", "//brave/components/brave_wallet/browser/blockchain_registry_unittest.cc", + "//brave/components/brave_wallet/browser/brave_wallet_auto_pin_service_unittest.cc", + "//brave/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc", "//brave/components/brave_wallet/browser/brave_wallet_utils_unittest.cc", "//brave/components/brave_wallet/browser/eip1559_transaction_unittest.cc", "//brave/components/brave_wallet/browser/eip2930_transaction_unittest.cc", diff --git a/components/brave_wallet/common/brave_wallet.mojom b/components/brave_wallet/common/brave_wallet.mojom index 88469debe067..b3f42815c368 100644 --- a/components/brave_wallet/common/brave_wallet.mojom +++ b/components/brave_wallet/common/brave_wallet.mojom @@ -212,6 +212,62 @@ interface SolanaProvider { mojo_base.mojom.DictionaryValue result); }; +enum WalletPinServiceErrorCode { + ERR_WRONG_TOKEN = 1, + ERR_NON_IPFS_TOKEN_URL = 2, + ERR_FETCH_METADATA_FAILED = 3, + ERR_WRONG_METADATA_FORMAT = 4, + ERR_ALREADY_PINNED = 5, + ERR_NOT_PINNED = 6, + ERR_PINNING_FAILED = 7 +}; + +enum TokenPinStatusCode { + STATUS_NOT_PINNED = 1, + STATUS_PINNED = 2, + STATUS_PINNING_IN_PROGRESS = 3, + STATUS_PINNING_FAILED = 4, + STATUS_UNPINNING_IN_PROGRESS = 5, + STATUS_UNPINNING_FAILED = 6, + STATUS_PINNING_PENDING = 7, + STATUS_UNPINNING_PENDING = 8 +}; + +struct PinError { + WalletPinServiceErrorCode error_code; + string message; +}; + +struct TokenPinStatus { + TokenPinStatusCode code; + PinError? error; + mojo_base.mojom.Time? validate_time; +}; + +struct TokenPinOverview { + TokenPinStatus local; + map remotes; +}; + +interface BraveWalletPinServiceObserver { + OnTokenStatusChanged(string? service, BlockchainToken token, TokenPinStatus status); +}; + +interface WalletPinService { + AddObserver(pending_remote observer); + + AddPin(BlockchainToken token, string? service) => (bool result, PinError? error); + RemovePin(BlockchainToken token, string? service) => (bool result, PinError? response); + GetTokenStatus(BlockchainToken token) => (TokenPinOverview? status, PinError? error); + Validate(BlockchainToken token, string? service) => (bool result, PinError? error); +}; + +interface WalletAutoPinService { + SetAutoPinEnabled(bool enabled); + IsAutoPinEnabled() => (bool enabled); + PostPinToken(BlockchainToken token) => (bool result); + PostUnpinToken(BlockchainToken token) => (bool result); +}; // Used by the WebUI page to bootstrap bidirectional communication. interface PanelHandlerFactory { @@ -247,8 +303,9 @@ interface PageHandlerFactory { pending_receiver solana_tx_manager_proxy, pending_receiver fil_tx_manager_proxy, pending_receiver brave_wallet_service, - pending_receiver brave_wallet_p3a); - + pending_receiver brave_wallet_p3a, + pending_receiver brave_wallet_pin_service, + pending_receiver brave_wallet_auto_pin_service); }; // Browser-side handler for requests from WebUI page. @@ -930,10 +987,10 @@ interface JsonRpcService { string owner_address, string spender_address) => (string allowance, ProviderError error, string error_message); // Obtains the metadata JSON for a token ID of an ERC721 contract - GetERC721Metadata(string contract, string token_id, string chain_id) => (string response, ProviderError error, string error_message); + GetERC721Metadata(string contract, string token_id, string chain_id) => (string token_url, string response, ProviderError error, string error_message); // Obtains the metadata JSON for a token ID of an ERC1155 contract - GetERC1155Metadata(string contract, string token_id, string chain_id) => (string response, ProviderError error, string error_message); + GetERC1155Metadata(string contract, string token_id, string chain_id) => (string token_url, string response, ProviderError error, string error_message); // ENS lookups EnableEnsOffchainLookup(); @@ -1183,6 +1240,11 @@ interface BraveWalletServiceObserver { OnDiscoverAssetsCompleted(array discovered_assets); }; +interface BraveWalletServiceTokenObserver { + OnTokenAdded(BlockchainToken token); + OnTokenRemoved(BlockchainToken token); +}; + struct SignMessageRequest { OriginInfo origin_info; int32 id; @@ -1239,6 +1301,8 @@ interface BraveWalletService { // Adds an observer for BraveWalletService AddObserver(pending_remote observer); + AddTokenObserver(pending_remote observer); + // Obtains the user assets for the specified chain ID and coin type. GetUserAssets(string chain_id, CoinType coin) => (array tokens); From 426bacc088a15a8d8d055965884ee3373736895b Mon Sep 17 00:00:00 2001 From: oisupov Date: Fri, 2 Dec 2022 20:36:28 +0400 Subject: [PATCH 04/15] Add BraveWalletAutoPinService --- browser/brave_wallet/BUILD.gn | 4 + .../brave_wallet_auto_pin_service_factory.cc | 88 +++ .../brave_wallet_auto_pin_service_factory.h | 54 ++ browser/profiles/brave_profile_manager.cc | 2 + .../browser/brave_wallet_auto_pin_service.cc | 243 +++++++++ .../browser/brave_wallet_auto_pin_service.h | 105 ++++ .../brave_wallet_auto_pin_service_unittest.cc | 514 ++++++++++++++++++ 7 files changed, 1010 insertions(+) create mode 100644 browser/brave_wallet/brave_wallet_auto_pin_service_factory.cc create mode 100644 browser/brave_wallet/brave_wallet_auto_pin_service_factory.h create mode 100644 components/brave_wallet/browser/brave_wallet_auto_pin_service.cc create mode 100644 components/brave_wallet/browser/brave_wallet_auto_pin_service.h create mode 100644 components/brave_wallet/browser/brave_wallet_auto_pin_service_unittest.cc diff --git a/browser/brave_wallet/BUILD.gn b/browser/brave_wallet/BUILD.gn index d471f53014bf..b4efee0a4179 100644 --- a/browser/brave_wallet/BUILD.gn +++ b/browser/brave_wallet/BUILD.gn @@ -8,8 +8,12 @@ source_set("brave_wallet") { "asset_ratio_service_factory.h", "blockchain_images_source.cc", "blockchain_images_source.h", + "brave_wallet_auto_pin_service_factory.cc", + "brave_wallet_auto_pin_service_factory.h", "brave_wallet_context_utils.cc", "brave_wallet_context_utils.h", + "brave_wallet_pin_service_factory.cc", + "brave_wallet_pin_service_factory.h", "brave_wallet_service_factory.cc", "brave_wallet_service_factory.h", "json_rpc_service_factory.cc", diff --git a/browser/brave_wallet/brave_wallet_auto_pin_service_factory.cc b/browser/brave_wallet/brave_wallet_auto_pin_service_factory.cc new file mode 100644 index 000000000000..f7d3a9dc6ac0 --- /dev/null +++ b/browser/brave_wallet/brave_wallet_auto_pin_service_factory.cc @@ -0,0 +1,88 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h" + +#include +#include + +#include "brave/browser/brave_wallet/brave_wallet_context_utils.h" + +#include "brave/browser/brave_wallet/brave_wallet_pin_service_factory.h" +#include "brave/browser/brave_wallet/brave_wallet_service_factory.h" + +#include "brave/components/brave_wallet/browser/brave_wallet_pin_service.h" +#include "brave/components/brave_wallet/browser/brave_wallet_service.h" + +#include "chrome/browser/profiles/incognito_helpers.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/user_prefs/user_prefs.h" + +namespace brave_wallet { + +// static +BraveWalletAutoPinServiceFactory* +BraveWalletAutoPinServiceFactory::GetInstance() { + return base::Singleton::get(); +} + +// static +mojo::PendingRemote +BraveWalletAutoPinServiceFactory::GetForContext( + content::BrowserContext* context) { + if (!IsAllowedForContext(context)) { + return mojo::PendingRemote(); + } + + return GetServiceForContext(context)->MakeRemote(); +} + +// static +BraveWalletAutoPinService* +BraveWalletAutoPinServiceFactory::GetServiceForContext( + content::BrowserContext* context) { + if (!IsAllowedForContext(context)) { + return nullptr; + } + return static_cast( + GetInstance()->GetServiceForBrowserContext(context, true)); +} + +// static +void BraveWalletAutoPinServiceFactory::BindForContext( + content::BrowserContext* context, + mojo::PendingReceiver receiver) { + auto* service = + BraveWalletAutoPinServiceFactory::GetServiceForContext(context); + if (service) { + service->Bind(std::move(receiver)); + } +} + +BraveWalletAutoPinServiceFactory::BraveWalletAutoPinServiceFactory() + : BrowserContextKeyedServiceFactory( + "BraveWalletAutoPinService", + BrowserContextDependencyManager::GetInstance()) { + DependsOn(BraveWalletServiceFactory::GetInstance()); + DependsOn(BraveWalletPinServiceFactory::GetInstance()); +} + +BraveWalletAutoPinServiceFactory::~BraveWalletAutoPinServiceFactory() = default; + +KeyedService* BraveWalletAutoPinServiceFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + return new BraveWalletAutoPinService( + user_prefs::UserPrefs::Get(context), + BraveWalletServiceFactory::GetServiceForContext(context), + BraveWalletPinServiceFactory::GetServiceForContext(context)); +} + +content::BrowserContext* +BraveWalletAutoPinServiceFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return chrome::GetBrowserContextRedirectedInIncognito(context); +} + +} // namespace brave_wallet diff --git a/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h b/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h new file mode 100644 index 000000000000..0d1ea5ae7832 --- /dev/null +++ b/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h @@ -0,0 +1,54 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_BROWSER_BRAVE_WALLET_BRAVE_WALLET_AUTO_PIN_SERVICE_FACTORY_H_ +#define BRAVE_BROWSER_BRAVE_WALLET_BRAVE_WALLET_AUTO_PIN_SERVICE_FACTORY_H_ + +#include "base/memory/singleton.h" + +#include "brave/components/brave_wallet/browser/brave_wallet_auto_pin_service.h" +#include "brave/components/brave_wallet/common/brave_wallet.mojom.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" +#include "components/keyed_service/core/keyed_service.h" +#include "content/public/browser/browser_context.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/pending_remote.h" + +namespace brave_wallet { + +class BraveWalletAutoPinService; + +class BraveWalletAutoPinServiceFactory + : public BrowserContextKeyedServiceFactory { + public: + static mojo::PendingRemote GetForContext( + content::BrowserContext* context); + static BraveWalletAutoPinService* GetServiceForContext( + content::BrowserContext* context); + static BraveWalletAutoPinServiceFactory* GetInstance(); + static void BindForContext( + content::BrowserContext* context, + mojo::PendingReceiver receiver); + + private: + friend struct base::DefaultSingletonTraits; + + BraveWalletAutoPinServiceFactory(); + ~BraveWalletAutoPinServiceFactory() override; + + BraveWalletAutoPinServiceFactory(const BraveWalletAutoPinServiceFactory&) = + delete; + BraveWalletAutoPinServiceFactory& operator=( + const BraveWalletAutoPinServiceFactory&) = delete; + + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; +}; + +} // namespace brave_wallet + +#endif // BRAVE_BROWSER_BRAVE_WALLET_BRAVE_WALLET_AUTO_PIN_SERVICE_FACTORY_H_ diff --git a/browser/profiles/brave_profile_manager.cc b/browser/profiles/brave_profile_manager.cc index 8deec5d924ed..15d73e1b3a4e 100644 --- a/browser/profiles/brave_profile_manager.cc +++ b/browser/profiles/brave_profile_manager.cc @@ -15,6 +15,7 @@ #include "brave/browser/brave_federated/brave_federated_service_factory.h" #include "brave/browser/brave_news/brave_news_controller_factory.h" #include "brave/browser/brave_rewards/rewards_service_factory.h" +#include "brave/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h" #include "brave/browser/brave_wallet/brave_wallet_service_factory.h" #include "brave/browser/profiles/profile_util.h" #include "brave/browser/url_sanitizer/url_sanitizer_service_factory.h" @@ -98,6 +99,7 @@ void BraveProfileManager::DoFinalInitForServices(Profile* profile, brave_ads::AdsServiceFactory::GetForProfile(profile); brave_rewards::RewardsServiceFactory::GetForProfile(profile); brave_wallet::BraveWalletServiceFactory::GetServiceForContext(profile); + brave_wallet::BraveWalletAutoPinServiceFactory::GetServiceForContext(profile); #if BUILDFLAG(ENABLE_IPFS) ipfs::IpfsServiceFactory::GetForContext(profile); #endif diff --git a/components/brave_wallet/browser/brave_wallet_auto_pin_service.cc b/components/brave_wallet/browser/brave_wallet_auto_pin_service.cc new file mode 100644 index 000000000000..a50fffde34e8 --- /dev/null +++ b/components/brave_wallet/browser/brave_wallet_auto_pin_service.cc @@ -0,0 +1,243 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_wallet/browser/brave_wallet_auto_pin_service.h" + +#include "brave/components/brave_wallet/browser/pref_names.h" + +namespace brave_wallet { + +IntentData::IntentData(const BlockchainTokenPtr& token, + Operation operation, + absl::optional service) + : token(token.Clone()), operation(operation), service(service) {} + +IntentData::~IntentData() {} + +BraveWalletAutoPinService::BraveWalletAutoPinService( + PrefService* prefs, + BraveWalletService* brave_wallet_service, + BraveWalletPinService* brave_wallet_pin_service) + : pref_service_(prefs), + brave_wallet_service_(brave_wallet_service), + brave_wallet_pin_service_(brave_wallet_pin_service) { + Restore(); + brave_wallet_service->AddTokenObserver( + token_observer_.BindNewPipeAndPassRemote()); +} + +BraveWalletAutoPinService::~BraveWalletAutoPinService() {} + +void BraveWalletAutoPinService::Bind( + mojo::PendingReceiver receiver) { + receivers_.Add(this, std::move(receiver)); +} + +void BraveWalletAutoPinService::OnTokenAdded(BlockchainTokenPtr token) { + if (!IsAutoPinEnabled()) { + return; + } + PostPinToken(std::move(token), base::OnceCallback()); +} + +void BraveWalletAutoPinService::OnTokenRemoved(BlockchainTokenPtr token) { + const auto iter = + std::remove_if(queue_.begin(), queue_.end(), + [&token](const std::unique_ptr& intent) { + return intent->token == token; + }); + queue_.erase(iter, queue_.end()); + PostUnpinToken(std::move(token), base::OnceCallback()); +} + +void BraveWalletAutoPinService::Restore() { + brave_wallet_service_->GetUserAssets( + mojom::kMainnetChainId, mojom::CoinType::ETH, + base::BindOnce(&BraveWalletAutoPinService::OnTokenListResolved, + base::Unretained(this))); +} + +void BraveWalletAutoPinService::OnTokenListResolved( + std::vector token_list) { + bool autopin_enabled = IsAutoPinEnabled(); + std::set known_tokens = + brave_wallet_pin_service_->GetTokens(absl::nullopt); + for (const auto& token : token_list) { + if (!token->is_erc721) { + continue; + } + + std::string current_token_path = + BraveWalletPinService::GetPath(absl::nullopt, token); + known_tokens.erase(known_tokens.find(current_token_path)); + + mojom::TokenPinStatusPtr status = + brave_wallet_pin_service_->GetTokenStatus(absl::nullopt, token); + + if (!status || + status->code == mojom::TokenPinStatusCode::STATUS_NOT_PINNED) { + if (autopin_enabled) { + AddOrExecute( + std::make_unique(token, Operation::ADD, absl::nullopt)); + } + } else if (status->code == + mojom::TokenPinStatusCode::STATUS_PINNING_FAILED || + status->code == + mojom::TokenPinStatusCode::STATUS_PINNING_IN_PROGRESS || + status->code == + mojom::TokenPinStatusCode::STATUS_PINNING_PENDING) { + AddOrExecute( + std::make_unique(token, Operation::ADD, absl::nullopt)); + } else if (status->code == + mojom::TokenPinStatusCode::STATUS_UNPINNING_FAILED || + status->code == + mojom::TokenPinStatusCode::STATUS_UNPINNING_IN_PROGRESS || + status->code == + mojom::TokenPinStatusCode::STATUS_UNPINNING_PENDING) { + AddOrExecute(std::make_unique(token, Operation::DELETE, + absl::nullopt)); + } else if (status->code == mojom::TokenPinStatusCode::STATUS_PINNED) { + auto t1 = status->validate_time; + if (!t1 || (base::Time::Now() - t1.value()) > base::Days(1) || + t1.value() > base::Time::Now()) { + AddOrExecute(std::make_unique(token, Operation::VALIDATE, + absl::nullopt)); + } + } + } + + for (const auto& t : known_tokens) { + mojom::BlockchainTokenPtr token = BraveWalletPinService::TokenFromPath(t); + if (token) { + AddOrExecute(std::make_unique(token, Operation::DELETE, + absl::nullopt)); + } + } + + CheckQueue(); +} + +void BraveWalletAutoPinService::PostPinToken(BlockchainTokenPtr token, + PostPinTokenCallback callback) { + queue_.push_back( + std::make_unique(token, Operation::ADD, absl::nullopt)); + CheckQueue(); +} + +void BraveWalletAutoPinService::PostUnpinToken(BlockchainTokenPtr token, + PostPinTokenCallback callback) { + queue_.push_back( + std::make_unique(token, Operation::DELETE, absl::nullopt)); + CheckQueue(); +} + +void BraveWalletAutoPinService::ValidateToken( + const std::unique_ptr& data) { + brave_wallet_pin_service_->Validate( + data->token->Clone(), data->service, + base::BindOnce(&BraveWalletAutoPinService::OnValidateTaskFinished, + base::Unretained(this))); +} + +void BraveWalletAutoPinService::PinToken( + const std::unique_ptr& data) { + brave_wallet_pin_service_->AddPin( + data->token->Clone(), data->service, + base::BindOnce(&BraveWalletAutoPinService::OnTaskFinished, + base::Unretained(this))); +} + +void BraveWalletAutoPinService::UnpinToken( + const std::unique_ptr& data) { + brave_wallet_pin_service_->RemovePin( + data->token->Clone(), data->service, + base::BindOnce(&BraveWalletAutoPinService::OnTaskFinished, + base::Unretained(this))); +} + +void BraveWalletAutoPinService::AddOrExecute(std::unique_ptr data) { + DCHECK(data); + for (const auto& v : queue_) { + if (v->token == data->token && v->service == data->service) { + return; + } + } + if (current_ && current_->token == data->token && + current_->service == data->service) { + return; + } + if (data->operation == Operation::ADD) { + brave_wallet_pin_service_->MarkAsPendingForPinning(data->token, + data->service); + } else if (data->operation == Operation::DELETE) { + brave_wallet_pin_service_->MarkAsPendingForUnpinning(data->token, + data->service); + } + queue_.push_back(std::move(data)); + CheckQueue(); +} + +void BraveWalletAutoPinService::PostRetry(std::unique_ptr data) { + int multiply = ++data->attempt; + base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&BraveWalletAutoPinService::AddOrExecute, + base::Unretained(this), std::move(data)), + base::Minutes(1 * multiply)); +} + +void BraveWalletAutoPinService::CheckQueue() { + if (queue_.empty() || current_) { + return; + } + + current_ = std::move(queue_.front()); + queue_.pop_front(); + + if (current_->operation == Operation::ADD) { + PinToken(current_); + } else if (current_->operation == Operation::DELETE) { + UnpinToken(current_); + } else if (current_->operation == Operation::VALIDATE) { + ValidateToken(current_); + } +} + +void BraveWalletAutoPinService::OnTaskFinished(bool result, + mojom::PinErrorPtr error) { + CHECK(current_); + if (!result) { + PostRetry(std::move(current_)); + } + current_.reset(); + CheckQueue(); +} + +void BraveWalletAutoPinService::OnValidateTaskFinished( + bool result, + mojom::PinErrorPtr error) { + if (!result) { + AddOrExecute(std::make_unique(current_->token, Operation::ADD, + current_->service)); + } + current_.reset(); + CheckQueue(); +} + +void BraveWalletAutoPinService::SetAutoPinEnabled(bool enabled) { + pref_service_->SetBoolean(kAutoPinEnabled, enabled); + Restore(); +} + +bool BraveWalletAutoPinService::IsAutoPinEnabled() { + return pref_service_->GetBoolean(kAutoPinEnabled); +} + +void BraveWalletAutoPinService::IsAutoPinEnabled( + IsAutoPinEnabledCallback callback) { + std::move(callback).Run(IsAutoPinEnabled()); +} + +} // namespace brave_wallet diff --git a/components/brave_wallet/browser/brave_wallet_auto_pin_service.h b/components/brave_wallet/browser/brave_wallet_auto_pin_service.h new file mode 100644 index 000000000000..6fe28f592848 --- /dev/null +++ b/components/brave_wallet/browser/brave_wallet_auto_pin_service.h @@ -0,0 +1,105 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_BRAVE_WALLET_BROWSER_BRAVE_WALLET_AUTO_PIN_SERVICE_H_ +#define BRAVE_COMPONENTS_BRAVE_WALLET_BROWSER_BRAVE_WALLET_AUTO_PIN_SERVICE_H_ + +#include +#include +#include +#include +#include +#include + +#include "base/memory/scoped_refptr.h" +#include "base/task/sequenced_task_runner.h" +#include "brave/components/brave_wallet/browser/blockchain_registry.h" +#include "brave/components/brave_wallet/browser/brave_wallet_pin_service.h" +#include "brave/components/brave_wallet/browser/brave_wallet_service.h" +#include "brave/components/brave_wallet/common/brave_wallet.mojom.h" +#include "components/prefs/pref_service.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver_set.h" +#include "mojo/public/cpp/bindings/remote_set.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +using brave_wallet::mojom::BlockchainTokenPtr; + +namespace brave_wallet { + +enum Operation { ADD = 0, DELETE = 1, VALIDATE = 2 }; + +struct IntentData { + BlockchainTokenPtr token; + Operation operation; + absl::optional service; + size_t attempt = 0; + IntentData(const BlockchainTokenPtr& token, + Operation operation, + absl::optional service); + ~IntentData(); +}; + +class BraveWalletAutoPinService + : public KeyedService, + public brave_wallet::mojom::WalletAutoPinService, + public brave_wallet::mojom::BraveWalletServiceTokenObserver { + public: + BraveWalletAutoPinService(PrefService* prefs, + BraveWalletService* brave_wallet_service, + BraveWalletPinService* brave_wallet_pin_service); + ~BraveWalletAutoPinService() override; + + mojo::PendingRemote MakeRemote(); + void Bind(mojo::PendingReceiver receiver); + + void SetAutoPinEnabled(bool enabled) override; + void IsAutoPinEnabled(IsAutoPinEnabledCallback callback) override; + + void PostPinToken(BlockchainTokenPtr token, + PostPinTokenCallback callback) override; + void PostUnpinToken(BlockchainTokenPtr token, + PostUnpinTokenCallback callback) override; + + // BraveWalletServiceTokenObserver + void OnTokenAdded(mojom::BlockchainTokenPtr token) override; + void OnTokenRemoved(mojom::BlockchainTokenPtr token) override; + + private: + void Restore(); + void OnTokenListResolved(std::vector); + + void CheckQueue(); + void AddOrExecute(std::unique_ptr data); + void PostRetry(std::unique_ptr data); + + bool IsAutoPinEnabled(); + + std::vector> GetServicesToPin(); + std::vector> GetKnownServices(); + + void ValidateToken(const std::unique_ptr& data); + void PinToken(const std::unique_ptr& data); + void UnpinToken(const std::unique_ptr& data); + + void OnTaskFinished(bool result, mojom::PinErrorPtr error); + void OnValidateTaskFinished(bool result, mojom::PinErrorPtr error); + + mojo::Receiver + token_observer_{this}; + mojo::ReceiverSet receivers_; + + PrefService* pref_service_; + BraveWalletService* brave_wallet_service_; + BraveWalletPinService* brave_wallet_pin_service_; + + std::unique_ptr current_; + std::deque> queue_; +}; + +} // namespace brave_wallet + +#endif // BRAVE_COMPONENTS_BRAVE_WALLET_BROWSER_BRAVE_WALLET_AUTO_PIN_SERVICE_H_ diff --git a/components/brave_wallet/browser/brave_wallet_auto_pin_service_unittest.cc b/components/brave_wallet/browser/brave_wallet_auto_pin_service_unittest.cc new file mode 100644 index 000000000000..964e9a87f1dc --- /dev/null +++ b/components/brave_wallet/browser/brave_wallet_auto_pin_service_unittest.cc @@ -0,0 +1,514 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_wallet/browser/brave_wallet_auto_pin_service.h" + +#include +#include +#include +#include + +#include "base/test/bind.h" +#include "base/time/time_override.h" +#include "brave/components/brave_wallet/browser/brave_wallet_pin_service.h" +#include "brave/components/brave_wallet/browser/brave_wallet_prefs.h" +#include "brave/components/brave_wallet/browser/json_rpc_service.h" +#include "brave/components/brave_wallet/browser/pref_names.h" +#include "brave/components/brave_wallet/common/brave_wallet.mojom.h" +#include "brave/components/ipfs/pin/ipfs_local_pin_service.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/scoped_user_pref_update.h" +#include "components/prefs/testing_pref_service.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; + +namespace brave_wallet { + +class MockBraveWalletPinService : public BraveWalletPinService { + public: + MockBraveWalletPinService() + : BraveWalletPinService(nullptr, nullptr, nullptr) {} + MOCK_METHOD3(AddPin, + void(mojom::BlockchainTokenPtr, + const absl::optional&, + BraveWalletPinService::AddPinCallback callback)); + MOCK_METHOD3(RemovePin, + void(mojom::BlockchainTokenPtr, + const absl::optional&, + BraveWalletPinService::RemovePinCallback callback)); + MOCK_METHOD3(Validate, + void(mojom::BlockchainTokenPtr, + const absl::optional&, + BraveWalletPinService::ValidateCallback)); + MOCK_METHOD1(GetTokens, + std::set(const absl::optional&)); + MOCK_METHOD2(GetTokenStatus, + mojom::TokenPinStatusPtr(absl::optional, + const mojom::BlockchainTokenPtr&)); + MOCK_METHOD2(GetLastValidateTime, + absl::optional(absl::optional, + const mojom::BlockchainTokenPtr&)); + MOCK_METHOD2(MarkAsPendingForPinning, + void(const mojom::BlockchainTokenPtr&, + const absl::optional&)); + MOCK_METHOD2(MarkAsPendingForUnpinning, + void(const mojom::BlockchainTokenPtr&, + const absl::optional&)); +}; + +class MockBraveWalletService : public BraveWalletService { + public: + MOCK_METHOD3(GetUserAssets, + void(const std::string&, + mojom::CoinType, + BraveWalletService::GetUserAssetsCallback)); +}; + +MATCHER_P(TokenPathMatches, path, "") { + return arg == BraveWalletPinService::TokenFromPath(path); +} + +class BraveWalletAutoPinServiceTest : public testing::Test { + public: + BraveWalletAutoPinServiceTest() = default; + + BraveWalletAutoPinService* service() { + return brave_wallet_auto_pin_service_.get(); + } + + protected: + void SetUp() override { + auto* registry = pref_service_.registry(); + registry->RegisterBooleanPref(kAutoPinEnabled, false); + brave_wallet_auto_pin_service_ = + std::make_unique( + GetPrefs(), GetBraveWalletService(), GetBraveWalletPinService()); + } + + PrefService* GetPrefs() { return &pref_service_; } + + testing::NiceMock* GetBraveWalletPinService() { + return &brave_wallet_pin_service_; + } + + testing::NiceMock* GetBraveWalletService() { + return &brave_wallet_service_; + } + + void SetAutoPinEnabled(bool value) {} + + testing::NiceMock brave_wallet_pin_service_; + testing::NiceMock brave_wallet_service_; + + std::unique_ptr brave_wallet_auto_pin_service_; + + TestingPrefServiceSimple pref_service_; + content::BrowserTaskEnvironment task_environment_; +}; + +TEST_F(BraveWalletAutoPinServiceTest, Autopin_WhenTokenAdded) { + service()->SetAutoPinEnabled(true); + + ON_CALL(*GetBraveWalletPinService(), AddPin(_, _, _)) + .WillByDefault( + ::testing::Invoke([](BlockchainTokenPtr token, + const absl::optional& service, + BraveWalletPinService::AddPinCallback callback) { + std::move(callback).Run(true, nullptr); + })); + EXPECT_CALL(*GetBraveWalletPinService(), AddPin(_, _, _)).Times(3); + + { + mojom::BlockchainTokenPtr token = BraveWalletPinService::TokenFromPath( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1"); + service()->OnTokenAdded(std::move(token)); + } + + { + mojom::BlockchainTokenPtr token = BraveWalletPinService::TokenFromPath( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2"); + service()->OnTokenAdded(std::move(token)); + } + + { + mojom::BlockchainTokenPtr token = BraveWalletPinService::TokenFromPath( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x3"); + service()->OnTokenAdded(std::move(token)); + } +} + +TEST_F(BraveWalletAutoPinServiceTest, TokenRemoved) { + ON_CALL(*GetBraveWalletPinService(), AddPin(_, _, _)) + .WillByDefault( + ::testing::Invoke([](BlockchainTokenPtr token, + const absl::optional& service, + BraveWalletPinService::AddPinCallback callback) { + std::move(callback).Run(true, nullptr); + })); +} + +TEST_F(BraveWalletAutoPinServiceTest, UnpinUnknownTokens_WhenRestore) { + std::set known_tokens; + + known_tokens.insert( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1"); + known_tokens.insert( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2"); + known_tokens.insert( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x3"); + + ON_CALL(*GetBraveWalletPinService(), + GetTokenStatus(testing::Eq(absl::nullopt), _)) + .WillByDefault( + ::testing::Invoke([](absl::optional service, + const mojom::BlockchainTokenPtr& token) + -> mojom::TokenPinStatusPtr { + mojom::TokenPinStatusPtr status = mojom::TokenPinStatus::New(); + status->code = mojom::TokenPinStatusCode::STATUS_PINNED; + status->validate_time = base::Time::Now(); + return status; + })); + ON_CALL(*GetBraveWalletPinService(), GetTokens(_)) + .WillByDefault(::testing::Return(known_tokens)); + ON_CALL(*GetBraveWalletService(), GetUserAssets(_, _, _)) + .WillByDefault(::testing::Invoke([](const std::string& chain_id, + mojom::CoinType coin, + BraveWalletService:: + GetUserAssetsCallback callback) { + std::vector result; + result.push_back(BraveWalletPinService::TokenFromPath( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1")); + result.push_back(BraveWalletPinService::TokenFromPath( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2")); + std::move(callback).Run(std::move(result)); + })); + + EXPECT_CALL(*GetBraveWalletPinService(), + RemovePin(TokenPathMatches( + "nft.local.60.0x1." + "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x3"), + testing::Eq(absl::nullopt), _)) + .Times(1); + + BraveWalletAutoPinService auto_pin_service( + GetPrefs(), GetBraveWalletService(), GetBraveWalletPinService()); +} + +TEST_F(BraveWalletAutoPinServiceTest, ValidateOldTokens_WhenRestore) { + std::set known_tokens; + + known_tokens.insert( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1"); + known_tokens.insert( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2"); + known_tokens.insert( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x3"); + known_tokens.insert( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x4"); + ON_CALL(*GetBraveWalletPinService(), + GetTokenStatus(testing::Eq(absl::nullopt), _)) + .WillByDefault( + ::testing::Invoke([](absl::optional service, + const mojom::BlockchainTokenPtr& token) + -> mojom::TokenPinStatusPtr { + mojom::TokenPinStatusPtr status = mojom::TokenPinStatus::New(); + + if ("0x1" == token->token_id) { + status->code = mojom::TokenPinStatusCode::STATUS_PINNED; + status->validate_time = base::Time::Now() - base::Days(20); + } else if ("0x2" == token->token_id) { + status->code = mojom::TokenPinStatusCode::STATUS_PINNED; + } else if ("0x3" == token->token_id) { + status->code = mojom::TokenPinStatusCode::STATUS_PINNED; + status->validate_time = base::Time::Now() + base::Days(20); + } else if ("0x4" == token->token_id) { + status->code = mojom::TokenPinStatusCode::STATUS_NOT_PINNED; + } + return status; + })); + ON_CALL(*GetBraveWalletPinService(), GetTokens(_)) + .WillByDefault(::testing::Return(known_tokens)); + ON_CALL(*GetBraveWalletService(), GetUserAssets(_, _, _)) + .WillByDefault(::testing::Invoke([](const std::string& chain_id, + mojom::CoinType coin, + BraveWalletService:: + GetUserAssetsCallback callback) { + std::vector result; + result.push_back(BraveWalletPinService::TokenFromPath( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1")); + result.push_back(BraveWalletPinService::TokenFromPath( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2")); + result.push_back(BraveWalletPinService::TokenFromPath( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x3")); + result.push_back(BraveWalletPinService::TokenFromPath( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x4")); + std::move(callback).Run(std::move(result)); + })); + + ON_CALL(*GetBraveWalletPinService(), Validate(_, _, _)) + .WillByDefault(::testing::Invoke( + [](BlockchainTokenPtr token, + const absl::optional& service, + BraveWalletPinService::ValidateCallback callback) { + std::move(callback).Run(true, nullptr); + })); + + EXPECT_CALL(*GetBraveWalletPinService(), + Validate(TokenPathMatches( + "nft.local.60.0x1." + "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1"), + testing::Eq(absl::nullopt), _)) + .Times(1); + EXPECT_CALL(*GetBraveWalletPinService(), + Validate(TokenPathMatches( + "nft.local.60.0x1." + "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2"), + testing::Eq(absl::nullopt), _)) + .Times(1); + EXPECT_CALL(*GetBraveWalletPinService(), + Validate(TokenPathMatches( + "nft.local.60.0x1." + "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x3"), + testing::Eq(absl::nullopt), _)) + .Times(1); + EXPECT_CALL(*GetBraveWalletPinService(), + Validate(TokenPathMatches( + "nft.local.60.0x1." + "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x4"), + testing::Eq(absl::nullopt), _)) + .Times(0); + + BraveWalletAutoPinService auto_pin_service( + GetPrefs(), GetBraveWalletService(), GetBraveWalletPinService()); +} + +TEST_F(BraveWalletAutoPinServiceTest, PinContinue_WhenRestore) { + std::set known_tokens; + + known_tokens.insert( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1"); + known_tokens.insert( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2"); + known_tokens.insert( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x3"); + + ON_CALL(*GetBraveWalletPinService(), + GetTokenStatus(testing::Eq(absl::nullopt), _)) + .WillByDefault( + ::testing::Invoke([](absl::optional service, + const mojom::BlockchainTokenPtr& token) + -> mojom::TokenPinStatusPtr { + mojom::TokenPinStatusPtr status = mojom::TokenPinStatus::New(); + if ("0x1" == token->token_id) { + status->code = mojom::TokenPinStatusCode::STATUS_PINNING_FAILED; + } else if ("0x2" == token->token_id) { + status->code = + mojom::TokenPinStatusCode::STATUS_PINNING_IN_PROGRESS; + } else if ("0x3" == token->token_id) { + status->code = mojom::TokenPinStatusCode::STATUS_PINNING_PENDING; + } + return status; + })); + ON_CALL(*GetBraveWalletPinService(), GetTokens(_)) + .WillByDefault(::testing::Return(known_tokens)); + ON_CALL(*GetBraveWalletService(), GetUserAssets(_, _, _)) + .WillByDefault(::testing::Invoke([](const std::string& chain_id, + mojom::CoinType coin, + BraveWalletService:: + GetUserAssetsCallback callback) { + std::vector result; + result.push_back(BraveWalletPinService::TokenFromPath( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1")); + result.push_back(BraveWalletPinService::TokenFromPath( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2")); + result.push_back(BraveWalletPinService::TokenFromPath( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x3")); + std::move(callback).Run(std::move(result)); + })); + + ON_CALL(*GetBraveWalletPinService(), AddPin(_, _, _)) + .WillByDefault( + ::testing::Invoke([](BlockchainTokenPtr token, + const absl::optional& service, + BraveWalletPinService::AddPinCallback callback) { + std::move(callback).Run(true, nullptr); + })); + + EXPECT_CALL( + *GetBraveWalletPinService(), + AddPin(TokenPathMatches("nft.local.60.0x1." + "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1"), + testing::Eq(absl::nullopt), _)) + .Times(1); + EXPECT_CALL( + *GetBraveWalletPinService(), + AddPin(TokenPathMatches("nft.local.60.0x1." + "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2"), + testing::Eq(absl::nullopt), _)) + .Times(1); + EXPECT_CALL( + *GetBraveWalletPinService(), + AddPin(TokenPathMatches("nft.local.60.0x1." + "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x3"), + testing::Eq(absl::nullopt), _)) + .Times(1); + + BraveWalletAutoPinService auto_pin_service( + GetPrefs(), GetBraveWalletService(), GetBraveWalletPinService()); +} + +TEST_F(BraveWalletAutoPinServiceTest, UnpinContinue_WhenRestore) { + std::set known_tokens; + + known_tokens.insert( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1"); + known_tokens.insert( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2"); + known_tokens.insert( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x3"); + + ON_CALL(*GetBraveWalletPinService(), + GetTokenStatus(testing::Eq(absl::nullopt), _)) + .WillByDefault( + ::testing::Invoke([](absl::optional service, + const mojom::BlockchainTokenPtr& token) + -> mojom::TokenPinStatusPtr { + mojom::TokenPinStatusPtr status = mojom::TokenPinStatus::New(); + if ("0x1" == token->token_id) { + status->code = mojom::TokenPinStatusCode::STATUS_UNPINNING_FAILED; + } else if ("0x2" == token->token_id) { + status->code = + mojom::TokenPinStatusCode::STATUS_UNPINNING_IN_PROGRESS; + } else if ("0x3" == token->token_id) { + status->code = + mojom::TokenPinStatusCode::STATUS_UNPINNING_PENDING; + } + return status; + })); + ON_CALL(*GetBraveWalletPinService(), GetTokens(_)) + .WillByDefault(::testing::Return(known_tokens)); + ON_CALL(*GetBraveWalletService(), GetUserAssets(_, _, _)) + .WillByDefault(::testing::Invoke([](const std::string& chain_id, + mojom::CoinType coin, + BraveWalletService:: + GetUserAssetsCallback callback) { + std::vector result; + result.push_back(BraveWalletPinService::TokenFromPath( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1")); + result.push_back(BraveWalletPinService::TokenFromPath( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2")); + std::move(callback).Run(std::move(result)); + })); + + ON_CALL(*GetBraveWalletPinService(), RemovePin(_, _, _)) + .WillByDefault(::testing::Invoke( + [](BlockchainTokenPtr token, + const absl::optional& service, + BraveWalletPinService::RemovePinCallback callback) { + std::move(callback).Run(true, nullptr); + })); + + EXPECT_CALL(*GetBraveWalletPinService(), + RemovePin(TokenPathMatches( + "nft.local.60.0x1." + "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1"), + testing::Eq(absl::nullopt), _)) + .Times(1); + EXPECT_CALL(*GetBraveWalletPinService(), + RemovePin(TokenPathMatches( + "nft.local.60.0x1." + "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2"), + testing::Eq(absl::nullopt), _)) + .Times(1); + + BraveWalletAutoPinService auto_pin_service( + GetPrefs(), GetBraveWalletService(), GetBraveWalletPinService()); +} + +TEST_F(BraveWalletAutoPinServiceTest, DoNotAutoPin_WhenAutoPinDisabled) { + service()->SetAutoPinEnabled(false); + + ON_CALL(*GetBraveWalletPinService(), AddPin(_, _, _)) + .WillByDefault( + ::testing::Invoke([](BlockchainTokenPtr token, + const absl::optional& service, + BraveWalletPinService::AddPinCallback callback) { + std::move(callback).Run(true, nullptr); + })); + EXPECT_CALL(*GetBraveWalletPinService(), AddPin(_, _, _)).Times(0); + + { + mojom::BlockchainTokenPtr token = BraveWalletPinService::TokenFromPath( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1"); + service()->OnTokenAdded(std::move(token)); + } +} + +TEST_F(BraveWalletAutoPinServiceTest, PinOldTokens_WhenAutoPinEnabled) { + std::set known_tokens; + + known_tokens.insert( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1"); + known_tokens.insert( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2"); + + ON_CALL(*GetBraveWalletPinService(), + GetTokenStatus(testing::Eq(absl::nullopt), _)) + .WillByDefault( + ::testing::Invoke([](absl::optional service, + const mojom::BlockchainTokenPtr& token) + -> mojom::TokenPinStatusPtr { + mojom::TokenPinStatusPtr status = mojom::TokenPinStatus::New(); + if ("0x1" == token->token_id) { + return nullptr; + } else if ("0x2" == token->token_id) { + status->code = mojom::TokenPinStatusCode::STATUS_NOT_PINNED; + } + return status; + })); + ON_CALL(*GetBraveWalletPinService(), GetTokens(_)) + .WillByDefault(::testing::Return(known_tokens)); + ON_CALL(*GetBraveWalletService(), GetUserAssets(_, _, _)) + .WillByDefault(::testing::Invoke([](const std::string& chain_id, + mojom::CoinType coin, + BraveWalletService:: + GetUserAssetsCallback callback) { + std::vector result; + result.push_back(BraveWalletPinService::TokenFromPath( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1")); + result.push_back(BraveWalletPinService::TokenFromPath( + "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2")); + std::move(callback).Run(std::move(result)); + })); + + ON_CALL(*GetBraveWalletPinService(), AddPin(_, _, _)) + .WillByDefault( + ::testing::Invoke([](BlockchainTokenPtr token, + const absl::optional& service, + BraveWalletPinService::AddPinCallback callback) { + std::move(callback).Run(true, nullptr); + })); + + EXPECT_CALL( + *GetBraveWalletPinService(), + AddPin(TokenPathMatches("nft.local.60.0x1." + "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1"), + testing::Eq(absl::nullopt), _)) + .Times(1); + EXPECT_CALL( + *GetBraveWalletPinService(), + AddPin(TokenPathMatches("nft.local.60.0x1." + "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2"), + testing::Eq(absl::nullopt), _)) + .Times(1); + + BraveWalletAutoPinService auto_pin_service( + GetPrefs(), GetBraveWalletService(), GetBraveWalletPinService()); +} + +} // namespace brave_wallet From 478a82bbd4b869fede5a0db7abc1cf25cfa4a676 Mon Sep 17 00:00:00 2001 From: oisupov Date: Fri, 2 Dec 2022 20:36:52 +0400 Subject: [PATCH 05/15] Add bindings to WebUI --- browser/ui/webui/brave_wallet/wallet_page_ui.cc | 13 ++++++++++++- browser/ui/webui/brave_wallet/wallet_page_ui.h | 6 +++++- .../common/actions/wallet_actions.ts | 3 ++- .../brave_wallet_ui/common/slices/wallet.slice.ts | 3 ++- .../brave_wallet_ui/common/wallet_api_proxy.ts | 10 ++++++++++ components/brave_wallet_ui/constants/types.ts | 1 + .../page/actions/wallet_page_actions.ts | 4 +++- .../page/async/wallet_page_async_handler.ts | 11 +++++++++++ .../brave_wallet_ui/page/reducers/page_reducer.ts | 9 ++++++++- .../page/selectors/page-selectors.ts | 1 + components/brave_wallet_ui/page/store.ts | 1 + .../brave_wallet_ui/page/wallet_page_api_proxy.ts | 4 +++- 12 files changed, 59 insertions(+), 7 deletions(-) diff --git a/browser/ui/webui/brave_wallet/wallet_page_ui.cc b/browser/ui/webui/brave_wallet/wallet_page_ui.cc index 6b9648688689..414d7e22c789 100644 --- a/browser/ui/webui/brave_wallet/wallet_page_ui.cc +++ b/browser/ui/webui/brave_wallet/wallet_page_ui.cc @@ -11,6 +11,8 @@ #include "base/command_line.h" #include "base/files/file_path.h" #include "brave/browser/brave_wallet/asset_ratio_service_factory.h" +#include "brave/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h" +#include "brave/browser/brave_wallet/brave_wallet_pin_service_factory.h" #include "brave/browser/brave_wallet/brave_wallet_service_factory.h" #include "brave/browser/brave_wallet/json_rpc_service_factory.h" #include "brave/browser/brave_wallet/keyring_service_factory.h" @@ -21,6 +23,7 @@ #include "brave/components/brave_wallet/browser/asset_ratio_service.h" #include "brave/components/brave_wallet/browser/blockchain_registry.h" #include "brave/components/brave_wallet/browser/brave_wallet_constants.h" +#include "brave/components/brave_wallet/browser/brave_wallet_pin_service.h" #include "brave/components/brave_wallet/browser/brave_wallet_service.h" #include "brave/components/brave_wallet/browser/json_rpc_service.h" #include "brave/components/brave_wallet/browser/keyring_service.h" @@ -111,7 +114,11 @@ void WalletPageUI::CreatePageHandler( mojo::PendingReceiver brave_wallet_service_receiver, mojo::PendingReceiver - brave_wallet_p3a_receiver) { + brave_wallet_p3a_receiver, + mojo::PendingReceiver + brave_wallet_pin_service_receiver, + mojo::PendingReceiver + brave_wallet_auto_pin_service_receiver) { DCHECK(page); auto* profile = Profile::FromWebUI(web_ui()); DCHECK(profile); @@ -142,6 +149,10 @@ void WalletPageUI::CreatePageHandler( wallet_service->Bind(std::move(brave_wallet_service_receiver)); wallet_service->GetBraveWalletP3A()->Bind( std::move(brave_wallet_p3a_receiver)); + brave_wallet::BraveWalletPinServiceFactory::BindForContext( + profile, std::move(brave_wallet_pin_service_receiver)); + brave_wallet::BraveWalletAutoPinServiceFactory::BindForContext( + profile, std::move(brave_wallet_auto_pin_service_receiver)); auto* blockchain_registry = brave_wallet::BlockchainRegistry::GetInstance(); if (blockchain_registry) { diff --git a/browser/ui/webui/brave_wallet/wallet_page_ui.h b/browser/ui/webui/brave_wallet/wallet_page_ui.h index f197e15aef5f..2d6895d31f87 100644 --- a/browser/ui/webui/brave_wallet/wallet_page_ui.h +++ b/browser/ui/webui/brave_wallet/wallet_page_ui.h @@ -58,7 +58,11 @@ class WalletPageUI : public ui::MojoWebUIController, mojo::PendingReceiver brave_wallet_service, mojo::PendingReceiver - brave_wallet_p3a) override; + brave_wallet_p3a, + mojo::PendingReceiver + brave_wallet_pin_service_receiver, + mojo::PendingReceiver + brave_wallet_auto_pin_service_receiver) override; std::unique_ptr page_handler_; std::unique_ptr wallet_handler_; diff --git a/components/brave_wallet_ui/common/actions/wallet_actions.ts b/components/brave_wallet_ui/common/actions/wallet_actions.ts index 9383e1826d0e..d8dac2598734 100644 --- a/components/brave_wallet_ui/common/actions/wallet_actions.ts +++ b/components/brave_wallet_ui/common/actions/wallet_actions.ts @@ -97,5 +97,6 @@ unlocked, updateUnapprovedTransactionGasFields, updateUnapprovedTransactionNonce, - updateUnapprovedTransactionSpendAllowance + updateUnapprovedTransactionSpendAllowance, + updateTokenPinStatus } = WalletActions diff --git a/components/brave_wallet_ui/common/slices/wallet.slice.ts b/components/brave_wallet_ui/common/slices/wallet.slice.ts index dc8420081358..2620057dfb8d 100644 --- a/components/brave_wallet_ui/common/slices/wallet.slice.ts +++ b/components/brave_wallet_ui/common/slices/wallet.slice.ts @@ -235,7 +235,8 @@ export const WalletAsyncActions = { addFilecoinAccount: createAction('addFilecoinAccount'), getOnRampCurrencies: createAction('getOnRampCurrencies'), - autoLockMinutesChanged: createAction('autoLockMinutesChanged') // No reducer or API logic for this (UNUSED) + autoLockMinutesChanged: createAction('autoLockMinutesChanged'), // No reducer or API logic for this (UNUSED) + updateTokenPinStatus: createAction('updateTokenPinStatus') } // slice diff --git a/components/brave_wallet_ui/common/wallet_api_proxy.ts b/components/brave_wallet_ui/common/wallet_api_proxy.ts index d384a05271ec..0efd69716206 100644 --- a/components/brave_wallet_ui/common/wallet_api_proxy.ts +++ b/components/brave_wallet_ui/common/wallet_api_proxy.ts @@ -24,6 +24,8 @@ export class WalletApiProxy { filTxManagerProxy = new BraveWallet.FilTxManagerProxyRemote() braveWalletService = new BraveWallet.BraveWalletServiceRemote() braveWalletP3A = new BraveWallet.BraveWalletP3ARemote() + braveWalletPinService = new BraveWallet.WalletPinServiceRemote() + braveWalletAutoPinService = new BraveWallet.WalletAutoPinServiceRemote() addJsonRpcServiceObserver (store: Store) { const jsonRpcServiceObserverReceiver = new BraveWallet.JsonRpcServiceObserverReceiver({ @@ -127,6 +129,14 @@ export class WalletApiProxy { }) this.braveWalletService.addObserver(braveWalletServiceObserverReceiver.$.bindNewPipeAndPassRemote()) } + + addBraveWalletPinServiceObserver (store: Store) { + const braveWalletServiceObserverReceiver = new BraveWallet.BraveWalletPinServiceObserverReceiver({ + onTokenStatusChanged: function (service, token, status) { + } + }) + this.braveWalletPinService.addObserver(braveWalletServiceObserverReceiver.$.bindNewPipeAndPassRemote()) + } } export default WalletApiProxy diff --git a/components/brave_wallet_ui/constants/types.ts b/components/brave_wallet_ui/constants/types.ts index 5a64d0cc2529..678c5d9212a8 100644 --- a/components/brave_wallet_ui/constants/types.ts +++ b/components/brave_wallet_ui/constants/types.ts @@ -295,6 +295,7 @@ export interface PageState { isFetchingNFTMetadata: boolean nftMetadata: NFTMetadataReturnType | undefined nftMetadataError: string | undefined + pinStatusOverview: BraveWallet.TokenPinOverview | undefined selectedAssetFiatPrice: BraveWallet.AssetPrice | undefined selectedAssetCryptoPrice: BraveWallet.AssetPrice | undefined selectedAssetPriceHistory: GetPriceHistoryReturnInfo[] diff --git a/components/brave_wallet_ui/page/actions/wallet_page_actions.ts b/components/brave_wallet_ui/page/actions/wallet_page_actions.ts index 19407bb0cd7d..a42726d3addb 100644 --- a/components/brave_wallet_ui/page/actions/wallet_page_actions.ts +++ b/components/brave_wallet_ui/page/actions/wallet_page_actions.ts @@ -42,5 +42,7 @@ export const { updateSelectedAsset, walletBackupComplete, walletCreated, - walletSetupComplete + walletSetupComplete, + updateNFTPinStatus, + getPinStatus } = PageActions diff --git a/components/brave_wallet_ui/page/async/wallet_page_async_handler.ts b/components/brave_wallet_ui/page/async/wallet_page_async_handler.ts index b23ff2d5760f..2860e40a13cf 100644 --- a/components/brave_wallet_ui/page/async/wallet_page_async_handler.ts +++ b/components/brave_wallet_ui/page/async/wallet_page_async_handler.ts @@ -144,6 +144,7 @@ handler.on(WalletPageActions.selectAsset.type, async (store: Store, payload: Upd if (payload.asset.isErc721 || payload.asset.isNft) { store.dispatch(WalletPageActions.getNFTMetadata(payload.asset)) + store.dispatch(WalletPageActions.getPinStatus(payload.asset)) } } else { store.dispatch(WalletPageActions.updatePriceInfo({ priceHistory: undefined, defaultFiatPrice: undefined, defaultCryptoPrice: undefined, timeFrame: payload.timeFrame })) @@ -308,4 +309,14 @@ handler.on(WalletPageActions.getNFTMetadata.type, async (store, payload: BraveWa store.dispatch(WalletPageActions.setIsFetchingNFTMetadata(false)) }) +handler.on(WalletPageActions.getPinStatus.type, async (store, payload: BraveWallet.BlockchainToken) => { + const braveWalletPinService = getWalletPageApiProxy().braveWalletPinService + const result = await braveWalletPinService.getTokenStatus(payload) + if (result.status) { + store.dispatch(WalletPageActions.updateNFTPinStatus(result.status)) + } else { + store.dispatch(WalletPageActions.updateNFTPinStatus(undefined)) + } +}) + export default handler.middleware diff --git a/components/brave_wallet_ui/page/reducers/page_reducer.ts b/components/brave_wallet_ui/page/reducers/page_reducer.ts index 861009666e11..82b582b0e2a1 100644 --- a/components/brave_wallet_ui/page/reducers/page_reducer.ts +++ b/components/brave_wallet_ui/page/reducers/page_reducer.ts @@ -41,6 +41,7 @@ const defaultState: PageState = { isFetchingNFTMetadata: true, nftMetadata: undefined, nftMetadataError: undefined, + pinStatusOverview: undefined, selectedAssetFiatPrice: undefined, selectedAssetCryptoPrice: undefined, selectedAssetPriceHistory: [], @@ -71,7 +72,9 @@ export const WalletPageAsyncActions = { removeImportedAccount: createAction('removeImportedAccount'), restoreWallet: createAction('restoreWallet'), selectAsset: createAction('selectAsset'), - updateAccountName: createAction('updateAccountName') + updateAccountName: createAction('updateAccountName'), + updateNFTPinStatus: createAction('updateNFTPinStatus'), + getPinStatus: createAction('getPinStatus') } export const createPageSlice = (initialState: PageState = defaultState) => { @@ -177,6 +180,10 @@ export const createPageSlice = (initialState: PageState = defaultState) => { // complete setup unless explicitly halted state.setupStillInProgress = !action?.payload state.mnemonic = undefined + }, + + updateNFTPinStatus (state, { payload }: PayloadAction) { + state.pinStatusOverview = payload } } }) diff --git a/components/brave_wallet_ui/page/selectors/page-selectors.ts b/components/brave_wallet_ui/page/selectors/page-selectors.ts index 5c9fd2889bc5..c5d4ce147dfb 100644 --- a/components/brave_wallet_ui/page/selectors/page-selectors.ts +++ b/components/brave_wallet_ui/page/selectors/page-selectors.ts @@ -33,6 +33,7 @@ export const nftMetadataError = ({ page }: State) => page.nftMetadataError export const portfolioPriceHistory = ({ page }: State) => page.portfolioPriceHistory export const selectedAsset = ({ page }: State) => page?.selectedAsset +export const pinStatusOverview = ({ page }: State) => page.pinStatusOverview export const selectedAssetCryptoPrice = ({ page }: State) => page.selectedAssetCryptoPrice export const selectedAssetFiatPrice = ({ page }: State) => page.selectedAssetFiatPrice export const selectedAssetPriceHistory = ({ page }: State) => page.selectedAssetPriceHistory diff --git a/components/brave_wallet_ui/page/store.ts b/components/brave_wallet_ui/page/store.ts index 46d0137cb1d3..1df99c1f0c7b 100644 --- a/components/brave_wallet_ui/page/store.ts +++ b/components/brave_wallet_ui/page/store.ts @@ -42,6 +42,7 @@ proxy.addJsonRpcServiceObserver(store) proxy.addKeyringServiceObserver(store) proxy.addTxServiceObserver(store) proxy.addBraveWalletServiceObserver(store) +proxy.addBraveWalletPinServiceObserver(store) export const walletPageApiProxy = proxy diff --git a/components/brave_wallet_ui/page/wallet_page_api_proxy.ts b/components/brave_wallet_ui/page/wallet_page_api_proxy.ts index 09d4ec92e596..6a870a905106 100644 --- a/components/brave_wallet_ui/page/wallet_page_api_proxy.ts +++ b/components/brave_wallet_ui/page/wallet_page_api_proxy.ts @@ -29,7 +29,9 @@ class WalletPageApiProxy extends WalletApiProxy { this.solanaTxManagerProxy.$.bindNewPipeAndPassReceiver(), this.filTxManagerProxy.$.bindNewPipeAndPassReceiver(), this.braveWalletService.$.bindNewPipeAndPassReceiver(), - this.braveWalletP3A.$.bindNewPipeAndPassReceiver()) + this.braveWalletP3A.$.bindNewPipeAndPassReceiver(), + this.braveWalletPinService.$.bindNewPipeAndPassReceiver(), + this.braveWalletAutoPinService.$.bindNewPipeAndPassReceiver()) } } From e1e751745efed871bce653158404bfdf4d89e303 Mon Sep 17 00:00:00 2001 From: oisupov Date: Sat, 3 Dec 2022 02:20:01 +0400 Subject: [PATCH 06/15] Fix build --- components/brave_wallet/browser/brave_wallet_service.cc | 2 +- components/brave_wallet/browser/brave_wallet_service.h | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/components/brave_wallet/browser/brave_wallet_service.cc b/components/brave_wallet/browser/brave_wallet_service.cc index f264e51fd9aa..91f6998e95d3 100644 --- a/components/brave_wallet/browser/brave_wallet_service.cc +++ b/components/brave_wallet/browser/brave_wallet_service.cc @@ -1413,7 +1413,7 @@ void BraveWalletService::DiscoverAssetsOnAllSupportedChains() { addresses[mojom::CoinType::SOL] = std::move(sol_account_addresses); // Discover assets owned by the SOL and ETH addresses on all supported chains - asset_discovery_manager_.DiscoverAssetsOnAllSupportedChainsRefresh(addresses); + asset_discovery_manager_->DiscoverAssetsOnAllSupportedChainsRefresh(addresses); } void BraveWalletService::CancelAllSuggestedTokenCallbacks() { diff --git a/components/brave_wallet/browser/brave_wallet_service.h b/components/brave_wallet/browser/brave_wallet_service.h index 36f9284e9599..01164d08c316 100644 --- a/components/brave_wallet/browser/brave_wallet_service.h +++ b/components/brave_wallet/browser/brave_wallet_service.h @@ -233,6 +233,10 @@ class BraveWalletService : public KeyedService, BraveWalletP3A* GetBraveWalletP3A(); + protected: + // For tests + BraveWalletService(); + private: friend class EthereumProviderImplUnitTest; friend class SolanaProviderImplUnitTest; @@ -319,7 +323,7 @@ class BraveWalletService : public KeyedService, raw_ptr tx_service_ = nullptr; raw_ptr profile_prefs_ = nullptr; BraveWalletP3A brave_wallet_p3a_; - AssetDiscoveryManager asset_discovery_manager_; + std::unique_ptr asset_discovery_manager_; mojo::ReceiverSet receivers_; PrefChangeRegistrar pref_change_registrar_; base::WeakPtrFactory weak_ptr_factory_; From 46940d263bb44131789efcf6c558711f57433df5 Mon Sep 17 00:00:00 2001 From: oisupov Date: Fri, 16 Dec 2022 19:40:58 +0400 Subject: [PATCH 07/15] Fix build --- .../brave_wallet_pin_service_unittest.cc | 6 +++--- .../browser/brave_wallet_service.cc | 12 +++++++----- .../brave_wallet/browser/brave_wallet_service.h | 2 -- .../browser/nft_metadata_fetcher.cc | 17 +++++++++-------- .../brave_wallet/browser/nft_metadata_fetcher.h | 4 +++- .../browser/nft_metadata_fetcher_unittest.cc | 3 ++- components/ipfs/pin/ipfs_base_pin_service.cc | 6 +++--- 7 files changed, 27 insertions(+), 23 deletions(-) diff --git a/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc b/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc index ccf5d9fc447b..130042976b0c 100644 --- a/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc +++ b/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc @@ -83,7 +83,7 @@ class MockJsonRpcService : public JsonRpcService { void(const std::string& contract_address, const std::string& token_id, const std::string& chain_id, - GetTokenMetadataCallback callback)); + GetERC721MetadataCallback callback)); ~MockJsonRpcService() override {} }; @@ -126,7 +126,7 @@ TEST_F(BraveWalletPinServiceTest, AddPin) { .WillByDefault(::testing::Invoke( [](const std::string& contract_address, const std::string& token_id, const std::string& chain_id, - MockJsonRpcService::GetTokenMetadataCallback callback) { + MockJsonRpcService::GetERC721MetadataCallback callback) { EXPECT_EQ("0x1", chain_id); EXPECT_EQ("0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", contract_address); @@ -183,7 +183,7 @@ TEST_F(BraveWalletPinServiceTest, AddPin) { .WillByDefault(::testing::Invoke( [](const std::string& contract_address, const std::string& token_id, const std::string& chain_id, - MockJsonRpcService::GetTokenMetadataCallback callback) { + MockJsonRpcService::GetERC721MetadataCallback callback) { EXPECT_EQ("0x1", chain_id); EXPECT_EQ("0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", contract_address); diff --git a/components/brave_wallet/browser/brave_wallet_service.cc b/components/brave_wallet/browser/brave_wallet_service.cc index 91f6998e95d3..6cf01ef42ffe 100644 --- a/components/brave_wallet/browser/brave_wallet_service.cc +++ b/components/brave_wallet/browser/brave_wallet_service.cc @@ -162,10 +162,11 @@ BraveWalletService::BraveWalletService( tx_service_(tx_service), profile_prefs_(profile_prefs), brave_wallet_p3a_(this, keyring_service, profile_prefs, local_state), - asset_discovery_manager_(this, - json_rpc_service, - keyring_service, - profile_prefs), + asset_discovery_manager_( + std::make_unique(this, + json_rpc_service, + keyring_service, + profile_prefs)), weak_ptr_factory_(this) { if (delegate_) delegate_->AddObserver(this); @@ -377,7 +378,8 @@ void BraveWalletService::GetUserAssets(const std::string& chain_id, bool BraveWalletService::AddUserAsset(mojom::BlockchainTokenPtr token) { mojom::BlockchainTokenPtr clone = token.Clone(); - bool result = BraveWalletService::AddUserAsset(std::move(token), profile_prefs_); + bool result = + BraveWalletService::AddUserAsset(std::move(token), profile_prefs_); if (result) { for (const auto& observer : token_observers_) { diff --git a/components/brave_wallet/browser/brave_wallet_service.h b/components/brave_wallet/browser/brave_wallet_service.h index 01164d08c316..93c32a0a1575 100644 --- a/components/brave_wallet/browser/brave_wallet_service.h +++ b/components/brave_wallet/browser/brave_wallet_service.h @@ -67,8 +67,6 @@ class BraveWalletService : public KeyedService, PrefService* profile_prefs, PrefService* local_state); - // For tests - BraveWalletService(); ~BraveWalletService() override; BraveWalletService(const BraveWalletService&) = delete; diff --git a/components/brave_wallet/browser/nft_metadata_fetcher.cc b/components/brave_wallet/browser/nft_metadata_fetcher.cc index f59ba33a9c73..76f69c953df4 100644 --- a/components/brave_wallet/browser/nft_metadata_fetcher.cc +++ b/components/brave_wallet/browser/nft_metadata_fetcher.cc @@ -94,14 +94,14 @@ void NftMetadataFetcher::GetEthTokenMetadata( auto network_url = GetNetworkURL(prefs_, chain_id, mojom::CoinType::ETH); if (!network_url.is_valid()) { std::move(callback).Run( - "", mojom::ProviderError::kInvalidParams, + "", "", mojom::ProviderError::kInvalidParams, l10n_util::GetStringUTF8(IDS_WALLET_INVALID_PARAMETERS)); return; } if (!EthAddress::IsValidAddress(contract_address)) { std::move(callback).Run( - "", mojom::ProviderError::kInvalidParams, + "", "", mojom::ProviderError::kInvalidParams, l10n_util::GetStringUTF8(IDS_WALLET_INVALID_PARAMETERS)); return; } @@ -125,13 +125,13 @@ void NftMetadataFetcher::OnGetSupportsInterface( mojom::ProviderError error, const std::string& error_message) { if (error != mojom::ProviderError::kSuccess) { - std::move(callback).Run("", error, error_message); + std::move(callback).Run("", "", error, error_message); return; } if (!is_supported) { std::move(callback).Run( - "", mojom::ProviderError::kMethodNotSupported, + "", "", mojom::ProviderError::kMethodNotSupported, l10n_util::GetStringUTF8(IDS_WALLET_METHOD_NOT_SUPPORTED_ERROR)); return; } @@ -149,20 +149,20 @@ void NftMetadataFetcher::OnGetEthTokenUri(GetEthTokenMetadataCallback callback, mojom::ProviderError error, const std::string& error_message) { if (error != mojom::ProviderError::kSuccess) { - std::move(callback).Run("", error, error_message); + std::move(callback).Run("", "", error, error_message); return; } if (!uri.is_valid()) { std::move(callback).Run( - "", mojom::ProviderError::kInternalError, + "", "", mojom::ProviderError::kInternalError, l10n_util::GetStringUTF8(IDS_WALLET_INTERNAL_ERROR)); return; } auto internal_callback = base::BindOnce(&NftMetadataFetcher::CompleteGetEthTokenMetadata, - weak_ptr_factory_.GetWeakPtr(), std::move(callback)); + weak_ptr_factory_.GetWeakPtr(), std::move(callback), uri); FetchMetadata(uri, std::move(internal_callback)); } @@ -263,13 +263,14 @@ void NftMetadataFetcher::OnGetTokenMetadataPayload( void NftMetadataFetcher::CompleteGetEthTokenMetadata( GetEthTokenMetadataCallback callback, + const GURL& uri, const std::string& response, int error, const std::string& error_message) { mojom::ProviderError mojo_err = static_cast(error); if (!mojom::IsKnownEnumValue(mojo_err)) mojo_err = mojom::ProviderError::kUnknown; - std::move(callback).Run(response, mojo_err, error_message); + std::move(callback).Run(uri.spec(), response, mojo_err, error_message); } void NftMetadataFetcher::GetSolTokenMetadata( diff --git a/components/brave_wallet/browser/nft_metadata_fetcher.h b/components/brave_wallet/browser/nft_metadata_fetcher.h index 2f5bde01eabf..56c74f48d93a 100644 --- a/components/brave_wallet/browser/nft_metadata_fetcher.h +++ b/components/brave_wallet/browser/nft_metadata_fetcher.h @@ -36,7 +36,8 @@ class NftMetadataFetcher { using APIRequestHelper = api_request_helper::APIRequestHelper; using APIRequestResult = api_request_helper::APIRequestResult; using GetEthTokenMetadataCallback = - base::OnceCallback; void GetEthTokenMetadata(const std::string& contract_address, @@ -83,6 +84,7 @@ class NftMetadataFetcher { mojom::SolanaProviderError error, const std::string& error_message); void CompleteGetEthTokenMetadata(GetEthTokenMetadataCallback callback, + const GURL& uri, const std::string& response, int error, const std::string& error_message); diff --git a/components/brave_wallet/browser/nft_metadata_fetcher_unittest.cc b/components/brave_wallet/browser/nft_metadata_fetcher_unittest.cc index 62e003a29770..058711612b2c 100644 --- a/components/brave_wallet/browser/nft_metadata_fetcher_unittest.cc +++ b/components/brave_wallet/browser/nft_metadata_fetcher_unittest.cc @@ -148,7 +148,8 @@ class NftMetadataFetcherUnitTest : public testing::Test { base::RunLoop run_loop; nft_metadata_fetcher_->GetEthTokenMetadata( contract, token_id, chain_id, interface_id, - base::BindLambdaForTesting([&](const std::string& response, + base::BindLambdaForTesting([&](const std::string& url, + const std::string& response, mojom::ProviderError error, const std::string& error_message) { CompareJSON(response, expected_response); diff --git a/components/ipfs/pin/ipfs_base_pin_service.cc b/components/ipfs/pin/ipfs_base_pin_service.cc index 50618cfaeb94..59f6f78825c7 100644 --- a/components/ipfs/pin/ipfs_base_pin_service.cc +++ b/components/ipfs/pin/ipfs_base_pin_service.cc @@ -84,9 +84,9 @@ void IpfsBasePinService::MaybeStartDaemon() { return; } - if (!ipfs::IsLocalGatewayConfigured(pref_service_)) { - return; - } +// if (!ipfs::IsLocalGatewayConfigured(pref_service_)) { +// return; +// } ipfs_service_->StartDaemonAndLaunch(base::BindOnce( &IpfsBasePinService::OnDaemonStarted, base::Unretained(this))); From 2397d3eeef7345256106d3b56347e3b13d80a6b1 Mon Sep 17 00:00:00 2001 From: oisupov Date: Wed, 21 Dec 2022 01:00:00 +0400 Subject: [PATCH 08/15] Build&review fix --- browser/brave_wallet/BUILD.gn | 5 + .../brave_wallet_auto_pin_service_factory.cc | 13 +- .../brave_wallet_auto_pin_service_factory.h | 8 +- .../brave_wallet_pin_service_factory.cc | 15 ++- .../brave_wallet_pin_service_factory.h | 9 +- ...browser_context_keyed_service_factories.cc | 4 + .../ipfs/ipfs_local_pin_service_factory.cc | 8 +- browser/ipfs/ipfs_local_pin_service_factory.h | 8 +- browser/profiles/brave_profile_manager.cc | 6 +- .../ui/webui/brave_wallet/wallet_page_ui.cc | 10 +- .../browser/brave_wallet_auto_pin_service.cc | 80 +++++++----- .../browser/brave_wallet_auto_pin_service.h | 18 +-- .../brave_wallet_auto_pin_service_unittest.cc | 60 +++++---- .../browser/brave_wallet_pin_service.cc | 121 ++++++++++-------- .../browser/brave_wallet_pin_service.h | 27 ++-- .../brave_wallet_pin_service_unittest.cc | 62 +++++---- .../browser/brave_wallet_service.cc | 35 +++++ .../browser/brave_wallet_service.h | 3 + .../browser/brave_wallet_utils.cc | 25 ++++ .../brave_wallet/browser/brave_wallet_utils.h | 8 ++ .../brave_wallet/browser/json_rpc_service.h | 1 + .../browser/nft_metadata_fetcher_unittest.cc | 17 ++- .../brave_wallet/common/brave_wallet.mojom | 25 ++-- .../stories/mock-data/mock-page-state.ts | 1 + components/ipfs/BUILD.gn | 5 + components/ipfs/ipfs_json_parser.cc | 110 +++++++--------- components/ipfs/ipfs_json_parser.h | 13 +- components/ipfs/ipfs_json_parser_unittest.cc | 100 ++++++++------- components/ipfs/ipfs_service.cc | 84 +++++------- components/ipfs/ipfs_service.h | 7 +- components/ipfs/pin/ipfs_base_pin_service.cc | 28 ++-- components/ipfs/pin/ipfs_base_pin_service.h | 13 +- .../pin/ipfs_base_pin_service_unittest.cc | 28 +--- components/ipfs/pin/ipfs_local_pin_service.cc | 83 ++++++------ components/ipfs/pin/ipfs_local_pin_service.h | 40 +++--- .../pin/ipfs_local_pin_service_unittest.cc | 36 +++--- components/ipfs/pin/ipfs_pin_rpc_types.cc | 14 +- components/ipfs/pin/ipfs_pin_rpc_types.h | 11 +- 38 files changed, 624 insertions(+), 517 deletions(-) diff --git a/browser/brave_wallet/BUILD.gn b/browser/brave_wallet/BUILD.gn index b4efee0a4179..55b6c6a23415 100644 --- a/browser/brave_wallet/BUILD.gn +++ b/browser/brave_wallet/BUILD.gn @@ -1,3 +1,8 @@ +# Copyright (c) 2022 The Brave Authors. All rights reserved. +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at https://mozilla.org/MPL/2.0/. + import("//brave/browser/ethereum_remote_client/buildflags/buildflags.gni") import("//extensions/buildflags/buildflags.gni") import("//testing/test.gni") diff --git a/browser/brave_wallet/brave_wallet_auto_pin_service_factory.cc b/browser/brave_wallet/brave_wallet_auto_pin_service_factory.cc index f7d3a9dc6ac0..d2459dd51bff 100644 --- a/browser/brave_wallet/brave_wallet_auto_pin_service_factory.cc +++ b/browser/brave_wallet/brave_wallet_auto_pin_service_factory.cc @@ -1,7 +1,7 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #include "brave/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h" @@ -12,6 +12,8 @@ #include "brave/browser/brave_wallet/brave_wallet_pin_service_factory.h" #include "brave/browser/brave_wallet/brave_wallet_service_factory.h" +// TODO(cypt4) : Refactor brave/browser into separate component (#27486) +#include "brave/browser/ipfs/ipfs_service_factory.h" // nogncheck #include "brave/components/brave_wallet/browser/brave_wallet_pin_service.h" #include "brave/components/brave_wallet/browser/brave_wallet_service.h" @@ -46,6 +48,9 @@ BraveWalletAutoPinServiceFactory::GetServiceForContext( if (!IsAllowedForContext(context)) { return nullptr; } + if (!ipfs::IpfsServiceFactory::IsIpfsEnabled(context)) { + return nullptr; + } return static_cast( GetInstance()->GetServiceForBrowserContext(context, true)); } diff --git a/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h b/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h index 0d1ea5ae7832..f35a8d3c4aea 100644 --- a/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h +++ b/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h @@ -1,7 +1,7 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #ifndef BRAVE_BROWSER_BRAVE_WALLET_BRAVE_WALLET_AUTO_PIN_SERVICE_FACTORY_H_ #define BRAVE_BROWSER_BRAVE_WALLET_BRAVE_WALLET_AUTO_PIN_SERVICE_FACTORY_H_ diff --git a/browser/brave_wallet/brave_wallet_pin_service_factory.cc b/browser/brave_wallet/brave_wallet_pin_service_factory.cc index 51d92f7e1d01..bb47ffe5294f 100644 --- a/browser/brave_wallet/brave_wallet_pin_service_factory.cc +++ b/browser/brave_wallet/brave_wallet_pin_service_factory.cc @@ -1,7 +1,7 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #include "brave/browser/brave_wallet/brave_wallet_pin_service_factory.h" @@ -10,7 +10,9 @@ #include "brave/browser/brave_wallet/brave_wallet_context_utils.h" #include "brave/browser/brave_wallet/json_rpc_service_factory.h" -#include "brave/browser/ipfs/ipfs_local_pin_service_factory.h" +// TODO(cypt4) : Refactor brave/browser into separate component (#27486) +#include "brave/browser/ipfs/ipfs_local_pin_service_factory.h" // nogncheck +#include "brave/browser/ipfs/ipfs_service_factory.h" // nogncheck #include "brave/components/brave_wallet/browser/brave_wallet_pin_service.h" #include "brave/components/brave_wallet/browser/brave_wallet_service.h" #include "brave/components/brave_wallet/browser/brave_wallet_service_delegate.h" @@ -41,6 +43,9 @@ BraveWalletPinService* BraveWalletPinServiceFactory::GetServiceForContext( if (!IsAllowedForContext(context)) { return nullptr; } + if (!ipfs::IpfsServiceFactory::IsIpfsEnabled(context)) { + return nullptr; + } return static_cast( GetInstance()->GetServiceForBrowserContext(context, true)); } diff --git a/browser/brave_wallet/brave_wallet_pin_service_factory.h b/browser/brave_wallet/brave_wallet_pin_service_factory.h index 05f589429638..2b1b0c4cd565 100644 --- a/browser/brave_wallet/brave_wallet_pin_service_factory.h +++ b/browser/brave_wallet/brave_wallet_pin_service_factory.h @@ -1,13 +1,12 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #ifndef BRAVE_BROWSER_BRAVE_WALLET_BRAVE_WALLET_PIN_SERVICE_FACTORY_H_ #define BRAVE_BROWSER_BRAVE_WALLET_BRAVE_WALLET_PIN_SERVICE_FACTORY_H_ #include "base/memory/singleton.h" -#include "brave/browser/ipfs/ipfs_service_factory.h" #include "brave/components/brave_wallet/common/brave_wallet.mojom.h" #include "components/keyed_service/content/browser_context_keyed_service_factory.h" #include "components/keyed_service/core/keyed_service.h" diff --git a/browser/browser_context_keyed_service_factories.cc b/browser/browser_context_keyed_service_factories.cc index b2c278c72079..273d1ccb3f7b 100644 --- a/browser/browser_context_keyed_service_factories.cc +++ b/browser/browser_context_keyed_service_factories.cc @@ -53,6 +53,8 @@ #endif #if BUILDFLAG(ENABLE_IPFS) +#include "brave/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h" +#include "brave/browser/brave_wallet/brave_wallet_pin_service_factory.h" #include "brave/browser/ipfs/ipfs_service_factory.h" #endif @@ -107,6 +109,8 @@ void EnsureBrowserContextKeyedServiceFactoriesBuilt() { #endif #if BUILDFLAG(ENABLE_IPFS) + brave_wallet::BraveWalletAutoPinServiceFactory::GetInstance(); + brave_wallet::BraveWalletPinServiceFactory::GetInstance(); ipfs::IpfsServiceFactory::GetInstance(); #endif diff --git a/browser/ipfs/ipfs_local_pin_service_factory.cc b/browser/ipfs/ipfs_local_pin_service_factory.cc index e52e6bdb9347..92af1458cf6c 100644 --- a/browser/ipfs/ipfs_local_pin_service_factory.cc +++ b/browser/ipfs/ipfs_local_pin_service_factory.cc @@ -1,7 +1,7 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #include "brave/browser/ipfs/ipfs_local_pin_service_factory.h" diff --git a/browser/ipfs/ipfs_local_pin_service_factory.h b/browser/ipfs/ipfs_local_pin_service_factory.h index f8e7fc6f8f56..30ec5b3cb414 100644 --- a/browser/ipfs/ipfs_local_pin_service_factory.h +++ b/browser/ipfs/ipfs_local_pin_service_factory.h @@ -1,7 +1,7 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #ifndef BRAVE_BROWSER_IPFS_IPFS_LOCAL_PIN_SERVICE_FACTORY_H_ #define BRAVE_BROWSER_IPFS_IPFS_LOCAL_PIN_SERVICE_FACTORY_H_ diff --git a/browser/profiles/brave_profile_manager.cc b/browser/profiles/brave_profile_manager.cc index 15d73e1b3a4e..2a4ec849d719 100644 --- a/browser/profiles/brave_profile_manager.cc +++ b/browser/profiles/brave_profile_manager.cc @@ -15,7 +15,6 @@ #include "brave/browser/brave_federated/brave_federated_service_factory.h" #include "brave/browser/brave_news/brave_news_controller_factory.h" #include "brave/browser/brave_rewards/rewards_service_factory.h" -#include "brave/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h" #include "brave/browser/brave_wallet/brave_wallet_service_factory.h" #include "brave/browser/profiles/profile_util.h" #include "brave/browser/url_sanitizer/url_sanitizer_service_factory.h" @@ -45,6 +44,7 @@ #endif #if BUILDFLAG(ENABLE_IPFS) +#include "brave/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h" #include "brave/browser/ipfs/ipfs_service_factory.h" #endif @@ -98,11 +98,11 @@ void BraveProfileManager::DoFinalInitForServices(Profile* profile, return; brave_ads::AdsServiceFactory::GetForProfile(profile); brave_rewards::RewardsServiceFactory::GetForProfile(profile); - brave_wallet::BraveWalletServiceFactory::GetServiceForContext(profile); - brave_wallet::BraveWalletAutoPinServiceFactory::GetServiceForContext(profile); #if BUILDFLAG(ENABLE_IPFS) + brave_wallet::BraveWalletAutoPinServiceFactory::GetServiceForContext(profile); ipfs::IpfsServiceFactory::GetForContext(profile); #endif + brave_wallet::BraveWalletServiceFactory::GetServiceForContext(profile); #if !BUILDFLAG(USE_GCM_FROM_PLATFORM) gcm::BraveGCMChannelStatus* status = gcm::BraveGCMChannelStatus::GetForProfile(profile); diff --git a/browser/ui/webui/brave_wallet/wallet_page_ui.cc b/browser/ui/webui/brave_wallet/wallet_page_ui.cc index 414d7e22c789..ace82b4575f4 100644 --- a/browser/ui/webui/brave_wallet/wallet_page_ui.cc +++ b/browser/ui/webui/brave_wallet/wallet_page_ui.cc @@ -11,8 +11,6 @@ #include "base/command_line.h" #include "base/files/file_path.h" #include "brave/browser/brave_wallet/asset_ratio_service_factory.h" -#include "brave/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h" -#include "brave/browser/brave_wallet/brave_wallet_pin_service_factory.h" #include "brave/browser/brave_wallet/brave_wallet_service_factory.h" #include "brave/browser/brave_wallet/json_rpc_service_factory.h" #include "brave/browser/brave_wallet/keyring_service_factory.h" @@ -45,6 +43,11 @@ #include "ui/base/accelerators/accelerator.h" #include "ui/base/webui/web_ui_util.h" +#if BUILDFLAG(ENABLE_IPFS) +#include "brave/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h" +#include "brave/browser/brave_wallet/brave_wallet_pin_service_factory.h" +#endif + WalletPageUI::WalletPageUI(content::WebUI* web_ui) : ui::MojoWebUIController(web_ui, true /* Needed for webui browser tests */) { @@ -149,10 +152,13 @@ void WalletPageUI::CreatePageHandler( wallet_service->Bind(std::move(brave_wallet_service_receiver)); wallet_service->GetBraveWalletP3A()->Bind( std::move(brave_wallet_p3a_receiver)); + +#if BUILDFLAG(ENABLE_IPFS) brave_wallet::BraveWalletPinServiceFactory::BindForContext( profile, std::move(brave_wallet_pin_service_receiver)); brave_wallet::BraveWalletAutoPinServiceFactory::BindForContext( profile, std::move(brave_wallet_auto_pin_service_receiver)); +#endif auto* blockchain_registry = brave_wallet::BlockchainRegistry::GetInstance(); if (blockchain_registry) { diff --git a/components/brave_wallet/browser/brave_wallet_auto_pin_service.cc b/components/brave_wallet/browser/brave_wallet_auto_pin_service.cc index a50fffde34e8..7cc5df091825 100644 --- a/components/brave_wallet/browser/brave_wallet_auto_pin_service.cc +++ b/components/brave_wallet/browser/brave_wallet_auto_pin_service.cc @@ -1,7 +1,7 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #include "brave/components/brave_wallet/browser/brave_wallet_auto_pin_service.h" @@ -12,7 +12,7 @@ namespace brave_wallet { IntentData::IntentData(const BlockchainTokenPtr& token, Operation operation, absl::optional service) - : token(token.Clone()), operation(operation), service(service) {} + : token(token.Clone()), operation(operation), service(std::move(service)) {} IntentData::~IntentData() {} @@ -35,7 +35,17 @@ void BraveWalletAutoPinService::Bind( receivers_.Add(this, std::move(receiver)); } +mojo::PendingRemote +BraveWalletAutoPinService::MakeRemote() { + mojo::PendingRemote remote; + receivers_.Add(this, remote.InitWithNewPipeAndPassReceiver()); + return remote; +} + void BraveWalletAutoPinService::OnTokenAdded(BlockchainTokenPtr token) { + if (!token->is_nft) { + return; + } if (!IsAutoPinEnabled()) { return; } @@ -43,20 +53,18 @@ void BraveWalletAutoPinService::OnTokenAdded(BlockchainTokenPtr token) { } void BraveWalletAutoPinService::OnTokenRemoved(BlockchainTokenPtr token) { - const auto iter = - std::remove_if(queue_.begin(), queue_.end(), - [&token](const std::unique_ptr& intent) { - return intent->token == token; - }); - queue_.erase(iter, queue_.end()); + if (!token->is_nft) { + return; + } + base::EraseIf(queue_, [&token](const std::unique_ptr& intent) { + return intent->token == token; + }); PostUnpinToken(std::move(token), base::OnceCallback()); } void BraveWalletAutoPinService::Restore() { - brave_wallet_service_->GetUserAssets( - mojom::kMainnetChainId, mojom::CoinType::ETH, - base::BindOnce(&BraveWalletAutoPinService::OnTokenListResolved, - base::Unretained(this))); + brave_wallet_service_->GetAllUserAssets(base::BindOnce( + &BraveWalletAutoPinService::OnTokenListResolved, base::Unretained(this))); } void BraveWalletAutoPinService::OnTokenListResolved( @@ -65,13 +73,16 @@ void BraveWalletAutoPinService::OnTokenListResolved( std::set known_tokens = brave_wallet_pin_service_->GetTokens(absl::nullopt); for (const auto& token : token_list) { - if (!token->is_erc721) { + if (!token->is_nft) { continue; } - std::string current_token_path = BraveWalletPinService::GetPath(absl::nullopt, token); - known_tokens.erase(known_tokens.find(current_token_path)); + + auto it = known_tokens.find(current_token_path); + if (it != known_tokens.end()) { + known_tokens.erase(it); + } mojom::TokenPinStatusPtr status = brave_wallet_pin_service_->GetTokenStatus(absl::nullopt, token); @@ -79,8 +90,8 @@ void BraveWalletAutoPinService::OnTokenListResolved( if (!status || status->code == mojom::TokenPinStatusCode::STATUS_NOT_PINNED) { if (autopin_enabled) { - AddOrExecute( - std::make_unique(token, Operation::ADD, absl::nullopt)); + AddOrExecute(std::make_unique(token, Operation::kAdd, + absl::nullopt)); } } else if (status->code == mojom::TokenPinStatusCode::STATUS_PINNING_FAILED || @@ -89,20 +100,19 @@ void BraveWalletAutoPinService::OnTokenListResolved( status->code == mojom::TokenPinStatusCode::STATUS_PINNING_PENDING) { AddOrExecute( - std::make_unique(token, Operation::ADD, absl::nullopt)); + std::make_unique(token, Operation::kAdd, absl::nullopt)); } else if (status->code == mojom::TokenPinStatusCode::STATUS_UNPINNING_FAILED || status->code == mojom::TokenPinStatusCode::STATUS_UNPINNING_IN_PROGRESS || status->code == mojom::TokenPinStatusCode::STATUS_UNPINNING_PENDING) { - AddOrExecute(std::make_unique(token, Operation::DELETE, + AddOrExecute(std::make_unique(token, Operation::kDelete, absl::nullopt)); } else if (status->code == mojom::TokenPinStatusCode::STATUS_PINNED) { auto t1 = status->validate_time; - if (!t1 || (base::Time::Now() - t1.value()) > base::Days(1) || - t1.value() > base::Time::Now()) { - AddOrExecute(std::make_unique(token, Operation::VALIDATE, + if ((base::Time::Now() - t1) > base::Days(1) || t1 > base::Time::Now()) { + AddOrExecute(std::make_unique(token, Operation::kValidate, absl::nullopt)); } } @@ -111,7 +121,7 @@ void BraveWalletAutoPinService::OnTokenListResolved( for (const auto& t : known_tokens) { mojom::BlockchainTokenPtr token = BraveWalletPinService::TokenFromPath(t); if (token) { - AddOrExecute(std::make_unique(token, Operation::DELETE, + AddOrExecute(std::make_unique(token, Operation::kDelete, absl::nullopt)); } } @@ -122,14 +132,14 @@ void BraveWalletAutoPinService::OnTokenListResolved( void BraveWalletAutoPinService::PostPinToken(BlockchainTokenPtr token, PostPinTokenCallback callback) { queue_.push_back( - std::make_unique(token, Operation::ADD, absl::nullopt)); + std::make_unique(token, Operation::kAdd, absl::nullopt)); CheckQueue(); } void BraveWalletAutoPinService::PostUnpinToken(BlockchainTokenPtr token, PostPinTokenCallback callback) { queue_.push_back( - std::make_unique(token, Operation::DELETE, absl::nullopt)); + std::make_unique(token, Operation::kDelete, absl::nullopt)); CheckQueue(); } @@ -168,10 +178,10 @@ void BraveWalletAutoPinService::AddOrExecute(std::unique_ptr data) { current_->service == data->service) { return; } - if (data->operation == Operation::ADD) { + if (data->operation == Operation::kAdd) { brave_wallet_pin_service_->MarkAsPendingForPinning(data->token, data->service); - } else if (data->operation == Operation::DELETE) { + } else if (data->operation == Operation::kDelete) { brave_wallet_pin_service_->MarkAsPendingForUnpinning(data->token, data->service); } @@ -184,7 +194,7 @@ void BraveWalletAutoPinService::PostRetry(std::unique_ptr data) { base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, base::BindOnce(&BraveWalletAutoPinService::AddOrExecute, - base::Unretained(this), std::move(data)), + weak_ptr_factory_.GetWeakPtr(), std::move(data)), base::Minutes(1 * multiply)); } @@ -196,11 +206,11 @@ void BraveWalletAutoPinService::CheckQueue() { current_ = std::move(queue_.front()); queue_.pop_front(); - if (current_->operation == Operation::ADD) { + if (current_->operation == Operation::kAdd) { PinToken(current_); - } else if (current_->operation == Operation::DELETE) { + } else if (current_->operation == Operation::kDelete) { UnpinToken(current_); - } else if (current_->operation == Operation::VALIDATE) { + } else if (current_->operation == Operation::kValidate) { ValidateToken(current_); } } @@ -219,7 +229,7 @@ void BraveWalletAutoPinService::OnValidateTaskFinished( bool result, mojom::PinErrorPtr error) { if (!result) { - AddOrExecute(std::make_unique(current_->token, Operation::ADD, + AddOrExecute(std::make_unique(current_->token, Operation::kAdd, current_->service)); } current_.reset(); diff --git a/components/brave_wallet/browser/brave_wallet_auto_pin_service.h b/components/brave_wallet/browser/brave_wallet_auto_pin_service.h index 6fe28f592848..9397d93930a2 100644 --- a/components/brave_wallet/browser/brave_wallet_auto_pin_service.h +++ b/components/brave_wallet/browser/brave_wallet_auto_pin_service.h @@ -1,7 +1,7 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #ifndef BRAVE_COMPONENTS_BRAVE_WALLET_BROWSER_BRAVE_WALLET_AUTO_PIN_SERVICE_H_ #define BRAVE_COMPONENTS_BRAVE_WALLET_BROWSER_BRAVE_WALLET_AUTO_PIN_SERVICE_H_ @@ -30,7 +30,7 @@ using brave_wallet::mojom::BlockchainTokenPtr; namespace brave_wallet { -enum Operation { ADD = 0, DELETE = 1, VALIDATE = 2 }; +enum Operation { kAdd = 0, kDelete = 1, kValidate = 2 }; struct IntentData { BlockchainTokenPtr token; @@ -92,12 +92,14 @@ class BraveWalletAutoPinService token_observer_{this}; mojo::ReceiverSet receivers_; - PrefService* pref_service_; - BraveWalletService* brave_wallet_service_; - BraveWalletPinService* brave_wallet_pin_service_; + raw_ptr pref_service_; + raw_ptr brave_wallet_service_; + raw_ptr brave_wallet_pin_service_; std::unique_ptr current_; std::deque> queue_; + + base::WeakPtrFactory weak_ptr_factory_{this}; }; } // namespace brave_wallet diff --git a/components/brave_wallet/browser/brave_wallet_auto_pin_service_unittest.cc b/components/brave_wallet/browser/brave_wallet_auto_pin_service_unittest.cc index 964e9a87f1dc..7595c0370b47 100644 --- a/components/brave_wallet/browser/brave_wallet_auto_pin_service_unittest.cc +++ b/components/brave_wallet/browser/brave_wallet_auto_pin_service_unittest.cc @@ -1,7 +1,7 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #include "brave/components/brave_wallet/browser/brave_wallet_auto_pin_service.h" @@ -29,6 +29,8 @@ using testing::_; namespace brave_wallet { +namespace { + class MockBraveWalletPinService : public BraveWalletPinService { public: MockBraveWalletPinService() @@ -48,10 +50,10 @@ class MockBraveWalletPinService : public BraveWalletPinService { MOCK_METHOD1(GetTokens, std::set(const absl::optional&)); MOCK_METHOD2(GetTokenStatus, - mojom::TokenPinStatusPtr(absl::optional, + mojom::TokenPinStatusPtr(const absl::optional&, const mojom::BlockchainTokenPtr&)); MOCK_METHOD2(GetLastValidateTime, - absl::optional(absl::optional, + absl::optional(const absl::optional&, const mojom::BlockchainTokenPtr&)); MOCK_METHOD2(MarkAsPendingForPinning, void(const mojom::BlockchainTokenPtr&, @@ -63,16 +65,16 @@ class MockBraveWalletPinService : public BraveWalletPinService { class MockBraveWalletService : public BraveWalletService { public: - MOCK_METHOD3(GetUserAssets, - void(const std::string&, - mojom::CoinType, - BraveWalletService::GetUserAssetsCallback)); + MOCK_METHOD1(GetAllUserAssets, + void(BraveWalletService::GetUserAssetsCallback)); }; MATCHER_P(TokenPathMatches, path, "") { return arg == BraveWalletPinService::TokenFromPath(path); } +} // namespace + class BraveWalletAutoPinServiceTest : public testing::Test { public: BraveWalletAutoPinServiceTest() = default; @@ -84,7 +86,7 @@ class BraveWalletAutoPinServiceTest : public testing::Test { protected: void SetUp() override { auto* registry = pref_service_.registry(); - registry->RegisterBooleanPref(kAutoPinEnabled, false); + registry->RegisterBooleanPref(kAutoPinEnabled, true); brave_wallet_auto_pin_service_ = std::make_unique( GetPrefs(), GetBraveWalletService(), GetBraveWalletPinService()); @@ -175,10 +177,8 @@ TEST_F(BraveWalletAutoPinServiceTest, UnpinUnknownTokens_WhenRestore) { })); ON_CALL(*GetBraveWalletPinService(), GetTokens(_)) .WillByDefault(::testing::Return(known_tokens)); - ON_CALL(*GetBraveWalletService(), GetUserAssets(_, _, _)) - .WillByDefault(::testing::Invoke([](const std::string& chain_id, - mojom::CoinType coin, - BraveWalletService:: + ON_CALL(*GetBraveWalletService(), GetAllUserAssets(_)) + .WillByDefault(::testing::Invoke([](BraveWalletService:: GetUserAssetsCallback callback) { std::vector result; result.push_back(BraveWalletPinService::TokenFromPath( @@ -233,10 +233,8 @@ TEST_F(BraveWalletAutoPinServiceTest, ValidateOldTokens_WhenRestore) { })); ON_CALL(*GetBraveWalletPinService(), GetTokens(_)) .WillByDefault(::testing::Return(known_tokens)); - ON_CALL(*GetBraveWalletService(), GetUserAssets(_, _, _)) - .WillByDefault(::testing::Invoke([](const std::string& chain_id, - mojom::CoinType coin, - BraveWalletService:: + ON_CALL(*GetBraveWalletService(), GetAllUserAssets(_)) + .WillByDefault(::testing::Invoke([](BraveWalletService:: GetUserAssetsCallback callback) { std::vector result; result.push_back(BraveWalletPinService::TokenFromPath( @@ -316,10 +314,8 @@ TEST_F(BraveWalletAutoPinServiceTest, PinContinue_WhenRestore) { })); ON_CALL(*GetBraveWalletPinService(), GetTokens(_)) .WillByDefault(::testing::Return(known_tokens)); - ON_CALL(*GetBraveWalletService(), GetUserAssets(_, _, _)) - .WillByDefault(::testing::Invoke([](const std::string& chain_id, - mojom::CoinType coin, - BraveWalletService:: + ON_CALL(*GetBraveWalletService(), GetAllUserAssets(_)) + .WillByDefault(::testing::Invoke([](BraveWalletService:: GetUserAssetsCallback callback) { std::vector result; result.push_back(BraveWalletPinService::TokenFromPath( @@ -392,10 +388,8 @@ TEST_F(BraveWalletAutoPinServiceTest, UnpinContinue_WhenRestore) { })); ON_CALL(*GetBraveWalletPinService(), GetTokens(_)) .WillByDefault(::testing::Return(known_tokens)); - ON_CALL(*GetBraveWalletService(), GetUserAssets(_, _, _)) - .WillByDefault(::testing::Invoke([](const std::string& chain_id, - mojom::CoinType coin, - BraveWalletService:: + ON_CALL(*GetBraveWalletService(), GetAllUserAssets(_)) + .WillByDefault(::testing::Invoke([](BraveWalletService:: GetUserAssetsCallback callback) { std::vector result; result.push_back(BraveWalletPinService::TokenFromPath( @@ -425,6 +419,12 @@ TEST_F(BraveWalletAutoPinServiceTest, UnpinContinue_WhenRestore) { "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2"), testing::Eq(absl::nullopt), _)) .Times(1); + EXPECT_CALL(*GetBraveWalletPinService(), + RemovePin(TokenPathMatches( + "nft.local.60.0x1." + "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x3"), + testing::Eq(absl::nullopt), _)) + .Times(1); BraveWalletAutoPinService auto_pin_service( GetPrefs(), GetBraveWalletService(), GetBraveWalletPinService()); @@ -473,10 +473,8 @@ TEST_F(BraveWalletAutoPinServiceTest, PinOldTokens_WhenAutoPinEnabled) { })); ON_CALL(*GetBraveWalletPinService(), GetTokens(_)) .WillByDefault(::testing::Return(known_tokens)); - ON_CALL(*GetBraveWalletService(), GetUserAssets(_, _, _)) - .WillByDefault(::testing::Invoke([](const std::string& chain_id, - mojom::CoinType coin, - BraveWalletService:: + ON_CALL(*GetBraveWalletService(), GetAllUserAssets(_)) + .WillByDefault(::testing::Invoke([](BraveWalletService:: GetUserAssetsCallback callback) { std::vector result; result.push_back(BraveWalletPinService::TokenFromPath( diff --git a/components/brave_wallet/browser/brave_wallet_pin_service.cc b/components/brave_wallet/browser/brave_wallet_pin_service.cc index 169f1bf99041..70bd31e70676 100644 --- a/components/brave_wallet/browser/brave_wallet_pin_service.cc +++ b/components/brave_wallet/browser/brave_wallet_pin_service.cc @@ -1,12 +1,13 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #include "brave/components/brave_wallet/browser/brave_wallet_pin_service.h" #include +#include "base/json/values_util.h" #include "base/strings/strcat.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" @@ -41,13 +42,13 @@ absl::optional StringToStatus( const std::string& status) { if (status == "not_pinned") { return mojom::TokenPinStatusCode::STATUS_NOT_PINNED; - } else if (status == "pining_failed") { + } else if (status == "pinning_failed") { return mojom::TokenPinStatusCode::STATUS_PINNING_FAILED; } else if (status == "pinned") { return mojom::TokenPinStatusCode::STATUS_PINNED; } else if (status == "pinning_in_progress") { return mojom::TokenPinStatusCode::STATUS_PINNING_IN_PROGRESS; - } else if (status == "unpining_in_progress") { + } else if (status == "unpinning_in_progress") { return mojom::TokenPinStatusCode::STATUS_UNPINNING_IN_PROGRESS; } else if (status == "unpining_failed") { return mojom::TokenPinStatusCode::STATUS_UNPINNING_FAILED; @@ -112,11 +113,11 @@ std::string StatusToString(const mojom::TokenPinStatusCode& status) { case mojom::TokenPinStatusCode::STATUS_PINNING_IN_PROGRESS: return "pinning_in_progress"; case mojom::TokenPinStatusCode::STATUS_UNPINNING_IN_PROGRESS: - return "unpining_in_progress"; + return "unpinning_in_progress"; case mojom::TokenPinStatusCode::STATUS_UNPINNING_FAILED: - return "unpining_failed"; + return "unpinning_failed"; case mojom::TokenPinStatusCode::STATUS_PINNING_FAILED: - return "pining_failed"; + return "pinning_failed"; case mojom::TokenPinStatusCode::STATUS_PINNING_PENDING: return "pinning_pendig"; case mojom::TokenPinStatusCode::STATUS_UNPINNING_PENDING: @@ -252,6 +253,9 @@ void BraveWalletPinService::Validate(BlockchainTokenPtr token, base::BindOnce(&BraveWalletPinService::OnTokenValidated, base::Unretained(this), service, std::move(callback), std::move(token))); + } else { + // Remote pinning not implemented yet + std::move(callback).Run(false, nullptr); } } @@ -272,12 +276,11 @@ void BraveWalletPinService::MarkAsPendingForUnpinning( void BraveWalletPinService::AddPin(BlockchainTokenPtr token, const absl::optional& service, AddPinCallback callback) { - if (!token->is_erc721) { - auto pin_error = - mojom::PinError::New(mojom::WalletPinServiceErrorCode::ERR_WRONG_TOKEN, - "Token is not erc721"); + if (!token->is_nft) { + auto pin_error = mojom::PinError::New( + mojom::WalletPinServiceErrorCode::ERR_WRONG_TOKEN, "Token is not nft"); - VLOG(1) << "Token is not erc721"; + VLOG(1) << "Token is not nft"; FinishAddingWithResult(service, token, false, std::move(pin_error), std::move(callback)); return; @@ -315,11 +318,16 @@ void BraveWalletPinService::RemovePin( mojom::TokenPinStatusCode::STATUS_UNPINNING_IN_PROGRESS, nullptr); - local_pin_service_->RemovePins( - GetPath(service, token), - base::BindOnce(&BraveWalletPinService::OnPinsRemoved, - base::Unretained(this), service, std::move(callback), - std::move(token))); + if (!service) { + local_pin_service_->RemovePins( + GetPath(service, token), + base::BindOnce(&BraveWalletPinService::OnPinsRemoved, + base::Unretained(this), service, std::move(callback), + std::move(token))); + } else { + // Remote pinning not implemented yet + std::move(callback).Run(false, nullptr); + } } void BraveWalletPinService::GetTokenStatus(BlockchainTokenPtr token, @@ -393,7 +401,10 @@ void BraveWalletPinService::OnTokenMetaDataReceived( cids.push_back(ExtractCID(token_url).value()); auto* image = parsed_result->FindStringKey("image"); if (image) { - cids.push_back(ExtractCID(*image).value()); + auto image_cid = ExtractCID(*image); + if (image_cid) { + cids.push_back(image_cid.value()); + } } CreateToken(service, token, cids); @@ -407,6 +418,9 @@ void BraveWalletPinService::OnTokenMetaDataReceived( base::BindOnce(&BraveWalletPinService::OnTokenPinned, base::Unretained(this), absl::nullopt, std::move(callback), std::move(token))); + } else { + // Remote pinning not implemented yet + std::move(callback).Run(false, nullptr); } } @@ -414,11 +428,11 @@ void BraveWalletPinService::OnTokenPinned(absl::optional service, AddPinCallback callback, mojom::BlockchainTokenPtr token, bool result) { - auto error = - !result ? mojom::PinError::New( - mojom::WalletPinServiceErrorCode::ERR_WRONG_METADATA_FORMAT, - "Wrong metadata format") - : nullptr; + auto error = !result + ? mojom::PinError::New( + mojom::WalletPinServiceErrorCode::ERR_PINNING_FAILED, + "Pinning failed") + : nullptr; SetTokenStatus(service, token, result ? mojom::TokenPinStatusCode::STATUS_PINNED : mojom::TokenPinStatusCode::STATUS_PINNING_FAILED, @@ -451,9 +465,10 @@ void BraveWalletPinService::OnTokenValidated( std::move(callback).Run(true, nullptr); } -void BraveWalletPinService::CreateToken(absl::optional service, - const mojom::BlockchainTokenPtr& token, - const std::vector& cids) { +void BraveWalletPinService::CreateToken( + const absl::optional& service, + const mojom::BlockchainTokenPtr& token, + const std::vector& cids) { DictionaryPrefUpdate update(prefs_, kPinnedErc721Assets); base::Value::Dict& update_dict = update->GetDict(); @@ -472,15 +487,21 @@ void BraveWalletPinService::CreateToken(absl::optional service, } void BraveWalletPinService::RemoveToken( - absl::optional service, + const absl::optional& service, const mojom::BlockchainTokenPtr& token) { - DictionaryPrefUpdate update(prefs_, kPinnedErc721Assets); - base::Value::Dict& update_dict = update->GetDict(); - update_dict.RemoveByDottedPath(GetPath(service, token)); + { + DictionaryPrefUpdate update(prefs_, kPinnedErc721Assets); + base::Value::Dict& update_dict = update->GetDict(); + update_dict.RemoveByDottedPath(GetPath(service, token)); + } + for (const auto& observer : observers_) { + observer->OnTokenStatusChanged(service, token.Clone(), + GetTokenStatus(service, token)); + } } void BraveWalletPinService::SetTokenStatus( - absl::optional service, + const absl::optional& service, const mojom::BlockchainTokenPtr& token, mojom::TokenPinStatusCode status, const mojom::PinErrorPtr& error) { @@ -503,7 +524,7 @@ void BraveWalletPinService::SetTokenStatus( if (status == mojom::TokenPinStatusCode::STATUS_PINNED) { update_dict.SetByDottedPath( GetPath(service, token) + "." + kValidateTimestamp, - base::NumberToString(base::Time::Now().ToInternalValue())); + base::TimeToValue(base::Time::Now())); } else { update_dict.RemoveByDottedPath(GetPath(service, token) + "." + kValidateTimestamp); @@ -542,7 +563,7 @@ absl::optional> BraveWalletPinService::ResolvePinItems( } mojom::TokenPinStatusPtr BraveWalletPinService::GetTokenStatus( - absl::optional service, + const absl::optional& service, const mojom::BlockchainTokenPtr& token) { const base::Value::Dict& pinned_assets_pref = prefs_->GetDict(kPinnedErc721Assets); @@ -551,29 +572,27 @@ mojom::TokenPinStatusPtr BraveWalletPinService::GetTokenStatus( auto* token_data_as_dict = pinned_assets_pref.FindDictByDottedPath(path); if (!token_data_as_dict) { - return nullptr; + return mojom::TokenPinStatus::New( + mojom::TokenPinStatusCode::STATUS_NOT_PINNED, nullptr, base::Time()); } auto* status = token_data_as_dict->FindString(kAssetStatus); if (!status) { return mojom::TokenPinStatus::New( - mojom::TokenPinStatusCode::STATUS_NOT_PINNED, nullptr, absl::nullopt); + mojom::TokenPinStatusCode::STATUS_NOT_PINNED, nullptr, base::Time()); } auto pin_status = StringToStatus(*status).value_or( mojom::TokenPinStatusCode::STATUS_NOT_PINNED); - absl::optional validate_timestamp; + base::Time validate_timestamp; mojom::PinErrorPtr error; { - auto* validate_timestamp_str = - token_data_as_dict->FindString(kValidateTimestamp); - uint64_t validate_timestamp_internal_value; - if (validate_timestamp_str && - base::StringToUint64(*validate_timestamp_str, - &validate_timestamp_internal_value)) { + auto* validate_timestamp_value = + token_data_as_dict->Find(kValidateTimestamp); + if (validate_timestamp_value) { validate_timestamp = - base::Time::FromInternalValue(validate_timestamp_internal_value); + base::ValueToTime(validate_timestamp_value).value_or(base::Time()); } auto* error_dict = token_data_as_dict->FindDict(kError); @@ -594,7 +613,7 @@ mojom::TokenPinStatusPtr BraveWalletPinService::GetTokenStatus( } absl::optional BraveWalletPinService::GetLastValidateTime( - absl::optional service, + const absl::optional& service, const mojom::BlockchainTokenPtr& token) { const base::Value::Dict& pinned_assets_pref = prefs_->GetDict(kPinnedErc721Assets); @@ -606,16 +625,12 @@ absl::optional BraveWalletPinService::GetLastValidateTime( return absl::nullopt; } - auto* time = token_data_as_dict->FindString(kValidateTimestamp); - int64_t value; - if (time && base::StringToInt64(*time, &value)) { - return base::Time::FromInternalValue(value); - } - return absl::nullopt; + auto* time = token_data_as_dict->Find(kValidateTimestamp); + return base::ValueToTime(time); } void BraveWalletPinService::FinishAddingWithResult( - absl::optional service, + const absl::optional& service, const mojom::BlockchainTokenPtr& token, bool result, mojom::PinErrorPtr error, diff --git a/components/brave_wallet/browser/brave_wallet_pin_service.h b/components/brave_wallet/browser/brave_wallet_pin_service.h index 9c90f47d3f46..de2ab62a7d76 100644 --- a/components/brave_wallet/browser/brave_wallet_pin_service.h +++ b/components/brave_wallet/browser/brave_wallet_pin_service.h @@ -1,7 +1,7 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #ifndef BRAVE_COMPONENTS_BRAVE_WALLET_BROWSER_BRAVE_WALLET_PIN_SERVICE_H_ #define BRAVE_COMPONENTS_BRAVE_WALLET_BROWSER_BRAVE_WALLET_PIN_SERVICE_H_ @@ -10,6 +10,7 @@ #include #include +#include "base/containers/cxx20_erase_deque.h" #include "base/memory/scoped_refptr.h" #include "base/task/sequenced_task_runner.h" #include "brave/components/brave_wallet/browser/brave_wallet_service.h" @@ -70,26 +71,26 @@ class BraveWalletPinService : public KeyedService, const absl::optional& service); virtual mojom::TokenPinStatusPtr GetTokenStatus( - absl::optional service, + const absl::optional& service, const mojom::BlockchainTokenPtr& token); virtual absl::optional GetLastValidateTime( - absl::optional service, + const absl::optional& service, const mojom::BlockchainTokenPtr& token); virtual std::set GetTokens( const absl::optional& service); private: - void CreateToken(absl::optional service, + void CreateToken(const absl::optional& service, const mojom::BlockchainTokenPtr& token, const std::vector& cids); - void RemoveToken(absl::optional service, + void RemoveToken(const absl::optional& service, const mojom::BlockchainTokenPtr& token); - void SetTokenStatus(absl::optional service, + void SetTokenStatus(const absl::optional& service, const mojom::BlockchainTokenPtr& token, mojom::TokenPinStatusCode, const mojom::PinErrorPtr& error); - void FinishAddingWithResult(absl::optional service, + void FinishAddingWithResult(const absl::optional& service, const mojom::BlockchainTokenPtr& token, bool result, mojom::PinErrorPtr error, @@ -124,11 +125,11 @@ class BraveWalletPinService : public KeyedService, mojo::RemoteSet observers_; // Prefs service is used to store list of pinned items - PrefService* prefs_; + raw_ptr prefs_; // JsonRpcService is used to fetch token metadata - JsonRpcService* json_rpc_service_; - ipfs::IpfsLocalPinService* local_pin_service_; + raw_ptr json_rpc_service_; + raw_ptr local_pin_service_; }; } // namespace brave_wallet diff --git a/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc b/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc index 130042976b0c..05304697357f 100644 --- a/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc +++ b/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc @@ -1,7 +1,7 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #include "brave/components/brave_wallet/browser/brave_wallet_pin_service.h" @@ -11,6 +11,7 @@ #include #include "base/json/json_reader.h" +#include "base/json/values_util.h" #include "base/test/bind.h" #include "base/time/time_override.h" #include "brave/components/brave_wallet/browser/brave_wallet_prefs.h" @@ -22,6 +23,7 @@ #include "components/prefs/scoped_user_pref_update.h" #include "components/prefs/testing_pref_service.h" #include "content/public/test/browser_task_environment.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -41,9 +43,12 @@ const char kMonkey1Url[] = "ipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/2413"; const char kMonkey1[] = R"({"image":"ipfs://Qmcyc7tm9sZB9JnvLgejPTwdzjjNjDMiRWCUvaZAfp6cUg", - "attributes":[{"trait_type":"Mouth","value":"Bored Cigarette"}, - {"trait_type":"Fur","value":"Zombie"},{"trait_type":"Background","value":"Purple"}, - {"trait_type":"Eyes","value":"Closed"},{"trait_type":"Clothes","value":"Toga"}, + "attributes":[ + {"trait_type":"Mouth","value":"Bored Cigarette"}, + {"trait_type":"Fur","value":"Zombie"}, + {"trait_type":"Background","value":"Purple"}, + {"trait_type":"Eyes","value":"Closed"}, + {"trait_type":"Clothes","value":"Toga"}, {"trait_type":"Hat","value":"Cowboy Hat"}]})"; base::Time g_overridden_now; @@ -54,8 +59,6 @@ std::unique_ptr OverrideWithTimeNow( []() { return g_overridden_now; }, nullptr, nullptr); } -} // namespace - class MockIpfsLocalPinService : public ipfs::IpfsLocalPinService { public: MockIpfsLocalPinService() {} @@ -77,7 +80,7 @@ class MockIpfsLocalPinService : public ipfs::IpfsLocalPinService { class MockJsonRpcService : public JsonRpcService { public: - MockJsonRpcService() {} + MockJsonRpcService() : JsonRpcService() {} MOCK_METHOD4(GetERC721Metadata, void(const std::string& contract_address, @@ -88,6 +91,8 @@ class MockJsonRpcService : public JsonRpcService { ~MockJsonRpcService() override {} }; +} // namespace + class BraveWalletPinServiceTest : public testing::Test { public: BraveWalletPinServiceTest() = default; @@ -146,8 +151,7 @@ TEST_F(BraveWalletPinServiceTest, AddPin) { std::move(callback).Run(true); })); - auto scoped_override = - OverrideWithTimeNow(base::Time::FromInternalValue(123u)); + auto scoped_override = OverrideWithTimeNow(base::Time::FromTimeT(123u)); mojom::BlockchainTokenPtr token = BraveWalletPinService::TokenFromPath(kMonkey1Path); @@ -175,7 +179,9 @@ TEST_F(BraveWalletPinServiceTest, AddPin) { *(token_record->FindString("status"))); EXPECT_EQ(nullptr, token_record->FindDict("error")); EXPECT_EQ(expected_cids, *(token_record->FindList("cids"))); - EXPECT_EQ("123", *(token_record->FindString("validate_timestamp"))); + EXPECT_EQ( + 123u, + base::ValueToTime(token_record->Find("validate_timestamp"))->ToTimeT()); } { @@ -293,7 +299,7 @@ TEST_F(BraveWalletPinServiceTest, ValidatePin) { base::Value::Dict item; item.Set("status", "pinned"); - item.Set("validate_timestamp", "123"); + item.Set("validate_timestamp", base::TimeToValue(base::Time::Now())); base::Value::List cids; cids.Append("QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq"); cids.Append("Qmcyc7tm9sZB9JnvLgejPTwdzjjNjDMiRWCUvaZAfp6cUg"); @@ -303,8 +309,7 @@ TEST_F(BraveWalletPinServiceTest, ValidatePin) { } { - auto scoped_override = - OverrideWithTimeNow(base::Time::FromInternalValue(345u)); + auto scoped_override = OverrideWithTimeNow(base::Time::FromTimeT(345u)); mojom::BlockchainTokenPtr token = BraveWalletPinService::TokenFromPath(kMonkey1Path); @@ -334,7 +339,9 @@ TEST_F(BraveWalletPinServiceTest, ValidatePin) { GetPrefs() ->GetDict(kPinnedErc721Assets) .FindDictByDottedPath(kMonkey1Path); - EXPECT_EQ("345", *(token_record->FindString("validate_timestamp"))); + EXPECT_EQ( + 345u, + base::ValueToTime(token_record->Find("validate_timestamp"))->ToTimeT()); } { @@ -362,7 +369,9 @@ TEST_F(BraveWalletPinServiceTest, ValidatePin) { GetPrefs() ->GetDict(kPinnedErc721Assets) .FindDictByDottedPath(kMonkey1Path); - EXPECT_EQ("345", *(token_record->FindString("validate_timestamp"))); + EXPECT_EQ( + 345u, + base::ValueToTime(token_record->Find("validate_timestamp"))->ToTimeT()); } { @@ -391,7 +400,7 @@ TEST_F(BraveWalletPinServiceTest, ValidatePin) { ->GetDict(kPinnedErc721Assets) .FindDictByDottedPath(kMonkey1Path); - EXPECT_EQ(nullptr, token_record->FindString("validate_timestamp")); + EXPECT_EQ(nullptr, token_record->Find("validate_timestamp")); } } @@ -402,7 +411,8 @@ TEST_F(BraveWalletPinServiceTest, GetTokenStatus) { base::Value::Dict item; item.Set("status", "pinned"); - item.Set("validate_timestamp", "123"); + item.Set("validate_timestamp", + base::TimeToValue(base::Time::FromTimeT(123u))); base::Value::List cids; cids.Append("QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq"); cids.Append("Qmcyc7tm9sZB9JnvLgejPTwdzjjNjDMiRWCUvaZAfp6cUg"); @@ -436,14 +446,13 @@ TEST_F(BraveWalletPinServiceTest, GetTokenStatus) { service()->GetTokenStatus(absl::nullopt, token1); EXPECT_EQ(mojom::TokenPinStatusCode::STATUS_PINNED, status->code); EXPECT_TRUE(status->error.is_null()); - EXPECT_EQ(base::Time::FromInternalValue(123u), - status->validate_time.value()); + EXPECT_EQ(base::Time::FromTimeT(123u), status->validate_time); } { mojom::TokenPinStatusPtr status = service()->GetTokenStatus("nft.storage", token1); - EXPECT_TRUE(status.is_null()); + EXPECT_EQ(mojom::TokenPinStatusCode::STATUS_NOT_PINNED, status->code); } mojom::BlockchainTokenPtr token2 = @@ -455,7 +464,7 @@ TEST_F(BraveWalletPinServiceTest, GetTokenStatus) { EXPECT_EQ(mojom::TokenPinStatusCode::STATUS_PINNING_FAILED, status->code); EXPECT_EQ(mojom::WalletPinServiceErrorCode::ERR_FETCH_METADATA_FAILED, status->error->error_code); - EXPECT_FALSE(status->validate_time.has_value()); + EXPECT_EQ(base::Time(), status->validate_time); } } @@ -466,7 +475,8 @@ TEST_F(BraveWalletPinServiceTest, GetLastValidateTime) { base::Value::Dict item; item.Set("status", "pinned"); - item.Set("validate_timestamp", "123"); + item.Set("validate_timestamp", + base::TimeToValue(base::Time::FromTimeT(123u))); base::Value::List cids; cids.Append("QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq"); cids.Append("Qmcyc7tm9sZB9JnvLgejPTwdzjjNjDMiRWCUvaZAfp6cUg"); @@ -481,7 +491,7 @@ TEST_F(BraveWalletPinServiceTest, GetLastValidateTime) { { base::Time last_validate_time = service()->GetLastValidateTime(absl::nullopt, token).value(); - EXPECT_EQ(base::Time::FromInternalValue(123u), last_validate_time); + EXPECT_EQ(base::Time::FromTimeT(123u), last_validate_time); } { diff --git a/components/brave_wallet/browser/brave_wallet_service.cc b/components/brave_wallet/browser/brave_wallet_service.cc index 6cf01ef42ffe..f3dfca23f3c5 100644 --- a/components/brave_wallet/browser/brave_wallet_service.cc +++ b/components/brave_wallet/browser/brave_wallet_service.cc @@ -277,6 +277,36 @@ absl::optional BraveWalletService::GetChecksumAddress( return eth_addr.ToChecksumAddress(chain); } +// static +std::vector BraveWalletService::GetUserAssets( + PrefService* profile_prefs) { + std::vector result; + const auto& user_assets_dict = profile_prefs->GetDict(kBraveWalletUserAssets); + for (auto coin_it : user_assets_dict) { + auto coin = GetCoinFromPref(coin_it.first); + if (!coin) + continue; + + for (auto network_it : coin_it.second.GetDict()) { + auto chain_id = GetChainId(profile_prefs, coin.value(), network_it.first); + + if (!chain_id) + continue; + + for (const auto& item : network_it.second.GetList()) { + const auto* token = item.GetIfDict(); + if (!token) + continue; + mojom::BlockchainTokenPtr tokenPtr = + ValueToBlockchainToken(*token, chain_id.value(), coin.value()); + if (tokenPtr) + result.push_back(std::move(tokenPtr)); + } + } + } + return result; +} + // static std::vector BraveWalletService::GetUserAssets( const std::string& chain_id, @@ -376,6 +406,11 @@ void BraveWalletService::GetUserAssets(const std::string& chain_id, std::move(callback).Run(std::move(result)); } +void BraveWalletService::GetAllUserAssets(GetUserAssetsCallback callback) { + std::vector result = GetUserAssets(profile_prefs_); + std::move(callback).Run(std::move(result)); +} + bool BraveWalletService::AddUserAsset(mojom::BlockchainTokenPtr token) { mojom::BlockchainTokenPtr clone = token.Clone(); bool result = diff --git a/components/brave_wallet/browser/brave_wallet_service.h b/components/brave_wallet/browser/brave_wallet_service.h index 93c32a0a1575..f2f8c18d4b00 100644 --- a/components/brave_wallet/browser/brave_wallet_service.h +++ b/components/brave_wallet/browser/brave_wallet_service.h @@ -87,6 +87,8 @@ class BraveWalletService : public KeyedService, const std::string& chain_id, mojom::CoinType coin, PrefService* profile_prefs); + static std::vector GetUserAssets( + PrefService* profile_prefs); static base::Value::Dict GetDefaultEthereumAssets(); static base::Value::Dict GetDefaultSolanaAssets(); static base::Value::Dict GetDefaultFilecoinAssets(); @@ -101,6 +103,7 @@ class BraveWalletService : public KeyedService, void GetUserAssets(const std::string& chain_id, mojom::CoinType coin, GetUserAssetsCallback callback) override; + void GetAllUserAssets(GetUserAssetsCallback callback) override; void AddUserAsset(mojom::BlockchainTokenPtr token, AddUserAssetCallback callback) override; void RemoveUserAsset(mojom::BlockchainTokenPtr token, diff --git a/components/brave_wallet/browser/brave_wallet_utils.cc b/components/brave_wallet/browser/brave_wallet_utils.cc index 038d8b6f24bf..090183c9f83e 100644 --- a/components/brave_wallet/browser/brave_wallet_utils.cc +++ b/components/brave_wallet/browser/brave_wallet_utils.cc @@ -1157,6 +1157,19 @@ std::string GetNetworkId(PrefService* prefs, return base::ToLowerASCII(id); } +absl::optional GetChainId(PrefService* prefs, + const mojom::CoinType& coin, + const std::string& network_id) { + std::vector networks = GetAllChains(prefs, coin); + for (const auto& network : networks) { + std::string id = GetKnownNetworkId(coin, network->chain_id); + if (id == network_id) { + return network->chain_id; + } + } + return absl::nullopt; +} + mojom::DefaultWallet GetDefaultEthereumWallet(PrefService* prefs) { return static_cast( prefs->GetInteger(kDefaultEthereumWallet)); @@ -1376,6 +1389,18 @@ std::string GetPrefKeyForCoinType(mojom::CoinType coin) { return ""; } +absl::optional GetCoinFromPref(const std::string& pref) { + if (pref == kEthereumPrefKey) { + return mojom::CoinType::ETH; + } else if (pref == kFilecoinPrefKey) { + return mojom::CoinType::FIL; + } else if (pref == kSolanaPrefKey) { + return mojom::CoinType::SOL; + } + NOTREACHED(); + return absl::nullopt; +} + std::string eTLDPlusOne(const url::Origin& origin) { return net::registry_controlled_domains::GetDomainAndRegistry( origin, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); diff --git a/components/brave_wallet/browser/brave_wallet_utils.h b/components/brave_wallet/browser/brave_wallet_utils.h index 9eecf96e76e4..fbdeafa1eff6 100644 --- a/components/brave_wallet/browser/brave_wallet_utils.h +++ b/components/brave_wallet/browser/brave_wallet_utils.h @@ -151,6 +151,14 @@ std::string GetCurrentChainId(PrefService* prefs, mojom::CoinType coin); std::string GetPrefKeyForCoinType(mojom::CoinType coin); +// Converts string representation of CoinType to enum. +absl::optional GetCoinFromPref(const std::string& pref); + +// Resolves chain_id from network_id. +absl::optional GetChainId(PrefService* prefs, + const mojom::CoinType& coin, + const std::string& network_id); + // Returns a string used for web3_clientVersion in the form of // BraveWallet/v[chromium-version]. Note that we expose only the Chromium // version and not the Brave version because that way no extra entropy diff --git a/components/brave_wallet/browser/json_rpc_service.h b/components/brave_wallet/browser/json_rpc_service.h index 00f306645e11..95a33bb3589b 100644 --- a/components/brave_wallet/browser/json_rpc_service.h +++ b/components/brave_wallet/browser/json_rpc_service.h @@ -55,6 +55,7 @@ class JsonRpcService : public KeyedService, public mojom::JsonRpcService { JsonRpcService( scoped_refptr url_loader_factory, PrefService* prefs); + // For testing: JsonRpcService(); ~JsonRpcService() override; diff --git a/components/brave_wallet/browser/nft_metadata_fetcher_unittest.cc b/components/brave_wallet/browser/nft_metadata_fetcher_unittest.cc index 058711612b2c..57f7aa1540e8 100644 --- a/components/brave_wallet/browser/nft_metadata_fetcher_unittest.cc +++ b/components/brave_wallet/browser/nft_metadata_fetcher_unittest.cc @@ -148,15 +148,14 @@ class NftMetadataFetcherUnitTest : public testing::Test { base::RunLoop run_loop; nft_metadata_fetcher_->GetEthTokenMetadata( contract, token_id, chain_id, interface_id, - base::BindLambdaForTesting([&](const std::string& url, - const std::string& response, - mojom::ProviderError error, - const std::string& error_message) { - CompareJSON(response, expected_response); - EXPECT_EQ(error, expected_error); - EXPECT_EQ(error_message, expected_error_message); - run_loop.Quit(); - })); + base::BindLambdaForTesting( + [&](const std::string& url, const std::string& response, + mojom::ProviderError error, const std::string& error_message) { + CompareJSON(response, expected_response); + EXPECT_EQ(error, expected_error); + EXPECT_EQ(error_message, expected_error_message); + run_loop.Quit(); + })); run_loop.Run(); } diff --git a/components/brave_wallet/common/brave_wallet.mojom b/components/brave_wallet/common/brave_wallet.mojom index b3f42815c368..b349345062bd 100644 --- a/components/brave_wallet/common/brave_wallet.mojom +++ b/components/brave_wallet/common/brave_wallet.mojom @@ -241,25 +241,30 @@ struct PinError { struct TokenPinStatus { TokenPinStatusCode code; PinError? error; - mojo_base.mojom.Time? validate_time; + mojo_base.mojom.Time validate_time; }; struct TokenPinOverview { - TokenPinStatus local; + TokenPinStatus? local; map remotes; }; interface BraveWalletPinServiceObserver { - OnTokenStatusChanged(string? service, BlockchainToken token, TokenPinStatus status); + OnTokenStatusChanged(string? service, BlockchainToken token, + TokenPinStatus status); }; interface WalletPinService { AddObserver(pending_remote observer); - AddPin(BlockchainToken token, string? service) => (bool result, PinError? error); - RemovePin(BlockchainToken token, string? service) => (bool result, PinError? response); - GetTokenStatus(BlockchainToken token) => (TokenPinOverview? status, PinError? error); - Validate(BlockchainToken token, string? service) => (bool result, PinError? error); + AddPin(BlockchainToken token, string? service) =>(bool result, + PinError? error); + RemovePin(BlockchainToken token, string? service) => (bool result, + PinError? response); + GetTokenStatus(BlockchainToken token) => (TokenPinOverview? status, + PinError? error); + Validate(BlockchainToken token, string? service) => (bool result, + PinError? error); }; interface WalletAutoPinService { @@ -305,7 +310,8 @@ interface PageHandlerFactory { pending_receiver brave_wallet_service, pending_receiver brave_wallet_p3a, pending_receiver brave_wallet_pin_service, - pending_receiver brave_wallet_auto_pin_service); + pending_receiver + brave_wallet_auto_pin_service); }; // Browser-side handler for requests from WebUI page. @@ -1303,6 +1309,9 @@ interface BraveWalletService { AddTokenObserver(pending_remote observer); + // Obtains all the user assets. + GetAllUserAssets() => (array tokens); + // Obtains the user assets for the specified chain ID and coin type. GetUserAssets(string chain_id, CoinType coin) => (array tokens); diff --git a/components/brave_wallet_ui/stories/mock-data/mock-page-state.ts b/components/brave_wallet_ui/stories/mock-data/mock-page-state.ts index fff129de6a1b..05e8d9068354 100644 --- a/components/brave_wallet_ui/stories/mock-data/mock-page-state.ts +++ b/components/brave_wallet_ui/stories/mock-data/mock-page-state.ts @@ -22,6 +22,7 @@ export const mockPageState: PageState = { isMetaMaskInitialized: false, portfolioPriceHistory: [], selectedAsset: undefined, + pinStatusOverview: undefined, selectedAssetCryptoPrice: undefined, selectedAssetFiatPrice: undefined, selectedAssetPriceHistory: [], diff --git a/components/ipfs/BUILD.gn b/components/ipfs/BUILD.gn index 6bc43e8daaaf..bba5c0c51458 100644 --- a/components/ipfs/BUILD.gn +++ b/components/ipfs/BUILD.gn @@ -1,3 +1,8 @@ +# Copyright (c) 2022 The Brave Authors. All rights reserved. +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at https://mozilla.org/MPL/2.0/. + import("//brave/components/ipfs/buildflags/buildflags.gni") static_library("ipfs") { diff --git a/components/ipfs/ipfs_json_parser.cc b/components/ipfs/ipfs_json_parser.cc index a80b20c94031..330671332b86 100644 --- a/components/ipfs/ipfs_json_parser.cc +++ b/components/ipfs/ipfs_json_parser.cc @@ -48,35 +48,32 @@ bool RemoveValueFromList(base::Value::List* root, const T& value_to_remove) { // ], // "Progress": "" // } -bool IPFSJSONParser::GetAddPinsResultFromJSON( - const std::string& json, - ipfs::AddPinResult* add_pin_result) { - absl::optional records_v = - base::JSONReader::Read(json, base::JSON_PARSE_CHROMIUM_EXTENSIONS | - base::JSONParserOptions::JSON_PARSE_RFC); - - if (!records_v) { - VLOG(1) << "Invalid response, could not parse JSON, JSON is: " << json; - return false; - } - - const base::Value* pins_arr = records_v->FindKey("Pins"); - if (!pins_arr || !pins_arr->is_list()) { +absl::optional IPFSJSONParser::GetAddPinsResultFromJSON( + const base::Value& value) { + auto* auto_dict = value.GetIfDict(); + if (!auto_dict) { + VLOG(1) << "Invalid response, wrong format."; + return absl::nullopt; + } + const base::Value::List* pins_list = auto_dict->FindList("Pins"); + if (!pins_list) { VLOG(1) << "Invalid response, can not find Pins array."; - return false; + return absl::nullopt; } - auto progress = records_v->FindIntKey("Progress"); + ipfs::AddPinResult result; + + auto progress = auto_dict->FindInt("Progress"); if (progress) { - add_pin_result->progress = *progress; + result.progress = *progress; } else { - add_pin_result->progress = -1; + result.progress = -1; } - for (const base::Value& val : pins_arr->GetList()) { - add_pin_result->pins.push_back(val.GetString()); + for (const base::Value& val : *pins_list) { + result.pins.push_back(val.GetString()); } - return true; + return result; } // static @@ -86,34 +83,28 @@ bool IPFSJSONParser::GetAddPinsResultFromJSON( // "" // ] // } -bool IPFSJSONParser::GetRemovePinsResultFromJSON( - const std::string& json, - ipfs::RemovePinResult* remove_pin_result) { - absl::optional records_v = - base::JSONReader::Read(json, base::JSON_PARSE_CHROMIUM_EXTENSIONS | - base::JSONParserOptions::JSON_PARSE_RFC); - - if (!records_v) { - VLOG(1) << "Invalid response, could not parse JSON, JSON is: " << json; - return false; - } - - const base::Value* pins_arr = records_v->FindKey("Pins"); - if (!pins_arr || !pins_arr->is_list()) { +absl::optional +IPFSJSONParser::GetRemovePinsResultFromJSON(const base::Value& value) { + auto* auto_dict = value.GetIfDict(); + if (!auto_dict) { + VLOG(1) << "Invalid response, wrong format."; + return absl::nullopt; + } + const base::Value::List* pins_list = auto_dict->FindList("Pins"); + if (!pins_list) { VLOG(1) << "Invalid response, can not find Pins array."; - return false; + return absl::nullopt; } ipfs::RemovePinResult result; - for (const base::Value& val : pins_arr->GetList()) { + for (const base::Value& val : *pins_list) { auto* val_as_str = val.GetIfString(); if (!val_as_str) { - return false; + return absl::nullopt; } result.push_back(*val_as_str); } - *remove_pin_result = result; - return true; + return result; } // static @@ -131,39 +122,36 @@ bool IPFSJSONParser::GetRemovePinsResultFromJSON( // "Type": "" // } // } -bool IPFSJSONParser::GetGetPinsResultFromJSON( - const std::string& json, - ipfs::GetPinsResult* get_pins_result) { - DCHECK(get_pins_result); - absl::optional records_v = - base::JSONReader::Read(json, base::JSON_PARSE_CHROMIUM_EXTENSIONS | - base::JSONParserOptions::JSON_PARSE_RFC); - - if (!records_v) { - VLOG(1) << "Invalid response, could not parse JSON, JSON is: " << json; - return false; +absl::optional IPFSJSONParser::GetGetPinsResultFromJSON( + const base::Value& value) { + auto* auto_dict = value.GetIfDict(); + if (!auto_dict) { + VLOG(1) << "Invalid response, wrong format."; + return absl::nullopt; } - const base::Value* keys = records_v->FindKey("Keys"); - if (!keys || !keys->is_dict()) { + const base::Value::Dict* keys = auto_dict->FindDict("Keys"); + if (!keys) { VLOG(1) << "Invalid response, can not find Keys in PinLsList dict."; - return false; + return absl::nullopt; } - for (const auto it : keys->GetDict()) { - if (!it.second.is_dict()) { + ipfs::GetPinsResult result; + for (auto it : *keys) { + auto* it_dict = it.second.GetIfDict(); + if (!it_dict) { VLOG(1) << "Missing Type for " << it.first; - return false; + return absl::nullopt; } - const std::string* type = it.second.FindStringKey("Type"); + const std::string* type = it_dict->FindString("Type"); if (!type) { VLOG(1) << "Missing Type for " << it.first; - return false; + return absl::nullopt; } - (*get_pins_result)[it.first] = *type; + result[it.first] = *type; } - return true; + return result; } // static diff --git a/components/ipfs/ipfs_json_parser.h b/components/ipfs/ipfs_json_parser.h index aef6dfb56152..49fe7c840652 100644 --- a/components/ipfs/ipfs_json_parser.h +++ b/components/ipfs/ipfs_json_parser.h @@ -48,13 +48,12 @@ class IPFSJSONParser { const std::string& peer_id, const std::string& address); // Local pins - static bool GetAddPinsResultFromJSON(const std::string& json, - ipfs::AddPinResult* add_pin_result); - static bool GetGetPinsResultFromJSON(const std::string& json, - ipfs::GetPinsResult* result); - static bool GetRemovePinsResultFromJSON( - const std::string& json, - ipfs::RemovePinResult* add_pin_result); + static absl::optional GetAddPinsResultFromJSON( + const base::Value& value); + static absl::optional GetGetPinsResultFromJSON( + const base::Value& value); + static absl::optional GetRemovePinsResultFromJSON( + const base::Value& value); }; #endif // BRAVE_COMPONENTS_IPFS_IPFS_JSON_PARSER_H_ diff --git a/components/ipfs/ipfs_json_parser_unittest.cc b/components/ipfs/ipfs_json_parser_unittest.cc index 5f9e35270f9c..207755364d65 100644 --- a/components/ipfs/ipfs_json_parser_unittest.cc +++ b/components/ipfs/ipfs_json_parser_unittest.cc @@ -386,105 +386,119 @@ TEST_F(IPFSJSONParserTest, RemovePeerFromConfigJSONTest) { TEST_F(IPFSJSONParserTest, GetGetPinsResultFromJSONTest) { { std::string json = R"({})"; - ipfs::GetPinsResult result; - EXPECT_FALSE(IPFSJSONParser::GetGetPinsResultFromJSON(json, &result)); + auto result = + IPFSJSONParser::GetGetPinsResultFromJSON(base::test::ParseJson(json)); + EXPECT_FALSE(result.has_value()); } { std::string json = R"({"Keys":{"QmA" : {"Type" : "Recursive"}}})"; - ipfs::GetPinsResult result; - EXPECT_TRUE(IPFSJSONParser::GetGetPinsResultFromJSON(json, &result)); - EXPECT_EQ(result.at("QmA"), "Recursive"); + auto result = + IPFSJSONParser::GetGetPinsResultFromJSON(base::test::ParseJson(json)); + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(result->at("QmA"), "Recursive"); } { std::string json = R"({"Keys":{}})"; - ipfs::GetPinsResult result; - EXPECT_TRUE(IPFSJSONParser::GetGetPinsResultFromJSON(json, &result)); - EXPECT_TRUE(result.empty()); + auto result = + IPFSJSONParser::GetGetPinsResultFromJSON(base::test::ParseJson(json)); + EXPECT_TRUE(result.has_value()); + EXPECT_TRUE(result->empty()); } { std::string json = R"({"Keys":[]})"; - ipfs::GetPinsResult result; - EXPECT_FALSE(IPFSJSONParser::GetGetPinsResultFromJSON(json, &result)); + auto result = + IPFSJSONParser::GetGetPinsResultFromJSON(base::test::ParseJson(json)); + EXPECT_FALSE(result.has_value()); } { std::string json = R"({"Keys":{"QmA" : {"Type" :"Recursive"}, "QmB" : {"Type" :"Direct"}}})"; - ipfs::GetPinsResult result; - EXPECT_TRUE(IPFSJSONParser::GetGetPinsResultFromJSON(json, &result)); - EXPECT_EQ(result.at("QmA"), "Recursive"); - EXPECT_EQ(result.at("QmB"), "Direct"); + auto result = + IPFSJSONParser::GetGetPinsResultFromJSON(base::test::ParseJson(json)); + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(result->at("QmA"), "Recursive"); + EXPECT_EQ(result->at("QmB"), "Direct"); } } TEST_F(IPFSJSONParserTest, GetRemovePinsResultFromJSONTest) { { std::string json = R"({})"; - ipfs::RemovePinResult result; - EXPECT_FALSE(IPFSJSONParser::GetRemovePinsResultFromJSON(json, &result)); + auto result = IPFSJSONParser::GetRemovePinsResultFromJSON( + base::test::ParseJson(json)); + EXPECT_FALSE(result.has_value()); } { std::string json = R"({"Pins" : {}})"; - ipfs::RemovePinResult result; - EXPECT_FALSE(IPFSJSONParser::GetRemovePinsResultFromJSON(json, &result)); + auto result = IPFSJSONParser::GetRemovePinsResultFromJSON( + base::test::ParseJson(json)); + EXPECT_FALSE(result.has_value()); } { std::string json = R"({"Pins" : []})"; - ipfs::RemovePinResult result; - EXPECT_TRUE(IPFSJSONParser::GetRemovePinsResultFromJSON(json, &result)); - EXPECT_TRUE(result.empty()); + auto result = IPFSJSONParser::GetRemovePinsResultFromJSON( + base::test::ParseJson(json)); + EXPECT_TRUE(result.has_value()); + EXPECT_TRUE(result.value().empty()); } { std::string json = R"({"Pins" : ["QmA", "QmB"]})"; - ipfs::RemovePinResult result; - EXPECT_TRUE(IPFSJSONParser::GetRemovePinsResultFromJSON(json, &result)); - EXPECT_EQ(result.at(0), "QmA"); - EXPECT_EQ(result.at(1), "QmB"); + auto result = IPFSJSONParser::GetRemovePinsResultFromJSON( + base::test::ParseJson(json)); + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(result->at(0), "QmA"); + EXPECT_EQ(result->at(1), "QmB"); } } TEST_F(IPFSJSONParserTest, GetAddPinsResultFromJSONTest) { { std::string json = R"({})"; - ipfs::AddPinResult result; - EXPECT_FALSE(IPFSJSONParser::GetAddPinsResultFromJSON(json, &result)); + auto result = + IPFSJSONParser::GetAddPinsResultFromJSON(base::test::ParseJson(json)); + EXPECT_FALSE(result.has_value()); } { std::string json = R"({"Pins" : {}})"; - ipfs::AddPinResult result; - EXPECT_FALSE(IPFSJSONParser::GetAddPinsResultFromJSON(json, &result)); + auto result = + IPFSJSONParser::GetAddPinsResultFromJSON(base::test::ParseJson(json)); + EXPECT_FALSE(result.has_value()); } { std::string json = R"({"Pins" : []})"; - ipfs::AddPinResult result; - EXPECT_TRUE(IPFSJSONParser::GetAddPinsResultFromJSON(json, &result)); - EXPECT_TRUE(result.pins.empty()); - EXPECT_EQ(result.progress, -1); + auto result = + IPFSJSONParser::GetAddPinsResultFromJSON(base::test::ParseJson(json)); + EXPECT_TRUE(result.has_value()); + EXPECT_TRUE(result->pins.empty()); + EXPECT_EQ(result->progress, -1); } { std::string json = R"({"Pins" : ["QmA", "QmB"]})"; - ipfs::AddPinResult result; - EXPECT_TRUE(IPFSJSONParser::GetAddPinsResultFromJSON(json, &result)); - EXPECT_EQ(result.pins.at(0), "QmA"); - EXPECT_EQ(result.pins.at(1), "QmB"); - EXPECT_EQ(result.progress, -1); + auto result = + IPFSJSONParser::GetAddPinsResultFromJSON(base::test::ParseJson(json)); + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(result->pins.at(0), "QmA"); + EXPECT_EQ(result->pins.at(1), "QmB"); + EXPECT_EQ(result->progress, -1); } { std::string json = R"({"Pins" : ["QmA", "QmB"], "Progress" : 10})"; - ipfs::AddPinResult result; - EXPECT_TRUE(IPFSJSONParser::GetAddPinsResultFromJSON(json, &result)); - EXPECT_EQ(result.pins.at(0), "QmA"); - EXPECT_EQ(result.pins.at(1), "QmB"); - EXPECT_EQ(result.progress, 10); + auto result = + IPFSJSONParser::GetAddPinsResultFromJSON(base::test::ParseJson(json)); + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(result->pins.at(0), "QmA"); + EXPECT_EQ(result->pins.at(1), "QmB"); + EXPECT_EQ(result->progress, 10); } } diff --git a/components/ipfs/ipfs_service.cc b/components/ipfs/ipfs_service.cc index 996c1929ba9e..7f39f58382d0 100644 --- a/components/ipfs/ipfs_service.cc +++ b/components/ipfs/ipfs_service.cc @@ -92,6 +92,11 @@ std::pair LoadConfigFileOnFileTaskRunner( return result; } +base::flat_map GetHeaders(const GURL& url) { + return { + {net::HttpRequestHeaders::kOrigin, url::Origin::Create(url).Serialize()}}; +} + } // namespace namespace ipfs { @@ -381,7 +386,7 @@ void IpfsService::AddPin(const std::vector& cids, bool recursive, AddPinCallback callback) { if (!IsDaemonLaunched()) { - std::move(callback).Run(false, absl::nullopt); + std::move(callback).Run(absl::nullopt); return; } @@ -401,14 +406,13 @@ void IpfsService::AddPin(const std::vector& cids, "POST", gurl, std::string(), std::string(), false, base::BindOnce(&IpfsService::OnPinAddResult, base::Unretained(this), iter, std::move(callback)), - {{net::HttpRequestHeaders::kOrigin, - url::Origin::Create(gurl).Serialize()}}); + GetHeaders(gurl)); } void IpfsService::RemovePin(const std::vector& cids, RemovePinCallback callback) { if (!IsDaemonLaunched()) { - std::move(callback).Run(false, absl::nullopt); + std::move(callback).Run(absl::nullopt); return; } @@ -416,7 +420,6 @@ void IpfsService::RemovePin(const std::vector& cids, for (const auto& cid : cids) { gurl = net::AppendQueryParameter(gurl, kArgQueryParam, cid); } - LOG(ERROR) << "XXZZZ " << gurl.spec(); auto url_loader = std::make_unique( GetIpfsNetworkTrafficAnnotationTag(), url_loader_factory_); @@ -427,8 +430,7 @@ void IpfsService::RemovePin(const std::vector& cids, "POST", gurl, std::string(), std::string(), false, base::BindOnce(&IpfsService::OnPinRemoveResult, base::Unretained(this), iter, std::move(callback)), - {{net::HttpRequestHeaders::kOrigin, - url::Origin::Create(gurl).Serialize()}}); + GetHeaders(gurl)); } void IpfsService::GetPins(const absl::optional>& cids, @@ -436,7 +438,7 @@ void IpfsService::GetPins(const absl::optional>& cids, bool quiet, GetPinsCallback callback) { if (!IsDaemonLaunched()) { - std::move(callback).Run(false, absl::nullopt); + std::move(callback).Run(absl::nullopt); return; } @@ -457,8 +459,7 @@ void IpfsService::GetPins(const absl::optional>& cids, "POST", gurl, std::string(), std::string(), false, base::BindOnce(&IpfsService::OnGetPinsResult, base::Unretained(this), iter, std::move(callback)), - {{net::HttpRequestHeaders::kOrigin, - url::Origin::Create(gurl).Serialize()}}); + GetHeaders(gurl)); } void IpfsService::ImportFileToIpfs(const base::FilePath& path, @@ -605,8 +606,7 @@ void IpfsService::GetConnectedPeers(GetConnectedPeersCallback callback, "POST", gurl, std::string(), std::string(), false, base::BindOnce(&IpfsService::OnGetConnectedPeers, base::Unretained(this), iter, std::move(callback), retries), - {{net::HttpRequestHeaders::kOrigin, - url::Origin::Create(gurl).Serialize()}}); + GetHeaders(gurl)); } base::TimeDelta IpfsService::CalculatePeersRetryTime() { @@ -671,8 +671,7 @@ void IpfsService::GetAddressesConfig(GetAddressesConfigCallback callback) { "POST", gurl, std::string(), std::string(), false, base::BindOnce(&IpfsService::OnGetAddressesConfig, base::Unretained(this), iter, std::move(callback)), - {{net::HttpRequestHeaders::kOrigin, - url::Origin::Create(gurl).Serialize()}}); + GetHeaders(gurl)); } void IpfsService::OnGetAddressesConfig( @@ -844,8 +843,7 @@ void IpfsService::GetRepoStats(GetRepoStatsCallback callback) { "POST", gurl, std::string(), std::string(), false, base::BindOnce(&IpfsService::OnRepoStats, base::Unretained(this), iter, std::move(callback)), - {{net::HttpRequestHeaders::kOrigin, - url::Origin::Create(gurl).Serialize()}}); + GetHeaders(gurl)); } void IpfsService::OnRepoStats(APIRequestList::iterator iter, @@ -885,8 +883,7 @@ void IpfsService::GetNodeInfo(GetNodeInfoCallback callback) { "POST", gurl, std::string(), std::string(), false, base::BindOnce(&IpfsService::OnNodeInfo, base::Unretained(this), iter, std::move(callback)), - {{net::HttpRequestHeaders::kOrigin, - url::Origin::Create(gurl).Serialize()}}); + GetHeaders(gurl)); } void IpfsService::OnNodeInfo(APIRequestList::iterator iter, @@ -926,8 +923,7 @@ void IpfsService::RunGarbageCollection(GarbageCollectionCallback callback) { "POST", gurl, std::string(), std::string(), false, base::BindOnce(&IpfsService::OnGarbageCollection, base::Unretained(this), iter, std::move(callback)), - {{net::HttpRequestHeaders::kOrigin, - url::Origin::Create(gurl).Serialize()}}); + GetHeaders(gurl)); } void IpfsService::OnGarbageCollection( @@ -959,8 +955,7 @@ void IpfsService::PreWarmShareableLink(const GURL& url) { iter->get()->Request("HEAD", url, std::string(), std::string(), false, base::BindOnce(&IpfsService::OnPreWarmComplete, base::Unretained(this), iter), - {{net::HttpRequestHeaders::kOrigin, - url::Origin::Create(url).Serialize()}}); + GetHeaders(url)); } void IpfsService::OnPreWarmComplete( @@ -991,24 +986,21 @@ void IpfsService::OnGetPinsResult( int response_code = response.response_code(); requests_list_.erase(iter); - bool success = response.Is2XXResponseCode(); - - if (!success) { + if (!response.Is2XXResponseCode()) { VLOG(1) << "Fail to get pins, response_code = " << response_code; - std::move(callback).Run(false, absl::nullopt); + std::move(callback).Run(absl::nullopt); return; } - ipfs::GetPinsResult result; - bool parse_result = - IPFSJSONParser::GetGetPinsResultFromJSON(response.body(), &result); + auto parse_result = + IPFSJSONParser::GetGetPinsResultFromJSON(response.value_body()); if (!parse_result) { VLOG(1) << "Fail to get pins, wrong format"; - std::move(callback).Run(false, absl::nullopt); + std::move(callback).Run(absl::nullopt); return; } - std::move(callback).Run(true, result); + std::move(callback).Run(std::move(parse_result)); } void IpfsService::OnPinAddResult( @@ -1018,24 +1010,21 @@ void IpfsService::OnPinAddResult( int response_code = response.response_code(); requests_list_.erase(iter); - bool success = response.Is2XXResponseCode(); - - if (!success) { + if (!response.Is2XXResponseCode()) { VLOG(1) << "Fail to add pin, response_code = " << response_code; - std::move(callback).Run(false, absl::nullopt); + std::move(callback).Run(absl::nullopt); return; } - ipfs::AddPinResult result; - bool parse_result = - IPFSJSONParser::GetAddPinsResultFromJSON(response.body(), &result); + auto parse_result = + IPFSJSONParser::GetAddPinsResultFromJSON(response.value_body()); if (!parse_result) { VLOG(1) << "Fail to add pin service, wrong format"; - std::move(callback).Run(false, absl::nullopt); + std::move(callback).Run(absl::nullopt); return; } - std::move(callback).Run(true, result); + std::move(callback).Run(std::move(parse_result)); } void IpfsService::OnPinRemoveResult( @@ -1045,24 +1034,21 @@ void IpfsService::OnPinRemoveResult( int response_code = response.response_code(); requests_list_.erase(iter); - bool success = response.Is2XXResponseCode(); - - if (!success) { + if (!response.Is2XXResponseCode()) { VLOG(1) << "Fail to remove pin, response_code = " << response_code; - std::move(callback).Run(false, absl::nullopt); + std::move(callback).Run(absl::nullopt); return; } - ipfs::RemovePinResult result; - bool parse_result = - IPFSJSONParser::GetRemovePinsResultFromJSON(response.body(), &result); + auto parse_result = + IPFSJSONParser::GetRemovePinsResultFromJSON(response.value_body()); if (!parse_result) { VLOG(1) << "Fail to remove pin, wrong response format"; - std::move(callback).Run(false, absl::nullopt); + std::move(callback).Run(absl::nullopt); return; } - std::move(callback).Run(true, result); + std::move(callback).Run(std::move(parse_result)); } void IpfsService::ValidateGateway(const GURL& url, BoolCallback callback) { diff --git a/components/ipfs/ipfs_service.h b/components/ipfs/ipfs_service.h index 3a5897b23304..f5e152c7042c 100644 --- a/components/ipfs/ipfs_service.h +++ b/components/ipfs/ipfs_service.h @@ -83,12 +83,11 @@ class IpfsService : public KeyedService, using GarbageCollectionCallback = base::OnceCallback; // Local pins - using AddPinCallback = - base::OnceCallback)>; + using AddPinCallback = base::OnceCallback)>; using RemovePinCallback = - base::OnceCallback)>; + base::OnceCallback)>; using GetPinsCallback = - base::OnceCallback)>; + base::OnceCallback)>; using BoolCallback = base::OnceCallback; using GetConfigCallback = base::OnceCallback; diff --git a/components/ipfs/pin/ipfs_base_pin_service.cc b/components/ipfs/pin/ipfs_base_pin_service.cc index 59f6f78825c7..8d6ca038d3a2 100644 --- a/components/ipfs/pin/ipfs_base_pin_service.cc +++ b/components/ipfs/pin/ipfs_base_pin_service.cc @@ -1,7 +1,7 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #include "brave/components/ipfs/pin/ipfs_base_pin_service.h" @@ -10,19 +10,13 @@ namespace ipfs { -IpfsBaseJob::IpfsBaseJob() {} +IpfsBaseJob::IpfsBaseJob() = default; -IpfsBaseJob::~IpfsBaseJob() {} +IpfsBaseJob::~IpfsBaseJob() = default; -IpfsBasePinService::IpfsBasePinService(PrefService* pref_service, - IpfsService* ipfs_service) - : pref_service_(pref_service), ipfs_service_(ipfs_service) { +IpfsBasePinService::IpfsBasePinService(IpfsService* ipfs_service) + : ipfs_service_(ipfs_service) { ipfs_service_->AddObserver(this); - pref_change_registrar_.Init(pref_service_); - pref_change_registrar_.Add( - kIPFSResolveMethod, - base::BindRepeating(&IpfsBasePinService::MaybeStartDaemon, - base::Unretained(this))); } IpfsBasePinService::IpfsBasePinService() {} @@ -64,6 +58,8 @@ void IpfsBasePinService::DoNextJob() { return; } + DCHECK(!current_job_); + current_job_ = std::move(jobs_.front()); jobs_.pop(); @@ -84,10 +80,6 @@ void IpfsBasePinService::MaybeStartDaemon() { return; } -// if (!ipfs::IsLocalGatewayConfigured(pref_service_)) { -// return; -// } - ipfs_service_->StartDaemonAndLaunch(base::BindOnce( &IpfsBasePinService::OnDaemonStarted, base::Unretained(this))); } diff --git a/components/ipfs/pin/ipfs_base_pin_service.h b/components/ipfs/pin/ipfs_base_pin_service.h index bf46354819f9..3d552d5f5727 100644 --- a/components/ipfs/pin/ipfs_base_pin_service.h +++ b/components/ipfs/pin/ipfs_base_pin_service.h @@ -1,7 +1,7 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #ifndef BRAVE_COMPONENTS_IPFS_PIN_IPFS_BASE_PIN_SERVICE_H_ #define BRAVE_COMPONENTS_IPFS_PIN_IPFS_BASE_PIN_SERVICE_H_ @@ -27,7 +27,7 @@ class IpfsBaseJob { class IpfsBasePinService : public IpfsServiceObserver { public: - IpfsBasePinService(PrefService* pref_service, IpfsService* service); + explicit IpfsBasePinService(IpfsService* service); ~IpfsBasePinService() override; virtual void AddJob(std::unique_ptr job); @@ -50,8 +50,7 @@ class IpfsBasePinService : public IpfsServiceObserver { void DoNextJob(); bool daemon_ready_ = false; - PrefService* pref_service_; - IpfsService* ipfs_service_; + raw_ptr ipfs_service_; PrefChangeRegistrar pref_change_registrar_; std::unique_ptr current_job_; std::queue> jobs_; diff --git a/components/ipfs/pin/ipfs_base_pin_service_unittest.cc b/components/ipfs/pin/ipfs_base_pin_service_unittest.cc index 77811a2b5314..67c57bf523e4 100644 --- a/components/ipfs/pin/ipfs_base_pin_service_unittest.cc +++ b/components/ipfs/pin/ipfs_base_pin_service_unittest.cc @@ -1,7 +1,7 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #include "brave/components/ipfs/pin/ipfs_base_pin_service.h" @@ -36,25 +36,14 @@ class IpfsBasePinServiceTest : public testing::Test { IpfsBasePinServiceTest() = default; void SetUp() override { - auto* registry = pref_service_.registry(); - IpfsService::RegisterProfilePrefs(registry); ipfs_base_pin_service_ = - std::make_unique(GetPrefs(), GetIpfsService()); + std::make_unique(GetIpfsService()); } void TearDown() override { ipfs_base_pin_service_->RemovePrefListenersForTests(); } - void SetLocalNodeEnabled(bool enabled) { - GetPrefs()->SetInteger( - kIPFSResolveMethod, - static_cast(enabled ? IPFSResolveMethodTypes::IPFS_LOCAL - : IPFSResolveMethodTypes::IPFS_DISABLED)); - } - - PrefService* GetPrefs() { return &pref_service_; } - testing::NiceMock* GetIpfsService() { return &ipfs_service_; } @@ -64,7 +53,6 @@ class IpfsBasePinServiceTest : public testing::Test { private: std::unique_ptr ipfs_base_pin_service_; testing::NiceMock ipfs_service_; - TestingPrefServiceSimple pref_service_; content::BrowserTaskEnvironment task_environment_; }; @@ -103,10 +91,4 @@ TEST_F(IpfsBasePinServiceTest, TasksExecuted) { EXPECT_TRUE(second_method_called.value()); } -TEST_F(IpfsBasePinServiceTest, LaunchDaemon_AfterSettingChange) { - SetLocalNodeEnabled(false); - EXPECT_CALL(*GetIpfsService(), StartDaemonAndLaunch(_)).Times(1); - SetLocalNodeEnabled(true); -} - } // namespace ipfs diff --git a/components/ipfs/pin/ipfs_local_pin_service.cc b/components/ipfs/pin/ipfs_local_pin_service.cc index 3e02edf6e4b3..0aeace72b7be 100644 --- a/components/ipfs/pin/ipfs_local_pin_service.cc +++ b/components/ipfs/pin/ipfs_local_pin_service.cc @@ -1,7 +1,7 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #include "brave/components/ipfs/pin/ipfs_local_pin_service.h" @@ -9,6 +9,7 @@ #include #include +#include "base/containers/contains.h" #include "brave/components/ipfs/pref_names.h" #include "components/prefs/scoped_user_pref_update.h" @@ -32,17 +33,15 @@ AddLocalPinJob::AddLocalPinJob(PrefService* prefs_service, AddLocalPinJob::~AddLocalPinJob() {} void AddLocalPinJob::Start() { - ipfs_service_->AddPin( - cids_, true, - base::BindOnce(&AddLocalPinJob::OnAddPinResult, base::Unretained(this))); + ipfs_service_->AddPin(cids_, true, + base::BindOnce(&AddLocalPinJob::OnAddPinResult, + weak_ptr_factory_.GetWeakPtr())); } -void AddLocalPinJob::OnAddPinResult(bool status, - absl::optional result) { - if (status && result) { +void AddLocalPinJob::OnAddPinResult(absl::optional result) { + if (result) { for (const auto& cid : cids_) { - if (std::find(result->pins.begin(), result->pins.end(), cid) == - result->pins.end()) { + if (!base::Contains(result->pins, cid)) { std::move(callback_).Run(false); return; } @@ -53,12 +52,7 @@ void AddLocalPinJob::OnAddPinResult(bool status, base::Value::Dict& update_dict = update->GetDict(); for (const auto& cid : cids_) { - base::Value::List* list = update_dict.FindList(cid); - if (!list) { - update_dict.Set(cid, base::Value::List()); - list = update_dict.FindList(cid); - } - DCHECK(list); + base::Value::List* list = update_dict.EnsureList(cid); list->EraseValue(base::Value(prefix_)); list->Append(base::Value(prefix_)); } @@ -116,26 +110,25 @@ VerifyLocalPinJob::~VerifyLocalPinJob() {} void VerifyLocalPinJob::Start() { ipfs_service_->GetPins(absl::nullopt, kRecursiveMode, true, base::BindOnce(&VerifyLocalPinJob::OnGetPinsResult, - base::Unretained(this))); + weak_ptr_factory_.GetWeakPtr())); } -void VerifyLocalPinJob::OnGetPinsResult(bool status, - absl::optional result) { - if (status && result) { +void VerifyLocalPinJob::OnGetPinsResult(absl::optional result) { + if (result) { DictionaryPrefUpdate update(prefs_service_, kIPFSPinnedCids); base::Value::Dict& update_dict = update->GetDict(); - bool verification_pased = true; + bool verification_passed = true; for (const auto& cid : cids_) { base::Value::List* list = update_dict.FindList(cid); if (!list) { - verification_pased = false; + verification_passed = false; } else { if (result->find(cid) != result->end()) { list->EraseValue(base::Value(prefix_)); list->Append(base::Value(prefix_)); } else { - verification_pased = false; + verification_passed = false; list->EraseValue(base::Value(prefix_)); } if (list->empty()) { @@ -143,7 +136,7 @@ void VerifyLocalPinJob::OnGetPinsResult(bool status, } } } - std::move(callback_).Run(verification_pased); + std::move(callback_).Run(verification_passed); } else { std::move(callback_).Run(absl::nullopt); } @@ -160,12 +153,12 @@ GcJob::~GcJob() {} void GcJob::Start() { ipfs_service_->GetPins( absl::nullopt, kRecursiveMode, true, - base::BindOnce(&GcJob::OnGetPinsResult, base::Unretained(this))); + base::BindOnce(&GcJob::OnGetPinsResult, weak_ptr_factory_.GetWeakPtr())); } -void GcJob::OnGetPinsResult(bool status, absl::optional result) { +void GcJob::OnGetPinsResult(absl::optional result) { std::vector cids_to_delete; - if (status && result) { + if (result) { const base::Value::Dict& dict = prefs_service_->GetDict(kIPFSPinnedCids); for (const auto& pair : result.value()) { const base::Value::List* list = dict.FindList(pair.first); @@ -175,9 +168,9 @@ void GcJob::OnGetPinsResult(bool status, absl::optional result) { } if (!cids_to_delete.empty()) { - ipfs_service_->RemovePin( - cids_to_delete, - base::BindOnce(&GcJob::OnPinsRemovedResult, base::Unretained(this))); + ipfs_service_->RemovePin(cids_to_delete, + base::BindOnce(&GcJob::OnPinsRemovedResult, + weak_ptr_factory_.GetWeakPtr())); } else { std::move(callback_).Run(true); } @@ -186,23 +179,18 @@ void GcJob::OnGetPinsResult(bool status, absl::optional result) { } } -void GcJob::OnPinsRemovedResult(bool status, - absl::optional result) { - if (status && result) { - std::move(callback_).Run(true); - } else { - std::move(callback_).Run(false); - } +void GcJob::OnPinsRemovedResult(absl::optional result) { + std::move(callback_).Run(result.has_value()); } IpfsLocalPinService::IpfsLocalPinService(PrefService* prefs_service, IpfsService* ipfs_service) : prefs_service_(prefs_service), ipfs_service_(ipfs_service) { - ipfs_base_pin_service_ = - std::make_unique(prefs_service_, ipfs_service_); + ipfs_base_pin_service_ = std::make_unique(ipfs_service_); base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, - base::BindOnce(&IpfsLocalPinService::AddGcTask, base::Unretained(this)), + base::BindOnce(&IpfsLocalPinService::AddGcTask, + weak_ptr_factory_.GetWeakPtr()), base::Minutes(1)); } @@ -221,7 +209,7 @@ void IpfsLocalPinService::AddPins(const std::string& prefix, ipfs_base_pin_service_->AddJob(std::make_unique( prefs_service_, ipfs_service_, prefix, cids, base::BindOnce(&IpfsLocalPinService::OnAddJobFinished, - base::Unretained(this), std::move(callback)))); + weak_ptr_factory_.GetWeakPtr(), std::move(callback)))); } void IpfsLocalPinService::RemovePins(const std::string& prefix, @@ -229,7 +217,7 @@ void IpfsLocalPinService::RemovePins(const std::string& prefix, ipfs_base_pin_service_->AddJob(std::make_unique( prefs_service_, prefix, base::BindOnce(&IpfsLocalPinService::OnRemovePinsFinished, - base::Unretained(this), std::move(callback)))); + weak_ptr_factory_.GetWeakPtr(), std::move(callback)))); } void IpfsLocalPinService::ValidatePins(const std::string& prefix, @@ -238,7 +226,7 @@ void IpfsLocalPinService::ValidatePins(const std::string& prefix, ipfs_base_pin_service_->AddJob(std::make_unique( prefs_service_, ipfs_service_, prefix, cids, base::BindOnce(&IpfsLocalPinService::OnValidateJobFinished, - base::Unretained(this), std::move(callback)))); + weak_ptr_factory_.GetWeakPtr(), std::move(callback)))); } void IpfsLocalPinService::OnRemovePinsFinished(RemovePinCallback callback, @@ -247,7 +235,8 @@ void IpfsLocalPinService::OnRemovePinsFinished(RemovePinCallback callback, if (status) { base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, - base::BindOnce(&IpfsLocalPinService::AddGcTask, base::Unretained(this)), + base::BindOnce(&IpfsLocalPinService::AddGcTask, + weak_ptr_factory_.GetWeakPtr()), base::Minutes(1)); } ipfs_base_pin_service_->OnJobDone(status); @@ -273,7 +262,7 @@ void IpfsLocalPinService::AddGcTask() { ipfs_base_pin_service_->AddJob(std::make_unique( prefs_service_, ipfs_service_, base::BindOnce(&IpfsLocalPinService::OnGcFinishedCallback, - base::Unretained(this)))); + weak_ptr_factory_.GetWeakPtr()))); } void IpfsLocalPinService::OnGcFinishedCallback(bool status) { diff --git a/components/ipfs/pin/ipfs_local_pin_service.h b/components/ipfs/pin/ipfs_local_pin_service.h index 826673b8192d..afcd8196f111 100644 --- a/components/ipfs/pin/ipfs_local_pin_service.h +++ b/components/ipfs/pin/ipfs_local_pin_service.h @@ -1,7 +1,7 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #ifndef BRAVE_COMPONENTS_IPFS_PIN_IPFS_LOCAL_PIN_SERVICE_H_ #define BRAVE_COMPONENTS_IPFS_PIN_IPFS_LOCAL_PIN_SERVICE_H_ @@ -35,13 +35,14 @@ class AddLocalPinJob : public IpfsBaseJob { void Start() override; private: - void OnAddPinResult(bool status, absl::optional result); + void OnAddPinResult(absl::optional result); - PrefService* prefs_service_; - IpfsService* ipfs_service_; + raw_ptr prefs_service_; + raw_ptr ipfs_service_; std::string prefix_; std::vector cids_; AddPinCallback callback_; + base::WeakPtrFactory weak_ptr_factory_{this}; }; class RemoveLocalPinJob : public IpfsBaseJob { @@ -54,9 +55,10 @@ class RemoveLocalPinJob : public IpfsBaseJob { void Start() override; private: - PrefService* prefs_service_; + raw_ptr prefs_service_; std::string prefix_; RemovePinCallback callback_; + base::WeakPtrFactory weak_ptr_factory_{this}; }; class VerifyLocalPinJob : public IpfsBaseJob { @@ -71,13 +73,14 @@ class VerifyLocalPinJob : public IpfsBaseJob { void Start() override; private: - void OnGetPinsResult(bool status, absl::optional result); + void OnGetPinsResult(absl::optional result); - PrefService* prefs_service_; - IpfsService* ipfs_service_; + raw_ptr prefs_service_; + raw_ptr ipfs_service_; std::string prefix_; std::vector cids_; ValidatePinsCallback callback_; + base::WeakPtrFactory weak_ptr_factory_{this}; }; class GcJob : public IpfsBaseJob { @@ -90,12 +93,13 @@ class GcJob : public IpfsBaseJob { void Start() override; private: - void OnGetPinsResult(bool status, absl::optional result); - void OnPinsRemovedResult(bool status, absl::optional result); + void OnGetPinsResult(absl::optional result); + void OnPinsRemovedResult(absl::optional result); - PrefService* prefs_service_; - IpfsService* ipfs_service_; + raw_ptr prefs_service_; + raw_ptr ipfs_service_; GcCallback callback_; + base::WeakPtrFactory weak_ptr_factory_{this}; }; class IpfsLocalPinService : public KeyedService { @@ -126,8 +130,10 @@ class IpfsLocalPinService : public KeyedService { bool gc_task_posted_ = false; std::unique_ptr ipfs_base_pin_service_; - PrefService* prefs_service_; - IpfsService* ipfs_service_; + raw_ptr prefs_service_; + raw_ptr ipfs_service_; + + base::WeakPtrFactory weak_ptr_factory_{this}; }; } // namespace ipfs diff --git a/components/ipfs/pin/ipfs_local_pin_service_unittest.cc b/components/ipfs/pin/ipfs_local_pin_service_unittest.cc index f28fa02fd2c0..ecda844f28e5 100644 --- a/components/ipfs/pin/ipfs_local_pin_service_unittest.cc +++ b/components/ipfs/pin/ipfs_local_pin_service_unittest.cc @@ -1,7 +1,7 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #include "brave/components/ipfs/pin/ipfs_local_pin_service.h" @@ -21,6 +21,8 @@ using testing::_; namespace ipfs { +namespace { + class MockIpfsService : public IpfsService { public: MockIpfsService() = default; @@ -49,6 +51,8 @@ class MockIpfsBasePinService : public IpfsBasePinService { } }; +} // namespace + class IpfsLocalPinServiceTest : public testing::Test { public: IpfsLocalPinServiceTest() = default; @@ -85,7 +89,7 @@ TEST_F(IpfsLocalPinServiceTest, AddLocalPinJobTest) { IpfsService::AddPinCallback callback) { AddPinResult result; result.pins = cids; - std::move(callback).Run(true, result); + std::move(callback).Run(result); })); absl::optional success; @@ -112,7 +116,7 @@ TEST_F(IpfsLocalPinServiceTest, AddLocalPinJobTest) { IpfsService::AddPinCallback callback) { AddPinResult result; result.pins = cids; - std::move(callback).Run(true, result); + std::move(callback).Run(result); })); absl::optional success; @@ -140,7 +144,7 @@ TEST_F(IpfsLocalPinServiceTest, AddLocalPinJobTest) { IpfsService::AddPinCallback callback) { AddPinResult result; result.pins = {"Qma", "Qmb", "Qmc"}; - std::move(callback).Run(true, result); + std::move(callback).Run(result); })); absl::optional success; @@ -166,7 +170,7 @@ TEST_F(IpfsLocalPinServiceTest, AddLocalPinJobTest) { .WillByDefault(::testing::Invoke( [](const std::vector& cids, bool recursive, IpfsService::AddPinCallback callback) { - std::move(callback).Run(false, absl::nullopt); + std::move(callback).Run(absl::nullopt); })); absl::optional success; @@ -278,7 +282,7 @@ TEST_F(IpfsLocalPinServiceTest, VerifyLocalPinJobTest) { IpfsService::GetPinsCallback callback) { GetPinsResult result = {{"Qma", "Recursive"}, {"Qmb", "Recursive"}}; - std::move(callback).Run(true, result); + std::move(callback).Run(result); })); absl::optional success; @@ -301,7 +305,7 @@ TEST_F(IpfsLocalPinServiceTest, VerifyLocalPinJobTest) { GetPinsResult result = {{"Qma", "Recursive"}, {"Qmb", "Recursive"}, {"Qmc", "Recursive"}}; - std::move(callback).Run(true, result); + std::move(callback).Run(result); })); absl::optional success; @@ -321,7 +325,7 @@ TEST_F(IpfsLocalPinServiceTest, VerifyLocalPinJobTest) { const std::string& type, bool quiet, IpfsService::GetPinsCallback callback) { GetPinsResult result = {}; - std::move(callback).Run(true, result); + std::move(callback).Run(result); })); absl::optional success = false; @@ -348,7 +352,7 @@ TEST_F(IpfsLocalPinServiceTest, VerifyLocalPinJobTest) { [](const absl::optional>& cid, const std::string& type, bool quiet, IpfsService::GetPinsCallback callback) { - std::move(callback).Run(false, absl::nullopt); + std::move(callback).Run(absl::nullopt); })); job.Start(); @@ -387,7 +391,7 @@ TEST_F(IpfsLocalPinServiceTest, GcJobTest) { GetPinsResult result = {{"Qma", "Recursive"}, {"Qmb", "Recursive"}, {"Qmc", "Recursive"}}; - std::move(callback).Run(true, result); + std::move(callback).Run(result); })); EXPECT_CALL(*GetIpfsService(), RemovePin(_, _)).Times(0); @@ -412,7 +416,7 @@ TEST_F(IpfsLocalPinServiceTest, GcJobTest) { EXPECT_FALSE(cid.has_value()); EXPECT_TRUE(quiet); GetPinsResult result = {{"Qm1", "Recursive"}, {"Qm2", "Recursive"}}; - std::move(callback).Run(true, result); + std::move(callback).Run(result); })); EXPECT_CALL(*GetIpfsService(), RemovePin(_, _)).Times(1); @@ -424,7 +428,7 @@ TEST_F(IpfsLocalPinServiceTest, GcJobTest) { EXPECT_EQ(cid[0], "Qm1"); EXPECT_EQ(cid[1], "Qm2"); RemovePinResult result = cid; - std::move(callback).Run(true, result); + std::move(callback).Run(result); })); job.Start(); @@ -443,7 +447,7 @@ TEST_F(IpfsLocalPinServiceTest, GcJobTest) { [](const absl::optional>& cid, const std::string& type, bool quiet, IpfsService::GetPinsCallback callback) { - std::move(callback).Run(false, absl::nullopt); + std::move(callback).Run(absl::nullopt); })); EXPECT_CALL(*GetIpfsService(), RemovePin(_, _)).Times(0); diff --git a/components/ipfs/pin/ipfs_pin_rpc_types.cc b/components/ipfs/pin/ipfs_pin_rpc_types.cc index b7707013080e..c09cea3c9db3 100644 --- a/components/ipfs/pin/ipfs_pin_rpc_types.cc +++ b/components/ipfs/pin/ipfs_pin_rpc_types.cc @@ -1,16 +1,18 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #include "brave/components/ipfs/pin/ipfs_pin_rpc_types.h" namespace ipfs { -AddPinResult::AddPinResult() {} +AddPinResult::AddPinResult() = default; -AddPinResult::~AddPinResult() {} +AddPinResult::~AddPinResult() = default; AddPinResult::AddPinResult(const AddPinResult& other) = default; +AddPinResult& AddPinResult::operator=(const AddPinResult&) = default; + } // namespace ipfs diff --git a/components/ipfs/pin/ipfs_pin_rpc_types.h b/components/ipfs/pin/ipfs_pin_rpc_types.h index 2ad0b362e107..263dd7214ce4 100644 --- a/components/ipfs/pin/ipfs_pin_rpc_types.h +++ b/components/ipfs/pin/ipfs_pin_rpc_types.h @@ -1,7 +1,7 @@ -/* Copyright (c) 2022 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Copyright (c) 2022 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. #ifndef BRAVE_COMPONENTS_IPFS_PIN_IPFS_PIN_RPC_TYPES_H_ #define BRAVE_COMPONENTS_IPFS_PIN_IPFS_PIN_RPC_TYPES_H_ @@ -16,8 +16,9 @@ struct AddPinResult { AddPinResult(); ~AddPinResult(); AddPinResult(const AddPinResult&); + AddPinResult& operator=(const AddPinResult&); std::vector pins; - int progress; + int progress = 0; }; using GetPinsResult = std::map; From a79e00c637ce275d709e81995a2f5970e670c89f Mon Sep 17 00:00:00 2001 From: oisupov Date: Fri, 23 Dec 2022 01:50:03 +0400 Subject: [PATCH 09/15] Review fix --- .../browser/brave_wallet_auto_pin_service.cc | 7 +- .../browser/brave_wallet_pin_service.cc | 116 ++++++++++++++---- .../browser/brave_wallet_pin_service.h | 11 +- .../brave_wallet_pin_service_unittest.cc | 9 +- 4 files changed, 105 insertions(+), 38 deletions(-) diff --git a/components/brave_wallet/browser/brave_wallet_auto_pin_service.cc b/components/brave_wallet/browser/brave_wallet_auto_pin_service.cc index 7cc5df091825..dd7b0d8670d9 100644 --- a/components/brave_wallet/browser/brave_wallet_auto_pin_service.cc +++ b/components/brave_wallet/browser/brave_wallet_auto_pin_service.cc @@ -76,10 +76,13 @@ void BraveWalletAutoPinService::OnTokenListResolved( if (!token->is_nft) { continue; } - std::string current_token_path = + auto current_token_path = BraveWalletPinService::GetPath(absl::nullopt, token); + if (!current_token_path) { + continue; + } - auto it = known_tokens.find(current_token_path); + auto it = known_tokens.find(current_token_path.value()); if (it != known_tokens.end()) { known_tokens.erase(it); } diff --git a/components/brave_wallet/browser/brave_wallet_pin_service.cc b/components/brave_wallet/browser/brave_wallet_pin_service.cc index 70bd31e70676..f205d4142bff 100644 --- a/components/brave_wallet/browser/brave_wallet_pin_service.cc +++ b/components/brave_wallet/browser/brave_wallet_pin_service.cc @@ -177,9 +177,19 @@ void BraveWalletPinService::AddObserver( } // static -std::string BraveWalletPinService::GetPath( +absl::optional BraveWalletPinService::GetPath( const absl::optional& service, const BlockchainTokenPtr& token) { + if (service && base::ContainsOnlyChars(service.value(), ".")) { + return absl::nullopt; + } + if (base::ContainsOnlyChars(token->contract_address, ".")) { + return absl::nullopt; + } + if (base::ContainsOnlyChars(token->token_id, ".")) { + return absl::nullopt; + } + DCHECK(!base::ContainsOnlyChars(token->chain_id, ".")); return base::StrCat({kNftPart, ".", service.value_or(kLocalService), ".", base::NumberToString(static_cast(token->coin)), ".", token->chain_id, ".", token->contract_address, ".", @@ -247,9 +257,18 @@ void BraveWalletPinService::Validate(BlockchainTokenPtr token, return; } + auto path = GetPath(absl::nullopt, token); + if (!path) { + std::move(callback).Run( + false, + mojom::PinError::New(mojom::WalletPinServiceErrorCode::ERR_WRONG_TOKEN, + "Wrong token data")); + return; + } + if (!service) { local_pin_service_->ValidatePins( - GetPath(absl::nullopt, token), cids.value(), + path.value(), cids.value(), base::BindOnce(&BraveWalletPinService::OnTokenValidated, base::Unretained(this), service, std::move(callback), std::move(token))); @@ -314,16 +333,24 @@ void BraveWalletPinService::RemovePin( return; } + auto path = GetPath(absl::nullopt, token); + if (!path) { + std::move(callback).Run( + false, + mojom::PinError::New(mojom::WalletPinServiceErrorCode::ERR_WRONG_TOKEN, + "Wrong token data")); + return; + } + SetTokenStatus(service, token, mojom::TokenPinStatusCode::STATUS_UNPINNING_IN_PROGRESS, nullptr); if (!service) { local_pin_service_->RemovePins( - GetPath(service, token), - base::BindOnce(&BraveWalletPinService::OnPinsRemoved, - base::Unretained(this), service, std::move(callback), - std::move(token))); + path.value(), base::BindOnce(&BraveWalletPinService::OnPinsRemoved, + base::Unretained(this), service, + std::move(callback), std::move(token))); } else { // Remote pinning not implemented yet std::move(callback).Run(false, nullptr); @@ -407,6 +434,15 @@ void BraveWalletPinService::OnTokenMetaDataReceived( } } + auto path = GetPath(service, token); + if (!path) { + std::move(callback).Run( + false, + mojom::PinError::New(mojom::WalletPinServiceErrorCode::ERR_WRONG_TOKEN, + "Wrong token data")); + return; + } + CreateToken(service, token, cids); SetTokenStatus(service, token, mojom::TokenPinStatusCode::STATUS_PINNING_IN_PROGRESS, @@ -414,7 +450,7 @@ void BraveWalletPinService::OnTokenMetaDataReceived( if (!service) { local_pin_service_->AddPins( - GetPath(service, token), cids, + path.value(), cids, base::BindOnce(&BraveWalletPinService::OnTokenPinned, base::Unretained(this), absl::nullopt, std::move(callback), std::move(token))); @@ -465,10 +501,15 @@ void BraveWalletPinService::OnTokenValidated( std::move(callback).Run(true, nullptr); } -void BraveWalletPinService::CreateToken( +bool BraveWalletPinService::CreateToken( const absl::optional& service, const mojom::BlockchainTokenPtr& token, const std::vector& cids) { + auto path = GetPath(service, token); + if (!path) { + return false; + } + DictionaryPrefUpdate update(prefs_, kPinnedErc721Assets); base::Value::Dict& update_dict = update->GetDict(); @@ -483,57 +524,68 @@ void BraveWalletPinService::CreateToken( token_data.Set(kAssetStatus, StatusToString(mojom::TokenPinStatusCode::STATUS_NOT_PINNED)); - update_dict.SetByDottedPath(GetPath(service, token), std::move(token_data)); + update_dict.SetByDottedPath(path.value(), std::move(token_data)); + return true; } -void BraveWalletPinService::RemoveToken( +bool BraveWalletPinService::RemoveToken( const absl::optional& service, const mojom::BlockchainTokenPtr& token) { + auto path = GetPath(service, token); + if (!path) { + return false; + } + { DictionaryPrefUpdate update(prefs_, kPinnedErc721Assets); base::Value::Dict& update_dict = update->GetDict(); - update_dict.RemoveByDottedPath(GetPath(service, token)); + update_dict.RemoveByDottedPath(path.value()); } for (const auto& observer : observers_) { observer->OnTokenStatusChanged(service, token.Clone(), GetTokenStatus(service, token)); } + return true; } -void BraveWalletPinService::SetTokenStatus( +bool BraveWalletPinService::SetTokenStatus( const absl::optional& service, const mojom::BlockchainTokenPtr& token, mojom::TokenPinStatusCode status, const mojom::PinErrorPtr& error) { + auto path = GetPath(service, token); + if (!path) { + return false; + } + { DictionaryPrefUpdate update(prefs_, kPinnedErc721Assets); base::Value::Dict& update_dict = update->GetDict(); - update_dict.SetByDottedPath(GetPath(service, token) + "." + kAssetStatus, + update_dict.SetByDottedPath(path.value() + "." + kAssetStatus, StatusToString(status)); if (error) { base::Value::Dict error_dict; error_dict.Set(kErrorCode, ErrorCodeToString(error->error_code)); error_dict.Set(kErrorMessage, error->message); - update_dict.SetByDottedPath(GetPath(service, token) + "." + kError, + update_dict.SetByDottedPath(path.value() + "." + kError, std::move(error_dict)); } else { - update_dict.RemoveByDottedPath(GetPath(service, token) + "." + kError); + update_dict.RemoveByDottedPath(path.value() + "." + kError); } if (status == mojom::TokenPinStatusCode::STATUS_PINNED) { - update_dict.SetByDottedPath( - GetPath(service, token) + "." + kValidateTimestamp, - base::TimeToValue(base::Time::Now())); + update_dict.SetByDottedPath(path.value() + "." + kValidateTimestamp, + base::TimeToValue(base::Time::Now())); } else { - update_dict.RemoveByDottedPath(GetPath(service, token) + "." + - kValidateTimestamp); + update_dict.RemoveByDottedPath(path.value() + "." + kValidateTimestamp); } } for (const auto& observer : observers_) { observer->OnTokenStatusChanged(service, token.Clone(), GetTokenStatus(service, token)); } + return true; } absl::optional> BraveWalletPinService::ResolvePinItems( @@ -542,9 +594,13 @@ absl::optional> BraveWalletPinService::ResolvePinItems( const base::Value::Dict& pinned_assets_pref = prefs_->GetDict(kPinnedErc721Assets); - const std::string& path = GetPath(service, token); + auto path = GetPath(service, token); + if (!path) { + return absl::nullopt; + } - auto* token_data_as_dict = pinned_assets_pref.FindDictByDottedPath(path); + auto* token_data_as_dict = + pinned_assets_pref.FindDictByDottedPath(path.value()); if (!token_data_as_dict) { return absl::nullopt; } @@ -568,9 +624,13 @@ mojom::TokenPinStatusPtr BraveWalletPinService::GetTokenStatus( const base::Value::Dict& pinned_assets_pref = prefs_->GetDict(kPinnedErc721Assets); - const std::string& path = GetPath(service, token); + auto path = GetPath(service, token); + if (!path) { + return nullptr; + } - auto* token_data_as_dict = pinned_assets_pref.FindDictByDottedPath(path); + auto* token_data_as_dict = + pinned_assets_pref.FindDictByDottedPath(path.value()); if (!token_data_as_dict) { return mojom::TokenPinStatus::New( mojom::TokenPinStatusCode::STATUS_NOT_PINNED, nullptr, base::Time()); @@ -618,9 +678,13 @@ absl::optional BraveWalletPinService::GetLastValidateTime( const base::Value::Dict& pinned_assets_pref = prefs_->GetDict(kPinnedErc721Assets); - const std::string& path = GetPath(service, token); + auto path = GetPath(service, token); + if (!path) { + return absl::nullopt; + } - auto* token_data_as_dict = pinned_assets_pref.FindDictByDottedPath(path); + auto* token_data_as_dict = + pinned_assets_pref.FindDictByDottedPath(path.value()); if (!token_data_as_dict) { return absl::nullopt; } diff --git a/components/brave_wallet/browser/brave_wallet_pin_service.h b/components/brave_wallet/browser/brave_wallet_pin_service.h index de2ab62a7d76..6075589c1b8b 100644 --- a/components/brave_wallet/browser/brave_wallet_pin_service.h +++ b/components/brave_wallet/browser/brave_wallet_pin_service.h @@ -43,8 +43,9 @@ class BraveWalletPinService : public KeyedService, mojo::PendingRemote MakeRemote(); void Bind(mojo::PendingReceiver receiver); - static std::string GetPath(const absl::optional& service, - const BlockchainTokenPtr& token); + static absl::optional GetPath( + const absl::optional& service, + const BlockchainTokenPtr& token); static BlockchainTokenPtr TokenFromPath(const std::string& path); static absl::optional ServiceFromPath(const std::string& path); @@ -80,12 +81,12 @@ class BraveWalletPinService : public KeyedService, const absl::optional& service); private: - void CreateToken(const absl::optional& service, + bool CreateToken(const absl::optional& service, const mojom::BlockchainTokenPtr& token, const std::vector& cids); - void RemoveToken(const absl::optional& service, + bool RemoveToken(const absl::optional& service, const mojom::BlockchainTokenPtr& token); - void SetTokenStatus(const absl::optional& service, + bool SetTokenStatus(const absl::optional& service, const mojom::BlockchainTokenPtr& token, mojom::TokenPinStatusCode, const mojom::PinErrorPtr& error); diff --git a/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc b/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc index 05304697357f..7839ae2053ee 100644 --- a/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc +++ b/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc @@ -179,9 +179,8 @@ TEST_F(BraveWalletPinServiceTest, AddPin) { *(token_record->FindString("status"))); EXPECT_EQ(nullptr, token_record->FindDict("error")); EXPECT_EQ(expected_cids, *(token_record->FindList("cids"))); - EXPECT_EQ( - 123u, - base::ValueToTime(token_record->Find("validate_timestamp"))->ToTimeT()); + EXPECT_EQ(base::Time::FromTimeT(123u), + base::ValueToTime(token_record->Find("validate_timestamp"))); } { @@ -529,7 +528,7 @@ TEST_F(BraveWalletPinServiceTest, GetPath) { token->token_id = "0x2"; token->chain_id = "mainnet"; auto path = BraveWalletPinService::GetPath(absl::nullopt, token); - EXPECT_EQ("nft.local.60.mainnet.abc.0x2", path); + EXPECT_EQ("nft.local.60.mainnet.abc.0x2", path.value()); } { @@ -539,7 +538,7 @@ TEST_F(BraveWalletPinServiceTest, GetPath) { token->token_id = "0x2"; token->chain_id = "mainnet"; auto path = BraveWalletPinService::GetPath("nftstorage", token); - EXPECT_EQ("nft.nftstorage.60.mainnet.abc.0x2", path); + EXPECT_EQ("nft.nftstorage.60.mainnet.abc.0x2", path.value()); } } From 8c436f2702a7ca6c224e5db928c822c1511a0011 Mon Sep 17 00:00:00 2001 From: oisupov Date: Mon, 2 Jan 2023 15:50:41 +0400 Subject: [PATCH 10/15] Review fix --- .../brave_wallet_auto_pin_service_factory.cc | 8 +++++++- browser/ipfs/test/ipfs_service_browsertest.cc | 6 ++++-- browser/ui/webui/ipfs_ui.cc | 6 ++++-- .../brave_wallet/browser/brave_wallet_pin_service.cc | 2 +- .../browser/brave_wallet_pin_service_unittest.cc | 10 ++++------ components/brave_wallet/browser/json_rpc_service.cc | 1 - components/ipfs/ipfs_navigation_throttle.cc | 3 ++- components/ipfs/ipfs_onboarding_page.cc | 2 +- components/ipfs/ipfs_service.cc | 6 ++++-- components/ipfs/ipfs_service.h | 2 +- components/ipfs/pin/ipfs_base_pin_service_unittest.cc | 3 ++- 11 files changed, 30 insertions(+), 19 deletions(-) diff --git a/browser/brave_wallet/brave_wallet_auto_pin_service_factory.cc b/browser/brave_wallet/brave_wallet_auto_pin_service_factory.cc index d2459dd51bff..b59db19648d5 100644 --- a/browser/brave_wallet/brave_wallet_auto_pin_service_factory.cc +++ b/browser/brave_wallet/brave_wallet_auto_pin_service_factory.cc @@ -38,7 +38,13 @@ BraveWalletAutoPinServiceFactory::GetForContext( return mojo::PendingRemote(); } - return GetServiceForContext(context)->MakeRemote(); + auto* service = GetServiceForContext(context); + + if (!service) { + return mojo::PendingRemote(); + } + + return service->MakeRemote(); } // static diff --git a/browser/ipfs/test/ipfs_service_browsertest.cc b/browser/ipfs/test/ipfs_service_browsertest.cc index 613768eae021..2b18727c9b09 100644 --- a/browser/ipfs/test/ipfs_service_browsertest.cc +++ b/browser/ipfs/test/ipfs_service_browsertest.cc @@ -707,7 +707,8 @@ IN_PROC_BROWSER_TEST_F(IpfsServiceBrowserTest, GetConnectedPeers) { base::Unretained(this))); ipfs_service()->GetConnectedPeers( base::BindOnce(&IpfsServiceBrowserTest::OnGetConnectedPeersSuccess, - base::Unretained(this))); + base::Unretained(this)), + absl::nullopt); WaitForRequest(); } @@ -717,7 +718,8 @@ IN_PROC_BROWSER_TEST_F(IpfsServiceBrowserTest, GetConnectedPeersServerError) { base::Unretained(this))); ipfs_service()->GetConnectedPeers( base::BindOnce(&IpfsServiceBrowserTest::OnGetConnectedPeersFail, - base::Unretained(this))); + base::Unretained(this)), + absl::nullopt); WaitForRequest(); } diff --git a/browser/ui/webui/ipfs_ui.cc b/browser/ui/webui/ipfs_ui.cc index 1138bbae3231..b0523b25fe07 100644 --- a/browser/ui/webui/ipfs_ui.cc +++ b/browser/ui/webui/ipfs_ui.cc @@ -127,8 +127,10 @@ void IPFSDOMHandler::HandleGetConnectedPeers(const base::Value::List& args) { if (!service) { return; } - service->GetConnectedPeers(base::BindOnce( - &IPFSDOMHandler::OnGetConnectedPeers, weak_ptr_factory_.GetWeakPtr())); + service->GetConnectedPeers( + base::BindOnce(&IPFSDOMHandler::OnGetConnectedPeers, + weak_ptr_factory_.GetWeakPtr()), + absl::nullopt); } void IPFSDOMHandler::OnGetConnectedPeers( diff --git a/components/brave_wallet/browser/brave_wallet_pin_service.cc b/components/brave_wallet/browser/brave_wallet_pin_service.cc index f205d4142bff..ab2077a455df 100644 --- a/components/brave_wallet/browser/brave_wallet_pin_service.cc +++ b/components/brave_wallet/browser/brave_wallet_pin_service.cc @@ -50,7 +50,7 @@ absl::optional StringToStatus( return mojom::TokenPinStatusCode::STATUS_PINNING_IN_PROGRESS; } else if (status == "unpinning_in_progress") { return mojom::TokenPinStatusCode::STATUS_UNPINNING_IN_PROGRESS; - } else if (status == "unpining_failed") { + } else if (status == "unpinning_failed") { return mojom::TokenPinStatusCode::STATUS_UNPINNING_FAILED; } else if (status == "pinning_pendig") { return mojom::TokenPinStatusCode::STATUS_PINNING_PENDING; diff --git a/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc b/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc index 7839ae2053ee..ff9428850193 100644 --- a/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc +++ b/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc @@ -338,9 +338,8 @@ TEST_F(BraveWalletPinServiceTest, ValidatePin) { GetPrefs() ->GetDict(kPinnedErc721Assets) .FindDictByDottedPath(kMonkey1Path); - EXPECT_EQ( - 345u, - base::ValueToTime(token_record->Find("validate_timestamp"))->ToTimeT()); + EXPECT_EQ(base::Time::FromTimeT(345u), + base::ValueToTime(token_record->Find("validate_timestamp"))); } { @@ -368,9 +367,8 @@ TEST_F(BraveWalletPinServiceTest, ValidatePin) { GetPrefs() ->GetDict(kPinnedErc721Assets) .FindDictByDottedPath(kMonkey1Path); - EXPECT_EQ( - 345u, - base::ValueToTime(token_record->Find("validate_timestamp"))->ToTimeT()); + EXPECT_EQ(base::Time::FromTimeT(345u), + base::ValueToTime(token_record->Find("validate_timestamp"))); } { diff --git a/components/brave_wallet/browser/json_rpc_service.cc b/components/brave_wallet/browser/json_rpc_service.cc index b1a5006ea556..3004959eee89 100644 --- a/components/brave_wallet/browser/json_rpc_service.cc +++ b/components/brave_wallet/browser/json_rpc_service.cc @@ -2123,7 +2123,6 @@ void JsonRpcService::OnGetEthTokenUri(GetEthTokenUriCallback callback, std::move(callback).Run(GURL(), error, error_message); return; } - std::string token_url_spec = url.spec(); std::move(callback).Run(url, mojom::ProviderError::kSuccess, ""); } diff --git a/components/ipfs/ipfs_navigation_throttle.cc b/components/ipfs/ipfs_navigation_throttle.cc index 29b5feac87a9..f8f0d8b15c8c 100644 --- a/components/ipfs/ipfs_navigation_throttle.cc +++ b/components/ipfs/ipfs_navigation_throttle.cc @@ -145,7 +145,8 @@ IpfsNavigationThrottle::WillFailRequest() { void IpfsNavigationThrottle::GetConnectedPeers() { ipfs_service_->GetConnectedPeers( base::BindOnce(&IpfsNavigationThrottle::OnGetConnectedPeers, - weak_ptr_factory_.GetWeakPtr())); + weak_ptr_factory_.GetWeakPtr()), + absl::nullopt); } void IpfsNavigationThrottle::OnGetConnectedPeers( diff --git a/components/ipfs/ipfs_onboarding_page.cc b/components/ipfs/ipfs_onboarding_page.cc index 7f28eb8a3aca..ee31f9f3f78c 100644 --- a/components/ipfs/ipfs_onboarding_page.cc +++ b/components/ipfs/ipfs_onboarding_page.cc @@ -133,7 +133,7 @@ void IPFSOnboardingPage::ReportDaemonStopped() { } void IPFSOnboardingPage::GetConnectedPeers() { - ipfs_service_->GetConnectedPeers(base::NullCallback()); + ipfs_service_->GetConnectedPeers(base::NullCallback(), absl::nullopt); } bool IPFSOnboardingPage::IsLocalNodeMode() { diff --git a/components/ipfs/ipfs_service.cc b/components/ipfs/ipfs_service.cc index 7f39f58382d0..c47b21c266fd 100644 --- a/components/ipfs/ipfs_service.cc +++ b/components/ipfs/ipfs_service.cc @@ -582,8 +582,9 @@ void IpfsService::OnImportFinished(ipfs::ImportCompletedCallback callback, importers_.erase(key); } #endif + void IpfsService::GetConnectedPeers(GetConnectedPeersCallback callback, - int retries) { + absl::optional retries) { if (!IsDaemonLaunched()) { if (callback) std::move(callback).Run(false, std::vector{}); @@ -605,7 +606,8 @@ void IpfsService::GetConnectedPeers(GetConnectedPeersCallback callback, iter->get()->Request( "POST", gurl, std::string(), std::string(), false, base::BindOnce(&IpfsService::OnGetConnectedPeers, base::Unretained(this), - iter, std::move(callback), retries), + iter, std::move(callback), + retries.value_or(kPeersDefaultRetries)), GetHeaders(gurl)); } diff --git a/components/ipfs/ipfs_service.h b/components/ipfs/ipfs_service.h index f5e152c7042c..42f307d5df8c 100644 --- a/components/ipfs/ipfs_service.h +++ b/components/ipfs/ipfs_service.h @@ -150,7 +150,7 @@ class IpfsService : public KeyedService, BoolCallback callback); #endif virtual void GetConnectedPeers(GetConnectedPeersCallback callback, - int retries = kPeersDefaultRetries); + absl::optional retries); void GetAddressesConfig(GetAddressesConfigCallback callback); virtual void LaunchDaemon(BoolCallback callback); void ShutdownDaemon(BoolCallback callback); diff --git a/components/ipfs/pin/ipfs_base_pin_service_unittest.cc b/components/ipfs/pin/ipfs_base_pin_service_unittest.cc index 67c57bf523e4..dc992117f855 100644 --- a/components/ipfs/pin/ipfs_base_pin_service_unittest.cc +++ b/components/ipfs/pin/ipfs_base_pin_service_unittest.cc @@ -28,7 +28,8 @@ class MockIpfsService : public IpfsService { MOCK_METHOD1(StartDaemonAndLaunch, void(base::OnceCallback)); MOCK_METHOD2(GetConnectedPeers, - void(IpfsService::GetConnectedPeersCallback, int)); + void(IpfsService::GetConnectedPeersCallback, + absl::optional)); }; class IpfsBasePinServiceTest : public testing::Test { From f0ce50a40b5f97b6bf4ba55e3229fdbb264798d1 Mon Sep 17 00:00:00 2001 From: oisupov Date: Mon, 2 Jan 2023 18:25:40 +0400 Subject: [PATCH 11/15] Add method to resolve local node status --- .../brave_wallet_pin_service_factory.cc | 4 ++- .../brave_wallet_auto_pin_service_unittest.cc | 3 +- .../browser/brave_wallet_pin_service.cc | 32 +++++++++++++++++-- .../browser/brave_wallet_pin_service.h | 16 ++++++++-- .../brave_wallet_pin_service_unittest.cc | 17 +++++++++- .../brave_wallet/common/brave_wallet.mojom | 2 ++ .../common/wallet_api_proxy.ts | 2 ++ .../pin/ipfs_base_pin_service_unittest.cc | 4 +++ 8 files changed, 71 insertions(+), 9 deletions(-) diff --git a/browser/brave_wallet/brave_wallet_pin_service_factory.cc b/browser/brave_wallet/brave_wallet_pin_service_factory.cc index bb47ffe5294f..6e6343d96bb5 100644 --- a/browser/brave_wallet/brave_wallet_pin_service_factory.cc +++ b/browser/brave_wallet/brave_wallet_pin_service_factory.cc @@ -66,6 +66,7 @@ BraveWalletPinServiceFactory::BraveWalletPinServiceFactory() BrowserContextDependencyManager::GetInstance()) { DependsOn(brave_wallet::JsonRpcServiceFactory::GetInstance()); DependsOn(ipfs::IpfsLocalPinServiceFactory::GetInstance()); + DependsOn(ipfs::IpfsServiceFactory::GetInstance()); } BraveWalletPinServiceFactory::~BraveWalletPinServiceFactory() = default; @@ -75,7 +76,8 @@ KeyedService* BraveWalletPinServiceFactory::BuildServiceInstanceFor( return new BraveWalletPinService( user_prefs::UserPrefs::Get(context), JsonRpcServiceFactory::GetServiceForContext(context), - ipfs::IpfsLocalPinServiceFactory::GetServiceForContext(context)); + ipfs::IpfsLocalPinServiceFactory::GetServiceForContext(context), + ipfs::IpfsServiceFactory::GetForContext(context)); } content::BrowserContext* BraveWalletPinServiceFactory::GetBrowserContextToUse( diff --git a/components/brave_wallet/browser/brave_wallet_auto_pin_service_unittest.cc b/components/brave_wallet/browser/brave_wallet_auto_pin_service_unittest.cc index 7595c0370b47..b8262a88f61d 100644 --- a/components/brave_wallet/browser/brave_wallet_auto_pin_service_unittest.cc +++ b/components/brave_wallet/browser/brave_wallet_auto_pin_service_unittest.cc @@ -33,8 +33,7 @@ namespace { class MockBraveWalletPinService : public BraveWalletPinService { public: - MockBraveWalletPinService() - : BraveWalletPinService(nullptr, nullptr, nullptr) {} + MockBraveWalletPinService() : BraveWalletPinService() {} MOCK_METHOD3(AddPin, void(mojom::BlockchainTokenPtr, const absl::optional&, diff --git a/components/brave_wallet/browser/brave_wallet_pin_service.cc b/components/brave_wallet/browser/brave_wallet_pin_service.cc index ab2077a455df..b5eace6eac24 100644 --- a/components/brave_wallet/browser/brave_wallet_pin_service.cc +++ b/components/brave_wallet/browser/brave_wallet_pin_service.cc @@ -152,12 +152,21 @@ std::string ErrorCodeToString( BraveWalletPinService::BraveWalletPinService( PrefService* prefs, JsonRpcService* service, - ipfs::IpfsLocalPinService* local_pin_service) + ipfs::IpfsLocalPinService* local_pin_service, + IpfsService* ipfs_service) : prefs_(prefs), json_rpc_service_(service), - local_pin_service_(local_pin_service) {} + local_pin_service_(local_pin_service), + ipfs_service_(ipfs_service) { + ipfs_service_->AddObserver(this); +} + +// For testing +BraveWalletPinService::BraveWalletPinService() = default; -BraveWalletPinService::~BraveWalletPinService() {} +BraveWalletPinService::~BraveWalletPinService() { + ipfs_service_->RemoveObserver(this); +} mojo::PendingRemote BraveWalletPinService::MakeRemote() { @@ -278,6 +287,23 @@ void BraveWalletPinService::Validate(BlockchainTokenPtr token, } } +void BraveWalletPinService::IsLocalNodeRunning( + IsLocalNodeRunningCallback callback) { + std::move(callback).Run(ipfs_service_->IsDaemonLaunched()); +} + +void BraveWalletPinService::OnIpfsLaunched(bool result, int64_t pid) { + for (const auto& observer : observers_) { + observer->OnLocalNodeStatusChanged(result); + } +} + +void BraveWalletPinService::OnIpfsShutdown() { + for (const auto& observer : observers_) { + observer->OnLocalNodeStatusChanged(false); + } +} + void BraveWalletPinService::MarkAsPendingForPinning( const mojom::BlockchainTokenPtr& token, const absl::optional& service) { diff --git a/components/brave_wallet/browser/brave_wallet_pin_service.h b/components/brave_wallet/browser/brave_wallet_pin_service.h index 6075589c1b8b..c3816daa4461 100644 --- a/components/brave_wallet/browser/brave_wallet_pin_service.h +++ b/components/brave_wallet/browser/brave_wallet_pin_service.h @@ -33,11 +33,13 @@ std::string ErrorCodeToString( const mojom::WalletPinServiceErrorCode& error_code); class BraveWalletPinService : public KeyedService, - public brave_wallet::mojom::WalletPinService { + public brave_wallet::mojom::WalletPinService, + public ipfs::IpfsServiceObserver { public: BraveWalletPinService(PrefService* prefs, JsonRpcService* service, - ipfs::IpfsLocalPinService* local_pin_service); + ipfs::IpfsLocalPinService* local_pin_service, + IpfsService* ipfs_service); ~BraveWalletPinService() override; mojo::PendingRemote MakeRemote(); @@ -63,6 +65,7 @@ class BraveWalletPinService : public KeyedService, void Validate(BlockchainTokenPtr token, const absl::optional& service, ValidateCallback callback) override; + void IsLocalNodeRunning(IsLocalNodeRunningCallback callback) override; virtual void MarkAsPendingForPinning( const mojom::BlockchainTokenPtr& token, @@ -80,6 +83,10 @@ class BraveWalletPinService : public KeyedService, virtual std::set GetTokens( const absl::optional& service); + protected: + // For testing + BraveWalletPinService(); + private: bool CreateToken(const absl::optional& service, const mojom::BlockchainTokenPtr& token, @@ -122,6 +129,10 @@ class BraveWalletPinService : public KeyedService, mojom::ProviderError error, const std::string& error_message); + // ipfs::IpfsServiceObserver + void OnIpfsLaunched(bool result, int64_t pid) override; + void OnIpfsShutdown() override; + mojo::ReceiverSet receivers_; mojo::RemoteSet observers_; @@ -131,6 +142,7 @@ class BraveWalletPinService : public KeyedService, // JsonRpcService is used to fetch token metadata raw_ptr json_rpc_service_; raw_ptr local_pin_service_; + raw_ptr ipfs_service_; }; } // namespace brave_wallet diff --git a/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc b/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc index ff9428850193..f7904f898afc 100644 --- a/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc +++ b/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc @@ -91,6 +91,15 @@ class MockJsonRpcService : public JsonRpcService { ~MockJsonRpcService() override {} }; +class MockIpfsService : public IpfsService { + public: + MockIpfsService() = default; + ~MockIpfsService() override = default; + + MOCK_METHOD1(AddObserver, void(ipfs::IpfsServiceObserver* observer)); + MOCK_METHOD0(IsDaemonLaunched, bool()); +}; + } // namespace class BraveWalletPinServiceTest : public testing::Test { @@ -104,7 +113,8 @@ class BraveWalletPinServiceTest : public testing::Test { auto* registry = pref_service_.registry(); registry->RegisterDictionaryPref(kPinnedErc721Assets); brave_wallet_pin_service_ = std::make_unique( - GetPrefs(), GetJsonRpcService(), GetIpfsLocalPinService()); + GetPrefs(), GetJsonRpcService(), GetIpfsLocalPinService(), + GetIpfsService()); } PrefService* GetPrefs() { return &pref_service_; } @@ -117,8 +127,13 @@ class BraveWalletPinServiceTest : public testing::Test { return &ipfs_local_pin_service_; } + testing::NiceMock* GetIpfsService() { + return &ipfs_service_; + } + testing::NiceMock ipfs_local_pin_service_; testing::NiceMock json_rpc_service_; + testing::NiceMock ipfs_service_; std::unique_ptr brave_wallet_pin_service_; TestingPrefServiceSimple pref_service_; diff --git a/components/brave_wallet/common/brave_wallet.mojom b/components/brave_wallet/common/brave_wallet.mojom index b349345062bd..cf577283ebac 100644 --- a/components/brave_wallet/common/brave_wallet.mojom +++ b/components/brave_wallet/common/brave_wallet.mojom @@ -252,6 +252,7 @@ struct TokenPinOverview { interface BraveWalletPinServiceObserver { OnTokenStatusChanged(string? service, BlockchainToken token, TokenPinStatus status); + OnLocalNodeStatusChanged(bool running); }; interface WalletPinService { @@ -265,6 +266,7 @@ interface WalletPinService { PinError? error); Validate(BlockchainToken token, string? service) => (bool result, PinError? error); + IsLocalNodeRunning() => (bool result); }; interface WalletAutoPinService { diff --git a/components/brave_wallet_ui/common/wallet_api_proxy.ts b/components/brave_wallet_ui/common/wallet_api_proxy.ts index 0efd69716206..2432d58121ca 100644 --- a/components/brave_wallet_ui/common/wallet_api_proxy.ts +++ b/components/brave_wallet_ui/common/wallet_api_proxy.ts @@ -133,6 +133,8 @@ export class WalletApiProxy { addBraveWalletPinServiceObserver (store: Store) { const braveWalletServiceObserverReceiver = new BraveWallet.BraveWalletPinServiceObserverReceiver({ onTokenStatusChanged: function (service, token, status) { + }, + onLocalNodeStatusChanged: function (status) { } }) this.braveWalletPinService.addObserver(braveWalletServiceObserverReceiver.$.bindNewPipeAndPassRemote()) diff --git a/components/ipfs/pin/ipfs_base_pin_service_unittest.cc b/components/ipfs/pin/ipfs_base_pin_service_unittest.cc index dc992117f855..f95cef81e9e2 100644 --- a/components/ipfs/pin/ipfs_base_pin_service_unittest.cc +++ b/components/ipfs/pin/ipfs_base_pin_service_unittest.cc @@ -20,6 +20,8 @@ using testing::_; namespace ipfs { +namespace { + class MockIpfsService : public IpfsService { public: MockIpfsService() = default; @@ -32,6 +34,8 @@ class MockIpfsService : public IpfsService { absl::optional)); }; +} // namespace + class IpfsBasePinServiceTest : public testing::Test { public: IpfsBasePinServiceTest() = default; From 737e96c08b26d4579ca5157d933a0075556d157b Mon Sep 17 00:00:00 2001 From: oisupov Date: Fri, 6 Jan 2023 13:54:29 +0400 Subject: [PATCH 12/15] Fix builds --- .../brave_wallet/browser/brave_wallet_pin_service.cc | 4 +++- .../brave_wallet/browser/brave_wallet_pin_service.h | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/components/brave_wallet/browser/brave_wallet_pin_service.cc b/components/brave_wallet/browser/brave_wallet_pin_service.cc index b5eace6eac24..8f19e89d1f59 100644 --- a/components/brave_wallet/browser/brave_wallet_pin_service.cc +++ b/components/brave_wallet/browser/brave_wallet_pin_service.cc @@ -165,7 +165,9 @@ BraveWalletPinService::BraveWalletPinService( BraveWalletPinService::BraveWalletPinService() = default; BraveWalletPinService::~BraveWalletPinService() { - ipfs_service_->RemoveObserver(this); + if (ipfs_service_) { + ipfs_service_->RemoveObserver(this); + } } mojo::PendingRemote diff --git a/components/brave_wallet/browser/brave_wallet_pin_service.h b/components/brave_wallet/browser/brave_wallet_pin_service.h index c3816daa4461..cc2b572b8105 100644 --- a/components/brave_wallet/browser/brave_wallet_pin_service.h +++ b/components/brave_wallet/browser/brave_wallet_pin_service.h @@ -137,12 +137,12 @@ class BraveWalletPinService : public KeyedService, mojo::RemoteSet observers_; // Prefs service is used to store list of pinned items - raw_ptr prefs_; + raw_ptr prefs_ = nullptr; // JsonRpcService is used to fetch token metadata - raw_ptr json_rpc_service_; - raw_ptr local_pin_service_; - raw_ptr ipfs_service_; + raw_ptr json_rpc_service_ = nullptr; + raw_ptr local_pin_service_ = nullptr; + raw_ptr ipfs_service_ = nullptr; }; } // namespace brave_wallet From 0a34eed49077b74cfb79085bd79ef286fc74f8fc Mon Sep 17 00:00:00 2001 From: oisupov Date: Mon, 16 Jan 2023 19:23:58 +0400 Subject: [PATCH 13/15] Review fix --- .../browser/brave_wallet_prefs.cc | 2 +- components/ipfs/pin/ipfs_base_pin_service.cc | 3 +- components/ipfs/pin/ipfs_base_pin_service.h | 2 + components/ipfs/pin/ipfs_local_pin_service.cc | 109 +++++++++--------- 4 files changed, 60 insertions(+), 56 deletions(-) diff --git a/components/brave_wallet/browser/brave_wallet_prefs.cc b/components/brave_wallet/browser/brave_wallet_prefs.cc index 840442318d87..af1520cc2ebb 100644 --- a/components/brave_wallet/browser/brave_wallet_prefs.cc +++ b/components/brave_wallet/browser/brave_wallet_prefs.cc @@ -128,7 +128,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { registry->RegisterListPref(kBraveWalletP3AWeeklyStorage); registry->RegisterDictionaryPref(kPinnedErc721Assets); - registry->RegisterBooleanPref(kAutoPinEnabled, true); + registry->RegisterBooleanPref(kAutoPinEnabled, false); } void RegisterProfilePrefsForMigration( diff --git a/components/ipfs/pin/ipfs_base_pin_service.cc b/components/ipfs/pin/ipfs_base_pin_service.cc index 8d6ca038d3a2..7f4bed51553d 100644 --- a/components/ipfs/pin/ipfs_base_pin_service.cc +++ b/components/ipfs/pin/ipfs_base_pin_service.cc @@ -81,10 +81,11 @@ void IpfsBasePinService::MaybeStartDaemon() { } ipfs_service_->StartDaemonAndLaunch(base::BindOnce( - &IpfsBasePinService::OnDaemonStarted, base::Unretained(this))); + &IpfsBasePinService::OnDaemonStarted, weak_ptr_factory_.GetWeakPtr())); } void IpfsBasePinService::OnDaemonStarted() { + // Ensure that daemon service is fully initialized ipfs_service_->GetConnectedPeers(base::NullCallback(), 2); } diff --git a/components/ipfs/pin/ipfs_base_pin_service.h b/components/ipfs/pin/ipfs_base_pin_service.h index 3d552d5f5727..a4375fff49da 100644 --- a/components/ipfs/pin/ipfs_base_pin_service.h +++ b/components/ipfs/pin/ipfs_base_pin_service.h @@ -54,6 +54,8 @@ class IpfsBasePinService : public IpfsServiceObserver { PrefChangeRegistrar pref_change_registrar_; std::unique_ptr current_job_; std::queue> jobs_; + + base::WeakPtrFactory weak_ptr_factory_{this}; }; } // namespace ipfs diff --git a/components/ipfs/pin/ipfs_local_pin_service.cc b/components/ipfs/pin/ipfs_local_pin_service.cc index 0aeace72b7be..ff55124c1f47 100644 --- a/components/ipfs/pin/ipfs_local_pin_service.cc +++ b/components/ipfs/pin/ipfs_local_pin_service.cc @@ -39,28 +39,29 @@ void AddLocalPinJob::Start() { } void AddLocalPinJob::OnAddPinResult(absl::optional result) { - if (result) { - for (const auto& cid : cids_) { - if (!base::Contains(result->pins, cid)) { - std::move(callback_).Run(false); - return; - } + if (!result) { + std::move(callback_).Run(false); + return; + } + + for (const auto& cid : cids_) { + if (!base::Contains(result->pins, cid)) { + std::move(callback_).Run(false); + return; } + } - { - DictionaryPrefUpdate update(prefs_service_, kIPFSPinnedCids); - base::Value::Dict& update_dict = update->GetDict(); + { + DictionaryPrefUpdate update(prefs_service_, kIPFSPinnedCids); + base::Value::Dict& update_dict = update->GetDict(); - for (const auto& cid : cids_) { - base::Value::List* list = update_dict.EnsureList(cid); - list->EraseValue(base::Value(prefix_)); - list->Append(base::Value(prefix_)); - } + for (const auto& cid : cids_) { + base::Value::List* list = update_dict.EnsureList(cid); + list->EraseValue(base::Value(prefix_)); + list->Append(base::Value(prefix_)); } - std::move(callback_).Run(true); - } else { - std::move(callback_).Run(false); } + std::move(callback_).Run(true); } RemoveLocalPinJob::RemoveLocalPinJob(PrefService* prefs_service, @@ -114,32 +115,32 @@ void VerifyLocalPinJob::Start() { } void VerifyLocalPinJob::OnGetPinsResult(absl::optional result) { - if (result) { - DictionaryPrefUpdate update(prefs_service_, kIPFSPinnedCids); - base::Value::Dict& update_dict = update->GetDict(); - - bool verification_passed = true; - for (const auto& cid : cids_) { - base::Value::List* list = update_dict.FindList(cid); - if (!list) { - verification_passed = false; + if (!result) { + std::move(callback_).Run(absl::nullopt); + return; + } + DictionaryPrefUpdate update(prefs_service_, kIPFSPinnedCids); + base::Value::Dict& update_dict = update->GetDict(); + + bool verification_passed = true; + for (const auto& cid : cids_) { + base::Value::List* list = update_dict.FindList(cid); + if (!list) { + verification_passed = false; + } else { + if (result->find(cid) != result->end()) { + list->EraseValue(base::Value(prefix_)); + list->Append(base::Value(prefix_)); } else { - if (result->find(cid) != result->end()) { - list->EraseValue(base::Value(prefix_)); - list->Append(base::Value(prefix_)); - } else { - verification_passed = false; - list->EraseValue(base::Value(prefix_)); - } - if (list->empty()) { - update_dict.Remove(cid); - } + verification_passed = false; + list->EraseValue(base::Value(prefix_)); + } + if (list->empty()) { + update_dict.Remove(cid); } } - std::move(callback_).Run(verification_passed); - } else { - std::move(callback_).Run(absl::nullopt); } + std::move(callback_).Run(verification_passed); } GcJob::GcJob(PrefService* prefs_service, @@ -157,25 +158,25 @@ void GcJob::Start() { } void GcJob::OnGetPinsResult(absl::optional result) { + if (!result) { + std::move(callback_).Run(false); + return; + } std::vector cids_to_delete; - if (result) { - const base::Value::Dict& dict = prefs_service_->GetDict(kIPFSPinnedCids); - for (const auto& pair : result.value()) { - const base::Value::List* list = dict.FindList(pair.first); - if (!list || list->empty()) { - cids_to_delete.push_back(pair.first); - } + const base::Value::Dict& dict = prefs_service_->GetDict(kIPFSPinnedCids); + for (const auto& pair : result.value()) { + const base::Value::List* list = dict.FindList(pair.first); + if (!list || list->empty()) { + cids_to_delete.push_back(pair.first); } + } - if (!cids_to_delete.empty()) { - ipfs_service_->RemovePin(cids_to_delete, - base::BindOnce(&GcJob::OnPinsRemovedResult, - weak_ptr_factory_.GetWeakPtr())); - } else { - std::move(callback_).Run(true); - } + if (!cids_to_delete.empty()) { + ipfs_service_->RemovePin(cids_to_delete, + base::BindOnce(&GcJob::OnPinsRemovedResult, + weak_ptr_factory_.GetWeakPtr())); } else { - std::move(callback_).Run(false); + std::move(callback_).Run(true); } } From 411a98b267d51527c37deeeee604923220789e87 Mon Sep 17 00:00:00 2001 From: oisupov Date: Fri, 20 Jan 2023 03:53:40 +0400 Subject: [PATCH 14/15] Review fix --- .../crypto_wallet/util/AsyncUtils.java | 2 +- browser/brave_wallet/BUILD.gn | 2 +- .../brave_wallet_auto_pin_service_factory.cc | 5 +- .../brave_wallet_auto_pin_service_factory.h | 2 +- .../brave_wallet_pin_service_factory.cc | 9 +- .../brave_wallet_pin_service_factory.h | 2 +- .../ipfs/ipfs_local_pin_service_factory.cc | 5 +- browser/ipfs/ipfs_local_pin_service_factory.h | 2 +- components/brave_wallet/browser/BUILD.gn | 2 +- .../browser/brave_wallet_auto_pin_service.cc | 50 +++-- .../browser/brave_wallet_auto_pin_service.h | 37 ++-- .../brave_wallet_auto_pin_service_unittest.cc | 51 +++-- .../brave_wallet/browser/brave_wallet_p3a.cc | 2 +- .../browser/brave_wallet_pin_service.cc | 196 +++++++++++------- .../browser/brave_wallet_pin_service.h | 52 ++--- .../brave_wallet_pin_service_unittest.cc | 111 +++++----- .../browser/brave_wallet_prefs.cc | 4 +- .../browser/brave_wallet_service.cc | 2 +- .../browser/brave_wallet_utils.cc | 8 +- .../brave_wallet/browser/brave_wallet_utils.h | 2 +- components/brave_wallet/browser/pref_names.cc | 2 +- components/brave_wallet/browser/pref_names.h | 2 +- .../brave_wallet/common/brave_wallet.mojom | 24 ++- components/ipfs/BUILD.gn | 2 +- components/ipfs/ipfs_json_parser.cc | 7 +- components/ipfs/ipfs_json_parser_unittest.cc | 14 ++ components/ipfs/pin/ipfs_base_pin_service.cc | 11 +- components/ipfs/pin/ipfs_base_pin_service.h | 8 +- .../pin/ipfs_base_pin_service_unittest.cc | 6 +- components/ipfs/pin/ipfs_local_pin_service.cc | 51 ++--- components/ipfs/pin/ipfs_local_pin_service.h | 44 +++- .../pin/ipfs_local_pin_service_unittest.cc | 2 +- components/ipfs/pin/ipfs_pin_rpc_types.cc | 2 +- components/ipfs/pin/ipfs_pin_rpc_types.h | 2 +- 34 files changed, 420 insertions(+), 303 deletions(-) diff --git a/android/java/org/chromium/chrome/browser/crypto_wallet/util/AsyncUtils.java b/android/java/org/chromium/chrome/browser/crypto_wallet/util/AsyncUtils.java index 90f4d198cfa3..1e50cd7c4059 100644 --- a/android/java/org/chromium/chrome/browser/crypto_wallet/util/AsyncUtils.java +++ b/android/java/org/chromium/chrome/browser/crypto_wallet/util/AsyncUtils.java @@ -423,7 +423,7 @@ public GetNftErc721MetadataContext(Runnable responseCompleteCallback) { } @Override - public void call(String erc721Metadata, Integer errorCode, String errorMessage) { + public void call(String tokenUrl, String erc721Metadata, Integer errorCode, String errorMessage) { this.tokenMetadata = erc721Metadata; this.errorCode = errorCode; this.errorMessage = errorMessage; diff --git a/browser/brave_wallet/BUILD.gn b/browser/brave_wallet/BUILD.gn index 55b6c6a23415..b3315b061960 100644 --- a/browser/brave_wallet/BUILD.gn +++ b/browser/brave_wallet/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2022 The Brave Authors. All rights reserved. +# Copyright (c) 2019 The Brave Authors. All rights reserved. # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this file, # You can obtain one at https://mozilla.org/MPL/2.0/. diff --git a/browser/brave_wallet/brave_wallet_auto_pin_service_factory.cc b/browser/brave_wallet/brave_wallet_auto_pin_service_factory.cc index b59db19648d5..e9954c3aba51 100644 --- a/browser/brave_wallet/brave_wallet_auto_pin_service_factory.cc +++ b/browser/brave_wallet/brave_wallet_auto_pin_service_factory.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. @@ -9,10 +9,9 @@ #include #include "brave/browser/brave_wallet/brave_wallet_context_utils.h" - #include "brave/browser/brave_wallet/brave_wallet_pin_service_factory.h" #include "brave/browser/brave_wallet/brave_wallet_service_factory.h" -// TODO(cypt4) : Refactor brave/browser into separate component (#27486) +// TODO(cypt4) : Refactor brave/browser/ipfs into separate component (#27486) #include "brave/browser/ipfs/ipfs_service_factory.h" // nogncheck #include "brave/components/brave_wallet/browser/brave_wallet_pin_service.h" diff --git a/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h b/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h index f35a8d3c4aea..c2778d2771c8 100644 --- a/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h +++ b/browser/brave_wallet/brave_wallet_auto_pin_service_factory.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. diff --git a/browser/brave_wallet/brave_wallet_pin_service_factory.cc b/browser/brave_wallet/brave_wallet_pin_service_factory.cc index 6e6343d96bb5..f49edf983367 100644 --- a/browser/brave_wallet/brave_wallet_pin_service_factory.cc +++ b/browser/brave_wallet/brave_wallet_pin_service_factory.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. @@ -34,7 +34,12 @@ BraveWalletPinServiceFactory::GetForContext(content::BrowserContext* context) { return mojo::PendingRemote(); } - return GetServiceForContext(context)->MakeRemote(); + auto* service = GetServiceForContext(context); + if (!service) { + return mojo::PendingRemote(); + } + + return service->MakeRemote(); } // static diff --git a/browser/brave_wallet/brave_wallet_pin_service_factory.h b/browser/brave_wallet/brave_wallet_pin_service_factory.h index 2b1b0c4cd565..35759571f282 100644 --- a/browser/brave_wallet/brave_wallet_pin_service_factory.h +++ b/browser/brave_wallet/brave_wallet_pin_service_factory.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. diff --git a/browser/ipfs/ipfs_local_pin_service_factory.cc b/browser/ipfs/ipfs_local_pin_service_factory.cc index 92af1458cf6c..aea731930338 100644 --- a/browser/ipfs/ipfs_local_pin_service_factory.cc +++ b/browser/ipfs/ipfs_local_pin_service_factory.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. @@ -25,6 +25,9 @@ IpfsLocalPinServiceFactory* IpfsLocalPinServiceFactory::GetInstance() { // static IpfsLocalPinService* IpfsLocalPinServiceFactory::GetServiceForContext( content::BrowserContext* context) { + if (!ipfs::IpfsServiceFactory::IsIpfsEnabled(context)) { + return nullptr; + } return static_cast( GetInstance()->GetServiceForBrowserContext(context, true)); } diff --git a/browser/ipfs/ipfs_local_pin_service_factory.h b/browser/ipfs/ipfs_local_pin_service_factory.h index 30ec5b3cb414..1ddcad2840c9 100644 --- a/browser/ipfs/ipfs_local_pin_service_factory.h +++ b/browser/ipfs/ipfs_local_pin_service_factory.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. diff --git a/components/brave_wallet/browser/BUILD.gn b/components/brave_wallet/browser/BUILD.gn index 86c7e5788fb2..75dee59a939a 100644 --- a/components/brave_wallet/browser/BUILD.gn +++ b/components/brave_wallet/browser/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2023 The Brave Authors. All rights reserved. +# Copyright (c) 2019 The Brave Authors. All rights reserved. # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this file, # You can obtain one at https://mozilla.org/MPL/2.0/. diff --git a/components/brave_wallet/browser/brave_wallet_auto_pin_service.cc b/components/brave_wallet/browser/brave_wallet_auto_pin_service.cc index dd7b0d8670d9..1217a041d13c 100644 --- a/components/brave_wallet/browser/brave_wallet_auto_pin_service.cc +++ b/components/brave_wallet/browser/brave_wallet_auto_pin_service.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. @@ -9,12 +9,13 @@ namespace brave_wallet { -IntentData::IntentData(const BlockchainTokenPtr& token, - Operation operation, - absl::optional service) +BraveWalletAutoPinService::IntentData::IntentData( + const BlockchainTokenPtr& token, + Operation operation, + absl::optional service) : token(token.Clone()), operation(operation), service(std::move(service)) {} -IntentData::~IntentData() {} +BraveWalletAutoPinService::IntentData::~IntentData() = default; BraveWalletAutoPinService::BraveWalletAutoPinService( PrefService* prefs, @@ -23,6 +24,7 @@ BraveWalletAutoPinService::BraveWalletAutoPinService( : pref_service_(prefs), brave_wallet_service_(brave_wallet_service), brave_wallet_pin_service_(brave_wallet_pin_service) { + DCHECK(brave_wallet_service); Restore(); brave_wallet_service->AddTokenObserver( token_observer_.BindNewPipeAndPassRemote()); @@ -43,41 +45,44 @@ BraveWalletAutoPinService::MakeRemote() { } void BraveWalletAutoPinService::OnTokenAdded(BlockchainTokenPtr token) { - if (!token->is_nft) { + if (!BraveWalletPinService::IsTokenSupportedForPinning(token)) { return; } if (!IsAutoPinEnabled()) { return; } - PostPinToken(std::move(token), base::OnceCallback()); + PostPinToken(std::move(token)); } void BraveWalletAutoPinService::OnTokenRemoved(BlockchainTokenPtr token) { - if (!token->is_nft) { + if (!BraveWalletPinService::IsTokenSupportedForPinning(token)) { return; } base::EraseIf(queue_, [&token](const std::unique_ptr& intent) { return intent->token == token; }); - PostUnpinToken(std::move(token), base::OnceCallback()); + PostUnpinToken(std::move(token)); } void BraveWalletAutoPinService::Restore() { - brave_wallet_service_->GetAllUserAssets(base::BindOnce( - &BraveWalletAutoPinService::OnTokenListResolved, base::Unretained(this))); + brave_wallet_service_->GetAllUserAssets( + base::BindOnce(&BraveWalletAutoPinService::OnTokenListResolved, + weak_ptr_factory_.GetWeakPtr())); } void BraveWalletAutoPinService::OnTokenListResolved( std::vector token_list) { bool autopin_enabled = IsAutoPinEnabled(); + // Resolves list of user tokens. + // Check whether they are pinned or not and posts corresponding tasks. std::set known_tokens = brave_wallet_pin_service_->GetTokens(absl::nullopt); for (const auto& token : token_list) { - if (!token->is_nft) { + if (!BraveWalletPinService::IsTokenSupportedForPinning(token)) { continue; } auto current_token_path = - BraveWalletPinService::GetPath(absl::nullopt, token); + BraveWalletPinService::GetTokenPrefPath(absl::nullopt, token); if (!current_token_path) { continue; } @@ -113,6 +118,8 @@ void BraveWalletAutoPinService::OnTokenListResolved( AddOrExecute(std::make_unique(token, Operation::kDelete, absl::nullopt)); } else if (status->code == mojom::TokenPinStatusCode::STATUS_PINNED) { + // Pinned tokens should be verified for entirety time to time. + // We should check that related CIDs are still pinned. auto t1 = status->validate_time; if ((base::Time::Now() - t1) > base::Days(1) || t1 > base::Time::Now()) { AddOrExecute(std::make_unique(token, Operation::kValidate, @@ -121,8 +128,11 @@ void BraveWalletAutoPinService::OnTokenListResolved( } } + // Tokens that were previously pinned but not listed in the wallet should be + // unpinned. for (const auto& t : known_tokens) { - mojom::BlockchainTokenPtr token = BraveWalletPinService::TokenFromPath(t); + mojom::BlockchainTokenPtr token = + BraveWalletPinService::TokenFromPrefPath(t); if (token) { AddOrExecute(std::make_unique(token, Operation::kDelete, absl::nullopt)); @@ -132,15 +142,13 @@ void BraveWalletAutoPinService::OnTokenListResolved( CheckQueue(); } -void BraveWalletAutoPinService::PostPinToken(BlockchainTokenPtr token, - PostPinTokenCallback callback) { +void BraveWalletAutoPinService::PostPinToken(BlockchainTokenPtr token) { queue_.push_back( std::make_unique(token, Operation::kAdd, absl::nullopt)); CheckQueue(); } -void BraveWalletAutoPinService::PostUnpinToken(BlockchainTokenPtr token, - PostPinTokenCallback callback) { +void BraveWalletAutoPinService::PostUnpinToken(BlockchainTokenPtr token) { queue_.push_back( std::make_unique(token, Operation::kDelete, absl::nullopt)); CheckQueue(); @@ -151,7 +159,7 @@ void BraveWalletAutoPinService::ValidateToken( brave_wallet_pin_service_->Validate( data->token->Clone(), data->service, base::BindOnce(&BraveWalletAutoPinService::OnValidateTaskFinished, - base::Unretained(this))); + weak_ptr_factory_.GetWeakPtr())); } void BraveWalletAutoPinService::PinToken( @@ -159,7 +167,7 @@ void BraveWalletAutoPinService::PinToken( brave_wallet_pin_service_->AddPin( data->token->Clone(), data->service, base::BindOnce(&BraveWalletAutoPinService::OnTaskFinished, - base::Unretained(this))); + weak_ptr_factory_.GetWeakPtr())); } void BraveWalletAutoPinService::UnpinToken( @@ -167,7 +175,7 @@ void BraveWalletAutoPinService::UnpinToken( brave_wallet_pin_service_->RemovePin( data->token->Clone(), data->service, base::BindOnce(&BraveWalletAutoPinService::OnTaskFinished, - base::Unretained(this))); + weak_ptr_factory_.GetWeakPtr())); } void BraveWalletAutoPinService::AddOrExecute(std::unique_ptr data) { diff --git a/components/brave_wallet/browser/brave_wallet_auto_pin_service.h b/components/brave_wallet/browser/brave_wallet_auto_pin_service.h index 9397d93930a2..e34ab3b94dbf 100644 --- a/components/brave_wallet/browser/brave_wallet_auto_pin_service.h +++ b/components/brave_wallet/browser/brave_wallet_auto_pin_service.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. @@ -30,19 +30,6 @@ using brave_wallet::mojom::BlockchainTokenPtr; namespace brave_wallet { -enum Operation { kAdd = 0, kDelete = 1, kValidate = 2 }; - -struct IntentData { - BlockchainTokenPtr token; - Operation operation; - absl::optional service; - size_t attempt = 0; - IntentData(const BlockchainTokenPtr& token, - Operation operation, - absl::optional service); - ~IntentData(); -}; - class BraveWalletAutoPinService : public KeyedService, public brave_wallet::mojom::WalletAutoPinService, @@ -59,16 +46,28 @@ class BraveWalletAutoPinService void SetAutoPinEnabled(bool enabled) override; void IsAutoPinEnabled(IsAutoPinEnabledCallback callback) override; - void PostPinToken(BlockchainTokenPtr token, - PostPinTokenCallback callback) override; - void PostUnpinToken(BlockchainTokenPtr token, - PostUnpinTokenCallback callback) override; - // BraveWalletServiceTokenObserver void OnTokenAdded(mojom::BlockchainTokenPtr token) override; void OnTokenRemoved(mojom::BlockchainTokenPtr token) override; private: + enum Operation { kAdd = 0, kDelete = 1, kValidate = 2 }; + + struct IntentData { + BlockchainTokenPtr token; + Operation operation; + absl::optional service; + size_t attempt = 0; + IntentData(const BlockchainTokenPtr& token, + Operation operation, + absl::optional service); + ~IntentData(); + }; + + void PostPinToken(BlockchainTokenPtr token); + void PostUnpinToken(BlockchainTokenPtr token); + + // Iterates through user tokens and manages their pin statuses. void Restore(); void OnTokenListResolved(std::vector); diff --git a/components/brave_wallet/browser/brave_wallet_auto_pin_service_unittest.cc b/components/brave_wallet/browser/brave_wallet_auto_pin_service_unittest.cc index b8262a88f61d..77e49b90039a 100644 --- a/components/brave_wallet/browser/brave_wallet_auto_pin_service_unittest.cc +++ b/components/brave_wallet/browser/brave_wallet_auto_pin_service_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. @@ -31,6 +31,13 @@ namespace brave_wallet { namespace { +mojom::BlockchainTokenPtr GetErc721Token(const std::string& pref_path) { + mojom::BlockchainTokenPtr token = + BraveWalletPinService::TokenFromPrefPath(pref_path); + token->is_erc721 = true; + return token; +} + class MockBraveWalletPinService : public BraveWalletPinService { public: MockBraveWalletPinService() : BraveWalletPinService() {} @@ -69,7 +76,10 @@ class MockBraveWalletService : public BraveWalletService { }; MATCHER_P(TokenPathMatches, path, "") { - return arg == BraveWalletPinService::TokenFromPath(path); + auto token = GetErc721Token(path); + return token->coin == arg->coin && token->chain_id == arg->chain_id && + token->contract_address == arg->contract_address && + token->token_id == arg->token_id; } } // namespace @@ -125,20 +135,23 @@ TEST_F(BraveWalletAutoPinServiceTest, Autopin_WhenTokenAdded) { EXPECT_CALL(*GetBraveWalletPinService(), AddPin(_, _, _)).Times(3); { - mojom::BlockchainTokenPtr token = BraveWalletPinService::TokenFromPath( + mojom::BlockchainTokenPtr token = GetErc721Token( "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1"); + token->is_erc721 = true; service()->OnTokenAdded(std::move(token)); } { - mojom::BlockchainTokenPtr token = BraveWalletPinService::TokenFromPath( + mojom::BlockchainTokenPtr token = GetErc721Token( "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2"); + token->is_erc721 = true; service()->OnTokenAdded(std::move(token)); } { - mojom::BlockchainTokenPtr token = BraveWalletPinService::TokenFromPath( + mojom::BlockchainTokenPtr token = GetErc721Token( "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x3"); + token->is_erc721 = true; service()->OnTokenAdded(std::move(token)); } } @@ -180,9 +193,9 @@ TEST_F(BraveWalletAutoPinServiceTest, UnpinUnknownTokens_WhenRestore) { .WillByDefault(::testing::Invoke([](BraveWalletService:: GetUserAssetsCallback callback) { std::vector result; - result.push_back(BraveWalletPinService::TokenFromPath( + result.push_back(GetErc721Token( "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1")); - result.push_back(BraveWalletPinService::TokenFromPath( + result.push_back(GetErc721Token( "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2")); std::move(callback).Run(std::move(result)); })); @@ -236,13 +249,13 @@ TEST_F(BraveWalletAutoPinServiceTest, ValidateOldTokens_WhenRestore) { .WillByDefault(::testing::Invoke([](BraveWalletService:: GetUserAssetsCallback callback) { std::vector result; - result.push_back(BraveWalletPinService::TokenFromPath( + result.push_back(GetErc721Token( "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1")); - result.push_back(BraveWalletPinService::TokenFromPath( + result.push_back(GetErc721Token( "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2")); - result.push_back(BraveWalletPinService::TokenFromPath( + result.push_back(GetErc721Token( "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x3")); - result.push_back(BraveWalletPinService::TokenFromPath( + result.push_back(GetErc721Token( "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x4")); std::move(callback).Run(std::move(result)); })); @@ -317,11 +330,11 @@ TEST_F(BraveWalletAutoPinServiceTest, PinContinue_WhenRestore) { .WillByDefault(::testing::Invoke([](BraveWalletService:: GetUserAssetsCallback callback) { std::vector result; - result.push_back(BraveWalletPinService::TokenFromPath( + result.push_back(GetErc721Token( "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1")); - result.push_back(BraveWalletPinService::TokenFromPath( + result.push_back(GetErc721Token( "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2")); - result.push_back(BraveWalletPinService::TokenFromPath( + result.push_back(GetErc721Token( "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x3")); std::move(callback).Run(std::move(result)); })); @@ -391,9 +404,9 @@ TEST_F(BraveWalletAutoPinServiceTest, UnpinContinue_WhenRestore) { .WillByDefault(::testing::Invoke([](BraveWalletService:: GetUserAssetsCallback callback) { std::vector result; - result.push_back(BraveWalletPinService::TokenFromPath( + result.push_back(GetErc721Token( "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1")); - result.push_back(BraveWalletPinService::TokenFromPath( + result.push_back(GetErc721Token( "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2")); std::move(callback).Run(std::move(result)); })); @@ -442,7 +455,7 @@ TEST_F(BraveWalletAutoPinServiceTest, DoNotAutoPin_WhenAutoPinDisabled) { EXPECT_CALL(*GetBraveWalletPinService(), AddPin(_, _, _)).Times(0); { - mojom::BlockchainTokenPtr token = BraveWalletPinService::TokenFromPath( + mojom::BlockchainTokenPtr token = GetErc721Token( "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1"); service()->OnTokenAdded(std::move(token)); } @@ -476,9 +489,9 @@ TEST_F(BraveWalletAutoPinServiceTest, PinOldTokens_WhenAutoPinEnabled) { .WillByDefault(::testing::Invoke([](BraveWalletService:: GetUserAssetsCallback callback) { std::vector result; - result.push_back(BraveWalletPinService::TokenFromPath( + result.push_back(GetErc721Token( "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1")); - result.push_back(BraveWalletPinService::TokenFromPath( + result.push_back(GetErc721Token( "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2")); std::move(callback).Run(std::move(result)); })); diff --git a/components/brave_wallet/browser/brave_wallet_p3a.cc b/components/brave_wallet/browser/brave_wallet_p3a.cc index f1679c4dbe9c..b87690364ced 100644 --- a/components/brave_wallet/browser/brave_wallet_p3a.cc +++ b/components/brave_wallet/browser/brave_wallet_p3a.cc @@ -108,7 +108,7 @@ BraveWalletP3A::BraveWalletP3A(BraveWalletService* wallet_service, base::Unretained(this), true)); } -BraveWalletP3A::BraveWalletP3A() {} +BraveWalletP3A::BraveWalletP3A() = default; BraveWalletP3A::~BraveWalletP3A() = default; diff --git a/components/brave_wallet/browser/brave_wallet_pin_service.cc b/components/brave_wallet/browser/brave_wallet_pin_service.cc index 8f19e89d1f59..a767587ccca1 100644 --- a/components/brave_wallet/browser/brave_wallet_pin_service.cc +++ b/components/brave_wallet/browser/brave_wallet_pin_service.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. @@ -21,9 +21,6 @@ #include "brave/components/ipfs/ipfs_utils.h" #include "components/prefs/scoped_user_pref_update.h" -using brave_wallet::mojom::BlockchainToken; -using brave_wallet::mojom::BlockchainTokenPtr; - namespace brave_wallet { const char kAssetStatus[] = "status"; @@ -104,7 +101,9 @@ absl::optional ExtractCID(const std::string& ipfs_url) { } // namespace -std::string StatusToString(const mojom::TokenPinStatusCode& status) { +// static +std::string BraveWalletPinService::StatusToString( + const mojom::TokenPinStatusCode& status) { switch (status) { case mojom::TokenPinStatusCode::STATUS_NOT_PINNED: return "not_pinned"; @@ -127,7 +126,8 @@ std::string StatusToString(const mojom::TokenPinStatusCode& status) { return ""; } -std::string ErrorCodeToString( +// static +std::string BraveWalletPinService::ErrorCodeToString( const mojom::WalletPinServiceErrorCode& error_code) { switch (error_code) { case mojom::WalletPinServiceErrorCode::ERR_WRONG_TOKEN: @@ -149,6 +149,52 @@ std::string ErrorCodeToString( return ""; } +// static +bool BraveWalletPinService::IsTokenSupportedForPinning( + const mojom::BlockchainTokenPtr& token) { + return token->is_erc721; +} + +/** + * Structure of kPinnedNFTAssets prefs: + * // Type of pinned content + * "nft" : { + * // List of services + * "local" : { + * // Coin type + * "60": { + * // Chain id + * "0x1": { + * // Contract + * "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d" : { + * // Token id + * "3139" : { + * "status": , + * "validate_timestamp": , + * "error": { + * "error_code": , + * "error_message": , + * }, + * cids: [ + * // List of related CIDs + * "bafy..", + * ... + * ] + * } + * ... + * } + * ... + * } + * ... + * } + * ... + * }, + * // Remote service + * nftstorage : { + * ... + * } + * } + */ BraveWalletPinService::BraveWalletPinService( PrefService* prefs, JsonRpcService* service, @@ -188,9 +234,9 @@ void BraveWalletPinService::AddObserver( } // static -absl::optional BraveWalletPinService::GetPath( +absl::optional BraveWalletPinService::GetTokenPrefPath( const absl::optional& service, - const BlockchainTokenPtr& token) { + const mojom::BlockchainTokenPtr& token) { if (service && base::ContainsOnlyChars(service.value(), ".")) { return absl::nullopt; } @@ -208,7 +254,7 @@ absl::optional BraveWalletPinService::GetPath( } // static -BlockchainTokenPtr BraveWalletPinService::TokenFromPath( +mojom::BlockchainTokenPtr BraveWalletPinService::TokenFromPrefPath( const std::string& path) { std::vector parts = base::SplitString(path, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); @@ -224,13 +270,12 @@ BlockchainTokenPtr BraveWalletPinService::TokenFromPath( token->chain_id = parts.at(3); token->contract_address = parts.at(4); token->token_id = parts.at(5); - token->is_erc721 = true; token->is_nft = true; return token; } // static -absl::optional BraveWalletPinService::ServiceFromPath( +absl::optional BraveWalletPinService::ServiceFromPrefPath( const std::string& path) { std::vector parts = base::SplitString(path, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); @@ -244,7 +289,7 @@ absl::optional BraveWalletPinService::ServiceFromPath( } } -void BraveWalletPinService::Validate(BlockchainTokenPtr token, +void BraveWalletPinService::Validate(mojom::BlockchainTokenPtr token, const absl::optional& service, ValidateCallback callback) { mojom::TokenPinStatusPtr status = GetTokenStatus(service, token); @@ -268,7 +313,7 @@ void BraveWalletPinService::Validate(BlockchainTokenPtr token, return; } - auto path = GetPath(absl::nullopt, token); + auto path = GetTokenPrefPath(absl::nullopt, token); if (!path) { std::move(callback).Run( false, @@ -281,8 +326,8 @@ void BraveWalletPinService::Validate(BlockchainTokenPtr token, local_pin_service_->ValidatePins( path.value(), cids.value(), base::BindOnce(&BraveWalletPinService::OnTokenValidated, - base::Unretained(this), service, std::move(callback), - std::move(token))); + weak_ptr_factory_.GetWeakPtr(), service, + std::move(callback), std::move(token))); } else { // Remote pinning not implemented yet std::move(callback).Run(false, nullptr); @@ -294,6 +339,12 @@ void BraveWalletPinService::IsLocalNodeRunning( std::move(callback).Run(ipfs_service_->IsDaemonLaunched()); } +void BraveWalletPinService::IsTokenSupported( + mojom::BlockchainTokenPtr token, + IsTokenSupportedCallback callback) { + std::move(callback).Run(IsTokenSupportedForPinning(token)); +} + void BraveWalletPinService::OnIpfsLaunched(bool result, int64_t pid) { for (const auto& observer : observers_) { observer->OnLocalNodeStatusChanged(result); @@ -320,16 +371,14 @@ void BraveWalletPinService::MarkAsPendingForUnpinning( mojom::TokenPinStatusCode::STATUS_UNPINNING_PENDING, nullptr); } -void BraveWalletPinService::AddPin(BlockchainTokenPtr token, +void BraveWalletPinService::AddPin(mojom::BlockchainTokenPtr token, const absl::optional& service, AddPinCallback callback) { - if (!token->is_nft) { - auto pin_error = mojom::PinError::New( - mojom::WalletPinServiceErrorCode::ERR_WRONG_TOKEN, "Token is not nft"); - - VLOG(1) << "Token is not nft"; - FinishAddingWithResult(service, token, false, std::move(pin_error), - std::move(callback)); + if (!IsTokenSupportedForPinning(token)) { + auto pin_error = + mojom::PinError::New(mojom::WalletPinServiceErrorCode::ERR_WRONG_TOKEN, + "Token pinning is not supported"); + std::move(callback).Run(false, std::move(pin_error)); return; } @@ -338,21 +387,19 @@ void BraveWalletPinService::AddPin(BlockchainTokenPtr token, token_status->code == mojom::TokenPinStatusCode::STATUS_PINNED) { auto pin_error = mojom::PinError::New( mojom::WalletPinServiceErrorCode::ERR_ALREADY_PINNED, "Already pinned"); - - FinishAddingWithResult(service, token, true, std::move(pin_error), - std::move(callback)); + std::move(callback).Run(true, std::move(pin_error)); return; } json_rpc_service_->GetERC721Metadata( token->contract_address, token->token_id, token->chain_id, base::BindOnce(&BraveWalletPinService::OnTokenMetaDataReceived, - base::Unretained(this), service, std::move(callback), - token.Clone())); + weak_ptr_factory_.GetWeakPtr(), service, + std::move(callback), token.Clone())); } void BraveWalletPinService::RemovePin( - BlockchainTokenPtr token, + mojom::BlockchainTokenPtr token, const absl::optional& service, RemovePinCallback callback) { auto token_status = GetTokenStatus(service, token); @@ -361,7 +408,7 @@ void BraveWalletPinService::RemovePin( return; } - auto path = GetPath(absl::nullopt, token); + auto path = GetTokenPrefPath(absl::nullopt, token); if (!path) { std::move(callback).Run( false, @@ -377,7 +424,7 @@ void BraveWalletPinService::RemovePin( if (!service) { local_pin_service_->RemovePins( path.value(), base::BindOnce(&BraveWalletPinService::OnPinsRemoved, - base::Unretained(this), service, + weak_ptr_factory_.GetWeakPtr(), service, std::move(callback), std::move(token))); } else { // Remote pinning not implemented yet @@ -385,7 +432,7 @@ void BraveWalletPinService::RemovePin( } } -void BraveWalletPinService::GetTokenStatus(BlockchainTokenPtr token, +void BraveWalletPinService::GetTokenStatus(mojom::BlockchainTokenPtr token, GetTokenStatusCallback callback) { mojom::TokenPinOverviewPtr result = mojom::TokenPinOverview::New(); result->local = GetTokenStatus(absl::nullopt, token); @@ -420,8 +467,7 @@ void BraveWalletPinService::OnTokenMetaDataReceived( "Failed to obtain token metadata"); SetTokenStatus(service, token, mojom::TokenPinStatusCode::STATUS_PINNING_FAILED, pin_error); - FinishAddingWithResult(service, token, false, std::move(pin_error), - std::move(callback)); + std::move(callback).Run(false, std::move(pin_error)); return; } @@ -432,8 +478,7 @@ void BraveWalletPinService::OnTokenMetaDataReceived( "Metadata has non-ipfs url"); SetTokenStatus(service, token, mojom::TokenPinStatusCode::STATUS_PINNING_FAILED, pin_error); - FinishAddingWithResult(service, token, false, std::move(pin_error), - std::move(callback)); + std::move(callback).Run(false, std::move(pin_error)); return; } @@ -446,8 +491,7 @@ void BraveWalletPinService::OnTokenMetaDataReceived( "Wrong metadata format"); SetTokenStatus(service, token, mojom::TokenPinStatusCode::STATUS_PINNING_FAILED, pin_error); - FinishAddingWithResult(service, token, false, std::move(pin_error), - std::move(callback)); + std::move(callback).Run(false, std::move(pin_error)); return; } @@ -462,7 +506,7 @@ void BraveWalletPinService::OnTokenMetaDataReceived( } } - auto path = GetPath(service, token); + auto path = GetTokenPrefPath(service, token); if (!path) { std::move(callback).Run( false, @@ -471,7 +515,7 @@ void BraveWalletPinService::OnTokenMetaDataReceived( return; } - CreateToken(service, token, cids); + AddToken(service, token, cids); SetTokenStatus(service, token, mojom::TokenPinStatusCode::STATUS_PINNING_IN_PROGRESS, nullptr); @@ -480,7 +524,7 @@ void BraveWalletPinService::OnTokenMetaDataReceived( local_pin_service_->AddPins( path.value(), cids, base::BindOnce(&BraveWalletPinService::OnTokenPinned, - base::Unretained(this), absl::nullopt, + weak_ptr_factory_.GetWeakPtr(), absl::nullopt, std::move(callback), std::move(token))); } else { // Remote pinning not implemented yet @@ -502,8 +546,7 @@ void BraveWalletPinService::OnTokenPinned(absl::optional service, : mojom::TokenPinStatusCode::STATUS_PINNING_FAILED, error); - FinishAddingWithResult(service, token, result, std::move(error), - std::move(callback)); + std::move(callback).Run(result, std::move(error)); } void BraveWalletPinService::OnTokenValidated( @@ -529,43 +572,45 @@ void BraveWalletPinService::OnTokenValidated( std::move(callback).Run(true, nullptr); } -bool BraveWalletPinService::CreateToken( - const absl::optional& service, - const mojom::BlockchainTokenPtr& token, - const std::vector& cids) { - auto path = GetPath(service, token); +bool BraveWalletPinService::AddToken(const absl::optional& service, + const mojom::BlockchainTokenPtr& token, + const std::vector& cids) { + auto path = GetTokenPrefPath(service, token); if (!path) { return false; } - DictionaryPrefUpdate update(prefs_, kPinnedErc721Assets); - base::Value::Dict& update_dict = update->GetDict(); + { + DictionaryPrefUpdate update(prefs_, kPinnedNFTAssets); + base::Value::Dict& update_dict = update->GetDict(); - base::Value::Dict token_data; - base::Value::List cids_list; + base::Value::Dict token_data; + base::Value::List cids_list; - for (const auto& cid : cids) { - cids_list.Append(cid); - } + for (const auto& cid : cids) { + cids_list.Append(cid); + } - token_data.Set(kAssetUrlListKey, std::move(cids_list)); - token_data.Set(kAssetStatus, - StatusToString(mojom::TokenPinStatusCode::STATUS_NOT_PINNED)); + token_data.Set(kAssetUrlListKey, std::move(cids_list)); + token_data.Set( + kAssetStatus, + StatusToString(mojom::TokenPinStatusCode::STATUS_NOT_PINNED)); - update_dict.SetByDottedPath(path.value(), std::move(token_data)); + update_dict.SetByDottedPath(path.value(), std::move(token_data)); + } return true; } bool BraveWalletPinService::RemoveToken( const absl::optional& service, const mojom::BlockchainTokenPtr& token) { - auto path = GetPath(service, token); + auto path = GetTokenPrefPath(service, token); if (!path) { return false; } { - DictionaryPrefUpdate update(prefs_, kPinnedErc721Assets); + DictionaryPrefUpdate update(prefs_, kPinnedNFTAssets); base::Value::Dict& update_dict = update->GetDict(); update_dict.RemoveByDottedPath(path.value()); } @@ -581,13 +626,13 @@ bool BraveWalletPinService::SetTokenStatus( const mojom::BlockchainTokenPtr& token, mojom::TokenPinStatusCode status, const mojom::PinErrorPtr& error) { - auto path = GetPath(service, token); + auto path = GetTokenPrefPath(service, token); if (!path) { return false; } { - DictionaryPrefUpdate update(prefs_, kPinnedErc721Assets); + DictionaryPrefUpdate update(prefs_, kPinnedNFTAssets); base::Value::Dict& update_dict = update->GetDict(); update_dict.SetByDottedPath(path.value() + "." + kAssetStatus, @@ -618,11 +663,11 @@ bool BraveWalletPinService::SetTokenStatus( absl::optional> BraveWalletPinService::ResolvePinItems( const absl::optional& service, - const BlockchainTokenPtr& token) { + const mojom::BlockchainTokenPtr& token) { const base::Value::Dict& pinned_assets_pref = - prefs_->GetDict(kPinnedErc721Assets); + prefs_->GetDict(kPinnedNFTAssets); - auto path = GetPath(service, token); + auto path = GetTokenPrefPath(service, token); if (!path) { return absl::nullopt; } @@ -650,9 +695,9 @@ mojom::TokenPinStatusPtr BraveWalletPinService::GetTokenStatus( const absl::optional& service, const mojom::BlockchainTokenPtr& token) { const base::Value::Dict& pinned_assets_pref = - prefs_->GetDict(kPinnedErc721Assets); + prefs_->GetDict(kPinnedNFTAssets); - auto path = GetPath(service, token); + auto path = GetTokenPrefPath(service, token); if (!path) { return nullptr; } @@ -704,9 +749,9 @@ absl::optional BraveWalletPinService::GetLastValidateTime( const absl::optional& service, const mojom::BlockchainTokenPtr& token) { const base::Value::Dict& pinned_assets_pref = - prefs_->GetDict(kPinnedErc721Assets); + prefs_->GetDict(kPinnedNFTAssets); - auto path = GetPath(service, token); + auto path = GetTokenPrefPath(service, token); if (!path) { return absl::nullopt; } @@ -721,21 +766,12 @@ absl::optional BraveWalletPinService::GetLastValidateTime( return base::ValueToTime(time); } -void BraveWalletPinService::FinishAddingWithResult( - const absl::optional& service, - const mojom::BlockchainTokenPtr& token, - bool result, - mojom::PinErrorPtr error, - AddPinCallback callback) { - std::move(callback).Run(result, std::move(error)); -} - std::set BraveWalletPinService::GetTokens( const absl::optional& service) { std::set result; const base::Value::Dict& pinned_assets_pref = - prefs_->GetDict(kPinnedErc721Assets); + prefs_->GetDict(kPinnedNFTAssets); const base::Value::Dict* service_dict = pinned_assets_pref.FindDictByDottedPath( diff --git a/components/brave_wallet/browser/brave_wallet_pin_service.h b/components/brave_wallet/browser/brave_wallet_pin_service.h index cc2b572b8105..461b695c5f6d 100644 --- a/components/brave_wallet/browser/brave_wallet_pin_service.h +++ b/components/brave_wallet/browser/brave_wallet_pin_service.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. @@ -12,6 +12,7 @@ #include "base/containers/cxx20_erase_deque.h" #include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" #include "base/task/sequenced_task_runner.h" #include "brave/components/brave_wallet/browser/brave_wallet_service.h" #include "brave/components/brave_wallet/browser/json_rpc_service.h" @@ -24,14 +25,8 @@ #include "mojo/public/cpp/bindings/remote_set.h" #include "third_party/abseil-cpp/absl/types/optional.h" -using brave_wallet::mojom::BlockchainTokenPtr; - namespace brave_wallet { -std::string StatusToString(const mojom::TokenPinStatusCode& status); -std::string ErrorCodeToString( - const mojom::WalletPinServiceErrorCode& error_code); - class BraveWalletPinService : public KeyedService, public brave_wallet::mojom::WalletPinService, public ipfs::IpfsServiceObserver { @@ -45,27 +40,35 @@ class BraveWalletPinService : public KeyedService, mojo::PendingRemote MakeRemote(); void Bind(mojo::PendingReceiver receiver); - static absl::optional GetPath( + static absl::optional GetTokenPrefPath( const absl::optional& service, - const BlockchainTokenPtr& token); - static BlockchainTokenPtr TokenFromPath(const std::string& path); - static absl::optional ServiceFromPath(const std::string& path); + const mojom::BlockchainTokenPtr& token); + static mojom::BlockchainTokenPtr TokenFromPrefPath(const std::string& path); + static absl::optional ServiceFromPrefPath( + const std::string& path); + static std::string StatusToString(const mojom::TokenPinStatusCode& status); + static std::string ErrorCodeToString( + const mojom::WalletPinServiceErrorCode& error_code); + static bool IsTokenSupportedForPinning( + const mojom::BlockchainTokenPtr& token); // WalletPinService void AddObserver(::mojo::PendingRemote observer) override; - void AddPin(BlockchainTokenPtr token, + void AddPin(mojom::BlockchainTokenPtr token, const absl::optional& service, AddPinCallback callback) override; - void RemovePin(BlockchainTokenPtr token, + void RemovePin(mojom::BlockchainTokenPtr token, const absl::optional& service, RemovePinCallback callback) override; - void GetTokenStatus(BlockchainTokenPtr token, + void GetTokenStatus(mojom::BlockchainTokenPtr token, GetTokenStatusCallback callback) override; - void Validate(BlockchainTokenPtr token, + void Validate(mojom::BlockchainTokenPtr token, const absl::optional& service, ValidateCallback callback) override; void IsLocalNodeRunning(IsLocalNodeRunningCallback callback) override; + void IsTokenSupported(mojom::BlockchainTokenPtr token, + IsTokenSupportedCallback callback) override; virtual void MarkAsPendingForPinning( const mojom::BlockchainTokenPtr& token, @@ -80,6 +83,9 @@ class BraveWalletPinService : public KeyedService, virtual absl::optional GetLastValidateTime( const absl::optional& service, const mojom::BlockchainTokenPtr& token); + // Returns list of known tokens for the provided pinning service. + // Tokens are returned in the format of string path. + // See BraveWalletPinService::GetTokenPrefPath. virtual std::set GetTokens( const absl::optional& service); @@ -88,9 +94,9 @@ class BraveWalletPinService : public KeyedService, BraveWalletPinService(); private: - bool CreateToken(const absl::optional& service, - const mojom::BlockchainTokenPtr& token, - const std::vector& cids); + bool AddToken(const absl::optional& service, + const mojom::BlockchainTokenPtr& token, + const std::vector& cids); bool RemoveToken(const absl::optional& service, const mojom::BlockchainTokenPtr& token); bool SetTokenStatus(const absl::optional& service, @@ -98,15 +104,9 @@ class BraveWalletPinService : public KeyedService, mojom::TokenPinStatusCode, const mojom::PinErrorPtr& error); - void FinishAddingWithResult(const absl::optional& service, - const mojom::BlockchainTokenPtr& token, - bool result, - mojom::PinErrorPtr error, - AddPinCallback callback); - absl::optional> ResolvePinItems( const absl::optional& service, - const BlockchainTokenPtr& token); + const mojom::BlockchainTokenPtr& token); void OnPinsRemoved(absl::optional service, RemovePinCallback callback, @@ -143,6 +143,8 @@ class BraveWalletPinService : public KeyedService, raw_ptr json_rpc_service_ = nullptr; raw_ptr local_pin_service_ = nullptr; raw_ptr ipfs_service_ = nullptr; + + base::WeakPtrFactory weak_ptr_factory_{this}; }; } // namespace brave_wallet diff --git a/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc b/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc index f7904f898afc..93c8417230c7 100644 --- a/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc +++ b/components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. @@ -111,7 +111,7 @@ class BraveWalletPinServiceTest : public testing::Test { protected: void SetUp() override { auto* registry = pref_service_.registry(); - registry->RegisterDictionaryPref(kPinnedErc721Assets); + registry->RegisterDictionaryPref(kPinnedNFTAssets); brave_wallet_pin_service_ = std::make_unique( GetPrefs(), GetJsonRpcService(), GetIpfsLocalPinService(), GetIpfsService()); @@ -169,8 +169,8 @@ TEST_F(BraveWalletPinServiceTest, AddPin) { auto scoped_override = OverrideWithTimeNow(base::Time::FromTimeT(123u)); mojom::BlockchainTokenPtr token = - BraveWalletPinService::TokenFromPath(kMonkey1Path); - + BraveWalletPinService::TokenFromPrefPath(kMonkey1Path); + token->is_erc721 = true; absl::optional call_status; service()->AddPin( std::move(token), absl::nullopt, @@ -183,14 +183,15 @@ TEST_F(BraveWalletPinServiceTest, AddPin) { const base::Value::Dict* token_record = GetPrefs() - ->GetDict(kPinnedErc721Assets) + ->GetDict(kPinnedNFTAssets) .FindDictByDottedPath(kMonkey1Path); base::Value::List expected_cids; expected_cids.Append("QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq"); expected_cids.Append("Qmcyc7tm9sZB9JnvLgejPTwdzjjNjDMiRWCUvaZAfp6cUg"); - EXPECT_EQ(StatusToString(mojom::TokenPinStatusCode::STATUS_PINNED), + EXPECT_EQ(BraveWalletPinService::StatusToString( + mojom::TokenPinStatusCode::STATUS_PINNED), *(token_record->FindString("status"))); EXPECT_EQ(nullptr, token_record->FindDict("error")); EXPECT_EQ(expected_cids, *(token_record->FindList("cids"))); @@ -213,8 +214,8 @@ TEST_F(BraveWalletPinServiceTest, AddPin) { })); mojom::BlockchainTokenPtr token = - BraveWalletPinService::TokenFromPath(kMonkey2Path); - + BraveWalletPinService::TokenFromPrefPath(kMonkey2Path); + token->is_erc721 = true; absl::optional call_status; service()->AddPin( std::move(token), absl::nullopt, @@ -228,12 +229,13 @@ TEST_F(BraveWalletPinServiceTest, AddPin) { const base::Value::Dict* token_record = GetPrefs() - ->GetDict(kPinnedErc721Assets) + ->GetDict(kPinnedNFTAssets) .FindDictByDottedPath(kMonkey2Path); - EXPECT_EQ(StatusToString(mojom::TokenPinStatusCode::STATUS_PINNING_FAILED), + EXPECT_EQ(BraveWalletPinService::StatusToString( + mojom::TokenPinStatusCode::STATUS_PINNING_FAILED), *(token_record->FindString("status"))); - EXPECT_EQ(ErrorCodeToString( + EXPECT_EQ(BraveWalletPinService::ErrorCodeToString( mojom::WalletPinServiceErrorCode::ERR_FETCH_METADATA_FAILED), token_record->FindByDottedPath("error.error_code")->GetString()); } @@ -241,7 +243,7 @@ TEST_F(BraveWalletPinServiceTest, AddPin) { TEST_F(BraveWalletPinServiceTest, RemovePin) { { - DictionaryPrefUpdate update(GetPrefs(), kPinnedErc721Assets); + DictionaryPrefUpdate update(GetPrefs(), kPinnedNFTAssets); base::Value::Dict& update_dict = update->GetDict(); base::Value::Dict item; @@ -263,8 +265,8 @@ TEST_F(BraveWalletPinServiceTest, RemovePin) { })); mojom::BlockchainTokenPtr token = - BraveWalletPinService::TokenFromPath(kMonkey1Path); - + BraveWalletPinService::TokenFromPrefPath(kMonkey1Path); + token->is_erc721 = true; absl::optional remove_status; service()->RemovePin( std::move(token), absl::nullopt, @@ -273,12 +275,12 @@ TEST_F(BraveWalletPinServiceTest, RemovePin) { remove_status = status; })); EXPECT_FALSE(remove_status.value()); - EXPECT_EQ( - StatusToString(mojom::TokenPinStatusCode::STATUS_UNPINNING_FAILED), - *(GetPrefs() - ->GetDict(kPinnedErc721Assets) - .FindByDottedPath(kMonkey1Path) - ->FindStringKey("status"))); + EXPECT_EQ(BraveWalletPinService::StatusToString( + mojom::TokenPinStatusCode::STATUS_UNPINNING_FAILED), + *(GetPrefs() + ->GetDict(kPinnedNFTAssets) + .FindByDottedPath(kMonkey1Path) + ->FindStringKey("status"))); } { @@ -290,8 +292,8 @@ TEST_F(BraveWalletPinServiceTest, RemovePin) { })); mojom::BlockchainTokenPtr token = - BraveWalletPinService::TokenFromPath(kMonkey1Path); - + BraveWalletPinService::TokenFromPrefPath(kMonkey1Path); + token->is_erc721 = true; absl::optional remove_status; service()->RemovePin( std::move(token), absl::nullopt, @@ -301,14 +303,14 @@ TEST_F(BraveWalletPinServiceTest, RemovePin) { })); EXPECT_TRUE(remove_status.value()); EXPECT_EQ(nullptr, GetPrefs() - ->GetDict(kPinnedErc721Assets) + ->GetDict(kPinnedNFTAssets) .FindDictByDottedPath(kMonkey1Path)); } } TEST_F(BraveWalletPinServiceTest, ValidatePin) { { - DictionaryPrefUpdate update(GetPrefs(), kPinnedErc721Assets); + DictionaryPrefUpdate update(GetPrefs(), kPinnedNFTAssets); base::Value::Dict& update_dict = update->GetDict(); base::Value::Dict item; @@ -326,8 +328,8 @@ TEST_F(BraveWalletPinServiceTest, ValidatePin) { auto scoped_override = OverrideWithTimeNow(base::Time::FromTimeT(345u)); mojom::BlockchainTokenPtr token = - BraveWalletPinService::TokenFromPath(kMonkey1Path); - + BraveWalletPinService::TokenFromPrefPath(kMonkey1Path); + token->is_erc721 = true; ON_CALL(*GetIpfsLocalPinService(), ValidatePins(_, _, _)) .WillByDefault(::testing::Invoke( [](const std::string& prefix, const std::vector& cids, @@ -351,7 +353,7 @@ TEST_F(BraveWalletPinServiceTest, ValidatePin) { const base::Value::Dict* token_record = GetPrefs() - ->GetDict(kPinnedErc721Assets) + ->GetDict(kPinnedNFTAssets) .FindDictByDottedPath(kMonkey1Path); EXPECT_EQ(base::Time::FromTimeT(345u), base::ValueToTime(token_record->Find("validate_timestamp"))); @@ -359,8 +361,8 @@ TEST_F(BraveWalletPinServiceTest, ValidatePin) { { mojom::BlockchainTokenPtr token = - BraveWalletPinService::TokenFromPath(kMonkey1Path); - + BraveWalletPinService::TokenFromPrefPath(kMonkey1Path); + token->is_erc721 = true; ON_CALL(*GetIpfsLocalPinService(), ValidatePins(_, _, _)) .WillByDefault(::testing::Invoke( [](const std::string& prefix, const std::vector& cids, @@ -380,7 +382,7 @@ TEST_F(BraveWalletPinServiceTest, ValidatePin) { const base::Value::Dict* token_record = GetPrefs() - ->GetDict(kPinnedErc721Assets) + ->GetDict(kPinnedNFTAssets) .FindDictByDottedPath(kMonkey1Path); EXPECT_EQ(base::Time::FromTimeT(345u), base::ValueToTime(token_record->Find("validate_timestamp"))); @@ -388,8 +390,8 @@ TEST_F(BraveWalletPinServiceTest, ValidatePin) { { mojom::BlockchainTokenPtr token = - BraveWalletPinService::TokenFromPath(kMonkey1Path); - + BraveWalletPinService::TokenFromPrefPath(kMonkey1Path); + token->is_erc721 = true; ON_CALL(*GetIpfsLocalPinService(), ValidatePins(_, _, _)) .WillByDefault(::testing::Invoke( [](const std::string& prefix, const std::vector& cids, @@ -409,7 +411,7 @@ TEST_F(BraveWalletPinServiceTest, ValidatePin) { const base::Value::Dict* token_record = GetPrefs() - ->GetDict(kPinnedErc721Assets) + ->GetDict(kPinnedNFTAssets) .FindDictByDottedPath(kMonkey1Path); EXPECT_EQ(nullptr, token_record->Find("validate_timestamp")); @@ -418,7 +420,7 @@ TEST_F(BraveWalletPinServiceTest, ValidatePin) { TEST_F(BraveWalletPinServiceTest, GetTokenStatus) { { - DictionaryPrefUpdate update(GetPrefs(), kPinnedErc721Assets); + DictionaryPrefUpdate update(GetPrefs(), kPinnedNFTAssets); base::Value::Dict& update_dict = update->GetDict(); base::Value::Dict item; @@ -434,15 +436,15 @@ TEST_F(BraveWalletPinServiceTest, GetTokenStatus) { } { - DictionaryPrefUpdate update(GetPrefs(), kPinnedErc721Assets); + DictionaryPrefUpdate update(GetPrefs(), kPinnedNFTAssets); base::Value::Dict& update_dict = update->GetDict(); base::Value::Dict item; - item.Set("status", - StatusToString(mojom::TokenPinStatusCode::STATUS_PINNING_FAILED)); + item.Set("status", BraveWalletPinService::StatusToString( + mojom::TokenPinStatusCode::STATUS_PINNING_FAILED)); base::Value::Dict error; error.Set("error_code", - ErrorCodeToString( + BraveWalletPinService::ErrorCodeToString( mojom::WalletPinServiceErrorCode::ERR_FETCH_METADATA_FAILED)); error.Set("error_message", "Fail to fetch metadata"); item.Set("error", std::move(error)); @@ -451,8 +453,8 @@ TEST_F(BraveWalletPinServiceTest, GetTokenStatus) { } mojom::BlockchainTokenPtr token1 = - BraveWalletPinService::TokenFromPath(kMonkey1Path); - + BraveWalletPinService::TokenFromPrefPath(kMonkey1Path); + token1->is_erc721 = true; { mojom::TokenPinStatusPtr status = service()->GetTokenStatus(absl::nullopt, token1); @@ -468,8 +470,8 @@ TEST_F(BraveWalletPinServiceTest, GetTokenStatus) { } mojom::BlockchainTokenPtr token2 = - BraveWalletPinService::TokenFromPath(kMonkey2Path); - + BraveWalletPinService::TokenFromPrefPath(kMonkey2Path); + token2->is_erc721 = true; { mojom::TokenPinStatusPtr status = service()->GetTokenStatus(absl::nullopt, token2); @@ -482,7 +484,7 @@ TEST_F(BraveWalletPinServiceTest, GetTokenStatus) { TEST_F(BraveWalletPinServiceTest, GetLastValidateTime) { { - DictionaryPrefUpdate update(GetPrefs(), kPinnedErc721Assets); + DictionaryPrefUpdate update(GetPrefs(), kPinnedNFTAssets); base::Value::Dict& update_dict = update->GetDict(); base::Value::Dict item; @@ -498,8 +500,8 @@ TEST_F(BraveWalletPinServiceTest, GetLastValidateTime) { } mojom::BlockchainTokenPtr token = - BraveWalletPinService::TokenFromPath(kMonkey1Path); - + BraveWalletPinService::TokenFromPrefPath(kMonkey1Path); + token->is_erc721 = true; { base::Time last_validate_time = service()->GetLastValidateTime(absl::nullopt, token).value(); @@ -512,10 +514,9 @@ TEST_F(BraveWalletPinServiceTest, GetLastValidateTime) { } } -TEST_F(BraveWalletPinServiceTest, TokenFromPath) { +TEST_F(BraveWalletPinServiceTest, TokenFromPrefPath) { mojom::BlockchainTokenPtr token = - BraveWalletPinService::TokenFromPath(kMonkey1Path); - EXPECT_TRUE(token->is_erc721); + BraveWalletPinService::TokenFromPrefPath(kMonkey1Path); EXPECT_EQ(mojom::CoinType::ETH, static_cast(token->coin)); EXPECT_EQ("0x1", token->chain_id); EXPECT_EQ("0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", @@ -525,9 +526,9 @@ TEST_F(BraveWalletPinServiceTest, TokenFromPath) { TEST_F(BraveWalletPinServiceTest, ServiceFromPath) { EXPECT_FALSE( - BraveWalletPinService::ServiceFromPath(kMonkey1Path).has_value()); + BraveWalletPinService::ServiceFromPrefPath(kMonkey1Path).has_value()); - EXPECT_EQ("nftstorage", BraveWalletPinService::ServiceFromPath( + EXPECT_EQ("nftstorage", BraveWalletPinService::ServiceFromPrefPath( "nft.nftstorage.60.0x1." "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1") .value()); @@ -540,7 +541,7 @@ TEST_F(BraveWalletPinServiceTest, GetPath) { token->contract_address = "abc"; token->token_id = "0x2"; token->chain_id = "mainnet"; - auto path = BraveWalletPinService::GetPath(absl::nullopt, token); + auto path = BraveWalletPinService::GetTokenPrefPath(absl::nullopt, token); EXPECT_EQ("nft.local.60.mainnet.abc.0x2", path.value()); } @@ -550,14 +551,14 @@ TEST_F(BraveWalletPinServiceTest, GetPath) { token->contract_address = "abc"; token->token_id = "0x2"; token->chain_id = "mainnet"; - auto path = BraveWalletPinService::GetPath("nftstorage", token); + auto path = BraveWalletPinService::GetTokenPrefPath("nftstorage", token); EXPECT_EQ("nft.nftstorage.60.mainnet.abc.0x2", path.value()); } } TEST_F(BraveWalletPinServiceTest, GetTokens) { { - DictionaryPrefUpdate update(GetPrefs(), kPinnedErc721Assets); + DictionaryPrefUpdate update(GetPrefs(), kPinnedNFTAssets); base::Value::Dict& update_dict = update->GetDict(); base::Value::Dict item; @@ -567,7 +568,7 @@ TEST_F(BraveWalletPinServiceTest, GetTokens) { } { - DictionaryPrefUpdate update(GetPrefs(), kPinnedErc721Assets); + DictionaryPrefUpdate update(GetPrefs(), kPinnedNFTAssets); base::Value::Dict& update_dict = update->GetDict(); base::Value::Dict item; @@ -577,7 +578,7 @@ TEST_F(BraveWalletPinServiceTest, GetTokens) { } { - DictionaryPrefUpdate update(GetPrefs(), kPinnedErc721Assets); + DictionaryPrefUpdate update(GetPrefs(), kPinnedNFTAssets); base::Value::Dict& update_dict = update->GetDict(); base::Value::Dict item; diff --git a/components/brave_wallet/browser/brave_wallet_prefs.cc b/components/brave_wallet/browser/brave_wallet_prefs.cc index af1520cc2ebb..3f2f5cd7d019 100644 --- a/components/brave_wallet/browser/brave_wallet_prefs.cc +++ b/components/brave_wallet/browser/brave_wallet_prefs.cc @@ -127,7 +127,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { registry->RegisterTimePref(kBraveWalletP3AFirstReportTime, base::Time()); registry->RegisterListPref(kBraveWalletP3AWeeklyStorage); - registry->RegisterDictionaryPref(kPinnedErc721Assets); + registry->RegisterDictionaryPref(kPinnedNFTAssets); registry->RegisterBooleanPref(kAutoPinEnabled, false); } @@ -198,7 +198,7 @@ void ClearBraveWalletServicePrefs(PrefService* prefs) { prefs->ClearPref(kBraveWalletUserAssets); prefs->ClearPref(kDefaultBaseCurrency); prefs->ClearPref(kDefaultBaseCryptocurrency); - prefs->ClearPref(kPinnedErc721Assets); + prefs->ClearPref(kPinnedNFTAssets); } void MigrateObsoleteProfilePrefs(PrefService* prefs) { diff --git a/components/brave_wallet/browser/brave_wallet_service.cc b/components/brave_wallet/browser/brave_wallet_service.cc index f3dfca23f3c5..82ec48511315 100644 --- a/components/brave_wallet/browser/brave_wallet_service.cc +++ b/components/brave_wallet/browser/brave_wallet_service.cc @@ -283,7 +283,7 @@ std::vector BraveWalletService::GetUserAssets( std::vector result; const auto& user_assets_dict = profile_prefs->GetDict(kBraveWalletUserAssets); for (auto coin_it : user_assets_dict) { - auto coin = GetCoinFromPref(coin_it.first); + auto coin = GetCoinTypeFromPrefKey(coin_it.first); if (!coin) continue; diff --git a/components/brave_wallet/browser/brave_wallet_utils.cc b/components/brave_wallet/browser/brave_wallet_utils.cc index 090183c9f83e..f682a025b68a 100644 --- a/components/brave_wallet/browser/brave_wallet_utils.cc +++ b/components/brave_wallet/browser/brave_wallet_utils.cc @@ -1389,12 +1389,12 @@ std::string GetPrefKeyForCoinType(mojom::CoinType coin) { return ""; } -absl::optional GetCoinFromPref(const std::string& pref) { - if (pref == kEthereumPrefKey) { +absl::optional GetCoinTypeFromPrefKey(const std::string& key) { + if (key == kEthereumPrefKey) { return mojom::CoinType::ETH; - } else if (pref == kFilecoinPrefKey) { + } else if (key == kFilecoinPrefKey) { return mojom::CoinType::FIL; - } else if (pref == kSolanaPrefKey) { + } else if (key == kSolanaPrefKey) { return mojom::CoinType::SOL; } NOTREACHED(); diff --git a/components/brave_wallet/browser/brave_wallet_utils.h b/components/brave_wallet/browser/brave_wallet_utils.h index fbdeafa1eff6..0f45c440441a 100644 --- a/components/brave_wallet/browser/brave_wallet_utils.h +++ b/components/brave_wallet/browser/brave_wallet_utils.h @@ -152,7 +152,7 @@ std::string GetCurrentChainId(PrefService* prefs, mojom::CoinType coin); std::string GetPrefKeyForCoinType(mojom::CoinType coin); // Converts string representation of CoinType to enum. -absl::optional GetCoinFromPref(const std::string& pref); +absl::optional GetCoinTypeFromPrefKey(const std::string& key); // Resolves chain_id from network_id. absl::optional GetChainId(PrefService* prefs, diff --git a/components/brave_wallet/browser/pref_names.cc b/components/brave_wallet/browser/pref_names.cc index aa347c29089a..a7da02ebf79d 100644 --- a/components/brave_wallet/browser/pref_names.cc +++ b/components/brave_wallet/browser/pref_names.cc @@ -72,5 +72,5 @@ const char kBraveWalletCurrentChainId[] = const char kBraveWalletUserAssetsDeprecated[] = "brave.wallet.user_assets"; const char kBraveWalletUserAssetsAddPreloadingNetworksMigratedDeprecated[] = "brave.wallet.user.assets.add_preloading_networks_migrated"; -const char kPinnedErc721Assets[] = "brave.wallet.user_pin_data"; +const char kPinnedNFTAssets[] = "brave.wallet.user_pin_data"; const char kAutoPinEnabled[] = "brave.wallet.auto_pin_enabled"; diff --git a/components/brave_wallet/browser/pref_names.h b/components/brave_wallet/browser/pref_names.h index 51bf85873a32..555074102924 100644 --- a/components/brave_wallet/browser/pref_names.h +++ b/components/brave_wallet/browser/pref_names.h @@ -59,7 +59,7 @@ extern const char kBraveWalletCurrentChainId[]; extern const char kBraveWalletUserAssetsDeprecated[]; extern const char kBraveWalletUserAssetsAddPreloadingNetworksMigratedDeprecated[]; -extern const char kPinnedErc721Assets[]; +extern const char kPinnedNFTAssets[]; extern const char kAutoPinEnabled[]; #endif // BRAVE_COMPONENTS_BRAVE_WALLET_BROWSER_PREF_NAMES_H_ diff --git a/components/brave_wallet/common/brave_wallet.mojom b/components/brave_wallet/common/brave_wallet.mojom index cf577283ebac..9ab969ca61f6 100644 --- a/components/brave_wallet/common/brave_wallet.mojom +++ b/components/brave_wallet/common/brave_wallet.mojom @@ -212,9 +212,13 @@ interface SolanaProvider { mojo_base.mojom.DictionaryValue result); }; + enum WalletPinServiceErrorCode { + // Token not supported for pinning ERR_WRONG_TOKEN = 1, + // Token metadata has non-ipfs url ERR_NON_IPFS_TOKEN_URL = 2, + // Fetching metadata has failed ERR_FETCH_METADATA_FAILED = 3, ERR_WRONG_METADATA_FORMAT = 4, ERR_ALREADY_PINNED = 5, @@ -239,41 +243,57 @@ struct PinError { }; struct TokenPinStatus { + // Actual token status TokenPinStatusCode code; + // Token error related to the pin status. May be null. PinError? error; + // Last time token was validated(checked that data is pinned correctly) mojo_base.mojom.Time validate_time; }; struct TokenPinOverview { + // Token status for the local pin backend. TokenPinStatus? local; + // Token statuses for remote pin backends. map remotes; }; +// Observers state of the BraveWalletPinService interface BraveWalletPinServiceObserver { OnTokenStatusChanged(string? service, BlockchainToken token, TokenPinStatus status); OnLocalNodeStatusChanged(bool running); }; +// Low-level interface for token pinning. interface WalletPinService { AddObserver(pending_remote observer); + // Launches pinning for provided token. + // At the moment only local pinning is supported so use null "service" argument. AddPin(BlockchainToken token, string? service) =>(bool result, PinError? error); + // Unpins token. RemovePin(BlockchainToken token, string? service) => (bool result, PinError? response); + // Returns overview for provided token. GetTokenStatus(BlockchainToken token) => (TokenPinOverview? status, PinError? error); + // Checks whether token in pinned correctly. Validate(BlockchainToken token, string? service) => (bool result, PinError? error); + // Returns whether IPFS localnode is currently running. IsLocalNodeRunning() => (bool result); + + // Returns whether token is supported for pinning. + IsTokenSupported(BlockchainToken token) => (bool result); }; +// Listens for added user tokens and automatically pins them. interface WalletAutoPinService { + // Enables autopinning, so old and new user tokens may be pinned. SetAutoPinEnabled(bool enabled); IsAutoPinEnabled() => (bool enabled); - PostPinToken(BlockchainToken token) => (bool result); - PostUnpinToken(BlockchainToken token) => (bool result); }; // Used by the WebUI page to bootstrap bidirectional communication. diff --git a/components/ipfs/BUILD.gn b/components/ipfs/BUILD.gn index bba5c0c51458..8dee6455e938 100644 --- a/components/ipfs/BUILD.gn +++ b/components/ipfs/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2022 The Brave Authors. All rights reserved. +# Copyright (c) 2020 The Brave Authors. All rights reserved. # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this file, # You can obtain one at https://mozilla.org/MPL/2.0/. diff --git a/components/ipfs/ipfs_json_parser.cc b/components/ipfs/ipfs_json_parser.cc index 330671332b86..2ddd7d7ba3c8 100644 --- a/components/ipfs/ipfs_json_parser.cc +++ b/components/ipfs/ipfs_json_parser.cc @@ -71,7 +71,12 @@ absl::optional IPFSJSONParser::GetAddPinsResultFromJSON( } for (const base::Value& val : *pins_list) { - result.pins.push_back(val.GetString()); + auto* val_as_str = val.GetIfString(); + if (!val_as_str) { + VLOG(1) << "Invalid response, wrong format."; + return absl::nullopt; + } + result.pins.push_back(*val_as_str); } return result; } diff --git a/components/ipfs/ipfs_json_parser_unittest.cc b/components/ipfs/ipfs_json_parser_unittest.cc index 207755364d65..18ca0f3f561e 100644 --- a/components/ipfs/ipfs_json_parser_unittest.cc +++ b/components/ipfs/ipfs_json_parser_unittest.cc @@ -448,6 +448,13 @@ TEST_F(IPFSJSONParserTest, GetRemovePinsResultFromJSONTest) { EXPECT_TRUE(result.value().empty()); } + { + std::string json = R"({"Pins" : [{}, 123]})"; + auto result = IPFSJSONParser::GetRemovePinsResultFromJSON( + base::test::ParseJson(json)); + EXPECT_FALSE(result.has_value()); + } + { std::string json = R"({"Pins" : ["QmA", "QmB"]})"; auto result = IPFSJSONParser::GetRemovePinsResultFromJSON( @@ -492,6 +499,13 @@ TEST_F(IPFSJSONParserTest, GetAddPinsResultFromJSONTest) { EXPECT_EQ(result->progress, -1); } + { + std::string json = R"({"Pins" : [{}, 123]})"; + auto result = + IPFSJSONParser::GetAddPinsResultFromJSON(base::test::ParseJson(json)); + EXPECT_FALSE(result.has_value()); + } + { std::string json = R"({"Pins" : ["QmA", "QmB"], "Progress" : 10})"; auto result = diff --git a/components/ipfs/pin/ipfs_base_pin_service.cc b/components/ipfs/pin/ipfs_base_pin_service.cc index 7f4bed51553d..ea55664b0508 100644 --- a/components/ipfs/pin/ipfs_base_pin_service.cc +++ b/components/ipfs/pin/ipfs_base_pin_service.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. @@ -19,14 +19,9 @@ IpfsBasePinService::IpfsBasePinService(IpfsService* ipfs_service) ipfs_service_->AddObserver(this); } -IpfsBasePinService::IpfsBasePinService() {} +IpfsBasePinService::IpfsBasePinService() = default; -IpfsBasePinService::~IpfsBasePinService() {} - -// For unit tests -void IpfsBasePinService::RemovePrefListenersForTests() { - pref_change_registrar_.RemoveAll(); -} +IpfsBasePinService::~IpfsBasePinService() = default; void IpfsBasePinService::OnIpfsShutdown() { daemon_ready_ = false; diff --git a/components/ipfs/pin/ipfs_base_pin_service.h b/components/ipfs/pin/ipfs_base_pin_service.h index a4375fff49da..5037c6abe2b1 100644 --- a/components/ipfs/pin/ipfs_base_pin_service.h +++ b/components/ipfs/pin/ipfs_base_pin_service.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. @@ -13,7 +13,6 @@ #include #include "brave/components/ipfs/ipfs_service.h" -#include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_service.h" namespace ipfs { @@ -25,6 +24,8 @@ class IpfsBaseJob { virtual void Start() = 0; }; +// Manages a queue of IpfsService-related tasks. +// Launches IPFS daemon if needed. class IpfsBasePinService : public IpfsServiceObserver { public: explicit IpfsBasePinService(IpfsService* service); @@ -37,8 +38,6 @@ class IpfsBasePinService : public IpfsServiceObserver { void OnGetConnectedPeers(bool succes, const std::vector& peers) override; - void RemovePrefListenersForTests(); - protected: // For testing IpfsBasePinService(); @@ -51,7 +50,6 @@ class IpfsBasePinService : public IpfsServiceObserver { bool daemon_ready_ = false; raw_ptr ipfs_service_; - PrefChangeRegistrar pref_change_registrar_; std::unique_ptr current_job_; std::queue> jobs_; diff --git a/components/ipfs/pin/ipfs_base_pin_service_unittest.cc b/components/ipfs/pin/ipfs_base_pin_service_unittest.cc index f95cef81e9e2..8814bb08bb2c 100644 --- a/components/ipfs/pin/ipfs_base_pin_service_unittest.cc +++ b/components/ipfs/pin/ipfs_base_pin_service_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. @@ -45,10 +45,6 @@ class IpfsBasePinServiceTest : public testing::Test { std::make_unique(GetIpfsService()); } - void TearDown() override { - ipfs_base_pin_service_->RemovePrefListenersForTests(); - } - testing::NiceMock* GetIpfsService() { return &ipfs_service_; } diff --git a/components/ipfs/pin/ipfs_local_pin_service.cc b/components/ipfs/pin/ipfs_local_pin_service.cc index ff55124c1f47..b80cbc8b9ee2 100644 --- a/components/ipfs/pin/ipfs_local_pin_service.cc +++ b/components/ipfs/pin/ipfs_local_pin_service.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. @@ -21,16 +21,16 @@ const char kRecursiveMode[] = "recursive"; AddLocalPinJob::AddLocalPinJob(PrefService* prefs_service, IpfsService* ipfs_service, - const std::string& prefix, + const std::string& key, const std::vector& cids, AddPinCallback callback) : prefs_service_(prefs_service), ipfs_service_(ipfs_service), - prefix_(prefix), + key_(key), cids_(cids), callback_(std::move(callback)) {} -AddLocalPinJob::~AddLocalPinJob() {} +AddLocalPinJob::~AddLocalPinJob() = default; void AddLocalPinJob::Start() { ipfs_service_->AddPin(cids_, true, @@ -57,21 +57,21 @@ void AddLocalPinJob::OnAddPinResult(absl::optional result) { for (const auto& cid : cids_) { base::Value::List* list = update_dict.EnsureList(cid); - list->EraseValue(base::Value(prefix_)); - list->Append(base::Value(prefix_)); + list->EraseValue(base::Value(key_)); + list->Append(base::Value(key_)); } } std::move(callback_).Run(true); } RemoveLocalPinJob::RemoveLocalPinJob(PrefService* prefs_service, - const std::string& prefix, + const std::string& key, RemovePinCallback callback) : prefs_service_(prefs_service), - prefix_(prefix), + key_(key), callback_(std::move(callback)) {} -RemoveLocalPinJob::~RemoveLocalPinJob() {} +RemoveLocalPinJob::~RemoveLocalPinJob() = default; void RemoveLocalPinJob::Start() { { @@ -82,7 +82,7 @@ void RemoveLocalPinJob::Start() { for (auto pair : update_dict) { base::Value::List* list = pair.second.GetIfList(); if (list) { - list->EraseValue(base::Value(prefix_)); + list->EraseValue(base::Value(key_)); if (list->empty()) { remove_list.push_back(pair.first); } @@ -97,16 +97,16 @@ void RemoveLocalPinJob::Start() { VerifyLocalPinJob::VerifyLocalPinJob(PrefService* prefs_service, IpfsService* ipfs_service, - const std::string& prefix, + const std::string& key, const std::vector& cids, ValidatePinsCallback callback) : prefs_service_(prefs_service), ipfs_service_(ipfs_service), - prefix_(prefix), + key_(key), cids_(cids), callback_(std::move(callback)) {} -VerifyLocalPinJob::~VerifyLocalPinJob() {} +VerifyLocalPinJob::~VerifyLocalPinJob() = default; void VerifyLocalPinJob::Start() { ipfs_service_->GetPins(absl::nullopt, kRecursiveMode, true, @@ -129,11 +129,11 @@ void VerifyLocalPinJob::OnGetPinsResult(absl::optional result) { verification_passed = false; } else { if (result->find(cid) != result->end()) { - list->EraseValue(base::Value(prefix_)); - list->Append(base::Value(prefix_)); + list->EraseValue(base::Value(key_)); + list->Append(base::Value(key_)); } else { verification_passed = false; - list->EraseValue(base::Value(prefix_)); + list->EraseValue(base::Value(key_)); } if (list->empty()) { update_dict.Remove(cid); @@ -149,7 +149,8 @@ GcJob::GcJob(PrefService* prefs_service, : prefs_service_(prefs_service), ipfs_service_(ipfs_service), callback_(std::move(callback)) {} -GcJob::~GcJob() {} + +GcJob::~GcJob() = default; void GcJob::Start() { ipfs_service_->GetPins( @@ -195,37 +196,37 @@ IpfsLocalPinService::IpfsLocalPinService(PrefService* prefs_service, base::Minutes(1)); } -IpfsLocalPinService::IpfsLocalPinService() {} +IpfsLocalPinService::IpfsLocalPinService() = default; void IpfsLocalPinService::SetIpfsBasePinServiceForTesting( std::unique_ptr service) { ipfs_base_pin_service_ = std::move(service); } -IpfsLocalPinService::~IpfsLocalPinService() {} +IpfsLocalPinService::~IpfsLocalPinService() = default; -void IpfsLocalPinService::AddPins(const std::string& prefix, +void IpfsLocalPinService::AddPins(const std::string& key, const std::vector& cids, AddPinCallback callback) { ipfs_base_pin_service_->AddJob(std::make_unique( - prefs_service_, ipfs_service_, prefix, cids, + prefs_service_, ipfs_service_, key, cids, base::BindOnce(&IpfsLocalPinService::OnAddJobFinished, weak_ptr_factory_.GetWeakPtr(), std::move(callback)))); } -void IpfsLocalPinService::RemovePins(const std::string& prefix, +void IpfsLocalPinService::RemovePins(const std::string& key, RemovePinCallback callback) { ipfs_base_pin_service_->AddJob(std::make_unique( - prefs_service_, prefix, + prefs_service_, key, base::BindOnce(&IpfsLocalPinService::OnRemovePinsFinished, weak_ptr_factory_.GetWeakPtr(), std::move(callback)))); } -void IpfsLocalPinService::ValidatePins(const std::string& prefix, +void IpfsLocalPinService::ValidatePins(const std::string& key, const std::vector& cids, ValidatePinsCallback callback) { ipfs_base_pin_service_->AddJob(std::make_unique( - prefs_service_, ipfs_service_, prefix, cids, + prefs_service_, ipfs_service_, key, cids, base::BindOnce(&IpfsLocalPinService::OnValidateJobFinished, weak_ptr_factory_.GetWeakPtr(), std::move(callback)))); } diff --git a/components/ipfs/pin/ipfs_local_pin_service.h b/components/ipfs/pin/ipfs_local_pin_service.h index afcd8196f111..9f80a94a5def 100644 --- a/components/ipfs/pin/ipfs_local_pin_service.h +++ b/components/ipfs/pin/ipfs_local_pin_service.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. @@ -23,11 +23,28 @@ using RemovePinCallback = base::OnceCallback; using ValidatePinsCallback = base::OnceCallback)>; using GcCallback = base::OnceCallback; +/** + * Pins provided cids and writes record to kIPFSPinnedCids: + * { + * // List of all pinned CIDs + * "Qme1": [ + * // List of tokens that contain this CID + * "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1" + * "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2" + * ], + * "Qme2": [ + * "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x1" + * ], + * "Qme3": [ + * "nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2" + * ] + * } + */ class AddLocalPinJob : public IpfsBaseJob { public: AddLocalPinJob(PrefService* prefs_service, IpfsService* ipfs_service, - const std::string& prefix, + const std::string& key, const std::vector& cids, AddPinCallback callback); ~AddLocalPinJob() override; @@ -39,16 +56,17 @@ class AddLocalPinJob : public IpfsBaseJob { raw_ptr prefs_service_; raw_ptr ipfs_service_; - std::string prefix_; + std::string key_; std::vector cids_; AddPinCallback callback_; base::WeakPtrFactory weak_ptr_factory_{this}; }; +// Removes records related to the key and launches GC task. class RemoveLocalPinJob : public IpfsBaseJob { public: RemoveLocalPinJob(PrefService* prefs_service, - const std::string& prefix, + const std::string& key, RemovePinCallback callback); ~RemoveLocalPinJob() override; @@ -56,16 +74,17 @@ class RemoveLocalPinJob : public IpfsBaseJob { private: raw_ptr prefs_service_; - std::string prefix_; + std::string key_; RemovePinCallback callback_; base::WeakPtrFactory weak_ptr_factory_{this}; }; +// Verifies that cids are actually pinned class VerifyLocalPinJob : public IpfsBaseJob { public: VerifyLocalPinJob(PrefService* prefs_service, IpfsService* ipfs_service, - const std::string& prefix, + const std::string& key, const std::vector& cids, ValidatePinsCallback callback); ~VerifyLocalPinJob() override; @@ -77,12 +96,13 @@ class VerifyLocalPinJob : public IpfsBaseJob { raw_ptr prefs_service_; raw_ptr ipfs_service_; - std::string prefix_; + std::string key_; std::vector cids_; ValidatePinsCallback callback_; base::WeakPtrFactory weak_ptr_factory_{this}; }; +// Unpins cids that don't have kIPFSPinnedCids record class GcJob : public IpfsBaseJob { public: GcJob(PrefService* prefs_service, @@ -109,12 +129,14 @@ class IpfsLocalPinService : public KeyedService { IpfsLocalPinService(); ~IpfsLocalPinService() override; - virtual void AddPins(const std::string& prefix, + // Pins provided cids and stores related record in the prefs. + virtual void AddPins(const std::string& key, const std::vector& cids, AddPinCallback callback); - virtual void RemovePins(const std::string& prefix, - RemovePinCallback callback); - virtual void ValidatePins(const std::string& prefix, + // Unpins all cids related to the key. + virtual void RemovePins(const std::string& key, RemovePinCallback callback); + // Checks that all cids related to the key are pinned. + virtual void ValidatePins(const std::string& key, const std::vector& cids, ValidatePinsCallback callback); diff --git a/components/ipfs/pin/ipfs_local_pin_service_unittest.cc b/components/ipfs/pin/ipfs_local_pin_service_unittest.cc index ecda844f28e5..76c0c9d11f8b 100644 --- a/components/ipfs/pin/ipfs_local_pin_service_unittest.cc +++ b/components/ipfs/pin/ipfs_local_pin_service_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. diff --git a/components/ipfs/pin/ipfs_pin_rpc_types.cc b/components/ipfs/pin/ipfs_pin_rpc_types.cc index c09cea3c9db3..0a4deca1c27d 100644 --- a/components/ipfs/pin/ipfs_pin_rpc_types.cc +++ b/components/ipfs/pin/ipfs_pin_rpc_types.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. diff --git a/components/ipfs/pin/ipfs_pin_rpc_types.h b/components/ipfs/pin/ipfs_pin_rpc_types.h index 263dd7214ce4..ba0b9c732886 100644 --- a/components/ipfs/pin/ipfs_pin_rpc_types.h +++ b/components/ipfs/pin/ipfs_pin_rpc_types.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Brave Authors. All rights reserved. +// Copyright (c) 2023 The Brave Authors. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. From be3bd529659968d3a082134959e462fef0fc291f Mon Sep 17 00:00:00 2001 From: oisupov Date: Wed, 25 Jan 2023 01:42:57 +0400 Subject: [PATCH 15/15] Review fix --- .../chrome/browser/crypto_wallet/util/AsyncUtils.java | 3 ++- .../brave_wallet/browser/brave_wallet_auto_pin_service.cc | 5 +---- components/brave_wallet/browser/brave_wallet_pin_service.cc | 5 +++++ components/brave_wallet/browser/brave_wallet_pin_service.h | 4 ++++ components/brave_wallet/browser/brave_wallet_service.cc | 3 ++- components/brave_wallet/common/brave_wallet.mojom | 6 +++++- 6 files changed, 19 insertions(+), 7 deletions(-) diff --git a/android/java/org/chromium/chrome/browser/crypto_wallet/util/AsyncUtils.java b/android/java/org/chromium/chrome/browser/crypto_wallet/util/AsyncUtils.java index 1e50cd7c4059..07116be2fb5c 100644 --- a/android/java/org/chromium/chrome/browser/crypto_wallet/util/AsyncUtils.java +++ b/android/java/org/chromium/chrome/browser/crypto_wallet/util/AsyncUtils.java @@ -423,7 +423,8 @@ public GetNftErc721MetadataContext(Runnable responseCompleteCallback) { } @Override - public void call(String tokenUrl, String erc721Metadata, Integer errorCode, String errorMessage) { + public void call( + String tokenUrl, String erc721Metadata, Integer errorCode, String errorMessage) { this.tokenMetadata = erc721Metadata; this.errorCode = errorCode; this.errorMessage = errorMessage; diff --git a/components/brave_wallet/browser/brave_wallet_auto_pin_service.cc b/components/brave_wallet/browser/brave_wallet_auto_pin_service.cc index 1217a041d13c..5e5dd6f371b2 100644 --- a/components/brave_wallet/browser/brave_wallet_auto_pin_service.cc +++ b/components/brave_wallet/browser/brave_wallet_auto_pin_service.cc @@ -87,10 +87,7 @@ void BraveWalletAutoPinService::OnTokenListResolved( continue; } - auto it = known_tokens.find(current_token_path.value()); - if (it != known_tokens.end()) { - known_tokens.erase(it); - } + known_tokens.erase(current_token_path.value()); mojom::TokenPinStatusPtr status = brave_wallet_pin_service_->GetTokenStatus(absl::nullopt, token); diff --git a/components/brave_wallet/browser/brave_wallet_pin_service.cc b/components/brave_wallet/browser/brave_wallet_pin_service.cc index a767587ccca1..443afc5e46ea 100644 --- a/components/brave_wallet/browser/brave_wallet_pin_service.cc +++ b/components/brave_wallet/browser/brave_wallet_pin_service.cc @@ -33,6 +33,11 @@ const char kAssetUrlListKey[] = "cids"; namespace { const char kNftPart[] = "nft"; +/** + * Service name used in prefs for local pinning service. + * Use absl::nullopt in methods to perform operations on + * the local pinning service. + */ const char kLocalService[] = "local"; absl::optional StringToStatus( diff --git a/components/brave_wallet/browser/brave_wallet_pin_service.h b/components/brave_wallet/browser/brave_wallet_pin_service.h index 461b695c5f6d..6d87692a8add 100644 --- a/components/brave_wallet/browser/brave_wallet_pin_service.h +++ b/components/brave_wallet/browser/brave_wallet_pin_service.h @@ -27,6 +27,10 @@ namespace brave_wallet { +/** + * At the moment only local pinning is supported so use absl::nullopt + * for optional service argument. + */ class BraveWalletPinService : public KeyedService, public brave_wallet::mojom::WalletPinService, public ipfs::IpfsServiceObserver { diff --git a/components/brave_wallet/browser/brave_wallet_service.cc b/components/brave_wallet/browser/brave_wallet_service.cc index 82ec48511315..6c71f9907542 100644 --- a/components/brave_wallet/browser/brave_wallet_service.cc +++ b/components/brave_wallet/browser/brave_wallet_service.cc @@ -1450,7 +1450,8 @@ void BraveWalletService::DiscoverAssetsOnAllSupportedChains() { addresses[mojom::CoinType::SOL] = std::move(sol_account_addresses); // Discover assets owned by the SOL and ETH addresses on all supported chains - asset_discovery_manager_->DiscoverAssetsOnAllSupportedChainsRefresh(addresses); + asset_discovery_manager_->DiscoverAssetsOnAllSupportedChainsRefresh( + addresses); } void BraveWalletService::CancelAllSuggestedTokenCallbacks() { diff --git a/components/brave_wallet/common/brave_wallet.mojom b/components/brave_wallet/common/brave_wallet.mojom index 9ab969ca61f6..a9bfd0925027 100644 --- a/components/brave_wallet/common/brave_wallet.mojom +++ b/components/brave_wallet/common/brave_wallet.mojom @@ -266,6 +266,9 @@ interface BraveWalletPinServiceObserver { }; // Low-level interface for token pinning. +// String service argument is used to select on which pinning +// service operation should be performed. +// At the moment we have only local pinning, so use null. interface WalletPinService { AddObserver(pending_remote observer); @@ -279,13 +282,14 @@ interface WalletPinService { // Returns overview for provided token. GetTokenStatus(BlockchainToken token) => (TokenPinOverview? status, PinError? error); - // Checks whether token in pinned correctly. + // Checks whether token is pinned correctly. Validate(BlockchainToken token, string? service) => (bool result, PinError? error); // Returns whether IPFS localnode is currently running. IsLocalNodeRunning() => (bool result); // Returns whether token is supported for pinning. + // Note: You should manually check token metadata url to have ipfs:// url. IsTokenSupported(BlockchainToken token) => (bool result); };