diff options
Diffstat (limited to 'chromium/components/safe_browsing/ios')
3 files changed, 308 insertions, 0 deletions
diff --git a/chromium/components/safe_browsing/ios/browser/BUILD.gn b/chromium/components/safe_browsing/ios/browser/BUILD.gn new file mode 100644 index 00000000000..87ca89f183a --- /dev/null +++ b/chromium/components/safe_browsing/ios/browser/BUILD.gn @@ -0,0 +1,18 @@ +# Copyright 2020 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. + +source_set("allow_list") { + sources = [ + "safe_browsing_url_allow_list.h", + "safe_browsing_url_allow_list.mm", + ] + + deps = [ + "//components/safe_browsing/core/db:v4_protocol_manager_util", + "//ios/web/public", + "//url", + ] + + configs += [ "//build/config/compiler:enable_arc" ] +} diff --git a/chromium/components/safe_browsing/ios/browser/safe_browsing_url_allow_list.h b/chromium/components/safe_browsing/ios/browser/safe_browsing_url_allow_list.h new file mode 100644 index 00000000000..3253e3bdea6 --- /dev/null +++ b/chromium/components/safe_browsing/ios/browser/safe_browsing_url_allow_list.h @@ -0,0 +1,131 @@ +// Copyright 2020 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. + +#ifndef COMPONENTS_SAFE_BROWSING_IOS_BROWSER_SAFE_BROWSING_URL_ALLOW_LIST_H_ +#define COMPONENTS_SAFE_BROWSING_IOS_BROWSER_SAFE_BROWSING_URL_ALLOW_LIST_H_ + +#include <map> +#include <set> + +#include "base/observer_list.h" +#include "base/observer_list_types.h" +#include "components/safe_browsing/core/db/v4_protocol_manager_util.h" +#import "ios/web/public/web_state_user_data.h" +#include "url/gurl.h" + +// SafeBrowsingUrlAllowList tracks the whitelist decisions for URLs for a given +// threat type, as well as decisions that are pending. Decisions are stored for +// URLs with empty paths, meaning that whitelisted threats are allowed for the +// entire domain. +class SafeBrowsingUrlAllowList + : public web::WebStateUserData<SafeBrowsingUrlAllowList> { + public: + // Enum describing the policy for navigations with a particular threat type to + // a URL. + enum class Policy : short { kDisallowed, kPending, kAllowed }; + + // Observer class for the allow list. + class Observer : public base::CheckedObserver { + public: + // Called when the policy for navigations to |url| with |threat_type| is + // updated to |policy|. + virtual void ThreatPolicyUpdated(SafeBrowsingUrlAllowList* allow_list, + const GURL& url, + safe_browsing::SBThreatType threat_type, + Policy policy) {} + + // Called when the policies for navigations to |url| with the threats in + // |threat_types| are updated to |policy|. + virtual void ThreatPolicyBatchUpdated( + SafeBrowsingUrlAllowList* allow_list, + const GURL& url, + const std::set<safe_browsing::SBThreatType>& threat_type, + Policy policy) {} + + // Called when |allow_list| is about to be destroyed. + virtual void SafeBrowsingAllowListDestroyed( + SafeBrowsingUrlAllowList* allow_list) {} + }; + + ~SafeBrowsingUrlAllowList() override; + + // Adds and removes observers. + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + // Returns whether unsafe navigations to |url| are allowed. If |threat_types| + // is non-null, it is populated with the allowed threat types. + bool AreUnsafeNavigationsAllowed( + const GURL& url, + std::set<safe_browsing::SBThreatType>* threat_types = nullptr) const; + + // Allows future unsafe navigations to |url| that encounter threats with + // |threat_type|. + void AllowUnsafeNavigations(const GURL& url, + safe_browsing::SBThreatType threat_type); + + // Prohibits all previously allowed navigations for |url|. + void DisallowUnsafeNavigations(const GURL& url); + + // Returns whether there are pending unsafe navigation decisions for |url|. + // If |threat_types| is non-null, it is populated with the pending threat + // types. + bool IsUnsafeNavigationDecisionPending( + const GURL& url, + std::set<safe_browsing::SBThreatType>* threat_types = nullptr) const; + + // Records that a navigation to |url| has encountered |threat_type|, but the + // user has not yet chosen whether to allow the navigation. + void AddPendingUnsafeNavigationDecision( + const GURL& url, + safe_browsing::SBThreatType threat_type); + + // Removes all pending decisions for |url|. + void RemovePendingUnsafeNavigationDecisions(const GURL& url); + + private: + explicit SafeBrowsingUrlAllowList(web::WebState* web_state); + friend class web::WebStateUserData<SafeBrowsingUrlAllowList>; + WEB_STATE_USER_DATA_KEY_DECL(); + + // Struct storing the threat types that have been allowed and those for + // which the user has not made a decision yet. + struct UnsafeNavigationDecisions { + UnsafeNavigationDecisions(); + ~UnsafeNavigationDecisions(); + std::set<safe_browsing::SBThreatType> allowed_threats; + std::set<safe_browsing::SBThreatType> pending_threats; + }; + + // Returns a reference to the UnsafeNavigationDecisions for |url|. The path + // is stripped from the URLs before accessing |decisions_| to allow unafe + // navigation decisions to be shared across all URLs for a given domain. + UnsafeNavigationDecisions& GetUnsafeNavigationDecisions(const GURL& url); + const UnsafeNavigationDecisions& GetUnsafeNavigationDecisions( + const GURL& url) const; + + // Setter for the policy for navigations to |url| with |threat_type|. + void SetThreatPolicy(const GURL& url, + safe_browsing::SBThreatType threat_type, + Policy policy); + + // Returns whether the list contains any |policy| decisions for |url|. + // Populates |threat_types| with found threats if provided. + bool ContainsThreats( + const GURL& url, + Policy policy, + std::set<safe_browsing::SBThreatType>* threat_types) const; + + // Disallows all threats that for |url| that are currently allowed under + // |policy|. + void RevertPolicy(const GURL& url, Policy policy); + + // The WebState whose allowed navigations are recorded by this list. + web::WebState* web_state_ = nullptr; + // Map storing the whitelist decisions for each URL. + std::map<GURL, UnsafeNavigationDecisions> decisions_; + base::ObserverList<Observer, /*check_empty=*/true> observers_; +}; + +#endif // COMPONENTS_SAFE_BROWSING_IOS_BROWSER_SAFE_BROWSING_URL_ALLOW_LIST_H_ diff --git a/chromium/components/safe_browsing/ios/browser/safe_browsing_url_allow_list.mm b/chromium/components/safe_browsing/ios/browser/safe_browsing_url_allow_list.mm new file mode 100644 index 00000000000..763f01145e0 --- /dev/null +++ b/chromium/components/safe_browsing/ios/browser/safe_browsing_url_allow_list.mm @@ -0,0 +1,159 @@ +// Copyright 2020 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. + +#import "components/safe_browsing/ios/browser/safe_browsing_url_allow_list.h" + +#import "ios/web/public/web_state.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +using safe_browsing::SBThreatType; + +WEB_STATE_USER_DATA_KEY_IMPL(SafeBrowsingUrlAllowList) + +SafeBrowsingUrlAllowList::SafeBrowsingUrlAllowList(web::WebState* web_state) + : web_state_(web_state) {} + +SafeBrowsingUrlAllowList::~SafeBrowsingUrlAllowList() { + for (auto& observer : observers_) { + observer.SafeBrowsingAllowListDestroyed(this); + } +} + +void SafeBrowsingUrlAllowList::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void SafeBrowsingUrlAllowList::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + +bool SafeBrowsingUrlAllowList::AreUnsafeNavigationsAllowed( + const GURL& url, + std::set<SBThreatType>* threat_types) const { + return ContainsThreats(url, Policy::kAllowed, threat_types); +} + +void SafeBrowsingUrlAllowList::AllowUnsafeNavigations( + const GURL& url, + SBThreatType threat_type) { + SetThreatPolicy(url, threat_type, Policy::kAllowed); +} + +void SafeBrowsingUrlAllowList::DisallowUnsafeNavigations(const GURL& url) { + RevertPolicy(url, Policy::kAllowed); +} + +bool SafeBrowsingUrlAllowList::IsUnsafeNavigationDecisionPending( + const GURL& url, + std::set<SBThreatType>* threat_types) const { + return ContainsThreats(url, Policy::kPending, threat_types); +} + +void SafeBrowsingUrlAllowList::AddPendingUnsafeNavigationDecision( + const GURL& url, + SBThreatType threat_type) { + SetThreatPolicy(url, threat_type, Policy::kPending); +} + +void SafeBrowsingUrlAllowList::RemovePendingUnsafeNavigationDecisions( + const GURL& url) { + RevertPolicy(url, Policy::kPending); +} + +#pragma mark - Private + +SafeBrowsingUrlAllowList::UnsafeNavigationDecisions& +SafeBrowsingUrlAllowList::GetUnsafeNavigationDecisions(const GURL& url) { + return decisions_[url.GetWithEmptyPath()]; +} + +const SafeBrowsingUrlAllowList::UnsafeNavigationDecisions& +SafeBrowsingUrlAllowList::GetUnsafeNavigationDecisions(const GURL& url) const { + static UnsafeNavigationDecisions kEmptyDecisions; + const auto& it = decisions_.find(url.GetWithEmptyPath()); + if (it == decisions_.end()) + return kEmptyDecisions; + return it->second; +} + +void SafeBrowsingUrlAllowList::SetThreatPolicy( + const GURL& url, + safe_browsing::SBThreatType threat_type, + Policy policy) { + auto& decisions = GetUnsafeNavigationDecisions(url); + if (policy == Policy::kDisallowed) { + decisions.allowed_threats.erase(threat_type); + decisions.pending_threats.erase(threat_type); + } + if (policy == Policy::kPending) { + decisions.allowed_threats.erase(threat_type); + decisions.pending_threats.insert(threat_type); + } + if (policy == Policy::kAllowed) { + decisions.allowed_threats.insert(threat_type); + decisions.pending_threats.erase(threat_type); + } + for (auto& observer : observers_) { + observer.ThreatPolicyUpdated(this, url, threat_type, policy); + } + web_state_->DidChangeVisibleSecurityState(); +} + +bool SafeBrowsingUrlAllowList::ContainsThreats( + const GURL& url, + Policy policy, + std::set<SBThreatType>* threat_types) const { + const std::set<SBThreatType>* threats_with_policy = nullptr; + switch (policy) { + case Policy::kAllowed: + threats_with_policy = &GetUnsafeNavigationDecisions(url).allowed_threats; + break; + case Policy::kPending: + threats_with_policy = &GetUnsafeNavigationDecisions(url).pending_threats; + break; + case Policy::kDisallowed: + break; + } + if (threats_with_policy && !threats_with_policy->empty()) { + if (threat_types) + *threat_types = *threats_with_policy; + return true; + } + return false; +} + +void SafeBrowsingUrlAllowList::RevertPolicy(const GURL& url, Policy policy) { + std::set<SBThreatType>* decisions_to_revert = nullptr; + switch (policy) { + case Policy::kAllowed: + decisions_to_revert = &GetUnsafeNavigationDecisions(url).allowed_threats; + break; + case Policy::kPending: + decisions_to_revert = &GetUnsafeNavigationDecisions(url).pending_threats; + break; + case Policy::kDisallowed: + break; + } + if (!decisions_to_revert) + return; + + std::set<SBThreatType> disallowed_threats; + disallowed_threats.swap(*decisions_to_revert); + for (auto& observer : observers_) { + observer.ThreatPolicyBatchUpdated(this, url, disallowed_threats, + Policy::kDisallowed); + } + web_state_->DidChangeVisibleSecurityState(); +} + +#pragma mark - SafeBrowsingUrlAllowList::UnsafeNavigationDecisions + +SafeBrowsingUrlAllowList::UnsafeNavigationDecisions:: + UnsafeNavigationDecisions() = default; + +SafeBrowsingUrlAllowList::UnsafeNavigationDecisions:: + ~UnsafeNavigationDecisions() = default; |