| // Copyright 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/payments/content/payment_handler_host.h" |
| |
| #include <utility> |
| |
| #include "base/callback.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "components/payments/core/error_strings.h" |
| #include "components/payments/core/native_error_strings.h" |
| #include "components/payments/core/payment_address.h" |
| #include "components/payments/core/payments_validators.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/devtools_background_services_context.h" |
| #include "content/public/browser/storage_partition.h" |
| #include "content/public/browser/web_contents.h" |
| #include "url/origin.h" |
| |
| namespace payments { |
| namespace { |
| |
| content::DevToolsBackgroundServicesContext* GetDevTools( |
| content::BrowserContext* browser_context, |
| const url::Origin& sw_origin) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| auto* storage_partition = content::BrowserContext::GetStoragePartitionForSite( |
| browser_context, sw_origin.GetURL(), /*can_create=*/true); |
| if (!storage_partition) |
| return nullptr; |
| |
| auto* dev_tools = storage_partition->GetDevToolsBackgroundServicesContext(); |
| return dev_tools && dev_tools->IsRecording( |
| content::DevToolsBackgroundService::kPaymentHandler) |
| ? dev_tools |
| : nullptr; |
| } |
| |
| // Generates a PaymentResponse with the given error, then runs the provided |
| // callback. |
| void RunCallbackWithError(const std::string& error, |
| ChangePaymentRequestDetailsCallback callback) { |
| mojom::PaymentRequestDetailsUpdatePtr response = |
| mojom::PaymentRequestDetailsUpdate::New(); |
| response->error = error; |
| std::move(callback).Run(std::move(response)); |
| } |
| |
| } // namespace |
| |
| PaymentHandlerHost::PaymentHandlerHost(content::WebContents* web_contents, |
| Delegate* delegate) |
| : web_contents_(web_contents), delegate_(delegate) { |
| DCHECK(web_contents_); |
| DCHECK(delegate_); |
| } |
| |
| PaymentHandlerHost::~PaymentHandlerHost() {} |
| |
| mojo::PendingRemote<mojom::PaymentHandlerHost> PaymentHandlerHost::Bind() { |
| receiver_.reset(); |
| mojo::PendingRemote<mojom::PaymentHandlerHost> host = |
| receiver_.BindNewPipeAndPassRemote(); |
| |
| // Connection error handler can be set only after the Bind() call. |
| receiver_.set_disconnect_handler(base::BindOnce( |
| &PaymentHandlerHost::Disconnect, weak_ptr_factory_.GetWeakPtr())); |
| |
| return host; |
| } |
| |
| void PaymentHandlerHost::UpdateWith( |
| mojom::PaymentRequestDetailsUpdatePtr response) { |
| if (!change_payment_request_details_callback_) |
| return; |
| |
| auto* dev_tools = |
| GetDevTools(web_contents_->GetBrowserContext(), sw_origin_for_logs_); |
| if (dev_tools) { |
| std::map<std::string, std::string> data = {{"Error", response->error}}; |
| |
| if (response->total) { |
| data["Total Currency"] = response->total->currency; |
| data["Total Value"] = response->total->value; |
| } |
| |
| if (response->stringified_payment_method_errors) { |
| data["Payment Method Errors"] = |
| *response->stringified_payment_method_errors; |
| } |
| |
| if (response->shipping_address_errors) { |
| data["Shipping Address Address Line Error"] = |
| response->shipping_address_errors->address_line; |
| data["Shipping Address City Error"] = |
| response->shipping_address_errors->city; |
| data["Shipping Address Country Error"] = |
| response->shipping_address_errors->country; |
| data["Shipping Address Dependent Locality Error"] = |
| response->shipping_address_errors->dependent_locality; |
| data["Shipping Address Organization Error"] = |
| response->shipping_address_errors->organization; |
| data["Shipping Address Phone Error"] = |
| response->shipping_address_errors->phone; |
| data["Shipping Address Postal Code Error"] = |
| response->shipping_address_errors->postal_code; |
| data["Shipping Address Recipient Error"] = |
| response->shipping_address_errors->recipient; |
| data["Shipping Address Region Error"] = |
| response->shipping_address_errors->region; |
| data["Shipping Address Sorting Code Error"] = |
| response->shipping_address_errors->sorting_code; |
| } |
| |
| if (response->modifiers) { |
| for (size_t i = 0; i < response->modifiers->size(); ++i) { |
| std::string prefix = |
| "Modifier" + (response->modifiers->size() == 1 |
| ? "" |
| : " #" + base::NumberToString(i)); |
| const auto& modifier = response->modifiers->at(i); |
| data.emplace(prefix + " Method Name", |
| modifier->method_data->method_name); |
| data.emplace(prefix + " Method Data", |
| modifier->method_data->stringified_data); |
| if (!modifier->total) |
| continue; |
| data.emplace(prefix + " Total Currency", modifier->total->currency); |
| data.emplace(prefix + " Total Value", modifier->total->value); |
| } |
| } |
| |
| if (response->shipping_options) { |
| for (size_t i = 0; i < response->shipping_options->size(); ++i) { |
| std::string prefix = |
| "Shipping Option" + (response->shipping_options->size() == 1 |
| ? "" |
| : " #" + base::NumberToString(i)); |
| const auto& option = response->shipping_options->at(i); |
| data.emplace(prefix + " Id", option->id); |
| data.emplace(prefix + " Label", option->label); |
| data.emplace(prefix + " Amount Currency", option->amount->currency); |
| data.emplace(prefix + " Amount Value", option->amount->value); |
| data.emplace(prefix + " Selected", option->selected ? "true" : "false"); |
| } |
| } |
| |
| dev_tools->LogBackgroundServiceEvent( |
| registration_id_for_logs_, sw_origin_for_logs_, |
| content::DevToolsBackgroundService::kPaymentHandler, "Update with", |
| /*instance_id=*/payment_request_id_for_logs_, data); |
| } |
| |
| std::move(change_payment_request_details_callback_).Run(std::move(response)); |
| } |
| |
| void PaymentHandlerHost::NoUpdatedPaymentDetails() { |
| if (!change_payment_request_details_callback_) |
| return; |
| |
| std::move(change_payment_request_details_callback_) |
| .Run(mojom::PaymentRequestDetailsUpdate::New()); |
| } |
| |
| void PaymentHandlerHost::Disconnect() { |
| receiver_.reset(); |
| } |
| |
| base::WeakPtr<PaymentHandlerHost> PaymentHandlerHost::AsWeakPtr() { |
| return weak_ptr_factory_.GetWeakPtr(); |
| } |
| |
| void PaymentHandlerHost::ChangePaymentMethod( |
| mojom::PaymentHandlerMethodDataPtr method_data, |
| ChangePaymentRequestDetailsCallback callback) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| |
| if (!method_data) { |
| RunCallbackWithError(errors::kMethodDataRequired, std::move(callback)); |
| return; |
| } |
| |
| if (method_data->method_name.empty()) { |
| RunCallbackWithError(errors::kMethodNameRequired, std::move(callback)); |
| return; |
| } |
| |
| if (!delegate_->ChangePaymentMethod(method_data->method_name, |
| method_data->stringified_data)) { |
| RunCallbackWithError(errors::kInvalidState, std::move(callback)); |
| return; |
| } |
| |
| auto* dev_tools = |
| GetDevTools(web_contents_->GetBrowserContext(), sw_origin_for_logs_); |
| if (dev_tools) { |
| dev_tools->LogBackgroundServiceEvent( |
| registration_id_for_logs_, sw_origin_for_logs_, |
| content::DevToolsBackgroundService::kPaymentHandler, |
| "Change payment method", |
| /*instance_id=*/payment_request_id_for_logs_, |
| {{"Method Name", method_data->method_name}, |
| {"Method Data", method_data->stringified_data}}); |
| } |
| |
| change_payment_request_details_callback_ = std::move(callback); |
| } |
| |
| void PaymentHandlerHost::ChangeShippingOption( |
| const std::string& shipping_option_id, |
| ChangePaymentRequestDetailsCallback callback) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| |
| if (shipping_option_id.empty()) { |
| RunCallbackWithError(errors::kShippingOptionIdRequired, |
| std::move(callback)); |
| return; |
| } |
| |
| if (!delegate_->ChangeShippingOption(shipping_option_id)) { |
| RunCallbackWithError(errors::kInvalidState, std::move(callback)); |
| return; |
| } |
| |
| auto* dev_tools = |
| GetDevTools(web_contents_->GetBrowserContext(), sw_origin_for_logs_); |
| if (dev_tools) { |
| dev_tools->LogBackgroundServiceEvent( |
| registration_id_for_logs_, sw_origin_for_logs_, |
| content::DevToolsBackgroundService::kPaymentHandler, |
| "Change shipping option", |
| /*instance_id=*/payment_request_id_for_logs_, |
| {{"Shipping Option Id", shipping_option_id}}); |
| } |
| |
| change_payment_request_details_callback_ = std::move(callback); |
| } |
| |
| void PaymentHandlerHost::ChangeShippingAddress( |
| mojom::PaymentAddressPtr shipping_address, |
| ChangePaymentRequestDetailsCallback callback) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| |
| if (!shipping_address || !PaymentsValidators::IsValidCountryCodeFormat( |
| shipping_address->country, nullptr)) { |
| RunCallbackWithError(errors::kShippingAddressInvalid, std::move(callback)); |
| return; |
| } |
| |
| if (!delegate_->ChangeShippingAddress(shipping_address.Clone())) { |
| RunCallbackWithError(errors::kInvalidState, std::move(callback)); |
| return; |
| } |
| |
| auto* dev_tools = |
| GetDevTools(web_contents_->GetBrowserContext(), sw_origin_for_logs_); |
| if (dev_tools) { |
| std::map<std::string, std::string> shipping_address_map; |
| shipping_address_map.emplace("Country", shipping_address->country); |
| for (size_t i = 0; i < shipping_address->address_line.size(); ++i) { |
| std::string key = |
| "Address Line" + (shipping_address->address_line.size() == 1 |
| ? "" |
| : " #" + base::NumberToString(i)); |
| shipping_address_map.emplace(key, shipping_address->address_line[i]); |
| } |
| |
| shipping_address_map.emplace("Region", shipping_address->region); |
| shipping_address_map.emplace("City", shipping_address->city); |
| shipping_address_map.emplace("Dependent Locality", |
| shipping_address->dependent_locality); |
| shipping_address_map.emplace("Postal Code", shipping_address->postal_code); |
| shipping_address_map.emplace("Sorting Code", |
| shipping_address->sorting_code); |
| shipping_address_map.emplace("Organization", |
| shipping_address->organization); |
| shipping_address_map.emplace("Recipient", shipping_address->recipient); |
| shipping_address_map.emplace("Phone", shipping_address->phone); |
| |
| dev_tools->LogBackgroundServiceEvent( |
| registration_id_for_logs_, sw_origin_for_logs_, |
| content::DevToolsBackgroundService::kPaymentHandler, |
| "Change shipping address", |
| /*instance_id=*/payment_request_id_for_logs_, shipping_address_map); |
| } |
| |
| change_payment_request_details_callback_ = std::move(callback); |
| } |
| |
| } // namespace payments |