Source Code
The entire project, readable in your browser. No hidden JavaScript, no sneaky beacons. If we claimed we don't track you, this is where you check.
|
Pages/
Feeds/
Backend/
Includes/
Stylesheet/
JavaScript/
data/counter.txt and data/guestbook.txt hold visitor-supplied content
(a number and signed messages), so they are not shown here.
|
1 /* ============================================================================ 2 export.js -- Local report export (JSON / HTML / Markdown / TXT) 3 ---------------------------------------------------------------------------- 4 Turns window.EYES.report into a downloadable file, entirely in the browser. 5 Nothing is uploaded; we build a Blob and trigger a download. 6 7 Exposes: window.EYES.exportReport(format, report?) 8 window.EYES.wireExportButtons() (auto-binds .export-btn[data-fmt]) 9 ========================================================================== */ 10 (function () { 11 "use strict"; 12 13 var EYES = window.EYES = window.EYES || {}; 14 15 function download(filename, text, mime) { 16 try { 17 var blob = new Blob([text], { type: (mime || 'text/plain') + ';charset=utf-8' }); 18 var url = URL.createObjectURL(blob); 19 var a = document.createElement('a'); 20 a.href = url; 21 a.download = filename; 22 document.body.appendChild(a); 23 a.click(); 24 document.body.removeChild(a); 25 setTimeout(function () { URL.revokeObjectURL(url); }, 4000); 26 } catch (e) { 27 // Fallback: open a data URI in a new tab. 28 var uri = 'data:' + (mime || 'text/plain') + ';charset=utf-8,' + encodeURIComponent(text); 29 window.open(uri, '_blank'); 30 } 31 } 32 33 function stamp() { 34 var d = new Date(); 35 function p(n) { return (n < 10 ? '0' : '') + n; } 36 return d.getFullYear() + p(d.getMonth() + 1) + p(d.getDate()) + '-' + p(d.getHours()) + p(d.getMinutes()) + p(d.getSeconds()); 37 } 38 39 /* ---- flatten the nested report into label/value pairs by section ------- */ 40 function sections(report) { 41 var b = report.browser || {}, s = report.server || {}, fp = report.fingerprint || {}; 42 var geo = s.geo || {}, req = s.request || {}, net = s.network || {}; 43 var priv = EYES.computePrivacy ? EYES.computePrivacy(report) : { score: 'n/a', categories: [] }; 44 var facts = EYES.funFacts ? EYES.funFacts(report) : []; 45 46 function pair(k, v) { return { k: k, v: (v == null || v === '') ? 'Unknown' : v }; } 47 48 var out = []; 49 50 out.push({ title: 'General', rows: [ 51 pair('IP Address', s.ip), 52 pair('HTTPS', req.is_https), 53 pair('Protocol', req.protocol), 54 pair('Host', s.server && s.server.host), 55 pair('Server Software', s.server && s.server.software), 56 pair('Generated', report.ts) 57 ]}); 58 59 out.push({ title: 'Network / Geolocation', rows: [ 60 pair('Country', geo.country), pair('City', geo.city), pair('Region', geo.region), 61 pair('Continent', geo.continent), pair('Timezone', geo.timezone), 62 pair('Coordinates', geo.lat != null ? geo.lat + ', ' + geo.lon : null), 63 pair('Currency', geo.currency), pair('ISP', geo.isp), pair('Organization', geo.org), 64 pair('ASN', geo.asn), pair('VPN/Proxy', geo.proxy || geo.vpn), 65 pair('Hosting', geo.hosting), pair('Behind Cloudflare', net.behind_cloudflare) 66 ]}); 67 68 if (b.ua) out.push({ title: 'Browser', rows: [ 69 pair('Browser', b.ua.browser + ' ' + b.ua.version), pair('Engine', b.ua.engine), 70 pair('OS', b.ua.os + ' ' + b.ua.osVersion), pair('Platform', b.platform.platform), 71 pair('Architecture', b.platform.architecture), 72 pair('Languages', (b.platform.languages || []).join(', ')), 73 pair('Cookies', b.apis.cookies), pair('Do Not Track', b.platform.doNotTrack), 74 pair('User-Agent', b.ua.raw) 75 ]}); 76 77 if (b.screen) out.push({ title: 'Display', rows: [ 78 pair('Resolution', b.screen.width + 'x' + b.screen.height), 79 pair('Available', b.screen.availWidth + 'x' + b.screen.availHeight), 80 pair('Viewport', b.screen.viewportW + 'x' + b.screen.viewportH), 81 pair('Pixel Ratio', b.screen.pixelRatio), pair('Color Depth', b.screen.colorDepth), 82 pair('Dark Mode', b.preferences.darkMode), pair('Touch', b.preferences.touch) 83 ]}); 84 85 if (b.platform) out.push({ title: 'Hardware', rows: [ 86 pair('CPU Cores', b.platform.cores), pair('Device Memory (GB)', b.platform.memory), 87 pair('Max Touch Points', b.platform.maxTouchPoints), 88 pair('GPU Vendor', b.webgl && b.webgl.vendor), pair('GPU Renderer', b.webgl && b.webgl.renderer), 89 pair('Battery', b.battery ? b.battery.level + '%' : null) 90 ]}); 91 92 if (fp && fp.id) { 93 var fprows = [ 94 pair('Fingerprint ID (SHA-256)', fp.id), 95 pair('Entropy (bits)', fp.entropyBits), 96 pair('Uniqueness (%)', fp.uniqueness), 97 pair('1 in', fp.oneIn), 98 pair('Tracking Risk', fp.trackingRisk) 99 ]; 100 Object.keys(fp.signals).forEach(function (k) { 101 fprows.push(pair('signal:' + k, fp.signals[k].hash)); 102 }); 103 out.push({ title: 'Fingerprint', rows: fprows }); 104 } 105 106 var prows = [pair('Overall Score', priv.score + ' / 100')]; 107 priv.categories.forEach(function (c) { prows.push(pair(c.name, c.score + '/100 (' + c.notes.join('; ') + ')')); }); 108 out.push({ title: 'Privacy Score', rows: prows }); 109 110 out.push({ title: 'Fun Facts', rows: facts.map(function (f, i) { return pair('#' + (i + 1), f); }) }); 111 112 return out; 113 } 114 115 /* ---- format builders --------------------------------------------------- */ 116 function toTXT(report) { 117 var secs = sections(report); 118 var lines = []; 119 lines.push('================================================================'); 120 lines.push(' WHAT CAN I LEARN ABOUT YOU? -- Local Report'); 121 lines.push(' Generated: ' + report.ts); 122 lines.push(' This report was created in YOUR browser and stored nowhere.'); 123 lines.push('================================================================', ''); 124 secs.forEach(function (sec) { 125 lines.push('+-- ' + sec.title + ' ' + Array(Math.max(2, 50 - sec.title.length)).join('-')); 126 sec.rows.forEach(function (r) { 127 lines.push(' ' + (r.k + ' ..................................').slice(0, 26) + ' : ' + r.v); 128 }); 129 lines.push(''); 130 }); 131 lines.push('-- No cookies. No tracking. No database. Made with PHP. --'); 132 return lines.join('\n'); 133 } 134 135 function toMarkdown(report) { 136 var secs = sections(report); 137 var out = []; 138 out.push('# What Can I Learn About You? — Report', ''); 139 out.push('_Generated: ' + report.ts + '. Created locally in your browser; stored nowhere._', ''); 140 secs.forEach(function (sec) { 141 out.push('## ' + sec.title, ''); 142 out.push('| Field | Value |', '| --- | --- |'); 143 sec.rows.forEach(function (r) { 144 out.push('| ' + String(r.k).replace(/\|/g, '\\|') + ' | ' + String(r.v).replace(/\|/g, '\\|').replace(/\n/g, ' ') + ' |'); 145 }); 146 out.push(''); 147 }); 148 out.push('---', '_No cookies. No tracking. No database. Made with PHP._'); 149 return out.join('\n'); 150 } 151 152 function esc(s) { 153 return String(s == null ? '' : s) 154 .replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); 155 } 156 157 function toHTML(report) { 158 var secs = sections(report); 159 var body = secs.map(function (sec) { 160 var rows = sec.rows.map(function (r) { 161 return '<tr><td class="k">' + esc(r.k) + '</td><td class="v">' + esc(r.v) + '</td></tr>'; 162 }).join(''); 163 return '<h2>' + esc(sec.title) + '</h2><table>' + rows + '</table>'; 164 }).join('\n'); 165 166 return '<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8">' + 167 '<title>What Can I Learn About You? - Report</title><style>' + 168 'body{background:#000;color:#D0D0D0;font-family:"Courier New",monospace;padding:16px;font-size:15px}' + 169 'h1{color:#00FF00}h2{color:#00FFFF;border-bottom:1px solid #00AA00;margin-top:20px}' + 170 'table{border-collapse:collapse;width:100%;margin:6px 0}' + 171 'td{border:1px solid #1c3a1c;padding:3px 8px;vertical-align:top;word-break:break-word}' + 172 'td.k{color:#00FFAA;width:30%}a{color:#00FFFF}.foot{color:#777;margin-top:20px}' + 173 '</style></head><body>' + 174 '<h1>What Can I Learn About You? — Report</h1>' + 175 '<p>Generated: ' + esc(report.ts) + '. Created locally in your browser; stored nowhere.</p>' + 176 body + 177 '<p class="foot">No cookies. No tracking. No database. Made with PHP. Open Source.</p>' + 178 '</body></html>'; 179 } 180 181 /* ---- public API -------------------------------------------------------- */ 182 EYES.exportReport = function (format, report) { 183 report = report || EYES.report; 184 if (!report) { 185 alert('Run a scan first (or open the Scan page).'); 186 return; 187 } 188 var base = 'whatcanilearn-' + stamp(); 189 switch (format) { 190 case 'json': 191 download(base + '.json', JSON.stringify(report, null, 2), 'application/json'); 192 break; 193 case 'txt': 194 download(base + '.txt', toTXT(report), 'text/plain'); 195 break; 196 case 'md': 197 download(base + '.md', toMarkdown(report), 'text/markdown'); 198 break; 199 case 'html': 200 download(base + '.html', toHTML(report), 'text/html'); 201 break; 202 default: 203 alert('Unknown format: ' + format); 204 } 205 }; 206 207 EYES.wireExportButtons = function () { 208 var btns = document.querySelectorAll('.export-btn'); 209 for (var i = 0; i < btns.length; i++) { 210 (function (btn) { 211 btn.addEventListener('click', function (ev) { 212 ev.preventDefault(); 213 EYES.exportReport(btn.getAttribute('data-fmt')); 214 }); 215 })(btns[i]); 216 } 217 }; 218 219 })(); 220 You are reading the real file being executed on the server. What you see is what runs. |