Commit 618f5936 authored by Rayan Kanso's avatar Rayan Kanso Committed by Commit Bot

Update DigitialAssetLinksHandler to be more flexible.

The handler can now support checking for different types of digital
asset links, including web targets.

Also includes some minor stylistic improvements.

Bug: 1043970
Change-Id: Icb651573a98201c810e53f74cea91a225a48cac0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2037673Reviewed-by: default avatarPeter Conn <peconn@chromium.org>
Commit-Queue: Rayan Kanso <rayankans@chromium.org>
Cr-Commit-Position: refs/heads/master@{#738583}
parent 285bc3c0
......@@ -38,9 +38,9 @@ OriginVerifier::OriginVerifier(JNIEnv* env,
DCHECK(profile);
asset_link_handler_ =
std::make_unique<digital_asset_links::DigitalAssetLinksHandler>(
content::WebContents::FromJavaWebContents(jweb_contents),
content::BrowserContext::GetDefaultStoragePartition(profile)
->GetURLLoaderFactoryForBrowserProcess());
->GetURLLoaderFactoryForBrowserProcess(),
content::WebContents::FromJavaWebContents(jweb_contents));
}
OriginVerifier::~OriginVerifier() = default;
......@@ -65,10 +65,10 @@ bool OriginVerifier::VerifyOrigin(JNIEnv* env,
// UrlFetcher making the request will also get killed, so we won't get any
// dangling callback reference issues.
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
return asset_link_handler_->CheckDigitalAssetLinkRelationship(
base::Bind(&customtabs::OriginVerifier::OnRelationshipCheckComplete,
base::Unretained(this)),
origin, package_name, fingerprint, relationship);
return asset_link_handler_->CheckDigitalAssetLinkRelationshipForAndroidApp(
origin, relationship, fingerprint, package_name,
base::BindOnce(&customtabs::OriginVerifier::OnRelationshipCheckComplete,
base::Unretained(this)));
}
void OriginVerifier::OnRelationshipCheckComplete(
......
......@@ -4,7 +4,6 @@
#include "chrome/browser/android/digital_asset_links/digital_asset_links_handler.h"
#include <string>
#include <vector>
#include "base/bind.h"
......@@ -75,12 +74,13 @@ bool StatementHasMatchingRelationship(const base::Value& statement,
return false;
}
bool StatementHasMatchingPackage(const base::Value& statement,
const std::string& target_package) {
bool StatementHasMatchingTargetValue(const base::Value& statement,
const std::string& target_key,
const std::string& target_value) {
const base::Value* package = statement.FindPathOfType(
{"target", "package_name"}, base::Value::Type::STRING);
{"target", target_key}, base::Value::Type::STRING);
return package && package->GetString() == target_package;
return package && package->GetString() == target_value;
}
bool StatementHasMatchingFingerprint(const base::Value& statement,
......@@ -121,17 +121,17 @@ namespace digital_asset_links {
const char kDigitalAssetLinksCheckResponseKeyLinked[] = "linked";
DigitalAssetLinksHandler::DigitalAssetLinksHandler(
content::WebContents* web_contents,
scoped_refptr<network::SharedURLLoaderFactory> factory)
scoped_refptr<network::SharedURLLoaderFactory> factory,
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
shared_url_loader_factory_(std::move(factory)) {}
DigitalAssetLinksHandler::~DigitalAssetLinksHandler() = default;
void DigitalAssetLinksHandler::OnURLLoadComplete(
const std::string& package,
const std::string& fingerprint,
const std::string& relationship,
std::string relationship,
base::Optional<std::string> fingerprint,
std::map<std::string, std::string> target_values,
std::unique_ptr<std::string> response_body) {
int response_code = -1;
if (url_loader_->ResponseInfo() && url_loader_->ResponseInfo()->headers)
......@@ -143,7 +143,7 @@ void DigitalAssetLinksHandler::OnURLLoadComplete(
net_error == net::ERR_NAME_NOT_RESOLVED) {
AddMessageToConsole(web_contents(),
"Digital Asset Links connection failed.");
std::move(callback_).Run(RelationshipCheckResult::NO_CONNECTION);
std::move(callback_).Run(RelationshipCheckResult::kNoConnection);
return;
}
......@@ -152,36 +152,36 @@ void DigitalAssetLinksHandler::OnURLLoadComplete(
base::StringPrintf(
"Digital Asset Links endpoint responded with code %d.",
response_code));
std::move(callback_).Run(RelationshipCheckResult::FAILURE);
std::move(callback_).Run(RelationshipCheckResult::kFailure);
return;
}
data_decoder::DataDecoder::ParseJsonIsolated(
*response_body,
base::BindOnce(&DigitalAssetLinksHandler::OnJSONParseResult,
weak_ptr_factory_.GetWeakPtr(), package, fingerprint,
relationship));
weak_ptr_factory_.GetWeakPtr(), std::move(relationship),
std::move(fingerprint), std::move(target_values)));
url_loader_.reset(nullptr);
}
void DigitalAssetLinksHandler::OnJSONParseResult(
const std::string& package,
const std::string& fingerprint,
const std::string& relationship,
std::string relationship,
base::Optional<std::string> fingerprint,
std::map<std::string, std::string> target_values,
data_decoder::DataDecoder::ValueOrError result) {
if (!result.value) {
AddMessageToConsole(
web_contents(),
"Digital Asset Links response parsing failed with message: " +
*result.error);
std::move(callback_).Run(RelationshipCheckResult::FAILURE);
std::move(callback_).Run(RelationshipCheckResult::kFailure);
return;
}
auto& statement_list = *result.value;
if (!statement_list.is_list()) {
std::move(callback_).Run(RelationshipCheckResult::FAILURE);
std::move(callback_).Run(RelationshipCheckResult::kFailure);
AddMessageToConsole(web_contents(), "Statement List is not a list.");
return;
}
......@@ -200,33 +200,54 @@ void DigitalAssetLinksHandler::OnJSONParseResult(
continue;
}
if (!StatementHasMatchingPackage(statement, package)) {
failures.push_back("Statement failure matching package.");
if (fingerprint &&
!StatementHasMatchingFingerprint(statement, *fingerprint)) {
failures.push_back("Statement failure matching fingerprint.");
continue;
}
if (!StatementHasMatchingFingerprint(statement, fingerprint)) {
failures.push_back("Statement failure matching fingerprint.");
continue;
bool failed_target_check = false;
for (const auto& key_value : target_values) {
if (!StatementHasMatchingTargetValue(statement, key_value.first,
key_value.second)) {
failures.push_back("Statement failure matching " + key_value.first +
".");
failed_target_check = true;
break;
}
}
if (failed_target_check)
continue;
std::move(callback_).Run(RelationshipCheckResult::SUCCESS);
std::move(callback_).Run(RelationshipCheckResult::kSuccess);
return;
}
for (const auto& failure_reason : failures)
AddMessageToConsole(web_contents(), failure_reason);
std::move(callback_).Run(RelationshipCheckResult::FAILURE);
std::move(callback_).Run(RelationshipCheckResult::kFailure);
}
bool DigitalAssetLinksHandler::CheckDigitalAssetLinkRelationship(
RelationshipCheckResultCallback callback,
bool DigitalAssetLinksHandler::CheckDigitalAssetLinkRelationshipForAndroidApp(
const std::string& web_domain,
const std::string& package,
const std::string& relationship,
const std::string& fingerprint,
const std::string& relationship) {
// TODO(peconn): Propegate the use of url::Origin backwards to clients.
const std::string& package,
RelationshipCheckResultCallback callback) {
// TODO(rayankans): Should we also check the namespace here?
return CheckDigitalAssetLinkRelationship(
web_domain, relationship, fingerprint, {{"package_name", package}},
std::move(callback));
}
bool DigitalAssetLinksHandler::CheckDigitalAssetLinkRelationship(
const std::string& web_domain,
const std::string& relationship,
const base::Optional<std::string>& fingerprint,
const std::map<std::string, std::string>& target_values,
RelationshipCheckResultCallback callback) {
// TODO(peconn): Propagate the use of url::Origin backwards to clients.
GURL request_url = GetUrlForAssetLinks(url::Origin::Create(GURL(web_domain)));
if (!request_url.is_valid())
......@@ -272,8 +293,8 @@ bool DigitalAssetLinksHandler::CheckDigitalAssetLinkRelationship(
url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
shared_url_loader_factory_.get(),
base::BindOnce(&DigitalAssetLinksHandler::OnURLLoadComplete,
weak_ptr_factory_.GetWeakPtr(), package, fingerprint,
relationship));
weak_ptr_factory_.GetWeakPtr(), relationship, fingerprint,
target_values));
return true;
}
......
......@@ -5,8 +5,12 @@
#ifndef CHROME_BROWSER_ANDROID_DIGITAL_ASSET_LINKS_DIGITAL_ASSET_LINKS_HANDLER_H_
#define CHROME_BROWSER_ANDROID_DIGITAL_ASSET_LINKS_DIGITAL_ASSET_LINKS_HANDLER_H_
#include <map>
#include <string>
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/values.h"
#include "content/public/browser/web_contents_observer.h"
#include "services/data_decoder/public/cpp/data_decoder.h"
......@@ -22,9 +26,9 @@ extern const char kDigitalAssetLinksCheckResponseKeyLinked[];
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.browserservices
enum class RelationshipCheckResult {
SUCCESS = 0,
FAILURE,
NO_CONNECTION
kSuccess = 0,
kFailure,
kNoConnection,
};
using RelationshipCheckResultCallback =
......@@ -39,9 +43,10 @@ using RelationshipCheckResultCallback =
// The WebContents are used for logging console messages.
class DigitalAssetLinksHandler : public content::WebContentsObserver {
public:
DigitalAssetLinksHandler(
content::WebContents* web_contents,
scoped_refptr<network::SharedURLLoaderFactory> factory);
// Optionally include |web_contents| for logging error messages to DevTools.
explicit DigitalAssetLinksHandler(
scoped_refptr<network::SharedURLLoaderFactory> factory,
content::WebContents* web_contents = nullptr);
~DigitalAssetLinksHandler() override;
// Checks whether the given "relationship" has been declared by the target
......@@ -55,23 +60,31 @@ class DigitalAssetLinksHandler : public content::WebContentsObserver {
// See
// https://developers.google.com/digital-asset-links/reference/rest/v1/assetlinks/check
// for details.
bool CheckDigitalAssetLinkRelationship(
RelationshipCheckResultCallback callback,
bool CheckDigitalAssetLinkRelationshipForAndroidApp(
const std::string& web_domain,
const std::string& package,
const std::string& relationship,
const std::string& fingerprint,
const std::string& relationship);
const std::string& package,
RelationshipCheckResultCallback callback);
private:
void OnURLLoadComplete(const std::string& package,
const std::string& fingerprint,
const std::string& relationship,
// Generic DAL verifier.
bool CheckDigitalAssetLinkRelationship(
const std::string& web_domain,
const std::string& relationship,
const base::Optional<std::string>& fingerprint,
const std::map<std::string, std::string>& target_values,
RelationshipCheckResultCallback callback);
void OnURLLoadComplete(std::string relationship,
base::Optional<std::string> fingerprint,
std::map<std::string, std::string> target_values,
std::unique_ptr<std::string> response_body);
// Callback for the DataDecoder.
void OnJSONParseResult(const std::string& package,
const std::string& fingerprint,
const std::string& relationship,
void OnJSONParseResult(std::string relationship,
base::Optional<std::string> fingerprint,
std::map<std::string, std::string> target_values,
data_decoder::DataDecoder::ValueOrError result);
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
......
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