Avi Drissman | 4e1b7bc3 | 2022-09-15 14:03:50 | [diff] [blame] | 1 | // Copyright 2017 The Chromium Authors |
alexmos | 4bc2632 | 2017-07-01 00:57:14 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
alexmos | 4bc2632 | 2017-07-01 00:57:14 | [diff] [blame] | 4 | #ifndef CONTENT_BROWSER_ISOLATED_ORIGIN_UTIL_H_ |
| 5 | #define CONTENT_BROWSER_ISOLATED_ORIGIN_UTIL_H_ |
| 6 | |
Andrew Stone | 6ed99b2 | 2019-06-07 06:14:39 | [diff] [blame] | 7 | #include <string> |
Md Hasibul Hasan | a963a934 | 2024-04-03 10:15:14 | [diff] [blame] | 8 | #include <string_view> |
Andrew Stone | 6ed99b2 | 2019-06-07 06:14:39 | [diff] [blame] | 9 | |
| 10 | #include "base/gtest_prod_util.h" |
alexmos | 4bc2632 | 2017-07-01 00:57:14 | [diff] [blame] | 11 | #include "content/common/content_export.h" |
| 12 | #include "url/origin.h" |
| 13 | |
| 14 | namespace content { |
| 15 | |
Andrew Stone | 6ed99b2 | 2019-06-07 06:14:39 | [diff] [blame] | 16 | // This class holds isolated origin patterns, providing support for double |
Andrew Stone | 404880d | 2019-07-10 02:23:31 | [diff] [blame] | 17 | // wildcard origins, e.g. https://[*.]foo.com indicates that all domains under |
Andrew Stone | 6ed99b2 | 2019-06-07 06:14:39 | [diff] [blame] | 18 | // foo.com are to be treated as if they are distinct isolated |
| 19 | // origins. Non-wildcard origins to be isolated are also supported, e.g. |
| 20 | // https://bar.com. |
| 21 | class CONTENT_EXPORT IsolatedOriginPattern { |
| 22 | public: |
Md Hasibul Hasan | a963a934 | 2024-04-03 10:15:14 | [diff] [blame] | 23 | explicit IsolatedOriginPattern(std::string_view pattern); |
Andrew Stone | 6ed99b2 | 2019-06-07 06:14:39 | [diff] [blame] | 24 | explicit IsolatedOriginPattern(const url::Origin& origin); |
| 25 | ~IsolatedOriginPattern(); |
| 26 | |
| 27 | // Copying and moving supported. |
| 28 | IsolatedOriginPattern(const IsolatedOriginPattern& other); |
| 29 | IsolatedOriginPattern& operator=(const IsolatedOriginPattern& other); |
| 30 | |
| 31 | IsolatedOriginPattern(IsolatedOriginPattern&& other); |
| 32 | IsolatedOriginPattern& operator=(IsolatedOriginPattern&& other); |
| 33 | |
| 34 | bool operator==(const IsolatedOriginPattern& other) const { |
Andrew Stone | 0a177fe2 | 2019-06-26 08:12:04 | [diff] [blame] | 35 | // |pattern_| is deliberately not considered during equality comparison as |
| 36 | // it stores the pattern as supplied at construction time, before |
| 37 | // normalisation. This leads to erroneous cases of mismatch where |
| 38 | // IsolatedOriginPattern("foo.com") and IsolatedOriginPattern("foo.com/") |
| 39 | // will fail equality comparison, despite both resolving to the same origin. |
| 40 | return origin_ == other.origin_ && |
| 41 | isolate_all_subdomains_ == other.isolate_all_subdomains_ && |
| 42 | is_valid_ == other.is_valid_; |
Andrew Stone | 6ed99b2 | 2019-06-07 06:14:39 | [diff] [blame] | 43 | } |
| 44 | |
| 45 | // Returns the url::Origin corresponding to the pattern supplied at |
| 46 | // construction time or via a call to Parse. In the event of parsing failure |
| 47 | // this oriqin will be opaque. |
| 48 | const url::Origin& origin() const { return origin_; } |
| 49 | |
Andrew Stone | 404880d | 2019-07-10 02:23:31 | [diff] [blame] | 50 | // True if the supplied pattern was of the form https://[*.]foo.com, |
| 51 | // indicating all subdomains of foo.com are to be isolated. |
Andrew Stone | 6ed99b2 | 2019-06-07 06:14:39 | [diff] [blame] | 52 | bool isolate_all_subdomains() const { return isolate_all_subdomains_; } |
| 53 | |
| 54 | // Return the original pattern used to construct this instance. |
Md Hasibul Hasan | a963a934 | 2024-04-03 10:15:14 | [diff] [blame] | 55 | const std::string_view pattern() const { return pattern_; } |
Andrew Stone | 6ed99b2 | 2019-06-07 06:14:39 | [diff] [blame] | 56 | |
| 57 | // Return if this origin is valid for isolation purposes. |
| 58 | bool is_valid() const { return is_valid_; } |
| 59 | |
| 60 | private: |
| 61 | friend class ChildProcessSecurityPolicyTest; |
| 62 | FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyTest, |
| 63 | IsolatedOriginPattern); |
| 64 | |
| 65 | // Checks if |pattern| is a wildcard pattern, checks the scheme is one of |
| 66 | // {http, https} and constructs a url::Origin() that can be retrieved if |
| 67 | // parsing is successful. Returns true on successful parsing. |
Md Hasibul Hasan | a963a934 | 2024-04-03 10:15:14 | [diff] [blame] | 68 | bool Parse(const std::string_view& pattern); |
Andrew Stone | 6ed99b2 | 2019-06-07 06:14:39 | [diff] [blame] | 69 | |
| 70 | std::string pattern_; |
| 71 | url::Origin origin_; |
| 72 | bool isolate_all_subdomains_; |
| 73 | bool is_valid_; |
| 74 | }; |
| 75 | |
alexmos | 4bc2632 | 2017-07-01 00:57:14 | [diff] [blame] | 76 | class CONTENT_EXPORT IsolatedOriginUtil { |
| 77 | public: |
| 78 | // Checks whether |origin| matches the isolated origin specified by |
| 79 | // |isolated_origin|. Subdomains are considered to match isolated origins, |
| 80 | // so this will be true if |
| 81 | // (1) |origin| has the same scheme, host, and port as |isolated_origin|, or |
| 82 | // (2) |origin| has the same scheme and port as |isolated_origin|, and its |
| 83 | // host is a subdomain of |isolated_origin|'s host. |
| 84 | // This does not consider site URLs, which don't care about port. |
| 85 | // |
| 86 | // For example, if |isolated_origin| is https://isolated.foo.com, this will |
| 87 | // return true if |origin| is https://isolated.foo.com or |
| 88 | // https://bar.isolated.foo.com, but it will return false for an |origin| of |
| 89 | // https://unisolated.foo.com or https://foo.com. |
| 90 | static bool DoesOriginMatchIsolatedOrigin(const url::Origin& origin, |
| 91 | const url::Origin& isolated_origin); |
| 92 | |
| 93 | // Check if |origin| is a valid isolated origin. Invalid isolated origins |
Domenic Denicola | 4d1145d | 2020-10-29 15:05:33 | [diff] [blame] | 94 | // include opaque origins, origins that don't have an HTTP or HTTPS scheme, |
alexmos | 4bc2632 | 2017-07-01 00:57:14 | [diff] [blame] | 95 | // and origins without a valid registry-controlled domain. IP addresses are |
| 96 | // allowed. |
| 97 | static bool IsValidIsolatedOrigin(const url::Origin& origin); |
Domenic Denicola | 4d1145d | 2020-10-29 15:05:33 | [diff] [blame] | 98 | |
| 99 | // Check if |origin| is a valid origin for opt-in origin isolation. Invalid |
| 100 | // origins for this purpose include opaque origins, origins that don't have a |
| 101 | // HTTP or HTTPS scheme, and origins that are not secure contexts. |
| 102 | static bool IsValidOriginForOptInIsolation(const url::Origin& origin); |
| 103 | |
W. James MacLean | c07dc41b | 2022-07-25 18:52:16 | [diff] [blame] | 104 | // Check if |origin| is a valid origin for opting out of origin isolation. |
| 105 | // Invalid origins for this purpose include opaque origins, and origins that |
| 106 | // don't have a HTTP or HTTPS scheme. |
| 107 | static bool IsValidOriginForOptOutIsolation(const url::Origin& origin); |
| 108 | |
Domenic Denicola | 4d1145d | 2020-10-29 15:05:33 | [diff] [blame] | 109 | private: |
| 110 | // Used to implement both IsValidIsolatedOrigin and |
W. James MacLean | d8d31f0f | 2023-05-26 19:15:57 | [diff] [blame] | 111 | // IsValidOriginForOptInIsolation. The legacy isolated origin case performs |
| 112 | // some additional checks that don't apply to the opt-in case: it verifies the |
| 113 | // origin has a registry domain (for subdomain matching) and disallows |
| 114 | // trailing dots in the domain. |
Domenic Denicola | 4d1145d | 2020-10-29 15:05:33 | [diff] [blame] | 115 | static bool IsValidIsolatedOriginImpl(const url::Origin& origin, |
W. James MacLean | d8d31f0f | 2023-05-26 19:15:57 | [diff] [blame] | 116 | bool is_legacy_isolated_origin_check); |
alexmos | 4bc2632 | 2017-07-01 00:57:14 | [diff] [blame] | 117 | }; |
| 118 | |
| 119 | } // namespace content |
| 120 | |
| 121 | #endif // CONTENT_BROWSER_ISOLATED_ORIGIN_UTIL_H_ |