Commit f8b34573 authored by Sahel Sharify's avatar Sahel Sharify Committed by Commit Bot

[Payments] Download secure-payment-confirmation instrument icon.

This cl downloads and encodes instrument icon for SPC before it is
written to db.

Bug: 1121021, 1121331
Change-Id: Ifa875ad6a42380fb5f7a7790022f4dd17b835122
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2380142
Commit-Queue: Sahel Sharify <sahel@chromium.org>
Reviewed-by: default avatarRouslan Solomakhin <rouslan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#802372}
parent 9613a90d
......@@ -11,6 +11,7 @@
#include "components/payments/content/payment_manifest_web_data_service.h"
#include "components/payments/content/payment_request_web_contents_manager.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
namespace payments {
......@@ -22,8 +23,16 @@ void CreatePaymentCredential(
content::WebContents::FromRenderFrameHost(render_frame_host);
if (!web_contents)
return;
content::GlobalFrameRoutingId initiator_frame_routing_id =
render_frame_host->GetProcess()
? content::GlobalFrameRoutingId(
render_frame_host->GetProcess()->GetID(),
render_frame_host->GetRoutingID())
: content::GlobalFrameRoutingId();
PaymentRequestWebContentsManager::GetOrCreateForWebContents(web_contents)
->CreatePaymentCredential(
initiator_frame_routing_id,
WebDataServiceFactory::GetPaymentManifestWebDataForProfile(
Profile::FromBrowserContext(web_contents->GetBrowserContext()),
ServiceAccessType::EXPLICIT_ACCESS),
......
......@@ -47,11 +47,13 @@ std::string getInvokePaymentRequestSnippet() {
}
#if !defined(OS_ANDROID)
static constexpr char kPaymentCreationOptions[] =
"var PAYMENT_INSTRUMENT = {"
std::string getPaymentCreationOptions(const std::string& icon_url) {
return base::StrCat(
{"var PAYMENT_INSTRUMENT = {"
" displayName: 'display_name_for_instrument',"
" icon: 'https://pics.acme.com/00/p/aBjjjpqPb.png'"
"};"
" icon: '",
icon_url,
"'};"
"var PUBLIC_KEY_RP = {"
" id: 'a.com',"
" name: 'Acme'"
......@@ -65,7 +67,8 @@ static constexpr char kPaymentCreationOptions[] =
" instrument: PAYMENT_INSTRUMENT,"
" challenge: new TextEncoder().encode('climb a mountain'),"
" pubKeyCredParams: PUBLIC_KEY_PARAMETERS,"
"};";
"};"});
}
static constexpr char kCreatePaymentCredential[] =
"navigator.credentials.create({ payment : PAYMENT_CREATION_OPTIONS })"
......@@ -269,6 +272,10 @@ class SecurePaymentConfirmationCreationTest
config.internal_uv_support = true;
virtual_device_factory->SetCtap2Config(config);
}
const std::string GetDefaultIconURL() {
return https_server()->GetURL("a.com", "/icon.png").spec();
}
};
#if defined(OS_WIN)
......@@ -289,7 +296,8 @@ IN_PROC_BROWSER_TEST_F(SecurePaymentConfirmationCreationTest,
std::string result;
EXPECT_TRUE(content::ExecuteScriptAndExtractString(
GetActiveWebContents(),
base::StrCat({kPaymentCreationOptions, kCreatePaymentCredential}),
base::StrCat({getPaymentCreationOptions(GetDefaultIconURL()),
kCreatePaymentCredential}),
&result));
EXPECT_EQ(result, "paymentCredential: OK");
}
......@@ -303,7 +311,7 @@ IN_PROC_BROWSER_TEST_F(SecurePaymentConfirmationCreationTest,
GetActiveWebContents(),
base::StrCat(
{"async function createPaymentCredential() {",
kPaymentCreationOptions,
getPaymentCreationOptions(GetDefaultIconURL()),
" const c = await navigator.credentials.create("
" {payment: PAYMENT_CREATION_OPTIONS});"
" return btoa(String.fromCharCode(...new Uint8Array(c.rawId)));"
......
......@@ -6,16 +6,25 @@
#include <memory>
#include "base/memory/ref_counted_memory.h"
#include "base/strings/utf_string_conversions.h"
#include "components/payments/content/payment_manifest_web_data_service.h"
#include "components/payments/core/secure_payment_confirmation_instrument.h"
#include "components/payments/core/url_util.h"
#include "content/public/browser/web_contents.h"
#include "ui/gfx/image/image.h"
namespace payments {
PaymentCredential::PaymentCredential(
content::WebContents* web_contents,
content::GlobalFrameRoutingId initiator_frame_routing_id,
scoped_refptr<PaymentManifestWebDataService> web_data_sevice,
mojo::PendingReceiver<mojom::PaymentCredential> receiver)
: web_data_service_(web_data_sevice) {
: WebContentsObserver(web_contents),
initiator_frame_routing_id_(initiator_frame_routing_id),
web_data_service_(web_data_sevice) {
DCHECK(web_contents);
receiver_.Bind(std::move(receiver));
}
......@@ -26,19 +35,76 @@ void PaymentCredential::StorePaymentCredential(
const std::vector<uint8_t>& credential_id,
const std::string& rp_id,
StorePaymentCredentialCallback callback) {
// TODO(https://crbug.com/1121021): Download `instrument->icon` and encode it
// into `std::vector<uint8_t>`.
if (!web_data_service_) {
std::move(callback).Run(
mojom::PaymentCredentialCreationStatus::FAILED_TO_STORE_INSTRUMENT);
return;
}
if (!web_contents() ||
!UrlUtil::IsOriginAllowedToUseWebPaymentApis(instrument->icon)) {
std::move(callback).Run(
mojom::PaymentCredentialCreationStatus::FAILED_TO_DOWNLOAD_ICON);
return;
}
// If the initiator frame doesn't exist any more, e.g. the frame has
// navigated away, don't download the icon.
content::RenderFrameHost* render_frame_host =
content::RenderFrameHost::FromID(initiator_frame_routing_id_);
if (!render_frame_host || !render_frame_host->IsCurrent()) {
std::move(callback).Run(
mojom::PaymentCredentialCreationStatus::FAILED_TO_DOWNLOAD_ICON);
return;
}
int request_id = web_contents()->DownloadImageInFrame(
initiator_frame_routing_id_,
instrument->icon, // source URL
true, // is_favicon
0, // no preferred size
0, // no max size
false, // normal cache policy (a.k.a. do not bypass cache)
base::BindOnce(&PaymentCredential::DidDownloadFavicon,
weak_ptr_factory_.GetWeakPtr(), std::move(instrument),
credential_id, rp_id, std::move(callback)));
pending_icon_download_request_ids_.insert(request_id);
}
void PaymentCredential::DidDownloadFavicon(
payments::mojom::PaymentCredentialInstrumentPtr instrument,
const std::vector<uint8_t>& credential_id,
const std::string& rp_id,
StorePaymentCredentialCallback callback,
int request_id,
int unused_http_status_code,
const GURL& image_url,
const std::vector<SkBitmap>& bitmaps,
const std::vector<gfx::Size>& unused_sizes) {
auto iterator = pending_icon_download_request_ids_.find(request_id);
DCHECK(iterator != pending_icon_download_request_ids_.end());
pending_icon_download_request_ids_.erase(iterator);
if (bitmaps.empty()) {
std::move(callback).Run(
mojom::PaymentCredentialCreationStatus::FAILED_TO_DOWNLOAD_ICON);
return;
}
// TODO(https://crbug.com/1110320): Get the best icon using |preferred size|
// rather than the first one if multiple downloaded.
gfx::Image downloaded_image = gfx::Image::CreateFrom1xBitmap(bitmaps[0]);
scoped_refptr<base::RefCountedMemory> raw_data =
downloaded_image.As1xPNGBytes();
auto encoded_icon =
std::vector<uint8_t>(raw_data->front_as<uint8_t>(),
raw_data->front_as<uint8_t>() + raw_data->size());
WebDataServiceBase::Handle handle =
web_data_service_->AddSecurePaymentConfirmationInstrument(
std::make_unique<SecurePaymentConfirmationInstrument>(
credential_id, rp_id, base::UTF8ToUTF16(instrument->display_name),
/*icon=*/std::vector<uint8_t>(1, 1)),
std::move(encoded_icon)),
/*consumer=*/this);
callbacks_[handle] = std::move(callback);
}
......
......@@ -6,16 +6,24 @@
#define COMPONENTS_PAYMENTS_CONTENT_PAYMENT_CREDENTIAL_H_
#include <map>
#include <set>
#include <string>
#include <vector>
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "components/webdata/common/web_data_service_base.h"
#include "components/webdata/common/web_data_service_consumer.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/web_contents_observer.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "third_party/blink/public/mojom/payments/payment_credential.mojom.h"
namespace content {
class WebContents;
} // namespace content
namespace payments {
class PaymentManifestWebDataService;
......@@ -25,9 +33,12 @@ class PaymentManifestWebDataService;
// These can be retrieved later to authenticate during a PaymentRequest
// that uses Secure Payment Confirmation.
class PaymentCredential : public mojom::PaymentCredential,
public WebDataServiceConsumer {
public WebDataServiceConsumer,
public content::WebContentsObserver {
public:
PaymentCredential(
content::WebContents* web_contents,
content::GlobalFrameRoutingId initiator_frame_routing_id,
scoped_refptr<PaymentManifestWebDataService> web_data_sevice,
mojo::PendingReceiver<mojom::PaymentCredential> receiver);
~PaymentCredential() override;
......@@ -48,10 +59,24 @@ class PaymentCredential : public mojom::PaymentCredential,
WebDataServiceBase::Handle h,
std::unique_ptr<WDTypedResult> result) override;
void DidDownloadFavicon(
payments::mojom::PaymentCredentialInstrumentPtr instrument,
const std::vector<uint8_t>& credential_id,
const std::string& rp_id,
StorePaymentCredentialCallback callback,
int request_id,
int unused_http_status_code,
const GURL& image_url,
const std::vector<SkBitmap>& bitmaps,
const std::vector<gfx::Size>& unused_sizes);
const content::GlobalFrameRoutingId initiator_frame_routing_id_;
scoped_refptr<PaymentManifestWebDataService> web_data_service_;
std::map<WebDataServiceBase::Handle, StorePaymentCredentialCallback>
callbacks_;
mojo::Receiver<mojom::PaymentCredential> receiver_{this};
std::set<int> pending_icon_download_request_ids_;
base::WeakPtrFactory<PaymentCredential> weak_ptr_factory_{this};
};
} // namespace payments
......
......@@ -81,10 +81,12 @@ void PaymentRequestWebContentsManager::DestroyRequest(PaymentRequest* request) {
}
void PaymentRequestWebContentsManager::CreatePaymentCredential(
content::GlobalFrameRoutingId initiator_frame_routing_id,
scoped_refptr<PaymentManifestWebDataService> web_data_sevice,
mojo::PendingReceiver<payments::mojom::PaymentCredential> receiver) {
payment_credential_ =
std::make_unique<PaymentCredential>(web_data_sevice, std::move(receiver));
payment_credential_ = std::make_unique<PaymentCredential>(
web_contents(), initiator_frame_routing_id, web_data_sevice,
std::move(receiver));
}
PaymentRequestWebContentsManager::PaymentRequestWebContentsManager(
......
......@@ -12,6 +12,7 @@
#include "base/memory/scoped_refptr.h"
#include "components/payments/content/payment_credential.h"
#include "components/payments/content/payment_request.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
......@@ -61,8 +62,9 @@ class PaymentRequestWebContentsManager
void DestroyRequest(PaymentRequest* request);
// Creates the mojo IPC endpoint that will receive requests from the renderer
// to store payment credential in user's profle.
// to store payment credential in user's profile.
void CreatePaymentCredential(
content::GlobalFrameRoutingId initiator_frame_routing_id,
scoped_refptr<PaymentManifestWebDataService> web_data_sevice,
mojo::PendingReceiver<payments::mojom::PaymentCredential> receiver);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment