├── LICENSE.txt ├── README.markdown ├── docs ├── docco.css └── jquery.browser-fingerprint-1.1.html └── src ├── jquery.browser-fingerprint-1.1.js └── jquery.browser-fingerprint-1.1.min.js /LICENSE.txt: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 14 rue de Plaisance, 75014 Paris, France 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | ### jquery.browser-fingerprint.js 2 | 3 | Browser fingerprinting is a technique to "mark" anonymous users using JS 4 | (or other things). To build an "identity" of sorts the browser is queried 5 | for a list of its plugins, the screen size and several other things, then 6 | hashes them. The idea is that these bits of information produce an unique 7 | "fingerprint" of sorts; the more elaborate the list of data points is, the 8 | more unique this fingerprint becomes. And you wouldn't even need to set a 9 | cookie to recognize this user when she visits again. 10 | 11 | For more information on this topic consult 12 | [Ars Technica](http://arstechnica.com/tech-policy/news/2010/05/how-your-web-browser-rats-you-out-online.ars) 13 | or the [EFF](http://panopticlick.eff.org/). There is a lot of potential 14 | for undesirable shenanigans, and I strictly oppose using this technique for 15 | marketing and ad-related tracking purposes. 16 | 17 | Anyways, I needed a really simple fingerprinting library, so I wrote a 18 | quick and dirty jQuery plugin. This is by no means a complete and 19 | watertight implementation -- it is merely the scratch for a particular itch 20 | I was having. YMMV. 21 | 22 | This library was written by Carlo Zottmann, carlo@municode.de, has its home 23 | @ [Github](http://github.com/carlo/jquery-browser-fingerprint) and is 24 | WTF-licensed (see LICENSE.txt). 25 | 26 | Documentation (docco-generated) can be found in the `docs/` folder. 27 | -------------------------------------------------------------------------------- /docs/docco.css: -------------------------------------------------------------------------------- 1 | /*--------------------- Layout and Typography ----------------------------*/ 2 | body { 3 | font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; 4 | font-size: 15px; 5 | line-height: 22px; 6 | color: #252519; 7 | margin: 0; padding: 0; 8 | } 9 | a { 10 | color: #261a3b; 11 | } 12 | a:visited { 13 | color: #261a3b; 14 | } 15 | p { 16 | margin: 0 0 15px 0; 17 | } 18 | h1, h2, h3, h4, h5, h6 { 19 | margin: 0px 0 15px 0; 20 | } 21 | h1 { 22 | margin-top: 40px; 23 | } 24 | #container { 25 | position: relative; 26 | } 27 | #background { 28 | position: fixed; 29 | top: 0; left: 525px; right: 0; bottom: 0; 30 | background: #f5f5ff; 31 | border-left: 1px solid #e5e5ee; 32 | z-index: -1; 33 | } 34 | #jump_to, #jump_page { 35 | background: white; 36 | -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777; 37 | -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; 38 | font: 10px Arial; 39 | text-transform: uppercase; 40 | cursor: pointer; 41 | text-align: right; 42 | } 43 | #jump_to, #jump_wrapper { 44 | position: fixed; 45 | right: 0; top: 0; 46 | padding: 5px 10px; 47 | } 48 | #jump_wrapper { 49 | padding: 0; 50 | display: none; 51 | } 52 | #jump_to:hover #jump_wrapper { 53 | display: block; 54 | } 55 | #jump_page { 56 | padding: 5px 0 3px; 57 | margin: 0 0 25px 25px; 58 | } 59 | #jump_page .source { 60 | display: block; 61 | padding: 5px 10px; 62 | text-decoration: none; 63 | border-top: 1px solid #eee; 64 | } 65 | #jump_page .source:hover { 66 | background: #f5f5ff; 67 | } 68 | #jump_page .source:first-child { 69 | } 70 | table td { 71 | border: 0; 72 | outline: 0; 73 | } 74 | td.docs, th.docs { 75 | max-width: 450px; 76 | min-width: 450px; 77 | min-height: 5px; 78 | padding: 10px 25px 1px 50px; 79 | overflow-x: hidden; 80 | vertical-align: top; 81 | text-align: left; 82 | } 83 | .docs pre { 84 | margin: 15px 0 15px; 85 | padding-left: 15px; 86 | } 87 | .docs p tt, .docs p code { 88 | background: #f8f8ff; 89 | border: 1px solid #dedede; 90 | font-size: 12px; 91 | padding: 0 0.2em; 92 | } 93 | .pilwrap { 94 | position: relative; 95 | } 96 | .pilcrow { 97 | font: 12px Arial; 98 | text-decoration: none; 99 | color: #454545; 100 | position: absolute; 101 | top: 3px; left: -20px; 102 | padding: 1px 2px; 103 | opacity: 0; 104 | -webkit-transition: opacity 0.2s linear; 105 | } 106 | td.docs:hover .pilcrow { 107 | opacity: 1; 108 | } 109 | td.code, th.code { 110 | padding: 14px 15px 16px 25px; 111 | width: 100%; 112 | vertical-align: top; 113 | background: #f5f5ff; 114 | border-left: 1px solid #e5e5ee; 115 | } 116 | pre, tt, code { 117 | font-size: 12px; line-height: 18px; 118 | font-family: Monaco, Consolas, "Lucida Console", monospace; 119 | margin: 0; padding: 0; 120 | } 121 | 122 | 123 | /*---------------------- Syntax Highlighting -----------------------------*/ 124 | td.linenos { background-color: #f0f0f0; padding-right: 10px; } 125 | span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } 126 | body .hll { background-color: #ffffcc } 127 | body .c { color: #408080; font-style: italic } /* Comment */ 128 | body .err { border: 1px solid #FF0000 } /* Error */ 129 | body .k { color: #954121 } /* Keyword */ 130 | body .o { color: #666666 } /* Operator */ 131 | body .cm { color: #408080; font-style: italic } /* Comment.Multiline */ 132 | body .cp { color: #BC7A00 } /* Comment.Preproc */ 133 | body .c1 { color: #408080; font-style: italic } /* Comment.Single */ 134 | body .cs { color: #408080; font-style: italic } /* Comment.Special */ 135 | body .gd { color: #A00000 } /* Generic.Deleted */ 136 | body .ge { font-style: italic } /* Generic.Emph */ 137 | body .gr { color: #FF0000 } /* Generic.Error */ 138 | body .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 139 | body .gi { color: #00A000 } /* Generic.Inserted */ 140 | body .go { color: #808080 } /* Generic.Output */ 141 | body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 142 | body .gs { font-weight: bold } /* Generic.Strong */ 143 | body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 144 | body .gt { color: #0040D0 } /* Generic.Traceback */ 145 | body .kc { color: #954121 } /* Keyword.Constant */ 146 | body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */ 147 | body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */ 148 | body .kp { color: #954121 } /* Keyword.Pseudo */ 149 | body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */ 150 | body .kt { color: #B00040 } /* Keyword.Type */ 151 | body .m { color: #666666 } /* Literal.Number */ 152 | body .s { color: #219161 } /* Literal.String */ 153 | body .na { color: #7D9029 } /* Name.Attribute */ 154 | body .nb { color: #954121 } /* Name.Builtin */ 155 | body .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 156 | body .no { color: #880000 } /* Name.Constant */ 157 | body .nd { color: #AA22FF } /* Name.Decorator */ 158 | body .ni { color: #999999; font-weight: bold } /* Name.Entity */ 159 | body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ 160 | body .nf { color: #0000FF } /* Name.Function */ 161 | body .nl { color: #A0A000 } /* Name.Label */ 162 | body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 163 | body .nt { color: #954121; font-weight: bold } /* Name.Tag */ 164 | body .nv { color: #19469D } /* Name.Variable */ 165 | body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 166 | body .w { color: #bbbbbb } /* Text.Whitespace */ 167 | body .mf { color: #666666 } /* Literal.Number.Float */ 168 | body .mh { color: #666666 } /* Literal.Number.Hex */ 169 | body .mi { color: #666666 } /* Literal.Number.Integer */ 170 | body .mo { color: #666666 } /* Literal.Number.Oct */ 171 | body .sb { color: #219161 } /* Literal.String.Backtick */ 172 | body .sc { color: #219161 } /* Literal.String.Char */ 173 | body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */ 174 | body .s2 { color: #219161 } /* Literal.String.Double */ 175 | body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ 176 | body .sh { color: #219161 } /* Literal.String.Heredoc */ 177 | body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ 178 | body .sx { color: #954121 } /* Literal.String.Other */ 179 | body .sr { color: #BB6688 } /* Literal.String.Regex */ 180 | body .s1 { color: #219161 } /* Literal.String.Single */ 181 | body .ss { color: #19469D } /* Literal.String.Symbol */ 182 | body .bp { color: #954121 } /* Name.Builtin.Pseudo */ 183 | body .vc { color: #19469D } /* Name.Variable.Class */ 184 | body .vg { color: #19469D } /* Name.Variable.Global */ 185 | body .vi { color: #19469D } /* Name.Variable.Instance */ 186 | body .il { color: #666666 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /docs/jquery.browser-fingerprint-1.1.html: -------------------------------------------------------------------------------- 1 | jquery.browser-fingerprint-1.1.js

jquery.browser-fingerprint-1.1.js

Browser fingerprinting is a technique to "mark" anonymous users using JS 2 | (or other things). To build an "identity" of sorts the browser is queried 3 | for a list of its plugins, the screen size and several other things, then 4 | hashes them. The idea is that these bits of information produce an unique 5 | "fingerprint" of sorts; the more elaborate the list of data points is, the 6 | more unique this fingerprint becomes. And you wouldn't even need to set a 7 | cookie to recognize this user when she visits again.

8 | 9 |

For more information on this topic consult 10 | Ars Technica 11 | or the EFF. There is a lot of potential 12 | for undesirable shenanigans, and I strictly oppose using this technique for 13 | marketing and ad-related tracking purposes.

14 | 15 |

Anyways, I needed a really simple fingerprinting library, so I wrote a 16 | quick and dirty jQuery plugin. This is by no means a complete and 17 | watertight implementation -- it is merely the scratch for a particular itch 18 | I was having. YMMV.

19 | 20 |

This library was written by Carlo Zottmann, carlo@municode.de, has its home 21 | on Github and is 22 | WTF-licensed (see LICENSE.txt).

( function($) {

Calling jQuery.fingerprint() will return an MD5 hash, i.e. said 23 | fingerprint.

  $.fingerprint = function() {

This function, _raw(), uses several browser details which are 24 | available to JS here to build a string, namely...

25 | 26 |
    27 |
  • the user agent
  • 28 |
  • screen size
  • 29 |
  • color depth
  • 30 |
  • the timezone offset
  • 31 |
  • sessionStorage support
  • 32 |
  • localStorage support
  • 33 |
  • the list of all installed plugins (we're using their names, 34 | descriptions, mime types and file name extensions here)
  • 35 |
    function _raw() {

That string is the return value.

      return [
36 |         navigator.userAgent,
37 |         [ screen.height, screen.width, screen.colorDepth ].join("x"),
38 |         ( new Date() ).getTimezoneOffset(),
39 |         !!window.sessionStorage,
40 |         !!window.localStorage,
41 |         $.map( navigator.plugins, function(p) {
42 |           return [
43 |             p.name,
44 |             p.description,
45 |             $.map( p, function(mt) {
46 |               return [ mt.type, mt.suffixes ].join("~");
47 |             }).join(",")
48 |           ].join("::");
49 |         }).join(";")
50 |       ].join("###");
51 |     }

_md5() computes a MD5 hash using md5-js.

    function _md5() {
52 |       if ( typeof window.md5 === "function" ) {

The return value is the hashed fingerprint string.

        return md5( _raw() );
53 |       }
54 |       else {

If window.md5() isn't available, an error is thrown.

        throw "md5 unavailable, please get it from http://github.com/wbond/md5-js/";
55 |       }
56 |     }

And, since I'm lazy, calling $.fingerprint() will return the hash 57 | right away, without the need for any other calls.

    return _md5();
58 |   }
59 | 
60 | })(jQuery);
61 | 
62 | 
-------------------------------------------------------------------------------- /src/jquery.browser-fingerprint-1.1.js: -------------------------------------------------------------------------------- 1 | // Browser fingerprinting is a technique to "mark" anonymous users using JS 2 | // (or other things). To build an "identity" of sorts the browser is queried 3 | // for a list of its plugins, the screen size and several other things, then 4 | // hashes them. The idea is that these bits of information produce an unique 5 | // "fingerprint" of sorts; the more elaborate the list of data points is, the 6 | // more unique this fingerprint becomes. And you wouldn't even need to set a 7 | // cookie to recognize this user when she visits again. 8 | // 9 | // For more information on this topic consult 10 | // [Ars Technica](http://arstechnica.com/tech-policy/news/2010/05/how-your-web-browser-rats-you-out-online.ars) 11 | // or the [EFF](http://panopticlick.eff.org/). There is a lot of potential 12 | // for undesirable shenanigans, and I strictly oppose using this technique for 13 | // marketing and ad-related tracking purposes. 14 | // 15 | // Anyways, I needed a really simple fingerprinting library, so I wrote a 16 | // quick and dirty jQuery plugin. This is by no means a complete and 17 | // watertight implementation -- it is merely the scratch for a particular itch 18 | // I was having. YMMV. 19 | // 20 | // This library was written by Carlo Zottmann, carlo@municode.de, has its home 21 | // on [Github](http://github.com/carlo/jquery-browser-fingerprint) and is 22 | // WTF-licensed (see LICENSE.txt). 23 | 24 | ( function($) { 25 | 26 | // Calling `jQuery.fingerprint()` will return an MD5 hash, i.e. said 27 | // fingerprint. 28 | 29 | $.fingerprint = function() { 30 | 31 | // This function, `_raw()`, uses several browser details which are 32 | // available to JS here to build a string, namely... 33 | // 34 | // * the user agent 35 | // * screen size 36 | // * color depth 37 | // * the timezone offset 38 | // * sessionStorage support 39 | // * localStorage support 40 | // * the list of all installed plugins (we're using their names, 41 | // descriptions, mime types and file name extensions here) 42 | function _raw() { 43 | // That string is the return value. 44 | return [ 45 | navigator.userAgent, 46 | [ screen.height, screen.width, screen.colorDepth ].join("x"), 47 | ( new Date() ).getTimezoneOffset(), 48 | !!window.sessionStorage, 49 | !!window.localStorage, 50 | $.map( navigator.plugins, function(p) { 51 | return [ 52 | p.name, 53 | p.description, 54 | $.map( p, function(mt) { 55 | return [ mt.type, mt.suffixes ].join("~"); 56 | }).join(",") 57 | ].join("::"); 58 | }).join(";") 59 | ].join("###"); 60 | } 61 | 62 | // `_md5()` computes a MD5 hash using [md5-js](http://github.com/wbond/md5-js/). 63 | function _md5() { 64 | if ( typeof window.md5 === "function" ) { 65 | // The return value is the hashed fingerprint string. 66 | return md5( _raw() ); 67 | } 68 | else { 69 | // If `window.md5()` isn't available, an error is thrown. 70 | throw "md5 unavailable, please get it from http://github.com/wbond/md5-js/"; 71 | } 72 | } 73 | 74 | // And, since I'm lazy, calling `$.fingerprint()` will return the hash 75 | // right away, without the need for any other calls. 76 | return _md5(); 77 | } 78 | 79 | })(jQuery); 80 | -------------------------------------------------------------------------------- /src/jquery.browser-fingerprint-1.1.min.js: -------------------------------------------------------------------------------- 1 | // This library was written by Carlo Zottmann, carlo@municode.de, has its home 2 | // on [Github](http://github.com/carlo/jquery-browser-fingerprint) and is 3 | // WTF-licensed (see LICENSE.txt). 4 | (function(a){a.fingerprint=function(){function b(){return[navigator.userAgent,[screen.height,screen.width,screen.colorDepth].join("x"),(new Date).getTimezoneOffset(),!!window.sessionStorage,!!window.localStorage,a.map(navigator.plugins,function(b){return[b.name,b.description,a.map(b,function(a){return[a.type,a.suffixes].join("~")}).join(",")].join("::")}).join(";")].join("###")}function c(){if(typeof window.md5=="function")return md5(b());throw"md5 unavailable, please get it from http://github.com/wbond/md5-js/"}return c()}})(jQuery); 5 | --------------------------------------------------------------------------------