[ CRT: off ]
Visitors: 000003490 | Server: 2026-07-13 23:24:52 UTC | UTC: 2026-07-13 23:24:52 UTC
Best Viewed in Firefox | Powered by PHP 7.4.33 | Connection: HTTPS (secure) | No Cookies · No Tracking
*** Welcome to the last honest website on the internet *** +++ This site stores NOTHING about you -- everything is computed in YOUR browser +++ NEW! Live browser fingerprinting module added +++ NEW! Interactive terminal -- type help to begin +++ Best viewed in Firefox at 1024x768 or higher +++ Remember: if the product is free, usually YOU are the product -- but not here +++ Greetz to everyone still running an old CRT monitor <3

disk 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.

disk assets/js/terminal.js  (15.4 KB, 368 lines)
   1  /* ============================================================================
   2     terminal.js  --  Interactive fake shell
   3     ----------------------------------------------------------------------------
   4     A retro command line with real, computed output. Commands:
   5       help  scan  browser  network  hardware  privacy  fingerprint
   6       clear ascii neofetch fortune about source whoami export ver echo
   7  
   8     Attaches to a container that already contains:
   9         <div id="termOutput"></div>
  10         <div class="term-inputline">
  11           <span class="ps1">guest@whatcanilearn:~$</span>
  12           <input class="term-input" id="termInput">
  13         </div>
  14  
  15     Reads the report from window.EYES.report if a scan has run; otherwise builds
  16     one on demand. Stores nothing.
  17     ========================================================================== */
  18  (function () {
  19    "use strict";
  20  
  21    var EYES = window.EYES = window.EYES || {};
  22  
  23    function esc(s) {
  24      return String(s == null ? '' : s)
  25        .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
  26    }
  27  
  28    var PS1 = 'guest@whatcanilearn:~$';
  29  
  30    function Terminal(outEl, inEl) {
  31      this.out = outEl;
  32      this.in = inEl;
  33      this.history = [];
  34      this.hpos = -1;
  35      var self = this;
  36  
  37      inEl.addEventListener('keydown', function (ev) {
  38        if (ev.key === 'Enter') {
  39          var cmd = inEl.value;
  40          inEl.value = '';
  41          self.run(cmd);
  42        } else if (ev.key === 'ArrowUp') {
  43          ev.preventDefault();
  44          if (self.history.length) {
  45            if (self.hpos < 0) self.hpos = self.history.length;
  46            self.hpos = Math.max(0, self.hpos - 1);
  47            inEl.value = self.history[self.hpos] || '';
  48          }
  49        } else if (ev.key === 'ArrowDown') {
  50          ev.preventDefault();
  51          if (self.history.length && self.hpos >= 0) {
  52            self.hpos = Math.min(self.history.length, self.hpos + 1);
  53            inEl.value = self.history[self.hpos] || '';
  54          }
  55        } else if (ev.key === 'l' && ev.ctrlKey) {
  56          ev.preventDefault();
  57          self.clear();
  58        }
  59      });
  60  
  61      // Focus the input when the terminal area is clicked.
  62      if (outEl.parentNode) {
  63        outEl.parentNode.addEventListener('click', function () { inEl.focus(); });
  64      }
  65    }
  66  
  67    Terminal.prototype.print = function (html) {
  68      var div = document.createElement('div');
  69      div.innerHTML = html;
  70      this.out.appendChild(div);
  71      this.out.scrollTop = this.out.scrollHeight;
  72    };
  73    Terminal.prototype.echoCmd = function (cmd) {
  74      this.print('<span class="prompt">' + esc(PS1) + '</span> ' + esc(cmd));
  75    };
  76    Terminal.prototype.clear = function () { this.out.innerHTML = ''; };
  77  
  78    Terminal.prototype.run = function (raw) {
  79      var cmd = (raw || '').trim();
  80      this.echoCmd(cmd);
  81      if (cmd === '') return;
  82      this.history.push(cmd);
  83      this.hpos = -1;
  84  
  85      var parts = cmd.split(/\s+/);
  86      var name = parts[0].toLowerCase();
  87      var args = parts.slice(1);
  88      var fn = this.commands[name];
  89      if (fn) {
  90        try { fn.call(this, args); }
  91        catch (e) { this.print('<span class="err">error: ' + esc(e.message) + '</span>'); }
  92      } else {
  93        this.print('<span class="err">' + esc(name) + ': command not found</span>. Type <span class="cyan">help</span>.');
  94      }
  95    };
  96  
  97    /* ---- helpers to get data ---------------------------------------------- */
  98    function withReport(cb, term) {
  99      if (EYES.report) { cb(EYES.report); return; }
 100      term.print('<span class="dim">no scan in memory -- collecting now...</span>');
 101      if (EYES.buildReport) {
 102        EYES.buildReport().then(cb).catch(function () {
 103          term.print('<span class="err">collection failed.</span>');
 104        });
 105      } else {
 106        term.print('<span class="err">scan engine not loaded on this page.</span>');
 107      }
 108    }
 109  
 110    /* ---- command implementations ------------------------------------------ */
 111    Terminal.prototype.commands = {
 112      help: function () {
 113        this.print(
 114          '<span class="cyan">Available commands:</span>\n' +
 115          '  help         this message\n' +
 116          '  scan         run a full scan and summarize\n' +
 117          '  browser      browser / OS / engine details\n' +
 118          '  network      IP, geo, ISP, VPN status\n' +
 119          '  hardware     CPU, memory, GPU, screen\n' +
 120          '  privacy      compute your privacy score\n' +
 121          '  fingerprint  show your local fingerprint ID\n' +
 122          '  whoami       one-line identity summary\n' +
 123          '  neofetch     system info, ASCII-art style\n' +
 124          '  ascii        show the site logo\n' +
 125          '  fortune      a privacy-themed fortune\n' +
 126          '  export       download your report (json|html|md|txt)\n' +
 127          '  ver          version info\n' +
 128          '  echo [text]  print text\n' +
 129          '  about        what is this site\n' +
 130          '  source       where to read the code\n' +
 131          '  clear        clear the screen'
 132        );
 133      },
 134  
 135      scan: function () {
 136        var t = this;
 137        withReport(function (r) {
 138          var b = r.browser || {}, s = r.server || {}, fp = r.fingerprint || {};
 139          var geo = s.geo || {};
 140          t.print(
 141            '<span class="ok">== SCAN COMPLETE ==</span>\n' +
 142            'IP ............ ' + esc(s.ip || '?') + '\n' +
 143            'Location ...... ' + esc([geo.city, geo.country].filter(Boolean).join(', ') || 'unknown') + '\n' +
 144            'ISP ........... ' + esc(geo.isp || 'unknown') + '\n' +
 145            'Browser ....... ' + esc((b.ua ? b.ua.browser + ' ' + b.ua.version : '?')) + '\n' +
 146            'OS ............ ' + esc((b.ua ? b.ua.os + ' ' + b.ua.osVersion : '?')) + '\n' +
 147            'CPU cores ..... ' + esc((b.platform ? b.platform.cores : '?')) + '\n' +
 148            'GPU ........... ' + esc((b.webgl ? b.webgl.renderer : '?')) + '\n' +
 149            'Fingerprint ... ' + esc(fp.id ? fp.id.slice(0, 32) + '...' : '?') + '\n' +
 150            'Tracking risk . ' + esc(fp.trackingRisk || '?') + '\n' +
 151            '<span class="dim">(nothing stored)</span>'
 152          );
 153        }, t);
 154      },
 155  
 156      browser: function () {
 157        var t = this;
 158        withReport(function (r) {
 159          var b = r.browser || {};
 160          if (!b.ua) { t.print('<span class="err">no browser data</span>'); return; }
 161          t.print(
 162            'Browser ....... ' + esc(b.ua.browser + ' ' + b.ua.version) + '\n' +
 163            'Engine ........ ' + esc(b.ua.engine) + '\n' +
 164            'OS ............ ' + esc(b.ua.os + ' ' + b.ua.osVersion) + '\n' +
 165            'Platform ...... ' + esc(b.platform.platform) + '\n' +
 166            'Arch .......... ' + esc(b.platform.architecture) + '\n' +
 167            'Languages ..... ' + esc((b.platform.languages || []).join(', ')) + '\n' +
 168            'Cookies ....... ' + esc(b.apis.cookies ? 'enabled' : 'disabled') + '\n' +
 169            'DNT ........... ' + esc(b.platform.doNotTrack || 'not set') + '\n' +
 170            'UA ............ ' + esc(b.ua.raw)
 171          );
 172        }, t);
 173      },
 174  
 175      network: function () {
 176        var t = this;
 177        withReport(function (r) {
 178          var s = r.server || {}, geo = (s.geo || {}), net = s.network || {};
 179          t.print(
 180            'IP ............ ' + esc(s.ip || '?') + '\n' +
 181            'Country ....... ' + esc(geo.country || 'unknown') + '\n' +
 182            'City .......... ' + esc(geo.city || 'unknown') + '\n' +
 183            'Timezone ...... ' + esc(geo.timezone || 'unknown') + '\n' +
 184            'Coords ........ ' + esc(geo.lat != null ? geo.lat + ', ' + geo.lon : 'unknown') + '\n' +
 185            'ISP ........... ' + esc(geo.isp || 'unknown') + '\n' +
 186            'ASN ........... ' + esc(geo.asn || 'unknown') + '\n' +
 187            'VPN/Proxy ..... ' + esc((geo.proxy || geo.vpn) ? 'YES' : 'no') + '\n' +
 188            'Hosting ....... ' + esc(geo.hosting ? 'YES' : 'no') + '\n' +
 189            'Cloudflare .... ' + esc(net.behind_cloudflare ? 'YES' : 'no') + '\n' +
 190            'HTTPS ......... ' + esc((s.request && s.request.is_https) ? 'yes' : 'NO')
 191          );
 192        }, t);
 193      },
 194  
 195      hardware: function () {
 196        var t = this;
 197        withReport(function (r) {
 198          var b = r.browser || {};
 199          t.print(
 200            'CPU cores ..... ' + esc(b.platform ? b.platform.cores : '?') + '\n' +
 201            'Memory ........ ' + esc(b.platform && b.platform.memory ? b.platform.memory + ' GB' : 'unknown') + '\n' +
 202            'GPU vendor .... ' + esc(b.webgl ? b.webgl.vendor : '?') + '\n' +
 203            'GPU renderer .. ' + esc(b.webgl ? b.webgl.renderer : '?') + '\n' +
 204            'Screen ........ ' + esc(b.screen ? b.screen.width + 'x' + b.screen.height : '?') + '\n' +
 205            'Pixel ratio ... ' + esc(b.screen ? b.screen.pixelRatio : '?') + '\n' +
 206            'Color depth ... ' + esc(b.screen ? b.screen.colorDepth + '-bit' : '?') + '\n' +
 207            'Touch points .. ' + esc(b.platform ? b.platform.maxTouchPoints : '?') +
 208            (b.battery ? '\nBattery ....... ' + esc(b.battery.level + '% ' + (b.battery.charging ? '(charging)' : '')) : '')
 209          );
 210        }, t);
 211      },
 212  
 213      privacy: function () {
 214        var t = this;
 215        withReport(function (r) {
 216          var p = EYES.computePrivacy(r);
 217          var lines = ['<span class="cyan">PRIVACY SCORE: ' + p.score + ' / 100</span>'];
 218          p.categories.forEach(function (c) {
 219            var total = 20, filled = Math.round((c.score / 100) * total);
 220            var bar = '';
 221            for (var i = 0; i < total; i++) bar += (i < filled ? '#' : '-');
 222            var pad = (c.name + '               ').slice(0, 16);
 223            var cls = c.score >= 66 ? 'ok' : c.score >= 33 ? 'warn' : 'err';
 224            lines.push(pad + ' [<span class="' + cls + '">' + bar + '</span>] ' + c.score);
 225          });
 226          t.print(lines.join('\n'));
 227        }, t);
 228      },
 229  
 230      fingerprint: function () {
 231        var t = this;
 232        withReport(function (r) {
 233          var fp = r.fingerprint || {};
 234          if (!fp.id) { t.print('<span class="err">no fingerprint available</span>'); return; }
 235          var lines = ['<span class="cyan">FINGERPRINT ID (SHA-256):</span>', esc(fp.id), '',
 236            'Entropy ....... ~' + esc(fp.entropyBits) + ' bits',
 237            'Uniqueness .... ' + esc(fp.uniqueness) + '%',
 238            'You are ~1 in . ' + esc(fp.oneIn.toLocaleString()),
 239            'Tracking risk . ' + esc(fp.trackingRisk), '', '<span class="dim">per-signal:</span>'];
 240          Object.keys(fp.signals).forEach(function (k) {
 241            lines.push('  ' + (k + '        ').slice(0, 10) + ' ' + esc(fp.signals[k].short) + '...');
 242          });
 243          t.print(lines.join('\n'));
 244        }, t);
 245      },
 246  
 247      whoami: function () {
 248        var t = this;
 249        withReport(function (r) {
 250          var b = r.browser || {}, s = r.server || {}, geo = s.geo || {};
 251          var who = (b.ua ? b.ua.browser : 'a browser') + ' on ' + (b.ua ? b.ua.os : 'an OS') +
 252            ', ~' + (geo.city || geo.country || 'somewhere') + ', via ' + (geo.isp || 'your ISP') +
 253            ', ' + (b.platform ? b.platform.cores + ' cores' : '') +
 254            '. You are 1 in ' + ((r.fingerprint && r.fingerprint.oneIn) ? r.fingerprint.oneIn.toLocaleString() : 'many') + '.';
 255          t.print('<span class="ok">' + esc(who) + '</span>');
 256        }, t);
 257      },
 258  
 259      neofetch: function () {
 260        var t = this;
 261        withReport(function (r) {
 262          var b = r.browser || {}, s = r.server || {}, geo = s.geo || {}, fp = r.fingerprint || {};
 263          var art = [
 264            "        .--.       ", "       |o_o |      ", "       |:_/ |      ",
 265            "      //   \\ \\     ", "     (|     | )    ", "    /'\\_   _/`\\    ",
 266            "    \\___)=(___/    "
 267          ];
 268          var info = [
 269            'guest@whatcanilearn',
 270            '-------------------',
 271            'OS:       ' + (b.ua ? b.ua.os + ' ' + b.ua.osVersion : '?'),
 272            'Browser:  ' + (b.ua ? b.ua.browser + ' ' + b.ua.version : '?'),
 273            'Engine:   ' + (b.ua ? b.ua.engine : '?'),
 274            'CPU:      ' + (b.platform ? b.platform.cores + ' cores' : '?'),
 275            'Memory:   ' + (b.platform && b.platform.memory ? b.platform.memory + ' GB' : '?'),
 276            'GPU:      ' + (b.webgl ? b.webgl.renderer : '?'),
 277            'Screen:   ' + (b.screen ? b.screen.width + 'x' + b.screen.height : '?'),
 278            'IP:       ' + (s.ip || '?'),
 279            'Location: ' + ([geo.city, geo.country].filter(Boolean).join(', ') || '?'),
 280            'ISP:      ' + (geo.isp || '?'),
 281            'FP:       ' + (fp.id ? fp.id.slice(0, 12) + '...' : '?'),
 282            'Risk:     ' + (fp.trackingRisk || '?')
 283          ];
 284          var lines = [];
 285          var n = Math.max(art.length, info.length);
 286          for (var i = 0; i < n; i++) {
 287            var a = art[i] || '                   ';
 288            var b2 = info[i] || '';
 289            lines.push('<span class="green">' + esc(a) + '</span> <span class="cyan">' + esc(b2) + '</span>');
 290          }
 291          t.print(lines.join('\n'));
 292        }, t);
 293      },
 294  
 295      ascii: function () {
 296        this.print('<span class="green">' + esc(
 297          " __        __            _\n" +
 298          " \\ \\      / /__ _ __ ___| |\n" +
 299          "  \\ \\ /\\ / / _ \\ '__/ _ \\ |\n" +
 300          "   \\ V  V /  __/ | |  __/_|\n" +
 301          "    \\_/\\_/ \\___|_|  \\___(_)\n" +
 302          "   What Can I Learn About You?"
 303        ) + '</span>');
 304      },
 305  
 306      fortune: function () {
 307        var fortunes = [
 308          'The internet never forgets. But this website does -- instantly.',
 309          'You are not paranoid if they really are fingerprinting you. (They are.)',
 310          'A cookie a day keeps the privacy away.',
 311          'Privacy is not about having something to hide. It is about having something to protect.',
 312          'Every "Accept All" button is a tiny surrender.',
 313          'Your GPU is basically a name tag you can never take off.',
 314          'The best time to install a tracker blocker was 20 years ago. The second best time is now.',
 315          'On the internet, nobody knows you are a dog -- but they know your screen resolution.',
 316          'VPN: because your ISP does not need a diary of your life.',
 317          'They cannot sell what they never collected.'
 318        ];
 319        var idx = Math.floor(Math.random() * fortunes.length);
 320        this.print('<span class="yellow">' + esc(fortunes[idx]) + '</span>');
 321      },
 322  
 323      export: function (args) {
 324        var fmt = (args[0] || 'json').toLowerCase();
 325        if (!EYES.exportReport) { this.print('<span class="err">export module not loaded</span>'); return; }
 326        if (['json','html','md','markdown','txt'].indexOf(fmt) < 0) {
 327          this.print('usage: export [json|html|md|txt]'); return;
 328        }
 329        var t = this;
 330        withReport(function (r) {
 331          EYES.exportReport(fmt === 'markdown' ? 'md' : fmt, r);
 332          t.print('<span class="ok">downloading report as ' + esc(fmt) + '...</span>');
 333        }, t);
 334      },
 335  
 336      ver: function () {
 337        this.print('WhatCanILearn shell v1.0 -- built like it is 2003. No warranty. No cookies.');
 338      },
 339  
 340      echo: function (args) { this.print(esc(args.join(' '))); },
 341  
 342      about: function () {
 343        this.print('This site shows what any website can learn about you, then throws it away.\n' +
 344          'No database. No tracking. No cookies. Type  source  to read the code.');
 345      },
 346  
 347      source: function () {
 348        this.print('The full source is on the <span class="cyan">Source</span> page: ' +
 349          '<a href="' + (EYES.BASE || '') + '/source.php">' + esc((EYES.BASE || '') + '/source.php') + '</a>');
 350      },
 351  
 352      clear: function () { this.clear(); }
 353    };
 354  
 355    /* ---- boot the terminal if the page has one ---------------------------- */
 356    EYES.initTerminal = function () {
 357      var outEl = document.getElementById('termOutput');
 358      var inEl = document.getElementById('termInput');
 359      if (!outEl || !inEl) return null;
 360      var term = new Terminal(outEl, inEl);
 361      term.print('<span class="dim">WhatCanILearn interactive shell. Type </span><span class="cyan">help</span><span class="dim"> to begin.</span>');
 362      EYES.terminal = term;
 363      inEl.focus();
 364      return term;
 365    };
 366  
 367  })();
 368  

You are reading the real file being executed on the server. What you see is what runs.