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 @@ ...@@ -11,6 +11,7 @@
#include "components/payments/content/payment_manifest_web_data_service.h" #include "components/payments/content/payment_manifest_web_data_service.h"
#include "components/payments/content/payment_request_web_contents_manager.h" #include "components/payments/content/payment_request_web_contents_manager.h"
#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
namespace payments { namespace payments {
...@@ -22,8 +23,16 @@ void CreatePaymentCredential( ...@@ -22,8 +23,16 @@ void CreatePaymentCredential(
content::WebContents::FromRenderFrameHost(render_frame_host); content::WebContents::FromRenderFrameHost(render_frame_host);
if (!web_contents) if (!web_contents)
return; 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) PaymentRequestWebContentsManager::GetOrCreateForWebContents(web_contents)
->CreatePaymentCredential( ->CreatePaymentCredential(
initiator_frame_routing_id,
WebDataServiceFactory::GetPaymentManifestWebDataForProfile( WebDataServiceFactory::GetPaymentManifestWebDataForProfile(
Profile::FromBrowserContext(web_contents->GetBrowserContext()), Profile::FromBrowserContext(web_contents->GetBrowserContext()),
ServiceAccessType::EXPLICIT_ACCESS), ServiceAccessType::EXPLICIT_ACCESS),
......
...@@ -47,25 +47,28 @@ std::string getInvokePaymentRequestSnippet() { ...@@ -47,25 +47,28 @@ std::string getInvokePaymentRequestSnippet() {
} }
#if !defined(OS_ANDROID) #if !defined(OS_ANDROID)
static constexpr char kPaymentCreationOptions[] = std::string getPaymentCreationOptions(const std::string& icon_url) {
"var PAYMENT_INSTRUMENT = {" return base::StrCat(
" displayName: 'display_name_for_instrument'," {"var PAYMENT_INSTRUMENT = {"
" icon: 'https://pics.acme.com/00/p/aBjjjpqPb.png'" " displayName: 'display_name_for_instrument',"
"};" " icon: '",
"var PUBLIC_KEY_RP = {" icon_url,
" id: 'a.com'," "'};"
" name: 'Acme'" "var PUBLIC_KEY_RP = {"
"};" " id: 'a.com',"
"var PUBLIC_KEY_PARAMETERS = [{" " name: 'Acme'"
" type: 'public-key'," "};"
" alg: -7," "var PUBLIC_KEY_PARAMETERS = [{"
"},];" " type: 'public-key',"
"var PAYMENT_CREATION_OPTIONS = {" " alg: -7,"
" rp: PUBLIC_KEY_RP," "},];"
" instrument: PAYMENT_INSTRUMENT," "var PAYMENT_CREATION_OPTIONS = {"
" challenge: new TextEncoder().encode('climb a mountain')," " rp: PUBLIC_KEY_RP,"
" pubKeyCredParams: PUBLIC_KEY_PARAMETERS," " instrument: PAYMENT_INSTRUMENT,"
"};"; " challenge: new TextEncoder().encode('climb a mountain'),"
" pubKeyCredParams: PUBLIC_KEY_PARAMETERS,"
"};"});
}
static constexpr char kCreatePaymentCredential[] = static constexpr char kCreatePaymentCredential[] =
"navigator.credentials.create({ payment : PAYMENT_CREATION_OPTIONS })" "navigator.credentials.create({ payment : PAYMENT_CREATION_OPTIONS })"
...@@ -269,6 +272,10 @@ class SecurePaymentConfirmationCreationTest ...@@ -269,6 +272,10 @@ class SecurePaymentConfirmationCreationTest
config.internal_uv_support = true; config.internal_uv_support = true;
virtual_device_factory->SetCtap2Config(config); virtual_device_factory->SetCtap2Config(config);
} }
const std::string GetDefaultIconURL() {
return https_server()->GetURL("a.com", "/icon.png").spec();
}
}; };
#if defined(OS_WIN) #if defined(OS_WIN)
...@@ -289,7 +296,8 @@ IN_PROC_BROWSER_TEST_F(SecurePaymentConfirmationCreationTest, ...@@ -289,7 +296,8 @@ IN_PROC_BROWSER_TEST_F(SecurePaymentConfirmationCreationTest,
std::string result; std::string result;
EXPECT_TRUE(content::ExecuteScriptAndExtractString( EXPECT_TRUE(content::ExecuteScriptAndExtractString(
GetActiveWebContents(), GetActiveWebContents(),
base::StrCat({kPaymentCreationOptions, kCreatePaymentCredential}), base::StrCat({getPaymentCreationOptions(GetDefaultIconURL()),
kCreatePaymentCredential}),
&result)); &result));
EXPECT_EQ(result, "paymentCredential: OK"); EXPECT_EQ(result, "paymentCredential: OK");
} }
...@@ -303,7 +311,7 @@ IN_PROC_BROWSER_TEST_F(SecurePaymentConfirmationCreationTest, ...@@ -303,7 +311,7 @@ IN_PROC_BROWSER_TEST_F(SecurePaymentConfirmationCreationTest,
GetActiveWebContents(), GetActiveWebContents(),
base::StrCat( base::StrCat(
{"async function createPaymentCredential() {", {"async function createPaymentCredential() {",
kPaymentCreationOptions, getPaymentCreationOptions(GetDefaultIconURL()),
" const c = await navigator.credentials.create(" " const c = await navigator.credentials.create("
" {payment: PAYMENT_CREATION_OPTIONS});" " {payment: PAYMENT_CREATION_OPTIONS});"
" return btoa(String.fromCharCode(...new Uint8Array(c.rawId)));" " return btoa(String.fromCharCode(...new Uint8Array(c.rawId)));"
......
...@@ -6,16 +6,25 @@ ...@@ -6,16 +6,25 @@
#include <memory> #include <memory>
#include "base/memory/ref_counted_memory.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "components/payments/content/payment_manifest_web_data_service.h" #include "components/payments/content/payment_manifest_web_data_service.h"
#include "components/payments/core/secure_payment_confirmation_instrument.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 { namespace payments {
PaymentCredential::PaymentCredential( PaymentCredential::PaymentCredential(
content::WebContents* web_contents,
content::GlobalFrameRoutingId initiator_frame_routing_id,
scoped_refptr<PaymentManifestWebDataService> web_data_sevice, scoped_refptr<PaymentManifestWebDataService> web_data_sevice,
mojo::PendingReceiver<mojom::PaymentCredential> receiver) 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)); receiver_.Bind(std::move(receiver));
} }
...@@ -26,19 +35,76 @@ void PaymentCredential::StorePaymentCredential( ...@@ -26,19 +35,76 @@ void PaymentCredential::StorePaymentCredential(
const std::vector<uint8_t>& credential_id, const std::vector<uint8_t>& credential_id,
const std::string& rp_id, const std::string& rp_id,
StorePaymentCredentialCallback callback) { StorePaymentCredentialCallback callback) {
// TODO(https://crbug.com/1121021): Download `instrument->icon` and encode it
// into `std::vector<uint8_t>`.
if (!web_data_service_) { if (!web_data_service_) {
std::move(callback).Run( std::move(callback).Run(
mojom::PaymentCredentialCreationStatus::FAILED_TO_STORE_INSTRUMENT); mojom::PaymentCredentialCreationStatus::FAILED_TO_STORE_INSTRUMENT);
return; 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 = WebDataServiceBase::Handle handle =
web_data_service_->AddSecurePaymentConfirmationInstrument( web_data_service_->AddSecurePaymentConfirmationInstrument(
std::make_unique<SecurePaymentConfirmationInstrument>( std::make_unique<SecurePaymentConfirmationInstrument>(
credential_id, rp_id, base::UTF8ToUTF16(instrument->display_name), credential_id, rp_id, base::UTF8ToUTF16(instrument->display_name),
/*icon=*/std::vector<uint8_t>(1, 1)), std::move(encoded_icon)),
/*consumer=*/this); /*consumer=*/this);
callbacks_[handle] = std::move(callback); callbacks_[handle] = std::move(callback);
} }
......
...@@ -6,16 +6,24 @@ ...@@ -6,16 +6,24 @@
#define COMPONENTS_PAYMENTS_CONTENT_PAYMENT_CREDENTIAL_H_ #define COMPONENTS_PAYMENTS_CONTENT_PAYMENT_CREDENTIAL_H_
#include <map> #include <map>
#include <set>
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/memory/scoped_refptr.h" #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_base.h"
#include "components/webdata/common/web_data_service_consumer.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/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/receiver.h"
#include "third_party/blink/public/mojom/payments/payment_credential.mojom.h" #include "third_party/blink/public/mojom/payments/payment_credential.mojom.h"
namespace content {
class WebContents;
} // namespace content
namespace payments { namespace payments {
class PaymentManifestWebDataService; class PaymentManifestWebDataService;
...@@ -25,9 +33,12 @@ class PaymentManifestWebDataService; ...@@ -25,9 +33,12 @@ class PaymentManifestWebDataService;
// These can be retrieved later to authenticate during a PaymentRequest // These can be retrieved later to authenticate during a PaymentRequest
// that uses Secure Payment Confirmation. // that uses Secure Payment Confirmation.
class PaymentCredential : public mojom::PaymentCredential, class PaymentCredential : public mojom::PaymentCredential,
public WebDataServiceConsumer { public WebDataServiceConsumer,
public content::WebContentsObserver {
public: public:
PaymentCredential( PaymentCredential(
content::WebContents* web_contents,
content::GlobalFrameRoutingId initiator_frame_routing_id,
scoped_refptr<PaymentManifestWebDataService> web_data_sevice, scoped_refptr<PaymentManifestWebDataService> web_data_sevice,
mojo::PendingReceiver<mojom::PaymentCredential> receiver); mojo::PendingReceiver<mojom::PaymentCredential> receiver);
~PaymentCredential() override; ~PaymentCredential() override;
...@@ -48,10 +59,24 @@ class PaymentCredential : public mojom::PaymentCredential, ...@@ -48,10 +59,24 @@ class PaymentCredential : public mojom::PaymentCredential,
WebDataServiceBase::Handle h, WebDataServiceBase::Handle h,
std::unique_ptr<WDTypedResult> result) override; 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_; scoped_refptr<PaymentManifestWebDataService> web_data_service_;
std::map<WebDataServiceBase::Handle, StorePaymentCredentialCallback> std::map<WebDataServiceBase::Handle, StorePaymentCredentialCallback>
callbacks_; callbacks_;
mojo::Receiver<mojom::PaymentCredential> receiver_{this}; mojo::Receiver<mojom::PaymentCredential> receiver_{this};
std::set<int> pending_icon_download_request_ids_;
base::WeakPtrFactory<PaymentCredential> weak_ptr_factory_{this};
}; };
} // namespace payments } // namespace payments
......
...@@ -81,10 +81,12 @@ void PaymentRequestWebContentsManager::DestroyRequest(PaymentRequest* request) { ...@@ -81,10 +81,12 @@ void PaymentRequestWebContentsManager::DestroyRequest(PaymentRequest* request) {
} }
void PaymentRequestWebContentsManager::CreatePaymentCredential( void PaymentRequestWebContentsManager::CreatePaymentCredential(
content::GlobalFrameRoutingId initiator_frame_routing_id,
scoped_refptr<PaymentManifestWebDataService> web_data_sevice, scoped_refptr<PaymentManifestWebDataService> web_data_sevice,
mojo::PendingReceiver<payments::mojom::PaymentCredential> receiver) { mojo::PendingReceiver<payments::mojom::PaymentCredential> receiver) {
payment_credential_ = payment_credential_ = std::make_unique<PaymentCredential>(
std::make_unique<PaymentCredential>(web_data_sevice, std::move(receiver)); web_contents(), initiator_frame_routing_id, web_data_sevice,
std::move(receiver));
} }
PaymentRequestWebContentsManager::PaymentRequestWebContentsManager( PaymentRequestWebContentsManager::PaymentRequestWebContentsManager(
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
#include "components/payments/content/payment_credential.h" #include "components/payments/content/payment_credential.h"
#include "components/payments/content/payment_request.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_observer.h"
#include "content/public/browser/web_contents_user_data.h" #include "content/public/browser/web_contents_user_data.h"
#include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_receiver.h"
...@@ -61,8 +62,9 @@ class PaymentRequestWebContentsManager ...@@ -61,8 +62,9 @@ class PaymentRequestWebContentsManager
void DestroyRequest(PaymentRequest* request); void DestroyRequest(PaymentRequest* request);
// Creates the mojo IPC endpoint that will receive requests from the renderer // 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( void CreatePaymentCredential(
content::GlobalFrameRoutingId initiator_frame_routing_id,
scoped_refptr<PaymentManifestWebDataService> web_data_sevice, scoped_refptr<PaymentManifestWebDataService> web_data_sevice,
mojo::PendingReceiver<payments::mojom::PaymentCredential> receiver); 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