241 lines
8.1 KiB
JavaScript
241 lines
8.1 KiB
JavaScript
// META: script=/resources/testdriver.js
|
|
// META: script=/resources/testdriver-vendor.js
|
|
// META: script=/common/get-host-info.sub.js
|
|
// META: script=/common/utils.js
|
|
// META: script=resources/ba-fledge-util.sub.js
|
|
// META: script=resources/fledge-util.sub.js
|
|
// META: script=third_party/cbor-js/cbor.js
|
|
// META: script=/common/subset-tests.js
|
|
// META: timeout=long
|
|
// META: variant=?1-6
|
|
// META: variant=?7-last
|
|
|
|
"use strict";
|
|
|
|
// These tests focus on the paggResponse field in AuctionConfig's
|
|
// serverResponse, i.e. auctions involving private aggregation reporting. NOTE:
|
|
// Due to debug mode being disabled for B&A's Private Aggregation reports, these
|
|
// tests just exercise the code paths and ensure that correct number of reports
|
|
// are sent -- they don't otherwise verify report content.
|
|
|
|
// To better isolate from private aggregation tests run in parallel,
|
|
// don't use the usual origin here.
|
|
const MAIN_ORIGIN = OTHER_ORIGIN1;
|
|
const MAIN_PATH = '/.well-known/private-aggregation/report-protected-audience';
|
|
|
|
const BUCKET_ONE = new Uint8Array([
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x01
|
|
]);
|
|
|
|
function BigEndianInteger128ToUint8Array(val) {
|
|
let buffer = new Uint8Array(16);
|
|
for (let i = 15; i >= 0; i--) {
|
|
buffer[i] = Number(val & 0xFFn);
|
|
val >>= 8n;
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
function createSimplePerOriginPAggResponse(
|
|
reportingOrigin = MAIN_ORIGIN, igIndex = 0, event = 'reserved.win',
|
|
bucket = BUCKET_ONE, value = 10, filteringId = null) {
|
|
let contribution = {};
|
|
if (bucket !== null) {
|
|
contribution.bucket = bucket;
|
|
}
|
|
if (value !== null) {
|
|
contribution.value = value;
|
|
}
|
|
if (filteringId !== null) {
|
|
contribution.filteringId = filteringId;
|
|
}
|
|
return {
|
|
'reportingOrigin': reportingOrigin,
|
|
'igContributions': [{
|
|
'igIndex': igIndex,
|
|
'eventContributions': [{'event': event, 'contributions': [contribution]}]
|
|
}]
|
|
};
|
|
}
|
|
|
|
async function privateAggregationTestWithMutatedServerResponse(
|
|
test, expectWin, paggResponse, timeout = 5000 /*ms*/,
|
|
ownerOverride = null) {
|
|
await resetReports(MAIN_ORIGIN + MAIN_PATH);
|
|
let result = await BA.testWithMutatedServerResponse(
|
|
test, expectWin,
|
|
(msg, uuid) => {
|
|
msg.paggResponse = paggResponse;
|
|
},
|
|
(ig, uuid) => {
|
|
ig.ads[0].renderURL = createRenderURL(uuid);
|
|
},
|
|
ownerOverride);
|
|
createAndNavigateFencedFrame(test, result);
|
|
const reports = await pollReports(MAIN_PATH, timeout);
|
|
return reports;
|
|
}
|
|
|
|
async function testInvalidPAggResponseFields(
|
|
test, reportingOrigin = MAIN_ORIGIN, igIndex = 0, event = 'reserved.win',
|
|
bucket = '1', value = 10, filteringId = null) {
|
|
const paggResponse = [createSimplePerOriginPAggResponse(
|
|
reportingOrigin, igIndex, event, bucket, value, filteringId)];
|
|
|
|
let reports = await privateAggregationTestWithMutatedServerResponse(
|
|
test,
|
|
/*expectWin=*/ true, paggResponse, /*timeout=*/ 5000, MAIN_ORIGIN);
|
|
assert_equals(reports, null);
|
|
}
|
|
|
|
// The next few methods are modified from Chrome-specific
|
|
// wpt_internal/private-aggregation/resources/utils.js
|
|
|
|
const resetReports = url => {
|
|
url = `${url}?clear_stash=true`;
|
|
const options = {
|
|
method: 'POST',
|
|
mode: 'no-cors',
|
|
};
|
|
return fetch(url, options);
|
|
};
|
|
|
|
const delay = ms => new Promise(resolve => step_timeout(resolve, ms));
|
|
|
|
async function pollReports(path, wait_for = 1, timeout = 5000 /*ms*/) {
|
|
const targetUrl = new URL(path, MAIN_ORIGIN);
|
|
const endTime = performance.now() + timeout;
|
|
const outReports = [];
|
|
|
|
do {
|
|
const response = await fetch(targetUrl);
|
|
assert_true(response.ok, 'pollReports() fetch response should be OK.');
|
|
const reports = await response.json();
|
|
outReports.push(...reports);
|
|
if (outReports.length >= wait_for) {
|
|
break;
|
|
}
|
|
await delay(/*ms=*/ 100);
|
|
} while (performance.now() < endTime);
|
|
|
|
return outReports.length ? outReports : null;
|
|
};
|
|
|
|
/**
|
|
* Verifies that a report's aggregation_service_payloads has the expected
|
|
* fields. Currently for B&A's PAgg reports, debug mode is disabled, so we
|
|
* cannot check contributions in payload.
|
|
*/
|
|
const verifyAggregationServicePayloads = (aggregation_service_payloads) => {
|
|
assert_equals(aggregation_service_payloads.length, 1);
|
|
const payload_obj = aggregation_service_payloads[0];
|
|
|
|
assert_own_property(payload_obj, 'key_id');
|
|
assert_own_property(payload_obj, 'payload');
|
|
// Check the payload is base64 encoded. We do not decrypt the payload to
|
|
// test its contents.
|
|
atob(payload_obj.payload);
|
|
|
|
// Check there are no extra keys
|
|
assert_equals(Object.keys(payload_obj).length, expected_payload ? 3 : 2);
|
|
};
|
|
|
|
/**
|
|
* Verifies that a report has the expected fields. The `expected_payload` should
|
|
* be undefined.
|
|
*/
|
|
const verifyReport = (report, reporting_origin) => {
|
|
assert_own_property(report, 'shared_info');
|
|
let shared_info = JSON.parse(report.shared_info);
|
|
assert_own_property(shared_info, 'reporting_origin');
|
|
assert_equals(shared_info.reporting_origin, reporting_origin);
|
|
assert_own_property(report, 'aggregation_service_payloads');
|
|
assert_own_property(report, 'aggregation_coordinator_origin');
|
|
// TODO(qingxinwu): Maybe add tests for coordinator origin.
|
|
|
|
assert_not_own_property(report, 'debug_key');
|
|
|
|
// Check there are no extra keys
|
|
let expected_length = 3;
|
|
assert_equals(Object.keys(report).length, expected_length);
|
|
};
|
|
|
|
subsetTest(promise_test, async test => {
|
|
await testInvalidPAggResponseFields(test, 'http://non-https.com');
|
|
}, 'Private aggregation - invalid reporting origin');
|
|
|
|
subsetTest(
|
|
promise_test,
|
|
async test => {await testInvalidPAggResponseFields(test, MAIN_ORIGIN, 100)},
|
|
'Private aggregation - invalid index');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
await testInvalidPAggResponseFields(
|
|
test, MAIN_ORIGIN, 0, 'reserved.not-supported');
|
|
}, 'Private aggregation - invalid event');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
await testInvalidPAggResponseFields(
|
|
test, MAIN_ORIGIN, 0, 'reserved.win', /*bucket=*/ null);
|
|
}, 'Private aggregation - missing required bucket');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
await testInvalidPAggResponseFields(
|
|
test, MAIN_ORIGIN, 0, 'reserved.win', new Uint8Array([
|
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x01
|
|
]));
|
|
}, 'Private aggregation - bucket is bigger than 128 bits');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
await testInvalidPAggResponseFields(
|
|
test, MAIN_ORIGIN, 0, 'reserved.win', BUCKET_ONE, /*value=*/ null);
|
|
}, 'Private aggregation - missing required value');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
await testInvalidPAggResponseFields(
|
|
test, MAIN_ORIGIN, 0, 'reserved.win', BUCKET_ONE, 10, 10000);
|
|
}, 'Private aggregation - invalid filteringId');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const paggResponse = [createSimplePerOriginPAggResponse()];
|
|
|
|
let reports = await privateAggregationTestWithMutatedServerResponse(
|
|
test,
|
|
/*expectWin=*/ true, paggResponse, /*timeout=*/ 6000, MAIN_ORIGIN);
|
|
assert_equals(reports.length, 1);
|
|
let report = JSON.parse(reports[0]);
|
|
verifyReport(report, MAIN_ORIGIN);
|
|
}, 'Private aggregation - successfully sent report');
|
|
|
|
// TODO(qingxinwu): may add a test for custom event type if possible.
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const paggResponse = [{
|
|
'reportingOrigin': MAIN_ORIGIN,
|
|
'igContributions': [{
|
|
'igIndex': 0,
|
|
'eventContributions': [
|
|
{
|
|
'event': 'reserved.win',
|
|
'contributions': [{'value': 10}, {'bucket': BUCKET_ONE, 'value': 11}]
|
|
},
|
|
{
|
|
'event': 'reserved.not-supported',
|
|
'contributions':
|
|
[{'bucket': BigEndianInteger128ToUint8Array(2n), 'value': 22}]
|
|
},
|
|
]
|
|
}]
|
|
}];
|
|
|
|
let reports = await privateAggregationTestWithMutatedServerResponse(
|
|
test,
|
|
/*expectWin=*/ true, paggResponse, /*timeout=*/ 6000, MAIN_ORIGIN);
|
|
assert_equals(reports.length, 1);
|
|
let report = JSON.parse(reports[0]);
|
|
verifyReport(report, MAIN_ORIGIN);
|
|
}, 'Private aggregation - invalid contributions do not affect valid ones');
|
|
|
|
// TODO(qingxinwu): privateAggregation multi-seller.
|