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 |