diff --git a/index.bs b/index.bs index 1489f0ef7..a4417ac79 100644 --- a/index.bs +++ b/index.bs @@ -1548,6 +1548,7 @@ data, rather than [=structured header|structured values=], because of limitations on nesting in the latter. The recursive nature of JSON makes it more amenable to future extensions. +
To parse an optional 64-bit signed integer given a [=map=] |map|, a [=string=] |key|, and a possibly null 64-bit signed integer |default|: @@ -1559,6 +1560,9 @@ To parse an optional 64-bit signed integer given a [=map=] |map|, a 1. If |value| cannot be represented by a 64-bit signed integer, return an error. 1. Return |value|. +
+ +
To parse an optional 64-bit unsigned integer given a [=map=] |map|, a [=string=] |key|, and a possibly null 64-bit unsigned integer |default|: @@ -1571,8 +1575,11 @@ a [=string=] |key|, and a possibly null 64-bit unsigned integer |default|: error. 1. Return |value|. +
+

Serialize attribution destinations

+
To serialize [=event-level report/attribution destinations=] |destinations|, run the following steps: 1. [=Assert=]: |destinations| is not [=set/is empty|empty=]. @@ -1593,11 +1600,17 @@ information about the original source registration, namely the order of the original JSON registration, which can be used to distinguish semantically equivalent registrations. +
+ +
To check if a scheme is suitable given a [=string=] |scheme|: 1. If |scheme| is "`http`" or "`https`", return true. 1. Return false. +
+ +
To check if an origin is suitable given an [=origin=] |origin|: 1. If |origin| is not a [=potentially trustworthy origin=], return false. @@ -1605,8 +1618,11 @@ To check if an origin is suitable given an [=origin=] |origin| [=check if a scheme is suitable|suitable=], return false. 1. Return true. +
+

Parsing filter data

+
To parse filter values given a |value|: 1. If |value| is not a [=map=], return an error. @@ -1621,6 +1637,9 @@ To parse filter values given a |value|: 1. [=map/Set=] |result|[|filter|] to |set|. 1. Return |result|. +
+ +
To parse filter data given a |value|: 1. Let |map| be the result of running [=parse filter values=] with |value|. @@ -1637,6 +1656,9 @@ To parse filter data given a |value|: return an error. 1. Return |map|. +
+ +
To parse filter config given a |value|: 1. If |value| is not a [=map=], return an error. @@ -1654,8 +1676,11 @@ To parse filter config given a |value|: :: |lookbackWindow| 1. Return |filter|. +
+

Parsing filters

+
To parse filters given a |value|: 1. Let |filtersList| be a new [=list=]. @@ -1671,6 +1696,9 @@ To parse filters given a |value|: 1. [=list/Append=] |filterConfig| to |filtersList|. 1. Return |filtersList|. +
+ +
To parse a filter pair given a [=map=] |map|: 1. Let |positive| be a [=list=] of [=filter configs=], initially empty. @@ -1683,8 +1711,11 @@ To parse a filter pair given a [=map=] |map|: 1. If |negative| is an error, return it. 1. Return the [=tuple=] (|positive|, |negative|). +
+

Parsing aggregation coordinator

+
To parse an aggregation coordinator given |value|: 1. If |value| is not a [=string=], return an error. @@ -1693,6 +1724,8 @@ To parse an aggregation coordinator given |value|: 1. If |url|'s [=url/origin=] is not an [=aggregation coordinator=], return an error. 1. Return |url|'s [=url/origin=]. +
+

Parsing aggregatable debug reporting config

An aggregatable-debug-reporting JSON key is one of the following: @@ -1705,6 +1738,7 @@ An aggregatable-debug-reporting JSON key is one of the follo
  • "value" +
    To parse aggregatable debug reporting data given a |dataList|, a positive integer |maxValue|, and a [=set=] of [=debug data types=] |supportedTypes|: @@ -1756,6 +1790,9 @@ positive integer |maxValue|, and a [=set=] of [=debug data types=] |debugDataMap|[|type|] to |unspecifiedContribution|. 1. Return |debugDataMap|. +
    + +
    To parse an aggregatable debug reporting config given a [=map=] |map|, a positive integer |maxValue|, a [=set=] of [=debug data types=] |supportedTypes|, and an [=aggregatable debug reporting config=] |default|: @@ -1791,8 +1828,11 @@ and an [=aggregatable debug reporting config=] |default|:

    The parsing errors are intentionally ignored in this algorithm with |default| returned to avoid data loss from the debug reporting feature. +

    +

    Getting registration info

    +
    To get registration info from a header list given a [=header list=] |headers|: @@ -1821,8 +1861,11 @@ To get registration info from a header list given a Issue: Require |preferredPlatformValue| to be a [=structured header/token=]. +
    +

    Cookie-based debugging

    +
    To check if cookie-based debugging is allowed given a [=suitable origin=] |reportingOrigin| and a [=site=] |contextSite|: @@ -1839,13 +1882,19 @@ To check if cookie-based debugging is allowed given a return blocked. 1. Return allowed. +
    +

    Obtaining context origin

    +
    To obtain the context origin of a [=node=] |node|, return |node|'s [=node navigable=]'s [=navigable/top-level traversable=]'s [=navigable/active document=]'s [=origin=]. +
    +

    Obtaining a randomized response

    +
    To obtain a randomized response given |trueValue|, a [=set=] |possibleValues|, and a double |randomPickRate|: @@ -1855,8 +1904,11 @@ double |randomPickRate|: probability. 1. Otherwise, return |trueValue|. +
    +

    Parsing aggregation key piece

    +
    To parse an aggregation key piece given a [=string=] |input|, perform the following steps. This algorithm will return either a non-negative 128-bit integer or an error. @@ -1868,9 +1920,13 @@ This algorithm will return either a non-negative 128-bit integer or an error. 1. If the characters within |value| are not all [=ASCII hex digits=], return an error. 1. Interpret |value| as a hexadecimal number and return as a non-negative 128-bit integer. -

    Should processing be blocked by reporting-origin limit

    +
    -Given an [=attribution rate-limit record=] |newRecord|: +

    Should processing be blocked by reporting-origin limit

    + +
    +To check if processing should be blocked by reporting-origin limit +given an [=attribution rate-limit record=] |newRecord|: 1. Let |max| be [=max source reporting origins per rate-limit window=]. 1. Let |scopeSet| be « "[=rate-limit scope/source=]" ». @@ -1888,17 +1944,25 @@ Given an [=attribution rate-limit record=] |newRecord|: 1. If |distinctReportingOrigins|'s [=set/size=] is greater than |max|, return blocked. 1. Return allowed. -

    Can attribution rate-limit record be removed

    +
    + +

    Can attribution rate-limit record be removed

    + +
    +To check if an attribution rate-limit record can be removed +given an [=attribution rate-limit record=] |record| and a [=moment=] |now|: -Given an [=attribution rate-limit record=] |record| and a [=moment=] |now|: 1. If the [=duration from=] |record|'s [=attribution rate-limit record|time=] and |now| is <= [=attribution rate-limit window=] , return false. 1. If |record|'s [=attribution rate-limit record/scope=] is "[=rate-limit scope/event-attribution=]" or "[=rate-limit scope/aggregatable-attribution=]", return true. 1. If |record|'s [=attribution rate-limit record/expiry time=] is after |now|, return false. 1. Return true. +
    +

    Obtaining and delivering a verbose debug report

    +
    To obtain and deliver a verbose debug report given a [=list=] of [=verbose debug data=] |data|, a [=suitable origin=] |reportingOrigin|, and a [=boolean=] |fenced|: @@ -1910,6 +1974,8 @@ a [=suitable origin=] |reportingOrigin|, and a [=boolean=] |fenced|: :: |reportingOrigin| 1. [=Queue a task=] to [=attempt to deliver a verbose debug report=] with |debugReport|. +
    +

    Making a background attributionsrc request

    An eligibility is one of the following: @@ -1933,6 +1999,7 @@ An eligibility is one of the following: +
    To validate a background attributionsrc eligibility given an [=eligibility=] |eligibility|: @@ -1940,6 +2007,9 @@ To validate a background attributionsrc eligibility given an "[=eligibility/navigation-source=]" or "[=eligibility/event-source-or-trigger=]". +
    + +
    To make a background attributionsrc request given a [=URL=] |url|, an [=origin=] |contextOrigin|, an [=eligibility=] |eligibility|, a [=boolean=] |fenced|, a {{Document}} |document|, and a [=referrer policy=] |referrerPolicy|: @@ -1975,6 +2045,9 @@ we cannot process registrations through integration with [=fetch=]. Issue: Check for transient activation with "[=eligibility/navigation-source=]". +
    + +
    To make background attributionsrc requests given an {{HTMLAttributionSrcElementUtils}} |element|, an [=eligibility=] |eligibility|, and a [=referrer policy=] |referrerPolicy|: @@ -1996,6 +2069,9 @@ and a [=referrer policy=] |referrerPolicy|: Issue: Consider allowing the user agent to limit the size of |tokens|. +
    + +
    To process an attributionsrc response given a [=suitable origin=] |contextOrigin|, an [=eligibility=] |eligibility|, a [=boolean=] |fenced|, and a [=response=] |response|: @@ -2003,6 +2079,9 @@ an [=eligibility=] |eligibility|, a [=boolean=] |fenced|, and a [=response=] |re 1. Run [=process an attribution eligible response=] with |contextOrigin|, |eligibility|, |fenced|, and |response|. +
    + +
    To get the registration platform given a [=header value=] or null |webHeader|, a [=header value=] or null |osHeader|, and a [=registrar=] or null |preferredPlatform|: @@ -2034,6 +2113,9 @@ a [=header value=] or null |osHeader|, and a [=registrar=] or null |preferredPla +
    + +
    To process an attribution source response given a [=suitable origin=] |contextOrigin|, a [=suitable origin=] |reportingOrigin|, a [=source type=] |sourceType|, a [=header value=] or null |webSourceHeader|, a [=header value=] @@ -2076,8 +2158,11 @@ or null |osSourceHeader|, a [=registration info=] |registrationInfo|, and a +
    + +
    To process an attribution trigger response given a [=suitable origin=] -|contextOrigin|, a [=suitable origin=] |reportingOrigin|, a [=response=] |response|, +|contextOrigin|, a [=suitable origin=] |reportingOrigin|, a [=header value=] or null |webTriggerHeader|, a [=header value=] or null |osTriggerHeader|, a [=registration info=] |registrationInfo|, and a [=boolean=] |fenced|: @@ -2118,6 +2203,9 @@ a [=header value=] or null |webTriggerHeader|, a [=header value=] or null +
    + +
    To process an attribution eligible response given a [=suitable origin=] |contextOrigin|, an [=eligibility=] |eligibility|, a [=boolean=] |fenced|, and a [=response=] |response|: @@ -2182,11 +2270,14 @@ and a [=response=] |response|: |sourceHeader|, |osSourceHeader|, |registrationInfo|, and |fenced|. 1. If |hasTriggerRegistration| is true: 1. Run [=process an attribution trigger response=] - with |contextOrigin|, |reportingOrigin|, |response|, |triggerHeader|, + with |contextOrigin|, |reportingOrigin|, |triggerHeader|, |osTriggerHeader|, |registrationInfo|, and |fenced|. +
    + +
    To obtain and deliver debug reports on registration header errors given a [=header name=] |headerName|, a [=header value=] |headerValue|, a [=suitable origin=] |reportingOrigin|, a [=suitable origin=] |contextOrigin|, @@ -2208,8 +2299,11 @@ and a [=boolean=] |fenced|: :: |body| 1. Run [=obtain and deliver a verbose debug report=] with « |data| », |reportingOrigin|, and |fenced|. +
    +

    Attribution debugging

    +
    To check if attribution debugging can be enabled given an [=attribution debug info=] |debugInfo|: 1. If |debugInfo|'s [=attribution debug info/source debug key=] is null, @@ -2218,6 +2312,9 @@ To check if attribution debugging can be enabled given an [=attributi return false. 1. Return true. +
    + +
    To serialize an attribution debug info given a [=map=] |data| and an [=attribution debug info=] |debugInfo|: @@ -2230,8 +2327,11 @@ To serialize an attribution debug info given a [=map=] |data| and an

    We require both source and trigger debug keys to be present to avoid a privacy leak from one-sided third-party cookie access. +

    +

    Obtaining and delivering an aggregatable debug report

    +
    To check if aggregatable debug reporting should be blocked by rate-limit given an [=aggregatable debug rate-limit record=] |newRecord|: @@ -2253,6 +2353,9 @@ given an [=aggregatable debug rate-limit record=] |newRecord|: return blocked. 1. Return allowed. +
    + +
    To obtain and deliver an aggregatable debug report given a [=list=] of [=aggregatable contributions=] |contributions|, a [=suitable origin=] |reportingOrigin|, a [=site=] |effectiveDestination|, @@ -2277,6 +2380,9 @@ an [=aggregation coordinator=] |aggregationCoordinator|, and a [=moment=] |now|: 1. [=Queue a task=] to [=attempt to deliver an aggregatable debug report=] with |report|. +
    + +
    To obtain and deliver an aggregatable debug report on registration given a [=list=] |contributions|, a [=site=] |contextSite|, an [=origin=] |reportingOrigin|, a possibly null [=attribution source=] |source|, a [=site=] |effectiveDestination|, @@ -2327,10 +2433,13 @@ an [=aggregation coordinator=] |aggregationCoordinator|, and a [=moment=] |now|: [=aggregatable debug rate-limit cache=] if the [=duration from=] |entry|'s [=aggregatable debug rate-limit record/time=] and |now| is > [=aggregatable debug rate-limit window=]. +
    + # Source Algorithms # {#source-algorithms}

    Obtaining a randomized source response

    +
    To obtain a set of possible trigger states given a [=randomized response output configuration=] |config|: 1. Let |possibleTriggerStates| be a new [=set=]. 1. [=set/iterate|For each=] |triggerData| of |config|'s [=randomized response output configuration/trigger data=]: @@ -2348,16 +2457,25 @@ To obtain a set of possible trigger states given a [=randomized respo with repetition. 1. Return |possibleValues|. +
    + +
    To obtain a randomized source response pick rate given a positive integer |states| and a double |epsilon|: 1. Return |states| / (|states| − 1 + e|epsilon|). +
    + +
    To obtain a randomized source response given a [=set=] of possible trigger states |possibleValues| and a double |epsilon|: 1. Let |pickRate| be the result of [=obtaining a randomized source response pick rate=] with |possibleValues|'s [=set/size=] and |epsilon|. 1. Return the result of [=obtaining a randomized response=] with null, |possibleValues|, and |pickRate|. +
    +

    Computing channel capacity

    +
    To compute the channel capacity of a source given a positive integer |states| and a double |epsilon|: 1. If |states| is 1, return 0. 1. If |states| is greater than the user agent's [=max trigger-state cardinality=], return an error. @@ -2367,10 +2485,15 @@ To compute the channel capacity of a source given a positive integer

    This algorithm computes the channel capacity [[CHAN]] of a q-ary symmetric channel [[Q-SC]]. +

    + +
    To compute the scopes channel capacity of a source given a positive integer |numTriggerStates|, a positive integer |attributionScopeLimit|, and a positive integer |maxEventStates|: 1. Let |totalStates| be |numTriggerStates| + |maxEventStates| × (|attributionScopeLimit| − 1). 1. Return log2(|totalStates|). +
    +

    Parsing source-registration JSON

    A source-registration JSON key is one of the following: @@ -2403,6 +2526,7 @@ A source-registration JSON key is one of the following:
  • "values" +
    To parse an attribution destination from a [=string=] |str|: 1. Let |url| be the result of running the [=URL parser=] on the value of the |str|. @@ -2412,6 +2536,9 @@ To parse an attribution destination from a [=string=] |str|: 1. Return the result of [=obtain a site|obtaining a site=] from |url|'s [=url/origin=]. +
    + +
    To parse attribution destinations from a [=map=] |map|: 1. If |map|["[=source-registration JSON key/destination=]"] does not [=map/exists|exist=], return an error. 1. Let |val| be |map|["[=source-registration JSON key/destination=]"]. @@ -2434,6 +2561,9 @@ To parse attribution destinations from a [=map=] |map|: destinations are equivalent, regardless of the order of sites in the registration JSON. +
    + +
    To parse a duration given a [=map=] |map|, a [=string=] |key|, and a tuple of [=durations=] (|clampStart|, |clampEnd|): @@ -2451,6 +2581,9 @@ tuple of [=durations=] (|clampStart|, |clampEnd|): Issue: Consider rejecting out-of-bounds values instead of silently clamping. +
    + +
    To parse aggregation keys given a [=map=] |map|: 1. Let |aggregationKeys| be a new [=map=]. @@ -2468,6 +2601,9 @@ To parse aggregation keys given a [=map=] |map|: 1. [=map/Set=] |aggregationKeys|[|key|] to |keyPiece|. 1. Return |aggregationKeys|. +
    + +
    To parse named budgets for source given a [=map=] |map|: 1. Let |namedBudgets| be a new [=map=]. @@ -2484,6 +2620,9 @@ To parse named budgets for source given a [=map=] |map|: 1. [=map/Set=] |namedBudgets|[|key|] to |value|. 1. Return |namedBudgets|. +
    + +
    To obtain default effective windows given a [=source type=] |sourceType|, a [=moment=] |sourceTime|, and a [=duration=] |eventReportWindow|: @@ -2504,6 +2643,9 @@ a [=moment=] |sourceTime|, and a [=duration=] |eventReportWindow|: 1. Set |lastEnd| to |lastEnd| + |deadline|. 1. Return |windows|. +
    + +
    To parse top-level report windows given a [=map=] |map|, a [=moment=] |sourceTime|, a [=source type=] |sourceType|, and a [=duration=] |expiry|: @@ -2520,6 +2662,9 @@ a [=source type=] |sourceType|, and a [=duration=] |expiry|: 1. Return the result of [=parsing report windows=] with |map|["[=source-registration JSON key/event_report_windows=]"], |sourceTime|, and |expiry|. +
    + +
    To parse report windows given a |value|, a [=moment=] |sourceTime|, and a [=duration=] |expiry|: @@ -2552,8 +2697,11 @@ To parse report windows given a |value|, a 1. Set |startDuration| to |endDuration|. 1. Return |windows|. -To parse trigger data into a trigger data set given a [=map=] |map| -and a [=trigger-data matching mode=] |matchingMode|: +
    + +
    +To parse trigger data into a trigger data set given a [=map=] |map|, +a [=trigger-data matching mode=] |matchingMode|, and a [=source type=] |sourceType|: 1. Let |set| be a new [=trigger data set=]. 1. If |map|["[=source-registration JSON key/trigger_data=]"] [=map/exists=]: @@ -2572,7 +2720,7 @@ and a [=trigger-data matching mode=] |matchingMode|: 1. [=set/iterate|For each=] integer |triggerData| of [=the exclusive range|the range=] 0 to [=default trigger data cardinality=][|sourceType|], exclusive: - 1. [=set/Append=] |triggerData| to |triggerDataSet|. + 1. [=set/Append=] |triggerData| to |set|. 1. If |matchingMode| is "[=trigger-data matching mode/modulus=]": 1. Let |i| be 0. 1. [=set/iterate|For each=] |triggerData| of |set|: @@ -2580,6 +2728,9 @@ and a [=trigger-data matching mode=] |matchingMode|: 1. Set |i| to |i| + 1. 1. Return |set|. +
    + +
    To parse a source aggregatable debug reporting config given |value|, a non-negative integer |defaultBudget|, and an [=aggregatable debug reporting config=] |defaultConfig|: @@ -2595,6 +2746,9 @@ non-negative integer |defaultBudget|, and an [=aggregatable debug reporting conf with |value|, |budget|, |supportedTypes|, and |defaultConfig|. 1. Return the [=tuple=] (|budget|, |config|). +
    + +
    To parse attribution scopes from a [=map=] |map|: 1. If |map|["[=source-registration JSON key/attribution_scopes=]"] does not [=map/exists|exist=], return null. 1. Let |value| be |map|["[=source-registration JSON key/attribution_scopes=]"]. @@ -2615,6 +2769,9 @@ To parse attribution scopes from a [=map=] |map|: :: |maxEventStates| 1. Return |attributionScopes|. +
    + +
    To parse max event states from a [=map=] |map|: 1. If |map|["[=source-registration JSON key/max_event_states=]"] does not [=map/exist=], return [=default max event states=]. 1. Let |maxEventStates| be |map|["[=source-registration JSON key/max_event_states=]"]. @@ -2622,6 +2779,9 @@ To parse max event states from a [=map=] |map|: 1. If |maxEventStates| is greater than the user agent's [=max trigger-state cardinality=], return an error. 1. Return |maxEventStates|. +
    + +
    To parse attribution scope values for source from a [=map=] |map| and a 32-bit positive integer |limit|: 1. If |map|["[=source-registration JSON key/values=]"] does not [=map/exist=], return an error. 1. Let |result| be a new [=set=]. @@ -2639,6 +2799,9 @@ To parse attribution scope values for source from a [=map=] |map| and to prevent the selection of both sources with and without scopes, which would effectively result in |limit| + 1 scopes. +
    + +
    To parse source-registration JSON given a [=byte sequence=] |json|, a [=suitable origin=] |sourceOrigin|, a [=suitable origin=] |reportingOrigin|, a [=source type=] |sourceType|, a [=moment=] |sourceTime|, and a [=boolean=] |fenced|: @@ -2709,8 +2872,8 @@ To parse source-registration JSON given a [=byte sequence=] [=parsing top-level report windows=] with |value|, |sourceTime|, |sourceType|, and |expiry|. 1. If |eventReportWindows| is an error, return it. -1. Let |triggerDataSet| be the result of [=parsing trigger data into a trigger data set=] with |value| - and |triggerDataMatchingMode|. +1. Let |triggerDataSet| be the result of [=parsing trigger data into a trigger data set=] with |value|, + |triggerDataMatchingMode|, and |sourceType|. 1. If |triggerDataSet| is an error, return it. 1. Let |attributionScopes| be the result of running [=parse attribution scopes=] with |value|. 1. If |attributionScopes| is an error, return it. @@ -2792,8 +2955,11 @@ To parse source-registration JSON given a [=byte sequence=] Issue: Determine proper charset-handling for the JSON header value. +
    +

    Processing an attribution source

    +
    To check if an [=attribution source=] exceeds the time-based destination limits given an [=attribution source=] |source|, run the following steps: @@ -2828,6 +2994,9 @@ To check if an [=attribution source=] exceeds the time-based destination li

    When both limits are hit, we interpret it as "[=destination rate-limit result/hit reporting limit=]" for debug reporting. +

    + +
    To check if an [=attribution source=] exceeds the per day destination limits given an [=attribution source=] |source|, run the following steps: @@ -2843,6 +3012,9 @@ given an [=attribution source=] |source|, run the following steps: [=set/union|unioned=] with |source|'s [=attribution source/attribution destinations=]. 1. Return whether |destinations|'s [=set/size=] is greater than [=max destinations per source reporting site per day=]. +
    + +
    To delete sources for unexpired destination limit given a [=set=] of [=attribution source/internal IDs=] |sourcesToDelete| and a [=moment=] |now|: @@ -2884,6 +3056,8 @@ To delete sources for unexpired destination limit given a [=set=] of +
    + A destination limit record is a [=struct=] with the following items:
    @@ -2898,6 +3072,7 @@ A destination limit record is a [=struct=] with the following items:
    +
    To get sources to delete for the unexpired destination limit given an [=attribution source=] |source|, run the following steps: 1. Let |destinationRecords| be a new [=list=]. @@ -2954,6 +3129,9 @@ To get sources to delete for the unexpired destination limit given an 1. [=set/Append=] |record|'s [=destination limit record/source ID=] to |sourcesToDelete|. 1. Return |sourcesToDelete|. +
    + +
    To check if an [=attribution source=] should be blocked by reporting-origin per site limit given an [=attribution source=] |source|: 1. Let |matchingRateLimitRecords| be all [=attribution rate-limit records=] |record| in the [=attribution rate-limit cache=] where all of the following are true: @@ -2965,6 +3143,9 @@ To check if an [=attribution source=] should be blocked by reporting-origin 1. If |distinctReportingOrigins|'s [=list/size=] is greater than [=max source reporting origins per source reporting site=], return blocked. 1. Return allowed. +
    + +
    To obtain a fake report given an [=attribution source=] |source| and a [=trigger state=] |triggerState|: @@ -2977,8 +3158,11 @@ a [=trigger state=] |triggerState|: |triggerState|'s [=trigger state/report window=]'s [=report window/end=]. 1. Return |fakeReport|. +
    + +
    To obtain and deliver a verbose debug report on source registration given a -[=source debug data types=] |dataType|, an [=attribution source=] |source|, +[=source debug data type=] |dataType|, an [=attribution source=] |source|, a [=boolean=] |isNoised|, and a [=boolean=] |destinationLimitReplaced|: 1. If |source|'s [=attribution source/debug reporting enabled=] is false, return. @@ -3054,6 +3238,9 @@ leakage of cross-origin data. 1. Run [=obtain and deliver a verbose debug report=] with « |data| », |source|'s [=attribution source/reporting origin=], and |source|'s [=attribution source/fenced=]. +
    + +
    To obtain and deliver an aggregatable debug report on source registration given a [=source debug data type=] |dataType|, an [=attribution source=] |source|, a [=boolean=] |isNoised|, and a [=boolean=] |destinationLimitReplaced|: @@ -3087,22 +3274,31 @@ a [=boolean=] |isNoised|, and a [=boolean=] |destinationLimitReplaced|: |config|'s [=aggregatable debug reporting config/aggregation coordinator=], and |source|'s [=attribution source/source time=]. +
    + +
    To obtain and deliver debug reports on source registration given a [=source debug data type=] |dataType|, an [=attribution source=] |source|, an optional [=boolean=] |isNoised| (default false), and an optional [=boolean=] |destinationLimitReplaced| (default false): 1. Run [=obtain and deliver a verbose debug report on source registration=] - with |dataTypes|, |source|, |isNoised|, and |destinationLimitReplaced|. + with |dataType|, |source|, |isNoised|, and |destinationLimitReplaced|. 1. Run [=obtain and deliver an aggregatable debug report on source registration=] - with |dataTypes|, |source|, |isNoised|, and |destinationLimitReplaced|. + with |dataType|, |source|, |isNoised|, and |destinationLimitReplaced|. + +
    +
    To delete expired sources given a [=moment=] |now|: 1. [=set/iterate|For each=] |source| of the [=attribution source cache=]: 1. If |source|'s [=attribution source/expiry time=] is less than |now|, [=set/remove=] |source| from the [=attribution source cache=]. +
    + +
    To find sources with common destinations and reporting origin given an [=attribution source=] |pendingSource|: 1. Let |matchingSources| be a new [=list=]. 1. [=set/iterate|For each=] |source| of the user agent's [=attribution source cache=]: @@ -3112,6 +3308,9 @@ To find sources with common destinations and reporting origin given a 1. [=list/Append=] |source| to |matchingSources|. 1. Return |matchingSources|. +
    + +
    To remove associated event-level reports and rate-limit records given an [=attribution source/internal ID=] |sourceId| and a [=moment=] |minTriggerTime|: 1. [=set/iterate|For each=] [=event-level report=] |report| of the [=event-level report cache=]: 1. If |report|'s [=event-level report/source ID=] is not equal to |sourceId|, [=iteration/continue=]. @@ -3119,6 +3318,9 @@ To remove associated event-level reports and rate-limit records given 1. [=set/Remove=] |report| from the [=event-level report cache=]. 1. [=list/Remove=] all [=attribution rate-limit records=] |entry| from the [=attribution rate-limit cache=] where |entry|'s [=attribution rate-limit record/entity ID=] is equal to |report|'s [=event-level report/internal ID=]. +
    + +
    To remove sources with unselected attribution scopes for destination given a [=site=] |destination| and an [=attribution source=] |pendingSource|: 1. Let |scopeRecords| be a new [=list=]. 1. Let |scopes| be |pendingSource|'s [=attribution source/attribution scopes=]'s [=attribution scopes/values=]. @@ -3140,6 +3342,9 @@ To remove sources with unselected attribution scopes for destination 1. [=Remove associated event-level reports and rate-limit records=] with |source|'s [=attribution source/internal ID=] and |pendingSource|'s [=attribution source/source time=]. 1. [=set/Remove=] |source| from the [=attribution source cache=]. +
    + +
    To remove sources with unselected attribution scopes given an [=attribution source=] |pendingSource|: 1. If |pendingSource|'s [=attribution source/attribution scopes=] is null, return. 1. [=Assert=]: |pendingSource|'s [=attribution source/attribution destinations=] is [=list/sort in ascending order|sorted=] in @@ -3149,6 +3354,9 @@ To remove sources with unselected attribution scopes given an [=attri 1. [=set/iterate|For each=] |destination| in |pendingSource|'s [=attribution source/attribution destinations=]: 1. [=Remove sources with unselected attribution scopes for destination=] with |destination| and |pendingSource|. +
    + +
    To remove or update sources for attribution scopes given an [=attribution source=] |pendingSource|: 1. Let |pendingScopes| be |pendingSource|'s [=attribution source/attribution scopes=]. 1. Let |matchingSources| be the result of running [=find sources with common destinations and reporting origin=] with |pendingSource|. @@ -3165,6 +3373,9 @@ To remove or update sources for attribution scopes given an [=attribu 1. [=set/Remove=] |source| from the [=attribution source cache=]. 1. [=Remove sources with unselected attribution scopes=] with |pendingSource|. +
    + +
    To process an attribution source given an [=attribution source=] |source|: 1. [=Delete expired sources=] with |source|'s [=attribution source/source time=]. @@ -3267,7 +3478,7 @@ To process an attribution source given an [=attribution source=] |sou :: |source|'s [=attribution source/internal ID=] : [=attribution rate-limit record/destination limit priority=] :: |source|'s [=attribution source/destination limit priority=] - 1. If the result of running [=should processing be blocked by reporting-origin limit=] with + 1. If the result of running [=check if processing should be blocked by reporting-origin limit=] with |rateLimitRecord| is blocked: 1. Run [=obtain and deliver debug reports on source registration=] with "[=source debug data type/source-reporting-origin-limit=]", @@ -3277,7 +3488,7 @@ To process an attribution source given an [=attribution source=] |sou 1. [=set/iterate|For each=] |record| of |newRateLimitRecords|, [=set/append=] |record| to the [=attribution rate-limit cache=]. 1. [=list/Remove=] all [=attribution rate-limit records=] |entry| from the [=attribution rate-limit cache=] if the result of running - [=can attribution rate-limit record be removed=] with |entry| and |source|'s [=attribution source/source time=] is true. + [=check if an attribution rate-limit record can be removed=] with |entry| and |source|'s [=attribution source/source time=] is true. 1. If |source|'s [=attribution source/randomized response=] is not null and is a [=list=]: 1. [=list/iterate|For each=] [=trigger state=] |triggerState| of |source|'s [=attribution source/randomized response=]: @@ -3318,6 +3529,8 @@ in [=verbose debug reports=] have to be checked before any limits that are repor prevent side-channel leakage of cross-origin data. Furthermore, the [=verbose debug data=] have to be fully determined regardless of the result of checks on implicitly reported limits. +
    + # Triggering Algorithms # {#trigger-algorithms} A trigger-registration JSON key is one of the following: @@ -3351,6 +3564,7 @@ A trigger-registration JSON key is one of the following:

    Creating an attribution trigger

    +
    To parse event triggers given a [=map=] |map|: 1. Let |eventTriggers| be a new [=set=]. @@ -3390,6 +3604,9 @@ To parse event triggers given a [=map=] |map|: 1. [=set/Append=] |eventTrigger| to |eventTriggers|. 1. Return |eventTriggers|. +
    + +
    To parse aggregatable trigger data given a [=map=] |map|: 1. Let |aggregatableTriggerData| be a new [=list=]. @@ -3422,6 +3639,9 @@ To parse aggregatable trigger data given a [=map=] |map|: 1. [=list/Append=] |aggregatableTrigger| to |aggregatableTriggerData|. 1. Return |aggregatableTriggerData|. +
    + +
    To parse aggregatable filtering ID max bytes given a [=map=] |map|: 1. Let |maxBytes| be [=default filtering ID max bytes=]. @@ -3432,12 +3652,18 @@ To parse aggregatable filtering ID max bytes given a [=map=] |map|: 1. Otherwise, return an error. 1. Return |maxBytes|. +
    + +
    To validate aggregatable key-values value given a |value|: 1. If |value| is not an integer, return false. 1. If |value| is less than or equal to 0, return false. 1. If |value| is greater than [=allowed aggregatable budget per source=], return false. 1. Return true. +
    + +
    To parse aggregatable key-values given a [=map=] |map| and a positive integer |maxBytes|: 1. Let |out| be a new [=map=]. @@ -3468,6 +3694,9 @@ To parse aggregatable key-values given a [=map=] |map| and a positive :: |filteringId| 1. Return |out|. +
    + +
    To parse aggregatable values given a [=map=] |map| and a positive integer |maxBytes|: 1. If |map|["[=trigger-registration JSON key/aggregatable_values=]"] does not [=map/exist=], return a new [=list=]. @@ -3505,6 +3734,9 @@ To parse aggregatable values given a [=map=] |map| and a positive int 1. [=list/Append=] |aggregatableValuesConfiguration| to |aggregatableValuesConfigurations|. 1. Return |aggregatableValuesConfigurations|. +
    + +
    To parse aggregatable dedup keys given a [=map=] |map|: 1. Let |aggregatableDedupKeys| be a new [=list=]. @@ -3530,6 +3762,9 @@ To parse aggregatable dedup keys given a [=map=] |map|: 1. [=set/Append=] |aggregatableDedupKey| to |aggregatableDedupKeys|. 1. Return |aggregatableDedupKeys|. +
    + +
    To parse named budgets for trigger given a [=map=] |map|: 1. Let |namedBudgets| be a new [=list=]. @@ -3555,6 +3790,9 @@ To parse named budgets for trigger given a [=map=] |map|: 1. [=list/Append=] |namedBudget| to |namedBudgets|. 1. Return |namedBudgets|. +
    + +
    To parse attribution scopes for trigger from a [=map=] |map|: 1. Let |result| be a new [=set=]. 1. If |map|["[=trigger-registration JSON key/attribution_scopes=]"] does not [=map/exist=], return |result|. @@ -3565,6 +3803,9 @@ To parse attribution scopes for trigger from a [=map=] |map|: 1. [=set/Append=] |value| to |result|. 1. Return |result|. +
    + +
    To create an attribution trigger given a [=byte sequence=] |json|, a [=site=] |destination|, a [=suitable origin=] |reportingOrigin|, a [=moment=] |triggerTime|, and a [=boolean=] |fenced|: @@ -3668,8 +3909,11 @@ a [=moment=] |triggerTime|, and a [=boolean=] |fenced|: Issue: Determine proper charset-handling for the JSON header value. +
    +

    Does filter data match

    +
    To match [=filter values=] given a [=filter value=] |a| and a [=filter value=] |b|: 1. If |b| [=set/is empty=], then: 1. If |a| [=set/is empty=], then return true. @@ -3678,6 +3922,9 @@ To match [=filter values=] given a [=filter value=] |a| and a [=filte 1. If |i| [=set/is empty=], then return false. 1. Return true. +
    + +
    To match [=filter values=] with negation given a [=filter value=] |a| and a [=filter value=] |b|: 1. If |b| [=set/is empty=], then: 1. If |a| is not [=set/is empty|empty=], then return true. @@ -3686,6 +3933,9 @@ To match [=filter values=] with negation given a [=filter value=] |a| 1. If |i| is not [=set/is empty|empty=], then return false. 1. Return true. +
    + +
    To match an attribution source against a filter config given an [=attribution source=] |source|, a [=filter config=] |filter|, a [=moment=] |moment|, and a [=boolean=] |isNegated|: @@ -3716,6 +3966,9 @@ To match an attribution source against a filter config given an 1. Return true. +
    + +
    To match an attribution source against filters given an [=attribution source=] |source|, a [=list=] of [=filter configs=] |filters|, a [=moment=] |moment|, and a [=boolean=] isNegated: @@ -3725,6 +3978,9 @@ To match an attribution source against filters given an 1. If the result of running [=match an attribution source against a filter config=] with |source|, |filter|, |moment|, and |isNegated| is true, return true. 1. Return false. +
    + +
    To match an attribution source against filters and negated filters given an [=attribution source=] |source|, a [=list=] of [=filter configs=] |filters|, a [=list=] of [=filter configs=] |notFilters|, and a [=moment=] |moment|: @@ -3734,8 +3990,11 @@ To match an attribution source against filters and negated filters gi |source|, |notFilters|, |moment|, and [=match an attribution source against filters/isNegated=] set to true is false, return false. 1. Return true. +
    +

    Should send a report unconditionally

    +
    To check if an aggregatable attribution report should be unconditionally sent given an [=attribution trigger=] |trigger|: 1. If |trigger|'s [=attribution trigger/trigger context ID=] is not null, return true. @@ -3743,8 +4002,11 @@ To check if an aggregatable attribution report should be unconditionally se is not equal to [=default filtering ID max bytes=], return true. 1. Return false. +
    +

    Should attribution be blocked by rate limits

    +
    To check if attribution should be blocked by attribution rate limit given an [=attribution rate-limit record=] |newRecord|: 1. Let |matchingRateLimitRecords| be all [=attribution rate-limit records=] |record| of [=attribution rate-limit cache=] where all of the following are true: @@ -3756,6 +4018,9 @@ To check if attribution should be blocked by attribution rate limit g 1. If |matchingRateLimitRecords|'s [=list/size=] is greater than or equal to [=max attributions per rate-limit window=], return blocked. 1. Return allowed. +
    + +
    To check if attribution should be blocked by rate limits given an [=attribution rate-limit record=] |newRecord|: 1. If the result of running [=check if attribution should be blocked by attribution rate limit=] with |newRecord| is blocked: @@ -3763,18 +4028,21 @@ To check if attribution should be blocked by rate limits given an [=a 1. If |newRecord|'s [=attribution rate-limit record/scope=] is "[=rate-limit scope/aggregatable-attribution=]", set |debugDataType| to "[=trigger debug data type/trigger-aggregate-attributions-per-source-destination-limit=]". 1. Return the [=triggering result=] ("[=triggering status/dropped=]", (|debugDataType|, null)). -1. If the result of running [=should processing be blocked by reporting-origin limit=] with +1. If the result of running [=check if processing should be blocked by reporting-origin limit=] with |newRecord| is blocked: 1. Return the [=triggering result=] ("[=triggering status/dropped=]", ("[=trigger debug data type/trigger-reporting-origin-limit=]", null)). 1. Return null. -Issue(1287): Consider performing [=should processing be blocked by reporting-origin limit=] from +Issue(1287): Consider performing [=check if processing should be blocked by reporting-origin limit=] from [=triggering attribution=] to avoid duplicate invocation from [=triggering event-level attribution=] and [=triggering aggregatable attribution=]. +
    +

    Creating aggregatable contributions

    +
    To create [=aggregatable contributions=] from [=attribution source/aggregation keys=] and aggregatable [=aggregatable values configuration/values=] given a [=map=] |aggregationKeys| and a [=map=] |aggregatableValues|, run the following steps: @@ -3792,6 +4060,9 @@ To create [=aggregatable contributions=] from [=attribution source/aggregat 1. [=list/Append=] |contribution| to |contributions|. 1. Return |contributions|. +
    + +
    To create [=aggregatable contributions=] given an [=attribution source=] |source| and an [=attribution trigger=] |trigger|, run the following steps: @@ -3816,8 +4087,11 @@ To create [=aggregatable contributions=] given an [=attribution sourc |aggregationKeys| and |aggregatableValuesConfiguration|'s [=aggregatable values configuration/values=]. 1. Return a new [=list=]. +
    +

    Can source create aggregatable contributions

    +
    To check if an [=attribution source=] can create [=aggregatable contributions=] given an [=aggregatable attribution report=] |report| and an [=attribution source=] |sourceToAttribute|, run the following steps: @@ -3827,6 +4101,9 @@ To check if an [=attribution source=] can create [=aggregatable contributio |remainingAggregatableBudget|, return false. 1. Return true. +
    + +
    To find matching budget name given an [=attribution trigger=] |trigger| and an [=attribution source=] |sourceToAttribute|: 1. [=list/iterate|For each=] [=named budget=] |namedBudget| of |trigger|'s [=attribution trigger/named budgets=]: 1. If the result of running [=match an attribution source against filters and negated filters=] @@ -3836,6 +4113,9 @@ To find matching budget name given an [=attribution trigger=] |trigge 1. Return |namedBudget|'s [=named budget/name=]. 1. Return null. +
    + +
    To check if an [=attribution source=] can create [=aggregatable contributions=] for matched budget name given an [=aggregatable attribution report=] |report|, an [=attribution source=] |sourceToAttribute|, and a [=string=] |matchedBudgetName|, run the following steps: @@ -3845,8 +4125,11 @@ and a [=string=] |matchedBudgetName|, run the following steps: |sourceToAttribute|'s [=attribution source/remaining named budgets=][|matchedBudgetName|], return false. 1. Return true. +
    +

    Obtaining verbose debug data on trigger registration

    +
    To obtain verbose debug data body on trigger registration given a [=trigger debug data type=] |dataType|, an [=attribution trigger=] |trigger|, a possibly null [=attribution source=] |sourceToAttribute|, and a possibly null @@ -3901,6 +4184,9 @@ a possibly null [=attribution source=] |sourceToAttribute|, and a possibly null [=serialize an integer|serialized=]. 1. Return |body|. +
    + +
    To obtain verbose debug data on trigger registration given a [=trigger debug data type=] |dataType|, an [=attribution trigger=] |trigger|, a possibly null [=attribution source=] |sourceToAttribute|, and a possibly null [=attribution report=] |report|: @@ -3917,8 +4203,11 @@ an [=attribution trigger=] |trigger|, a possibly null [=attribution source=] :: The result of running [=obtain verbose debug data body on trigger registration=] with |dataType|, |trigger|, |sourceToAttribute|, and |report|. 1. Return |data|. +
    +

    Triggering event-level attribution

    +
    An [=event-level report=] |a| is lower-priority than an [=event-level report=] |b| if any of the following are true: @@ -3926,6 +4215,8 @@ an [=event-level report=] |b| if any of the following are true: * |a|'s [=event-level report/trigger priority=] is equal to |b|'s [=event-level report/trigger priority=] and |a|'s [=event-level report/trigger time=] is greater than |b|'s [=event-level report/trigger time=]. +
    + An event-level-report-replacement result is one of the following:
    @@ -3943,6 +4234,7 @@ An event-level-report-replacement result is one of the follo
    +
    To maybe replace event-level report given an [=attribution source=] |sourceToAttribute| and an [=event-level report=] |report|: @@ -3973,6 +4265,9 @@ To maybe replace event-level report given an [=attribution source=] 1. [=set/Remove=] |rateLimitRecord| from the [=attribution rate-limit cache=]. 1. Return "[=event-level-report-replacement result/add-new-report=]". +
    + +
    To trigger event-level attribution given an [=attribution trigger=] |trigger| and an [=attribution source=] |sourceToAttribute|, run the following steps: @@ -4084,8 +4379,11 @@ To trigger event-level attribution given an [=attribution trigger=] | [=attempt to deliver a debug report=] with |report|. 1. Return the [=triggering result=] (|triggeringStatus|, |debugData|). +
    +

    Triggering aggregatable attribution

    +
    To trigger aggregatable attribution given an [=attribution trigger=] |trigger| and an [=attribution source=] |sourceToAttribute|, run the following steps: @@ -4164,8 +4462,11 @@ To trigger aggregatable attribution given an [=attribution trigger=] [=queue a task=] to [=attempt to deliver a debug report=] with |report|. 1. Return the [=triggering result=] ("[=triggering status/attributed=]", null). +
    +

    Triggering attribution

    +
    To obtain and deliver a verbose debug report on trigger registration given a [=set=] of [=trigger debug data=] |dataSet|, an [=attribution trigger=] |trigger|, and a possibly null [=attribution source=] |sourceToAttribute|: @@ -4180,6 +4481,9 @@ and a possibly null [=attribution source=] |sourceToAttribute|: 1. Run [=obtain and deliver a verbose debug report=] with |debugDataList|, |trigger|'s [=attribution trigger/reporting origin=], and |trigger|'s [=attribution trigger/fenced=]. +
    + +
    To obtain and deliver an aggregatable debug report on trigger registration given a [=set=] of [=trigger debug data=] |dataSet|, an [=attribution trigger=] |trigger|, and a possibly null [=attribution source=] |sourceToAttribute|: @@ -4214,6 +4518,9 @@ and a possibly null [=attribution source=] |sourceToAttribute|: |config|'s [=aggregatable debug reporting config/aggregation coordinator=], and |trigger|'s [=attribution trigger/trigger time=]. +
    + +
    To obtain and deliver debug reports on trigger registration given a [=set=] of [=trigger debug data=] |dataSet|, an [=attribution trigger=] |trigger|, and a possibly null [=attribution source=] @@ -4224,11 +4531,17 @@ and a possibly null [=attribution source=] 1. Run [=obtain and deliver an aggregatable debug report on trigger registration=] with |dataSet|, |trigger|, and |sourceToAttribute|. +
    + +
    To check if an [=attribution source=] and [=attribution trigger=] have matching attribution scopes given an [=attribution source=] |source| and an [=attribution trigger=] |trigger|: 1. If |trigger|'s [=attribution trigger/attribution scopes=] [=set/is empty=], return true. 1. Return whether the [=set/intersection=] of |source|'s [=attribution source/attribution scopes=]'s [=attribution scopes/values=] and |trigger|'s [=attribution trigger/attribution scopes=] is not [=set/is empty|empty=]. +
    + +
    An [=attribution source=] |a| is higher-priority than an [=attribution source=] |b| if the following steps return true: @@ -4237,6 +4550,9 @@ if the following steps return true: 1. If |a|'s [=attribution source/source time=] is greater than |b|'s [=attribution source/source time=], return true. 1. Return false. +
    + +
    To find matching sources given an [=attribution trigger=] |trigger|: 1. Let |matchingSources| be a new [=list=]. @@ -4259,6 +4575,9 @@ To find matching sources given an [=attribution trigger=] |trigger|: [=check if an attribution source and attribution trigger have matching attribution scopes|matching attribution scopes with the attribution trigger=] to avoid creating multiple [=attribution reports=] from a single cross-site user interaction. +
    + +
    To check if an [=attribution trigger=] contains aggregatable data given an [=attribution trigger=] |trigger|, run the following steps: @@ -4266,6 +4585,9 @@ run the following steps: 1. If any of |trigger|'s [=attribution trigger/aggregatable values configurations=]'s [=aggregatable values configuration/values=] is not [=list/is empty|empty=], return true. 1. Return false. +
    + +
    To trigger attribution given an [=attribution trigger=] |trigger|, run the following steps: 1. Let |hasAggregatableData| be the result of [=checking if an attribution trigger contains aggregatable data=] @@ -4308,12 +4630,15 @@ To trigger attribution given an [=attribution trigger=] |tri run [=generate null attribution reports=] with |trigger| and [=generate null attribution reports/report=] set to null. 1. [=list/Remove=] all [=attribution rate-limit records=] |entry| from the [=attribution rate-limit cache=] if the result of running - [=can attribution rate-limit record be removed=] with |entry| and |trigger|'s [=attribution trigger/trigger time=] is true. + [=check if an attribution rate-limit record can be removed=] with |entry| and |trigger|'s [=attribution trigger/trigger time=] is true. Issue(1287): Consider replacing |debugDataSet| with a [=list=]. +
    +

    Establishing report delivery time

    +
    To check whether a moment falls within a window given a [=moment=] |moment| and a [=report window=] |window|: @@ -4323,6 +4648,9 @@ a [=report window=] |window|: return falls after. 1. Return falls within. +
    + +
    To obtain an event-level report delivery time given a [=report window list=] |windows| and a [=moment=] |triggerTime|: @@ -4333,6 +4661,9 @@ To obtain an event-level report delivery time given a |window|'s [=report window/end=]. 1. [=Assert=]: not reached. +
    + +
    To obtain an aggregatable attribution report delivery time given an [=attribution trigger=] |trigger|, perform the following steps. They return a [=moment=]. @@ -4342,8 +4673,11 @@ To obtain an aggregatable attribution report delivery time given an [ 1. Let |r| be a random double between 0 (inclusive) and 1 (exclusive) with uniform probability. 1. Return |triggerTime| + |r| × [=randomized aggregatable attribution report delay=]. +
    +

    Obtaining an event-level report

    +
    To obtain an event-level report given an [=attribution source=] |source|, a [=moment=] |triggerTime|, a possibly null non-negative 64-bit integer triggerDebugKey, @@ -4381,14 +4715,20 @@ a 64-bit integer priority |priority|, and a non-negative 64-bit integer |trigger :: (|source|'s [=attribution source/debug key=], |triggerDebugKey|). 1. Return |report|. +
    +

    Obtaining an aggregatable report's required budget

    +
    An [=aggregatable report=] |report|'s required aggregatable budget is the total [=aggregatable contribution/value=] of |report|'s [=aggregatable report/contributions=]. +
    +

    Obtaining an aggregatable attribution report

    +
    To obtain an aggregatable attribution report given an [=attribution source=] |source| and an [=attribution trigger=] |trigger|: @@ -4423,8 +4763,11 @@ an [=attribution trigger=] |trigger|: :: |source|'s [=attribution source/internal ID=]. 1. Return |report|. +
    +

    Generating randomized null attribution reports

    +
    To obtain a null attribution report given an [=attribution trigger=] |trigger| and a [=moment=] |sourceTime|: 1. Let |reportTime| be the result of running [=obtain an aggregatable attribution report delivery time=] with |trigger|. @@ -4460,9 +4803,15 @@ To obtain a null attribution report given an [=attribution trigger=] :: Null 1. Return |report|. +
    + +
    To obtain rounded source time given a [=moment=] |sourceTime|, return |sourceTime| in seconds since the UNIX epoch, rounded down to a multiple of a whole day (86400 seconds). +
    + +
    To determine if a randomized null attribution report is generated given a double |randomPickRate|: 1. [=Assert=]: |randomPickRate| is between 0 and 1 (both inclusive). @@ -4470,6 +4819,9 @@ To determine if a randomized null attribution report is generated giv 1. If |r| is less than |randomPickRate|, return true. 1. Otherwise, return false. +
    + +
    To generate null attribution reports given an [=attribution trigger=] |trigger| and a possibly null [=aggregatable attribution report=] report: @@ -4501,11 +4853,17 @@ To generate null attribution reports given an [=attribution trigger=] 1. [=list/Append=] |nullReport| to |nullReports|. 1. Return |nullReports|. +
    + +
    To shuffle a [=list=] |list|, reorder |list|'s elements such that each possible permutation has equal probability of appearance. +
    +

    Deferring trigger attribution

    +
    To maybe defer and then complete trigger attribution given an [=attribution trigger=] |trigger|, run the following steps [=in parallel=]: @@ -4518,6 +4876,8 @@ run the following steps [=in parallel=]: Issue: Specify this in terms of Navigation +
    + # Report delivery # {#report-delivery} The user agent must periodically run [=queue reports for delivery=] on the @@ -4531,6 +4891,7 @@ For example, this can be used to limit the maximum age of any report that is sent.

    +
    To queue reports for delivery given a [=set=] of [=attribution reports=] |cache|, run the following steps: @@ -4560,15 +4921,21 @@ To queue reports for delivery given a [=set=] of

    This is intended to allow user agents to optimize device resource usage. 1. Run [=attempt to deliver a report=] with |report|. +

    +

    Encode an unsigned k-bit integer

    +
    To encode an unsigned k-byte integer given an integer |integerToEncode| and an integer |byteLength|, return the representation of |integerToEncode| as a big-endian [=byte sequence=] of length |byteLength|, left padding with zeroes as necessary. +
    +

    Obtaining an aggregatable report's debug mode

    +
    An [=aggregatable report=] |report|'s debug mode is the result of running the following steps: @@ -4585,8 +4952,11 @@ of running the following steps: +
    +

    Obtaining an aggregatable report's shared info

    +
    An [=aggregatable report=] |report|'s shared info is the result of running the following steps: @@ -4630,8 +5000,11 @@ of running the following steps: 1. Return the [=string=] resulting from executing [=serialize an infra value to a json string=] on |sharedInfo|. +
    +

    Obtaining an aggregatable report's aggregation service payloads

    +
    To obtain the public key for encryption given an [=aggregation coordinator=] |aggregationCoordinator|: 1. Let |url| be a new [=URL record=]. @@ -4648,6 +5021,9 @@ Issue: Specify this in terms of [=fetch=]. might independently pick a key uniformly at random for every encryption operation. The key has to be uniquely identifiable. +
    + +
    An [=aggregatable report=] |report|'s plaintext payload is the result of running the following steps: @@ -4699,6 +5075,9 @@ is the result of running the following steps: 1. Return the [=byte sequence=] resulting from [[!RFC8949|CBOR encoding]] |payload|. +
    + +
    To obtain the encrypted payload given an [=aggregatable report=] |report| and a public key |pkR|, run the following steps: @@ -4710,6 +5089,9 @@ a public key |pkR|, run the following steps: 1. Return the [=byte sequence=] or an error resulting from [[RFC9180#name-encryption-and-decryption|encrypting]] |plaintext| with the [[RFC9180#name-encryption-to-a-public-key|sender's context]]. +
    + +
    To obtain the aggregation service payloads given an [=aggregatable report=] |report|, run the following steps: @@ -4732,8 +5114,11 @@ run the following steps: 1. [=list/Append=] |aggregationServicePayload| to |aggregationServicePayloads|. 1. Return |aggregationServicePayloads|. +
    +

    Serialize attribution report body

    +
    To obtain an event-level report body given an [=attribution report=] |report|, run the following steps: 1. Let |data| be a [=map=] of the following key/value pairs: @@ -4762,11 +5147,17 @@ To obtain an event-level report body given an [=attribution report=] [=event-level report/attribution debug info=]. 1. Return |data|. +
    + +
    To serialize an [=event-level report=] |report|, run the following steps: 1. Let |data| be the result of running [=obtain an event-level report body=] with |report|. 1. Return the [=byte sequence=] resulting from executing [=serialize an infra value to JSON bytes=] on |data|. +
    + +
    To obtain an [=aggregatable report=] body given an [=aggregatable report=] |report|, run the following steps: 1. [=Assert=]: |report|'s [=aggregatable report/effective attribution destination=] is not an [=opaque origin=]. @@ -4783,6 +5174,9 @@ To obtain an [=aggregatable report=] body given an [=aggregatable rep 1. Return |data|. +
    + +
    To serialize an [=aggregatable attribution report=] |report|, run the following steps: 1. Let |data| be the result of running [=obtain an aggregatable report body=] with |report|. @@ -4792,11 +5186,17 @@ To serialize an [=aggregatable attribution report=] |report|, run th |data|["`trigger_context_id`"] to |report|'s [=aggregatable attribution report/trigger context ID=]. 1. Return the [=byte sequence=] resulting from executing [=serialize an infra value to JSON bytes=] on |data|. +
    + +
    To serialize an [=aggregatable debug report=] |report|, run the following steps: 1. Let |data| be the result of running [=obtain an aggregatable report body=] with |report|. 1. Return the [=byte sequence=] resulting from executing [=serialize an infra value to JSON bytes=] on |data|. +
    + +
    To serialize an [=attribution report=] |report|, run the following steps: 1. [=Assert=]: |report| is an [=event-level report=] or an [=aggregatable attribution report=]. @@ -4809,8 +5209,11 @@ To serialize an [=attribution report=] |report|, run the following st +
    +

    Serialize verbose debug report body

    +
    To serialize a [=verbose debug report=] |report|, run the following steps: 1. Let |collection| be a new [=list=]. @@ -4823,8 +5226,11 @@ To serialize a [=verbose debug report=] |report|, run the following s 1. [=list/Append=] |data| to |collection|. 1. Return the [=byte sequence=] resulting from executing [=serialize an Infra value to JSON bytes=] on |collection|. +
    +

    Get report request URL

    +
    To generate a report URL given a [=suitable origin=] |reportingOrigin| and a [=list=] of [=strings=] |path|: 1. Let |reportUrl| be a new [=URL=] record. @@ -4836,6 +5242,9 @@ To generate a report URL given a [=suitable origin=] |reportingOrigin 1. Set |reportUrl|'s [=url/path=] to |fullPath|. 1. Return |reportUrl|. +
    + +
    To generate an attribution report URL given an [=attribution report=] |report| and an optional [=boolean=] isDebugReport (default false): @@ -4853,20 +5262,29 @@ To generate an attribution report URL given an [=attribution report=] 1. Return the result of running [=generate a report URL=] with |report|'s [=attribution report/reporting origin=] and |path|. +
    + +
    To generate a verbose debug report URL given a [=verbose debug report=] |report|: 1. Let |path| be «"`debug`", "`verbose`"». 1. Return the result of running [=generate a report URL=] with |report|'s [=verbose debug report/reporting origin=] and |path|. +
    + +
    To generate an aggregatable debug report URL given an [=aggregatable debug report=] |report|: 1. Let |path| be «"`debug`", "`report-aggregate-debug`"». 1. Return the result of running [=generate a report URL=] with |report|'s [=aggregatable debug report/reporting origin=] and |path|. +
    +

    Creating a report request

    +
    To create a report request given a [=URL=] |url| and a [=byte sequence=] |body|: 1. Let |headers| be a new [=header list=] containing a [=header=] named @@ -4900,10 +5318,13 @@ To create a report request given a [=URL=] |url| and a [=byte sequenc :: "`no-store`" 1. Return |request|. +
    +

    Issuing a report request

    This algorithm constructs a [=request=] and attempts to deliver it to a [=suitable origin=]. +
    To attempt to deliver a report given an [=attribution report=] |report|, run the following steps: 1. [=Assert=]: Neither the [=event-level report cache=] nor the @@ -4921,8 +5342,11 @@ A user agent may retry this algorithm in the event that there was an error. To prevent the report recipient from learning additional information about whether a user is online, retries might be limited in number and subject to random delays. +
    +

    Issuing a debug report request

    +
    To attempt to deliver a debug report given an [=attribution report=] |report|: 1. The user-agent may ignore the report; if so, return. @@ -4933,8 +5357,11 @@ To attempt to deliver a debug report given an [=attribution report=] 1. Let |request| be the result of executing [=create a report request=] on |url| and |data|. 1. [=Fetch=] |request|. +
    +

    Issuing a verbose debug request

    +
    To attempt to deliver a verbose debug report given a [=verbose debug report=] |report|: 1. The user-agent may ignore the report; if so, return. @@ -4943,8 +5370,11 @@ To attempt to deliver a verbose debug report given a [=verbose debug 1. Let |request| be the result of executing [=create a report request=] on |url| and |data|. 1. [=Fetch=] |request|. +
    +

    Issuing an aggregatable debug request

    +
    To attempt to deliver an aggregatable debug report given an [=aggregatable debug report=] |report|: 1. The user-agent may ignore the report; if so, return. @@ -4957,6 +5387,8 @@ Issue(220): This fetch should use a network partition key for an opaque origin. A user agent may retry this algorithm in the event that there was an error. +
    + # Cross App and Web Algorithms # {#cross-app-and-web}

    Get OS registrations

    @@ -4971,6 +5403,7 @@ An OS registration is a [=struct=] with the following items: +
    To get [=OS registrations=] from a header value given a [=header value=] |header|: @@ -4996,6 +5429,8 @@ To get [=OS registrations=] from a header value given a 1. If |registrations| [=list/is empty=], return an error. 1. Return |registrations|. +
    +

    Registrars

    A registrar is one of the following: @@ -5008,6 +5443,7 @@ A registrar is one of the following: +
    To get supported registrars: 1. Let |supportedRegistrars| be a new [=list=]. @@ -5017,8 +5453,11 @@ To get supported registrars: to |supportedRegistrars|. 1. Return |supportedRegistrars|. +
    +

    Deliver OS registration debug reports

    +
    To obtain and deliver debug reports on OS registrations given an [=OS debug data type=] |dataType|, a [=list=] of [=OS registrations=] |registrations|, an [=origin=] |contextOrigin|, and a [=boolean=] |fenced|: @@ -5042,6 +5481,8 @@ an [=origin=] |contextOrigin|, and a [=boolean=] |fenced|: :: |body| 1. Run [=obtain and deliver a verbose debug report=] with « |data| », |origin|, and |fenced|. +
    + # User-Agent Automation # {#automation} The user-agent has an associated boolean automation local testing mode (default false).