Note: this project is on hold. Chrome's prototype FLEDGE implementation is accessible locally with feature flags, and per the Privacy Sandbox Timeline broader testing should be possible soon.
This is the beginning of a pure-JavaScript implementation of the FLEDGE proposal, on top of existing browser APIs. The goal is to allow testing as much of FLEDGE as possible, in as realistic a manner as possible, given the constraint of not being able to add new features to the browser itself.
This project has not yet been tested in production; use at your own risk. Furthermore, most of the API is not yet implemented.
As with most JavaScript projects, you'll need Node.js and npm. Install
dependencies with npm install
as per usual.
In order to build the frame, you have to set a list of allowed URL prefixes for
the worklets. The frame will only allow biddingLogicUrl
and decisionLogicUrl
values that start with those prefixes. Each such prefix must consist of an HTTPS
origin optionally followed by a path, and must end with a slash. So, for
instance, you could allow worklet scripts under https://dsp.example
, or
https://ssp.example/js/
.
The reason for this is because worklet scripts have access to cross-site interest group and related data, and nothing prevents them from exfiltrating that data. So, if you're going to host the frame and have such cross-site data stored in its origin in users' browsers, you should make sure to only allow worklet scripts from sources that you trust not to do that.
Once you have an allowlist, set the ALLOWED_LOGIC_URL_PREFIXES
environment
variable to the allowlist with the entries separated by commas, then run
npm run build
. For example, on Mac or Linux, you might run
ALLOWED_LOGIC_URL_PREFIXES=https://dsp.example/,https://ssp.example/js/ npm run build
;
on Windows PowerShell, the equivalent would be
$Env:ALLOWED_LOGIC_URL_PREFIXES = "https://dsp.example/,https://ssp.example/js/"; npm run build
.
FLEDGE requires a way to store information in the browser that is (a) accessible
across all websites but (b) only through JavaScript access control.
localStorage
in a cross-origin iframe fits this well. In Chrome this is not
partitioned and only JavaScript running within the iframe can read or modify the
data.
The shim is divided into two pieces:
-
A frame that's embedded onto the page cross-origin in an
<iframe>
tag, e.g.,<iframe src="https://fledge-shim.example/0.1.html">
. -
A library that consumers use to communicate with the frame over
postMessage
.
Almost all of the work happens in the frame; the library is a small adapter that translates the API from functions to messages.
We're planning to implement the API as closely as possible to what is presented in the explainer, but some aspects necessarily differ due to the constraints of running on publisher and advertiser pages, and implementing without browser changes.
To make the API available on a page consumers will compile the library into their code. We're thinking of making it available as an NPM package, or people can pull from github manually.
The library needs to know how to load the frame on the page.
const fledgeShim = new FledgeShim("https://fledge-polyfill.example/0.1.html");
The version number of the frame must match that of the library; this is checked at runtime.
fledgeShim.joinAdInterestGroup(myGroup, 30 * kSecsPerDay);
Initially, only owner
, name
, user_bidding_signals
, and ads
will be
supported. We also plan to support for daily_update_url
and
trusted_bidding_signals_*
, and at least the report_win
portion of
bidding_logic_url
. See the worklet discussion below for more on
bidding_logic_url
.
The daily_update_url
is supported, but because we cannot actually run updates
in the background as the browser would, we will only be able to fetch updates on
days when the polyfill loads on some page.
For trusted bidding signals, we'll need to implement our own caching of responses, since we read FLEDGE as caching at the per-key level. We'll need to parse caching response headers, but we might limit the range of formats we accept.
// auctionWinnerUrl is an opaque token, and not the real rendering url
const auctionWinnerUrl = await fledgeShim.runAdAuction(myAuctionConfig);
All auction configuration options will be supported, but decision_logic_url
(see worklet discussion below) will initially only handle report_result
.
const adFrame = document.createElement("iframe");
adFrame.src = auctionWinnerUrl;
// set whatever further attributes you like on adFrame
document.getElementById("ad-slot-div").appendChild(adFrame);
Because fencedframes don't exist yet, this will render the ad in an ordinary iframe. The shim will not be realistic in testing the security, privacy, performance, or other attributes of fencedframes, since it won't use them at all.
The auctionWinnerUrl
will be the same URL as the FLEDGE Shim frame, with a
randomly generated token appended in the fragment. When rendered with such a
token in its URL fragment, the FLEDGE Shim frame will create a nested iframe
inside itself pointing at the original renderUrl
. This only works from the
same page that called runAdAuction
.
The proposal allows buyers and sellers to provide custom JavaScript
(generate_bid
, score_ad
) which will have access to interest group
information. That access is compatible with the privacy model, because these
worklets are heavily locked down, have no network access, and operate as pure
functions. We are not aware of any secure way to execute arbitrary JavaScript
while protecting information from exfiltration. Initially, we are planning to
require buyers and sellers to check their logic into this repo. Later, we may be
able to use Web Assembly or something custom to avoid that requirement.
Users may wish to test FLEDGE in circumstances where the privacy guarantees are not necessary, such as internal end-to-end testing. We will probably build support for running custom JavaScript in WebWorkers, behind a compile-time "testing only" flag.
Because the MVP allows event level reporting, we do not need the same level of
protection for reporting worklets. The report_result
and report_win
functions will be invoked as described in the spec.
We are planning to implement this in stages, trying to have a version that is minimally useful as early as possible. Our current planned stages are:
Implement core functionality:
joinAdInterestGroup
leaveAdInterestGroup
runAdAuction
Bidding and auction logic will be hardcoded; currently, each ad simply has a static price, and the ad with the highest price wins.
Implement network functionality: respecting daily_update_url
and
trusted_bidding_signals_url
.
Implement bidding and auction logic: respecting bidding_logic_url
and
decision_logic_url
.
Reporting. Respect report_result
and report_win
.
-
Performance: While we will build the shim in a manner as performant as possible, you should not generally expect the performance characteristics of the shim to be realistic.
-
K-Anonymity: We don't intend to implement any of the k-anonymity restrictions. Implementing these restrictions requires either peer-to-peer browser interactions or a trusted server. We may revisit this once Chrome announces how they intend to implement it.
fledge-shim's People
fledge-shim's Issues
trusted_bidding_signals_url
Initially we'll just fetch this and then throw away the results. Later, when more sophisticated bidding algorithms are supported (see #20), they may use the results.
additional_bids
In the spec, this is currently characterized by lots of handwaving and uncertainty, so for the moment we won't implement until a more solid plan for it is in place.
Require 2XX status on network requests
I just checked and Chrome does enforce this.
Event-level reporting for sellers
There's a bit of an open question as to how this API will work, since decision_logic_url
won't work exactly as described in the spec. Options include:
- Add a separate field that callers have to pass
- Have
decision_logic_url
just do reporting and use trusted signals to choose the scoring algorithm - Have
decision_logic_url
do reporting and also make the choice of scoring algorithm in the global scope
Figure out whether partial updates via joinAdInterestGroup are supposed to be supported
See WICG/turtledove#188.
Ads composed of multiple pieces
Deferred for now due to uncertainty and complexity; may be picked back up later if it proves to be needed.
Add unit test: useStore should not commit the transaction if a request callback throws
I've got an implementation on my machine, but it fails because Karma's uncaught exception handling catches the failure and fails the test, and I haven't figured out how to make this not happen.
Fledge shim for trusted server worklets
In turledove:#154 we proposed a way to move some of the JavaScript out of the browser and into a trusted server instead, using this technology. Would it be possible to extend the Fledge Shim so that it supports running experiments around this idea?
We’re thinking of two related experiments, both of which look like relatively minor changes to the Shim and which build on top of each other:
- Have JavaScript be pre-registered in the trusted server via a separate channel and assigned an id. Rather than send the full JS code from the browser to the trusted server, send just the function id and the arguments to call it with. The server runs the registered function and returns the results.
- Move the execution of a group of JS bidding functions, a scoring function, and the final auction to the trusted server.
- The network overhead and browser compute would be further reduced here. We don’t yet know whether that will be required compared to (1).
- In this setup either the FLEDGE Shim requests trusted signals from the client, or the server performs those calls given the keys from the client.
Note that we’re not yet sure what the trust model will be for the trusted server. That’s being explored here and so out of scope for these experiments.
Thanks,
Phil
Multiple bidding algorithms
Currently, the only supported bidding algorithm is "bid a static price associated with the creative". Once others are suggested, we will need a way to allow bidders to choose between them. This will be the FLEDGE bidding_logic_url
parameter, except that it will be a URI of the form fledge-shim:algorithm-name
.
Allow arbitrary metadata instead of just a static price
Follow-up to #20.
Figure out whether relative URLs are supposed to be allowed in calls
Right now, we do allow them, and we convert them to absolute URLs in the calling page, but I'm realizing that I'm actually not sure whether it's supposed to work that way.
Auction timeouts
This should apply both to fetching the worklet script and to running it. Follow-up to #20.
Test persistence across page loads
I don't think Karma can do this, so we'd need WebDriver.
Figure out what's supposed to happen in case of a tie
No source maps in Karma
This makes debugging annoying.
seller property of runAdAuction argument
For the moment I'm not planning to implement this because it seems to be redundant, but filing an issue so this is on our radar in case the spec changes later.
Interest group owners
Feature-Policy will not be supported; the top-level site's permission will not be needed to join an interest group (since we have no way to enforce this). Group owner permission will simply be a domain check for now, without support for delegation. The FLEDGE proposal is ambiguous as to whether we're supposed to support public suffixes; for now, we won't.
Run our implementation against Chrome's tests, and/or vice versa
This could be a good way to find and fix behavioral divergences if we can find a way to make it work.
Behavioral differences with Chrome's implementation of trusted signals fetching
Looking through https://source.chromium.org/chromium/chromium/src/+/main:content/services/auction_worklet/trusted_bidding_signals.cc, there are two apparent differences with how we fetch trusted signals:
- FLEDGE Shim appends the
hostname
andkeys
parameters after any existing query parameters in the provided URL. Chrome appears to require that the provided URL have no query parameters. - FLEDGE Shim escapes each key, joins them with
,
, then escapes them again. Chrome appears to do only one layer of escaping, which means thatkeys
may be ambiguous if there's a,
in one of them.
We should find out whether these are bugs in Chrome's implementation or whether the intent is for the feature to be specified this way.
Support future database version upgrades
IndexedDB requires users to be careful about database versioning, or else code can crash or deadlock. We should figure out some form of this before FLEDGE Shim is deployed into production, to avoid having a problem that can't be fixed later.
Public TypeScript typings for worklet script authors
If you're writing a worklet script in TypeScript, TypeScript should know what type generateBid
is supposed to be and should yell at you if you get it wrong. There's an open question as to how exactly to distribute these typings, e.g., whether they should be a separate package, or what. Follow-up to #20.
Disallow rendering into a different origin from where the auction ran
Without this, browser_signals.top_window_hostname
may not be accurate.
Verify that browser storage will not allow operation when third party cookies are disabled
We got a question offline on whether the shim will function for users who have disabled third party cookies. It is not intended to, but we should check.
Figure out whether embedded credentials are supposed to be allowed in URLs
Currently, we allow embedded credentials in URLs, because I haven't put in a check to explicitly disallow them. There's a comment to the effect that they're not supposed to be allowed in the Chrome codebase, and I could swear at one point I saw the code that actually implemented this check, but I can't find it now.
I think this might be security-relevant but am not super clear on the details. I wish there was an actual spec...
k-anonymity
For the reasons described in README.md, this won't be implemented for now.
Support error telemetry in the frame
Would be good for parties hosting the frame to be able to know if something is going wrong with it. (E.g., if there's a bug that they might want to tell us about.)
Test positioning of creative
In particular we want to make sure that there aren't any undesirable borders or margins or anything and that the inner iframe's width and height are the same as the outer one's.
I tried Intersection Observer but that doesn't seem to be able to look through the iframe viewport to see the position relative to the actual browser window. I looked at the WebDriver documentation but didn't see any way to do this. I suppose I could try just measuring each iframe relative to its parent but that seems like a place where mistakes could get in. Still trying to think of other options.
Using a same-origin ad creative might be necessary or at least convenient. The API doesn't currently allow srcdoc and data: URIs are cross-origin, so this might require a change on the build-tooling side.
Switch to camelCase
Chrome's in-progress implementation is using camelCase, so we should too. See WICG/turtledove#156
Use Trusted Types
Probably via https://github.com/google/safevalues.
Join forces?
Hi @jeffkaufman @taymonbeal 👋🏼 ,
@iamnewton and I have been working on a similar project to provide a pure JS implementation of the fledge spec. I don't see any value in having two versions of what will eventually be a throwaway library. Do. you want to collaborate together on this effort?
Optimize out assertions in production builds
Either the whole thing or just error messages, depending on how paranoid we want to be about being wrong about assert failures being impossible.
Multiple scoring algorithms
Currently, the only supported scoring algorithm is "pass through the bid verbatim". Once others are suggested, we will need a way to allow sellers to choose between them. This will be the FLEDGE decision_logic_url
parameter, except that it will be a URI of the form fledge-shim:algorithm-name
.
user_bidding_signals
We'll add this when there are bidding algorithms that need it (see #20).
Interest group ownership delegation
This isn't an immediate priority, but noting for completeness.
Event-level reporting for buyers
There's a bit of an open question as to how this API will work, since bidding_logic_url
won't work exactly as described in the spec. Options include:
- Add a separate field that callers have to pass
- Have
bidding_logic_url
just do reporting and use trusted signals to choose the bidding algorithm - Have
bidding_logic_url
do reporting and also make the choice of bidding algorithm in the global scope
Sort keys before sending them
Helps avoid leaks, just in case.
Figure out whether hostname is supposed to be included in trustedScoringSignalsUrl
There's been some ambiguity on this.
Interest group expiration
We can't auto-expire the actual storage (whatwg/storage#11), so this'll have to work by simply storing the expiration date, and deleting interest groups after reading them if they're expired.
trusted_scoring_signals_url
Initially we'll just fetch this and then throw away the results. Later, when more sophisticated scoring algorithms are supported (see #21), they may use the results.
browserSignals
Follow-up to #20.
Deduplicate script fetches
As of #20, if n interest groups in a single auction all use the same biddingLogicUrl
, we fetch it n times. This is clearly undesirable.
Write tests that exercise the public API end-to-end
This requires figuring out how to serve the compiled (or at least transpiled) frame into a Karma test.
Not implementing `interest_group_buyers=*` for now
Chrome's M91 implementation of FLEDGE doesn't include [1] interest_group_buyers=*
; the interaction of "allow all buyers" and "byos 'trusted' server" isn't great. I think the same reasoning applies to the shim, and we should require sellers to explicitly list what buyers they want to allow to participate.
auctionSignals
Follow-up to #20.
daily_update_url
This won't support any k-anonymity restrictions, and it will only trigger on frame load, not in the background.
Compile-time allowlisting of bidding and scoring logic URLs
Not totally clear on whether this is needed, since if you're vendoring this code and you've got logic that you don't want to open source, you can just put it in your local copy. But if you're using npm then that might be trickier. There are various implications to the different possible API shapes here, so will wait to investigate further until we know what users need.
Optimize worker support code
As of #20, the source code is just included verbatim as a string in the binary, with no minification or anything. This is clearly undesirable. To fix it we're going to have to figure out some Webpack stuff.
Karma auto-reloader breaks Service Worker
So we have to restart the test server every time a change is made.
trustedBiddingSignalsKeys
After #20, we fetch trustedBiddingSignalsUrl
and we run a worklet, but we don't plumb the two together. This needs to be added.
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.