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

Add AMP loop protection page #182

Merged
merged 1 commit into from
Feb 13, 2024
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
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ <h2>Privacy Protections Tests</h2>
<li><a href='./privacy-protections/surrogates/'>Surrogates</a></li>
<li><a href='./privacy-protections/gpc/'>Global Privacy Control</a></li>
<li><a href='./privacy-protections/amp/'>AMP Links</a></li>
<li><a href='./privacy-protections/amp-loop-protection/'>AMP Loop Protection</a></li>
<li><a href='./privacy-protections/query-parameters/'>Query Parameters</a></li>
<li><a href='./content-scope-scripts/runtime-checks/'>Runtime checks</a></li>
</ul>
Expand Down
58 changes: 58 additions & 0 deletions privacy-protections/amp-loop-protection/amp-only.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AMP loop protection</title>
</head>
<body>
<h1 id="param-display"></h1>
<script>
const MAX = 15;
const LS_ITEM_KEY = 'amp-loop-protection-attempt';
const newUrl = new URL(location.href);
const isStart = newUrl.searchParams.has('start');

if (isStart) {
localStorage[LS_ITEM_KEY] = 0;
}
const attempt = Number.parseInt(localStorage[LS_ITEM_KEY], 10) || 0;
localStorage[LS_ITEM_KEY] = attempt + 1;

document.getElementById('param-display').innerText = `${newUrl.searchParams}`;
document.body.innerHTML += `<p>Attempt ${attempt + 1}/${MAX}</p>`;

// set amp attr, count attempts
const params = new URLSearchParams(location.search);
if (params.get('amp') === '1') {
document.documentElement.setAttribute('amp', '');
const link = document.createElement('link');
link.setAttribute('rel', 'canonical');
const ampUrl = new URL('http://good.third-party.site/privacy-protections/amp-loop-protection/amp-only.html');
if (isStart) {
ampUrl.searchParams.set('start', '1');
}
link.setAttribute('href', ampUrl.href);
document.head.appendChild(link);

localStorage.removeItem(LS_ITEM_KEY);
const onMessage = msg => {
if (msg.data.action && msg.data.action === 'url') {
if (window.opener) {
window.opener.postMessage({ url: document.location.href, type: msg.data.type }, '*');
} else if (window.parent) {
window.parent.postMessage({ url: document.location.href, type: msg.data.type }, '*');
}
}
};

window.addEventListener('message', onMessage);
} else if (attempt < MAX) {
newUrl.searchParams.set('amp', 1);
newUrl.pathname = newUrl.pathname
location.href = newUrl.href;
}
</script>
</body>
</html>
28 changes: 28 additions & 0 deletions privacy-protections/amp-loop-protection/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AMP loop protection</title>

<script src='./main.js' defer></script>
<link href='./style.css' rel='stylesheet'></link>
</head>
<body>
<p><a href="../../">[Home]</a> ↣ <a href="../">[Privacy Protections Tests]</a> ↣ <strong>[AMP Upgrade Loop Protection]</strong></p>

<p>This test will navigate to a non-AMP page that immediately redirects to its AMP version. This will cause a non-AMP↔AMP loop (client trying to get real page, page redirecting). Clients should detect this scenario and allow the AMP page to load.</p>
<p>If the loop protection works the reported url will have the amp=1 parameter.</p>

<p><button id='start'>Start test</button></p>

<details id='tests' hidden>
<summary id='tests-summary'></summary>
<ul id='tests-details'>
</ul>
</details>

<p><button id='download' disabled>Download the result</button></p>

</body>
</html>
142 changes: 142 additions & 0 deletions privacy-protections/amp-loop-protection/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
const startButton = document.querySelector('#start');
const downloadButton = document.querySelector('#download');

const testsDiv = document.querySelector('#tests');
const testsSummaryDiv = document.querySelector('#tests-summary');
const testsDetailsDiv = document.querySelector('#tests-details');

const TEST_DOMAIN = 'good.third-party.site';

const tests = [
{
id: 'rewrite-amp',
run: () => {
let res;
const promise = new Promise((resolve, reject) => { res = resolve; });
const otherWindow = window.open(`http://${TEST_DOMAIN}/privacy-protections/amp-loop-protection/amp-only.html?amp=1&start`);

const interval = setInterval(() => {
otherWindow.postMessage({ action: 'url', type: 'navigation' }, `http://${TEST_DOMAIN}/`);
}, 500);

function onMessage (m) {
if (m.data && m.data.type === 'navigation') {
clearInterval(interval);
otherWindow.close();
window.removeEventListener('message', onMessage);
console.log('navigation', m.data.url);
res(m.data.url);
}
}

window.addEventListener('message', onMessage);

return promise;
}
}
];

// object that contains results of all tests
const results = {
page: 'amp-loop-protection',
date: null,
results: []
};

function resultToHTML (data) {
if (Array.isArray(data)) {
return `<ul>${data.map(r => `<li>${r.test} - ${r.result}</li>`).join('')}</ul>`;
} else if (data) {
return JSON.stringify(data, null, 2);
}

return null;
}

/**
* Test runner
*/
function runTests () {
startButton.setAttribute('disabled', 'disabled');
downloadButton.removeAttribute('disabled');
testsDiv.removeAttribute('hidden');

results.results.length = 0;
results.date = (new Date()).toUTCString();
let all = 0;
let failed = 0;

testsDetailsDiv.innerHTML = '';

function updateSummary () {
testsSummaryDiv.innerText = `Performed ${all} tests${failed > 0 ? ` (${failed} failed)` : ''}. Click for details.`;
}

for (const test of tests) {
const resultObj = {
id: test.id,
value: null
};
results.results.push(resultObj);

const li = document.createElement('li');
li.id = `test-${test.id.replace(' ', '-')}`;
li.innerHTML = `${test.id} - <span class='value'>…</span>`;
const valueSpan = li.querySelector('.value');

testsDetailsDiv.appendChild(li);

try {
const result = test.run();

if (result instanceof Promise) {
result
.then(data => {
valueSpan.textContent = resultToHTML(data);
resultObj.value = data || null;
})
.catch(e => {
failed++;
valueSpan.innerHTML = `❌ error thrown ("${e.message ? e.message : e}")`;
updateSummary();
});
} else {
valueSpan.innerHTML = resultToHTML(result);
resultObj.value = result || null;
}
} catch (e) {
failed++;
valueSpan.innerHTML = `❌ error thrown ("${e.message ? e.message : e}")`;
}

all++;
}

updateSummary();

startButton.removeAttribute('disabled');
}

function downloadTheResults () {
const data = JSON.stringify(results, null, 2);
const a = document.createElement('a');
const url = window.URL.createObjectURL(new Blob([data], { type: 'application/json' }));
a.href = url;
a.download = 'amp-loop-protection-results.json';

document.body.appendChild(a);
a.click();

window.URL.revokeObjectURL(url);
a.remove();
}

downloadButton.addEventListener('click', () => downloadTheResults());

// run tests if button was clicked or…
startButton.addEventListener('click', () => runTests());

// if url query is '?run' start tests imadiatelly
if (document.location.search === '?run') {
runTests();
}
7 changes: 7 additions & 0 deletions privacy-protections/amp-loop-protection/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
* {
box-sizing: border-box;
}

.value {
color: gray;
}
1 change: 1 addition & 0 deletions privacy-protections/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ <h1>Privacy Protections Tests</h1>
<li><a href='./surrogates/'>Surrogates</a></li>
<li><a href='./gpc/'>Global Privacy Control</a></li>
<li><a href='./amp/'>AMP Links</a></li>
<li><a href='./amp-loop-protection/'>AMP Loop Protection</a></li>
<li><a href='./query-parameters/'>Query Parameters</a></li>
</ul>

Expand Down
Loading