blob: b2616811d34de94cbab2a3d33e4d22b2bfa4db4d [file] [log] [blame]
// 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.
#include "one_time_geolocation_permission_provider.h"
#include "chrome/browser/permissions/last_tab_standing_tracker.h"
#include "chrome/browser/permissions/last_tab_standing_tracker_factory.h"
#include "components/content_settings/core/browser/content_settings_rule.h"
#include "components/content_settings/core/common/content_settings_utils.h"
#include "url/gurl.h"
namespace {
class OneTimeRuleIterator : public content_settings::RuleIterator {
public:
using PatternToGrantTimeMap =
OneTimeGeolocationPermissionProvider::PatternToGrantTimeMap;
explicit OneTimeRuleIterator(
const PatternToGrantTimeMap& pattern_to_grant_time_map)
: begin_iterator_(pattern_to_grant_time_map.begin()),
end_iterator_(pattern_to_grant_time_map.end()) {}
~OneTimeRuleIterator() override = default;
bool HasNext() const override { return begin_iterator_ != end_iterator_; }
content_settings::Rule Next() override {
content_settings::Rule rule(
begin_iterator_->first, ContentSettingsPattern::Wildcard(),
content_settings::ContentSettingToValue(CONTENT_SETTING_ALLOW),
begin_iterator_->second + base::Days(1),
content_settings::SessionModel::OneTime);
begin_iterator_++;
return rule;
}
private:
PatternToGrantTimeMap::const_iterator begin_iterator_;
const PatternToGrantTimeMap::const_iterator end_iterator_;
};
} // namespace
OneTimeGeolocationPermissionProvider::OneTimeGeolocationPermissionProvider(
content::BrowserContext* browser_context) {
last_tab_standing_tracker_ =
LastTabStandingTrackerFactory::GetForBrowserContext(browser_context);
last_tab_standing_tracker_->AddObserver(this);
}
OneTimeGeolocationPermissionProvider::~OneTimeGeolocationPermissionProvider() {
if (last_tab_standing_tracker_)
last_tab_standing_tracker_->RemoveObserver(this);
}
std::unique_ptr<content_settings::RuleIterator>
OneTimeGeolocationPermissionProvider::GetRuleIterator(
ContentSettingsType content_type,
bool incognito) const {
if (content_type != ContentSettingsType::GEOLOCATION)
return nullptr;
return std::make_unique<OneTimeRuleIterator>(grants_with_open_tabs_);
}
bool OneTimeGeolocationPermissionProvider::SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_settings_type,
base::Value&& value,
const content_settings::ContentSettingConstraints& constraints) {
if (content_settings_type != ContentSettingsType::GEOLOCATION)
return false;
// This block handles transitions from Allow Once to Ask/Block by clearing
// the one time grant and letting the pref provider handle the permission as
// usual.
if (constraints.session_model != content_settings::SessionModel::OneTime) {
auto matching_iterator = grants_with_open_tabs_.find(primary_pattern);
if (matching_iterator != grants_with_open_tabs_.end())
grants_with_open_tabs_.erase(matching_iterator);
return false;
}
DCHECK_EQ(content_settings::ValueToContentSetting(value),
CONTENT_SETTING_ALLOW);
grants_with_open_tabs_[primary_pattern] = base::Time::Now();
// We need to handle transitions from Allow to Allow Once gracefully.
// In that case we add the Allow Once setting in this provider, but also
// have to clear the Allow setting in the pref provider. By returning false
// here, we let the control flow trickle down to the pref provider.
return false;
}
base::Time OneTimeGeolocationPermissionProvider::GetWebsiteSettingLastModified(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type) {
if (content_type != ContentSettingsType::GEOLOCATION)
return base::Time();
std::map<ContentSettingsPattern, base::Time>::const_iterator
matching_iterator = grants_with_open_tabs_.find(primary_pattern);
if (matching_iterator == grants_with_open_tabs_.end())
return base::Time();
if (matching_iterator->second + base::Days(1) < base::Time::Now()) {
return base::Time();
}
return matching_iterator->second;
}
void OneTimeGeolocationPermissionProvider::ClearAllContentSettingsRules(
ContentSettingsType content_type) {
if (content_type == ContentSettingsType::GEOLOCATION)
return;
grants_with_open_tabs_.clear();
}
void OneTimeGeolocationPermissionProvider::ShutdownOnUIThread() {
RemoveAllObservers();
}
void OneTimeGeolocationPermissionProvider::SetClockForTesting(
base::Clock* clock) {
NOTREACHED();
}
// All pages with the given origin have either been closed or navigated away
// from. We remove all permissions associated with the origin.
void OneTimeGeolocationPermissionProvider::OnLastPageFromOriginClosed(
const url::Origin& origin) {
for (auto pattern_and_grant_time : grants_with_open_tabs_) {
if (pattern_and_grant_time.first.Matches(origin.GetURL())) {
grants_with_open_tabs_.erase(pattern_and_grant_time.first);
break;
}
}
}
void OneTimeGeolocationPermissionProvider::OnShutdown() {
last_tab_standing_tracker_ = nullptr;
}