diff --git a/spec.bs b/spec.bs
index 6a6ec2d..f8eb34c 100644
--- a/spec.bs
+++ b/spec.bs
@@ -338,6 +338,8 @@ An aggregatable report is a [=struct=] with the following items:
:: A [=string=]
: debug details
:: A [=debug details=]
+: aggregation coordinator
+:: An [=aggregation coordinator=]
: context ID
:: A [=string=] or null
: queued
@@ -345,6 +347,18 @@ An aggregatable report is a [=struct=] with the following items:
+Aggregation coordinator {#aggregation-coordinator-structure}
+------------------------------------------------------------
+
+An aggregation coordinator is an [=origin=] that the [=allowed
+aggregation coordinator set=] [=set/contains=].
+
+Issue: Consider switching to the suitable
+origin concept used by the Attribution Reporting API here and elsewhere.
+
+Issue: Move other structures to be defined inline instead of via a header.
+ Consider also removing all the subheadings.
+
` block to match, and
+ add styling for all algorithms per
+ [bikeshed/1472](https://github.com/speced/bikeshed/issues/1472).
+
To
set the context ID for a batching scope given
a [=string=] |contextId| and a [=batching scope=] |batchingScope|:
@@ -519,8 +573,8 @@ Scheduling reports {#scheduling-reports}
To perform the
report creation and scheduling steps with an
[=origin=] |reportingOrigin|, a [=context type=] |api|, a [=list=] of
{{PAHistogramContribution}}s |contributions|, a [=debug details=]
-|debugDetails|, a [=string=] or null |contextId| and a [=moment=] or null
-|timeout|:
+|debugDetails|, an [=aggregation coordinator=] |aggregationCoordinator|, a
+[=string=] or null |contextId| and a [=moment=] or null |timeout|:
1. [=Assert=]: |reportingOrigin| is a [=potentially trustworthy origin=].
1. Optionally, return.
@@ -553,7 +607,7 @@ To perform the
report creation and scheduling steps with an
reports](#protecting-against-leaks-via-the-number-of-reports).
1. Let |report| be the result of [=obtaining an aggregatable report=] given
|reportingOrigin|, |api|, |truncatedContributions|, |debugDetails|,
- |contextId|, |timeout| and |currentWallTime|.
+ |aggregationCoordinator|, |contextId|, |timeout| and |currentWallTime|.
1. [=set/Append=] |report| to the user agent's [=aggregatable report cache=].
To
consume budget if permitted given a {{long}} |value|, an
@@ -569,8 +623,9 @@ this algorithm should return true.
To
obtain an aggregatable report given an [=origin=]
|reportingOrigin|, a [=context type=] |api|, a [=list=] of
{{PAHistogramContribution}}s |contributions|, a [=debug details=]
-|debugDetails|, a [=string=] or null |contextId|, a [=moment] or null |timeout|
-and a [=moment=] |currentTime|,
+|debugDetails|, an [=aggregation coordinator=] |aggregationCoordinator|, a
+[=string=] or null |contextId|, a [=moment] or null |timeout| and a [=moment=]
+|currentTime|,
perform the following steps. They return an [=aggregatable report=].
1. [=Assert=]: |reportingOrigin| is a [=potentially trustworthy origin=].
1. Let |reportTime| be the result of running [=obtain a report delivery time=]
@@ -590,6 +645,8 @@ perform the following steps. They return an [=aggregatable report=].
:: The result of [=generating a random UUID=].
: [=aggregatable report/debug details=]
:: |debugDetails|
+ : [=aggregatable report/aggregation coordinator=]
+ :: |aggregationCoordinator|
: [=aggregatable report/context ID=]
:: |contextId|
: [=aggregatable report/queued=]
@@ -740,10 +797,8 @@ error.
|aggregationServicePayloads|.
1. Let |data| be an [=ordered map=] of the following key/value pairs:
: "`aggregation_coordinator_origin`"
- :: An [=implementation-defined=] [=origin=], [=serialization of an
- origin|serialized=].
-
- Issue(78): Replace with the chosen (or default) aggregation coordinator.
+ :: |report|'s [=aggregatable report/aggregation coordinator=],
+ [=serialization of an origin|serialized=].
: "`aggregation_service_payloads`"
:: |aggregationServicePayloads|
: "`shared_info`"
@@ -761,7 +816,8 @@ To
obtain the aggregation service payloads given an [=aggregatable
report=] |report|, perform the following steps. They return a [=list=] of
[=maps=] or an error.
1. Let |publicKeyTuple| be the result of [=obtaining the public key for
- encryption=].
+ encryption=] given |report|'s [=aggregatable report/aggregation
+ coordinator=].
1. If |publicKeyTuple| is an error, return |publicKeyTuple|.
1. Let (|pkR|, |keyId|) be |publicKeyTuple|.
1. Let |plaintextPayload| be the result of [=obtaining the plaintext payload=]
@@ -785,11 +841,23 @@ report=] |report|, perform the following steps. They return a [=list=] of
1. [=list/Append=] |aggregationServicePayload| to |aggregationServicePayloads|.
1. Return |aggregationServicePayloads|.
-To
obtain the public key for encryption, perform an
-[=implementation-defined=] sequence of steps. They return a [=tuple=] consisting
-of a public key and a [=string=] (which should uniquely identify the public
-key), or an error in the event that the [=user agent=] failed to obtain the
-public key.
+To
obtain the public key for encryption given an [=aggregation
+coordinator=] |aggregationCoordinator|, perform the following steps. They return
+a [=tuple=] consisting of a public key and a [=string=], or an error.
+
+1. Let |url| be a new [=URL record=].
+1. Set |url|'s [=url/scheme=] to |aggregationCoordinator|'s [=origin/scheme=].
+1. Set |url|'s [=url/host=] to |aggregationCoordinator|'s [=origin/host=].
+1. Set |url|'s [=url/port=] to |aggregationCoordinator|'s [=origin/port=].
+1. Set |url|'s [=url/path=] to «"`.well-known`", "`aggregation-service`",
+ "`v1`", "`public-keys`"».
+1. Return an [=implementation-defined=] [=tuple=] consisting of a public key
+ from |url| and a [=string=] that should uniquely identify the public key or,
+ in the event that the user agent failed to obtain the public key from |url|,
+ an error. This step may be asynchronous.
+
+Issue: Specify this in terms of [=fetch=]. Add details about which encryption
+ standards to use, length requirements, etc.
Note: The user agent is encouraged to enforce regular key rotation. If there are
multiple keys, the user agent can independently pick a key uniformly at
@@ -936,6 +1004,7 @@ partial interface SharedStorageWorkletGlobalScope {
};
dictionary SharedStoragePrivateAggregationConfig {
+ USVString aggregationCoordinatorOrigin;
USVString contextId;
};
@@ -951,6 +1020,26 @@ Add the following algorithm in the subsection
"
Run Operation
Methods":
+To
obtain the aggregation coordinator given a
+{{SharedStorageRunOperationMethodOptions}} |options|, perform the following
+steps. They return an [=aggregation coordinator=], null or a {{DOMException}}:
+
+1. If |options|["`privateAggregationConfig`"] does not [=map/exist=], return
+ null.
+1. If |options|["`privateAggregationConfig`"]["`aggregatonCoordinatorOrigin`"]
+ does not [=map/exist=], return null.
+1. Let |url| be the result of running the [=URL parser=] on
+ |options|["`privateAggregationConfig`"]["`aggregatonCoordinatorOrigin`"].
+1. If |url| is failure or null, return a new {{DOMException}} with name
+ "`SyntaxError`".
+
+ Issue: Consider throwing an error if the path is not empty.
+1. Let |origin| be |url|'s [=url/origin=].
+1. If the result of [=determining if an origin is an aggregation coordinator=]
+ given |origin| is false, return a new {{DOMException}} with name
+ "`DataError`".
+1. Return |origin|.
+
To
obtain the context ID given a
{{SharedStorageRunOperationMethodOptions}} |options|, perform the following
steps. They return a [=string=], null, or a {{DOMException}}:
@@ -970,9 +1059,13 @@ modified in four ways. First, add the following steps just after step 2 ("If
as appropriate:
3. Let |contextId| be the result of [=obtaining the context ID=] given
- options.
+ |options|.
1. If |contextId| is a {{DOMException}}, return [=a promise rejected with=]
|contextId|.
+1. Let |aggregationCoordinator| be the result of [=obtaining the aggregation
+ coordinator=] given |options|.
+1. If |aggregationCoordinator| is a {{DOMException}}, return [=a promise
+ rejected with=] |aggregationCoordinator|.
Second, add the following steps in the nested scope just after "Let |operation|
@@ -986,6 +1079,8 @@ be |operationMap|[|name|]." (renumbering later steps as appropriate):
non-negative [=implementation-defined=] [=duration=].
1. [=Set the context ID for a batching scope=] given |contextId| and
|batchingScope|.
+1. If |aggregationCoordinator| is not null, [=set the aggregation coordinator
+ for a batching scope=] given |aggregationCoordinator| and |batchingScope|.
@@ -1027,9 +1122,13 @@ are modified in three ways. First, add the following steps just after step 5
steps:
6. Let |contextId| be the result of [=obtaining the context ID=] given
- options.
+ |options|.
1. If |contextId| is a {{DOMException}}, return [=a promise rejected with=]
|contextId|.
+1. Let |aggregationCoordinator| be the result of [=obtaining the aggregation
+ coordinator=] given |options|.
+1. If |aggregationCoordinator| is a {{DOMException}}, return [=a promise
+ rejected with=] |aggregationCoordinator|.
Second, add the following steps in the nested scope just after "Let |operation|
@@ -1048,6 +1147,8 @@ be |operationMap|[|name|]." (renumbering later steps as appropriate):
|batchingScope|,
+17. If |group|[{{AuctionAdInterestGroup/privateAggregationConfig}}]
+ [=map/exists=]:
+ 1. Let |aggregationCoordinator| be the result of [=obtaining the Private
+ Aggregation coordinator=] given
+ |group|[{{AuctionAdInterestGroup/privateAggregationConfig}}].
+ 1. If |aggregationCoordinator| is a {{DOMException}}, then
+ [=exception/throw=] |aggregationCoordinator|.
+ 1. Set interestGroup's [=interest group/Private
+ Aggregation coordinator=] to |aggregationCoordinator|.
+
+
+
The {{Navigator/runAdAuction()}} method steps are modified to add the
following step just after step 5 ("If
+16. The [=string/length=] of the [=serialization of an origin|serialization=] of
+ ig's [=interest group/Private Aggregation coordinator=] if
+ the field is not null.
+
+
+
+The