From 91669cc660bf1c291a5eba3decbb087631c9f3dd Mon Sep 17 00:00:00 2001 From: Szilard Szaloki Date: Fri, 18 Nov 2022 22:56:44 -0500 Subject: [PATCH] Implements `GetRecipientIDGemini`. --- vendor/bat-native-ledger/BUILD.gn | 2 + .../public/interfaces/ledger_endpoints.mojom | 6 + .../internal/endpoint/gemini/gemini_utils.h | 9 +- .../post_recipient_id_gemini.cc | 2 +- .../get_recipient_id_gemini.cc | 84 ++++++++++ .../get_recipient_id_gemini.h | 71 +++++++++ .../get_recipient_id_gemini_unittest.cc | 145 ++++++++++++++++++ .../gemini/connect_gemini_wallet.cc | 44 +++++- .../gemini/connect_gemini_wallet.h | 13 +- vendor/bat-native-ledger/test/BUILD.gn | 1 + 10 files changed, 362 insertions(+), 15 deletions(-) create mode 100644 vendor/bat-native-ledger/src/bat/ledger/internal/endpoints/gemini/get_recipient_id/get_recipient_id_gemini.cc create mode 100644 vendor/bat-native-ledger/src/bat/ledger/internal/endpoints/gemini/get_recipient_id/get_recipient_id_gemini.h create mode 100644 vendor/bat-native-ledger/src/bat/ledger/internal/endpoints/gemini/get_recipient_id/get_recipient_id_gemini_unittest.cc diff --git a/vendor/bat-native-ledger/BUILD.gn b/vendor/bat-native-ledger/BUILD.gn index cc87cb82c01a..b07e67a26bb5 100644 --- a/vendor/bat-native-ledger/BUILD.gn +++ b/vendor/bat-native-ledger/BUILD.gn @@ -407,6 +407,8 @@ source_set("ledger") { "src/bat/ledger/internal/endpoint/uphold/uphold_server.h", "src/bat/ledger/internal/endpoint/uphold/uphold_utils.cc", "src/bat/ledger/internal/endpoint/uphold/uphold_utils.h", + "src/bat/ledger/internal/endpoints/gemini/get_recipient_id/get_recipient_id_gemini.cc", + "src/bat/ledger/internal/endpoints/gemini/get_recipient_id/get_recipient_id_gemini.h", "src/bat/ledger/internal/endpoints/get_parameters/get_parameters.cc", "src/bat/ledger/internal/endpoints/get_parameters/get_parameters.h", "src/bat/ledger/internal/endpoints/get_parameters/get_parameters_utils.cc", diff --git a/vendor/bat-native-ledger/include/bat/ledger/public/interfaces/ledger_endpoints.mojom b/vendor/bat-native-ledger/include/bat/ledger/public/interfaces/ledger_endpoints.mojom index a2e4d00af782..a0ef9f4f1788 100644 --- a/vendor/bat-native-ledger/include/bat/ledger/public/interfaces/ledger_endpoints.mojom +++ b/vendor/bat-native-ledger/include/bat/ledger/public/interfaces/ledger_endpoints.mojom @@ -4,6 +4,12 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. module ledger.mojom; +enum GetRecipientIDGeminiError { + kFailedToCreateRequest, + kUnexpectedStatusCode, // HTTP xxx + kFailedToParseBody +}; + enum GetParametersError { kFailedToCreateRequest, kFailedToGetParameters, // HTTP 500 diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/endpoint/gemini/gemini_utils.h b/vendor/bat-native-ledger/src/bat/ledger/internal/endpoint/gemini/gemini_utils.h index 4a078ce26d41..9106e0c86ba2 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/endpoint/gemini/gemini_utils.h +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/endpoint/gemini/gemini_utils.h @@ -12,8 +12,10 @@ #include "bat/ledger/ledger.h" namespace ledger { -namespace endpoint { -namespace gemini { +namespace endpoints { +inline const char kGeminiRecipientIDLabel[] = "Brave Browser"; +} +namespace endpoint::gemini { std::string GetClientId(); @@ -26,8 +28,7 @@ std::string GetOauthServerUrl(const std::string& path); mojom::Result CheckStatusCode(const int status_code); -} // namespace gemini -} // namespace endpoint +} // namespace endpoint::gemini } // namespace ledger #endif // BRAVE_VENDOR_BAT_NATIVE_LEDGER_SRC_BAT_LEDGER_INTERNAL_ENDPOINT_GEMINI_GEMINI_UTILS_H_ diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/endpoint/gemini/post_recipient_id/post_recipient_id_gemini.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/endpoint/gemini/post_recipient_id/post_recipient_id_gemini.cc index d0d54c185b19..1a0a58980d79 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/endpoint/gemini/post_recipient_id/post_recipient_id_gemini.cc +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/endpoint/gemini/post_recipient_id/post_recipient_id_gemini.cc @@ -56,7 +56,7 @@ mojom::Result PostRecipientId::ParseBody(const std::string& body, std::string PostRecipientId::GeneratePayload() { base::Value::Dict payload; - payload.Set("label", base::GenerateGUID()); + payload.Set("label", endpoints::kGeminiRecipientIDLabel); std::string json; base::JSONWriter::Write(payload, &json); diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/endpoints/gemini/get_recipient_id/get_recipient_id_gemini.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/endpoints/gemini/get_recipient_id/get_recipient_id_gemini.cc new file mode 100644 index 000000000000..30ba0467a28e --- /dev/null +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/endpoints/gemini/get_recipient_id/get_recipient_id_gemini.cc @@ -0,0 +1,84 @@ +/* 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 "bat/ledger/internal/endpoints/gemini/get_recipient_id/get_recipient_id_gemini.h" + +#include + +#include "base/json/json_reader.h" +#include "bat/ledger/internal/endpoint/gemini/gemini_utils.h" +#include "bat/ledger/internal/ledger_impl.h" +#include "net/http/http_status_code.h" + +namespace ledger::endpoints { +using Error = GetRecipientIDGemini::Error; +using Result = GetRecipientIDGemini::Result; + +namespace { + +Result ParseBody(const std::string& body) { + auto value = base::JSONReader::Read(body); + if (!value || !value->is_list()) { + BLOG(0, "Failed to parse body!"); + return base::unexpected(Error::kFailedToParseBody); + } + + for (auto& item : value->GetList()) { + auto* pair = item.GetIfDict(); + if (!pair) { + BLOG(0, "Failed to parse body!"); + return base::unexpected(Error::kFailedToParseBody); + } + + auto* label = pair->FindString("label"); + auto* recipient_id = pair->FindString("recipient_id"); + + if (!label || !recipient_id) { + BLOG(0, "Failed to parse body!"); + return base::unexpected(Error::kFailedToParseBody); + } + + if (*label == kGeminiRecipientIDLabel) { + return std::move(*recipient_id); + } + } + + return ""; +} + +} // namespace + +// static +Result GetRecipientIDGemini::ProcessResponse( + const mojom::UrlResponse& response) { + switch (response.status_code) { + case net::HTTP_OK: // HTTP 200 + return ParseBody(response.body); + default: + BLOG(0, "Unexpected status code! (HTTP " << response.status_code << ')'); + return base::unexpected(Error::kUnexpectedStatusCode); + } +} + +GetRecipientIDGemini::GetRecipientIDGemini(LedgerImpl* ledger, + std::string&& token) + : RequestBuilder(ledger), token_(std::move(token)) {} + +GetRecipientIDGemini::~GetRecipientIDGemini() = default; + +absl::optional GetRecipientIDGemini::Url() const { + return endpoint::gemini::GetApiServerUrl("/v1/payments/recipientIds"); +} + +mojom::UrlMethod GetRecipientIDGemini::Method() const { + return mojom::UrlMethod::GET; +} + +absl::optional> GetRecipientIDGemini::Headers( + const std::string&) const { + return endpoint::gemini::RequestAuthorization(token_); +} + +} // namespace ledger::endpoints diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/endpoints/gemini/get_recipient_id/get_recipient_id_gemini.h b/vendor/bat-native-ledger/src/bat/ledger/internal/endpoints/gemini/get_recipient_id/get_recipient_id_gemini.h new file mode 100644 index 000000000000..be310420652c --- /dev/null +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/endpoints/gemini/get_recipient_id/get_recipient_id_gemini.h @@ -0,0 +1,71 @@ +/* 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_VENDOR_BAT_NATIVE_LEDGER_SRC_BAT_LEDGER_INTERNAL_ENDPOINTS_GEMINI_GET_RECIPIENT_ID_GET_RECIPIENT_ID_GEMINI_H_ +#define BRAVE_VENDOR_BAT_NATIVE_LEDGER_SRC_BAT_LEDGER_INTERNAL_ENDPOINTS_GEMINI_GET_RECIPIENT_ID_GET_RECIPIENT_ID_GEMINI_H_ + +#include +#include + +#include "bat/ledger/internal/endpoints/request_builder.h" +#include "bat/ledger/internal/endpoints/response_handler.h" +#include "bat/ledger/internal/endpoints/result_for.h" +#include "brave/vendor/bat-native-ledger/include/bat/ledger/public/interfaces/ledger_endpoints.mojom.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +// GET /v1/payments/recipientIds +// +// Request body: +// - +// +// Response body: +// [ +// { +// "label": "95eac685-3e3e-4e5d-a32d-5bc18716cb0d", +// "recipient_id": "621609a9-ce36-453f-b892-0d7b42212329" +// }, { +// "label": "de476441-a834-4b93-82e3-3226e5153f73", +// "recipient_id": "621d392c-75b3-b655-94e4-2849a44d38a9" +// }, { +// "label": "Brave Browser", +// "recipient_id": "6378fc55-18db-488a-85a3-1af557767d0a" +// } +// ] + +namespace ledger { +class LedgerImpl; + +namespace endpoints { + +class GetRecipientIDGemini; + +template <> +struct ResultFor { + using Value = std::string; // recipient ID + using Error = mojom::GetRecipientIDGeminiError; +}; + +class GetRecipientIDGemini final + : public RequestBuilder, + public ResponseHandler { + public: + static Result ProcessResponse(const mojom::UrlResponse&); + + GetRecipientIDGemini(LedgerImpl*, std::string&& token); + ~GetRecipientIDGemini() override; + + private: + absl::optional Url() const override; + mojom::UrlMethod Method() const override; + absl::optional> Headers( + const std::string& content) const override; + + std::string token_; +}; + +} // namespace endpoints +} // namespace ledger + +#endif // BRAVE_VENDOR_BAT_NATIVE_LEDGER_SRC_BAT_LEDGER_INTERNAL_ENDPOINTS_GEMINI_GET_RECIPIENT_ID_GET_RECIPIENT_ID_GEMINI_H_ diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/endpoints/gemini/get_recipient_id/get_recipient_id_gemini_unittest.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/endpoints/gemini/get_recipient_id/get_recipient_id_gemini_unittest.cc new file mode 100644 index 000000000000..842781db5e02 --- /dev/null +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/endpoints/gemini/get_recipient_id/get_recipient_id_gemini_unittest.cc @@ -0,0 +1,145 @@ +/* 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 +#include +#include + +#include "base/test/bind.h" +#include "base/test/task_environment.h" +#include "bat/ledger/internal/endpoints/gemini/get_recipient_id/get_recipient_id_gemini.h" +#include "bat/ledger/internal/endpoints/request_for.h" +#include "bat/ledger/internal/ledger_client_mock.h" +#include "bat/ledger/internal/ledger_impl_mock.h" +#include "net/http/http_status_code.h" +#include "testing/gtest/include/gtest/gtest.h" + +// npm run test -- brave_unit_tests --filter=*GetRecipientIDGemini* + +using ::testing::_; +using ::testing::Invoke; +using ::testing::TestParamInfo; +using ::testing::TestWithParam; +using ::testing::Values; + +namespace ledger::endpoints::test { +using Error = GetRecipientIDGemini::Error; +using Result = GetRecipientIDGemini::Result; + +// clang-format off +using GetRecipientIDGeminiParamType = std::tuple< + std::string, // test name suffix + net::HttpStatusCode, // GET recipient ID Gemini endpoint response status code + std::string, // GET recipient ID Gemini endpoint response body + Result // expected result +>; +// clang-format on + +class GetRecipientIDGemini + : public TestWithParam { + public: + GetRecipientIDGemini(const GetRecipientIDGemini&) = delete; + GetRecipientIDGemini& operator=(const GetRecipientIDGemini&) = delete; + + GetRecipientIDGemini(GetRecipientIDGemini&&) = delete; + GetRecipientIDGemini& operator=(GetRecipientIDGemini&&) = delete; + + private: + base::test::TaskEnvironment task_environment_; + + protected: + GetRecipientIDGemini() + : mock_ledger_client_(), mock_ledger_impl_(&mock_ledger_client_) {} + + MockLedgerClient mock_ledger_client_; + MockLedgerImpl mock_ledger_impl_; +}; + +TEST_P(GetRecipientIDGemini, Paths) { + const auto& [ignore, status_code, body, expected_result] = GetParam(); + + ON_CALL(mock_ledger_client_, LoadURL(_, _)) + .WillByDefault(Invoke( + [status_code = status_code, body = body]( + mojom::UrlRequestPtr, client::LoadURLCallback callback) mutable { + mojom::UrlResponse response; + response.status_code = status_code; + response.body = std::move(body); + std::move(callback).Run(response); + })); + + RequestFor(&mock_ledger_impl_, "token") + .Send(base::BindLambdaForTesting( + [expected_result = expected_result](Result&& result) { + EXPECT_EQ(result, expected_result); + })); +} + +// clang-format off +INSTANTIATE_TEST_SUITE_P( + Endpoints, + GetRecipientIDGemini, + Values( + GetRecipientIDGeminiParamType{ + "HTTP_200_success", + net::HTTP_OK, + R"( + [ + { + "label": "de476441-a834-4b93-82e3-3226e5153f73", + "recipient_id": "621d392c-75b3-b655-94e4-2849a44d38a9" + }, { + "label": "Brave Browser", + "recipient_id": "6378fc55-18db-488a-85a3-1af557767d0a" + } + ] + )", + "6378fc55-18db-488a-85a3-1af557767d0a" + }, + GetRecipientIDGeminiParamType{ + "HTTP_200_no_recipient_id_with_brave_browser_label", + net::HTTP_OK, + R"( + [ + { + "label": "de476441-a834-4b93-82e3-3226e5153f73", + "recipient_id": "621d392c-75b3-b655-94e4-2849a44d38a9" + }, { + "label": "not Brave Browser", + "recipient_id": "6378fc55-18db-488a-85a3-1af557767d0a" + } + ] + )", + "" + }, + GetRecipientIDGeminiParamType{ + "HTTP_200_failed_to_parse_body", + net::HTTP_OK, + R"( + [ + { + "label": "de476441-a834-4b93-82e3-3226e5153f73", + "recipient_id": "621d392c-75b3-b655-94e4-2849a44d38a9" + }, { + "label": 42, + "recipient_id": 42 + } + ] + )", + base::unexpected(Error::kFailedToParseBody) + }, + GetRecipientIDGeminiParamType{ + "HTTP_503_unexpected_status_code", + net::HTTP_SERVICE_UNAVAILABLE, + "", + base::unexpected(Error::kUnexpectedStatusCode) + }), + [](const auto& info) { + return std::get<0>(info.param); + } +); +// clang-format on + +} // namespace ledger::endpoints::test diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/wallet_provider/gemini/connect_gemini_wallet.cc b/vendor/bat-native-ledger/src/bat/ledger/internal/wallet_provider/gemini/connect_gemini_wallet.cc index 864288341a46..fa69cfdbf9d5 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/wallet_provider/gemini/connect_gemini_wallet.cc +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/wallet_provider/gemini/connect_gemini_wallet.cc @@ -19,6 +19,7 @@ #include "bat/ledger/internal/logging/event_log_keys.h" #include "crypto/sha2.h" +using ledger::endpoints::GetRecipientIDGemini; using ledger::endpoints::PostConnectGemini; using ledger::endpoints::RequestFor; using ledger::wallet_provider::ConnectExternalWallet; @@ -80,13 +81,44 @@ void ConnectGeminiWallet::OnAuthorize( base::unexpected(mojom::ConnectExternalWalletError::kUnexpected)); } - gemini_server_->post_recipient_id()->Request( - token, - base::BindOnce(&ConnectGeminiWallet::OnFetchRecipientId, - base::Unretained(this), std::move(callback), token)); + auto on_get_recipient_id = + base::BindOnce(&ConnectGeminiWallet::OnGetRecipientID, + base::Unretained(this), std::move(callback), token); + + RequestFor(ledger_, std::move(token)) + .Send(std::move(on_get_recipient_id)); +} + +void ConnectGeminiWallet::OnGetRecipientID( + ledger::ConnectExternalWalletCallback callback, + std::string&& token, + endpoints::GetRecipientIDGemini::Result&& result) const { + if (!ledger_->gemini()->GetWalletIf({mojom::WalletStatus::kNotConnected, + mojom::WalletStatus::kLoggedOut})) { + return std::move(callback).Run( + base::unexpected(mojom::ConnectExternalWalletError::kUnexpected)); + } + + if (!result.has_value()) { + return std::move(callback).Run( + base::unexpected(mojom::ConnectExternalWalletError::kUnexpected)); + } + + auto recipient_id = std::move(result).value(); + if (recipient_id.empty()) { + return gemini_server_->post_recipient_id()->Request( + token, + base::BindOnce(&ConnectGeminiWallet::OnPostRecipientID, + base::Unretained(this), std::move(callback), token)); + } + + gemini_server_->post_account()->Request( + token, base::BindOnce(&ConnectGeminiWallet::OnPostAccount, + base::Unretained(this), std::move(callback), token, + std::move(recipient_id))); } -void ConnectGeminiWallet::OnFetchRecipientId( +void ConnectGeminiWallet::OnPostRecipientID( ledger::ConnectExternalWalletCallback callback, std::string&& token, mojom::Result result, @@ -112,7 +144,7 @@ void ConnectGeminiWallet::OnFetchRecipientId( } if (result != mojom::Result::LEDGER_OK) { - BLOG(0, "Failed to fetch recipient ID!"); + BLOG(0, "Failed to create recipient ID!"); return std::move(callback).Run( base::unexpected(mojom::ConnectExternalWalletError::kUnexpected)); } diff --git a/vendor/bat-native-ledger/src/bat/ledger/internal/wallet_provider/gemini/connect_gemini_wallet.h b/vendor/bat-native-ledger/src/bat/ledger/internal/wallet_provider/gemini/connect_gemini_wallet.h index 1ed2ff8299e3..8f6cd9a72593 100644 --- a/vendor/bat-native-ledger/src/bat/ledger/internal/wallet_provider/gemini/connect_gemini_wallet.h +++ b/vendor/bat-native-ledger/src/bat/ledger/internal/wallet_provider/gemini/connect_gemini_wallet.h @@ -10,6 +10,7 @@ #include #include "base/containers/flat_map.h" +#include "bat/ledger/internal/endpoints/gemini/get_recipient_id/get_recipient_id_gemini.h" #include "bat/ledger/internal/wallet_provider/connect_external_wallet.h" #include "bat/ledger/ledger.h" @@ -38,10 +39,14 @@ class ConnectGeminiWallet : public wallet_provider::ConnectExternalWallet { mojom::Result, std::string&& token) const; - void OnFetchRecipientId(ledger::ConnectExternalWalletCallback, - std::string&& token, - mojom::Result, - std::string&& recipient_id) const; + void OnGetRecipientID(ledger::ConnectExternalWalletCallback, + std::string&& token, + endpoints::GetRecipientIDGemini::Result&&) const; + + void OnPostRecipientID(ledger::ConnectExternalWalletCallback, + std::string&& token, + mojom::Result, + std::string&& recipient_id) const; void OnPostAccount(ledger::ConnectExternalWalletCallback, std::string&& token, diff --git a/vendor/bat-native-ledger/test/BUILD.gn b/vendor/bat-native-ledger/test/BUILD.gn index a7f4cdfdc79c..6c9f0a1eb86f 100644 --- a/vendor/bat-native-ledger/test/BUILD.gn +++ b/vendor/bat-native-ledger/test/BUILD.gn @@ -81,6 +81,7 @@ source_set("bat_native_ledger_tests") { "//brave/vendor/bat-native-ledger/src/bat/ledger/internal/endpoint/uphold/post_transaction/post_transaction_unittest.cc", "//brave/vendor/bat-native-ledger/src/bat/ledger/internal/endpoint/uphold/post_transaction_commit/post_transaction_commit_unittest.cc", "//brave/vendor/bat-native-ledger/src/bat/ledger/internal/endpoint/uphold/uphold_utils_unittest.cc", + "//brave/vendor/bat-native-ledger/src/bat/ledger/internal/endpoints/gemini/get_recipient_id/get_recipient_id_gemini_unittest.cc", "//brave/vendor/bat-native-ledger/src/bat/ledger/internal/endpoints/get_parameters/get_parameters_unittest.cc", "//brave/vendor/bat-native-ledger/src/bat/ledger/internal/endpoints/patch_wallets/patch_wallets_unittest.cc", "//brave/vendor/bat-native-ledger/src/bat/ledger/internal/endpoints/post_connect/post_connect_unittest.cc",