OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/password_manager/core/browser/affiliation_utils.h" | |
6 | |
7 #include "base/base64.h" | |
8 #include "base/strings/string_piece.h" | |
9 #include "base/strings/string_util.h" | |
10 #include "url/gurl.h" | |
11 #include "url/third_party/mozilla/url_parse.h" | |
12 | |
13 namespace password_manager { | |
14 | |
15 namespace { | |
16 | |
17 // The scheme used for identifying Android applications. | |
18 const char kAndroidAppScheme[] = "android"; | |
19 | |
20 base::StringPiece ExtractComponent(const std::string& uri, | |
21 const url::Component& component) { | |
22 if (!component.is_valid()) | |
23 return base::StringPiece(); | |
24 return base::StringPiece(uri.c_str() + component.begin, component.len); | |
25 } | |
26 | |
27 base::StringPiece ExtractScheme(const std::string& uri) { | |
28 url::Component scheme_component; | |
29 if (url::ExtractScheme(uri.c_str(), uri.size(), &scheme_component)) | |
30 return ExtractComponent(uri, scheme_component); | |
31 return base::StringPiece(); | |
32 } | |
33 | |
34 // Computes the canonicalized form of |uri| into |canonical_uri|, and returns | |
35 // whether or not the result is a valid facet URI. Even if the result is not | |
36 // valid, |canonical_uri| will contain something reasonable. | |
37 bool CanonicalizeFacetURI(const std::string& uri, std::string* canonical_uri) { | |
38 DCHECK(canonical_uri); | |
39 canonical_uri->clear(); | |
40 canonical_uri->reserve(uri.size() + 32); | |
41 | |
42 url::Parsed original_parsed; | |
43 url::ParseStandardURL(uri.c_str(), uri.size(), &original_parsed); | |
44 url::Parsed canonical_parsed; | |
45 url::StdStringCanonOutput canonical_output(canonical_uri); | |
46 if (!url::CanonicalizeStandardURL(uri.c_str(), uri.size(), original_parsed, | |
47 NULL, &canonical_output, | |
48 &canonical_parsed)) { | |
49 return false; | |
50 } | |
51 canonical_output.Complete(); | |
52 | |
53 // Note that in the canonical form, the scheme will be in lower case already. | |
54 if (ExtractComponent(*canonical_uri, canonical_parsed.scheme) == | |
55 url::kHttpsScheme) { | |
56 // Web facet URI, should be of the form: https://<host>[:<port>]/ | |
57 return !canonical_parsed.username.is_valid() && | |
58 !canonical_parsed.password.is_valid() && | |
59 canonical_parsed.host.is_nonempty() && | |
60 ExtractComponent(*canonical_uri, canonical_parsed.path) == "/" && | |
61 !canonical_parsed.query.is_valid() && | |
62 !canonical_parsed.ref.is_valid(); | |
63 } else if (ExtractComponent(*canonical_uri, canonical_parsed.scheme) == | |
64 kAndroidAppScheme) { | |
65 // Android facet URI, should be form: android://<cert_hash>@<package_name>/, | |
66 // where <cert_hash> is base64-encoded but uses '-' and '_' as the 62nd and | |
67 // 63rd value, respectively, and the '=' padding character is URL-encoded. | |
68 base::StringPiece hash_component( | |
69 ExtractComponent(*canonical_uri, canonical_parsed.username)); | |
70 std::string base64_encoded_hash(hash_component.as_string()); | |
71 base::ReplaceChars(base64_encoded_hash, "-", "+", &base64_encoded_hash); | |
72 base::ReplaceChars(base64_encoded_hash, "_", "/", &base64_encoded_hash); | |
73 ReplaceSubstringsAfterOffset(&base64_encoded_hash, 0, "%3D", "="); | |
74 std::string unused_decoded_hash; | |
75 return canonical_parsed.username.is_nonempty() && | |
76 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
| |
77 !canonical_parsed.password.is_valid() && | |
78 canonical_parsed.host.is_nonempty() && | |
79 ExtractComponent(*canonical_uri, canonical_parsed.path) == "/" && | |
80 !canonical_parsed.query.is_valid() && | |
81 !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
| |
82 } | |
83 return false; | |
84 } | |
85 | |
86 } // namespace | |
87 | |
88 FacetURI::FacetURI() : is_valid_(false) { | |
89 } | |
90 | |
91 // static | |
92 FacetURI FacetURI::FromPotentiallyInvalidURI(const std::string& uri) { | |
93 std::string canonical_uri; | |
94 return FacetURI(canonical_uri, CanonicalizeFacetURI(uri, &canonical_uri)); | |
95 } | |
96 | |
97 // static | |
98 FacetURI FacetURI::FromCanonicalFacetURI(const std::string& uri) { | |
99 return FacetURI(uri, true); | |
100 } | |
101 | |
102 bool FacetURI::IsValidWebFacetURI() const { | |
103 return is_valid_ && ExtractScheme(canonical_uri_) == url::kHttpsScheme; | |
104 } | |
105 | |
106 bool FacetURI::IsValidAndroidFacetURI() const { | |
107 return is_valid_ && ExtractScheme(canonical_uri_) == kAndroidAppScheme; | |
108 } | |
109 | |
110 FacetURI::FacetURI(const std::string& canonical_facet_uri, bool is_valid) | |
111 : is_valid_(is_valid), canonical_uri_(canonical_facet_uri) { | |
112 } | |
113 | |
114 bool AreEquivalenceClassesEqual(const AffiliatedFacets& a, | |
115 const AffiliatedFacets& b) { | |
116 if (a.size() != b.size()) | |
117 return false; | |
118 | |
119 std::vector<FacetURI> a_sorted(a.begin(), a.end()); | |
120 std::vector<FacetURI> b_sorted(b.begin(), b.end()); | |
121 std::sort(a_sorted.begin(), a_sorted.end()); | |
122 std::sort(b_sorted.begin(), b_sorted.end()); | |
123 return std::equal(a_sorted.begin(), a_sorted.end(), b_sorted.begin()); | |
124 } | |
125 | |
126 } // namespace password_manager | |
OLD | NEW |