Skip to content

Commit 3433a3e

Browse files
authored
Spec: Define per-context contribution limits (#164)
This change adds the web-visible `maxContributions` field, which enables some callers to request different numbers of contributions per report.
1 parent 1e6db01 commit 3433a3e

File tree

1 file changed

+60
-21
lines changed

1 file changed

+60
-21
lines changed

spec.bs

+60-21
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,8 @@ An aggregatable report is a [=struct=] with the following items:
378378
:: A [=string=] or null
379379
: <dfn>filtering ID max bytes</dfn>
380380
:: A positive integer
381+
: <dfn>max contributions</dfn>
382+
:: A positive integer
381383
: <dfn>queued</dfn>
382384
:: A [=boolean=]
383385

@@ -410,6 +412,8 @@ items:
410412
:: A [=string=] or null
411413
: <dfn>filtering ID max bytes</dfn> (default: [=default filtering ID max bytes=])
412414
:: A positive integer
415+
: <dfn>max contributions</dfn> (default: null)
416+
:: A positive integer or null
413417

414418
</dl>
415419

@@ -466,10 +470,15 @@ controls which [=origins=] are valid [=aggregation coordinators=]. Every
466470
<dfn>Default aggregation coordinator</dfn> is an [=aggregation coordinator=]
467471
that controls which is used for a report if none is explicitly selected.
468472

469-
<dfn>Maximum report contributions</dfn> is a [=map=] from [=context type=] to
470-
positive integers. Semantically, it defines the maximum number of contributions
471-
that can be present in a single report for every kind of calling context, e.g.
472-
Shared Storage.
473+
<dfn>Maximum maxContributions</dfn> is a positive integer that defines an upper
474+
bound on the number of contributions per [=aggregatable report=].
475+
476+
<dfn>Default maxContributions by API</dfn> is a [=map=] from [=context types=]
477+
to positive integers. Semantically, it defines the default number of
478+
contributions per report for every kind of calling context, e.g. Shared Storage.
479+
The values in this map are used when callers do not specifically request another
480+
value. Each value in this map must be less than or equal to [=maximum
481+
maxContributions=].
473482

474483
<dfn>Minimum report delay</dfn> is a non-negative [=duration=] that controls the
475484
minimum delay to deliver an [=aggregatable report=].
@@ -569,12 +578,19 @@ steps. They return a [=boolean=]:
569578
not null, return true.
570579
1. If |preSpecifiedParams|' [=pre-specified report parameters/filtering ID max
571580
bytes=] is not the [=default filtering ID max bytes=], return true.
581+
1. If |preSpecifiedParams|' [=pre-specified report parameters/max
582+
contributions=] is not null, return true.
572583
1. Return false.
573584

574-
Note: If a context ID or non-default filtering ID max bytes was specified, a
575-
report is sent, even if there are no contributions or there is insufficent
576-
budget for the requested contributions. See [Protecting against leaks via
577-
the number of reports](#protecting-against-leaks-via-the-number-of-reports).
585+
Note: It is sometimes necessary to send a 'null report' to conceal the fact that
586+
there were no contributions. For instance, it's possible that budget, which is
587+
cross-site data in its own right, was insufficient for the requested
588+
contributions. Alternatively, the caller might have chosen to make no
589+
contributions after reading cross-site data. In these kinds of scenarios, the
590+
absence of a report could reveal cross-site data to the reporting endpoint. See
591+
[Protecting against leaks via the number of
592+
reports](#protecting-against-leaks-via-the-number-of-reports).
593+
578594
</div>
579595

580596
<div algorithm>
@@ -683,6 +699,9 @@ scope</dfn> given a [=pre-specified report parameters=] |params| and a
683699
filtering ID max bytes=].
684700
1. [=Assert=]: |filteringIdMaxBytes| is [=set/contained=] in the [=valid
685701
filtering ID max bytes range=]
702+
1. Let |maxContributions| be |params|' [=pre-specified report parameters/max
703+
contributions=].
704+
1. [=Assert=]: |maxContributions| is null or greater than zero.
686705
1. [=map/Set=] [=pre-specified report parameters map=][|batchingScope|] to
687706
|params|.
688707

@@ -718,11 +737,13 @@ null |timeout|:
718737
1. [=iteration/Break=].
719738
1. If |hasProcessedContribution| is false, [=list/append=] |contribution| to
720739
|mergedContributions|.
740+
1. Let |effectiveMaxContributions| be the result of [=determining the max
741+
contributions=] with |preSpecifiedParams| and |api|.
721742
1. Let |truncatedContributions| be a new [=list=].
722-
1. If |mergedContributions| has a [=list/size=] greater than [=maximum report
723-
contributions=][|api|]:
724-
1. [=set/For each=] |n| of [=the exclusive range|the range=] 0 to [=maximum
725-
report contributions=][|api|], exclusive:
743+
1. If |mergedContributions| has a [=list/size=] greater than
744+
|effectiveMaxContributions|:
745+
1. [=set/For each=] |n| of [=the exclusive range|the range=] 0 to
746+
|effectiveMaxContributions|, exclusive:
726747
1. [=set/Append=] |mergedContributions|[|n|] to
727748
|truncatedContributions|.
728749
1. Otherwise, set |truncatedContributions| to |mergedContributions|.
@@ -771,7 +792,7 @@ To <dfn>obtain an aggregatable report</dfn> given an [=origin=]
771792
|reportingOrigin|, a [=context type=] |api|, a [=list=] of
772793
{{PAHistogramContribution}}s |contributions|, a [=debug details=]
773794
|debugDetails|, an [=aggregation coordinator=] |aggregationCoordinator|, a
774-
[=pre-specified report parameters=] |preSpecifiedParams|, a [=moment] or null
795+
[=pre-specified report parameters=] |preSpecifiedParams|, a [=moment=] or null
775796
|timeout| and a [=moment=] |currentTime|,
776797
perform the following steps. They return an [=aggregatable report=].
777798
1. [=Assert=]: |reportingOrigin| is a [=potentially trustworthy origin=].
@@ -799,6 +820,9 @@ perform the following steps. They return an [=aggregatable report=].
799820
: [=aggregatable report/filtering ID max bytes=]
800821
:: |preSpecifiedParams|' [=pre-specified report parameters/filtering ID max
801822
bytes=]
823+
: [=aggregatable report/max contributions=]
824+
:: The result of [=determining the max contributions=] with
825+
|preSpecifiedParams| and |api|.
802826
: [=aggregatable report/queued=]
803827
:: false
804828
1. Return |report|.
@@ -821,6 +845,20 @@ They return a [=moment=].
821845

822846
</div>
823847

848+
<div algorithm>
849+
To <dfn>determine the max contributions</dfn> given a [=pre-specified report
850+
parameters=] |preSpecifiedParams| and a [=context type=] |api|, perform the
851+
following steps. They return a positive integer.
852+
1. Let |maxContributions| be |preSpecifiedParams|' [=pre-specified report
853+
parameters/max contributions=].
854+
1. If |maxContributions| is null, return [=default maxContributions by
855+
API=][|api|].
856+
1. If |maxContributions| is greater than [=maximum maxContributions=], return
857+
[=maximum maxContributions=].
858+
1. Return |maxContributions|.
859+
860+
</div>
861+
824862
Sending reports {#sending-reports}
825863
----------------------------------
826864

@@ -1044,8 +1082,7 @@ To <dfn>obtain the plaintext payload</dfn> given an [=aggregatable report=]
10441082
|report|, perform the following steps. They return a [=byte sequence=].
10451083
1. Let |payloadData| be a new [=list=].
10461084
1. Let |contributions| be |report|'s [=aggregatable report/contributions=].
1047-
1. Let |maxContributions| be
1048-
[=maximum report contributions=][[=aggregatable report/api=]].
1085+
1. Let |maxContributions| be |report|'s [=aggregatable report/max contributions=].
10491086
1. [=Assert=]: |contributions|' [=list/size=] is not greater than
10501087
|maxContributions|.
10511088
1. [=iteration/While=] |contributions|' [=list/size=] is less than
@@ -1258,18 +1295,20 @@ However, the number of reports with the given metadata could expose some
12581295
cross-site information. To protect against this, the API delays sending reports
12591296
by a randomized amount of time to make it difficult to determine whether a
12601297
report was sent or not from any particular event. In the case that a
1261-
[=aggregatable report/context ID=] is supplied or a non-default [=aggregatable
1262-
report/filtering ID max bytes=] is specified, the API makes the number of
1263-
reports sent deterministic (sending 'null reports' if necessary -- each
1264-
containing only a contribution with a value of 0 in the payload). Additional
1265-
mitigations may also be possible in the future, e.g. adding noise to the report
1266-
count.
1298+
[=pre-specified report parameters/context ID=] is supplied, a non-default
1299+
[=pre-specified report parameters/filtering ID max bytes=] is specified, or a
1300+
[=pre-specified report parameters/max contributions=] is specified, the API
1301+
makes the number of reports sent deterministic (sending 'null reports' if
1302+
necessary — each containing only a contribution with a value of 0 in the
1303+
payload). Additional mitigations may also be possible in the future, e.g. adding
1304+
noise to the report count.
12671305

12681306
### Protecting against leaks via payload size ### {#protecting-against-leaks-via-payload-size}
12691307

12701308
The length of the payload could additionally expose some cross-site information,
12711309
namely how many contributions are included. To protect against this, the payload
12721310
is padded to a fixed number of contributions.
1311+
12731312
### Temporary debugging mechanism ### {#temporary-debugging-mechanism}
12741313

12751314
The {{PrivateAggregation/enableDebugMode()}} method allows for many of the

0 commit comments

Comments
 (0)