@@ -38,7 +38,7 @@ const fetchAndParse = async (url, parser) => {
3838
3939 try {
4040 const response = await fetch ( url , { signal } ) ;
41- return parser ( response ) ;
41+ return parser ( url , await response ) ;
4242 } catch ( error ) {
4343 return {
4444 status : - 1 ,
@@ -48,28 +48,20 @@ const fetchAndParse = async (url, parser) => {
4848 }
4949} ;
5050
51- /**
52- * Checks if the response URL ends with any of the specified endings and if the response is OK.
53- * @param {Response } response - The fetch response object.
54- * @param {string[] } endings - An array of URL endings to check against.
55- * @returns {boolean } - Returns true if the response is OK and the URL ends with one of the specified endings.
56- */
57- const isPresent = ( response , endings ) => response . ok && endings . some ( ending => response . url . endsWith ( ending ) ) ;
58-
5951/**
6052 * Parses the response from a DSR delete request.
6153 * @param {Response } response - The response object from the fetch request.
6254 * @returns {Promise<Object> } A promise that resolves to an object containing the parsed response data.
6355 */
64- const parseDSRdelete = async ( response ) => {
56+ const parseDSRdelete = ( url , response ) => {
6557 let result = {
66- present : isPresent ( response , [ '/dsrdelete. json'] ) ,
58+ present : response . ok && response . url . endsWith ( url ) && response . headers . get ( 'content-type' ) === 'application/ json',
6759 status : response . status ,
6860 } ;
6961 Object . assign ( result , result . present ? { redirected : response . redirected } : { } ) ;
7062
7163 try {
72- let content = JSON . parse ( await response . text ( ) ) ;
64+ let content = JSON . parse ( response . text ( ) ) ;
7365 if ( result . present && content ) {
7466 for ( const element of content . identifiers ) {
7567 delete element . id ;
@@ -83,94 +75,10 @@ const parseDSRdelete = async (response) => {
8375 Object . assign ( result , result . present ? { error : error . message } : { } ) ;
8476 }
8577
86- return Promise . resolve ( result ) ;
78+ return result ;
8779}
8880
8981let sync_metrics = {
90- /**
91- * Privacy policies
92- * Wording sourced from: https://github.com/RUB-SysSec/we-value-your-privacy/blob/master/privacy_wording.json
93- * words = privacy_wording.map(country => country.words).filter((v, i, a) => a.indexOf(v) === i).flat().sort().join('|');
94- */
95- privacy_wording_links : ( ( ) => {
96- const languageKeywords = {
97- af : "beskyttelse af personlige oplysninger|privatlivspolitik|persondata" ,
98- ar : "الخصوصية|سياسة البيانات|سياسة الخصوصية|سياسة الخصوصية والبيانات" ,
99- az : "məxfilik|şəxsi məlumatlar" ,
100- be : "абарона дадзеных|палітыка прыватнасці" ,
101- bg : "поверителност|политика за бисквитки|политика за данни|условия|условия за ползване|политика за поверителност" ,
102- bn : "গোপনীয়তা|ডেটা নীতি|গোপনীয়তা নীতি" ,
103- bs : "privatnost|politika privatnosti|politika podataka|pravila o privatnosti" ,
104- ca : "protecció de dades|política de privacitat" ,
105- cs : "ochrana dat|ochrana osobních údajů|ochrana soukromí|ochrana súkromia|ochrana udaju|ochrana údajov|ochrany osobných údajov|podmínky|soukromi|soukromí|zásady používání dat|zásady používání cookies" ,
106- da : "cookiepolitik|datapolicy|beskyttelse af personlige oplysninger|personlige data|personoplysninger|privatlivspolitik|regler om fortrolighed" ,
107- de : "datenrichtlinie|datenschutz|datenschutzbestimmungen|datenschutzrichtlinie|privatssphäre|cookie-richtlinie|privatsphärenerklärung" ,
108- el : "απόρρητο|πολιτική απορρήτου|πολιτική δεδομένων|προσωπικά δεδομένα|όροι και γνωστοποιήσεις|πολιτική cookies" ,
109- en : "cookie policy|cookies|data policy|datapolicy|privacy|privacy policy|cookiepolicy" ,
110- es : "aviso legal|confidencialidad|confidencialite|confidentialité|política de datos|privacidad|privacidad|politica de datos|política de privacidad|política de cookies" ,
111- et : "andmekaitsetingimused|isikuandmete|isikuandmete töötlemise|kasutustingimused|privaatsuspoliitika|andmepoliitika|küpsisepoliitika" ,
112- eu : "privatua|datu pertsonalen babesa|datu pertsonalen politika" ,
113- fa : "حریم خصوصی|سیاست حفظ حریم خصوصی|سیاست داده|داده های شخصی" ,
114- fi : "yksityisyyden suoja|yksityisyydensuoja|yksityisyys|tietokäytäntö|tietosuoja|tietosuojakäytäntö|tietosuojaseloste|evästekäytäntö" ,
115- fil : "patakaran sa cookies" ,
116- fr : "cgu|cgv|confidentialité|mentions légales|politique d’utilisation des données|rgpd|vie privée|politique de confidentialité|politique de données|politique de cookie" ,
117- ga : "beartas príobháideachta|beartas sonraí|beartas fianán|beartas sonraí pearsanta" ,
118- he : "מדיניות נתונים|פרטיות" ,
119- hi : "गोपनीयता|डेटा नीति|गोपनीयता नीति" ,
120- hr : "privatnost|pravila o privatnosti|pravila o podacima|pravila o kolačićima" ,
121- hu : "adatvédelem|adatvédelmi|személyes adatok védelme|adatvédelmi nyilatkozat|adatkezelési tájékoztató|cookie-kra vonatkozó irányelv" ,
122- id : "integritetspolicy|piškotki|kebijakan privasi" ,
123- is : "persónuvernd|persónuverndarstefna" ,
124- it : "normativa sui dati|privatezza|informativa sulla privacy|informativa sui dati|informativa sui cookie|politica dei dati|politica dei cookies" ,
125- ja : "プライバシー|データポリシー|個人情報保護" ,
126- ko : "개인정보|개인정보 처리방침|개인정보 보호정책|개인정보 보호|정보 처리 방침" ,
127- ka : "კერძო წამყვანი|პირადი ინფორმაციის დაცვა|პირადი ინფორმაციის პოლიტიკა" ,
128- lt : "privatumas|privatumo|slapukai|slapukkih|privatumo politika|duomenų politika|slapukų politika|privatumo pareiškimas" ,
129- lv : "sīkdatne|sīkdatņu|privātuma|privātums|privātuma politika|datu politika|sīkdatņu politika|privātuma politikas paziņojums" ,
130- mt : "politika dwar il-privatezza|politika tad-data|politika tal-cookies|politika dwar id-dati" ,
131- ms : "privasi|polisi data|polisi privasi|data peribadi|terma dan syarat" ,
132- nb : "personvern|informasjonskapselregler" ,
133- nl : "gegevensbeleid|privacybeleid|cookiebeleid|privacyverklaring" ,
134- no : "personvern|personvernerklæring|informasjonskapsler|personvernspolicy" ,
135- pl : "prywatnosci|prywatności|prywatność|zasady dotyczące danych|polityka prywatności|polityka danych|polityka plików cookie" ,
136- pt : "privacidade|política de privacidade|política de dados|política de cookies" ,
137- ro : "confidențialitate|politica de utilizare|protectia datelor|politica de confidențialitate|politica de date|politica cookie" ,
138- ru : "конфиденциальность|политика использования данных|политика конфиденциальности|политика данных|политика файлов cookie|персональных данных" ,
139- si : "piškotki" ,
140- sk : "ochrana osobných údajov|zásady ochrany osobných|zásady používání dat|zásady využívania údajov|zásady ochrany osobných údajov|zásady používania údajov|zásady používania cookies|ochrana údajov" ,
141- sl : "piškotki|varstvo podatkov|zasebnost|pravilnik o zasebnosti|pravilnik o podatkih|pravilnik o piškotkih|politika zasebnosti" ,
142- sq : "konfidencialiteti|politika e privatësisë|politika e të dhënave personale" ,
143- sr : "konfidentsiaalsuse|pravila o upotrebi podataka|privatnost|privatnosti|prywatnosci|prywatności|prywatność|protecţia datelor|политика о подацима|приватност|защита података" ,
144- sv : "integritetspolicy|personuppgifter|privatlivspolitik|sekretess|webbplatsen|yksityisyyden suoja|yksityisyydensuoja|yksityisyys|datapolitik" ,
145- sw : "política de datos" ,
146- tr : "gizlilik|kişisel verilerin korunması|politika e të dhënave|politikat e privatesise|politikat e privatësisë|veri i̇lkesi|veri politikası|gizlilik politikası|veri politikası|çerez politikası" ,
147- th : "ความเป็นส่วนตัว|นโยบายความเป็นส่วนตัว|นโยบายข้อมูล|ข้อมูลส่วนบุคคล|เงื่อนไข" ,
148- vi : "quyền riêng tư|chính sách bảo mật|chính sách dữ liệu|dữ liệu cá nhân|điều khoản và điều kiện" ,
149- uk : "конфіденційність|конфіденційності|політика даних|файлів cookie|персональних даних|захисту даних" ,
150- zh : "数据使用政策|隐私政策|数据保护政策|隐私保护政策|數據使用政策|隱私政策|數據保護政策|隱私保護政策"
151- }
152- const websiteLanguage = document . documentElement . lang . slice ( 0 , 2 ) . toLowerCase ( ) ;
153- let keywords ;
154- if ( websiteLanguage == 'en' ) {
155- keywords = languageKeywords [ websiteLanguage ]
156- } else if ( ! ( websiteLanguage in languageKeywords ) ) {
157- keywords = Object . values ( languageKeywords ) . join ( '|' ) ;
158- } else {
159- keywords = languageKeywords [ websiteLanguage ] + '|' + languageKeywords [ 'en' ]
160- }
161- const pattern = new RegExp ( `(?:${ keywords } )` , 'gi' ) ;
162-
163- const privacy_links = Array . from ( document . querySelectorAll ( 'a' ) ) . filter ( a =>
164- pattern . test ( a . innerText )
165- ) . map (
166- a => ( {
167- text : a . innerText ,
168- } )
169- ) ;
170-
171- return privacy_links ;
172- } ) ( ) ,
173-
17482 // Consent Management Platforms
17583
17684 /**
@@ -250,7 +158,7 @@ let sync_metrics = {
250158 } ) ( ) ,
251159
252160 /**
253- * Global Privacy Platfrom (GPP)
161+ * Global Privacy Protocol (GPP)
254162 * https://github.com/InteractiveAdvertisingBureau/Global-Privacy-Platform
255163 */
256164 iab_gpp : ( ( ) => {
@@ -380,114 +288,6 @@ let sync_metrics = {
380288 return rp ;
381289 } ) ( ) ,
382290
383- /**
384- * Media devices
385- * https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices
386- */
387- media_devices : {
388- navigator_mediaDevices_enumerateDevices : testPropertyStringInResponseBodies (
389- 'mediaDevices.+enumerateDevices'
390- ) ,
391- navigator_mediaDevices_getUserMedia : testPropertyStringInResponseBodies (
392- 'mediaDevices.+getUserMedia'
393- ) ,
394- navigator_mediaDevices_getDisplayMedia : testPropertyStringInResponseBodies (
395- 'mediaDevices.+getDisplayMedia'
396- ) ,
397- } ,
398-
399- /**
400- * Geolocation API
401- * https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API
402- */
403- geolocation : {
404- navigator_geolocation_getCurrentPosition : testPropertyStringInResponseBodies (
405- 'geolocation.+getCurrentPosition'
406- ) ,
407- navigator_geolocation_watchPosition : testPropertyStringInResponseBodies (
408- 'geolocation.+watchPosition'
409- ) ,
410- } ,
411-
412- fingerprinting : ( ( ) => {
413- //These are determined by looking at the tests in https://github.com/fingerprintjs/fingerprintjs
414- const fingerprintingAPIs = [
415- 'ApplePaySession.canMakePayments' ,
416- 'getChannelData' , //audioContext
417- 'toDataURL' , //canvas
418- 'getImageData' , //canvas, not actually used by fingerprintJS
419- 'screen.colorDepth' ,
420- 'color-gamut' ,
421- 'prefers-contrast' ,
422- 'cpuClass' ,
423- 'deviceMemory' ,
424- 'forced-colors' ,
425- 'hardwareConcurrency' ,
426- 'dynamic-range' ,
427- 'indexedDB' ,
428- 'inverted-colors' ,
429- 'navigator.language' , //"language" would be too generic here
430- 'navigator.userLanguage' , //TODO exists?
431- 'localStorage' ,
432- 'min-monochrome' ,
433- 'max-monochrome' ,
434- 'openDatabase' ,
435- 'navigator.oscpu' ,
436- 'pdfViewerEnabled' ,
437- 'navigator.platform' , //"platform" would be too generic
438- 'navigator.plugins' ,
439- 'attributionSourceId' ,
440- 'prefers-reduced-motion' ,
441- 'prefers-reduced-transparency' ,
442- 'availWidth' ,
443- 'availHeight' ,
444- 'screen.width' ,
445- 'screen.height' ,
446- 'sessionStorage' ,
447- 'resolvedOptions().timeZone' ,
448- 'getTimezoneOffset' ,
449- 'maxTouchPoints' ,
450- 'ontouchstart' ,
451- 'navigator.vendor' ,
452- 'vendorUnmasked' ,
453- 'rendererUnmasked' ,
454- 'shadingLanguageVersion' ,
455- 'WEBGL_debug_renderer_info' ,
456- 'getShaderPrecisionFormat'
457- ] . map ( api => api . toLowerCase ( ) )
458-
459- const response_bodies = $WPT_BODIES . filter ( body => ( body . response_body && ( body . type === 'Document' || body . type === 'Script' ) ) )
460-
461- let fingerprintingUsageCounts = { }
462- let likelyFingerprintingScripts = [ ]
463-
464- response_bodies . forEach ( req => {
465- let total_occurrences = 0
466-
467- let body = req . response_body . toLowerCase ( )
468-
469- fingerprintingAPIs . forEach ( api => {
470- let api_occurrences = 0
471- let index = body . indexOf ( api )
472- while ( index !== - 1 ) {
473- api_occurrences ++
474- index = body . indexOf ( api , index + 1 )
475- }
476-
477- if ( api_occurrences > 0 ) {
478- fingerprintingUsageCounts [ api ] = ( fingerprintingUsageCounts [ api ] || 0 ) + api_occurrences
479- }
480- total_occurrences += api_occurrences
481- } )
482-
483- if ( total_occurrences >= 5 ) { //TODO what should this threshold be?
484- likelyFingerprintingScripts . push ( req . url )
485- }
486- } )
487-
488- return { counts : fingerprintingUsageCounts , likelyFingerprintingScripts }
489- } ) ( ) ,
490-
491291 /**
492292 * List of hostnames with CNAME record
493293 */
@@ -576,10 +376,7 @@ let sync_metrics = {
576376
577377 let CCPAdata = {
578378 hasCCPALink : CCPALinks . length > 0 ,
579- }
580- if ( CCPAdata . hasCCPALink ) {
581- CCPAdata . CCPALinkPhrases = CCPALinks . map ( link => link . textContent . trim ( ) . toLowerCase ( ) )
582- }
379+ } ;
583380
584381 return CCPAdata
585382 } ) ( )
0 commit comments