Chromium Code Reviews| Index: components/password_manager/core/browser/affiliation_utils.cc |
| diff --git a/components/password_manager/core/browser/affiliation_utils.cc b/components/password_manager/core/browser/affiliation_utils.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..e906ee4c62a7e3924b4f249fc033a2408c8de6a9 |
| --- /dev/null |
| +++ b/components/password_manager/core/browser/affiliation_utils.cc |
| @@ -0,0 +1,126 @@ |
| +// Copyright 2014 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/password_manager/core/browser/affiliation_utils.h" |
| + |
| +#include "base/base64.h" |
| +#include "base/strings/string_piece.h" |
| +#include "base/strings/string_util.h" |
| +#include "url/gurl.h" |
| +#include "url/third_party/mozilla/url_parse.h" |
| + |
| +namespace password_manager { |
| + |
| +namespace { |
| + |
| +// The scheme used for identifying Android applications. |
| +const char kAndroidAppScheme[] = "android"; |
| + |
| +base::StringPiece ExtractComponent(const std::string& uri, |
| + const url::Component& component) { |
| + if (!component.is_valid()) |
| + return base::StringPiece(); |
| + return base::StringPiece(uri.c_str() + component.begin, component.len); |
| +} |
| + |
| +base::StringPiece ExtractScheme(const std::string& uri) { |
| + url::Component scheme_component; |
| + if (url::ExtractScheme(uri.c_str(), uri.size(), &scheme_component)) |
| + return ExtractComponent(uri, scheme_component); |
| + return base::StringPiece(); |
| +} |
| + |
| +// Computes the canonicalized form of |uri| into |canonical_uri|, and returns |
| +// whether or not the result is a valid facet URI. Even if the result is not |
| +// valid, |canonical_uri| will contain something reasonable. |
| +bool CanonicalizeFacetURI(const std::string& uri, std::string* canonical_uri) { |
| + DCHECK(canonical_uri); |
| + canonical_uri->clear(); |
| + canonical_uri->reserve(uri.size() + 32); |
| + |
| + url::Parsed original_parsed; |
| + url::ParseStandardURL(uri.c_str(), uri.size(), &original_parsed); |
| + url::Parsed canonical_parsed; |
| + url::StdStringCanonOutput canonical_output(canonical_uri); |
| + if (!url::CanonicalizeStandardURL(uri.c_str(), uri.size(), original_parsed, |
| + NULL, &canonical_output, |
| + &canonical_parsed)) { |
| + return false; |
| + } |
| + canonical_output.Complete(); |
| + |
| + // Note that in the canonical form, the scheme will be in lower case already. |
| + if (ExtractComponent(*canonical_uri, canonical_parsed.scheme) == |
| + url::kHttpsScheme) { |
| + // Web facet URI, should be of the form: https://<host>[:<port>]/ |
| + return !canonical_parsed.username.is_valid() && |
| + !canonical_parsed.password.is_valid() && |
| + canonical_parsed.host.is_nonempty() && |
| + ExtractComponent(*canonical_uri, canonical_parsed.path) == "/" && |
| + !canonical_parsed.query.is_valid() && |
| + !canonical_parsed.ref.is_valid(); |
| + } else if (ExtractComponent(*canonical_uri, canonical_parsed.scheme) == |
| + kAndroidAppScheme) { |
| + // Android facet URI, should be form: android://<cert_hash>@<package_name>/, |
| + // where <cert_hash> is base64-encoded but uses '-' and '_' as the 62nd and |
| + // 63rd value, respectively, and the '=' padding character is URL-encoded. |
| + base::StringPiece hash_component( |
| + ExtractComponent(*canonical_uri, canonical_parsed.username)); |
| + std::string base64_encoded_hash(hash_component.as_string()); |
| + base::ReplaceChars(base64_encoded_hash, "-", "+", &base64_encoded_hash); |
| + base::ReplaceChars(base64_encoded_hash, "_", "/", &base64_encoded_hash); |
| + ReplaceSubstringsAfterOffset(&base64_encoded_hash, 0, "%3D", "="); |
| + std::string unused_decoded_hash; |
| + return canonical_parsed.username.is_nonempty() && |
| + base::Base64Decode(base64_encoded_hash, &unused_decoded_hash) && |
|
Mike West
2014/12/03 22:58:35
Hrm. It surprises me a little bit that we don't su
engedy
2014/12/08 20:53:16
I could not find any support for this in the commo
|
| + !canonical_parsed.password.is_valid() && |
| + canonical_parsed.host.is_nonempty() && |
| + ExtractComponent(*canonical_uri, canonical_parsed.path) == "/" && |
| + !canonical_parsed.query.is_valid() && |
| + !canonical_parsed.ref.is_valid(); |
|
Mike West
2014/12/03 22:58:35
Most of this is shared with the case above. Pretty
engedy
2014/12/08 20:53:16
Unfortunately, I have realized that we cannot cano
|
| + } |
| + return false; |
| +} |
| + |
| +} // namespace |
| + |
| +FacetURI::FacetURI() : is_valid_(false) { |
| +} |
| + |
| +// static |
| +FacetURI FacetURI::FromPotentiallyInvalidURI(const std::string& uri) { |
| + std::string canonical_uri; |
| + return FacetURI(canonical_uri, CanonicalizeFacetURI(uri, &canonical_uri)); |
| +} |
| + |
| +// static |
| +FacetURI FacetURI::FromCanonicalFacetURI(const std::string& uri) { |
| + return FacetURI(uri, true); |
| +} |
| + |
| +bool FacetURI::IsValidWebFacetURI() const { |
| + return is_valid_ && ExtractScheme(canonical_uri_) == url::kHttpsScheme; |
| +} |
| + |
| +bool FacetURI::IsValidAndroidFacetURI() const { |
| + return is_valid_ && ExtractScheme(canonical_uri_) == kAndroidAppScheme; |
| +} |
| + |
| +FacetURI::FacetURI(const std::string& canonical_facet_uri, bool is_valid) |
| + : is_valid_(is_valid), canonical_uri_(canonical_facet_uri) { |
| +} |
| + |
| +bool AreEquivalenceClassesEqual(const AffiliatedFacets& a, |
| + const AffiliatedFacets& b) { |
| + if (a.size() != b.size()) |
| + return false; |
| + |
| + std::vector<FacetURI> a_sorted(a.begin(), a.end()); |
| + std::vector<FacetURI> b_sorted(b.begin(), b.end()); |
| + std::sort(a_sorted.begin(), a_sorted.end()); |
| + std::sort(b_sorted.begin(), b_sorted.end()); |
| + return std::equal(a_sorted.begin(), a_sorted.end(), b_sorted.begin()); |
| +} |
| + |
| +} // namespace password_manager |