| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/components/security_interstitials/safe_browsing/pending_unsafe_resource_storage.h" |
| |
| #import "base/containers/contains.h" |
| #import "base/functional/callback_helpers.h" |
| #import "base/memory/ptr_util.h" |
| #import "ios/components/security_interstitials/safe_browsing/unsafe_resource_util.h" |
| |
| using safe_browsing::SBThreatType; |
| using security_interstitials::UnsafeResource; |
| |
| namespace { |
| // Returns whether a pending decision exists for `resource`. |
| bool IsUnsafeResourcePending(const UnsafeResource& resource) { |
| SafeBrowsingUrlAllowList* allow_list = GetAllowListForResource(resource); |
| GURL decision_url = SafeBrowsingUrlAllowList::GetDecisionUrl(resource); |
| std::set<SBThreatType> pending_threat_types; |
| return allow_list && |
| allow_list->IsUnsafeNavigationDecisionPending(decision_url, |
| &pending_threat_types) && |
| base::Contains(pending_threat_types, resource.threat_type); |
| } |
| } // namespace |
| |
| #pragma mark - PendingUnsafeResourceStorage |
| |
| PendingUnsafeResourceStorage::PendingUnsafeResourceStorage() = default; |
| |
| PendingUnsafeResourceStorage::PendingUnsafeResourceStorage( |
| const PendingUnsafeResourceStorage& other) |
| : resource_(other.resource_) { |
| UpdatePolicyObserver(); |
| } |
| |
| PendingUnsafeResourceStorage& PendingUnsafeResourceStorage::operator=( |
| const PendingUnsafeResourceStorage& other) { |
| resource_ = other.resource_; |
| UpdatePolicyObserver(); |
| return *this; |
| } |
| |
| PendingUnsafeResourceStorage::~PendingUnsafeResourceStorage() = default; |
| |
| PendingUnsafeResourceStorage::PendingUnsafeResourceStorage( |
| const security_interstitials::UnsafeResource& resource) |
| : resource_(resource) { |
| DCHECK(IsUnsafeResourcePending(resource)); |
| // Reset the resource's callback to prevent misuse. |
| resource_.value().callback = base::DoNothing(); |
| // Create the policy observer for `resource`. |
| UpdatePolicyObserver(); |
| } |
| |
| #pragma mark Private |
| |
| void PendingUnsafeResourceStorage::UpdatePolicyObserver() { |
| if (resource_) { |
| policy_observer_ = ResourcePolicyObserver(this); |
| } else { |
| policy_observer_ = std::nullopt; |
| } |
| } |
| |
| void PendingUnsafeResourceStorage::ResetResource() { |
| resource_ = std::nullopt; |
| policy_observer_ = std::nullopt; |
| } |
| |
| #pragma mark - PendingUnsafeResourceStorage::ResourcePolicyObserver |
| |
| PendingUnsafeResourceStorage::ResourcePolicyObserver::ResourcePolicyObserver( |
| PendingUnsafeResourceStorage* storage) |
| : storage_(storage) { |
| scoped_observation_.Observe(SafeBrowsingUrlAllowList::FromWebState( |
| storage_->resource()->weak_web_state.get())); |
| } |
| |
| PendingUnsafeResourceStorage::ResourcePolicyObserver::ResourcePolicyObserver( |
| const ResourcePolicyObserver& other) |
| : storage_(other.storage_) { |
| scoped_observation_.Observe(SafeBrowsingUrlAllowList::FromWebState( |
| storage_->resource()->weak_web_state.get())); |
| } |
| |
| PendingUnsafeResourceStorage::ResourcePolicyObserver& |
| PendingUnsafeResourceStorage::ResourcePolicyObserver::operator=( |
| const ResourcePolicyObserver& other) { |
| storage_ = other.storage_; |
| return *this; |
| } |
| |
| PendingUnsafeResourceStorage::ResourcePolicyObserver:: |
| ~ResourcePolicyObserver() = default; |
| |
| void PendingUnsafeResourceStorage::ResourcePolicyObserver::ThreatPolicyUpdated( |
| SafeBrowsingUrlAllowList* allow_list, |
| const GURL& url, |
| safe_browsing::SBThreatType threat_type, |
| SafeBrowsingUrlAllowList::Policy policy) { |
| const UnsafeResource* resource = storage_->resource(); |
| if (policy == SafeBrowsingUrlAllowList::Policy::kPending || |
| url != resource->navigation_url || threat_type != resource->threat_type) { |
| return; |
| } |
| |
| storage_->ResetResource(); |
| // ResetResource() destroys `this`, so no additional code should be added. |
| } |
| |
| void PendingUnsafeResourceStorage::ResourcePolicyObserver:: |
| ThreatPolicyBatchUpdated( |
| SafeBrowsingUrlAllowList* allow_list, |
| const GURL& url, |
| const std::set<safe_browsing::SBThreatType>& threat_types, |
| SafeBrowsingUrlAllowList::Policy policy) { |
| const UnsafeResource* resource = storage_->resource(); |
| if (policy == SafeBrowsingUrlAllowList::Policy::kPending || |
| url != resource->navigation_url || |
| !base::Contains(threat_types, resource->threat_type)) { |
| return; |
| } |
| |
| storage_->ResetResource(); |
| // ResetResource() destroys `this`, so no additional code should be added. |
| } |
| |
| void PendingUnsafeResourceStorage::ResourcePolicyObserver:: |
| SafeBrowsingAllowListDestroyed(SafeBrowsingUrlAllowList* allow_list) { |
| storage_->ResetResource(); |
| // ResetResource() destroys `this`, so no additional code should be added. |
| } |