-
Notifications
You must be signed in to change notification settings - Fork 15
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
Harmful APIs test page #78
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
d84aa8e
Fix template
kdzwinel 9d638d5
Add to index
kdzwinel 77e491f
Harmfull APIs test page
kdzwinel 050c9b8
Address feedback - move direct sockets to manual testing, remove raw …
kdzwinel baf03bc
add fledge
kdzwinel c688b25
make results object and displayed results more readable and consistent
kdzwinel 747204b
Merge branch 'main' into konrad/harmful-apis
dharb File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<meta http-equiv="Accept-CH" content="Device-Memory, DPR, Viewport-Width, Downlink, RTT, ECT"> <!-- ask for client hints --> | ||
<title>Harmful APIs Test Page</title> | ||
|
||
<script src='./main.js' defer></script> | ||
<link href='./style.css' rel='stylesheet'></link> | ||
</head> | ||
<body> | ||
<p><a href="../../">[Home]</a> ↣ <strong>[Harmful APIs Test Page]</strong></p> | ||
|
||
<p>This page will test if web APIs that are considered harmful are available in your browser. Only availablity is verified, privacy concerns might have been mitigated.</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>API's for manual testing:</p> | ||
<ul> | ||
<li><a href='https://chromestatus.com/feature/5745285984681984'>signed exchanges</a> - <a href='/reflect-headers'>click</a> and look for 'application/signed-exchange' in the 'accept' header</li> | ||
<li><a href='https://chromestatus.com/feature/6398297361088512'>direct/raw sockets</a> - not shipped yet. Once shipped, only available in installed PWA's - look for availability of `TCPSocket` and `UDPSocket` classes.</li> | ||
</ul> | ||
|
||
<p><button id='download' disabled>Download the result</button></p> | ||
|
||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,323 @@ | ||
const PAGE_NAME = 'harmful-apis'; | ||
|
||
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 tests = [ | ||
{ | ||
id: 'battery-api', | ||
run: () => { | ||
return ('getBattery' in navigator); | ||
} | ||
}, | ||
{ | ||
id: 'webbluetooth-api', | ||
run: () => { | ||
return ('bluetooth' in navigator); | ||
} | ||
}, | ||
{ | ||
id: 'webusb-api', | ||
run: () => { | ||
return ('usb' in navigator); | ||
} | ||
}, | ||
{ | ||
id: 'webnfc-api', | ||
run: () => { | ||
return ('NDEFReader' in window); | ||
} | ||
}, | ||
{ | ||
id: 'webserial-api', | ||
run: () => { | ||
return ('serial' in navigator); | ||
} | ||
}, | ||
{ | ||
id: 'webhid-api', | ||
run: () => { | ||
return ('hid' in navigator); | ||
} | ||
}, | ||
{ | ||
id: 'accelerometer-api', | ||
run: () => { | ||
return ('Accelerometer' in window); | ||
} | ||
}, | ||
{ | ||
id: 'linearaccelerationsensor-api', | ||
run: () => { | ||
return ('LinearAccelerationSensor' in window); | ||
} | ||
}, | ||
{ | ||
id: 'absoluteorientationsensor-api', | ||
run: () => { | ||
return ('AbsoluteOrientationSensor' in window); | ||
} | ||
}, | ||
{ | ||
id: 'gyroscope-api', | ||
run: () => { | ||
return ('Gyroscope' in window); | ||
} | ||
}, | ||
{ | ||
id: 'relativeorientationsensor-api', | ||
run: () => { | ||
return ('RelativeOrientationSensor' in window); | ||
} | ||
}, | ||
{ | ||
id: 'gravitysensor-api', | ||
run: () => { | ||
return ('GravitySensor' in window); | ||
} | ||
}, | ||
{ | ||
id: 'ambientlightsensor-api', | ||
run: () => { | ||
return ('AmbientLightSensor' in window); | ||
} | ||
}, | ||
{ | ||
id: 'magnetometer-api', | ||
run: () => { | ||
return ('Magnetometer' in window); | ||
} | ||
}, | ||
{ | ||
id: 'keyboard-api', | ||
run: () => { | ||
return ('keyboard' in navigator); | ||
} | ||
}, | ||
{ | ||
id: 'installed-related-apps-api', | ||
run: () => { | ||
return ('getInstalledRelatedApps' in navigator); | ||
} | ||
}, | ||
{ | ||
id: 'hardwareConcurrency-api', | ||
run: () => { | ||
return ('hardwareConcurrency' in navigator); | ||
} | ||
}, | ||
{ | ||
id: 'deviceMemory-api', | ||
run: () => { | ||
return ('deviceMemory' in navigator); | ||
} | ||
}, | ||
{ | ||
id: 'mediadevices-enumarete-devices-api', | ||
run: () => { | ||
return ('MediaDevices' in window) && ('enumerateDevices' in MediaDevices.prototype); | ||
} | ||
}, | ||
{ | ||
id: 'storage-manager-estimate-api', | ||
run: () => { | ||
return ('StorageManager' in window) && ('estimate' in StorageManager.prototype); | ||
} | ||
}, | ||
{ | ||
id: 'network-information-api', | ||
run: () => { | ||
return ('connection' in navigator); | ||
} | ||
}, | ||
{ | ||
id: 'client-hints-api', | ||
run: () => { | ||
return fetch('/reflect-headers') | ||
.then(r => r.json()) | ||
.then(data => { | ||
const chData = { | ||
'device-memory': data.headers['device-memory'], | ||
downlink: data.headers.downlink, | ||
dpr: data.headers.dpr, | ||
ect: data.headers.ect, | ||
rtt: data.headers.rtt, | ||
'viewport-width': data.headers['viewport-width'] | ||
}; | ||
|
||
if (Object.values(chData).every(i => i === undefined) && !('userAgentData' in navigator)) { | ||
return false; | ||
} | ||
|
||
return true; | ||
}); | ||
} | ||
}, | ||
{ | ||
id: 'topics-api', | ||
run: () => { | ||
return ('browsingTopics' in document); | ||
} | ||
}, | ||
{ | ||
id: 'floc-api', | ||
run: () => { | ||
return ('interestCohort' in document); | ||
} | ||
}, | ||
{ | ||
id: 'idle-detection-api', | ||
run: () => { | ||
return ('IdleDetector' in window); | ||
} | ||
}, | ||
{ | ||
id: 'native-filesystem-api', | ||
run: () => { | ||
return ('showOpenFilePicker' in window); | ||
} | ||
}, | ||
{ | ||
id: 'background-sync-api', | ||
run: () => { | ||
return ('ServiceWorkerRegistration' in window) && ('sync' in ServiceWorkerRegistration.prototype); | ||
} | ||
}, | ||
{ | ||
id: 'periodic-sync-api', | ||
run: () => { | ||
return ('ServiceWorkerRegistration' in window) && ('periodicSync' in ServiceWorkerRegistration.prototype); | ||
} | ||
}, | ||
{ | ||
id: 'push-api', | ||
run: () => { | ||
return ('ServiceWorkerRegistration' in window) && ('pushManager' in ServiceWorkerRegistration.prototype); | ||
} | ||
}, | ||
{ | ||
id: 'first-party-sets-api', | ||
run: () => { | ||
if (!window.cookieStore) { | ||
throw new Error('❌ Can\'t be tested - CookieStore not available'); | ||
} | ||
|
||
return window.cookieStore.set({ name: 'first-party-sets-test', value: 'value' }) | ||
.then(() => window.cookieStore.getAll()) | ||
.then(cookies => { | ||
const cookie = cookies.find(c => c.name === 'first-party-sets-test'); | ||
|
||
return ('sameParty' in cookie); | ||
}); | ||
} | ||
}, | ||
{ | ||
id: 'fledge', | ||
run: () => { | ||
return ('joinAdInterestGroup' in navigator) || ('runAdAuction' in navigator); | ||
} | ||
} | ||
]; | ||
|
||
// object that contains results of all tests | ||
const results = { | ||
page: `${PAGE_NAME}-test`, | ||
date: null, | ||
results: [] | ||
}; | ||
|
||
function resultToHTML (data) { | ||
return ((data === false) ? 'API not available' : '🛑 API available'); | ||
} | ||
|
||
/** | ||
* 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.innerHTML = resultToHTML(data); | ||
resultObj.value = Boolean(data); | ||
}) | ||
.catch(e => { | ||
failed++; | ||
valueSpan.innerHTML = `❌ error thrown ("${e.message ? e.message : e}")`; | ||
kdzwinel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
updateSummary(); | ||
}); | ||
} else { | ||
valueSpan.innerHTML = resultToHTML(result); | ||
resultObj.value = Boolean(result); | ||
} | ||
} catch (e) { | ||
failed++; | ||
valueSpan.innerHTML = `⚠️ error thrown ("${e.message ? e.message : e}")`; | ||
} | ||
|
||
all++; | ||
} | ||
|
||
updateSummary(); | ||
|
||
startButton.removeAttribute('disabled'); | ||
} | ||
|
||
function downloadTheResults () { | ||
kdzwinel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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 = `${PAGE_NAME}-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' | ||
if (document.location.search === '?run') { | ||
runTests(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
* { | ||
box-sizing: border-box; | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When running this test locally using
python -m SimpleHTTPServer 8000
I receive an unhelpful error for this test:client-hints-api - ❌ error thrown ("JSON.parse: unexpected character at line 1 column 1 of the JSON data")
. This happens because the reflect headers endpoint isn't available (running the node server fixes it).I wonder if there's an easy way to warn the user using a test page that the text page requires the node server? We could set up a simple endpoint in the node server, ping it, and display an error in the body of the page if it isn't available. Alternatively we can just update the README to say the node server is always required when testing locally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's a good idea but it'd be nice to do this for all pages affected somehow. I'm putting it on a backlog for now.