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

Couple of changes to the surrogates page. #58

Merged
merged 4 commits into from
Sep 27, 2021
Merged
Show file tree
Hide file tree
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
24 changes: 24 additions & 0 deletions privacy-protections/surrogates/frame.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Tracker surrogates</title>

<script src='https://google-analytics.com/analytics.js' defer></script>
<script>
const onMessage = msg => {
if (msg.data.action && msg.data.action === 'surrogate') {
window.parent.postMessage({
surrogate: (window.ga && window.ga.name !== 'N' && window.ga.answer === 42)
Copy link
Member Author

Choose a reason for hiding this comment

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

checks if surrogate has loaded and reports back to the main frame.

}, '*');
}
};

window.addEventListener('message', onMessage);
</script>
</style>
</head>
<body>
</body>
</html>
4 changes: 2 additions & 2 deletions privacy-protections/surrogates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
</head>
<p><a href="../../">[Home]</a> ↣ <a href="../">[Privacy Protections Tests]</a> ↣ <strong>[Surrogates Test Page]</strong></p>

<p><b>Test blocking and redirecting to a surrogate</b></p>
<p>This page tests if surrogate script for google-analytics.com/analytics.js is being loaded. This page expects <a href='https://github.com/duckduckgo/tracker-surrogates/blob/main/surrogates/analytics.js'>specific surrogate</a> to be loaded.</p>
<table id='results-table'>
<tr><th>Surrogate</th><th>Loaded</th><th>Passed Test</th><th>Notes</th></tr>
<tr><th>Description</th><th>Loaded</th></tr>
</table>
</body>
<script src='./main.js'></script>
Expand Down
184 changes: 112 additions & 72 deletions privacy-protections/surrogates/main.js
Original file line number Diff line number Diff line change
@@ -1,108 +1,148 @@
const results = {};
const results = {
page: 'surrogates',
date: (new Date()).toUTCString(),
results: []
};

function updateTable ({ name, testData, error }) {
const table = document.getElementById('results-table');
const row = table.insertRow(-1);
const testName = row.insertCell(0);
const loaded = row.insertCell(1);
const passed = row.insertCell(2);
const note = row.insertCell(3);

// set default values and colors
testName.innerText = name;
loaded.innerText = 'failed';
passed.innerText = 'failed';
row.style.backgroundColor = '#f97268';
note.style.backgroundColor = '#ffff';

results[name] = { pass: true };
const descriptionCell = row.insertCell(0);
const testCell = row.insertCell(1);

let testPassed = true;

if (!error && testData.shouldFail) {
testPassed = false;
}

if (testPassed) {
loaded.innerText = 'pass';

const result = testData.test();
if (result) {
passed.innerText = 'pass';
row.style.backgroundColor = '#71bf69';
// set default values and colors
descriptionCell.innerText = testData.notes;
testCell.innerText = 'request failed';
testCell.style.backgroundColor = '#f97268';

const result = {
id: name,
loaded: false
};

if (!error) {
const testResult = testData.test();

if (testResult) {
result.loaded = true;
testCell.innerText = 'surrogate loaded';
testCell.style.backgroundColor = '#71bf69';
} else {
results[name].pass = false;
loaded.innerText = 'failed';
testCell.innerText = 'surrogate not loaded';
}
}

if (testData.notes) {
results[name].notes = testData.notes;
note.innerText = testData.notes;
}

if (testData.cleanUp) {
testData.cleanUp();
}

results.results.push(result);
}

function checkSurrogate () {
if (window.ga && window.ga.name !== 'N' && window.ga.answer === 42) {
Copy link
Member Author

Choose a reason for hiding this comment

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

this is a simple way of detecting our surrogate

return true;
}

return false;
}

const surrogates = {
'google-analytics.com/analytics.js, crossOrigin': {
'main-frame': {
url: 'https://google-analytics.com/analytics.js',
crossOrigin: 'anonymous',
notes: 'Test loading with crossOrigin set on element (should fail on Firefox) https://bugzilla.mozilla.org/show_bug.cgi?id=1694679',
shouldFail: false,
test: () => { return !!(window.ga && Object.keys(window.ga.create()).length === 0); },
notes: 'Loading surrogate in the main frame.',
test: checkSurrogate,
cleanUp: () => { delete window.ga; }
},
'google-analytics.com/analytics.js broken integrity': {
'cross-origin': {
url: 'https://google-analytics.com/analytics.js',
crossOrigin: 'anonymous',
integrity: 'sha512-1xNTXD/ZeaKg/Xjb6De9la7CXo5gC1lMk+beyKo691KJrjlj0HbZG6frzK0Wo6bm96i9Cp6w/WB4vSN/8zDBLQ==',
notes: 'Surrogate will fail to load due to integrity check. We think this check should not apply to extensions.',
shouldFail: false,
test: () => { return !!(window.ga && Object.keys(window.ga.create()).length === 0); },
notes: 'Loading surrogate with crossOrigin=anonymous set.',
test: checkSurrogate,
cleanUp: () => { delete window.ga; }
},
'google-analytics.com/analytics.js': {
'integrity-check': {
url: 'https://google-analytics.com/analytics.js',
shouldFail: false,
test: () => { return !!(window.ga && Object.keys(window.ga.create()).length === 0); },
crossOrigin: 'anonymous',
integrity: 'sha512-1xNTXD/ZeaKg/Xjb6De9la7CXo5gC1lMk+beyKo691KJrjlj0HbZG6frzK0Wo6bm96i9Cp6w/WB4vSN/8zDBLQ==',
notes: 'Loading surrogate with integrity=sha512-… set.',
test: checkSurrogate,
cleanUp: () => { delete window.ga; }
},
'Directly accessing a web resouce': {
'direct-access': {
url: 'chrome-extension://bkdgflcldnnnapblkhphbgpggdiikppg/web_accessible_resources/analytics.js',
notes: 'Chromium browsers Only: need access key for web resources',
shouldFail: true,
notes: 'Chromium only - it should not be possible to access local surrogate file',
test: () => { return true; }
},
'sub-frame': {
notes: 'Loading surrogate in an iframe.',
load: () => {
const url = './frame.html';
let res;
const promise = new Promise((resolve, reject) => { res = resolve; });

const origin = (new URL(url, document.location.href)).origin;

const iframe = document.createElement('iframe');
iframe.src = url;
iframe.style.width = '10px';
iframe.style.height = '10px';

const onMessage = msg => {
// check message and if it's comming from the right origin
if (msg.data.surrogate && msg.origin === origin) {
res(msg.data.surrogate);
window.removeEventListener('message', onMessage);
document.body.removeChild(iframe);
}
};

window.addEventListener('message', onMessage);

document.body.appendChild(iframe);

iframe.addEventListener('load', () => {
iframe.contentWindow.postMessage({ action: 'surrogate' }, origin);
});

return promise;
}
}
};

(async function loadSurrogates () {
for (const [name, testData] of Object.entries(surrogates)) {
await new Promise((resolve, reject) => {
const s = document.createElement('script');

if (testData.crossOrigin) {
s.crossOrigin = testData.crossOrigin;
}
if (testData.integrity) {
s.integrity = testData.integrity;
}

s.onload = () => {
if (testData.url) {
await new Promise((resolve, reject) => {
const s = document.createElement('script');

if (testData.crossOrigin) {
s.crossOrigin = testData.crossOrigin;
}
if (testData.integrity) {
s.integrity = testData.integrity;
}

s.onload = () => {
updateTable({ name, testData });
resolve();
};

s.onerror = (error) => {
updateTable({ name, testData, error });
resolve();
};

s.src = testData.url;

document.body.appendChild(s);
});
} else {
testData.load().then(result => {
testData.test = () => result;
updateTable({ name, testData });
resolve();
};

s.onerror = (error) => {
updateTable({ name, testData, error });
resolve();
};

s.src = testData.url;

document.body.appendChild(s);
});
});
}
}
})();