Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[spec] Introduce StorageInterestGroup and "get storage interest group… #1299

Merged
merged 3 commits into from
Oct 31, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions spec.bs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ spec: html; urlPrefix: https://html.spec.whatwg.org/C
text: create an agent; url: create-an-agent
text: immediately; url: immediately
text: valid floating-point number; url: valid-floating-point-number
text: serialization; for: origin; url: browsers.html#ascii-serialisation-of-an-origin
text: structured clone algorithm; url: dom-structuredclone
spec: infra; urlPrefix: https://infra.spec.whatwg.org/
type: dfn
Expand All @@ -75,6 +76,7 @@ spec: WebAssembly-web-api; urlPrefix: https://webassembly.github.io/spec/web-api
spec: WebIDL; urlPrefix: https://webidl.spec.whatwg.org/
type: dfn
text: convert a Web IDL arguments list to an ECMAScript arguments list; url: #web-idl-arguments-list-converting
text:an exception was thrown
spec: Fenced Frame; urlPrefix: https://wicg.github.io/fenced-frame/
type: dfn
for: browsing context
Expand Down Expand Up @@ -3711,6 +3713,108 @@ RAPPOR</a> noises each coordinate of the bit vector independently, and it is par
1. Return |histogram|.
</div>

## Get storage interest groups for owner ## {#get-storage-interest-groups-for-owner-header}

*This first introductory paragraph is non-normative.*

The [=get storage interest groups for owner=] algorithm returns a Web IDL array of interest groups. This allows a Protected Audience buyer within a shared storage worklet to gain insights into their users and to send Private Aggregation reports.

<xmp class="idl">
dictionary StorageInterestGroup : AuctionAdInterestGroup {
unsigned long long joinCount;
xyaoinum marked this conversation as resolved.
Show resolved Hide resolved
unsigned long long bidCount;
sequence<PreviousWin> prevWinsMs;
USVString joiningOrigin;
long long timeSinceGroupJoinedMs;
long long lifetimeRemainingMs;
long long timeSinceLastUpdateMs;
long long timeUntilNextUpdateMs;
unsigned long long estimatedSize;
};
</xmp>

<div algorithm>
xyaoinum marked this conversation as resolved.
Show resolved Hide resolved
To <dfn>get storage interest groups for owner</dfn> given an [=origin=] |owner|:

1. Let |resultIgs| be an empty [=list=].
xyaoinum marked this conversation as resolved.
Show resolved Hide resolved
1. Let |now| be a [=moment=] equal to the [=current wall time=].
1. [=list/For each=] |ig| of [=user agent=]'s [=interest group set=]:
1. If |ig|'s [=interest group/owner=] does not equal |owner|, then [=iteration/continue=].
1. Let |resultIg| be an empty {{StorageInterestGroup}} dictionary.
1. [=map/Set=] |resultIg|["{{GenerateBidInterestGroup/owner}}"] to the [=serialization of an origin|serialization=] of |ig|'s [=interest group/owner=].
1. [=map/Set=] |resultIg|["{{GenerateBidInterestGroup/name}}"] to |ig|'s [=interest group/name=].
1. [=map/Set=] |resultIg|["{{GenerateBidInterestGroup/enableBiddingSignalsPrioritization}}"] to |ig|'s [=interest group/enable bidding signals prioritization=].
1. If |ig|'s [=interest group/priority vector=] is not null:
1. [=map/Set=] |resultIg|["{{GenerateBidInterestGroup/priorityVector}}"] to |ig|'s [=interest group/priority vector=].
1. If |ig|'s [=interest group/seller capabilities=] is not null:
1. Let |resultSellerCapabilities| be an [=ordered map=].
1. [=map/For each=] |origin| → |originSellerCapabilities| of |ig|'s [=interest group/seller capabilities=]:
1. Let |serializedOrigin| be the [=serialization of an origin|serialization=] of |origin|.
1. [=map/Set=] |resultSellerCapabilities|[|serializedOrigin|] to |originSellerCapabilities|.
1. [=map/Set=] |resultIg|["{{GenerateBidInterestGroup/sellerCapabilities}}"] to |resultSellerCapabilities|.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{{GenerateBidInterestGroup/sellerCapabilities}} is not an [=ordered map=] of byte sequences, it's a record<USVString, sequence<DOMString>>. You need to convert it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, record and ordered_map (== map) should be "implicitly compatible". And the following implicitly conversions should also hold: set (== ordered set) == list == sequence

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, record and ordered_map are "implicitly compatible", but the actual capabilities are stored internally as a byte sequence, not a sequence<DOMString>. So we need some conversion here. That might be kind of difficult since I don't think we actually specify how the enum is encoded into a byte sequence other than that it only takes a bit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I filed #1316, as I feel the right approach is to define those enum fields as strings directly. Besides, in the current specification, when these fields are being set, there's no conversion either: "If capabilityString is "interest-group-counts" or "latency-stats", then append capabilityString to sellerCapabilities."

Thus, it looks like it's best to treat these fields as strings now? This improves readability and aligns with the direction of the proposed specification.

1. [=map/Set=] |resultIg|["{{GenerateBidInterestGroup/executionMode}}"] to |ig|'s [=interest group/execution mode=].
1. [=map/Set=] |resultIg|["{{GenerateBidInterestGroup/biddingLogicURL}}"] to the [=serialize a URL|serialization=] of |ig|'s [=interest group/bidding url=].
1. [=map/Set=] |resultIg|["{{GenerateBidInterestGroup/biddingWasmHelperURL}}"] to the [=serialize a URL|serialization=] of |ig|'s [=interest group/bidding wasm helper url=].
1. [=map/Set=] |resultIg|["{{GenerateBidInterestGroup/updateURL}}"] to the [=serialize a URL|serialization=] of |ig|'s [=interest group/update url=].
1. [=map/Set=] |resultIg|["{{GenerateBidInterestGroup/trustedBiddingSignalsURL}}"] to the [=serialize a URL|serialization=] of |ig|'s [=interest group/trusted bidding signals url=].
1. If |ig|'s [=interest group/trusted bidding signals keys=] is not null:
1. [=map/Set=] |resultIg|["{{GenerateBidInterestGroup/trustedBiddingSignalsKeys}}"] to |ig|'s [=interest group/trusted bidding signals keys=].
1. [=map/Set=] |resultIg|["{{GenerateBidInterestGroup/trustedBiddingSignalsSlotSizeMode}}"] to |ig|'s [=interest group/trusted bidding signals slot size mode=].
1. [=map/Set=] |resultIg|["{{GenerateBidInterestGroup/maxTrustedBiddingSignalsURLLength}}"] to |ig|'s [=interest group/max trusted bidding signals url length=].
1. If |ig|'s [=interest group/user bidding signals=] is not null:
1. Let |parsedUserBiddingSignals| be |ig|'s [=interest group/user bidding signals=] [=parsing a JSON string to a JavaScript value|parsed to a JavaScript value=].
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are you handling failure here? (and other conversion failures in this algorithm)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming the data storage only contains valid serialized values, so we shouldn't expect any deserialization/conversion failures. Perhaps technically it's still better to handle failures due to database corruption? but even so, I assume we don't have to include this in the specification. Please correct me if I made any wrong assumptions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think specifying how failures are handled is probably one of the most important aspects of a specification. If you look at all the issues with undefined behavior in C/C++...

Please specify how failures are handled. I agree that the user bidding signals should be valid JSON, but there are still failure modes where it isn't (such as when the encoder and decoder are using a different JSON version).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Added "return failure" for failed JSON parsing and base64 encode.

1. If [=an exception was thrown=], then return failure.
1. [=map/Set=] |resultIg|["{{GenerateBidInterestGroup/userBiddingSignals}}"] to |parsedUserBiddingSignals|.
1. If |ig|'s [=interest group/ads=] is not null:
1. [=map/Set=] |resultIg|["{{GenerateBidInterestGroup/ads}}"] to |ig|'s [=interest group/ads=] [=converted to an AuctionAd sequence=].
1. If [=an exception was thrown=], then return failure.
1. If |ig|'s [=interest group/ad components=] is not null:
1. [=map/Set=] |resultIg|["{{GenerateBidInterestGroup/adComponents}}"] to |ig|'s [=interest group/ad components=] [=converted to an AuctionAd sequence=].
1. If [=an exception was thrown=], then return failure.
1. If |ig|'s [=interest group/ad sizes=] is not null:
1. Let |resultAdSizes| be an [=ordered map=].
1. [=map/For each=] |sizeName| → |adSize| of |ig|'s [=interest group/ad sizes=]:
1. [=map/Set=] |resultAdSizes|[|sizeName|] to |adSize| [=convert an ad size to a map|converted to a map=].
1. [=map/Set=] |resultIg|["{{GenerateBidInterestGroup/adSizes}}"] to |resultAdSizes|.
1. If |ig|'s [=interest group/size groups=] is not null:
1. [=map/Set=] |resultIg|["{{GenerateBidInterestGroup/sizeGroups}}"] to |ig|'s [=interest group/size groups=].
1. [=map/Set=] |resultIg|["{{AuctionAdInterestGroup/priority}}"] to |ig|'s [=interest group/priority=].
1. If |ig|'s [=interest group/priority signals overrides=] is not null:
1. [=map/Set=] |resultIg|["{{AuctionAdInterestGroup/prioritySignalsOverrides}}"] to |ig|'s [=interest group/priority signals overrides=].
1. If |ig|'s [=interest group/additional bid key=] is not null:
1. Let |encoded| be the result of running [=forgiving-base64 encode=] with |ig|'s [=interest group/additional bid key=].
1. If |encoded| is failure, then return failure.
1. [=map/Set=] |resultIg|["{{AuctionAdInterestGroup/additionalBidKey}}"] to the result of running [=forgiving-base64 encode=] with |ig|'s [=interest group/additional bid key=].
1. [=map/Set=] |resultIg|["{{StorageInterestGroup/joinCount}}"] to the sum of |ig|'s [=interest group/join counts=] for all days within the last 30 days.
1. [=map/Set=] |resultIg|["{{StorageInterestGroup/bidCount}}"] to the sum of |ig|'s [=interest group/bid counts=] for all days within the last 30 days.
1. Let |resultPrevWins| be a new <code>[=sequence=]<{{PreviousWin}}></code>.
1. [=list/For each=] |prevWin| of |ig|'s [=interest group/previous wins=] for all days within the
the last 30 days:
1. Let |timeDelta| be (|now| &minus; |prevWin|'s [=previous win/time=]) in millseconds.
1. Set |timeDelta| to 0 if |timeDelta| is negative, |timeDelta|'s nearest second (rounding down)
otherwise.
1. Let |metadata| be |prevWin|'s [=interest group ad/metadata=] [=parsing a JSON string to a JavaScript value|parsed to a JavaScript value=].
1. If [=an exception was thrown=], then return failure.
1. Let |prevWinAdIDL| be a new {{AuctionAd}} with the following [=struct/items=]:
: {{AuctionAd/renderURL}}
:: the [=URL serializer|serialization=] of |prevWin|'s [=interest group ad/render url=]
: {{AuctionAd/metadata}}
:: |metadata|.
: {{AuctionAd/adRenderId}}
:: |prevWin|'s [=interest group ad/ad render ID=]
1. Let |prevWinElement| be the <code>[=sequence=]<{{PreviousWinElement}}></code> «|timeDelta|, |prevWinAdIDL|».
1. [=list/Append=] |prevWinElement| to |resultPrevWins|.
1. [=map/Set=] |resultIg|["{{StorageInterestGroup/prevWinsMs}}"] to |resultPrevWins|.
1. [=map/Set=] |resultIg|["{{StorageInterestGroup/joiningOrigin}}"] to the [=serialization of an origin|serialization=] of |ig|'s [=interest group/joining origin=].
1. [=map/Set=] |resultIg|["{{StorageInterestGroup/timeSinceGroupJoinedMs}}"] to (|now| &minus; |ig|'s [=interest group/join time=]) in millseconds.
1. [=map/Set=] |resultIg|["{{StorageInterestGroup/lifetimeRemainingMs}}"] to (|ig|'s [=interest group/expiry=] &minus; |now|) in millseconds.
1. [=map/Set=] |resultIg|["{{StorageInterestGroup/timeSinceLastUpdateMs}}"] to (|now| &minus; |ig|'s [=interest group/last updated=]) in millseconds.
1. [=map/Set=] |resultIg|["{{StorageInterestGroup/timeUntilNextUpdateMs}}"] to (|ig|'s [=interest group/next update after=] &minus; |now|) in millseconds.
1. [=map/Set=] |resultIg|["{{StorageInterestGroup/estimatedSize}}"] to |ig|'s [=interest group/estimated size=].
1. [=list/Append=] |resultIg| to |resultIgs|.
1. Return |resultIgs|.
</div>

# Additional Bids and Negative Targeting # {#additional-bids-and-negative-targeting}

## createAuctionNonce() ## {#create-auction-nonce}
Expand Down
Loading