Hacker News new | past | comments | ask | show | jobs | submit login
Webcam in a Favicon (twitter.com)
225 points by MagicPropmaker on Apr 21, 2019 | hide | past | web | favorite | 35 comments

The source code is actually small enough to be posted here

  navigator.getUserMedia = navigator.getUserMedia || 
    window.onload = () => {
      // Create favicon link element
      const favicon = document.createElement('link');
      favicon.rel = 'shortcut icon';
      favicon.type = 'image/png';
      favicon.href = '../../images/favicon.ico';
      document.getElementsByTagName('head') . [0].appendChild(favicon);
      // Create hidden canvas
      const w = 32;
      const h = 32;
      const canvas = document.createElement('canvas');
      canvas.style = 'display: none';
      canvas.width = w;
      canvas.height = h;
      // Grab canvas context
      const ctx = canvas.getContext('2d');
      // Create hidden video element
      const video = document.createElement('video');
      video.style = 'display: none';
      video.width = canvas.width;
      video.height = canvas.height;
      // Assign user media to video and start loop
      navigator.getUserMedia({video: true}, stream => {
          video.srcObject = stream;
      }, () => {});
      // Loop forever
      const loop = () => {
          // Copy video to canvas
          ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
          // Set canvas to favicon
          favicon.setAttribute('href', canvas.toDataURL());
          // Loop
          setTimeout(loop, 100);
From https://github.com/wybiral/code-art/blob/master/projects/tin...

That explains why it does nothing in Safari. Safari doesn't support `navigator.getUserMedia`, as that's deprecated and no longer part of the standard. The standard way to do this is navigator.mediaDevices.getUserMedia

Is there a reason that he sets a timeout of 100? Since this is all local (because of canvas.toDataURL()), can't it just run every 16ms (60 fps) instead of 100? I noticed in the gif that it was super choppy but I kind of assumed there was a technical reason, but I can't think of a reason that there would be a reason to have such a long delay.

The browser doesn't seem to update the image any faster (at least not Chrome on Linux) than it already does. You can try different framerates though, maybe some platforms allow higher frequency?

Another interesting (and more practical) use of the favicon is visit duration tracking without JS: https://twitter.com/davywtf/status/951203191944773632

Basically the favicon connection to the server stays open sending a periodic junk-update so that the server can detect when the tab is closed. You can do it with any asset but the favicon hides the loading indicator.

Presumably you could do the same thing with a `<script async>` tag, drip-feeding bytes across the connection and waiting for it to close. Though now that I've said that, it occurs to me that disabling JavaScript almost certainly avoids loading script hrefs to begin with rather than just not executing them.

Is there an equivalent with any other type of resource, that avoids deferring onLoad?

> Is there an equivalent with any other type of resource, that avoids deferring onLoad?

If JS is disabled the event doesn't really matter and any asset can be handled this way. I just use the favicon because it stops the browser from showing a loading spinner so everything looks still and nobody assumes there's anything going on in the background.

You can use persistent connections like this in other strange ways too. For instance this is a no-JS chat that's even able to update the connection count by sending a bit of CSS lazily: https://harmless.herokuapp.com/main

Sigh, it's neat yea - but advertisers are going to start leveraging favicon stay-alives for revenue gauging.

It's easier and common to do with JS, so it would be a really niche target. I was investigating it as a method of tracking users on Tor where JS is often disabled.

While really novel and interesting, would it really work that well on Tor/etc? Most people using those browsers are pretty privacy conscious and I feel like people would notice a connection that never closes

Tor can also create a false sense of privacy because people think it will do all of the work for them.

If they look at the network tab in their browser they can see it, but it just looks like a favicon asset that's really slow to load. And people usually assume that with JS disabled these things don't happen.

That's also the purpose of using it in the favicon. It prevents the loading spinner so you'd have to inspect the connections.

You could also consider that people using TOR explicitly do not want to be tracked.

Why isn't stuff like this considered a security vulnerability in the browser and not require extra permissions from the user? I thought companies like Mozilla were supposed to be on the side of the users, but it often seems like they just make it easier and easier for companies to spy on users.

This particular cases is just an unintended consequence. They could put a limit on the connection duration, but you could also just slowly drip the bytes of a real favicon image (possibly augmented with junk metadata) and how would the browser know that it's not just a slow server connection?

These are favicons we are talking about. There is no legitimate reason for the browser to enable and permit this type of tracking without some permission from the user.

It's not really "permitting" it, that's just how the internet works. If you send the data slowly you can keep a connection open.

And fighting privacy violation is basically a game of cat and mouse. As soon as we figure out how to block their tactics, they evolve. If what I'm doing here became mainstream they would probably do something about it, but as it stands this is much easier to do using JS or something anyway (which people know violates their privacy but they leave it enabled because modern websites break down without it).

Anyways I disabled favicons on my computer from when I installed it, because that is not a feature I use.

I did not know of this specific use before, but now I do.

I wonder if there was a proposal to make the time an equal split between GMT+

The URL equalizer further down is possibly even cooler:


Note that the link is to something that is an audio spectrum analyzer/visualizer and not an equalizer. It's even called "Analyser" in the code. At first I was amazed that an equalizer could be implemented into a URL, I was wondering how one would input the gains for the frequency bands, but alas it just displays the volume at each frequency.

Whoops, the person who quote-tweeted it in the original thread called it an equalizer and I didn't give it any thought

It would be fun to flip the image so it really looks like a Tiny Mirror. I wonder if this would work?

In the initial setup:

  ctx.scale( -1, 1 );
In the drawing loop:

  ctx.drawImage( video, 0, 0, canvas.width * -1, canvas.height );
Something like that anyway. We have guests arriving soon, so no time to test right now, but if anyone tries it I will be curious!

That's such an awesome little hack. Next think we need is to synchronize multiple tabs and a multi-player favicon game where you get to shoot the tabs of your opponents.

It crashes Firefox 66.0.3 (64-bit) on Windows 10.0.17763.437. https://crash-stats.mozilla.org/report/index/7d1ca3eb-2d06-4...

Good news! That crash (RGB24ToARGBRow_SSSE3) is fixed in Firefox 67 Beta, which will be released on May 14:


Tested on 66.0.3 on a fully updated Windows 10 (64bit all around) and it works fine.

Works fine on Firefox 66.0.3 (64-bit) on Linux.

If it crashes it, there may be an attack vector here!

If you really want to crash a Firefox browser without JS, there's this: https://fan-pages.herokuapp.com/

It basically keeps sending iframe's with data URL's for download, see code: https://github.com/wybiral/crash

On Chrome it blocks request popups after the first but FF usually crashes (even Tor Browser).

The interesting thing about this is that you can keep the connection open as long as you want and then send the iframes on command.

>The interesting thing about this is that you can keep the connection open as long as you want and then send the iframes on command.

What do you mean?

If I'm operating the server I can keep the connection open to your browser and wait until sending the iframes to crash you.

So combined with other tracking techniques (to tell if a tab is still open) you can crash their browser and see which other tabs close.

Works great in Firefox 68.0a1 on Fedora 29 with the HTC Vive front-facing camera.

Next release: larger video image! Since it's impossible to show a larger image in the thumbnail area, we'll show the video in the main browser window.

This fails in Safari on the use of a deprecated API https://developer.mozilla.org/en-US/docs/Web/API/Navigator/g...

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact