chromium/services/network/public/mojom/cookie_manager.mojom

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

module network.mojom;

import "components/content_settings/core/common/content_settings.mojom";
import "components/content_settings/core/common/content_settings_types.mojom";
import "mojo/public/mojom/base/time.mojom";
import "sandbox/policy/mojom/context.mojom";
import "services/network/public/mojom/cookie_partition_key.mojom";
import "services/network/public/mojom/first_party_sets.mojom";
import "services/network/public/mojom/schemeful_site.mojom";
import "url/mojom/url.mojom";

// Parameters for constructing a cookie manager.
struct CookieManagerParams {
  // Whether or not third party cookies should be blocked.
  bool block_third_party_cookies = false;

  // Whether tracking protection for 3PCD (prefs + UX) is enabled.
  bool tracking_protection_enabled_for_3pcd = false;

  // Whether Third Party Cookie Deprecation mitigations efforts such as Third
  // Party Cookie Deprecation Metadata grants are permitted.
  bool mitigations_enabled_for_3pcd = false;

  // Content settings for CookieManager.
  map<content_settings.mojom.ContentSettingsType,
    array<content_settings.mojom.ContentSettingPatternSource>> content_settings;

  // Schemes that unconditionally allow cookies from secure origins.
  array<string> secure_origin_cookies_allowed_schemes;

  // Schemes that unconditionally allow cookies from the same scheme.
  array<string> matching_scheme_cookies_allowed_schemes;

  // Schemes that unconditionally allow third party cookies.
  array<string> third_party_cookies_allowed_schemes;

  // Whether or not to allow cookies for file:// URLs. Can be overridden by
  // CookieManager.AllowFileSchemeCookies().
  bool allow_file_scheme_cookies = false;

  // The type of CookieAccessDelegate to pass to the underlying CookieStore.
  // If these params are not present, CookieManager defaults to using
  // USE_CONTENT_SETTINGS.
  CookieAccessDelegateType cookie_access_delegate_type = USE_CONTENT_SETTINGS;
};

enum CookieAccessDelegateType {
  // Decides access semantics based on the content settings it was constructed
  // with.
  USE_CONTENT_SETTINGS,
  // Always returns Legacy access semantics.
  ALWAYS_LEGACY,
  // Always returns Non-Legacy access semantics.
  ALWAYS_NONLEGACY,
};

enum CookiePriority {
  LOW,
  MEDIUM,
  HIGH
};

enum CookieSourceScheme {
  kUnset,
  kNonSecure,
  kSecure,
};

// See https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00
// and https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis for
// information about same site cookie restrictions.
// Keep in sync with net/cookies/cookie_constants.h.
// Note: Don't renumber, as these values are persisted to a database.
enum CookieSameSite {
  UNSPECIFIED = -1,
  NO_RESTRICTION = 0,
  LAX_MODE = 1,
  STRICT_MODE = 2,
  // Reserved 3 (was EXTENDED_MODE), next number is 4.
};

enum CookieEffectiveSameSite {
  kNoRestriction = 0,
  kLaxMode = 1,
  kStrictMode = 2,
  kLaxModeAllowUnsafe = 3,
  kUndefined = 4,
};

// Defined in net::CookieInclusionStatus::ExemptionReason.
enum CookieExemptionReason {
    kNone = 0,
    kUserSetting = 1,
    k3PCDMetadata = 2,
    k3PCDDeprecationTrial = 3,
    kTopLevel3PCDDeprecationTrial = 4,
    k3PCDHeuristics = 5,
    kEnterprisePolicy = 6,
    kStorageAccess = 7,
    kTopLevelStorageAccess = 8,
    kCorsOptIn = 9,
    kScheme = 10,
};

enum ContextType {
  CROSS_SITE,
  SAME_SITE_LAX_METHOD_UNSAFE,
  SAME_SITE_LAX,
  SAME_SITE_STRICT
};

enum CookieSameSiteContextMetadataDowngradeType {
  kNoDowngrade,
  kStrictToLax,
  kStrictToCross,
  kLaxToCross,
};

enum CookieSourceType {
  kUnknown,
  kHTTP,
  kScript,
  kOther,
};

enum ContextRedirectTypeBug1221316 {
  kUnset,
  kNoRedirect,
  kCrossSiteRedirect,
  kPartialSameSiteRedirect,
  kAllSameSiteRedirect,
};

enum HttpMethod {
  kUnset,
  kUnknown,
  kGet,
  kHead,
  kPost,
  KPut,
  kDelete,
  kConnect,
  kOptions,
  kTrace,
  kPatch,
};

// Keep defaults here in sync with net/cookies/cookie_options.h.
struct CookieSameSiteContextMetadata {
  CookieSameSiteContextMetadataDowngradeType cross_site_redirect_downgrade = kNoDowngrade;
  ContextRedirectTypeBug1221316 redirect_type_bug_1221316 = kUnset;
  HttpMethod http_method_bug_1221316 = kUnset;
};

// Keep defaults here in sync with net/cookies/cookie_options.h.
struct CookieSameSiteContext {
  ContextType context = CROSS_SITE;
  ContextType schemeful_context = CROSS_SITE;
  CookieSameSiteContextMetadata metadata;
  CookieSameSiteContextMetadata schemeful_metadata;
};

// What rules to apply when determining whether access to a particular cookie is
// allowed.
// Keep in sync with net/cookies/cookie_constants.h.
enum CookieAccessSemantics {
  UNKNOWN = -1,
  NONLEGACY = 0,
  LEGACY,
};

// Keep defaults here in sync with net/cookies/cookie_options.cc.
struct CookieOptions {
  bool exclude_httponly = true;
  CookieSameSiteContext same_site_cookie_context;
  bool update_access_time = true;
  bool return_excluded_cookies = false;
};

// See net/cookies/canonical_cookie.{h,cc} for documentation.
// Keep defaults here in sync with those files.
struct CanonicalCookie {
  string name;
  string value;
  string domain;
  string path;
  mojo_base.mojom.Time creation;
  mojo_base.mojom.Time expiry;
  mojo_base.mojom.Time last_access;
  mojo_base.mojom.Time last_update;
  bool secure = false;
  bool httponly = false;
  CookieSameSite site_restrictions = NO_RESTRICTION;
  CookiePriority priority = MEDIUM;
  CookieSourceScheme source_scheme = kUnset;
  CookiePartitionKey? partition_key;
  // -1 because of url::PORT_UNSPECIFIED
  // url/third_party/mozilla/url_parse.h
  int32 source_port = -1;
  CookieSourceType source_type = kUnknown;
};

// Indicates reasons why a cookie may be excluded in a get or set
// operation and if it should be warned about.
// TODO(crbug.com/40219875): Improve serialization validation comments.
struct CookieInclusionStatus {
  // Bitfield. Is defined in
  // net::CookieInclusionStatus::ExclusionReason.
  uint32 exclusion_reasons;
  // Bitfield. Is defined in
  // net::CookieInclusionStatus::WarningReason.
  uint32 warning_reasons;

  CookieExemptionReason exemption_reason;
};

struct CookieAndLineWithAccessResult {
  CanonicalCookie? cookie;
  string cookie_string;
  CookieAccessResult access_result;
};

union CookieOrLine {
  CanonicalCookie cookie;
  string cookie_string;
};

struct CookieOrLineWithAccessResult {
  CookieOrLine cookie_or_line;
  CookieAccessResult access_result;
};

// See net/cookies/cookie_access_result.{cc,h} for documentation.
struct CookieAccessResult {
  CookieEffectiveSameSite effective_same_site;
  CookieAccessSemantics access_semantics;
  CookieInclusionStatus status;
  bool is_allowed_to_access_secure_cookies;
};

struct CookieWithAccessResult {
  CanonicalCookie cookie;
  CookieAccessResult access_result;
};

// Keep values here in sync with net::CookieChangeCause.
enum CookieChangeCause {
  // The cookie was inserted.
  INSERTED,
  // The cookie was changed directly by a consumer's action.
  EXPLICIT,
  // The cookie was deleted, but no more details are known.
  UNKNOWN_DELETION,
  // The cookie was automatically removed due to an insert operation that
  // overwrote it.
  OVERWRITE,
  // The cookie was automatically removed as it expired.
  EXPIRED,
  // The cookie was automatically evicted during garbage collection.
  EVICTED,
  // The cookie was overwritten with an already-expired expiration date.
  EXPIRED_OVERWRITE
};

struct CookieChangeInfo {
  // The cookie that changed, in its post-change state.
  CanonicalCookie cookie;
  // Access results at the time of the change.
  CookieAccessResult access_result;
  CookieChangeCause cause;
};

// Session cookies are cookies that expire at the end of the browser session.
// That is represented in canonical cookies by a null expiry time.
enum CookieDeletionSessionControl {
  IGNORE_CONTROL,
  SESSION_COOKIES,
  PERSISTENT_COOKIES,
};

// All existing filters are ANDed together.  I.e. if there is a value for
// created_after_time and there's a value for including_domains, only cookies
// in including_domains that have been created after the specified date would be
// deleted.  A value for session_control of IGNORE_CONTROL is treated the same
// as optional values not being present for the other filters.
// If no filters are specified then all cookies will be deleted; this can be
// thought of as there being a default "match everything" filter which is
// ANDed in with all other filters.
//
// Note that whether a domain matches a cookie or not is somewhat nuanced.  For
// the purposes of this filter:
//      * The host/domain cookie distinction is ignored
//      * A cookies effective domain is considered to be the top level registry
//        (including private registries) for the domain stored in the cookie
//        + the next entry down.  So the effective domain for x.y.google.com
//        would be google.com, and the effective domain for x.google.co.uk would
//        be google.co.uk.  See the function
//        net::registry_controlled_domains::GetDomainAndRegistry for more
//        details.
//      * If a cookie does not have such a top level domain (e.g. IP address
//        or private hostname), the domain specified in the cookie (the IP
//        address or private hostname) is used.
struct CookieDeletionFilter {
  // Delete cookies created after a date.
  mojo_base.mojom.Time? created_after_time;

  // Delete cookies created before a date.
  mojo_base.mojom.Time? created_before_time;

  // Delete cookies whose domains are not listed.
  array<string>? excluding_domains;

  // Deletes cookies whose domains are listed.
  array<string>? including_domains;

  // Delete cookies with a particular name.
  string? cookie_name;

  // Delete cookies from a particular host.
  string? host_name;

  // Delete cookies which match the given URL.
  // See https://tools.ietf.org/html/rfc6265, sections 5.1.{3,4} & 5.2.{5,6}
  // for matching rules.  In general terms, secure cookies only match
  // https URLs, the domain must match (the cookie domain must be a suffix
  // of the URL domain), and the path must match (the cookie path must
  // be a prefix of the URL path).  So
  // a cookie with {domain: ".sub.example.com", path: "/path", secure}
  // would be deleted if the URL passed was
  // "https://www.sub.example.com/path/path2" but not if it was
  // "http://www.example.com/x"--in fact, that cookie wouldn't be deleted
  // if any of the secure/domain/path attributes in the URL were changed.
  url.mojom.Url? url;

  // Delete session/persistent cookies.
  CookieDeletionSessionControl session_control = IGNORE_CONTROL;

  // Only delete partitioned cookies contained in this
  // CookiePartitionKeyCollection.
  // See net/cookies/cookie_partition_key_collection.h for documentation.
  // If the field is not set, then we delete cookies from all partitions. This
  // is equivalent to setting the field to
  // CookiePartitionKeyCollection::ContainsAll.
  CookiePartitionKeyCollection? cookie_partition_key_collection;

  // If true, it indicates that third-party cookie blocking would apply to the
  // context triggering the deletion. In these cases, we should only delete
  // partitioned cookies.
  bool partitioned_state_only;
};

interface CookieChangeListener {
  // TODO(rdsmith): Should this be made a batch interface?
  OnCookieChange(CookieChangeInfo change);
};

// CookieManager is a privileged interface that should only be used in trusted
// processes.
//
// Untrusted processes like renderers should use RestrictedCookieManager.
[RequireContext=sandbox.mojom.Context.kBrowser]
interface CookieManager {
  // TODO(rdsmith): Worthwhile specifying a sort order for the getters?

  // Get all the cookies known to the service.
  // Returned cookie list is sorted first by path length (longest first)
  // and second by creation time.
  // TODO(rdsmith): There are consumers that rely on this behavior, but
  // for this function it doesn't make a lot of sense not to also sort
  // on origin.  Should the returned cookies also be sorted by origin?
  GetAllCookies() => (array<CanonicalCookie> cookies);

  // Get all the cookies known to the service.
  // Returned cookie list is sorted first by path length (longest first)
  // and second by creation time.
  // Additionally get a list of the CookieAccessSemantics that applies to each,
  // if known. The |access_semantics_list| is guaranteed to be the same length
  // as |cookies|, with each element in |cookies| having the access semantics
  // which is given by the same index in |access_semantics_list|. If this method
  // is not implemented in the underlying CookieStore, the returned
  // |access_semantics_list| will just contain all UNKNOWNs. If it is
  // supported, the access semantics values will have been determined by
  // querying the CookieStore's CookieAccessDelegate.
  GetAllCookiesWithAccessSemantics()
      => (array<CanonicalCookie> cookies,
          array<CookieAccessSemantics> access_semantics_list);

  // Get all cookies for the specified URL and cookie options.
  // Will also return any partitioned cookies whose partition key are in
  // |cookie_partition_key_collection|.
  // Returned cookie list is sorted first by path length (longest first)
  // and second by creation time. If the |return_excluded_cookies| option is set
  // in the options, |excluded_cookies| with be a list of cookies that were
  // blocked from being sent along with the reason each cookie was blocked. By
  // default, that option is not set and |excluded_cookies| is an empty list.
  GetCookieList(url.mojom.Url url,
                CookieOptions cookie_options,
                CookiePartitionKeyCollection cookie_partition_key_collection)
      => (array<CookieWithAccessResult> cookies,
          array<CookieWithAccessResult> excluded_cookies);

  // Set a cookie.  |source_url| is used to check whether existing secure
  // cookies can be overwritten (secure cookies may be created from a
  // non-secure source), and whether the URL's scheme is permitted to use
  // cookies in the first place.  |cookie_options| indicates whether http_only
  // or SameSite cookies may be overwritten. If a cookie is not permitted to be
  // set, |status| will indicate why it was blocked. If the cookie is permitted,
  // |status| will be set to INCLUDE.
  SetCanonicalCookie(CanonicalCookie cookie, url.mojom.Url source_url,
                     CookieOptions cookie_options)
      => (CookieAccessResult access_result);

  // Delete a cookie. Returns true if a cookie was deleted.
  DeleteCanonicalCookie(CanonicalCookie cookie) => (bool success);

  // Delete a set of cookies matching the passed filter.
  // Returns the number of cookies deleted.
  DeleteCookies(CookieDeletionFilter filter) => (uint32 num_deleted);

  // Delete cookies marked as session-only in cookie settings.
  // Returns the number of cookies deleted.
  DeleteSessionOnlyCookies() => (uint32 num_deleted);

  // Delete cookies marked as session-only in cookie settings that are stale
  // (haven't been accessed or updated in 7 days).
  // Returns the number of cookies deleted.
  // See crbug.com/40285083 for more info.
  //
  // If there is a more general use case for filtering cookie deletion on
  // the last access time, consider replacing this with a call to DeleteCookies
  // by adding a last_accessed time range to CookieDeletionFilter.
  DeleteStaleSessionOnlyCookies() => (uint32 num_deleted);

  // Subscribes the given listener to changes to a cookie.
  //
  // The subscription is canceled by closing the CookieChangeListener's pipe.
  //
  // Note that if the caller may be racing with other uses of the cookie store,
  // it should follow the subscription request with a probe of the relevant
  // information about the tracked cookie, to make sure that a change to the
  // cookie did not happen right before the listener was registered.
  //
  // If |name| is omitted then changes are returned for all cookies for |url|.
  //
  // TODO(rdsmith): Should this have a filter to register for a lot of
  // notifications at once?  Maybe combine with the deletion filter?
  // TODO(rdsmith): Describe the performance implications of using this method.
  // The comments in CookieMonster::AddCallbackForCookie look pretty scary.
  AddCookieChangeListener(
      url.mojom.Url url,
      string? name,
      pending_remote<CookieChangeListener> listener);

  // Subscribes the given listener to changes to this CookieManager's cookies.
  //
  // The subscription is canceled by closing the CookieChangeListener's pipe.
  //
  // TODO(rdsmith): Should this have a filter to register for a lot of
  // notifications at once?  Maybe combine with the deletion filter?
  AddGlobalChangeListener(
      pending_remote<CookieChangeListener> notification_pointer);

  // Clone the interface for use somewhere else.  After this call,
  // requests to the same implementation may be posted to the other side
  // of the pipe new_interface was configured on.
  [AllowedContext=sandbox.mojom.Context.kBrowser]
  CloneInterface(pending_receiver<CookieManager> new_interface);

  // Flush the backing store (if any) to disk.
  FlushCookieStore() => ();

  // Configure this CookieManager to allow/disallow setting cookies for file://
  // URLs. If this is not called, the CookieManager follows
  // CookieManagerParams.allow_file_scheme_cookies. This should be called before
  // the first use of the backing store, otherwise this will have no effect on
  // the CookieManager, returning false to indicate so.
  AllowFileSchemeCookies(bool allow) => (bool success);

  // Sets content settings for cookies. These are used to determine cookie
  // access and cookie deletion behavior. Will
  // ack the caller with a callback when settings have been updated.
  SetContentSettings(
      content_settings.mojom.ContentSettingsType content_settings_type,
      array<content_settings.mojom.ContentSettingPatternSource> settings) => ();

  // Instructs the cookie store to not discard session only cookies on shutdown.
  SetForceKeepSessionState();

  // Enables/Disables blocking of third-party cookies.
  BlockThirdPartyCookies(bool block);

  // Enables/Disables mitigations for third-party cookies deprecation.
  SetMitigationsEnabledFor3pcd(bool enable);

  // Enables/Disables tracking protection for 3PCD (prefs + UX).
  SetTrackingProtectionEnabledFor3pcd(bool enable);

  // Adds a pre-commit delay to the cookie database sqlite persistent store.
  // This delay occurs before every commit and blocks the background task
  // runner.
  SetPreCommitCallbackDelayForTesting(mojo_base.mojom.TimeDelta delay);
};