blob: 6b7ec7bff7461af6665bf60a9a3d57d28b00d3a3 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_LOOKALIKES_LOOKALIKE_URL_SERVICE_H_
#define CHROME_BROWSER_LOOKALIKES_LOOKALIKE_URL_SERVICE_H_
#include <vector>
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/field_trial_params.h"
#include "base/sequence_checker.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/lookalikes/core/lookalike_url_util.h"
#include "components/security_state/core/security_state.h"
#include "url/gurl.h"
class Profile;
namespace lookalikes {
struct DomainInfo;
}
namespace content {
class WebContents;
}
// Wrapper used to store the results of a safety tip check. Specifically, this
// is passed to the callback given to GetSafetyTipStatus. |url| is the URL
// applicable for this result.
struct SafetyTipCheckResult {
SafetyTipCheckResult() = default;
SafetyTipCheckResult(const SafetyTipCheckResult& other) = default;
security_state::SafetyTipStatus safety_tip_status =
security_state::SafetyTipStatus::kNone;
GURL url;
GURL suggested_url;
// True if a lookalike heuristic was triggered. Used to track whether a
// heuristic triggered for the given URL.
bool lookalike_heuristic_triggered = false;
};
// Callback type used for retrieving safety tip status. The results of the
// check are given in |result|.
using SafetyTipCheckCallback =
base::OnceCallback<void(SafetyTipCheckResult result)>;
class Profile;
namespace base {
class Clock;
}
// A service that handles operations on lookalike URLs. It can fetch the list of
// engaged sites in a background thread and cache the results until the next
// update. This is more efficient than fetching the list on each navigation for
// each tab separately.
class LookalikeUrlService : public KeyedService {
public:
explicit LookalikeUrlService(Profile* profile);
LookalikeUrlService(const LookalikeUrlService&) = delete;
LookalikeUrlService& operator=(const LookalikeUrlService&) = delete;
~LookalikeUrlService() override;
using EngagedSitesCallback =
base::OnceCallback<void(const std::vector<lookalikes::DomainInfo>&)>;
static LookalikeUrlService* Get(Profile* profile);
// Returns whether the engaged site list is recently updated. Returns true
// even when an update has already been queued or is in progress.
bool EngagedSitesNeedUpdating() const;
// Triggers an update to the engaged site list if one is not already inflight,
// then schedules |callback| to be called with the new list once available.
void ForceUpdateEngagedSites(EngagedSitesCallback callback);
// Returns the _current_ list of engaged sites, without updating them if
// they're out of date.
const std::vector<lookalikes::DomainInfo> GetLatestEngagedSites() const;
void SetClockForTesting(base::Clock* clock);
base::Clock* clock() const { return clock_; }
// Stores the result of a lookalike URL check.
struct LookalikeUrlCheckResult {
// Action to take. kNone means the navigated URL wasn't a lookalike.
lookalikes::LookalikeActionType action_type =
lookalikes::LookalikeActionType::kNone;
// Heuristic match type. kNone means the navigated URL wasn't a lookalike.
lookalikes::LookalikeUrlMatchType match_type =
lookalikes::LookalikeUrlMatchType::kNone;
// Good URL suggested by the matching heuristic. Can be empty if there is no
// suggestion in which case the UI will show a different string.
GURL suggested_url;
// If true, the URL was previously flagged as a lookalike and the warning
// was dismissed by the user. Clears on browser restart for a given URL.
bool is_warning_previously_dismissed = false;
// If true, the URL was allowlisted by the component updater or enterprise
// policies.
bool is_allowlisted = false;
// Elapsed time for the GetDomainInfo() call. Zero if the function wasn't
// called.
base::TimeDelta get_domain_info_duration;
};
// This is the main function to call to check if a url is a lookalike URL. It
// runs all of the necessary checks on `url` before returning a result.
// If `url` is a lookalike, returns a result with the `action_type` and
// `match_type` populated.
// If stop_checking_on_allowlist_or_ignore is true, stops checking if the
// URL is allowlisted or a warning for it was previously ignored.
LookalikeUrlCheckResult CheckUrlForLookalikes(
const GURL& url,
const std::vector<lookalikes::DomainInfo>& engaged_sites,
bool stop_checking_on_allowlist_or_ignore) const;
// Check the safety tip status of the given URL, and
// asynchronously call |callback| with the results. See
// SafetyTipCheckCallback above for details on what's returned. |callback|
// will be called regardless of whether |url| is flagged or
// not. (Specifically, |callback| will be called with SafetyTipStatus::kNone
// if the url is not flagged).
void CheckSafetyTipStatus(const GURL& url,
content::WebContents* web_contents,
SafetyTipCheckCallback callback);
// Returns whether the user has dismissed a similar warning (interstitial or
// safety tip), and thus no warning should be shown for the provided url.
bool IsIgnored(const GURL& url) const;
// Tells the service that the user has explicitly ignored the warning (thus
// adding to the profile-wide allowlist).
void SetUserIgnore(const GURL& url);
// Tells the service that the user has the UI disabled, and thus the warning
// should be ignored. This ensures that subsequent loads of the page are not
// seen as flagged in metrics. This only impacts metrics for control groups.
void OnUIDisabledFirstVisit(const GURL& url);
// Reset set of eTLD+1s to forget the user action that ignores warning. Only
// for testing.
void ResetWarningDismissedETLDPlusOnesForTesting();
static void EnsureFactoryBuilt();
private:
// Called when an async engaged site computation is finished.
void OnUpdateEngagedSitesCompleted(
std::vector<lookalikes::DomainInfo> new_engaged_sites);
// Callback once we have up-to-date |engaged_sites|. Performs checks on the
// navigated |url|. Caller will display the Safety Tip warning when needed.
void CheckSafetyTipStatusWithEngagedSites(
const GURL& url,
SafetyTipCheckCallback callback,
const std::vector<lookalikes::DomainInfo>& engaged_sites);
raw_ptr<Profile> profile_;
raw_ptr<base::Clock> clock_;
base::Time last_engagement_fetch_time_;
std::vector<lookalikes::DomainInfo> engaged_sites_
GUARDED_BY_CONTEXT(sequence_checker_);
// Indicates that an update to the engaged sites list has been queued. Serves
// to prevent enqueuing excessive updates.
bool update_in_progress_ = false;
std::vector<EngagedSitesCallback> pending_update_complete_callbacks_;
// Set of eTLD+1s that we've warned about, and the user has explicitly
// ignored. Used to avoid re-warning the user.
std::set<std::string> warning_dismissed_etld1s_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<LookalikeUrlService> weak_factory_{this};
};
#endif // CHROME_BROWSER_LOOKALIKES_LOOKALIKE_URL_SERVICE_H_