Skip to content
Permalink
Browse files
PCM: Request signature for unlinkable token using attributionSourceNonce
https://bugs.webkit.org/show_bug.cgi?id=222076
<rdar://73581651>

Reviewed by Chris Dumez.

Source/WebCore:

Test: http/tests/privateClickMeasurement/store-private-click-measurement-with-source-nonce.html

* html/HTMLAnchorElement.cpp:
(WebCore::HTMLAnchorElement::handleClick):
    Adoption of renamed function PrivateClickMeasurement::attributionReportURL().
* loader/PrivateClickMeasurement.cpp:
(WebCore::PrivateClickMeasurement::tokenSignatureURL const):
(WebCore::PrivateClickMeasurement::tokenSignatureJSON const):
    New functions to facilitate the request for a token signature.
(WebCore::PrivateClickMeasurement::attributionReportURL const):
(WebCore::PrivateClickMeasurement::attributionReportJSON const):
    Renamed functions to make them distinct from their token signing peers.
(WebCore::PrivateClickMeasurement::reportURL const): Deleted.
(WebCore::PrivateClickMeasurement::json const): Deleted.
* loader/PrivateClickMeasurement.h:
(WebCore::PrivateClickMeasurement::encode const):
(WebCore::PrivateClickMeasurement::decode):
(WebCore::PrivateClickMeasurement::EphemeralSourceNonce::encode const):
(WebCore::PrivateClickMeasurement::EphemeralSourceNonce::decode):
    Encode and decode to facilitate transfer over IPC.

Source/WebKit:

This patch makes PrivateClickMeasurementManager::storeUnattributed() look
for incoming source nonces and if found, call the new function
PrivateClickMeasurementManager::getSignedUnlinkableToken().

A new static function generateNetworkResourceLoadParameters() was added
to reuse code between PrivateClickMeasurementManager::getSignedUnlinkableToken()
and the existing PrivateClickMeasurementManager::fireConversionRequest().

To enable testing, there is a new function called
NetworkSession::setPrivateClickMeasurementTokenSignatureURLForTesting() and
function setPrivateClickMeasurementConversionURLForTesting() was renamed
setPrivateClickMeasurementAttributionReportURLForTesting() in NetworkProcess,
NetworkSession, WKPagePrivate, WKWebViewPrivateForTesting, and
PrivateClickMeasurementManager to align with the naming used in other places.

* NetworkProcess/NetworkProcess.cpp:
(WebKit::NetworkProcess::setPrivateClickMeasurementTokenSignatureURLForTesting):
(WebKit::NetworkProcess::setPrivateClickMeasurementAttributionReportURLForTesting):
(WebKit::NetworkProcess::setPrivateClickMeasurementConversionURLForTesting): Deleted.
* NetworkProcess/NetworkProcess.h:
* NetworkProcess/NetworkProcess.messages.in:
* NetworkProcess/NetworkSession.cpp:
(WebKit::NetworkSession::setPrivateClickMeasurementTokenSignatureURLForTesting):
(WebKit::NetworkSession::setPrivateClickMeasurementAttributionReportURLForTesting):
(WebKit::NetworkSession::setPrivateClickMeasurementConversionURLForTesting): Deleted.
* NetworkProcess/NetworkSession.h:
* NetworkProcess/PrivateClickMeasurementManager.cpp:
(WebKit::PrivateClickMeasurementManager::storeUnattributed):
(WebKit::generateNetworkResourceLoadParameters):
(WebKit::PrivateClickMeasurementManager::getSignedUnlinkableToken):
(WebKit::PrivateClickMeasurementManager::fireConversionRequest):
(WebKit::PrivateClickMeasurementManager::setTokenSignatureURLForTesting):
(WebKit::PrivateClickMeasurementManager::setAttributionReportURLForTesting):
(WebKit::PrivateClickMeasurementManager::setConversionURLForTesting): Deleted.
* NetworkProcess/PrivateClickMeasurementManager.h:
* UIProcess/API/C/WKPage.cpp:
(WKPageSetPrivateClickMeasurementTokenSignatureURLForTesting):
(WKPageSetPrivateClickMeasurementAttributionReportURLForTesting):
(WKPageSetPrivateClickMeasurementConversionURLForTesting): Deleted.
* UIProcess/API/C/WKPagePrivate.h:
* UIProcess/API/Cocoa/WKWebViewPrivateForTesting.h:
* UIProcess/API/Cocoa/WKWebViewTesting.mm:
(-[WKWebView _setPrivateClickMeasurementAttributionReportURLForTesting:completionHandler:]):
(-[WKWebView _setPrivateClickMeasurementConversionURLForTesting:completionHandler:]): Deleted.
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::setPrivateClickMeasurementTokenSignatureURLForTesting):
(WebKit::WebPageProxy::setPrivateClickMeasurementAttributionReportURLForTesting):
(WebKit::WebPageProxy::setPrivateClickMeasurementConversionURLForTesting): Deleted.
* UIProcess/WebPageProxy.h:

Tools:

The changes to the TestRunner are:
- Rename setPrivateClickMeasurementConversionURLForTesting() to
setPrivateClickMeasurementAttributionReportURLForTesting() to align with other
naming and make it clear that it does.
- Add the new setPrivateClickMeasurementTokenSignatureURLForTesting() used for
testing the token signing request.

The changes to API tests are to adopt renamed functions in
WebCore::PrivateClickMeasurement:
- reportURL() renamed attributionReportURL().
- json() renamed attributionReportJSON().

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebCore/PrivateClickMeasurement.cpp:
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/WebKitCocoa/EventAttribution.mm:
(TestWebKitAPI::TEST):
* WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
* WebKitTestRunner/InjectedBundle/TestRunner.cpp:
(WTR::TestRunner::setPrivateClickMeasurementTokenSignatureURLForTesting):
(WTR::TestRunner::setPrivateClickMeasurementAttributionReportURLForTesting):
(WTR::TestRunner::setPrivateClickMeasurementConversionURLForTesting): Deleted.
* WebKitTestRunner/InjectedBundle/TestRunner.h:
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::setPrivateClickMeasurementTokenSignatureURLForTesting):
(WTR::TestController::setPrivateClickMeasurementAttributionReportURLForTesting):
(WTR::TestController::setPrivateClickMeasurementConversionURLForTesting): Deleted.
* WebKitTestRunner/TestController.h:
* WebKitTestRunner/TestInvocation.cpp:
(WTR::TestInvocation::didReceiveSynchronousMessageFromInjectedBundle):

LayoutTests:

* http/tests/contentextensions/block-private-click-measurement.html:
    Adoption of renamed TestRunner function setPrivateClickMeasurementAttributionReportURLForTesting().
* http/tests/privateClickMeasurement/conversion-disabled-in-ephemeral-session.html:
    Adoption of renamed TestRunner function setPrivateClickMeasurementAttributionReportURLForTesting().
* http/tests/privateClickMeasurement/expired-attribution-report-gets-sent-on-session-start.html:
    Adoption of renamed TestRunner function setPrivateClickMeasurementAttributionReportURLForTesting().
* http/tests/privateClickMeasurement/resources/getConversionData.php:
    Adoption of renamed TestRunner function setPrivateClickMeasurementAttributionReportURLForTesting().
* http/tests/privateClickMeasurement/resources/getTokenSigningData.php: Added.
* http/tests/privateClickMeasurement/resources/signToken.php: Added.
* http/tests/privateClickMeasurement/resources/tokenSigningFilePath.php: Added.
* http/tests/privateClickMeasurement/resources/util.js:
(tearDownAndFinish):
    Adoption of renamed TestRunner function setPrivateClickMeasurementAttributionReportURLForTesting().
    Now also calls setPrivateClickMeasurementTokenSignatureURLForTesting().
* http/tests/privateClickMeasurement/send-attribution-conversion-request.html:
    Adoption of renamed TestRunner function setPrivateClickMeasurementAttributionReportURLForTesting().
* http/tests/privateClickMeasurement/store-private-click-measurement-with-source-nonce-expected.txt: Added.
* http/tests/privateClickMeasurement/store-private-click-measurement-with-source-nonce.html: Added.


Canonical link: https://commits.webkit.org/234286@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@273088 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
johnwilander committed Feb 18, 2021
1 parent 5ae5c63 commit 729025a632bc862933f028e4c616d85345645165
Showing 40 changed files with 599 additions and 81 deletions.
@@ -1,3 +1,31 @@
2021-02-18 John Wilander <wilander@apple.com>

PCM: Request signature for unlinkable token using attributionSourceNonce
https://bugs.webkit.org/show_bug.cgi?id=222076
<rdar://73581651>

Reviewed by Chris Dumez.

* http/tests/contentextensions/block-private-click-measurement.html:
Adoption of renamed TestRunner function setPrivateClickMeasurementAttributionReportURLForTesting().
* http/tests/privateClickMeasurement/conversion-disabled-in-ephemeral-session.html:
Adoption of renamed TestRunner function setPrivateClickMeasurementAttributionReportURLForTesting().
* http/tests/privateClickMeasurement/expired-attribution-report-gets-sent-on-session-start.html:
Adoption of renamed TestRunner function setPrivateClickMeasurementAttributionReportURLForTesting().
* http/tests/privateClickMeasurement/resources/getConversionData.php:
Adoption of renamed TestRunner function setPrivateClickMeasurementAttributionReportURLForTesting().
* http/tests/privateClickMeasurement/resources/getTokenSigningData.php: Added.
* http/tests/privateClickMeasurement/resources/signToken.php: Added.
* http/tests/privateClickMeasurement/resources/tokenSigningFilePath.php: Added.
* http/tests/privateClickMeasurement/resources/util.js:
(tearDownAndFinish):
Adoption of renamed TestRunner function setPrivateClickMeasurementAttributionReportURLForTesting().
Now also calls setPrivateClickMeasurementTokenSignatureURLForTesting().
* http/tests/privateClickMeasurement/send-attribution-conversion-request.html:
Adoption of renamed TestRunner function setPrivateClickMeasurementAttributionReportURLForTesting().
* http/tests/privateClickMeasurement/store-private-click-measurement-with-source-nonce-expected.txt: Added.
* http/tests/privateClickMeasurement/store-private-click-measurement-with-source-nonce.html: Added.

2021-02-18 Michael Saboff <msaboff@apple.com>

[JSC] Implement RegExp Match Indices proposal
@@ -15,7 +15,7 @@

if (window.testRunner) {
testRunner.setPrivateClickMeasurementOverrideTimerForTesting(true);
testRunner.setPrivateClickMeasurementConversionURLForTesting("http://127.0.0.1:8000/privateClickMeasurement/resources/conversionReport.php");
testRunner.setPrivateClickMeasurementAttributionReportURLForTesting("http://127.0.0.1:8000/privateClickMeasurement/resources/conversionReport.php");
}

function activateElement(elementID) {
@@ -18,7 +18,7 @@
prepareTest();

if (window.testRunner)
testRunner.setPrivateClickMeasurementConversionURLForTesting("http://127.0.0.1:8000/privateClickMeasurement/resources/conversionReport.php?nonce=" + nonce);
testRunner.setPrivateClickMeasurementAttributionReportURLForTesting("http://127.0.0.1:8000/privateClickMeasurement/resources/conversionReport.php?nonce=" + nonce);

function activateElement(elementID) {
var element = document.getElementById(elementID);
@@ -18,7 +18,7 @@
prepareTest();

if (window.testRunner) {
testRunner.setPrivateClickMeasurementConversionURLForTesting("http://127.0.0.1:8000/privateClickMeasurement/resources/conversionReport.php?nonce=" + nonce);
testRunner.setPrivateClickMeasurementAttributionReportURLForTesting("http://127.0.0.1:8000/privateClickMeasurement/resources/conversionReport.php?nonce=" + nonce);
}

function activateElement(elementID) {
@@ -45,7 +45,7 @@
echo "if (window.testRunner) {";
echo " testRunner.notifyDone();";
echo " testRunner.setPrivateClickMeasurementOverrideTimerForTesting(false);";
echo " testRunner.setPrivateClickMeasurementConversionURLForTesting('');";
echo " testRunner.setPrivateClickMeasurementAttributionReportURLForTesting('');";
echo "}";
echo "</script>";
}
@@ -0,0 +1,54 @@
<?php
require_once 'tokenSigningFilePath.php';

$noTimeout = True;
$timeoutMsecs = 0;
if (isset($_GET['timeout_ms'])) {
$noTimeout = False;
$timeoutMsecs = (int) $_GET['timeout_ms'];
}

$tokenSigningFileFound = False;
while ($noTimeout || $timeoutMsecs > 0) {
if (file_exists($tokenSigningFilePath)) {
$tokenSigningFileFound = True;
break;
}
$sleepMsecs = 10;
usleep($sleepMsecs * 1000);
if (!$noTimeout) {
$timeoutMsecs -= $sleepMsecs;
}
// file_exists() caches results, we want to invalidate the cache.
clearstatcache();
}


echo "<html><body>\n";

if ($tokenSigningFileFound) {
echo "Token signing request received.";
$tokenSigningFile = fopen($tokenSigningFilePath, 'r');
while ($line = fgets($tokenSigningFile)) {
echo "<br>";
echo trim($line);
}
echo "<br>";
fclose($tokenSigningFile);
unlink($tokenSigningFilePath);
} else {
echo "Token signing request not received - timed out.<br>";
}

if (isset($_GET['endTest'])) {
echo "<script>";
echo "if (window.testRunner) {";
echo " testRunner.setPrivateClickMeasurementOverrideTimerForTesting(false);";
echo " testRunner.setPrivateClickMeasurementTokenSignatureURLForTesting('');";
echo " testRunner.notifyDone();";
echo "}";
echo "</script>";
}

echo "</body></html>";
?>
@@ -0,0 +1,44 @@
<?php
require_once "tokenSigningFilePath.php";

$tokenSigningFile = fopen($tokenSigningFilePath . ".tmp", 'w');
$httpHeaders = $_SERVER;
$cookiesFound = false;

if ($value = $httpHeaders["HTTP_HOST"]) {
fwrite($tokenSigningFile, "HTTP_HOST: $value\n");
}

if ($value = $httpHeaders["HTTP_COOKIE"]) {
fwrite($tokenSigningFile, "Cookies in token signing request: $value\n");
$cookiesFound = true;
}

if ($value = $httpHeaders["CONTENT_TYPE"]) {
fwrite($tokenSigningFile, "Content type: $value\n");
}

if ($value = $httpHeaders["REQUEST_URI"]) {
$value = $httpHeaders["REQUEST_URI"];
$positionOfDummy = strpos($value, "?dummy=");
if ($positionOfDummy === false)
$outputURL = $value;
else
$outputURL = substr($value, 0, $positionOfDummy);
fwrite($tokenSigningFile, "REQUEST_URI: $outputURL\n");
}

if (!$cookiesFound) {
fwrite($tokenSigningFile, "No cookies in token signing request.\n");
}

$requestBody = file_get_contents("php://input");
fwrite($tokenSigningFile, "Request body:\n$requestBody\n");

fclose($tokenSigningFile);
rename($tokenSigningFilePath . ".tmp", $tokenSigningFilePath);

header("HTTP/1.1 201 Created");
setcookie("cookieSetInTokenSigningResponse", "1", 0, "/");

?>
@@ -0,0 +1,9 @@
<?php
require_once '../../resources/portabilityLayer.php';

if (isset($_GET["dummy"]))
$tokenSigningFileName = "/privateClickMeasurementTokenSigningRequest" . $_GET["dummy"] . ".txt";
else
$tokenSigningFileName = "/privateClickMeasurementTokenSigningRequest.txt";
$tokenSigningFilePath = sys_get_temp_dir() . $tokenSigningFileName;
?>
@@ -11,7 +11,8 @@ function tearDownAndFinish() {
if (window.testRunner) {
testRunner.setAllowsAnySSLCertificate(false);
testRunner.setPrivateClickMeasurementOverrideTimerForTesting(false);
testRunner.setPrivateClickMeasurementConversionURLForTesting("");
testRunner.setPrivateClickMeasurementAttributionReportURLForTesting("");
testRunner.setPrivateClickMeasurementTokenSignatureURLForTesting("");
testRunner.notifyDone();
}
}
@@ -19,7 +19,6 @@

if (window.testRunner) {
testRunner.setPrivateClickMeasurementOverrideTimerForTesting(true);
testRunner.setPrivateClickMeasurementConversionURLForTesting("http://127.0.0.1:8000/privateClickMeasurement/resources/conversionReport.php?nonce=" + nonce);
}

function activateElement(elementID) {
@@ -60,6 +59,7 @@
function runTest() {
if (window.testRunner) {
if (window.location.search === "?stepTwo") {
testRunner.setPrivateClickMeasurementAttributionReportURLForTesting("http://127.0.0.1:8000/privateClickMeasurement/resources/conversionReport.php?nonce=" + nonce);
let imageElement = document.createElement("img");
imageElement.src = "https://127.0.0.1:8443/privateClickMeasurement/resources/redirectToConversion.php?conversionData=12&nonce=" + nonce;
imageElement.id = "pixel";
@@ -0,0 +1,21 @@
Tests that the presence of a source nonce triggers a token signing request.



--------
Frame: '<!--frame1-->'
--------
Token signing request received.
HTTP_HOST: 127.0.0.1:8000
Content type: application/json
REQUEST_URI: /privateClickMeasurement/resources/signToken.php
No cookies in token signing request.
Request body:
{"source_engagement_type":"click","source_nonce":"ABCDEFabcdef0123456789","unlinkable_token":"TODO","version":2}

Unattributed Private Click Measurements:
WebCore::PrivateClickMeasurement 1
Source site: 127.0.0.1
Attribute on site: localhost
Source ID: 3
No attribution trigger data.
@@ -0,0 +1,66 @@
<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true PrivateClickMeasurementFraudPreventionEnabled=true ] -->
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<script src="/js-test-resources/ui-helper.js"></script>
<script src="resources/util.js"></script>
</head>
<body onload="setTimeout(runTest, 0)">
<div id="description">Tests that the presence of a source nonce triggers a token signing request.</div>
<a id="targetLink" attributionsourceid="3" attributeon="http://localhost:8000" attributionsourcenonce="ABCDEFabcdef0123456789">Link</a><br>
<div id="output"></div>
<script>
if (!window.location.search)
prepareTest();

function activateElement(elementID) {
var element = document.getElementById(elementID);
var centerX = element.offsetLeft + element.offsetWidth / 2;
var centerY = element.offsetTop + element.offsetHeight / 2;
UIHelper.activateAt(centerX, centerY).then(
function () {
},
function () {
document.getElementById("output").innerText = "FAIL Promise rejected.";
tearDownAndFinish();
}
);
}

function appendIframe(url, onloadCallback) {
let iframeElement = document.createElement("iframe");
iframeElement.src = url;
if (onloadCallback)
iframeElement.onload = onloadCallback;
document.body.appendChild(iframeElement);
}

function appendTokenSignatureIframeAndFinish(dummy) {
appendIframe("http://127.0.0.1:8000/privateClickMeasurement/resources/getTokenSigningData.php?timeout_ms=4000&dummy=" + dummy, function() {
testRunner.dumpPrivateClickMeasurement();
document.body.removeChild(document.getElementById("targetLink"));
tearDownAndFinish();
});
}

function runTest() {
if (window.testRunner) {
if (!window.location.search) {
const currentTimeMillis = (new Date()).getTime();
const highEntropyBits = currentTimeMillis - (Math.floor(currentTimeMillis / 1000000) * 1000000);
const dummy = highEntropyBits + "" + Math.floor(Math.random() * 100);
testRunner.setPrivateClickMeasurementTokenSignatureURLForTesting("http://127.0.0.1:8000/privateClickMeasurement/resources/signToken.php?dummy=" + dummy);
targetLink.href = "http://localhost:8000/privateClickMeasurement/store-private-click-measurement-with-source-nonce.html?dummy=" + dummy;
activateElement("targetLink");
} else {
let params = new URLSearchParams(window.location.search);
appendTokenSignatureIframeAndFinish(params.get("dummy"));
}
} else {
document.getElementById("output").innerText = "FAIL No testRunner.";
}
}
</script>
</body>
</html>
@@ -1,3 +1,32 @@
2021-02-18 John Wilander <wilander@apple.com>

PCM: Request signature for unlinkable token using attributionSourceNonce
https://bugs.webkit.org/show_bug.cgi?id=222076
<rdar://73581651>

Reviewed by Chris Dumez.

Test: http/tests/privateClickMeasurement/store-private-click-measurement-with-source-nonce.html

* html/HTMLAnchorElement.cpp:
(WebCore::HTMLAnchorElement::handleClick):
Adoption of renamed function PrivateClickMeasurement::attributionReportURL().
* loader/PrivateClickMeasurement.cpp:
(WebCore::PrivateClickMeasurement::tokenSignatureURL const):
(WebCore::PrivateClickMeasurement::tokenSignatureJSON const):
New functions to facilitate the request for a token signature.
(WebCore::PrivateClickMeasurement::attributionReportURL const):
(WebCore::PrivateClickMeasurement::attributionReportJSON const):
Renamed functions to make them distinct from their token signing peers.
(WebCore::PrivateClickMeasurement::reportURL const): Deleted.
(WebCore::PrivateClickMeasurement::json const): Deleted.
* loader/PrivateClickMeasurement.h:
(WebCore::PrivateClickMeasurement::encode const):
(WebCore::PrivateClickMeasurement::decode):
(WebCore::PrivateClickMeasurement::EphemeralSourceNonce::encode const):
(WebCore::PrivateClickMeasurement::EphemeralSourceNonce::decode):
Encode and decode to facilitate transfer over IPC.

2021-02-18 Michael Catanzaro <mcatanzaro@gnome.org>

[GTK] Remove all Google user agent quirks except for Google Docs
@@ -527,7 +527,7 @@ void HTMLAnchorElement::handleClick(Event& event)
auto privateClickMeasurement = parsePrivateClickMeasurement();
// A matching conversion event needs to happen before the complete private click measurement
// URL can be created. Thus, it should be empty for now.
ASSERT(!privateClickMeasurement || privateClickMeasurement->reportURL().isNull());
ASSERT(!privateClickMeasurement || privateClickMeasurement->attributionReportURL().isNull());

frame->loader().changeLocation(completedURL, effectiveTarget, &event, referrerPolicy, document().shouldOpenExternalURLsPolicyToPropagate(), newFrameOpenerPolicy, downloadAttribute, systemPreviewInfo, WTFMove(privateClickMeasurement));

@@ -37,6 +37,7 @@
namespace WebCore {

static const char privateClickMeasurementTriggerAttributionPath[] = "/.well-known/private-click-measurement/trigger-attribution/";
static const char privateClickMeasurementTokenSignaturePath[] = "/.well-known/private-click-measurement/sign-unlinkable-token/";
static const char privateClickMeasurementReportAttributionPath[] = "/.well-known/private-click-measurement/report-attribution/";
const size_t privateClickMeasurementAttributionTriggerDataPathSegmentSize = 2;
const size_t privateClickMeasurementPriorityPathSegmentSize = 2;
@@ -114,7 +115,37 @@ bool PrivateClickMeasurement::hasHigherPriorityThan(const PrivateClickMeasuremen
return m_attributionTriggerData->priority > other.m_attributionTriggerData->priority;
}

URL PrivateClickMeasurement::reportURL() const
URL PrivateClickMeasurement::tokenSignatureURL() const
{
if (!m_ephemeralSourceNonce || !m_ephemeralSourceNonce->isValid())
return URL();

StringBuilder builder;
builder.appendLiteral("https://");
builder.append(m_sourceSite.registrableDomain.string());
builder.appendLiteral(privateClickMeasurementTokenSignaturePath);

URL url { URL(), builder.toString() };
if (url.isValid())
return url;

return URL();
}

Ref<JSON::Object> PrivateClickMeasurement::tokenSignatureJSON() const
{
auto reportDetails = JSON::Object::create();
if (!m_ephemeralSourceNonce || !m_ephemeralSourceNonce->isValid())
return reportDetails;

reportDetails->setString("source_engagement_type"_s, "click"_s);
reportDetails->setString("source_nonce"_s, m_ephemeralSourceNonce->nonce);
reportDetails->setString("unlinkable_token"_s, "TODO"_s);
reportDetails->setInteger("version"_s, 2);
return reportDetails;
}

URL PrivateClickMeasurement::attributionReportURL() const
{
if (!isValid())
return URL();
@@ -131,7 +162,7 @@ URL PrivateClickMeasurement::reportURL() const
return URL();
}

Ref<JSON::Object> PrivateClickMeasurement::json() const
Ref<JSON::Object> PrivateClickMeasurement::attributionReportJSON() const
{
auto reportDetails = JSON::Object::create();
if (!m_attributionTriggerData || !isValid())

0 comments on commit 729025a

Please sign in to comment.